From 2f1164e561e44eb1caa6136064854bc0799edc11 Mon Sep 17 00:00:00 2001 From: Craig Condon Date: Sun, 23 Jun 2019 17:34:36 -0400 Subject: [PATCH 1/4] get started on async functionality --- lib/index.js | 81 ++++++++++++++++++++++++++++++++++++++++------ src/index.js | 79 ++++++++++++++++++++++++++++++++++++++------ test/async-test.js | 79 +++++++++++++++++++++++++++++++++----------- 3 files changed, 201 insertions(+), 38 deletions(-) diff --git a/lib/index.js b/lib/index.js index 77ddb6b..6bd4539 100644 --- a/lib/index.js +++ b/lib/index.js @@ -47,6 +47,24 @@ function get(obj, key) { return isFunction(obj.get) ? obj.get(key) : obj[key]; } +function identity(value) { + return value; +} + +function promiseAll(promises) { + return Promise.all(promises).then(function(results) { + return !results.some(function(result) { + return !result; + }); + }); +} + +function promiseSome(promises) { + return Promise.all(promises).then(function(results) { + return results.some(identity); + }); +} + /** */ @@ -177,11 +195,26 @@ var defaultExpressions = { */ $or: function $or(a, b, k, o) { + var thenableResults = void 0; for (var i = 0, n = a.length; i < n; i++) { - if (validate(get(a, i), b, k, o)) { - return true; + var result = validate(get(a, i), b, k, o); + if (result && result.then && !thenableResults) { + thenableResults = []; + } + + if (thenableResults) { + thenableResults.push(result); + } else { + if (result) { + return true; + } } } + + if (thenableResults) { + return promiseSome(thenableResults); + } + return false; }, @@ -196,11 +229,27 @@ var defaultExpressions = { */ $and: function $and(a, b, k, o) { + var thenableResults = void 0; + for (var i = 0, n = a.length; i < n; i++) { - if (!validate(get(a, i), b, k, o)) { - return false; + var result = validate(get(a, i), b, k, o); + if (result && result.then && !thenableResults) { + thenableResults = []; } + + if (thenableResults) { + thenableResults.push(result); + } else { + if (!result) { + return false; + } + } + } + + if (thenableResults) { + return promiseAll(thenableResults); } + return true; }, @@ -223,7 +272,7 @@ var defaultExpressions = { $elemMatch: function $elemMatch(a, b, k, o) { if (isArray(b)) { - return !!~search(b, a); + return search(b, a) !== -1; } return validate(a, b, k, o); }, @@ -308,7 +357,9 @@ var prepare = { var comparable = options.comparable; return function(b) { - if (b instanceof Array) { + var thenableResults = void 0; + + if (isArray(b)) { for (var i = b.length; i--; ) { if (~a.indexOf(comparable(get(b, i)))) { return true; @@ -344,8 +395,15 @@ var prepare = { */ for (var i = a.length; i--; ) { var validator = createRootValidator(get(a, i), options); - var result = validate(validator, b, i, a); - if ( + var result = validate(validator, comparableB, i, a); + + if (result && result.then && !thenableResults) { + thenableResults = []; + } + + if (thenableResults) { + thenableResults.push(result); + } else if ( result && String(result) !== "[object Object]" && String(b) !== "[object Object]" @@ -354,7 +412,10 @@ var prepare = { } } - return !!~a.indexOf(comparableB); + if (thenableResults) { + console.log(thenableResults); + return promiseSome(thenableResults); + } } return false; @@ -453,7 +514,7 @@ var prepare = { */ $exists: function $exists(a) { - return !!a; + return Boolean(a); } }; diff --git a/src/index.js b/src/index.js index 1f12633..b31453c 100644 --- a/src/index.js +++ b/src/index.js @@ -24,6 +24,22 @@ function get(obj, key) { return isFunction(obj.get) ? obj.get(key) : obj[key]; } +function identity(value) { + return value; +} + +function promiseAll(promises) { + return Promise.all(promises).then(results => { + return !results.some(result => !result); + }); +} + +function promiseSome(promises) { + return Promise.all(promises).then(results => { + return results.some(identity); + }); +} + /** */ @@ -154,11 +170,26 @@ var defaultExpressions = { */ $or: function(a, b, k, o) { + let thenableResults; for (var i = 0, n = a.length; i < n; i++) { - if (validate(get(a, i), b, k, o)) { - return true; + const result = validate(get(a, i), b, k, o); + if (result && result.then && !thenableResults) { + thenableResults = []; + } + + if (thenableResults) { + thenableResults.push(result); + } else { + if (result) { + return true; + } } } + + if (thenableResults) { + return promiseSome(thenableResults); + } + return false; }, @@ -173,11 +204,27 @@ var defaultExpressions = { */ $and: function(a, b, k, o) { + let thenableResults; + for (var i = 0, n = a.length; i < n; i++) { - if (!validate(get(a, i), b, k, o)) { - return false; + const result = validate(get(a, i), b, k, o); + if (result && result.then && !thenableResults) { + thenableResults = []; } + + if (thenableResults) { + thenableResults.push(result); + } else { + if (!result) { + return false; + } + } + } + + if (thenableResults) { + return promiseAll(thenableResults); } + return true; }, @@ -200,7 +247,7 @@ var defaultExpressions = { $elemMatch: function(a, b, k, o) { if (isArray(b)) { - return !!~search(b, a); + return search(b, a) !== -1; } return validate(a, b, k, o); }, @@ -269,7 +316,9 @@ var prepare = { $in: function(a, query, options) { const { comparable } = options; return function(b) { - if (b instanceof Array) { + let thenableResults; + + if (isArray(b)) { for (var i = b.length; i--; ) { if (~a.indexOf(comparable(get(b, i)))) { return true; @@ -302,8 +351,15 @@ var prepare = { */ for (var i = a.length; i--; ) { var validator = createRootValidator(get(a, i), options); - var result = validate(validator, b, i, a); - if ( + var result = validate(validator, comparableB, i, a); + + if (result && result.then && !thenableResults) { + thenableResults = []; + } + + if (thenableResults) { + thenableResults.push(result); + } else if ( result && String(result) !== "[object Object]" && String(b) !== "[object Object]" @@ -312,7 +368,10 @@ var prepare = { } } - return !!~a.indexOf(comparableB); + if (thenableResults) { + console.log(thenableResults); + return promiseSome(thenableResults); + } } return false; @@ -411,7 +470,7 @@ var prepare = { */ $exists: function(a) { - return !!a; + return Boolean(a); } }; diff --git a/test/async-test.js b/test/async-test.js index ca92d33..9c94241 100644 --- a/test/async-test.js +++ b/test/async-test.js @@ -8,30 +8,73 @@ describe(__filename + "#", () => { { $eq: function(value) { return new Promise(function(resolve) { - resolve(value > 2); + resolve(value); }); } }, [1, 2, 3, 4, 5], [3, 4, 5] - ] + ], + + [ + "can use a simple async $in or filter", + { + $in: [ + function(value) { + return new Promise(function(resolve) { + resolve(5); + }); + }, + function(value) { + return new Promise(function(resolve) { + resolve(2); + }); + } + ] + }, + [1, 2, 3, 4, 5], + [2, 5] + ], - // [ - // "can use a simple async $or filter", - // { - // $and: [ - // function(value) { - // new Promise(function(resolve) { - // resolve(value > 2); - // }) - // }, - // function(value) { - // new Promise(function(resolve) { - // resolve(value < 5); - // }) - // } - // ] - // }, [1, 2, 3, 4, 5], [3, 4]] + [ + "can use a simple async $and filter", + { + $and: [ + function(value) { + return new Promise(function(resolve) { + resolve(value > 2); + }); + }, + function(value) { + return new Promise(function(resolve) { + resolve(value < 5); + }); + } + ] + }, + [1, 2, 3, 4, 5], + [3, 4] + ], + + [ + "can use a simple async $or filter", + { + $or: [ + function(value) { + return new Promise(function(resolve) { + resolve(value !== 1); + }); + }, + function(value) { + return new Promise(function(resolve) { + resolve(value < 5 && value !== 1); + }); + } + ] + }, + [1, 2, 3, 4, 5], + [2, 3, 4, 5] + ] ].forEach(function([description, query, values, result]) { it(description, function() { return new Promise(function(resolve, reject) { From cd82c0de0433886f232beab2f564460d4c478e71 Mon Sep 17 00:00:00 2001 From: Craig Condon Date: Sat, 29 Jun 2019 14:20:51 -0400 Subject: [PATCH 2/4] convert all operation tests to async --- lib/index.js | 4 ++-- src/index.js | 4 ++-- test/async-test.js | 16 +++++----------- test/operations-test.js | 22 ++++++++++++++++++++++ 4 files changed, 31 insertions(+), 15 deletions(-) diff --git a/lib/index.js b/lib/index.js index 6bd4539..ec05e0f 100644 --- a/lib/index.js +++ b/lib/index.js @@ -361,12 +361,13 @@ var prepare = { if (isArray(b)) { for (var i = b.length; i--; ) { - if (~a.indexOf(comparable(get(b, i)))) { + if (a.indexOf(comparable(get(b, i))) !== -1) { return true; } } } else { var comparableB = comparable(b); + if ( comparableB === b && (typeof b === "undefined" ? "undefined" : _typeof(b)) === "object" @@ -413,7 +414,6 @@ var prepare = { } if (thenableResults) { - console.log(thenableResults); return promiseSome(thenableResults); } } diff --git a/src/index.js b/src/index.js index b31453c..bc2397b 100644 --- a/src/index.js +++ b/src/index.js @@ -320,12 +320,13 @@ var prepare = { if (isArray(b)) { for (var i = b.length; i--; ) { - if (~a.indexOf(comparable(get(b, i)))) { + if (a.indexOf(comparable(get(b, i))) !== -1) { return true; } } } else { var comparableB = comparable(b); + if (comparableB === b && typeof b === "object") { for (var i = a.length; i--; ) { if (String(a[i]) === String(b) && String(b) !== "[object Object]") { @@ -369,7 +370,6 @@ var prepare = { } if (thenableResults) { - console.log(thenableResults); return promiseSome(thenableResults); } } diff --git a/test/async-test.js b/test/async-test.js index 9c94241..045f9df 100644 --- a/test/async-test.js +++ b/test/async-test.js @@ -7,9 +7,7 @@ describe(__filename + "#", () => { "can use a simple async $eq filter", { $eq: function(value) { - return new Promise(function(resolve) { - resolve(value); - }); + return value > 2; } }, [1, 2, 3, 4, 5], @@ -20,15 +18,11 @@ describe(__filename + "#", () => { "can use a simple async $in or filter", { $in: [ - function(value) { - return new Promise(function(resolve) { - resolve(5); - }); + function() { + return 5; }, - function(value) { - return new Promise(function(resolve) { - resolve(2); - }); + function() { + return Promise.resolve(2); } ] }, diff --git a/test/operations-test.js b/test/operations-test.js index c853211..b78030c 100644 --- a/test/operations-test.js +++ b/test/operations-test.js @@ -475,5 +475,27 @@ describe(__filename + "#", function() { JSON.stringify(matchArray) ); }); + + it("async " + i + ": " + JSON.stringify(filter), function() { + const asyncFilter = makeQueryAync(filter); + Promise.all(array.filter(sift(asyncFilter))).then(results => { + assert.equal(results, JSON.stringify(matchArray)); + }); + }); }); }); + +const makeQueryAync = query => { + if (Array.isArray(query)) { + return query.map(makeQueryAync); + } else if (query && query.constructor === Object) { + const newQuery = {}; + for (const key in query) { + newQuery[key] = Promise.resolve(query[key]); + } + } else if (typeof query === "function") { + return query; + } + + return Promise.resolve(query); +}; From 4b289d24a2c38b63d26816c62733e0345dc35881 Mon Sep 17 00:00:00 2001 From: Craig Condon Date: Sun, 21 Jul 2019 11:53:10 -0400 Subject: [PATCH 3/4] prettyfy From 5ec7225fc6b280a9d79c4226d2f8e5d08c932307 Mon Sep 17 00:00:00 2001 From: Craig Condon Date: Mon, 9 Sep 2019 11:55:23 +0200 Subject: [PATCH 4/4] cleanup --- lib/index.js | 51 +++++++++++++++++++++++++++++---------------------- src/index.js | 50 ++++++++++++++++++++++++++++---------------------- 2 files changed, 57 insertions(+), 44 deletions(-) diff --git a/lib/index.js b/lib/index.js index ec05e0f..85a92c1 100644 --- a/lib/index.js +++ b/lib/index.js @@ -285,6 +285,29 @@ var defaultExpressions = { } }; +function castTesterAsFn(a, comparable, compare) { + if (a instanceof RegExp) { + return function(b) { + return typeof b === "string" && a.test(b); + }; + } else if (a instanceof Function) { + return a; + } else if (isArray(a) && !a.length) { + // Special case of a == [] + return function(b) { + return isArray(b) && !b.length; + }; + } else if (a === null) { + return function(b) { + //will match both null and undefined + return b == null; + }; + } + return function(b) { + return compare(comparable(b), comparable(a)) === 0; + }; +} + /** */ @@ -296,26 +319,7 @@ var prepare = { var comparable = _ref.comparable, compare = _ref.compare; - if (a instanceof RegExp) { - return or(function(b) { - return typeof b === "string" && a.test(b); - }); - } else if (a instanceof Function) { - return or(a); - } else if (isArray(a) && !a.length) { - // Special case of a == [] - return or(function(b) { - return isArray(b) && !b.length; - }); - } else if (a === null) { - return or(function(b) { - //will match both null and undefined - return b == null; - }); - } - return or(function(b) { - return compare(comparable(b), comparable(a)) === 0; - }); + return or(castTesterAsFn(a, comparable, compare)); }, $gt: function $gt(a, query, _ref2) { @@ -354,7 +358,8 @@ var prepare = { }, $in: function $in(a, query, options) { - var comparable = options.comparable; + var comparable = options.comparable, + compare = options.compare; return function(b) { var thenableResults = void 0; @@ -395,6 +400,8 @@ var prepare = { Handles the case of {'field': {$in: [/regexp1/, /regexp2/, ...]}} */ for (var i = a.length; i--; ) { + var tester = castTesterAsFn(get(a, i), comparable, compare); + var validator = createRootValidator(get(a, i), options); var result = validate(validator, comparableB, i, a); @@ -402,7 +409,7 @@ var prepare = { thenableResults = []; } - if (thenableResults) { + if (thenableResults != null) { thenableResults.push(result); } else if ( result && diff --git a/src/index.js b/src/index.js index bc2397b..77fd577 100644 --- a/src/index.js +++ b/src/index.js @@ -260,6 +260,29 @@ var defaultExpressions = { } }; +function castTesterAsFn(a, comparable, compare) { + if (a instanceof RegExp) { + return function(b) { + return typeof b === "string" && a.test(b); + }; + } else if (a instanceof Function) { + return a; + } else if (isArray(a) && !a.length) { + // Special case of a == [] + return function(b) { + return isArray(b) && !b.length; + }; + } else if (a === null) { + return function(b) { + //will match both null and undefined + return b == null; + }; + } + return function(b) { + return compare(comparable(b), comparable(a)) === 0; + }; +} + /** */ @@ -268,26 +291,7 @@ var prepare = { */ $eq: function(a, query, { comparable, compare }) { - if (a instanceof RegExp) { - return or(function(b) { - return typeof b === "string" && a.test(b); - }); - } else if (a instanceof Function) { - return or(a); - } else if (isArray(a) && !a.length) { - // Special case of a == [] - return or(function(b) { - return isArray(b) && !b.length; - }); - } else if (a === null) { - return or(function(b) { - //will match both null and undefined - return b == null; - }); - } - return or(function(b) { - return compare(comparable(b), comparable(a)) === 0; - }); + return or(castTesterAsFn(a, comparable, compare)); }, $gt: function(a, query, { comparable, compare }) { @@ -314,7 +318,7 @@ var prepare = { }, $in: function(a, query, options) { - const { comparable } = options; + const { comparable, compare } = options; return function(b) { let thenableResults; @@ -351,6 +355,8 @@ var prepare = { Handles the case of {'field': {$in: [/regexp1/, /regexp2/, ...]}} */ for (var i = a.length; i--; ) { + var tester = castTesterAsFn(get(a, i), comparable, compare); + var validator = createRootValidator(get(a, i), options); var result = validate(validator, comparableB, i, a); @@ -358,7 +364,7 @@ var prepare = { thenableResults = []; } - if (thenableResults) { + if (thenableResults != null) { thenableResults.push(result); } else if ( result &&