Merge pull request #1046 from ParsePlatform/flovilmart.fix1014
Fixes bug related to subqueries on unfetched objects
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
'use strict';
|
||||||
// This is a port of the test suite:
|
// This is a port of the test suite:
|
||||||
// hungry/js/test/parse_relation_test.js
|
// hungry/js/test/parse_relation_test.js
|
||||||
|
|
||||||
@@ -237,7 +238,7 @@ describe('Parse.Relation testing', () => {
|
|||||||
success: function(list) {
|
success: function(list) {
|
||||||
equal(list.length, 1, "There should be only one result");
|
equal(list.length, 1, "There should be only one result");
|
||||||
equal(list[0].id, parent2.id,
|
equal(list[0].id, parent2.id,
|
||||||
"Should have gotten back the right result");
|
"Should have gotten back the right result");
|
||||||
done();
|
done();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -246,7 +247,7 @@ describe('Parse.Relation testing', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("queries on relation fields with multiple ins", (done) => {
|
it("queries on relation fields with multiple ins", (done) => {
|
||||||
var ChildObject = Parse.Object.extend("ChildObject");
|
var ChildObject = Parse.Object.extend("ChildObject");
|
||||||
var childObjects = [];
|
var childObjects = [];
|
||||||
@@ -268,7 +269,7 @@ describe('Parse.Relation testing', () => {
|
|||||||
relation2.add(childObjects[4]);
|
relation2.add(childObjects[4]);
|
||||||
relation2.add(childObjects[5]);
|
relation2.add(childObjects[5]);
|
||||||
relation2.add(childObjects[6]);
|
relation2.add(childObjects[6]);
|
||||||
|
|
||||||
var otherChild2 = parent2.relation("otherChild");
|
var otherChild2 = parent2.relation("otherChild");
|
||||||
otherChild2.add(childObjects[0]);
|
otherChild2.add(childObjects[0]);
|
||||||
otherChild2.add(childObjects[1]);
|
otherChild2.add(childObjects[1]);
|
||||||
@@ -290,7 +291,7 @@ describe('Parse.Relation testing', () => {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("query on pointer and relation fields with equal", (done) => {
|
it("query on pointer and relation fields with equal", (done) => {
|
||||||
var ChildObject = Parse.Object.extend("ChildObject");
|
var ChildObject = Parse.Object.extend("ChildObject");
|
||||||
var childObjects = [];
|
var childObjects = [];
|
||||||
@@ -306,21 +307,21 @@ describe('Parse.Relation testing', () => {
|
|||||||
relation.add(childObjects[0]);
|
relation.add(childObjects[0]);
|
||||||
relation.add(childObjects[1]);
|
relation.add(childObjects[1]);
|
||||||
relation.add(childObjects[2]);
|
relation.add(childObjects[2]);
|
||||||
|
|
||||||
var parent2 = new ParentObject();
|
var parent2 = new ParentObject();
|
||||||
parent2.set("x", 3);
|
parent2.set("x", 3);
|
||||||
parent2.set("toChild", childObjects[2]);
|
parent2.set("toChild", childObjects[2]);
|
||||||
|
|
||||||
var parents = [];
|
var parents = [];
|
||||||
parents.push(parent);
|
parents.push(parent);
|
||||||
parents.push(parent2);
|
parents.push(parent2);
|
||||||
parents.push(new ParentObject());
|
parents.push(new ParentObject());
|
||||||
|
|
||||||
return Parse.Object.saveAll(parents).then(() => {
|
return Parse.Object.saveAll(parents).then(() => {
|
||||||
var query = new Parse.Query(ParentObject);
|
var query = new Parse.Query(ParentObject);
|
||||||
query.equalTo("objectId", parent.id);
|
query.equalTo("objectId", parent.id);
|
||||||
query.equalTo("toChilds", childObjects[2]);
|
query.equalTo("toChilds", childObjects[2]);
|
||||||
|
|
||||||
return query.find().then((list) => {
|
return query.find().then((list) => {
|
||||||
equal(list.length, 1, "There should be 1 result");
|
equal(list.length, 1, "There should be 1 result");
|
||||||
done();
|
done();
|
||||||
@@ -328,7 +329,7 @@ describe('Parse.Relation testing', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("query on pointer and relation fields with equal bis", (done) => {
|
it("query on pointer and relation fields with equal bis", (done) => {
|
||||||
var ChildObject = Parse.Object.extend("ChildObject");
|
var ChildObject = Parse.Object.extend("ChildObject");
|
||||||
var childObjects = [];
|
var childObjects = [];
|
||||||
@@ -344,23 +345,23 @@ describe('Parse.Relation testing', () => {
|
|||||||
relation.add(childObjects[0]);
|
relation.add(childObjects[0]);
|
||||||
relation.add(childObjects[1]);
|
relation.add(childObjects[1]);
|
||||||
relation.add(childObjects[2]);
|
relation.add(childObjects[2]);
|
||||||
|
|
||||||
var parent2 = new ParentObject();
|
var parent2 = new ParentObject();
|
||||||
parent2.set("x", 3);
|
parent2.set("x", 3);
|
||||||
parent2.relation("toChilds").add(childObjects[2]);
|
parent2.relation("toChilds").add(childObjects[2]);
|
||||||
|
|
||||||
var parents = [];
|
var parents = [];
|
||||||
parents.push(parent);
|
parents.push(parent);
|
||||||
parents.push(parent2);
|
parents.push(parent2);
|
||||||
parents.push(new ParentObject());
|
parents.push(new ParentObject());
|
||||||
|
|
||||||
return Parse.Object.saveAll(parents).then(() => {
|
return Parse.Object.saveAll(parents).then(() => {
|
||||||
var query = new Parse.Query(ParentObject);
|
var query = new Parse.Query(ParentObject);
|
||||||
query.equalTo("objectId", parent2.id);
|
query.equalTo("objectId", parent2.id);
|
||||||
// childObjects[2] is in 2 relations
|
// childObjects[2] is in 2 relations
|
||||||
// before the fix, that woul yield 2 results
|
// before the fix, that woul yield 2 results
|
||||||
query.equalTo("toChilds", childObjects[2]);
|
query.equalTo("toChilds", childObjects[2]);
|
||||||
|
|
||||||
return query.find().then((list) => {
|
return query.find().then((list) => {
|
||||||
equal(list.length, 1, "There should be 1 result");
|
equal(list.length, 1, "There should be 1 result");
|
||||||
done();
|
done();
|
||||||
@@ -368,7 +369,7 @@ describe('Parse.Relation testing', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("or queries on pointer and relation fields", (done) => {
|
it("or queries on pointer and relation fields", (done) => {
|
||||||
var ChildObject = Parse.Object.extend("ChildObject");
|
var ChildObject = Parse.Object.extend("ChildObject");
|
||||||
var childObjects = [];
|
var childObjects = [];
|
||||||
@@ -384,16 +385,16 @@ describe('Parse.Relation testing', () => {
|
|||||||
relation.add(childObjects[0]);
|
relation.add(childObjects[0]);
|
||||||
relation.add(childObjects[1]);
|
relation.add(childObjects[1]);
|
||||||
relation.add(childObjects[2]);
|
relation.add(childObjects[2]);
|
||||||
|
|
||||||
var parent2 = new ParentObject();
|
var parent2 = new ParentObject();
|
||||||
parent2.set("x", 3);
|
parent2.set("x", 3);
|
||||||
parent2.set("toChild", childObjects[2]);
|
parent2.set("toChild", childObjects[2]);
|
||||||
|
|
||||||
var parents = [];
|
var parents = [];
|
||||||
parents.push(parent);
|
parents.push(parent);
|
||||||
parents.push(parent2);
|
parents.push(parent2);
|
||||||
parents.push(new ParentObject());
|
parents.push(new ParentObject());
|
||||||
|
|
||||||
return Parse.Object.saveAll(parents).then(() => {
|
return Parse.Object.saveAll(parents).then(() => {
|
||||||
var query1 = new Parse.Query(ParentObject);
|
var query1 = new Parse.Query(ParentObject);
|
||||||
query1.containedIn("toChilds", [childObjects[2]]);
|
query1.containedIn("toChilds", [childObjects[2]]);
|
||||||
@@ -501,5 +502,154 @@ describe('Parse.Relation testing', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
it('should properly get related objects with unfetched queries', (done) => {
|
||||||
|
let objects = [];
|
||||||
|
let owners = [];
|
||||||
|
let allObjects = [];
|
||||||
|
// Build 10 Objects and 10 owners
|
||||||
|
while (objects.length != 10) {
|
||||||
|
let object = new Parse.Object('AnObject');
|
||||||
|
object.set({
|
||||||
|
index: objects.length,
|
||||||
|
even: objects.length % 2 == 0
|
||||||
|
});
|
||||||
|
objects.push(object);
|
||||||
|
let owner = new Parse.Object('AnOwner');
|
||||||
|
owners.push(owner);
|
||||||
|
allObjects.push(object);
|
||||||
|
allObjects.push(owner);
|
||||||
|
}
|
||||||
|
|
||||||
|
let anotherOwner = new Parse.Object('AnotherOwner');
|
||||||
|
|
||||||
|
return Parse.Object.saveAll(allObjects.concat([anotherOwner])).then(() => {
|
||||||
|
// put all the AnObject into the anotherOwner relationKey
|
||||||
|
anotherOwner.relation('relationKey').add(objects);
|
||||||
|
// Set each object[i] into owner[i];
|
||||||
|
owners.forEach((owner,i) => {
|
||||||
|
owner.set('key', objects[i]);
|
||||||
|
});
|
||||||
|
return Parse.Object.saveAll(owners.concat([anotherOwner]));
|
||||||
|
}).then(() => {
|
||||||
|
// Query on the relation of another owner
|
||||||
|
let object = new Parse.Object('AnotherOwner');
|
||||||
|
object.id = anotherOwner.id;
|
||||||
|
let relationQuery = object.relation('relationKey').query();
|
||||||
|
// Just get the even ones
|
||||||
|
relationQuery.equalTo('even', true);
|
||||||
|
// Make the query on anOwner
|
||||||
|
let query = new Parse.Query('AnOwner');
|
||||||
|
// where key match the relation query.
|
||||||
|
query.matchesQuery('key', relationQuery);
|
||||||
|
query.include('key');
|
||||||
|
return query.find();
|
||||||
|
}).then((results) => {
|
||||||
|
expect(results.length).toBe(5);
|
||||||
|
results.forEach((result) => {
|
||||||
|
expect(result.get('key').get('even')).toBe(true);
|
||||||
|
});
|
||||||
|
return Promise.resolve();
|
||||||
|
}).then(() => {
|
||||||
|
// Query on the relation of another owner
|
||||||
|
let object = new Parse.Object('AnotherOwner');
|
||||||
|
object.id = anotherOwner.id;
|
||||||
|
let relationQuery = object.relation('relationKey').query();
|
||||||
|
// Just get the even ones
|
||||||
|
relationQuery.equalTo('even', true);
|
||||||
|
// Make the query on anOwner
|
||||||
|
let query = new Parse.Query('AnOwner');
|
||||||
|
// where key match the relation query.
|
||||||
|
query.doesNotMatchQuery('key', relationQuery);
|
||||||
|
query.include('key');
|
||||||
|
return query.find();
|
||||||
|
}).then((results) => {
|
||||||
|
expect(results.length).toBe(5);
|
||||||
|
results.forEach((result) => {
|
||||||
|
expect(result.get('key').get('even')).toBe(false);
|
||||||
|
});
|
||||||
|
done();
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
it("select query", function(done) {
|
||||||
|
var RestaurantObject = Parse.Object.extend("Restaurant");
|
||||||
|
var PersonObject = Parse.Object.extend("Person");
|
||||||
|
var OwnerObject = Parse.Object.extend('Owner');
|
||||||
|
var restaurants = [
|
||||||
|
new RestaurantObject({ ratings: 5, location: "Djibouti" }),
|
||||||
|
new RestaurantObject({ ratings: 3, location: "Ouagadougou" }),
|
||||||
|
];
|
||||||
|
let persons = [
|
||||||
|
new PersonObject({ name: "Bob", hometown: "Djibouti" }),
|
||||||
|
new PersonObject({ name: "Tom", hometown: "Ouagadougou" }),
|
||||||
|
new PersonObject({ name: "Billy", hometown: "Detroit" }),
|
||||||
|
];
|
||||||
|
let owner = new OwnerObject({name: 'Joe'});
|
||||||
|
let ownerId;
|
||||||
|
let allObjects = [owner].concat(restaurants).concat(persons);
|
||||||
|
expect(allObjects.length).toEqual(6);
|
||||||
|
Parse.Object.saveAll([owner].concat(restaurants).concat(persons)).then(function() {
|
||||||
|
ownerId = owner.id;
|
||||||
|
owner.relation('restaurants').add(restaurants);
|
||||||
|
return owner.save()
|
||||||
|
}).then(() => {
|
||||||
|
let unfetchedOwner = new OwnerObject();
|
||||||
|
unfetchedOwner.id = owner.id;
|
||||||
|
var query = unfetchedOwner.relation('restaurants').query();
|
||||||
|
query.greaterThan("ratings", 4);
|
||||||
|
var mainQuery = new Parse.Query(PersonObject);
|
||||||
|
mainQuery.matchesKeyInQuery("hometown", "location", query);
|
||||||
|
mainQuery.find(expectSuccess({
|
||||||
|
success: function(results) {
|
||||||
|
equal(results.length, 1);
|
||||||
|
if (results.length > 0) {
|
||||||
|
equal(results[0].get('name'), 'Bob');
|
||||||
|
}
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("dontSelect query", function(done) {
|
||||||
|
var RestaurantObject = Parse.Object.extend("Restaurant");
|
||||||
|
var PersonObject = Parse.Object.extend("Person");
|
||||||
|
var OwnerObject = Parse.Object.extend('Owner');
|
||||||
|
var restaurants = [
|
||||||
|
new RestaurantObject({ ratings: 5, location: "Djibouti" }),
|
||||||
|
new RestaurantObject({ ratings: 3, location: "Ouagadougou" }),
|
||||||
|
];
|
||||||
|
let persons = [
|
||||||
|
new PersonObject({ name: "Bob", hometown: "Djibouti" }),
|
||||||
|
new PersonObject({ name: "Tom", hometown: "Ouagadougou" }),
|
||||||
|
new PersonObject({ name: "Billy", hometown: "Detroit" }),
|
||||||
|
];
|
||||||
|
let owner = new OwnerObject({name: 'Joe'});
|
||||||
|
let ownerId;
|
||||||
|
let allObjects = [owner].concat(restaurants).concat(persons);
|
||||||
|
expect(allObjects.length).toEqual(6);
|
||||||
|
Parse.Object.saveAll([owner].concat(restaurants).concat(persons)).then(function() {
|
||||||
|
ownerId = owner.id;
|
||||||
|
owner.relation('restaurants').add(restaurants);
|
||||||
|
return owner.save()
|
||||||
|
}).then(() => {
|
||||||
|
let unfetchedOwner = new OwnerObject();
|
||||||
|
unfetchedOwner.id = owner.id;
|
||||||
|
var query = unfetchedOwner.relation('restaurants').query();
|
||||||
|
query.greaterThan("ratings", 4);
|
||||||
|
var mainQuery = new Parse.Query(PersonObject);
|
||||||
|
mainQuery.doesNotMatchKeyInQuery("hometown", "location", query);
|
||||||
|
mainQuery.ascending('name');
|
||||||
|
mainQuery.find(expectSuccess({
|
||||||
|
success: function(results) {
|
||||||
|
equal(results.length, 2);
|
||||||
|
if (results.length > 0) {
|
||||||
|
equal(results[0].get('name'), 'Billy');
|
||||||
|
equal(results[1].get('name'), 'Tom');
|
||||||
|
}
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ function RestQuery(config, auth, className, restWhere = {}, restOptions = {}) {
|
|||||||
this.className = className;
|
this.className = className;
|
||||||
this.restWhere = restWhere;
|
this.restWhere = restWhere;
|
||||||
this.response = null;
|
this.response = null;
|
||||||
|
|
||||||
this.findOptions = {};
|
this.findOptions = {};
|
||||||
if (!this.auth.isMaster) {
|
if (!this.auth.isMaster) {
|
||||||
this.findOptions.acl = this.auth.user ? [this.auth.user.id] : null;
|
this.findOptions.acl = this.auth.user ? [this.auth.user.id] : null;
|
||||||
@@ -205,15 +204,19 @@ RestQuery.prototype.replaceInQuery = function() {
|
|||||||
'improper usage of $inQuery');
|
'improper usage of $inQuery');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let additionalOptions = {
|
||||||
|
redirectClassNameForKey: inQueryValue.redirectClassNameForKey
|
||||||
|
};
|
||||||
|
|
||||||
var subquery = new RestQuery(
|
var subquery = new RestQuery(
|
||||||
this.config, this.auth, inQueryValue.className,
|
this.config, this.auth, inQueryValue.className,
|
||||||
inQueryValue.where);
|
inQueryValue.where, additionalOptions);
|
||||||
return subquery.execute().then((response) => {
|
return subquery.execute().then((response) => {
|
||||||
var values = [];
|
var values = [];
|
||||||
for (var result of response.results) {
|
for (var result of response.results) {
|
||||||
values.push({
|
values.push({
|
||||||
__type: 'Pointer',
|
__type: 'Pointer',
|
||||||
className: inQueryValue.className,
|
className: subquery.className,
|
||||||
objectId: result.objectId
|
objectId: result.objectId
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -223,7 +226,6 @@ RestQuery.prototype.replaceInQuery = function() {
|
|||||||
} else {
|
} else {
|
||||||
inQueryObject['$in'] = values;
|
inQueryObject['$in'] = values;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recurse to repeat
|
// Recurse to repeat
|
||||||
return this.replaceInQuery();
|
return this.replaceInQuery();
|
||||||
});
|
});
|
||||||
@@ -246,15 +248,19 @@ RestQuery.prototype.replaceNotInQuery = function() {
|
|||||||
'improper usage of $notInQuery');
|
'improper usage of $notInQuery');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let additionalOptions = {
|
||||||
|
redirectClassNameForKey: notInQueryValue.redirectClassNameForKey
|
||||||
|
};
|
||||||
|
|
||||||
var subquery = new RestQuery(
|
var subquery = new RestQuery(
|
||||||
this.config, this.auth, notInQueryValue.className,
|
this.config, this.auth, notInQueryValue.className,
|
||||||
notInQueryValue.where);
|
notInQueryValue.where, additionalOptions);
|
||||||
return subquery.execute().then((response) => {
|
return subquery.execute().then((response) => {
|
||||||
var values = [];
|
var values = [];
|
||||||
for (var result of response.results) {
|
for (var result of response.results) {
|
||||||
values.push({
|
values.push({
|
||||||
__type: 'Pointer',
|
__type: 'Pointer',
|
||||||
className: notInQueryValue.className,
|
className: subquery.className,
|
||||||
objectId: result.objectId
|
objectId: result.objectId
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -293,9 +299,13 @@ RestQuery.prototype.replaceSelect = function() {
|
|||||||
'improper usage of $select');
|
'improper usage of $select');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let additionalOptions = {
|
||||||
|
redirectClassNameForKey: selectValue.query.redirectClassNameForKey
|
||||||
|
};
|
||||||
|
|
||||||
var subquery = new RestQuery(
|
var subquery = new RestQuery(
|
||||||
this.config, this.auth, selectValue.query.className,
|
this.config, this.auth, selectValue.query.className,
|
||||||
selectValue.query.where);
|
selectValue.query.where, additionalOptions);
|
||||||
return subquery.execute().then((response) => {
|
return subquery.execute().then((response) => {
|
||||||
var values = [];
|
var values = [];
|
||||||
for (var result of response.results) {
|
for (var result of response.results) {
|
||||||
@@ -334,9 +344,13 @@ RestQuery.prototype.replaceDontSelect = function() {
|
|||||||
throw new Parse.Error(Parse.Error.INVALID_QUERY,
|
throw new Parse.Error(Parse.Error.INVALID_QUERY,
|
||||||
'improper usage of $dontSelect');
|
'improper usage of $dontSelect');
|
||||||
}
|
}
|
||||||
|
let additionalOptions = {
|
||||||
|
redirectClassNameForKey: dontSelectValue.query.redirectClassNameForKey
|
||||||
|
};
|
||||||
|
|
||||||
var subquery = new RestQuery(
|
var subquery = new RestQuery(
|
||||||
this.config, this.auth, dontSelectValue.query.className,
|
this.config, this.auth, dontSelectValue.query.className,
|
||||||
dontSelectValue.query.where);
|
dontSelectValue.query.where, additionalOptions);
|
||||||
return subquery.execute().then((response) => {
|
return subquery.execute().then((response) => {
|
||||||
var values = [];
|
var values = [];
|
||||||
for (var result of response.results) {
|
for (var result of response.results) {
|
||||||
@@ -385,7 +399,6 @@ RestQuery.prototype.runFind = function() {
|
|||||||
r.className = this.redirectClassName;
|
r.className = this.redirectClassName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.response = {results: results};
|
this.response = {results: results};
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -423,7 +436,7 @@ RestQuery.prototype.handleInclude = function() {
|
|||||||
this.include = this.include.slice(1);
|
this.include = this.include.slice(1);
|
||||||
return this.handleInclude();
|
return this.handleInclude();
|
||||||
}
|
}
|
||||||
|
|
||||||
return pathResponse;
|
return pathResponse;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user