From 1887ab649c81ef9078c9a2426bd937f83540ceb6 Mon Sep 17 00:00:00 2001 From: Florent Vilmart Date: Tue, 3 Oct 2017 11:38:46 -0400 Subject: [PATCH 1/5] Adds support for pointer/string pointers comparison in LiveQuery --- spec/QueryTools.spec.js | 75 +++++++++++++++++++++++++++++++++++++ src/LiveQuery/QueryTools.js | 26 ++++++++++++- 2 files changed, 99 insertions(+), 2 deletions(-) diff --git a/spec/QueryTools.spec.js b/spec/QueryTools.spec.js index ea7ad708ad..196707b969 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 a476da4af9..01c3186896 100644 --- a/src/LiveQuery/QueryTools.js +++ b/src/LiveQuery/QueryTools.js @@ -89,6 +89,28 @@ function queryHash(query) { return query.className + ':' + sections.join('|'); } +/** + * contains -- Determines wether a constaint in for form of a list + * contains a particular object. + * This also supports, pointer comparion and strings as lightweight pointers + */ +function contains(compareTo: Array, object: any): boolean { + if (object.__type && object.__type === 'Pointer') { + for (const i in compareTo) { + const ptr = compareTo[i]; + if (typeof ptr == 'string' && ptr === object.objectId) { + return true; + } + if (typeof object !== 'undefined' && + ptr.className === object.className && + ptr.objectId === object.objectId) { + return true; + } + } + return false; + } + return compareTo.indexOf(object) > -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 +229,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; From 0046680aebeae90c573bae134fe06b549162ccd8 Mon Sep 17 00:00:00 2001 From: Florent Vilmart Date: Tue, 3 Oct 2017 12:38:16 -0400 Subject: [PATCH 2/5] nits --- spec/QueryTools.spec.js | 2 +- src/LiveQuery/QueryTools.js | 22 ++++++++++++---------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/spec/QueryTools.spec.js b/spec/QueryTools.spec.js index 196707b969..b43ccb5e86 100644 --- a/spec/QueryTools.spec.js +++ b/spec/QueryTools.spec.js @@ -497,7 +497,7 @@ describe('matchesQuery', function() { }); function pointer(className, objectId) { - return {__type: 'Pointer', className, objectId }; + return { __type: 'Pointer', className, objectId }; } it('should support containedIn with pointers', () => { diff --git a/src/LiveQuery/QueryTools.js b/src/LiveQuery/QueryTools.js index 01c3186896..543b4ddfd6 100644 --- a/src/LiveQuery/QueryTools.js +++ b/src/LiveQuery/QueryTools.js @@ -90,26 +90,28 @@ function queryHash(query) { } /** - * contains -- Determines wether a constaint in for form of a list + * contains -- Determines whether a constraint in the form of a list * contains a particular object. - * This also supports, pointer comparion and strings as lightweight pointers + * If the compared to object is a pointer it will match either full pointers + * or string (objectId) + * Otherwise it will use a simple indexOf. */ -function contains(compareTo: Array, object: any): boolean { - if (object.__type && object.__type === 'Pointer') { - for (const i in compareTo) { - const ptr = compareTo[i]; - if (typeof ptr == 'string' && ptr === object.objectId) { +function contains(haystack: Array, needle: any): boolean { + if (needle.__type && needle.__type === 'Pointer') { + for (const i in haystack) { + const ptr = haystack[i]; + if (typeof ptr === 'string' && ptr === needle.objectId) { return true; } if (typeof object !== 'undefined' && - ptr.className === object.className && - ptr.objectId === object.objectId) { + ptr.className === needle.className && + ptr.objectId === needle.objectId) { return true; } } return false; } - return compareTo.indexOf(object) > -1; + return haystack.indexOf(needle) > -1; } /** * matchesQuery -- Determines if an object would be returned by a Parse Query From f73d09deafb51c73508042f996266e2f12cc8a13 Mon Sep 17 00:00:00 2001 From: Florent Vilmart Date: Tue, 3 Oct 2017 12:38:59 -0400 Subject: [PATCH 3/5] Makes sure needed is set --- src/LiveQuery/QueryTools.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LiveQuery/QueryTools.js b/src/LiveQuery/QueryTools.js index 543b4ddfd6..ea91a87d2f 100644 --- a/src/LiveQuery/QueryTools.js +++ b/src/LiveQuery/QueryTools.js @@ -97,7 +97,7 @@ function queryHash(query) { * Otherwise it will use a simple indexOf. */ function contains(haystack: Array, needle: any): boolean { - if (needle.__type && needle.__type === 'Pointer') { + if (needle && needle.__type && needle.__type === 'Pointer') { for (const i in haystack) { const ptr = haystack[i]; if (typeof ptr === 'string' && ptr === needle.objectId) { From 058b2d1a8d8d546b3ec5ef7f3601bc54da02376f Mon Sep 17 00:00:00 2001 From: Florent Vilmart Date: Tue, 3 Oct 2017 12:51:13 -0400 Subject: [PATCH 4/5] Update QueryTools.js --- src/LiveQuery/QueryTools.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/LiveQuery/QueryTools.js b/src/LiveQuery/QueryTools.js index ea91a87d2f..b1e3153987 100644 --- a/src/LiveQuery/QueryTools.js +++ b/src/LiveQuery/QueryTools.js @@ -90,11 +90,7 @@ function queryHash(query) { } /** - * contains -- Determines whether a constraint in the form of a list - * contains a particular object. - * If the compared to object is a pointer it will match either full pointers - * or string (objectId) - * Otherwise it will use a simple indexOf. + * 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') { From ea62945b8b069881c20154bb59e8c82758b1f68b Mon Sep 17 00:00:00 2001 From: Florent Vilmart Date: Tue, 3 Oct 2017 13:01:37 -0400 Subject: [PATCH 5/5] Update QueryTools.js --- src/LiveQuery/QueryTools.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/LiveQuery/QueryTools.js b/src/LiveQuery/QueryTools.js index b1e3153987..5a42b9d824 100644 --- a/src/LiveQuery/QueryTools.js +++ b/src/LiveQuery/QueryTools.js @@ -99,8 +99,7 @@ function contains(haystack: Array, needle: any): boolean { if (typeof ptr === 'string' && ptr === needle.objectId) { return true; } - if (typeof object !== 'undefined' && - ptr.className === needle.className && + if (ptr.className === needle.className && ptr.objectId === needle.objectId) { return true; }