From 30255cb0a3e846d99e2979049ac2d347782663bd Mon Sep 17 00:00:00 2001 From: "Daniel W. Hieber" Date: Sun, 28 Aug 2016 02:13:45 -0500 Subject: [PATCH 01/18] init clear.js, length.js Adds two stored procedures to the samples. --- samples/stored-procedures/clear.js | 130 ++++++++++++++++++++++++++++ samples/stored-procedures/length.js | 97 +++++++++++++++++++++ 2 files changed, 227 insertions(+) create mode 100644 samples/stored-procedures/clear.js create mode 100644 samples/stored-procedures/length.js diff --git a/samples/stored-procedures/clear.js b/samples/stored-procedures/clear.js new file mode 100644 index 0000000..341bae8 --- /dev/null +++ b/samples/stored-procedures/clear.js @@ -0,0 +1,130 @@ +/* global __ */ + +/* eslint-disable + func-style, + no-param-reassign, + no-magic-numbers, + no-underscore-dangle +*/ + +/** + * A stored procedure for Azure DocumentDB which deletes documents with a specified filter + * @function + * @param {String} filterOn = 'type' The key to filter documents on for deletion. + * @param {String} filterValue = 'session' The value that a document's filter key must have to be deleted + * @return {responseBody} + */ +function clear(filterOn, filterValue) { + + // set default filter key and value + filterOn = filterOn || 'type'; + filterValue = filterValue || 'session'; + + const response = __.response; // get the response object + + /** + * The response body returned by the stored procedure + * @const + * @typedef {Object} responseBody + * @type {Object} responseBody + * @prop {Number} deleted The number of documents which were deleted. + * @prop {Boolean} continuation Whether there are still more documents to delete. + */ + const responseBody = { + deleted: 0, + continuation: true, + }; + + /** + * Recursively deletes each session in an array, and then attempts to get more to delete + * @function + * @param {Array} sessions The array of session documents to delete + */ + function deleteSessions(sessions) { + if (sessions.length > 0) { + + // attempt to delete the first document in the array + const accepted = __.deleteDocument(sessions[0]._self, function handler(err) { + if (err) throw err; + + responseBody.deleted++; // increment deleted counter + sessions.shift(); // remove document from array + deleteSessions(sessions); // delete the next doc + + }); + + // if the delete request was not accepted due to timeout, return the {@link responseBody} with a continuation + if (!accepted) response.setBody(responseBody); + + } else { + + // if there are no more documents to delete, try getting more + getSessions(); + + } + } + + /** + * Filters for session documents based on the provided filter key and value ({@link filterOn}, {@link filterValue}), and immediately begins deleting them as results are returned + * @function + * @param {String} [continuationToken] A continuation token, if one was received from a previous request + */ + function getSessions(continuationToken) { + + /** + * The filter function that returns a doc only if it has the given filter {@link filterOn} and {@link filterValue} + * @function + * @param {Object} doc The DocumentDB document to test against + * @return {Boolean} Whether the document has the given filter key and value + */ + const filter = function filter(doc) { + return doc[filterOn] === filterValue; + }; + + /** + * Handler for the filter request + * @function + * @param {Object} err The error object, if any was thrown + * @param {Number} err.number The error code + * @param {String} err.body The body of the error message + * @param {Array} sessions The retrieved sessions + * @param {Object} info Info about the request, including a continuation token + * @param {String} info.continuation The continuation token, if any was passed + * @return {responseBody} + */ + const handler = function handler(err, sessions, info) { + if (err) throw err; + + if (sessions.length > 0) { + + // if sessions were found, begin deleting them immediately (prioritizes deletion over searching) + deleteSessions(sessions); + + } else if (info.continuation) { + + // if the filter came back empty but with a continuation token, get the next set of results + getSessions(info.continuation); + + } else { + + // if there are no more documents and no continuation token, return the {@link responseBody} without a continuation + responseBody.continuation = false; + response.setBody(responseBody); + + } + + }; + + // filter the collection for sessions using the filter function + const accepted = __.filter(filter, { continuation: continuationToken }, handler); + + // if the filter request is not accepted due to timeout, return the response with a continuation + if (!accepted) response.setBody(responseBody); + + } + + getSessions(); // start the stored procedure + +} + +module.exports = clear; diff --git a/samples/stored-procedures/length.js b/samples/stored-procedures/length.js new file mode 100644 index 0000000..c44af7d --- /dev/null +++ b/samples/stored-procedures/length.js @@ -0,0 +1,97 @@ +/* global __ */ +/* eslint-disable + func-style, + no-param-reassign, + object-shorthand +*/ + +/** + * A stored procedure for Azure DocumentDB which gets a count of the session documents + * @function + * @param {String} filterOn = 'type' The key to filter documents on for deletion. + * @param {String} filterValue = 'session' The value that a document's filter key must have to be counted + * @param {String} [continuationToken] The previous continuation token, if any was passed + * @return {responseBody} + */ +function length(filterOn, filterValue, continuationToken) { + + // set default filter key and value + filterOn = filterOn || 'type'; + filterValue = filterValue || 'session'; + + const response = __.response; // get the response object + let documentsFound = 0; + + /** + * The response body returned by the stored procedure + * @const + * @typedef {Object} responseBody + * @type {Object} responseBody + * @prop {Number} documentsFound The number of documents found so far. + * @prop {Boolean} continuation Whether there are still more documents to find. + */ + const responseBody = { + documentsFound: documentsFound, + continuation: false, + }; + + /** + * Filters for session documents based on the provider filter key {@link filterOn} and value {@link filterValue}, and adds the number of results to the running count + * @function + * @param {String} continuationToken The continuation token, if one was received from the previous request + */ + function getSessions(continuationToken) { + + /** + * The filter function that returns a doc only if it has the given filter {@link filterOn} and {@link filterValue} + * @function + * @param {Object} doc The DocumentDB document to test against + * @return {Boolean} Whether the document has the given filter key and value + */ + const filter = function filter(doc) { + return doc[filterOn] === filterValue; + }; + + /** + * Handler for the filter request. + * @function + * @param {Object} err The error object, if any was thrown + * @param {Number} err.number The error code + * @param {String} err.body The body of the error message + * @param {Array} sessions An array of the retrieved sessions + * @param {Object} info Info about the request, including a continuation token + * @param {String} info.continuation The continuation token, if any was passed + * @return {responseBody} + */ + const handler = function handler(err, sessions, info) { + if (err) throw err; + + // if sessions were found, add them to the running documents total + documentsFound += sessions.length; + + if (info.continuation) { + // if there was a continuation token, get the next set of results + getSessions(info.continuation); + } else { + // otherwise, return the response body, including the count of the results + response.setBody(responseBody); + } + + }; + + // filter the collection for sessions using the filter function + const accepted = __.filter(filter, { continuation: continuationToken }, handler); + + // if the filter request is not accepted due to timeout, return the response with a continuation + if (!accepted) { + responseBody.continuation = continuationToken; + response.setBody(responseBody); + } + + } + + getSessions(continuationToken); + +} + +module.exports = length; From 4a5695a18367a0afd01b6dac464b590f67b99e8b Mon Sep 17 00:00:00 2001 From: "Daniel W. Hieber" Date: Sun, 28 Aug 2016 02:15:05 -0500 Subject: [PATCH 02/18] remove ESLint comments --- samples/stored-procedures/length.js | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/samples/stored-procedures/length.js b/samples/stored-procedures/length.js index c44af7d..7a054a2 100644 --- a/samples/stored-procedures/length.js +++ b/samples/stored-procedures/length.js @@ -1,12 +1,5 @@ -/* global __ */ -/* eslint-disable - func-style, - no-param-reassign, - object-shorthand -*/ - /** - * A stored procedure for Azure DocumentDB which gets a count of the session documents + * A stored procedure for Azure DocumentDB which gets a count of the session documents using the .filter() method of the collection. * @function * @param {String} filterOn = 'type' The key to filter documents on for deletion. * @param {String} filterValue = 'session' The value that a document's filter key must have to be counted From f55af41b2f38cc1b136e2fe9e4c5db1bdeba3b9a Mon Sep 17 00:00:00 2001 From: "Daniel W. Hieber" Date: Sun, 28 Aug 2016 02:15:59 -0500 Subject: [PATCH 03/18] remove ESLint comments --- samples/stored-procedures/clear.js | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/samples/stored-procedures/clear.js b/samples/stored-procedures/clear.js index 341bae8..3c60c22 100644 --- a/samples/stored-procedures/clear.js +++ b/samples/stored-procedures/clear.js @@ -1,14 +1,5 @@ -/* global __ */ - -/* eslint-disable - func-style, - no-param-reassign, - no-magic-numbers, - no-underscore-dangle -*/ - /** - * A stored procedure for Azure DocumentDB which deletes documents with a specified filter + * A stored procedure for Azure DocumentDB which deletes documents with a specified filter key and value * @function * @param {String} filterOn = 'type' The key to filter documents on for deletion. * @param {String} filterValue = 'session' The value that a document's filter key must have to be deleted From 780ca9c1d0f07b4eb50c78a6030d3d74441b0296 Mon Sep 17 00:00:00 2001 From: "Daniel W. Hieber" Date: Thu, 15 Sep 2016 13:11:31 -0500 Subject: [PATCH 04/18] rename count.js > bulkDelete_underscoreAPI.js --- .../{clear.js => bulkDelete_underscoreAPI.js} | 242 +++++++++--------- 1 file changed, 121 insertions(+), 121 deletions(-) rename samples/stored-procedures/{clear.js => bulkDelete_underscoreAPI.js} (97%) diff --git a/samples/stored-procedures/clear.js b/samples/stored-procedures/bulkDelete_underscoreAPI.js similarity index 97% rename from samples/stored-procedures/clear.js rename to samples/stored-procedures/bulkDelete_underscoreAPI.js index 3c60c22..84a053f 100644 --- a/samples/stored-procedures/clear.js +++ b/samples/stored-procedures/bulkDelete_underscoreAPI.js @@ -1,121 +1,121 @@ -/** - * A stored procedure for Azure DocumentDB which deletes documents with a specified filter key and value - * @function - * @param {String} filterOn = 'type' The key to filter documents on for deletion. - * @param {String} filterValue = 'session' The value that a document's filter key must have to be deleted - * @return {responseBody} - */ -function clear(filterOn, filterValue) { - - // set default filter key and value - filterOn = filterOn || 'type'; - filterValue = filterValue || 'session'; - - const response = __.response; // get the response object - - /** - * The response body returned by the stored procedure - * @const - * @typedef {Object} responseBody - * @type {Object} responseBody - * @prop {Number} deleted The number of documents which were deleted. - * @prop {Boolean} continuation Whether there are still more documents to delete. - */ - const responseBody = { - deleted: 0, - continuation: true, - }; - - /** - * Recursively deletes each session in an array, and then attempts to get more to delete - * @function - * @param {Array} sessions The array of session documents to delete - */ - function deleteSessions(sessions) { - if (sessions.length > 0) { - - // attempt to delete the first document in the array - const accepted = __.deleteDocument(sessions[0]._self, function handler(err) { - if (err) throw err; - - responseBody.deleted++; // increment deleted counter - sessions.shift(); // remove document from array - deleteSessions(sessions); // delete the next doc - - }); - - // if the delete request was not accepted due to timeout, return the {@link responseBody} with a continuation - if (!accepted) response.setBody(responseBody); - - } else { - - // if there are no more documents to delete, try getting more - getSessions(); - - } - } - - /** - * Filters for session documents based on the provided filter key and value ({@link filterOn}, {@link filterValue}), and immediately begins deleting them as results are returned - * @function - * @param {String} [continuationToken] A continuation token, if one was received from a previous request - */ - function getSessions(continuationToken) { - - /** - * The filter function that returns a doc only if it has the given filter {@link filterOn} and {@link filterValue} - * @function - * @param {Object} doc The DocumentDB document to test against - * @return {Boolean} Whether the document has the given filter key and value - */ - const filter = function filter(doc) { - return doc[filterOn] === filterValue; - }; - - /** - * Handler for the filter request - * @function - * @param {Object} err The error object, if any was thrown - * @param {Number} err.number The error code - * @param {String} err.body The body of the error message - * @param {Array} sessions The retrieved sessions - * @param {Object} info Info about the request, including a continuation token - * @param {String} info.continuation The continuation token, if any was passed - * @return {responseBody} - */ - const handler = function handler(err, sessions, info) { - if (err) throw err; - - if (sessions.length > 0) { - - // if sessions were found, begin deleting them immediately (prioritizes deletion over searching) - deleteSessions(sessions); - - } else if (info.continuation) { - - // if the filter came back empty but with a continuation token, get the next set of results - getSessions(info.continuation); - - } else { - - // if there are no more documents and no continuation token, return the {@link responseBody} without a continuation - responseBody.continuation = false; - response.setBody(responseBody); - - } - - }; - - // filter the collection for sessions using the filter function - const accepted = __.filter(filter, { continuation: continuationToken }, handler); - - // if the filter request is not accepted due to timeout, return the response with a continuation - if (!accepted) response.setBody(responseBody); - - } - - getSessions(); // start the stored procedure - -} - -module.exports = clear; +/** + * A stored procedure for Azure DocumentDB which deletes documents with a specified filter key and value + * @function + * @param {String} filterOn = 'type' The key to filter documents on for deletion. + * @param {String} filterValue = 'session' The value that a document's filter key must have to be deleted + * @return {responseBody} + */ +function clear(filterOn, filterValue) { + + // set default filter key and value + filterOn = filterOn || 'type'; + filterValue = filterValue || 'session'; + + const response = __.response; // get the response object + + /** + * The response body returned by the stored procedure + * @const + * @typedef {Object} responseBody + * @type {Object} responseBody + * @prop {Number} deleted The number of documents which were deleted. + * @prop {Boolean} continuation Whether there are still more documents to delete. + */ + const responseBody = { + deleted: 0, + continuation: true, + }; + + /** + * Recursively deletes each session in an array, and then attempts to get more to delete + * @function + * @param {Array} sessions The array of session documents to delete + */ + function deleteSessions(sessions) { + if (sessions.length > 0) { + + // attempt to delete the first document in the array + const accepted = __.deleteDocument(sessions[0]._self, function handler(err) { + if (err) throw err; + + responseBody.deleted++; // increment deleted counter + sessions.shift(); // remove document from array + deleteSessions(sessions); // delete the next doc + + }); + + // if the delete request was not accepted due to timeout, return the {@link responseBody} with a continuation + if (!accepted) response.setBody(responseBody); + + } else { + + // if there are no more documents to delete, try getting more + getSessions(); + + } + } + + /** + * Filters for session documents based on the provided filter key and value ({@link filterOn}, {@link filterValue}), and immediately begins deleting them as results are returned + * @function + * @param {String} [continuationToken] A continuation token, if one was received from a previous request + */ + function getSessions(continuationToken) { + + /** + * The filter function that returns a doc only if it has the given filter {@link filterOn} and {@link filterValue} + * @function + * @param {Object} doc The DocumentDB document to test against + * @return {Boolean} Whether the document has the given filter key and value + */ + const filter = function filter(doc) { + return doc[filterOn] === filterValue; + }; + + /** + * Handler for the filter request + * @function + * @param {Object} err The error object, if any was thrown + * @param {Number} err.number The error code + * @param {String} err.body The body of the error message + * @param {Array} sessions The retrieved sessions + * @param {Object} info Info about the request, including a continuation token + * @param {String} info.continuation The continuation token, if any was passed + * @return {responseBody} + */ + const handler = function handler(err, sessions, info) { + if (err) throw err; + + if (sessions.length > 0) { + + // if sessions were found, begin deleting them immediately (prioritizes deletion over searching) + deleteSessions(sessions); + + } else if (info.continuation) { + + // if the filter came back empty but with a continuation token, get the next set of results + getSessions(info.continuation); + + } else { + + // if there are no more documents and no continuation token, return the {@link responseBody} without a continuation + responseBody.continuation = false; + response.setBody(responseBody); + + } + + }; + + // filter the collection for sessions using the filter function + const accepted = __.filter(filter, { continuation: continuationToken }, handler); + + // if the filter request is not accepted due to timeout, return the response with a continuation + if (!accepted) response.setBody(responseBody); + + } + + getSessions(); // start the stored procedure + +} + +module.exports = clear; From be725a2ca369d984e0f5654a55ad2b3d07419ebd Mon Sep 17 00:00:00 2001 From: "Daniel W. Hieber" Date: Thu, 15 Sep 2016 13:14:07 -0500 Subject: [PATCH 05/18] rename length.js > count_underScoreAPI.js --- .../{length.js => count_underscoreAPI.js} | 180 +++++++++--------- 1 file changed, 90 insertions(+), 90 deletions(-) rename samples/stored-procedures/{length.js => count_underscoreAPI.js} (97%) diff --git a/samples/stored-procedures/length.js b/samples/stored-procedures/count_underscoreAPI.js similarity index 97% rename from samples/stored-procedures/length.js rename to samples/stored-procedures/count_underscoreAPI.js index 7a054a2..0d27c44 100644 --- a/samples/stored-procedures/length.js +++ b/samples/stored-procedures/count_underscoreAPI.js @@ -1,90 +1,90 @@ -/** - * A stored procedure for Azure DocumentDB which gets a count of the session documents using the .filter() method of the collection. - * @function - * @param {String} filterOn = 'type' The key to filter documents on for deletion. - * @param {String} filterValue = 'session' The value that a document's filter key must have to be counted - * @param {String} [continuationToken] The previous continuation token, if any was passed - * @return {responseBody} - */ -function length(filterOn, filterValue, continuationToken) { - - // set default filter key and value - filterOn = filterOn || 'type'; - filterValue = filterValue || 'session'; - - const response = __.response; // get the response object - let documentsFound = 0; - - /** - * The response body returned by the stored procedure - * @const - * @typedef {Object} responseBody - * @type {Object} responseBody - * @prop {Number} documentsFound The number of documents found so far. - * @prop {Boolean} continuation Whether there are still more documents to find. - */ - const responseBody = { - documentsFound: documentsFound, - continuation: false, - }; - - /** - * Filters for session documents based on the provider filter key {@link filterOn} and value {@link filterValue}, and adds the number of results to the running count - * @function - * @param {String} continuationToken The continuation token, if one was received from the previous request - */ - function getSessions(continuationToken) { - - /** - * The filter function that returns a doc only if it has the given filter {@link filterOn} and {@link filterValue} - * @function - * @param {Object} doc The DocumentDB document to test against - * @return {Boolean} Whether the document has the given filter key and value - */ - const filter = function filter(doc) { - return doc[filterOn] === filterValue; - }; - - /** - * Handler for the filter request. - * @function - * @param {Object} err The error object, if any was thrown - * @param {Number} err.number The error code - * @param {String} err.body The body of the error message - * @param {Array} sessions An array of the retrieved sessions - * @param {Object} info Info about the request, including a continuation token - * @param {String} info.continuation The continuation token, if any was passed - * @return {responseBody} - */ - const handler = function handler(err, sessions, info) { - if (err) throw err; - - // if sessions were found, add them to the running documents total - documentsFound += sessions.length; - - if (info.continuation) { - // if there was a continuation token, get the next set of results - getSessions(info.continuation); - } else { - // otherwise, return the response body, including the count of the results - response.setBody(responseBody); - } - - }; - - // filter the collection for sessions using the filter function - const accepted = __.filter(filter, { continuation: continuationToken }, handler); - - // if the filter request is not accepted due to timeout, return the response with a continuation - if (!accepted) { - responseBody.continuation = continuationToken; - response.setBody(responseBody); - } - - } - - getSessions(continuationToken); - -} - -module.exports = length; +/** + * A stored procedure for Azure DocumentDB which gets a count of the session documents using the .filter() method of the collection. + * @function + * @param {String} filterOn = 'type' The key to filter documents on for deletion. + * @param {String} filterValue = 'session' The value that a document's filter key must have to be counted + * @param {String} [continuationToken] The previous continuation token, if any was passed + * @return {responseBody} + */ +function length(filterOn, filterValue, continuationToken) { + + // set default filter key and value + filterOn = filterOn || 'type'; + filterValue = filterValue || 'session'; + + const response = __.response; // get the response object + let documentsFound = 0; + + /** + * The response body returned by the stored procedure + * @const + * @typedef {Object} responseBody + * @type {Object} responseBody + * @prop {Number} documentsFound The number of documents found so far. + * @prop {Boolean} continuation Whether there are still more documents to find. + */ + const responseBody = { + documentsFound: documentsFound, + continuation: false, + }; + + /** + * Filters for session documents based on the provider filter key {@link filterOn} and value {@link filterValue}, and adds the number of results to the running count + * @function + * @param {String} continuationToken The continuation token, if one was received from the previous request + */ + function getSessions(continuationToken) { + + /** + * The filter function that returns a doc only if it has the given filter {@link filterOn} and {@link filterValue} + * @function + * @param {Object} doc The DocumentDB document to test against + * @return {Boolean} Whether the document has the given filter key and value + */ + const filter = function filter(doc) { + return doc[filterOn] === filterValue; + }; + + /** + * Handler for the filter request. + * @function + * @param {Object} err The error object, if any was thrown + * @param {Number} err.number The error code + * @param {String} err.body The body of the error message + * @param {Array} sessions An array of the retrieved sessions + * @param {Object} info Info about the request, including a continuation token + * @param {String} info.continuation The continuation token, if any was passed + * @return {responseBody} + */ + const handler = function handler(err, sessions, info) { + if (err) throw err; + + // if sessions were found, add them to the running documents total + documentsFound += sessions.length; + + if (info.continuation) { + // if there was a continuation token, get the next set of results + getSessions(info.continuation); + } else { + // otherwise, return the response body, including the count of the results + response.setBody(responseBody); + } + + }; + + // filter the collection for sessions using the filter function + const accepted = __.filter(filter, { continuation: continuationToken }, handler); + + // if the filter request is not accepted due to timeout, return the response with a continuation + if (!accepted) { + responseBody.continuation = continuationToken; + response.setBody(responseBody); + } + + } + + getSessions(continuationToken); + +} + +module.exports = length; From f0f61d2ea5f3fa03f6925e11fcf7d9f1b2d44007 Mon Sep 17 00:00:00 2001 From: "Daniel W. Hieber" Date: Thu, 15 Sep 2016 13:26:09 -0500 Subject: [PATCH 06/18] inline predicate function * also camelCase file names for consistency --- .../bulkDelete_underscoreAPI.js | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/samples/stored-procedures/bulkDelete_underscoreAPI.js b/samples/stored-procedures/bulkDelete_underscoreAPI.js index 84a053f..27c52c6 100644 --- a/samples/stored-procedures/bulkDelete_underscoreAPI.js +++ b/samples/stored-procedures/bulkDelete_underscoreAPI.js @@ -62,16 +62,6 @@ function clear(filterOn, filterValue) { */ function getSessions(continuationToken) { - /** - * The filter function that returns a doc only if it has the given filter {@link filterOn} and {@link filterValue} - * @function - * @param {Object} doc The DocumentDB document to test against - * @return {Boolean} Whether the document has the given filter key and value - */ - const filter = function filter(doc) { - return doc[filterOn] === filterValue; - }; - /** * Handler for the filter request * @function @@ -106,8 +96,12 @@ function clear(filterOn, filterValue) { }; - // filter the collection for sessions using the filter function - const accepted = __.filter(filter, { continuation: continuationToken }, handler); + // filter the collection for sessions using a filter function + // NB: The filter function must be inlined in order to take advantage of index + // (otherwise it will be a full scan). + const accepted = __.filter(function filter(doc) { + return doc[filterOn] === filterValue; + }, { continuation: continuationToken }, handler); // if the filter request is not accepted due to timeout, return the response with a continuation if (!accepted) response.setBody(responseBody); From afbbec747e479814d5e9e9537258a88870be1193 Mon Sep 17 00:00:00 2001 From: "Daniel W. Hieber" Date: Thu, 15 Sep 2016 13:27:39 -0500 Subject: [PATCH 07/18] fix typo: 'deletion' > 'counting' --- samples/stored-procedures/count_underscoreAPI.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/stored-procedures/count_underscoreAPI.js b/samples/stored-procedures/count_underscoreAPI.js index 0d27c44..380dea0 100644 --- a/samples/stored-procedures/count_underscoreAPI.js +++ b/samples/stored-procedures/count_underscoreAPI.js @@ -1,7 +1,7 @@ /** * A stored procedure for Azure DocumentDB which gets a count of the session documents using the .filter() method of the collection. * @function - * @param {String} filterOn = 'type' The key to filter documents on for deletion. + * @param {String} filterOn = 'type' The key to filter documents on for counting. * @param {String} filterValue = 'session' The value that a document's filter key must have to be counted * @param {String} [continuationToken] The previous continuation token, if any was passed * @return {responseBody} From b0f33048fb2aa988a6fcbe37141dd83dd6654e4f Mon Sep 17 00:00:00 2001 From: "Daniel W. Hieber" Date: Thu, 15 Sep 2016 13:28:47 -0500 Subject: [PATCH 08/18] inline predicate function in count_underscoreAPI.js --- samples/stored-procedures/count_underscoreAPI.js | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/samples/stored-procedures/count_underscoreAPI.js b/samples/stored-procedures/count_underscoreAPI.js index 380dea0..ea60667 100644 --- a/samples/stored-procedures/count_underscoreAPI.js +++ b/samples/stored-procedures/count_underscoreAPI.js @@ -35,16 +35,6 @@ function length(filterOn, filterValue, continuationToken) { */ function getSessions(continuationToken) { - /** - * The filter function that returns a doc only if it has the given filter {@link filterOn} and {@link filterValue} - * @function - * @param {Object} doc The DocumentDB document to test against - * @return {Boolean} Whether the document has the given filter key and value - */ - const filter = function filter(doc) { - return doc[filterOn] === filterValue; - }; - /** * Handler for the filter request. * @function @@ -73,7 +63,9 @@ function length(filterOn, filterValue, continuationToken) { }; // filter the collection for sessions using the filter function - const accepted = __.filter(filter, { continuation: continuationToken }, handler); + const accepted = __.filter(function filter(doc) { + return doc[filterOn] === filterValue; + }, { continuation: continuationToken }, handler); // if the filter request is not accepted due to timeout, return the response with a continuation if (!accepted) { From 5b696e29930c123a262ec5d789d6f0b74e5aed0b Mon Sep 17 00:00:00 2001 From: "Daniel W. Hieber" Date: Thu, 15 Sep 2016 13:45:06 -0500 Subject: [PATCH 09/18] change commit message --- sqw2dgid.5b3.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 sqw2dgid.5b3.txt diff --git a/sqw2dgid.5b3.txt b/sqw2dgid.5b3.txt new file mode 100644 index 0000000..11f5ae4 --- /dev/null +++ b/sqw2dgid.5b3.txt @@ -0,0 +1 @@ +reword f0f61d2 inline predicate function in bulkDelete_underscoreAPI.js From 1763c9925953eec28a73f51b625a94c060327f9f Mon Sep 17 00:00:00 2001 From: "Daniel W. Hieber" Date: Thu, 15 Sep 2016 13:47:22 -0500 Subject: [PATCH 10/18] remove reference to module --- samples/stored-procedures/bulkDelete_underscoreAPI.js | 2 -- samples/stored-procedures/count_underscoreAPI.js | 2 -- sqw2dgid.5b3.txt | 1 - 3 files changed, 5 deletions(-) delete mode 100644 sqw2dgid.5b3.txt diff --git a/samples/stored-procedures/bulkDelete_underscoreAPI.js b/samples/stored-procedures/bulkDelete_underscoreAPI.js index 27c52c6..ed14db0 100644 --- a/samples/stored-procedures/bulkDelete_underscoreAPI.js +++ b/samples/stored-procedures/bulkDelete_underscoreAPI.js @@ -111,5 +111,3 @@ function clear(filterOn, filterValue) { getSessions(); // start the stored procedure } - -module.exports = clear; diff --git a/samples/stored-procedures/count_underscoreAPI.js b/samples/stored-procedures/count_underscoreAPI.js index ea60667..2aef8f2 100644 --- a/samples/stored-procedures/count_underscoreAPI.js +++ b/samples/stored-procedures/count_underscoreAPI.js @@ -78,5 +78,3 @@ function length(filterOn, filterValue, continuationToken) { getSessions(continuationToken); } - -module.exports = length; diff --git a/sqw2dgid.5b3.txt b/sqw2dgid.5b3.txt deleted file mode 100644 index 11f5ae4..0000000 --- a/sqw2dgid.5b3.txt +++ /dev/null @@ -1 +0,0 @@ -reword f0f61d2 inline predicate function in bulkDelete_underscoreAPI.js From 3c157495761211e3d9738182fb6047c5907fe8c9 Mon Sep 17 00:00:00 2001 From: "Daniel W. Hieber" Date: Thu, 15 Sep 2016 13:53:57 -0500 Subject: [PATCH 11/18] change 'sessions' to more generic 'documents' --- .../bulkDelete_underscoreAPI.js | 40 +++++++++---------- .../stored-procedures/count_underscoreAPI.js | 24 +++++------ 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/samples/stored-procedures/bulkDelete_underscoreAPI.js b/samples/stored-procedures/bulkDelete_underscoreAPI.js index ed14db0..8f41068 100644 --- a/samples/stored-procedures/bulkDelete_underscoreAPI.js +++ b/samples/stored-procedures/bulkDelete_underscoreAPI.js @@ -2,14 +2,14 @@ * A stored procedure for Azure DocumentDB which deletes documents with a specified filter key and value * @function * @param {String} filterOn = 'type' The key to filter documents on for deletion. - * @param {String} filterValue = 'session' The value that a document's filter key must have to be deleted + * @param {String} filterValue = '' The value that a document's filter key must have to be deleted * @return {responseBody} */ function clear(filterOn, filterValue) { // set default filter key and value filterOn = filterOn || 'type'; - filterValue = filterValue || 'session'; + filterValue = filterValue || ''; const response = __.response; // get the response object @@ -27,20 +27,20 @@ function clear(filterOn, filterValue) { }; /** - * Recursively deletes each session in an array, and then attempts to get more to delete + * Recursively deletes each document in an array, and then attempts to get more to delete * @function - * @param {Array} sessions The array of session documents to delete + * @param {Array} docs The array of documents to delete */ - function deleteSessions(sessions) { - if (sessions.length > 0) { + function deleteDocuments(docs) { + if (docs.length > 0) { // attempt to delete the first document in the array - const accepted = __.deleteDocument(sessions[0]._self, function handler(err) { + const accepted = __.deleteDocument(docs[0]._self, function handler(err) { if (err) throw err; responseBody.deleted++; // increment deleted counter - sessions.shift(); // remove document from array - deleteSessions(sessions); // delete the next doc + docs.shift(); // remove document from array + deleteDocuments(docs); // delete the next doc }); @@ -50,17 +50,17 @@ function clear(filterOn, filterValue) { } else { // if there are no more documents to delete, try getting more - getSessions(); + getDocuments(); } } /** - * Filters for session documents based on the provided filter key and value ({@link filterOn}, {@link filterValue}), and immediately begins deleting them as results are returned + * Filters for documents based on the provided filter key and value ({@link filterOn}, {@link filterValue}), and immediately begins deleting them as results are returned * @function * @param {String} [continuationToken] A continuation token, if one was received from a previous request */ - function getSessions(continuationToken) { + function getDocuments(continuationToken) { /** * Handler for the filter request @@ -68,23 +68,23 @@ function clear(filterOn, filterValue) { * @param {Object} err The error object, if any was thrown * @param {Number} err.number The error code * @param {String} err.body The body of the error message - * @param {Array} sessions The retrieved sessions + * @param {Array} docs The retrieved documents * @param {Object} info Info about the request, including a continuation token * @param {String} info.continuation The continuation token, if any was passed * @return {responseBody} */ - const handler = function handler(err, sessions, info) { + const handler = function handler(err, docs, info) { if (err) throw err; - if (sessions.length > 0) { + if (docs.length > 0) { - // if sessions were found, begin deleting them immediately (prioritizes deletion over searching) - deleteSessions(sessions); + // if documents were found, begin deleting them immediately (prioritizes deletion over searching) + deleteDocuments(docs); } else if (info.continuation) { // if the filter came back empty but with a continuation token, get the next set of results - getSessions(info.continuation); + getDocuments(info.continuation); } else { @@ -96,7 +96,7 @@ function clear(filterOn, filterValue) { }; - // filter the collection for sessions using a filter function + // filter the collection for documents using a filter function // NB: The filter function must be inlined in order to take advantage of index // (otherwise it will be a full scan). const accepted = __.filter(function filter(doc) { @@ -108,6 +108,6 @@ function clear(filterOn, filterValue) { } - getSessions(); // start the stored procedure + getDocuments(); // start the stored procedure } diff --git a/samples/stored-procedures/count_underscoreAPI.js b/samples/stored-procedures/count_underscoreAPI.js index 2aef8f2..b9d0c1f 100644 --- a/samples/stored-procedures/count_underscoreAPI.js +++ b/samples/stored-procedures/count_underscoreAPI.js @@ -1,8 +1,8 @@ /** - * A stored procedure for Azure DocumentDB which gets a count of the session documents using the .filter() method of the collection. + * A stored procedure for Azure DocumentDB which gets a count of documents in a collection using the .filter() method of the collection. * @function * @param {String} filterOn = 'type' The key to filter documents on for counting. - * @param {String} filterValue = 'session' The value that a document's filter key must have to be counted + * @param {String} filterValue = '' The value that a document's filter key must have to be counted * @param {String} [continuationToken] The previous continuation token, if any was passed * @return {responseBody} */ @@ -10,7 +10,7 @@ function length(filterOn, filterValue, continuationToken) { // set default filter key and value filterOn = filterOn || 'type'; - filterValue = filterValue || 'session'; + filterValue = filterValue || ''; const response = __.response; // get the response object let documentsFound = 0; @@ -29,11 +29,11 @@ function length(filterOn, filterValue, continuationToken) { }; /** - * Filters for session documents based on the provider filter key {@link filterOn} and value {@link filterValue}, and adds the number of results to the running count + * Filters for documents based on the provided filter key {@link filterOn} and value {@link filterValue}, and adds the number of results to the running count * @function * @param {String} continuationToken The continuation token, if one was received from the previous request */ - function getSessions(continuationToken) { + function getDocuments(continuationToken) { /** * Handler for the filter request. @@ -41,20 +41,20 @@ function length(filterOn, filterValue, continuationToken) { * @param {Object} err The error object, if any was thrown * @param {Number} err.number The error code * @param {String} err.body The body of the error message - * @param {Array} sessions An array of the retrieved sessions + * @param {Array} docs An array of the retrieved documents * @param {Object} info Info about the request, including a continuation token * @param {String} info.continuation The continuation token, if any was passed * @return {responseBody} */ - const handler = function handler(err, sessions, info) { + const handler = function handler(err, docs, info) { if (err) throw err; - // if sessions were found, add them to the running documents total - documentsFound += sessions.length; + // if documents were found, add them to the running documents total + documentsFound += docs.length; if (info.continuation) { // if there was a continuation token, get the next set of results - getSessions(info.continuation); + getDocuments(info.continuation); } else { // otherwise, return the response body, including the count of the results response.setBody(responseBody); @@ -62,7 +62,7 @@ function length(filterOn, filterValue, continuationToken) { }; - // filter the collection for sessions using the filter function + // filter the collection for documents using the filter function const accepted = __.filter(function filter(doc) { return doc[filterOn] === filterValue; }, { continuation: continuationToken }, handler); @@ -75,6 +75,6 @@ function length(filterOn, filterValue, continuationToken) { } - getSessions(continuationToken); + getDocuments(continuationToken); } From ea5876a89d63cc89dd1ecf8b521513532c911905 Mon Sep 17 00:00:00 2001 From: "Daniel W. Hieber" Date: Thu, 15 Sep 2016 14:33:32 -0500 Subject: [PATCH 12/18] replace filterOn and filterValue params with filterObj --- .../bulkDelete_underscoreAPI.js | 15 +++++++------ .../stored-procedures/count_underscoreAPI.js | 22 +++++++++---------- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/samples/stored-procedures/bulkDelete_underscoreAPI.js b/samples/stored-procedures/bulkDelete_underscoreAPI.js index 8f41068..97241f2 100644 --- a/samples/stored-procedures/bulkDelete_underscoreAPI.js +++ b/samples/stored-procedures/bulkDelete_underscoreAPI.js @@ -1,15 +1,13 @@ /** * A stored procedure for Azure DocumentDB which deletes documents with a specified filter key and value * @function - * @param {String} filterOn = 'type' The key to filter documents on for deletion. - * @param {String} filterValue = '' The value that a document's filter key must have to be deleted + * @param {Object} filterObj = {} An object containing the attributes and values to filter documents on. A document must have each of the matching attributes and values in this object to be deleted. A special case is made for a value of 'any'. This will delete documents which have the given attribute, regardless of its value. Passing an empty or undefined filterObj will delete all the documents in the collection. * @return {responseBody} */ -function clear(filterOn, filterValue) { +function clear(filterObj) { - // set default filter key and value - filterOn = filterOn || 'type'; - filterValue = filterValue || ''; + // set default filter object + filterObj = filterObj || {}; const response = __.response; // get the response object @@ -100,7 +98,10 @@ function clear(filterOn, filterValue) { // NB: The filter function must be inlined in order to take advantage of index // (otherwise it will be a full scan). const accepted = __.filter(function filter(doc) { - return doc[filterOn] === filterValue; + return Object.keys(filterObj).every(function checkProperty(filterKey) { + return doc.hasOwnProperty(filterKey) + && (doc[filterKey] === filterObj[filterKey] || filterKey === 'any'); + }); }, { continuation: continuationToken }, handler); // if the filter request is not accepted due to timeout, return the response with a continuation diff --git a/samples/stored-procedures/count_underscoreAPI.js b/samples/stored-procedures/count_underscoreAPI.js index b9d0c1f..140eb54 100644 --- a/samples/stored-procedures/count_underscoreAPI.js +++ b/samples/stored-procedures/count_underscoreAPI.js @@ -1,19 +1,16 @@ /** * A stored procedure for Azure DocumentDB which gets a count of documents in a collection using the .filter() method of the collection. * @function - * @param {String} filterOn = 'type' The key to filter documents on for counting. - * @param {String} filterValue = '' The value that a document's filter key must have to be counted + * @param {Object} filterObj = {} An object containing the attributes and values to filter documents on. A document must have each of the matching attributes and values in this object to be returned. A special case is made for a value of 'any'. This will return documents which have the given attribute, regardless of its value. * @param {String} [continuationToken] The previous continuation token, if any was passed * @return {responseBody} */ -function length(filterOn, filterValue, continuationToken) { +function length(filterObj, continuationToken) { - // set default filter key and value - filterOn = filterOn || 'type'; - filterValue = filterValue || ''; + // set default filter object + filterObj = filterObj || {}; const response = __.response; // get the response object - let documentsFound = 0; /** * The response body returned by the stored procedure @@ -24,7 +21,7 @@ function length(filterOn, filterValue, continuationToken) { * @prop {Boolean} continuation Whether there are still more documents to find. */ const responseBody = { - documentsFound: documentsFound, + documentsFound: 0, continuation: false, }; @@ -50,7 +47,7 @@ function length(filterOn, filterValue, continuationToken) { if (err) throw err; // if documents were found, add them to the running documents total - documentsFound += docs.length; + responseBody.documentsFound += docs.length; if (info.continuation) { // if there was a continuation token, get the next set of results @@ -62,9 +59,12 @@ function length(filterOn, filterValue, continuationToken) { }; - // filter the collection for documents using the filter function + // filter the collection for documents using the filter object const accepted = __.filter(function filter(doc) { - return doc[filterOn] === filterValue; + return Object.keys(filterObj).every(function checkProperty(filterKey) { + return doc.hasOwnProperty(filterKey) + && (doc[filterKey] === filterObj[filterKey] || filterKey === 'any'); + }); }, { continuation: continuationToken }, handler); // if the filter request is not accepted due to timeout, return the response with a continuation From d42afe467647fde8e3c40e12598b331f9889a95e Mon Sep 17 00:00:00 2001 From: "Daniel W. Hieber" Date: Fri, 16 Sep 2016 17:05:27 -0500 Subject: [PATCH 13/18] change `handler` function to `filterHandler` --- .eslintrc | 345 ++++++++++++++++++ .../bulkDelete_underscoreAPI.js | 6 +- .../stored-procedures/count_underscoreAPI.js | 6 +- 3 files changed, 351 insertions(+), 6 deletions(-) create mode 100644 .eslintrc diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..43a99ad --- /dev/null +++ b/.eslintrc @@ -0,0 +1,345 @@ +{ + + "parserOptions": { + "ecmaVersion": 7, + "ecmaFeatures": { + "impliedStrict": true + } + }, + + "env": { + "es6": true, + "jasmine": true, + "node": true + }, + + "rules": { + "id-blacklist": ["error"], + "no-restricted-globals": ["error"], + "no-restricted-imports": ["error"], + "no-restricted-modules": ["error"], + "no-restricted-syntax": ["error"], + + "accessor-pairs": "warn", + "array-callback-return": "warn", + "arrow-body-style": ["warn", "as-needed"], + "array-bracket-spacing": ["error", "never", { + "singleValue": false, + "objectsInArrays": false, + "arraysInArrays": false + }], + "arrow-parens": ["error", "as-needed"], + "arrow-spacing": ["error", { "before": true, "after": true }], + "block-scoped-var": "warn", + "block-spacing": ["error", "always"], + "brace-style": ["error", "1tbs", { "allowSingleLine": true }], + "callback-return": "error", + "camelcase": ["warn", { "properties": "always" }], + "comma-dangle": ["error", "always-multiline"], + "comma-spacing": ["error", { "before": false, "after": true }], + "comma-style": ["error", "last"], + "complexity": "off", + "computed-property-spacing": ["error", "never"], + "consistent-return": "warn", + "consistent-this": "off", + "constructor-super": "error", + "curly": ["error", "multi-line", "consistent"], + "default-case": "error", + "dot-location": ["error", "property"], + "dot-notation": ["error", { "allowKeywords": true }], + "eqeqeq": ["warn", "always"], + "eol-last": "error", + "func-names": ["error", "always"], + "func-style": ["error", "expression", { "allowArrowFunctions": true }], + "generator-star-spacing": ["error", { "before": false, "after": true }], + "global-require": "warn", + "guard-for-in": "warn", + "handle-callback-err": "error", + "id-length": "off", + "id-match": "off", + "indent": ["error", 2, { "SwitchCase": 1 }], + "init-declarations": ["warn", "always"], + "key-spacing": ["error", { + "beforeColon": false, + "afterColon": true, + "mode": "minimum" + }], + "keyword-spacing": ["error", { "before": true, "after": true }], + "linebreak-style": ["off"], + "lines-around-comment": ["warn", { + "beforeBlockComment": true, + "afterBlockComment": false, + "beforeLineComment": false, + "afterLineComment": false, + "allowBlockStart": true, + "allowBlockEnd": false, + "allowObjectStart": false, + "allowObjectEnd": false, + "allowArrayStart": false, + "allowArrayEnd": false + }], + "max-depth": "warn", + "max-len": ["warn", { + "code": 100, + "ignoreUrls": true, + "ignoreComments": true + }], + "max-lines": "off", + "max-nested-callbacks": ["warn", 2], + "max-params": ["warn", 4], + "max-statements": ["warn", 10], + "max-statements-per-line": ["warn", { "max": 2 }], + "multiline-ternary": "off", + "new-cap": ["error", { + "newIsCap": true, + "capIsNew": true, + "properties": true + }], + "new-parens": "off", + "newline-after-var": ["warn", "always"], + "newline-before-return": "off", + "newline-per-chained-call": ["warn", { "ignoreChainWithDepth": 2 }], + "no-alert": "warn", + "no-array-constructor": "warn", + "no-bitwise": "warn", + "no-caller": "error", + "no-case-declarations": "error", + "no-catch-shadow": "error", + "no-class-assign": "error", + "no-cond-assign": ["error", "except-parens"], + "no-confusing-arrow": ["error", { "allowParens": false }], + "no-console": "warn", + "no-const-assign": "error", + "no-constant-condition": ["error", { "checkLoops": true }], + "no-continue": "warn", + "no-control-regex": "warn", + "no-delete-var": "error", + "no-div-regex": "warn", + "no-debugger": "error", + "no-dupe-args": "error", + "no-dupe-class-members": "error", + "no-dupe-keys": "error", + "no-duplicate-case": "error", + "no-duplicate-imports": ["error", { "includeExports": true }], + "no-else-return": "error", + "no-empty": ["error", { "allowEmptyCatch": false }], + "no-empty-character-class": "error", + "no-empty-function": "error", + "no-empty-pattern": "error", + "no-eq-null": "error", + "no-eval": "error", + "no-ex-assign": "error", + "no-extend-native": "error", + "no-extra-bind": "error", + "no-extra-boolean-cast": "error", + "no-extra-label": "warn", + "no-extra-parens": ["warn", "all", { "nestedBinaryExpressions": false }], + "no-extra-semi": "error", + "no-fallthrough": "error", + "no-floating-decimal": "error", + "no-func-assign": "error", + "no-implicit-coercion": "warn", + "no-implicit-globals": "error", + "no-implied-eval": "error", + "no-inline-comments": "off", + "no-inner-declarations": ["error", "functions"], + "no-invalid-regexp": "error", + "no-invalid-this": "warn", + "no-irregular-whitespace": ["warn", { + "skipStrings": false, + "skipRegExps": false, + "skipComments": true, + "skipTemplates": false + }], + "no-iterator": "error", + "no-label-var": "error", + "no-labels": "off", + "no-lone-blocks": "error", + "no-lonely-if": "warn", + "no-loop-func": "error", + "no-magic-numbers": ["warn", { + "ignoreArrayIndexes": true, + "ignore": [0, 1, 2] + }], + "no-mixed-operators": ["warn", { "allowSamePrecedence": true }], + "no-mixed-requires": ["error", { "allowCall": true }], + "no-mixed-spaces-and-tabs": "error", + "no-multi-spaces": ["error", { + "exceptions": { + "AssignmentExpression": true, + "VariableDeclarator": true + } + }], + "no-multi-str": "error", + "no-multiple-empty-lines": ["warn", { "max": 2 }], + "no-native-reassign": "error", + "no-negated-condition": "warn", + "no-negated-in-lhs": "error", + "no-nested-ternary": "error", + "no-new": "warn", + "no-new-func": "error", + "no-new-object": "warn", + "no-new-require": "error", + "no-new-symbol": "error", + "no-new-wrappers": "warn", + "no-obj-calls": "error", + "no-octal": "error", + "no-octal-escape": "error", + "no-param-reassign": ["error", { "props": true }], + "no-path-concat": "error", + "no-plusplus": "off", + "no-process-env": "off", + "no-process-exit": "error", + "no-proto": "error", + "no-prototype-builtins": "warn", + "no-redeclare": "error", + "no-regex-spaces": "error", + "no-return-assign": ["error", "always"], + "no-script-url": "error", + "no-self-assign": "error", + "no-self-compare": "error", + "no-sequences": "error", + "no-shadow": ["warn", { + "builtinGlobals": true, + "hoist": "all" + }], + "no-shadow-restricted-names": "error", + "no-spaced-func": "error", + "no-sparse-arrays": "warn", + "no-sync": "error", + "no-tabs": "warn", + "no-ternary": "off", + "no-this-before-super": "error", + "no-throw-literal": "error", + "no-trailing-spaces": ["error", { "skipBlankLines": false }], + "no-undef": ["error", { "typeof": true }], + "no-undef-init": "error", + "no-undefined": "warn", + "no-underscore-dangle": "error", + "no-unexpected-multiline": "error", + "no-unmodified-loop-condition": "warn", + "no-unneeded-ternary": ["error", { "defaultAssignment": false }], + "no-unreachable": "error", + "no-unsafe-finally": "warn", + "no-unused-expressions": "error", + "no-unused-labels": "error", + "no-unused-vars": "error", + "no-use-before-define": "warn", + "no-useless-call": "error", + "no-useless-concat": "error", + "no-useless-computed-key": "error", + "no-useless-constructor": "error", + "no-useless-escape": "error", + "no-useless-rename": "error", + "no-var": "warn", + "no-void": "warn", + "no-warning-comments": "warn", + "no-whitespace-before-property": "error", + "no-with": "warn", + "object-curly-newline": ["warn", { + "minProperties": 2, + }], + "object-curly-spacing": ["error", "always", { + "objectsInObjects": true, + "arraysInObjects": true + }], + "object-property-newline": "error", + "object-shorthand": ["warn", "always"], + "one-var": ["error", "never"], + "one-var-declaration-per-line": "off", + "operator-assignment": ["error", "always"], + "operator-linebreak": ["error", "before", { + "overrides": { + "?": "ignore", + ":": "ignore" + } + }], + "padded-blocks": "off", + "prefer-arrow-callback": ["error", { + "allowNamedFunctions": true, + "allowUnboundThis": true + }], + "prefer-const": ["error", { + "destructuring": "any", + "ignoreReadBeforeAssign": false + }], + "prefer-reflect": "warn", + "prefer-rest-params": "error", + "prefer-spread": "error", + "prefer-template": "error", + "quote-props": ["error", "as-needed", { + "keywords": false, + "unnecessary": true + }], + "quotes": ["error", "single", { + "avoidEscape": true, + "allowTemplateLiterals": true + }], + "radix": ["error", "always"], + "require-jsdoc": ["error", { + "require": { + "FunctionDeclaration": true, + "MethodDefinition": false, + "ClassDeclaration": false + } + }], + "require-yield": "error", + "rest-spread-spacing": ["error", "never"], + "semi": ["error", "always"], + "semi-spacing": ["error", { "before": false, "after": true }], + "sort-imports": "warn", + "sort-vars": ["warn", { "ignoreCase": true }], + "space-before-blocks": ["error", "always"], + "space-before-function-paren": ["error", { + "anonymous": "always", + "named": "never" + }], + "space-in-parens": ["error", "never"], + "space-infix-ops": "error", + "space-unary-ops": ["error", { "words": true, "nonwords": false }], + "spaced-comment": ["error", "always", { "markers": ["*"] }], + "template-curly-spacing": ["warn", "never"], + "unicode-bom": ["error", "never"], + "use-isnan": "error", + "valid-typeof": "error", + "vars-on-top": "warn", + "wrap-iife": ["error", "outside"], + "wrap-regex": "off", + "yield-star-spacing": ["error", "after"], + "yoda": ["error", "never"], + + "valid-jsdoc": ["warn", { + "prefer": { + "arg": "param", + "argument": "param", + "augments": "extends", + "constant": "const", + "constructor": "class", + "defaultvalue": "default", + "desc": "description", + "exception": "throws", + "file": "overview", + "fileoverview": "overview", + "fires": "emits", + "func": "function", + "host": "external", + "property": "prop", + "returns": "return", + "virtual": "abstract" + }, + "preferType": { + "boolean": "Boolean", + "number": "Number", + "object": "Object", + "string": "String", + "function": "Function", + "promise": "Promise" + }, + "requireParamDescription": true, + "requireReturnDescription": false, + "requireReturn": false, + "requireReturnType": true + }] + } + +} diff --git a/samples/stored-procedures/bulkDelete_underscoreAPI.js b/samples/stored-procedures/bulkDelete_underscoreAPI.js index 97241f2..21e1ab0 100644 --- a/samples/stored-procedures/bulkDelete_underscoreAPI.js +++ b/samples/stored-procedures/bulkDelete_underscoreAPI.js @@ -4,7 +4,7 @@ * @param {Object} filterObj = {} An object containing the attributes and values to filter documents on. A document must have each of the matching attributes and values in this object to be deleted. A special case is made for a value of 'any'. This will delete documents which have the given attribute, regardless of its value. Passing an empty or undefined filterObj will delete all the documents in the collection. * @return {responseBody} */ -function clear(filterObj) { +function bulkDelete(filterObj) { // set default filter object filterObj = filterObj || {}; @@ -71,7 +71,7 @@ function clear(filterObj) { * @param {String} info.continuation The continuation token, if any was passed * @return {responseBody} */ - const handler = function handler(err, docs, info) { + const filterHandler = function filterHandler(err, docs, info) { if (err) throw err; if (docs.length > 0) { @@ -102,7 +102,7 @@ function clear(filterObj) { return doc.hasOwnProperty(filterKey) && (doc[filterKey] === filterObj[filterKey] || filterKey === 'any'); }); - }, { continuation: continuationToken }, handler); + }, { continuation: continuationToken }, filterHandler); // if the filter request is not accepted due to timeout, return the response with a continuation if (!accepted) response.setBody(responseBody); diff --git a/samples/stored-procedures/count_underscoreAPI.js b/samples/stored-procedures/count_underscoreAPI.js index 140eb54..5e2c730 100644 --- a/samples/stored-procedures/count_underscoreAPI.js +++ b/samples/stored-procedures/count_underscoreAPI.js @@ -5,7 +5,7 @@ * @param {String} [continuationToken] The previous continuation token, if any was passed * @return {responseBody} */ -function length(filterObj, continuationToken) { +function count(filterObj, continuationToken) { // set default filter object filterObj = filterObj || {}; @@ -43,7 +43,7 @@ function length(filterObj, continuationToken) { * @param {String} info.continuation The continuation token, if any was passed * @return {responseBody} */ - const handler = function handler(err, docs, info) { + const filterHandler = function filterHandler(err, docs, info) { if (err) throw err; // if documents were found, add them to the running documents total @@ -65,7 +65,7 @@ function length(filterObj, continuationToken) { return doc.hasOwnProperty(filterKey) && (doc[filterKey] === filterObj[filterKey] || filterKey === 'any'); }); - }, { continuation: continuationToken }, handler); + }, { continuation: continuationToken }, filterHandler); // if the filter request is not accepted due to timeout, return the response with a continuation if (!accepted) { From a449eb006260af52594a3b8aad6d89ab4e6a08fb Mon Sep 17 00:00:00 2001 From: "Daniel W. Hieber" Date: Fri, 16 Sep 2016 17:21:43 -0500 Subject: [PATCH 14/18] use filterKey & filterValue as params rather than filterObj --- .../bulkDelete_underscoreAPI.js | 21 ++++++++++------ .../stored-procedures/count_underscoreAPI.js | 25 +++++++++++-------- 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/samples/stored-procedures/bulkDelete_underscoreAPI.js b/samples/stored-procedures/bulkDelete_underscoreAPI.js index 21e1ab0..81a04a8 100644 --- a/samples/stored-procedures/bulkDelete_underscoreAPI.js +++ b/samples/stored-procedures/bulkDelete_underscoreAPI.js @@ -1,13 +1,15 @@ /** * A stored procedure for Azure DocumentDB which deletes documents with a specified filter key and value * @function - * @param {Object} filterObj = {} An object containing the attributes and values to filter documents on. A document must have each of the matching attributes and values in this object to be deleted. A special case is made for a value of 'any'. This will delete documents which have the given attribute, regardless of its value. Passing an empty or undefined filterObj will delete all the documents in the collection. + * @param {String} [filterKey] A key to filter documents on. Only documents with the specified key are deleted. If no key is provided, all documents are deleted. If you would like to also specify a value for this key, pass the filterValue parameter as well. The filterKey parameter must be pesent if the filterValue is present. + * @param {Any} [filterValue] If provided, the value that the filterKey must have in order for the document to be deleted. If no filterValue is provided, all documents with the specified filterKey are deleted. * @return {responseBody} */ -function bulkDelete(filterObj) { +function bulkDelete(filterKey, filterValue) { - // set default filter object - filterObj = filterObj || {}; + if (filterValue && !filterKey) { + throw new Error('If the "filterValue" parameter is provided, the "filterKey" parameter must be provided as well.'); + } const response = __.response; // get the response object @@ -98,10 +100,13 @@ function bulkDelete(filterObj) { // NB: The filter function must be inlined in order to take advantage of index // (otherwise it will be a full scan). const accepted = __.filter(function filter(doc) { - return Object.keys(filterObj).every(function checkProperty(filterKey) { - return doc.hasOwnProperty(filterKey) - && (doc[filterKey] === filterObj[filterKey] || filterKey === 'any'); - }); + + if (filterValue) { + return doc[filterKey] === filterValue; + } + + return doc.hasOwnProperty(filterKey); + }, { continuation: continuationToken }, filterHandler); // if the filter request is not accepted due to timeout, return the response with a continuation diff --git a/samples/stored-procedures/count_underscoreAPI.js b/samples/stored-procedures/count_underscoreAPI.js index 5e2c730..0371964 100644 --- a/samples/stored-procedures/count_underscoreAPI.js +++ b/samples/stored-procedures/count_underscoreAPI.js @@ -1,14 +1,16 @@ /** - * A stored procedure for Azure DocumentDB which gets a count of documents in a collection using the .filter() method of the collection. + * A stored procedure for Azure DocumentDB which counts documents with a specified filter key and value * @function - * @param {Object} filterObj = {} An object containing the attributes and values to filter documents on. A document must have each of the matching attributes and values in this object to be returned. A special case is made for a value of 'any'. This will return documents which have the given attribute, regardless of its value. - * @param {String} [continuationToken] The previous continuation token, if any was passed + * @param {String} [filterKey] A key to filter documents on. Only documents with the specified key are returned. If no key is provided, all documents are returned. If you would like to also specify a value for this key, pass the filterValue parameter as well. This parameter must be pesent if the filterValue is present. + * @param {Any} [filterValue] If provided, the value that the filterKey must have in order for the document to be returned. If no filterValue is provided, all documents with the specified filterKey are returned. + * @param {String} [continuationToken] A continuation token, if one was returned from the previous request. * @return {responseBody} */ -function count(filterObj, continuationToken) { +function count(filterKey, filterValue, continuationToken) { - // set default filter object - filterObj = filterObj || {}; + if (filterValue && !filterKey) { + throw new Error('If the "filterValue" parameter is provided, the "filterKey" parameter must be provided as well.'); + } const response = __.response; // get the response object @@ -61,10 +63,13 @@ function count(filterObj, continuationToken) { // filter the collection for documents using the filter object const accepted = __.filter(function filter(doc) { - return Object.keys(filterObj).every(function checkProperty(filterKey) { - return doc.hasOwnProperty(filterKey) - && (doc[filterKey] === filterObj[filterKey] || filterKey === 'any'); - }); + + if (filterValue) { + return doc[filterKey] === filterValue; + } + + return doc.hasOwnProperty(filterKey); + }, { continuation: continuationToken }, filterHandler); // if the filter request is not accepted due to timeout, return the response with a continuation From 780d08e981da4fe4809a3748018f133c736f111c Mon Sep 17 00:00:00 2001 From: "Daniel W. Hieber" Date: Fri, 16 Sep 2016 17:22:42 -0500 Subject: [PATCH 15/18] remove .eslintrc --- .eslintrc | 345 ------------------------------------------------------ 1 file changed, 345 deletions(-) delete mode 100644 .eslintrc diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index 43a99ad..0000000 --- a/.eslintrc +++ /dev/null @@ -1,345 +0,0 @@ -{ - - "parserOptions": { - "ecmaVersion": 7, - "ecmaFeatures": { - "impliedStrict": true - } - }, - - "env": { - "es6": true, - "jasmine": true, - "node": true - }, - - "rules": { - "id-blacklist": ["error"], - "no-restricted-globals": ["error"], - "no-restricted-imports": ["error"], - "no-restricted-modules": ["error"], - "no-restricted-syntax": ["error"], - - "accessor-pairs": "warn", - "array-callback-return": "warn", - "arrow-body-style": ["warn", "as-needed"], - "array-bracket-spacing": ["error", "never", { - "singleValue": false, - "objectsInArrays": false, - "arraysInArrays": false - }], - "arrow-parens": ["error", "as-needed"], - "arrow-spacing": ["error", { "before": true, "after": true }], - "block-scoped-var": "warn", - "block-spacing": ["error", "always"], - "brace-style": ["error", "1tbs", { "allowSingleLine": true }], - "callback-return": "error", - "camelcase": ["warn", { "properties": "always" }], - "comma-dangle": ["error", "always-multiline"], - "comma-spacing": ["error", { "before": false, "after": true }], - "comma-style": ["error", "last"], - "complexity": "off", - "computed-property-spacing": ["error", "never"], - "consistent-return": "warn", - "consistent-this": "off", - "constructor-super": "error", - "curly": ["error", "multi-line", "consistent"], - "default-case": "error", - "dot-location": ["error", "property"], - "dot-notation": ["error", { "allowKeywords": true }], - "eqeqeq": ["warn", "always"], - "eol-last": "error", - "func-names": ["error", "always"], - "func-style": ["error", "expression", { "allowArrowFunctions": true }], - "generator-star-spacing": ["error", { "before": false, "after": true }], - "global-require": "warn", - "guard-for-in": "warn", - "handle-callback-err": "error", - "id-length": "off", - "id-match": "off", - "indent": ["error", 2, { "SwitchCase": 1 }], - "init-declarations": ["warn", "always"], - "key-spacing": ["error", { - "beforeColon": false, - "afterColon": true, - "mode": "minimum" - }], - "keyword-spacing": ["error", { "before": true, "after": true }], - "linebreak-style": ["off"], - "lines-around-comment": ["warn", { - "beforeBlockComment": true, - "afterBlockComment": false, - "beforeLineComment": false, - "afterLineComment": false, - "allowBlockStart": true, - "allowBlockEnd": false, - "allowObjectStart": false, - "allowObjectEnd": false, - "allowArrayStart": false, - "allowArrayEnd": false - }], - "max-depth": "warn", - "max-len": ["warn", { - "code": 100, - "ignoreUrls": true, - "ignoreComments": true - }], - "max-lines": "off", - "max-nested-callbacks": ["warn", 2], - "max-params": ["warn", 4], - "max-statements": ["warn", 10], - "max-statements-per-line": ["warn", { "max": 2 }], - "multiline-ternary": "off", - "new-cap": ["error", { - "newIsCap": true, - "capIsNew": true, - "properties": true - }], - "new-parens": "off", - "newline-after-var": ["warn", "always"], - "newline-before-return": "off", - "newline-per-chained-call": ["warn", { "ignoreChainWithDepth": 2 }], - "no-alert": "warn", - "no-array-constructor": "warn", - "no-bitwise": "warn", - "no-caller": "error", - "no-case-declarations": "error", - "no-catch-shadow": "error", - "no-class-assign": "error", - "no-cond-assign": ["error", "except-parens"], - "no-confusing-arrow": ["error", { "allowParens": false }], - "no-console": "warn", - "no-const-assign": "error", - "no-constant-condition": ["error", { "checkLoops": true }], - "no-continue": "warn", - "no-control-regex": "warn", - "no-delete-var": "error", - "no-div-regex": "warn", - "no-debugger": "error", - "no-dupe-args": "error", - "no-dupe-class-members": "error", - "no-dupe-keys": "error", - "no-duplicate-case": "error", - "no-duplicate-imports": ["error", { "includeExports": true }], - "no-else-return": "error", - "no-empty": ["error", { "allowEmptyCatch": false }], - "no-empty-character-class": "error", - "no-empty-function": "error", - "no-empty-pattern": "error", - "no-eq-null": "error", - "no-eval": "error", - "no-ex-assign": "error", - "no-extend-native": "error", - "no-extra-bind": "error", - "no-extra-boolean-cast": "error", - "no-extra-label": "warn", - "no-extra-parens": ["warn", "all", { "nestedBinaryExpressions": false }], - "no-extra-semi": "error", - "no-fallthrough": "error", - "no-floating-decimal": "error", - "no-func-assign": "error", - "no-implicit-coercion": "warn", - "no-implicit-globals": "error", - "no-implied-eval": "error", - "no-inline-comments": "off", - "no-inner-declarations": ["error", "functions"], - "no-invalid-regexp": "error", - "no-invalid-this": "warn", - "no-irregular-whitespace": ["warn", { - "skipStrings": false, - "skipRegExps": false, - "skipComments": true, - "skipTemplates": false - }], - "no-iterator": "error", - "no-label-var": "error", - "no-labels": "off", - "no-lone-blocks": "error", - "no-lonely-if": "warn", - "no-loop-func": "error", - "no-magic-numbers": ["warn", { - "ignoreArrayIndexes": true, - "ignore": [0, 1, 2] - }], - "no-mixed-operators": ["warn", { "allowSamePrecedence": true }], - "no-mixed-requires": ["error", { "allowCall": true }], - "no-mixed-spaces-and-tabs": "error", - "no-multi-spaces": ["error", { - "exceptions": { - "AssignmentExpression": true, - "VariableDeclarator": true - } - }], - "no-multi-str": "error", - "no-multiple-empty-lines": ["warn", { "max": 2 }], - "no-native-reassign": "error", - "no-negated-condition": "warn", - "no-negated-in-lhs": "error", - "no-nested-ternary": "error", - "no-new": "warn", - "no-new-func": "error", - "no-new-object": "warn", - "no-new-require": "error", - "no-new-symbol": "error", - "no-new-wrappers": "warn", - "no-obj-calls": "error", - "no-octal": "error", - "no-octal-escape": "error", - "no-param-reassign": ["error", { "props": true }], - "no-path-concat": "error", - "no-plusplus": "off", - "no-process-env": "off", - "no-process-exit": "error", - "no-proto": "error", - "no-prototype-builtins": "warn", - "no-redeclare": "error", - "no-regex-spaces": "error", - "no-return-assign": ["error", "always"], - "no-script-url": "error", - "no-self-assign": "error", - "no-self-compare": "error", - "no-sequences": "error", - "no-shadow": ["warn", { - "builtinGlobals": true, - "hoist": "all" - }], - "no-shadow-restricted-names": "error", - "no-spaced-func": "error", - "no-sparse-arrays": "warn", - "no-sync": "error", - "no-tabs": "warn", - "no-ternary": "off", - "no-this-before-super": "error", - "no-throw-literal": "error", - "no-trailing-spaces": ["error", { "skipBlankLines": false }], - "no-undef": ["error", { "typeof": true }], - "no-undef-init": "error", - "no-undefined": "warn", - "no-underscore-dangle": "error", - "no-unexpected-multiline": "error", - "no-unmodified-loop-condition": "warn", - "no-unneeded-ternary": ["error", { "defaultAssignment": false }], - "no-unreachable": "error", - "no-unsafe-finally": "warn", - "no-unused-expressions": "error", - "no-unused-labels": "error", - "no-unused-vars": "error", - "no-use-before-define": "warn", - "no-useless-call": "error", - "no-useless-concat": "error", - "no-useless-computed-key": "error", - "no-useless-constructor": "error", - "no-useless-escape": "error", - "no-useless-rename": "error", - "no-var": "warn", - "no-void": "warn", - "no-warning-comments": "warn", - "no-whitespace-before-property": "error", - "no-with": "warn", - "object-curly-newline": ["warn", { - "minProperties": 2, - }], - "object-curly-spacing": ["error", "always", { - "objectsInObjects": true, - "arraysInObjects": true - }], - "object-property-newline": "error", - "object-shorthand": ["warn", "always"], - "one-var": ["error", "never"], - "one-var-declaration-per-line": "off", - "operator-assignment": ["error", "always"], - "operator-linebreak": ["error", "before", { - "overrides": { - "?": "ignore", - ":": "ignore" - } - }], - "padded-blocks": "off", - "prefer-arrow-callback": ["error", { - "allowNamedFunctions": true, - "allowUnboundThis": true - }], - "prefer-const": ["error", { - "destructuring": "any", - "ignoreReadBeforeAssign": false - }], - "prefer-reflect": "warn", - "prefer-rest-params": "error", - "prefer-spread": "error", - "prefer-template": "error", - "quote-props": ["error", "as-needed", { - "keywords": false, - "unnecessary": true - }], - "quotes": ["error", "single", { - "avoidEscape": true, - "allowTemplateLiterals": true - }], - "radix": ["error", "always"], - "require-jsdoc": ["error", { - "require": { - "FunctionDeclaration": true, - "MethodDefinition": false, - "ClassDeclaration": false - } - }], - "require-yield": "error", - "rest-spread-spacing": ["error", "never"], - "semi": ["error", "always"], - "semi-spacing": ["error", { "before": false, "after": true }], - "sort-imports": "warn", - "sort-vars": ["warn", { "ignoreCase": true }], - "space-before-blocks": ["error", "always"], - "space-before-function-paren": ["error", { - "anonymous": "always", - "named": "never" - }], - "space-in-parens": ["error", "never"], - "space-infix-ops": "error", - "space-unary-ops": ["error", { "words": true, "nonwords": false }], - "spaced-comment": ["error", "always", { "markers": ["*"] }], - "template-curly-spacing": ["warn", "never"], - "unicode-bom": ["error", "never"], - "use-isnan": "error", - "valid-typeof": "error", - "vars-on-top": "warn", - "wrap-iife": ["error", "outside"], - "wrap-regex": "off", - "yield-star-spacing": ["error", "after"], - "yoda": ["error", "never"], - - "valid-jsdoc": ["warn", { - "prefer": { - "arg": "param", - "argument": "param", - "augments": "extends", - "constant": "const", - "constructor": "class", - "defaultvalue": "default", - "desc": "description", - "exception": "throws", - "file": "overview", - "fileoverview": "overview", - "fires": "emits", - "func": "function", - "host": "external", - "property": "prop", - "returns": "return", - "virtual": "abstract" - }, - "preferType": { - "boolean": "Boolean", - "number": "Number", - "object": "Object", - "string": "String", - "function": "Function", - "promise": "Promise" - }, - "requireParamDescription": true, - "requireReturnDescription": false, - "requireReturn": false, - "requireReturnType": true - }] - } - -} From 584a8272844c5abb30647bb0a1e34016cc0b6201 Mon Sep 17 00:00:00 2001 From: "Daniel W. Hieber" Date: Fri, 16 Sep 2016 17:31:10 -0500 Subject: [PATCH 16/18] fix logic in filter function --- samples/stored-procedures/bulkDelete_underscoreAPI.js | 4 +++- samples/stored-procedures/count_underscoreAPI.js | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/samples/stored-procedures/bulkDelete_underscoreAPI.js b/samples/stored-procedures/bulkDelete_underscoreAPI.js index 81a04a8..40b216d 100644 --- a/samples/stored-procedures/bulkDelete_underscoreAPI.js +++ b/samples/stored-procedures/bulkDelete_underscoreAPI.js @@ -103,9 +103,11 @@ function bulkDelete(filterKey, filterValue) { if (filterValue) { return doc[filterKey] === filterValue; + } else if (filterKey) { + return doc.hasOwnProperty(filterKey); } - return doc.hasOwnProperty(filterKey); + return true; }, { continuation: continuationToken }, filterHandler); diff --git a/samples/stored-procedures/count_underscoreAPI.js b/samples/stored-procedures/count_underscoreAPI.js index 0371964..58bce9d 100644 --- a/samples/stored-procedures/count_underscoreAPI.js +++ b/samples/stored-procedures/count_underscoreAPI.js @@ -66,9 +66,11 @@ function count(filterKey, filterValue, continuationToken) { if (filterValue) { return doc[filterKey] === filterValue; + } else if (filterKey) { + return doc.hasOwnProperty(filterKey); } - return doc.hasOwnProperty(filterKey); + return true; }, { continuation: continuationToken }, filterHandler); From 321329b9f3bf4ed76d039167f87f7c4bd93c9053 Mon Sep 17 00:00:00 2001 From: "Daniel W. Hieber" Date: Fri, 16 Sep 2016 17:33:22 -0500 Subject: [PATCH 17/18] temporarily rename files --- .../{BulkImport.js => BulkImportUpper.js} | 118 ++++++++-------- .../{Count.js => CountUpper.js} | 132 +++++++++--------- .../{SimpleScript.js => SimpleScriptUpper.js} | 52 +++---- 3 files changed, 151 insertions(+), 151 deletions(-) rename samples/stored-procedures/{BulkImport.js => BulkImportUpper.js} (97%) rename samples/stored-procedures/{Count.js => CountUpper.js} (98%) rename samples/stored-procedures/{SimpleScript.js => SimpleScriptUpper.js} (97%) diff --git a/samples/stored-procedures/BulkImport.js b/samples/stored-procedures/BulkImportUpper.js similarity index 97% rename from samples/stored-procedures/BulkImport.js rename to samples/stored-procedures/BulkImportUpper.js index 11217bd..f784669 100644 --- a/samples/stored-procedures/BulkImport.js +++ b/samples/stored-procedures/BulkImportUpper.js @@ -1,59 +1,59 @@ -/** -* This script called as stored procedure to import lots of documents in one batch. -* The script sets response body to the number of docs imported and is called multiple times -* by the client until total number of docs desired by the client is imported. -* @param {Object[]} docs - Array of documents to import. -*/ -function bulkImport(docs) { - var collection = getContext().getCollection(); - var collectionLink = collection.getSelfLink(); - - // The count of imported docs, also used as current doc index. - var count = 0; - - // Validate input. - if (!docs) throw new Error("The array is undefined or null."); - - var docsLength = docs.length; - if (docsLength == 0) { - getContext().getResponse().setBody(0); - return; - } - - // Call the CRUD API to create a document. - tryCreate(docs[count], callback); - - // Note that there are 2 exit conditions: - // 1) The createDocument request was not accepted. - // In this case the callback will not be called, we just call setBody and we are done. - // 2) The callback was called docs.length times. - // In this case all documents were created and we don't need to call tryCreate anymore. Just call setBody and we are done. - function tryCreate(doc, callback) { - var isAccepted = collection.createDocument(collectionLink, doc, callback); - - // If the request was accepted, callback will be called. - // Otherwise report current count back to the client, - // which will call the script again with remaining set of docs. - // This condition will happen when this stored procedure has been running too long - // and is about to get cancelled by the server. This will allow the calling client - // to resume this batch from the point we got to before isAccepted was set to false - if (!isAccepted) getContext().getResponse().setBody(count); - } - - // This is called when collection.createDocument is done and the document has been persisted. - function callback(err, doc, options) { - if (err) throw err; - - // One more document has been inserted, increment the count. - count++; - - if (count >= docsLength) { - // If we have created all documents, we are done. Just set the response. - getContext().getResponse().setBody(count); - } else { - // Create next document. - tryCreate(docs[count], callback); - } - } -} - +/** +* This script called as stored procedure to import lots of documents in one batch. +* The script sets response body to the number of docs imported and is called multiple times +* by the client until total number of docs desired by the client is imported. +* @param {Object[]} docs - Array of documents to import. +*/ +function bulkImport(docs) { + var collection = getContext().getCollection(); + var collectionLink = collection.getSelfLink(); + + // The count of imported docs, also used as current doc index. + var count = 0; + + // Validate input. + if (!docs) throw new Error("The array is undefined or null."); + + var docsLength = docs.length; + if (docsLength == 0) { + getContext().getResponse().setBody(0); + return; + } + + // Call the CRUD API to create a document. + tryCreate(docs[count], callback); + + // Note that there are 2 exit conditions: + // 1) The createDocument request was not accepted. + // In this case the callback will not be called, we just call setBody and we are done. + // 2) The callback was called docs.length times. + // In this case all documents were created and we don't need to call tryCreate anymore. Just call setBody and we are done. + function tryCreate(doc, callback) { + var isAccepted = collection.createDocument(collectionLink, doc, callback); + + // If the request was accepted, callback will be called. + // Otherwise report current count back to the client, + // which will call the script again with remaining set of docs. + // This condition will happen when this stored procedure has been running too long + // and is about to get cancelled by the server. This will allow the calling client + // to resume this batch from the point we got to before isAccepted was set to false + if (!isAccepted) getContext().getResponse().setBody(count); + } + + // This is called when collection.createDocument is done and the document has been persisted. + function callback(err, doc, options) { + if (err) throw err; + + // One more document has been inserted, increment the count. + count++; + + if (count >= docsLength) { + // If we have created all documents, we are done. Just set the response. + getContext().getResponse().setBody(count); + } else { + // Create next document. + tryCreate(docs[count], callback); + } + } +} + diff --git a/samples/stored-procedures/Count.js b/samples/stored-procedures/CountUpper.js similarity index 98% rename from samples/stored-procedures/Count.js rename to samples/stored-procedures/CountUpper.js index 0f81bf0..296570c 100644 --- a/samples/stored-procedures/Count.js +++ b/samples/stored-procedures/CountUpper.js @@ -1,66 +1,66 @@ -/** -* This is executed as stored procedure to count the number of docs in the collection. -* To avoid script timeout on the server when there are lots of documents (100K+), the script executed in batches, -* each batch counts docs to some number and returns continuation token. -* The script is run multiple times, starting from empty continuation, -* then using continuation returned by last invocation script until continuation returned by the script is null/empty string. -* -* @param {String} filterQuery - Optional filter for query (e.g. "SELECT * FROM docs WHERE docs.category = 'food'"). -* @param {String} continuationToken - The continuation token passed by request, continue counting from this token. -*/ -function count(filterQuery, continuationToken) { - var collection = getContext().getCollection(); - var maxResult = 25; // MAX number of docs to process in one batch, when reached, return to client/request continuation. - // intentionally set low to demonstrate the concept. This can be much higher. Try experimenting. - // We've had it in to the high thousands before seeing the stored proceudre timing out. - - // The number of documents counted. - var result = 0; - - tryQuery(continuationToken); - - // Helper method to check for max result and call query. - function tryQuery(nextContinuationToken) { - var responseOptions = { continuation: nextContinuationToken, pageSize : maxResult }; - - // In case the server is running this script for long time/near timeout, it would return false, - // in this case we set the response to current continuation token, - // and the client will run this script again starting from this continuation. - // When the client calls this script 1st time, is passes empty continuation token. - if (result >= maxResult || !query(responseOptions)) { - setBody(nextContinuationToken); - } - } - - function query(responseOptions) { - // For empty query string, use readDocuments rather than queryDocuments -- it's faster as doesn't need to process the query. - return (filterQuery && filterQuery.length) ? - collection.queryDocuments(collection.getSelfLink(), filterQuery, responseOptions, onReadDocuments) : - collection.readDocuments(collection.getSelfLink(), responseOptions, onReadDocuments); - } - - // This is callback is called from collection.queryDocuments/readDocuments. - function onReadDocuments(err, docFeed, responseOptions) { - if (err) { - throw 'Error while reading document: ' + err; - } - - // Increament the number of documents counted so far. - result += docFeed.length; - - // If there is continuation, call query again with it, - // otherwise we are done, in which case set continuation to null. - if (responseOptions.continuation) { - tryQuery(responseOptions.continuation); - } else { - setBody(null); - } - } - - // Set response body: use an object the client is expecting (2 properties: result and continuationToken). - function setBody(continuationToken) { - var body = { count: result, continuationToken: continuationToken }; - getContext().getResponse().setBody(body); - } -} - +/** +* This is executed as stored procedure to count the number of docs in the collection. +* To avoid script timeout on the server when there are lots of documents (100K+), the script executed in batches, +* each batch counts docs to some number and returns continuation token. +* The script is run multiple times, starting from empty continuation, +* then using continuation returned by last invocation script until continuation returned by the script is null/empty string. +* +* @param {String} filterQuery - Optional filter for query (e.g. "SELECT * FROM docs WHERE docs.category = 'food'"). +* @param {String} continuationToken - The continuation token passed by request, continue counting from this token. +*/ +function count(filterQuery, continuationToken) { + var collection = getContext().getCollection(); + var maxResult = 25; // MAX number of docs to process in one batch, when reached, return to client/request continuation. + // intentionally set low to demonstrate the concept. This can be much higher. Try experimenting. + // We've had it in to the high thousands before seeing the stored proceudre timing out. + + // The number of documents counted. + var result = 0; + + tryQuery(continuationToken); + + // Helper method to check for max result and call query. + function tryQuery(nextContinuationToken) { + var responseOptions = { continuation: nextContinuationToken, pageSize : maxResult }; + + // In case the server is running this script for long time/near timeout, it would return false, + // in this case we set the response to current continuation token, + // and the client will run this script again starting from this continuation. + // When the client calls this script 1st time, is passes empty continuation token. + if (result >= maxResult || !query(responseOptions)) { + setBody(nextContinuationToken); + } + } + + function query(responseOptions) { + // For empty query string, use readDocuments rather than queryDocuments -- it's faster as doesn't need to process the query. + return (filterQuery && filterQuery.length) ? + collection.queryDocuments(collection.getSelfLink(), filterQuery, responseOptions, onReadDocuments) : + collection.readDocuments(collection.getSelfLink(), responseOptions, onReadDocuments); + } + + // This is callback is called from collection.queryDocuments/readDocuments. + function onReadDocuments(err, docFeed, responseOptions) { + if (err) { + throw 'Error while reading document: ' + err; + } + + // Increament the number of documents counted so far. + result += docFeed.length; + + // If there is continuation, call query again with it, + // otherwise we are done, in which case set continuation to null. + if (responseOptions.continuation) { + tryQuery(responseOptions.continuation); + } else { + setBody(null); + } + } + + // Set response body: use an object the client is expecting (2 properties: result and continuationToken). + function setBody(continuationToken) { + var body = { count: result, continuationToken: continuationToken }; + getContext().getResponse().setBody(body); + } +} + diff --git a/samples/stored-procedures/SimpleScript.js b/samples/stored-procedures/SimpleScriptUpper.js similarity index 97% rename from samples/stored-procedures/SimpleScript.js rename to samples/stored-procedures/SimpleScriptUpper.js index 532c975..c515cf0 100644 --- a/samples/stored-procedures/SimpleScript.js +++ b/samples/stored-procedures/SimpleScriptUpper.js @@ -1,26 +1,26 @@ -/** -* This is run as stored procedure and does the following: -* - get 1st document in the collection, convert to JSON, prepend string specified by the prefix parameter -* and set response to the result of that. -* -* @param {String} prefix - The string to prepend to the 1st document in collection. -*/ -function simple(prefix) { - var collection = getContext().getCollection(); - - // Query documents and take 1st item. - var isAccepted = collection.queryDocuments( - collection.getSelfLink(), - 'SELECT * FROM root r', - function (err, feed, options) { - if (err) throw err; - - // Check the feed and if it's empty, set the body to 'no docs found', - // Otherwise just take 1st element from the feed. - if (!feed || !feed.length) getContext().getResponse().setBody("no docs found"); - else getContext().getResponse().setBody(prefix + JSON.stringify(feed[0])); - }); - - if (!isAccepted) throw new Error("The query wasn't accepted by the server. Try again/use continuation token between API and script."); -} - +/** +* This is run as stored procedure and does the following: +* - get 1st document in the collection, convert to JSON, prepend string specified by the prefix parameter +* and set response to the result of that. +* +* @param {String} prefix - The string to prepend to the 1st document in collection. +*/ +function simple(prefix) { + var collection = getContext().getCollection(); + + // Query documents and take 1st item. + var isAccepted = collection.queryDocuments( + collection.getSelfLink(), + 'SELECT * FROM root r', + function (err, feed, options) { + if (err) throw err; + + // Check the feed and if it's empty, set the body to 'no docs found', + // Otherwise just take 1st element from the feed. + if (!feed || !feed.length) getContext().getResponse().setBody("no docs found"); + else getContext().getResponse().setBody(prefix + JSON.stringify(feed[0])); + }); + + if (!isAccepted) throw new Error("The query wasn't accepted by the server. Try again/use continuation token between API and script."); +} + From 86432761d5614a74cc5248bb0b306b194944292a Mon Sep 17 00:00:00 2001 From: "Daniel W. Hieber" Date: Fri, 16 Sep 2016 17:34:04 -0500 Subject: [PATCH 18/18] camelCase filenames for consistency --- samples/stored-procedures/{BulkImportUpper.js => bulkImport.js} | 0 samples/stored-procedures/{CountUpper.js => count.js} | 0 .../stored-procedures/{SimpleScriptUpper.js => simpleScript.js} | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename samples/stored-procedures/{BulkImportUpper.js => bulkImport.js} (100%) rename samples/stored-procedures/{CountUpper.js => count.js} (100%) rename samples/stored-procedures/{SimpleScriptUpper.js => simpleScript.js} (100%) diff --git a/samples/stored-procedures/BulkImportUpper.js b/samples/stored-procedures/bulkImport.js similarity index 100% rename from samples/stored-procedures/BulkImportUpper.js rename to samples/stored-procedures/bulkImport.js diff --git a/samples/stored-procedures/CountUpper.js b/samples/stored-procedures/count.js similarity index 100% rename from samples/stored-procedures/CountUpper.js rename to samples/stored-procedures/count.js diff --git a/samples/stored-procedures/SimpleScriptUpper.js b/samples/stored-procedures/simpleScript.js similarity index 100% rename from samples/stored-procedures/SimpleScriptUpper.js rename to samples/stored-procedures/simpleScript.js