From 49736846c95b177c0bec8bc5c9068dec99938c67 Mon Sep 17 00:00:00 2001 From: Julius Lisauskas Date: Thu, 30 Mar 2017 21:02:11 +0300 Subject: [PATCH 1/6] Added failing test --- spec/ParseQuery.spec.js | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/spec/ParseQuery.spec.js b/spec/ParseQuery.spec.js index 9d27f302ca..492951e6f9 100644 --- a/spec/ParseQuery.spec.js +++ b/spec/ParseQuery.spec.js @@ -1891,6 +1891,41 @@ describe('Parse.Query testing', () => { }); }); + it("dontSelect and equalTo (#3678)", function(done) { + var AuthorObject = Parse.Object.extend("Author"); + var BlockedObject = Parse.Object.extend("Blocked"); + var PostObject = Parse.Object.extend("Post"); + + var postAuthor = null; + var requestUser = null; + + return new AuthorObject({ name: "Julius"}).save().then((user) => { + postAuthor = user; + return new AuthorObject({ name: "Bob"}).save(); + }).then((user) => { + requestUser = user; + var objects = [ + new PostObject({ author: postAuthor, title: "Lorem ipsum" }), + new PostObject({ author: requestUser, title: "Kafka" }), + new PostObject({ author: requestUser, title: "Brown fox" }), + new BlockedObject({ blockedBy: postAuthor, blockedUser: requestUser}) + ]; + return Parse.Object.saveAll(objects); + }).then(() => { + var banListQuery = new Parse.Query(BlockedObject); + banListQuery.equalTo("blockedUser", requestUser); + + return new Parse.Query(PostObject) + .equalTo("author", postAuthor) + .doesNotMatchKeyInQuery("author", "blockedBy", banListQuery) + .find() + .then((r) => { + expect(r.length).toEqual(0); + done(); + }, done.fail); + }) + }); + it("object with length", function(done) { var TestObject = Parse.Object.extend("TestObject"); var obj = new TestObject(); From 5a174dfb558f7f09ccac3b2c20a2fc5eed6069cb Mon Sep 17 00:00:00 2001 From: Julius Lisauskas Date: Wed, 5 Apr 2017 11:36:56 +0300 Subject: [PATCH 2/6] Updated test description --- spec/ParseQuery.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/ParseQuery.spec.js b/spec/ParseQuery.spec.js index 492951e6f9..b238e24e63 100644 --- a/spec/ParseQuery.spec.js +++ b/spec/ParseQuery.spec.js @@ -1891,7 +1891,7 @@ describe('Parse.Query testing', () => { }); }); - it("dontSelect and equalTo (#3678)", function(done) { + it("equalTo on same column as $dontSelect should not break $dontSelect functionality (#3678)", function(done) { var AuthorObject = Parse.Object.extend("Author"); var BlockedObject = Parse.Object.extend("Blocked"); var PostObject = Parse.Object.extend("Post"); From 97fd8f9b814e7e4914024e6ea5765dd5c75a4d0e Mon Sep 17 00:00:00 2001 From: Florent Vilmart Date: Sun, 16 Apr 2017 13:29:36 -0400 Subject: [PATCH 3/6] Properly handle equalities with additional operator constraints --- src/RestQuery.js | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/RestQuery.js b/src/RestQuery.js index 974e3e8912..31f8681f3c 100644 --- a/src/RestQuery.js +++ b/src/RestQuery.js @@ -169,6 +169,8 @@ RestQuery.prototype.buildRestWhere = function() { return this.replaceInQuery(); }).then(() => { return this.replaceNotInQuery(); + }).then(() => { + return this.replaceEquality(); }); } @@ -438,6 +440,39 @@ const cleanResultAuthData = function (result) { } }; +const replaceEqualityConstraint = (constraint) => { + if (typeof constraint !== 'object') { + return constraint; + } + const equalToObject = {}; + let hasDirectConstraint = false; + let hasOperatorConstraint = false; + for (const key in constraint) { + if (key.indexOf('$') != 0) { + hasDirectConstraint = true; + equalToObject[key] = constraint[key]; + } else { + hasOperatorConstraint = true; + } + } + if (hasDirectConstraint && hasOperatorConstraint) { + constraint['$eq'] = equalToObject; + Object.keys(equalToObject).forEach((key) => { + delete constraint[key]; + }); + } + return constraint; +} + +RestQuery.prototype.replaceEquality = function() { + if (typeof this.restWhere !== 'object') { + return; + } + for (const key in this.restWhere) { + this.restWhere[key] = replaceEqualityConstraint(this.restWhere[key]); + } +} + // Returns a promise for whether it was successful. // Populates this.response with an object that only has 'results'. RestQuery.prototype.runFind = function(options = {}) { From 95c7bc0289d013141dfe02333aa5089361cdd44f Mon Sep 17 00:00:00 2001 From: Florent Vilmart Date: Sun, 16 Apr 2017 13:54:43 -0400 Subject: [PATCH 4/6] adds continuation to silence rejected promises --- spec/AuthenticationAdapters.spec.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/spec/AuthenticationAdapters.spec.js b/spec/AuthenticationAdapters.spec.js index 501b64b392..526fa5c82b 100644 --- a/spec/AuthenticationAdapters.spec.js +++ b/spec/AuthenticationAdapters.spec.js @@ -10,8 +10,12 @@ describe('AuthenticationProviers', function() { var provider = require("../src/Adapters/Auth/" + providerName); jequal(typeof provider.validateAuthData, "function"); jequal(typeof provider.validateAppId, "function"); - jequal(provider.validateAuthData({}, {}).constructor, Promise.prototype.constructor); - jequal(provider.validateAppId("app", "key", {}).constructor, Promise.prototype.constructor); + const authDataPromise = provider.validateAuthData({}, {}); + const validateAppIdPromise = provider.validateAppId("app", "key", {}); + jequal(authDataPromise.constructor, Promise.prototype.constructor); + jequal(validateAppIdPromise.constructor, Promise.prototype.constructor); + authDataPromise.then(()=>{}, ()=>{}); + validateAppIdPromise.then(()=>{}, ()=>{}); done(); }); }); From b5592ed159e0563996899223a7c55e2b96d1d46b Mon Sep 17 00:00:00 2001 From: Florent Vilmart Date: Sun, 16 Apr 2017 14:01:55 -0400 Subject: [PATCH 5/6] Wrap json parsing --- src/Adapters/Auth/facebook.js | 6 +++++- src/Adapters/Auth/github.js | 6 +++++- src/Adapters/Auth/google.js | 6 +++++- src/Adapters/Auth/janrainengage.js | 9 +++++++-- src/Adapters/Auth/linkedin.js | 6 +++++- src/Adapters/Auth/meetup.js | 6 +++++- src/Adapters/Auth/qq.js | 6 +++++- src/Adapters/Auth/spotify.js | 6 +++++- src/Adapters/Auth/vkontakte.js | 6 +++++- src/Adapters/Auth/wechat.js | 6 +++++- src/Adapters/Auth/weibo.js | 6 +++++- 11 files changed, 57 insertions(+), 12 deletions(-) diff --git a/src/Adapters/Auth/facebook.js b/src/Adapters/Auth/facebook.js index 84f8956678..ab846e43e6 100644 --- a/src/Adapters/Auth/facebook.js +++ b/src/Adapters/Auth/facebook.js @@ -43,7 +43,11 @@ function graphRequest(path) { data += chunk; }); res.on('end', function() { - data = JSON.parse(data); + try { + data = JSON.parse(data); + } catch(e) { + return reject(e); + } resolve(data); }); }).on('error', function() { diff --git a/src/Adapters/Auth/github.js b/src/Adapters/Auth/github.js index e6e2c05e8c..146fbdc6f2 100644 --- a/src/Adapters/Auth/github.js +++ b/src/Adapters/Auth/github.js @@ -36,7 +36,11 @@ function request(path, access_token) { data += chunk; }); res.on('end', function() { - data = JSON.parse(data); + try { + data = JSON.parse(data); + } catch(e) { + return reject(e); + } resolve(data); }); }).on('error', function() { diff --git a/src/Adapters/Auth/google.js b/src/Adapters/Auth/google.js index 4699c83789..7cc414922a 100644 --- a/src/Adapters/Auth/google.js +++ b/src/Adapters/Auth/google.js @@ -55,7 +55,11 @@ function request(path) { data += chunk; }); res.on('end', function() { - data = JSON.parse(data); + try { + data = JSON.parse(data); + } catch(e) { + return reject(e); + } resolve(data); }); }).on('error', function() { diff --git a/src/Adapters/Auth/janrainengage.js b/src/Adapters/Auth/janrainengage.js index 4df5701a41..7de682e7d4 100644 --- a/src/Adapters/Auth/janrainengage.js +++ b/src/Adapters/Auth/janrainengage.js @@ -41,7 +41,7 @@ function request(api_key, auth_token) { } }; - return new Promise(function (resolve) { + return new Promise(function (resolve, reject) { // Create the post request. var post_req = https.request(post_options, function (res) { var data = ''; @@ -52,7 +52,12 @@ function request(api_key, auth_token) { }); // Once we have all the data, we can parse it and return the data we want. res.on('end', function () { - resolve(JSON.parse(data)); + try { + data = JSON.parse(data); + } catch(e) { + return reject(e); + } + resolve(data); }); }); diff --git a/src/Adapters/Auth/linkedin.js b/src/Adapters/Auth/linkedin.js index 63c6cd97e1..de5fc66ce5 100644 --- a/src/Adapters/Auth/linkedin.js +++ b/src/Adapters/Auth/linkedin.js @@ -42,7 +42,11 @@ function request(path, access_token, is_mobile_sdk) { data += chunk; }); res.on('end', function() { - data = JSON.parse(data); + try { + data = JSON.parse(data); + } catch(e) { + return reject(e); + } resolve(data); }); }).on('error', function() { diff --git a/src/Adapters/Auth/meetup.js b/src/Adapters/Auth/meetup.js index e5c7e2c91e..bb14dc547b 100644 --- a/src/Adapters/Auth/meetup.js +++ b/src/Adapters/Auth/meetup.js @@ -35,7 +35,11 @@ function request(path, access_token) { data += chunk; }); res.on('end', function() { - data = JSON.parse(data); + try { + data = JSON.parse(data); + } catch(e) { + return reject(e); + } resolve(data); }); }).on('error', function() { diff --git a/src/Adapters/Auth/qq.js b/src/Adapters/Auth/qq.js index 376a5e650b..6f4dfdc0cf 100644 --- a/src/Adapters/Auth/qq.js +++ b/src/Adapters/Auth/qq.js @@ -32,7 +32,11 @@ function graphRequest(path) { throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'qq auth is invalid for this user.'); } data = data.substring(starPos + 1,endPos - 1); - data = JSON.parse(data); + try { + data = JSON.parse(data); + } catch(e) { + return reject(e); + } resolve(data); }); }).on('error', function () { diff --git a/src/Adapters/Auth/spotify.js b/src/Adapters/Auth/spotify.js index 7c39ed65e9..701422c585 100644 --- a/src/Adapters/Auth/spotify.js +++ b/src/Adapters/Auth/spotify.js @@ -49,7 +49,11 @@ function request(path, access_token) { data += chunk; }); res.on('end', function() { - data = JSON.parse(data); + try { + data = JSON.parse(data); + } catch(e) { + return reject(e); + } resolve(data); }); }).on('error', function() { diff --git a/src/Adapters/Auth/vkontakte.js b/src/Adapters/Auth/vkontakte.js index 0fdf28f2f1..4e57b25993 100644 --- a/src/Adapters/Auth/vkontakte.js +++ b/src/Adapters/Auth/vkontakte.js @@ -47,7 +47,11 @@ function request(host, path) { data += chunk; }); res.on('end', function () { - data = JSON.parse(data); + try { + data = JSON.parse(data); + } catch(e) { + return reject(e); + } resolve(data); }); }).on('error', function () { diff --git a/src/Adapters/Auth/wechat.js b/src/Adapters/Auth/wechat.js index 77cd7cfa2a..9432b7c5c3 100644 --- a/src/Adapters/Auth/wechat.js +++ b/src/Adapters/Auth/wechat.js @@ -26,7 +26,11 @@ function graphRequest(path) { data += chunk; }); res.on('end', function () { - data = JSON.parse(data); + try { + data = JSON.parse(data); + } catch(e) { + return reject(e); + } resolve(data); }); }).on('error', function () { diff --git a/src/Adapters/Auth/weibo.js b/src/Adapters/Auth/weibo.js index 8daf11de43..64efada2f6 100644 --- a/src/Adapters/Auth/weibo.js +++ b/src/Adapters/Auth/weibo.js @@ -39,7 +39,11 @@ function graphRequest(access_token) { data += chunk; }); res.on('end', function () { - data = JSON.parse(data); + try { + data = JSON.parse(data); + } catch(e) { + return reject(e); + } resolve(data); }); res.on('error', function () { From 7938be9967aff7add640cdbc329ce205eef01333 Mon Sep 17 00:00:00 2001 From: Florent Vilmart Date: Sun, 23 Apr 2017 17:26:16 -0400 Subject: [PATCH 6/6] nits --- src/RestQuery.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/RestQuery.js b/src/RestQuery.js index 31f8681f3c..37cbd518d6 100644 --- a/src/RestQuery.js +++ b/src/RestQuery.js @@ -448,7 +448,7 @@ const replaceEqualityConstraint = (constraint) => { let hasDirectConstraint = false; let hasOperatorConstraint = false; for (const key in constraint) { - if (key.indexOf('$') != 0) { + if (key.indexOf('$') !== 0) { hasDirectConstraint = true; equalToObject[key] = constraint[key]; } else {