diff --git a/.gitignore b/.gitignore index ce3eff2a59..d9c04d95df 100644 --- a/.gitignore +++ b/.gitignore @@ -61,3 +61,5 @@ lib/ # Redis Dump dump.rdb + +_mongodb_runner \ No newline at end of file diff --git a/src/RestQuery.js b/src/RestQuery.js index 621700984b..dd1992e56b 100644 --- a/src/RestQuery.js +++ b/src/RestQuery.js @@ -852,31 +852,54 @@ _UnsafeRestQuery.prototype.handleExcludeKeys = function () { }; // Augments this.response with data at the paths provided in this.include. -_UnsafeRestQuery.prototype.handleInclude = function () { +_UnsafeRestQuery.prototype.handleInclude = async function () { if (this.include.length == 0) { return; } - var pathResponse = includePath( - this.config, - this.auth, - this.response, - this.include[0], - this.context, - this.restOptions - ); - if (pathResponse.then) { - return pathResponse.then(newResponse => { - this.response = newResponse; - this.include = this.include.slice(1); - return this.handleInclude(); + const indexedResults = this.response.results.reduce((indexed, result, i) => { + indexed[result.objectId] = i; + return indexed; + }, {}); + + // Build the execution tree + const executionTree = {} + this.include.forEach(path => { + let current = executionTree; + path.forEach((node) => { + if (!current[node]) { + current[node] = { + path, + children: {} + }; + } + current = current[node].children }); - } else if (this.include.length > 0) { - this.include = this.include.slice(1); - return this.handleInclude(); + }); + + const recursiveExecutionTree = async (treeNode) => { + const { path, children } = treeNode; + const pathResponse = includePath( + this.config, + this.auth, + this.response, + path, + this.context, + this.restOptions, + this, + ); + if (pathResponse.then) { + const newResponse = await pathResponse + newResponse.results.forEach(newObject => { + // We hydrate the root of each result with sub results + this.response.results[indexedResults[newObject.objectId]][path[0]] = newObject[path[0]]; + }) + } + return Promise.all(Object.values(children).map(recursiveExecutionTree)); } - return pathResponse; + await Promise.all(Object.values(executionTree).map(recursiveExecutionTree)); + this.include = [] }; //Returns a promise of a processed set of results @@ -1013,7 +1036,6 @@ function includePath(config, auth, response, path, context, restOptions = {}) { } else if (restOptions.readPreference) { includeRestOptions.readPreference = restOptions.readPreference; } - const queryPromises = Object.keys(pointersHash).map(async className => { const objectIds = Array.from(pointersHash[className]); let where; @@ -1052,7 +1074,6 @@ function includePath(config, auth, response, path, context, restOptions = {}) { } return replace; }, {}); - var resp = { results: replacePointers(response.results, path, replace), };