From ee0626730e1b53d0d9dfa839ba6a9a1edb09d8d3 Mon Sep 17 00:00:00 2001 From: Florent Vilmart Date: Mon, 19 Sep 2016 21:40:48 -0400 Subject: [PATCH 1/3] test for repro #2005 --- spec/schemas.spec.js | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/spec/schemas.spec.js b/spec/schemas.spec.js index aa0faad3e0..1d5a9b2e17 100644 --- a/spec/schemas.spec.js +++ b/spec/schemas.spec.js @@ -1548,6 +1548,34 @@ describe('schemas', () => { }); }); + it('can query with include and CLP (issue #2005)', (done) => { + setPermissionsOnClass('AnotherObject', { + get: {"*": true}, + find: {}, + create: {'*': true}, + update: {'*': true}, + delete: {'*': true}, + addField:{'*': true} + }).then(() => { + let obj = new Parse.Object('AnObject'); + let anotherObject = new Parse.Object('AnotherObject'); + return obj.save({ + anotherObject + }) + }).then(() => { + let query = new Parse.Query('AnObject'); + query.include('anotherObject'); + return query.find(); + }).then((res) => { + expect(res.length).toBe(1); + expect(res[0].get('anotherObject')).not.toBeUndefined(); + done(); + }).catch((err) => { + jfail(err); + done(); + }) + }); + it('can add field as master (issue #1257)', (done) => { setPermissionsOnClass('AClass', { 'addField': {} From 419da581514e0bc8e92a0d102a67d083a436290d Mon Sep 17 00:00:00 2001 From: Florent Vilmart Date: Mon, 19 Sep 2016 21:41:40 -0400 Subject: [PATCH 2/3] Adds ability to override CLP op from RestQuery.execute --- src/Controllers/DatabaseController.js | 2 +- src/RestQuery.js | 17 ++++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/Controllers/DatabaseController.js b/src/Controllers/DatabaseController.js index 8d50d14c5c..c7834034ba 100644 --- a/src/Controllers/DatabaseController.js +++ b/src/Controllers/DatabaseController.js @@ -715,7 +715,7 @@ DatabaseController.prototype.find = function(className, query, { } = {}) { let isMaster = acl === undefined; let aclGroup = acl || []; - let op = typeof query.objectId == 'string' && Object.keys(query).length === 1 ? 'get' : 'find'; + op = op || (typeof query.objectId == 'string' && Object.keys(query).length === 1 ? 'get' : 'find'); let classExists = true; return this.loadSchema() .then(schemaController => { diff --git a/src/RestQuery.js b/src/RestQuery.js index 14f07c056c..79f53b78f3 100644 --- a/src/RestQuery.js +++ b/src/RestQuery.js @@ -113,11 +113,11 @@ function RestQuery(config, auth, className, restWhere = {}, restOptions = {}, cl // Returns a promise for the response - an object with optional keys // 'results' and 'count'. // TODO: consolidate the replaceX functions -RestQuery.prototype.execute = function() { +RestQuery.prototype.execute = function(executeOptions) { return Promise.resolve().then(() => { return this.buildRestWhere(); }).then(() => { - return this.runFind(); + return this.runFind(executeOptions); }).then(() => { return this.runCount(); }).then(() => { @@ -387,7 +387,7 @@ RestQuery.prototype.replaceDontSelect = function() { // Returns a promise for whether it was successful. // Populates this.response with an object that only has 'results'. -RestQuery.prototype.runFind = function() { +RestQuery.prototype.runFind = function(options = {}) { if (this.findOptions.limit === 0) { this.response = {results: []}; return Promise.resolve(); @@ -398,7 +398,7 @@ RestQuery.prototype.runFind = function() { }); } return this.config.database.find( - this.className, this.restWhere, this.findOptions).then((results) => { + this.className, this.restWhere, this.findOptions, options.op).then((results) => { if (this.className === '_User') { for (var result of results) { delete result.password; @@ -473,7 +473,6 @@ function includePath(config, auth, response, path, restOptions = {}) { return response; } let pointersHash = {}; - var objectIds = {}; for (var pointer of pointers) { if (!pointer) { continue; @@ -481,8 +480,8 @@ function includePath(config, auth, response, path, restOptions = {}) { let className = pointer.className; // only include the good pointers if (className) { - pointersHash[className] = pointersHash[className] || []; - pointersHash[className].push(pointer.objectId); + pointersHash[className] = pointersHash[className] || new Set(); + pointersHash[className].add(pointer.objectId); } } @@ -504,9 +503,9 @@ function includePath(config, auth, response, path, restOptions = {}) { } let queryPromises = Object.keys(pointersHash).map((className) => { - var where = {'objectId': {'$in': pointersHash[className]}}; + let where = {'objectId': {'$in': Array.from(pointersHash[className])}}; var query = new RestQuery(config, auth, className, where, includeRestOptions); - return query.execute().then((results) => { + return query.execute({op: 'get'}).then((results) => { results.className = className; return Promise.resolve(results); }) From 7dec71a1fe61b6b0d2d18b0906651c9028adf604 Mon Sep 17 00:00:00 2001 From: Florent Vilmart Date: Sat, 24 Sep 2016 13:44:15 -0400 Subject: [PATCH 3/3] nits --- src/Controllers/DatabaseController.js | 3 ++- src/RestQuery.js | 8 ++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/Controllers/DatabaseController.js b/src/Controllers/DatabaseController.js index c7834034ba..0c45c04eb7 100644 --- a/src/Controllers/DatabaseController.js +++ b/src/Controllers/DatabaseController.js @@ -711,7 +711,8 @@ DatabaseController.prototype.find = function(className, query, { acl, sort = {}, count, - keys + keys, + op } = {}) { let isMaster = acl === undefined; let aclGroup = acl || []; diff --git a/src/RestQuery.js b/src/RestQuery.js index 79f53b78f3..717b53f907 100644 --- a/src/RestQuery.js +++ b/src/RestQuery.js @@ -392,13 +392,17 @@ RestQuery.prototype.runFind = function(options = {}) { this.response = {results: []}; return Promise.resolve(); } + let findOptions = Object.assign({}, this.findOptions); if (this.keys) { - this.findOptions.keys = Array.from(this.keys).map((key) => { + findOptions.keys = Array.from(this.keys).map((key) => { return key.split('.')[0]; }); } + if (options.op) { + findOptions.op = options.op; + } return this.config.database.find( - this.className, this.restWhere, this.findOptions, options.op).then((results) => { + this.className, this.restWhere, findOptions).then((results) => { if (this.className === '_User') { for (var result of results) { delete result.password;