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': {} diff --git a/src/Controllers/DatabaseController.js b/src/Controllers/DatabaseController.js index 8d50d14c5c..0c45c04eb7 100644 --- a/src/Controllers/DatabaseController.js +++ b/src/Controllers/DatabaseController.js @@ -711,11 +711,12 @@ DatabaseController.prototype.find = function(className, query, { acl, sort = {}, count, - keys + keys, + op } = {}) { 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..717b53f907 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,18 +387,22 @@ 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(); } + 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).then((results) => { + this.className, this.restWhere, findOptions).then((results) => { if (this.className === '_User') { for (var result of results) { delete result.password; @@ -473,7 +477,6 @@ function includePath(config, auth, response, path, restOptions = {}) { return response; } let pointersHash = {}; - var objectIds = {}; for (var pointer of pointers) { if (!pointer) { continue; @@ -481,8 +484,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 +507,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); })