diff --git a/spec/ParseRelation.spec.js b/spec/ParseRelation.spec.js index 664a9ba9..550e4b33 100644 --- a/spec/ParseRelation.spec.js +++ b/spec/ParseRelation.spec.js @@ -287,7 +287,55 @@ describe('Parse.Relation testing', () => { query.containedIn("otherChild", [childObjects[0]]); query.find({ success: function(list) { - equal(list.length, 2, "There should be only one result"); + equal(list.length, 2, "There should be 2 results"); + done(); + } + }); + } + }); + } + }); + }); + + it("or queries on pointer and relation fields", (done) => { + var ChildObject = Parse.Object.extend("ChildObject"); + var childObjects = []; + for (var i = 0; i < 10; i++) { + childObjects.push(new ChildObject({x: i})); + } + + Parse.Object.saveAll(childObjects, { + success: function() { + var ParentObject = Parse.Object.extend("ParentObject"); + var parent = new ParentObject(); + parent.set("x", 4); + var relation = parent.relation("toChilds"); + relation.add(childObjects[0]); + relation.add(childObjects[1]); + relation.add(childObjects[2]); + + var parent2 = new ParentObject(); + parent2.set("x", 3); + parent2.set("toChild", childObjects[2]); + + var parents = []; + parents.push(parent); + parents.push(parent2); + parents.push(new ParentObject()); + + Parse.Object.saveAll(parents, { + success: function() { + var query1 = new Parse.Query(ParentObject); + query1.containedIn("toChilds", [childObjects[2]]); + var query2 = new Parse.Query(ParentObject); + query2.equalTo("toChild", childObjects[2]); + var query = Parse.Query.or(query1, query2); + query.find({ + success: function(list) { + list = list.filter(function(item){ + return item.id == parent.id || item.id == parent2.id; + }); + equal(list.length, 2, "There should be 2 results"); done(); } }); diff --git a/src/Controllers/DatabaseController.js b/src/Controllers/DatabaseController.js index 8901004d..923e6e49 100644 --- a/src/Controllers/DatabaseController.js +++ b/src/Controllers/DatabaseController.js @@ -366,13 +366,11 @@ DatabaseController.prototype.deleteEverything = function() { function keysForQuery(query) { var sublist = query['$and'] || query['$or']; if (sublist) { - var answer = new Set(); - for (var subquery of sublist) { - for (var key of keysForQuery(subquery)) { - answer.add(key); - } - } - return answer; + let answer = sublist.reduce((memo, subquery) => { + return memo.concat(keysForQuery(subquery)); + }, []); + + return new Set(answer); } return new Set(Object.keys(query)); @@ -400,6 +398,17 @@ DatabaseController.prototype.owningIds = function(className, key, relatedIds) { DatabaseController.prototype.reduceInRelation = function(className, query, schema) { // Search for an in-relation or equal-to-relation // Make it sequential for now, not sure of paralleization side effects + if (query['$or']) { + let ors = query['$or']; + return Promise.all(ors.map((aQuery, index) => { + return this.reduceInRelation(className, aQuery, schema).then((aQuery) => { + if (aQuery) { + query['$or'][index] = aQuery; + } + }) + })); + } + return Object.keys(query).reduce((promise, key) => { return promise.then(() => { if (query[key] && @@ -420,15 +429,25 @@ DatabaseController.prototype.reduceInRelation = function(className, query, schem delete query[key]; query.objectId = Object.assign({'$in': []}, query.objectId); query.objectId['$in'] = query.objectId['$in'].concat(ids); + return Promise.resolve(query); }); } }); - }, Promise.resolve()); + }, Promise.resolve()).then(() => { + return Promise.resolve(query); + }) }; // Modifies query so that it no longer has $relatedTo // Returns a promise that resolves when query is mutated DatabaseController.prototype.reduceRelationKeys = function(className, query) { + + if (query['$or']) { + return Promise.all(query['$or'].map((aQuery) => { + return this.reduceRelationKeys(className, aQuery); + })); + } + var relatedTo = query['$relatedTo']; if (relatedTo) { return this.relatedIds(