Skip to content

Commit 9ea344a

Browse files
committed
Merge pull request #1046 from ParsePlatform/flovilmart.fix1014
Fixes bug related to subqueries on unfetched objects
2 parents 3e89373 + 3451fc3 commit 9ea344a

File tree

2 files changed

+191
-28
lines changed

2 files changed

+191
-28
lines changed

spec/ParseRelation.spec.js

Lines changed: 168 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
'use strict';
12
// This is a port of the test suite:
23
// hungry/js/test/parse_relation_test.js
34

@@ -237,7 +238,7 @@ describe('Parse.Relation testing', () => {
237238
success: function(list) {
238239
equal(list.length, 1, "There should be only one result");
239240
equal(list[0].id, parent2.id,
240-
"Should have gotten back the right result");
241+
"Should have gotten back the right result");
241242
done();
242243
}
243244
});
@@ -246,7 +247,7 @@ describe('Parse.Relation testing', () => {
246247
}
247248
});
248249
});
249-
250+
250251
it("queries on relation fields with multiple ins", (done) => {
251252
var ChildObject = Parse.Object.extend("ChildObject");
252253
var childObjects = [];
@@ -268,7 +269,7 @@ describe('Parse.Relation testing', () => {
268269
relation2.add(childObjects[4]);
269270
relation2.add(childObjects[5]);
270271
relation2.add(childObjects[6]);
271-
272+
272273
var otherChild2 = parent2.relation("otherChild");
273274
otherChild2.add(childObjects[0]);
274275
otherChild2.add(childObjects[1]);
@@ -290,7 +291,7 @@ describe('Parse.Relation testing', () => {
290291
done();
291292
});
292293
});
293-
294+
294295
it("query on pointer and relation fields with equal", (done) => {
295296
var ChildObject = Parse.Object.extend("ChildObject");
296297
var childObjects = [];
@@ -306,29 +307,29 @@ describe('Parse.Relation testing', () => {
306307
relation.add(childObjects[0]);
307308
relation.add(childObjects[1]);
308309
relation.add(childObjects[2]);
309-
310+
310311
var parent2 = new ParentObject();
311312
parent2.set("x", 3);
312313
parent2.set("toChild", childObjects[2]);
313-
314+
314315
var parents = [];
315316
parents.push(parent);
316317
parents.push(parent2);
317318
parents.push(new ParentObject());
318-
319+
319320
return Parse.Object.saveAll(parents).then(() => {
320321
var query = new Parse.Query(ParentObject);
321322
query.equalTo("objectId", parent.id);
322323
query.equalTo("toChilds", childObjects[2]);
323-
324+
324325
return query.find().then((list) => {
325326
equal(list.length, 1, "There should be 1 result");
326327
done();
327328
});
328329
});
329330
});
330331
});
331-
332+
332333
it("query on pointer and relation fields with equal bis", (done) => {
333334
var ChildObject = Parse.Object.extend("ChildObject");
334335
var childObjects = [];
@@ -344,31 +345,31 @@ describe('Parse.Relation testing', () => {
344345
relation.add(childObjects[0]);
345346
relation.add(childObjects[1]);
346347
relation.add(childObjects[2]);
347-
348+
348349
var parent2 = new ParentObject();
349350
parent2.set("x", 3);
350351
parent2.relation("toChilds").add(childObjects[2]);
351-
352+
352353
var parents = [];
353354
parents.push(parent);
354355
parents.push(parent2);
355356
parents.push(new ParentObject());
356-
357+
357358
return Parse.Object.saveAll(parents).then(() => {
358359
var query = new Parse.Query(ParentObject);
359360
query.equalTo("objectId", parent2.id);
360361
// childObjects[2] is in 2 relations
361362
// before the fix, that woul yield 2 results
362363
query.equalTo("toChilds", childObjects[2]);
363-
364+
364365
return query.find().then((list) => {
365366
equal(list.length, 1, "There should be 1 result");
366367
done();
367368
});
368369
});
369370
});
370371
});
371-
372+
372373
it("or queries on pointer and relation fields", (done) => {
373374
var ChildObject = Parse.Object.extend("ChildObject");
374375
var childObjects = [];
@@ -384,16 +385,16 @@ describe('Parse.Relation testing', () => {
384385
relation.add(childObjects[0]);
385386
relation.add(childObjects[1]);
386387
relation.add(childObjects[2]);
387-
388+
388389
var parent2 = new ParentObject();
389390
parent2.set("x", 3);
390391
parent2.set("toChild", childObjects[2]);
391-
392+
392393
var parents = [];
393394
parents.push(parent);
394395
parents.push(parent2);
395396
parents.push(new ParentObject());
396-
397+
397398
return Parse.Object.saveAll(parents).then(() => {
398399
var query1 = new Parse.Query(ParentObject);
399400
query1.containedIn("toChilds", [childObjects[2]]);
@@ -501,5 +502,154 @@ describe('Parse.Relation testing', () => {
501502
});
502503
});
503504

504-
});
505+
it('should properly get related objects with unfetched queries', (done) => {
506+
let objects = [];
507+
let owners = [];
508+
let allObjects = [];
509+
// Build 10 Objects and 10 owners
510+
while (objects.length != 10) {
511+
let object = new Parse.Object('AnObject');
512+
object.set({
513+
index: objects.length,
514+
even: objects.length % 2 == 0
515+
});
516+
objects.push(object);
517+
let owner = new Parse.Object('AnOwner');
518+
owners.push(owner);
519+
allObjects.push(object);
520+
allObjects.push(owner);
521+
}
522+
523+
let anotherOwner = new Parse.Object('AnotherOwner');
505524

525+
return Parse.Object.saveAll(allObjects.concat([anotherOwner])).then(() => {
526+
// put all the AnObject into the anotherOwner relationKey
527+
anotherOwner.relation('relationKey').add(objects);
528+
// Set each object[i] into owner[i];
529+
owners.forEach((owner,i) => {
530+
owner.set('key', objects[i]);
531+
});
532+
return Parse.Object.saveAll(owners.concat([anotherOwner]));
533+
}).then(() => {
534+
// Query on the relation of another owner
535+
let object = new Parse.Object('AnotherOwner');
536+
object.id = anotherOwner.id;
537+
let relationQuery = object.relation('relationKey').query();
538+
// Just get the even ones
539+
relationQuery.equalTo('even', true);
540+
// Make the query on anOwner
541+
let query = new Parse.Query('AnOwner');
542+
// where key match the relation query.
543+
query.matchesQuery('key', relationQuery);
544+
query.include('key');
545+
return query.find();
546+
}).then((results) => {
547+
expect(results.length).toBe(5);
548+
results.forEach((result) => {
549+
expect(result.get('key').get('even')).toBe(true);
550+
});
551+
return Promise.resolve();
552+
}).then(() => {
553+
// Query on the relation of another owner
554+
let object = new Parse.Object('AnotherOwner');
555+
object.id = anotherOwner.id;
556+
let relationQuery = object.relation('relationKey').query();
557+
// Just get the even ones
558+
relationQuery.equalTo('even', true);
559+
// Make the query on anOwner
560+
let query = new Parse.Query('AnOwner');
561+
// where key match the relation query.
562+
query.doesNotMatchQuery('key', relationQuery);
563+
query.include('key');
564+
return query.find();
565+
}).then((results) => {
566+
expect(results.length).toBe(5);
567+
results.forEach((result) => {
568+
expect(result.get('key').get('even')).toBe(false);
569+
});
570+
done();
571+
})
572+
});
573+
574+
it("select query", function(done) {
575+
var RestaurantObject = Parse.Object.extend("Restaurant");
576+
var PersonObject = Parse.Object.extend("Person");
577+
var OwnerObject = Parse.Object.extend('Owner');
578+
var restaurants = [
579+
new RestaurantObject({ ratings: 5, location: "Djibouti" }),
580+
new RestaurantObject({ ratings: 3, location: "Ouagadougou" }),
581+
];
582+
let persons = [
583+
new PersonObject({ name: "Bob", hometown: "Djibouti" }),
584+
new PersonObject({ name: "Tom", hometown: "Ouagadougou" }),
585+
new PersonObject({ name: "Billy", hometown: "Detroit" }),
586+
];
587+
let owner = new OwnerObject({name: 'Joe'});
588+
let ownerId;
589+
let allObjects = [owner].concat(restaurants).concat(persons);
590+
expect(allObjects.length).toEqual(6);
591+
Parse.Object.saveAll([owner].concat(restaurants).concat(persons)).then(function() {
592+
ownerId = owner.id;
593+
owner.relation('restaurants').add(restaurants);
594+
return owner.save()
595+
}).then(() => {
596+
let unfetchedOwner = new OwnerObject();
597+
unfetchedOwner.id = owner.id;
598+
var query = unfetchedOwner.relation('restaurants').query();
599+
query.greaterThan("ratings", 4);
600+
var mainQuery = new Parse.Query(PersonObject);
601+
mainQuery.matchesKeyInQuery("hometown", "location", query);
602+
mainQuery.find(expectSuccess({
603+
success: function(results) {
604+
equal(results.length, 1);
605+
if (results.length > 0) {
606+
equal(results[0].get('name'), 'Bob');
607+
}
608+
done();
609+
}
610+
}));
611+
});
612+
});
613+
614+
it("dontSelect query", function(done) {
615+
var RestaurantObject = Parse.Object.extend("Restaurant");
616+
var PersonObject = Parse.Object.extend("Person");
617+
var OwnerObject = Parse.Object.extend('Owner');
618+
var restaurants = [
619+
new RestaurantObject({ ratings: 5, location: "Djibouti" }),
620+
new RestaurantObject({ ratings: 3, location: "Ouagadougou" }),
621+
];
622+
let persons = [
623+
new PersonObject({ name: "Bob", hometown: "Djibouti" }),
624+
new PersonObject({ name: "Tom", hometown: "Ouagadougou" }),
625+
new PersonObject({ name: "Billy", hometown: "Detroit" }),
626+
];
627+
let owner = new OwnerObject({name: 'Joe'});
628+
let ownerId;
629+
let allObjects = [owner].concat(restaurants).concat(persons);
630+
expect(allObjects.length).toEqual(6);
631+
Parse.Object.saveAll([owner].concat(restaurants).concat(persons)).then(function() {
632+
ownerId = owner.id;
633+
owner.relation('restaurants').add(restaurants);
634+
return owner.save()
635+
}).then(() => {
636+
let unfetchedOwner = new OwnerObject();
637+
unfetchedOwner.id = owner.id;
638+
var query = unfetchedOwner.relation('restaurants').query();
639+
query.greaterThan("ratings", 4);
640+
var mainQuery = new Parse.Query(PersonObject);
641+
mainQuery.doesNotMatchKeyInQuery("hometown", "location", query);
642+
mainQuery.ascending('name');
643+
mainQuery.find(expectSuccess({
644+
success: function(results) {
645+
equal(results.length, 2);
646+
if (results.length > 0) {
647+
equal(results[0].get('name'), 'Billy');
648+
equal(results[1].get('name'), 'Tom');
649+
}
650+
done();
651+
}
652+
}));
653+
});
654+
});
655+
});

src/RestQuery.js

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ function RestQuery(config, auth, className, restWhere = {}, restOptions = {}) {
2020
this.className = className;
2121
this.restWhere = restWhere;
2222
this.response = null;
23-
2423
this.findOptions = {};
2524
if (!this.auth.isMaster) {
2625
this.findOptions.acl = this.auth.user ? [this.auth.user.id] : null;
@@ -205,15 +204,19 @@ RestQuery.prototype.replaceInQuery = function() {
205204
'improper usage of $inQuery');
206205
}
207206

207+
let additionalOptions = {
208+
redirectClassNameForKey: inQueryValue.redirectClassNameForKey
209+
};
210+
208211
var subquery = new RestQuery(
209212
this.config, this.auth, inQueryValue.className,
210-
inQueryValue.where);
213+
inQueryValue.where, additionalOptions);
211214
return subquery.execute().then((response) => {
212215
var values = [];
213216
for (var result of response.results) {
214217
values.push({
215218
__type: 'Pointer',
216-
className: inQueryValue.className,
219+
className: subquery.className,
217220
objectId: result.objectId
218221
});
219222
}
@@ -223,7 +226,6 @@ RestQuery.prototype.replaceInQuery = function() {
223226
} else {
224227
inQueryObject['$in'] = values;
225228
}
226-
227229
// Recurse to repeat
228230
return this.replaceInQuery();
229231
});
@@ -246,15 +248,19 @@ RestQuery.prototype.replaceNotInQuery = function() {
246248
'improper usage of $notInQuery');
247249
}
248250

251+
let additionalOptions = {
252+
redirectClassNameForKey: notInQueryValue.redirectClassNameForKey
253+
};
254+
249255
var subquery = new RestQuery(
250256
this.config, this.auth, notInQueryValue.className,
251-
notInQueryValue.where);
257+
notInQueryValue.where, additionalOptions);
252258
return subquery.execute().then((response) => {
253259
var values = [];
254260
for (var result of response.results) {
255261
values.push({
256262
__type: 'Pointer',
257-
className: notInQueryValue.className,
263+
className: subquery.className,
258264
objectId: result.objectId
259265
});
260266
}
@@ -293,9 +299,13 @@ RestQuery.prototype.replaceSelect = function() {
293299
'improper usage of $select');
294300
}
295301

302+
let additionalOptions = {
303+
redirectClassNameForKey: selectValue.query.redirectClassNameForKey
304+
};
305+
296306
var subquery = new RestQuery(
297307
this.config, this.auth, selectValue.query.className,
298-
selectValue.query.where);
308+
selectValue.query.where, additionalOptions);
299309
return subquery.execute().then((response) => {
300310
var values = [];
301311
for (var result of response.results) {
@@ -334,9 +344,13 @@ RestQuery.prototype.replaceDontSelect = function() {
334344
throw new Parse.Error(Parse.Error.INVALID_QUERY,
335345
'improper usage of $dontSelect');
336346
}
347+
let additionalOptions = {
348+
redirectClassNameForKey: dontSelectValue.query.redirectClassNameForKey
349+
};
350+
337351
var subquery = new RestQuery(
338352
this.config, this.auth, dontSelectValue.query.className,
339-
dontSelectValue.query.where);
353+
dontSelectValue.query.where, additionalOptions);
340354
return subquery.execute().then((response) => {
341355
var values = [];
342356
for (var result of response.results) {
@@ -385,7 +399,6 @@ RestQuery.prototype.runFind = function() {
385399
r.className = this.redirectClassName;
386400
}
387401
}
388-
389402
this.response = {results: results};
390403
});
391404
};
@@ -423,7 +436,7 @@ RestQuery.prototype.handleInclude = function() {
423436
this.include = this.include.slice(1);
424437
return this.handleInclude();
425438
}
426-
439+
427440
return pathResponse;
428441
};
429442

0 commit comments

Comments
 (0)