Skip to content

Instantly share code, notes, and snippets.

@aheld
Last active January 17, 2022 18:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save aheld/ab59bce3bd3b3d1115adbae7d6ca65be to your computer and use it in GitHub Desktop.
Save aheld/ab59bce3bd3b3d1115adbae7d6ca65be to your computer and use it in GitHub Desktop.
companion to tutorial on aaronheld.com
/** 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