Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds support for multiple $in, pointer / relation queries on $or #769

Merged
merged 4 commits into from
Mar 3, 2016
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 51 additions & 1 deletion spec/ParseRelation.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,57 @@ describe('Parse.Relation testing', () => {
success: function(list) {
equal(list.length, 1, "There should be only one result");
equal(list[0].id, parent2.id,
"Should have gotten back the right result");
"Should have gotten back the right result");
done();
}
});
}
});
}
});
});

it("queries on relation fields with multiple ins", (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("child");
relation.add(childObjects[0]);
relation.add(childObjects[1]);
relation.add(childObjects[2]);
var parent2 = new ParentObject();
parent2.set("x", 3);
var relation2 = parent2.relation("child");
relation2.add(childObjects[4]);
relation2.add(childObjects[5]);
relation2.add(childObjects[6]);

var otherChild2 = parent2.relation("otherChild");
otherChild2.add(childObjects[0]);
otherChild2.add(childObjects[1]);
otherChild2.add(childObjects[2]);

var parents = [];
parents.push(parent);
parents.push(parent2);
Parse.Object.saveAll(parents, {
success: function() {
var query = new Parse.Query(ParentObject);
var objects = [];
objects.push(childObjects[0]);
query.containedIn("child", objects);
query.containedIn("otherChild", [childObjects[0]]);
query.find({
success: function(list) {
equal(list.length, 2, "There should be only one result");
done();
}
});
Expand Down
46 changes: 24 additions & 22 deletions src/Controllers/DatabaseController.js
Original file line number Diff line number Diff line change
Expand Up @@ -397,31 +397,33 @@ DatabaseController.prototype.owningIds = function(className, key, relatedIds) {
// Modifies query so that it no longer has $in on relation fields, or
// equal-to-pointer constraints on relation fields.
// Returns a promise that resolves when query is mutated
// TODO: this only handles one of these at a time - make it handle more
DatabaseController.prototype.reduceInRelation = function(className, query, schema) {
// Search for an in-relation or equal-to-relation
for (var key in query) {
if (query[key] &&
(query[key]['$in'] || query[key].__type == 'Pointer')) {
var t = schema.getExpectedType(className, key);
var match = t ? t.match(/^relation<(.*)>$/) : false;
if (!match) {
continue;
}
var relatedClassName = match[1];
var relatedIds;
if (query[key]['$in']) {
relatedIds = query[key]['$in'].map(r => r.objectId);
} else {
relatedIds = [query[key].objectId];
// Make it sequential for now, not sure of paralleization side effects
return Object.keys(query).reduce((promise, key) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest using Promise.all rather than reduce when possible, you should get slightly better perf that way, and IMO it's more readable.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was wondering about race conditions in that case, but that's fine for me

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all can lead to race conditions, but I think in this case it won't.

return promise.then(() => {
if (query[key] &&
(query[key]['$in'] || query[key].__type == 'Pointer')) {
let t = schema.getExpectedType(className, key);
let match = t ? t.match(/^relation<(.*)>$/) : false;
if (!match) {
return;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should produce an inconsistent return type from the function, not sure if that is expected behavior or not. You are returning void or a Promise (later one down the line). Maybe convert to Promise.resolve(), but don't feel strongly.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's enclosed into a promise.then() , so that's pretty much the same as doing return Promise.resolve();

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still an inconsistent return type from a closure(lambda?), but nature of JS wins here.

}
let relatedClassName = match[1];
let relatedIds;
if (query[key]['$in']) {
relatedIds = query[key]['$in'].map(r => r.objectId);
} else {
relatedIds = [query[key].objectId];
}
return this.owningIds(className, key, relatedIds).then((ids) => {
delete query[key];
query.objectId = Object.assign({'$in': []}, query.objectId);
query.objectId['$in'] = query.objectId['$in'].concat(ids);
});
}
return this.owningIds(className, key, relatedIds).then((ids) => {
delete query[key];
query.objectId = {'$in': ids};
});
}
}
return Promise.resolve();
});
}, Promise.resolve());
};

// Modifies query so that it no longer has $relatedTo
Expand Down