Last active
January 17, 2022 18:34
-
-
Save aheld/ab59bce3bd3b3d1115adbae7d6ca65be to your computer and use it in GitHub Desktop.
companion to tutorial on aaronheld.com
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** some examples for using and testing sprocs | |
Needs the key in the env var: export cosmos_key="q2Mk..... | |
npm i -s @azure/cosmos | |
npm i -s uuid | |
runHello will create a simple sproc, update it to the collection, and then test it | |
runSprocCase will create a sproc that does a server-side update for atomic updates, pushes it to the collection, tests it | |
runClient does an client based document replace, using etags for optimistic concurrency locking | |
*/ | |
const assert = require('assert') | |
const { CosmosClient } = require('@azure/cosmos') | |
const uuidv4 = require('uuid').v4 | |
const endpoint = 'https://xxxxxx.documents.azure.com:443/' | |
const key = process.env.cosmos_key | |
const client = new CosmosClient({ endpoint, key }); | |
const container = client.database('dbName').container('coupons') | |
DEBUG=false | |
async function runHello() { | |
console.log("\n*****\n* Starting simple case\n") | |
const sproc = helloWorldStoredProc | |
await createOrUpdateSproc(sproc) | |
const res = await runSproc(sproc.id, "") | |
if (DEBUG) console.log(res) | |
assert.strictEqual(res, "Hello, World") | |
console.log("\n*Assertions passed") | |
} | |
async function runSprocCase(){ | |
console.log("\n*****\n* Starting advanced case\n") | |
// await createOrUpdateSproc(updateCoupon) | |
const guid = uuidv4() | |
const doc = await createDoc(guid) | |
// doc.userId is the partition key in this collection | |
await runSproc(updateCoupon.id, doc.userId, doc.userId) | |
const updatedDoc = await getDoc(doc.userId) | |
assert.strictEqual(updatedDoc.user_coupon_id, guid) | |
assert.strictEqual(updatedDoc.touched_by_sproc, "yes") | |
await deleteDoc(updatedDoc) | |
console.log("\n*Assertions passed") | |
} | |
async function runClient(){ | |
console.log("\n*****\n* Starting client case\n") | |
const guid = uuidv4() | |
const doc = await createDoc(guid) | |
await runClientReplace(doc) | |
const updatedDoc = await getDoc(doc.userId) | |
assert.strictEqual(updatedDoc.user_coupon_id, guid) | |
assert.strictEqual(updatedDoc.touched_by_client, "yes") | |
await deleteDoc(updatedDoc) | |
console.log("\n*Assertions passed") | |
} | |
// Simple case | |
//define simple sproc | |
const helloWorldStoredProc = { | |
id: "helloWorld2", | |
body: function () { | |
var context = getContext(); | |
var response = context.getResponse(); | |
console.log("logging message from the sproc") | |
response.setBody("Hello, World"); | |
} | |
} | |
//define slightly more advanced sproc | |
const updateCoupon = { | |
id: "updateCoupon_001", | |
body: function (userId) { | |
var collection = getContext().getCollection() | |
console.log("Sproc called with " + userId) | |
var filterQuery = | |
{ | |
'query' : 'SELECT * FROM root r where r.userId = @userId', | |
'parameters' : [{'name':'@userId', 'value':userId}] | |
} | |
var isAccepted = collection.queryDocuments( | |
collection.getSelfLink(), | |
filterQuery, | |
{}, | |
function (err, feed, options) { if (err) throw err | |
var response = getContext().getResponse() | |
if (!feed || !feed.length) { | |
response.setBody('no docs found..') | |
} | |
else { | |
for(var i = 0;i<feed.length;i++){ | |
var doc = feed[i] | |
doc.touched_by_sproc = "yes" | |
console.log("updated " + userId) | |
collection.replaceDocument(doc._self,doc,function(err) {if (err) throw err;}) | |
} | |
var body = { updated: feed }; | |
response.setBody(JSON.stringify(body)); | |
} | |
}) | |
if (!isAccepted) throw new Error('The query was not accepted by the server.') | |
} | |
} | |
async function createOrUpdateSproc(sproc) { | |
try { | |
if (DEBUG) console.log('Try to REPLACE sproc ', sproc.id) | |
await container.scripts.storedProcedure(sproc.id).replace(sproc) | |
} catch (e) { | |
if (e.code === 404) { | |
if (DEBUG) console.log('REPLACE failed, try to add ', sproc.id) | |
await container.scripts.storedProcedures.create(sproc) | |
} else { | |
throw(e) | |
} | |
} | |
} | |
async function runSproc(sprocname, partition_id, args) { | |
if (DEBUG) console.log(`runSproc("%s", "%s", "%s")`, sprocname, partition_id, args) | |
const result = await container.scripts.storedProcedure(sprocname).execute(partition_id, args, { enableScriptLogging: true }) | |
if (DEBUG) console.log("Sproc Log: ", decodeURIComponent(result.headers['x-ms-documentdb-script-log-results'])) | |
console.log("Sproc RU cost: ", result.headers['x-ms-request-charge']) | |
if (DEBUG) console.log("Result ", result) | |
return result.resource | |
} | |
async function runClientReplace(doc) { | |
// function upsert<T>(body: T, options?: RequestOptions)accessCondition | |
if (DEBUG) console.log('updating doc from the client') | |
const item = await container.item(doc.id, doc.userId) | |
doc.touched_by_client = 'yes' | |
const result = await item.replace(doc, { accessCondition: { type: "IfMatch", condition: doc._etag } }) | |
console.log("Local Replace RU cost: ", result.headers['x-ms-request-charge']) | |
if (DEBUG) console.log("Result after client replace ", result.resource) | |
} | |
async function createDoc(id) { | |
const doc = getFixture(id) | |
const result = await container.items.create(doc) | |
const serverDoc = result.resource | |
if (DEBUG) console.log("Create Doc ", serverDoc) | |
return serverDoc | |
} | |
async function deleteDoc(doc) { | |
await container.item(doc.id, doc.userId).delete() | |
} | |
async function getDoc(userId) { | |
const res = await container.items | |
.query({ | |
'query' : 'SELECT * FROM root r where r.userId = @Id', | |
'parameters' : [{'name':'@Id', 'value':userId}] | |
}) | |
.fetchAll() | |
//fetchall returns an array, so assume we got one (GUID!) | |
if (DEBUG) console.log("Post query, get Doc from query ", res.resources[0]) | |
return res.resources[0] | |
} | |
function getFixture(guid) { | |
return { | |
"id": guid, | |
"user_coupon_id": guid, | |
"used_for_sproc_testing": "yes", | |
"userId": "testUser-" + guid, | |
"coupon_name": "generic coupon name", | |
"expiration_date": "2019-04-30T00:00:00.000Z", | |
"touched_by_sproc" : "no" | |
} | |
} | |
async function runTests() { | |
await runHello() | |
await runSprocCase() | |
await runClient() | |
} | |
runTests() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment