From 2a168936fcaf18b037e354a6379beff44ddeb553 Mon Sep 17 00:00:00 2001 From: Florent Vilmart Date: Tue, 3 Oct 2017 13:50:20 -0400 Subject: [PATCH] Adds support for pointer/string pointers comparison in LiveQuery (#4231) * Adds support for pointer/string pointers comparison in LiveQuery * nits * Makes sure needed is set * Update QueryTools.js * Update QueryTools.js --- spec/QueryTools.spec.js | 75 +++++++++++++++++++++++++++++++++++++ src/LiveQuery/QueryTools.js | 23 +++++++++++- 2 files changed, 96 insertions(+), 2 deletions(-) diff --git a/spec/QueryTools.spec.js b/spec/QueryTools.spec.js index ea7ad708..b43ccb5e 100644 --- a/spec/QueryTools.spec.js +++ b/spec/QueryTools.spec.js @@ -495,4 +495,79 @@ describe('matchesQuery', function() { expect(matchesQuery(message, q)).toBe(false); }); + + function pointer(className, objectId) { + return { __type: 'Pointer', className, objectId }; + } + + it('should support containedIn with pointers', () => { + var message = { + id: new Id('Message', 'O1'), + profile: pointer('Profile', 'abc') + }; + var q = new Parse.Query('Message'); + q.containedIn('profile', [Parse.Object.fromJSON({ className: 'Profile', objectId: 'abc' }), + Parse.Object.fromJSON({ className: 'Profile', objectId: 'def' })]); + expect(matchesQuery(message, q)).toBe(true); + + q = new Parse.Query('Message'); + q.containedIn('profile', [Parse.Object.fromJSON({ className: 'Profile', objectId: 'ghi' }), + Parse.Object.fromJSON({ className: 'Profile', objectId: 'def' })]); + expect(matchesQuery(message, q)).toBe(false); + }); + + it('should support notContainedIn with pointers', () => { + var message = { + id: new Id('Message', 'O1'), + profile: pointer('Profile', 'abc') + }; + var q = new Parse.Query('Message'); + q.notContainedIn('profile', [Parse.Object.fromJSON({ className: 'Profile', objectId: 'def' }), + Parse.Object.fromJSON({ className: 'Profile', objectId: 'ghi' })]); + expect(matchesQuery(message, q)).toBe(true); + + message = { + id: new Id('Message', 'O1'), + profile: pointer('Profile', 'def') + }; + q = new Parse.Query('Message'); + q.notContainedIn('profile', [Parse.Object.fromJSON({ className: 'Profile', objectId: 'ghi' }), + Parse.Object.fromJSON({ className: 'Profile', objectId: 'def' })]); + expect(matchesQuery(message, q)).toBe(false); + }); + + it('should support containedIn queries with [objectId]', () => { + var message = { + id: new Id('Message', 'O1'), + profile: pointer('Profile', 'abc') + }; + var q = new Parse.Query('Message'); + q.containedIn('profile', ['abc', 'def']); + expect(matchesQuery(message, q)).toBe(true); + + message = { + id: new Id('Message', 'O1'), + profile: pointer('Profile', 'ghi') + }; + q = new Parse.Query('Message'); + q.containedIn('profile', ['abc', 'def']); + expect(matchesQuery(message, q)).toBe(false); + }); + + it('should support notContainedIn queries with [objectId]', () => { + var message = { + id: new Id('Message', 'O1'), + profile: pointer('Profile', 'ghi') + }; + var q = new Parse.Query('Message'); + q.notContainedIn('profile', ['abc', 'def']); + expect(matchesQuery(message, q)).toBe(true); + message = { + id: new Id('Message', 'O1'), + profile: pointer('Profile', 'ghi') + }; + q = new Parse.Query('Message'); + q.notContainedIn('profile', ['abc', 'def', 'ghi']); + expect(matchesQuery(message, q)).toBe(false); + }); }); diff --git a/src/LiveQuery/QueryTools.js b/src/LiveQuery/QueryTools.js index a476da4a..5a42b9d8 100644 --- a/src/LiveQuery/QueryTools.js +++ b/src/LiveQuery/QueryTools.js @@ -89,6 +89,25 @@ function queryHash(query) { return query.className + ':' + sections.join('|'); } +/** + * contains -- Determines if an object is contained in a list with special handling for Parse pointers. + */ +function contains(haystack: Array, needle: any): boolean { + if (needle && needle.__type && needle.__type === 'Pointer') { + for (const i in haystack) { + const ptr = haystack[i]; + if (typeof ptr === 'string' && ptr === needle.objectId) { + return true; + } + if (ptr.className === needle.className && + ptr.objectId === needle.objectId) { + return true; + } + } + return false; + } + return haystack.indexOf(needle) > -1; +} /** * matchesQuery -- Determines if an object would be returned by a Parse Query * It's a lightweight, where-clause only implementation of a full query engine. @@ -207,12 +226,12 @@ function matchesKeyConstraints(object, key, constraints) { } break; case '$in': - if (compareTo.indexOf(object[key]) < 0) { + if (!contains(compareTo, object[key])) { return false; } break; case '$nin': - if (compareTo.indexOf(object[key]) > -1) { + if (contains(compareTo, object[key])) { return false; } break;