Comparing version 0.0.1 to 0.0.2
@@ -5,2 +5,3 @@ /*! | ||
*/ | ||
'use strict'; | ||
module.exports = require('./lib/MapDSL.js'); |
@@ -5,3 +5,5 @@ /*! | ||
*/ | ||
const querySelectors = require('../queries/'); | ||
'use strict'; | ||
const queryOperators = require('../operators/Query'), | ||
logicalOperators = require('../operators/Logical'); | ||
@@ -14,17 +16,27 @@ class MapDSL extends Map { | ||
/* | ||
* Flatten the query object to an array of arrays. | ||
* [ [<Search Key>, <Query Selector>, <Test Value>], ... ] | ||
* Convert the query object to an Object with an Array of queries. | ||
*/ | ||
_flattenQueries (obj = {}) { | ||
let results = []; | ||
compileQueries (obj = {}) { | ||
let results = { | ||
operator: false, | ||
list: [] | ||
}; | ||
for (let key of Object.keys(obj)) { | ||
let isOP = this.isOperator(key); | ||
if (obj[key].constructor === Object) { | ||
let val = obj[key]; | ||
for (let mode of Object.keys(val)) { | ||
results.push([key, mode, obj[key][mode]]); | ||
results.list.push([key, mode, obj[key][mode]]); | ||
} | ||
// If the query is an array, treat it as a logical operator. | ||
} else if (isOP && Array.isArray(obj[key])) { | ||
for (let subobj of obj[key]) { | ||
// Recursively compile sub-queries for logical operators. | ||
results.list.push(this.compileQueries(subobj)); | ||
} | ||
// Store the logical operator for this query; used in _validate(). | ||
results.operator = key; | ||
} else { | ||
results.push([null, key, obj[key]]); | ||
results.list.push([(isOP ? null : key), (isOP ? key: '$eq'), obj[key]]); | ||
} | ||
} | ||
@@ -35,30 +47,63 @@ return results; | ||
/* | ||
* Check if a string is a query operator. | ||
*/ | ||
isQueryOperator (qs = null) { | ||
return queryOperators.hasOwnProperty(qs) == true; | ||
} | ||
/* | ||
* Get the query selector to test against. | ||
*/ | ||
_getQuerySelector (qs) { | ||
return (querySelectors[qs] ? querySelectors[qs] : () => { return false }); | ||
getQueryOperator (qs = '$_default') { | ||
return (queryOperators[qs] ? queryOperators[qs] : queryOperators['$_default']); | ||
} | ||
/* | ||
* Test the query selectors against an entry. If no entry key (query[0]) is provided treat the | ||
* entry as if it is not an object. | ||
* Check if a string is a logic operator. | ||
*/ | ||
_test (entry = [], queries = []) { | ||
return queries.every((query) => { | ||
let value = (query[0] ? entry[1][query[0]] : entry[1]); | ||
isLogicalOperator (lo = null) { | ||
return logicalOperators.hasOwnProperty(lo) == true; | ||
} | ||
return value && this._getQuerySelector(query[1]).call(this, value, query[2]); | ||
}); | ||
/* | ||
* Get the logic operator by name. | ||
*/ | ||
getLogicalOperator (lo) { | ||
return (logicalOperators[lo] ? logicalOperators[lo] : { fn: [].every }); | ||
} | ||
/* | ||
* Check if a string is a query operator OR a logical operator. | ||
*/ | ||
isOperator (op) { | ||
return this.isQueryOperator(op) || this.isLogicalOperator(op); | ||
} | ||
/* | ||
* Recursively test the query operator(s) against an entry, checking against any | ||
* logic operators provided. | ||
*/ | ||
_validate (entry = [], queries = {}) { | ||
return this.getLogicalOperator(queries.operator).fn.call(queries.list, (_query) => { | ||
if (this.isLogicalOperator(queries.operator)) { | ||
return this._validate(entry, _query); | ||
} else { | ||
return this.getQueryOperator(_query[1]).fn.apply(this, [ | ||
(_query[0] ? entry[1][_query[0]] : entry[1]), // Entry value | ||
_query[2], // Test value | ||
_query[0], // Test key | ||
entry // Entry [<Key>, <Value>] | ||
]); | ||
} | ||
}); | ||
} | ||
/* | ||
* Check all entries against every provided query selector; sync. | ||
*/ | ||
querySync (queries = {}) { | ||
let _queries = this._flattenQueries(queries), | ||
find (queries = {}, projections = {}) { | ||
let _queries = this.compileQueries(queries), | ||
results = []; | ||
for (let entry of this.entries()) { | ||
if (this._test(entry, _queries)) { | ||
if (this._validate(entry, _queries)) { | ||
results.push(Object.assign({ | ||
@@ -72,14 +117,15 @@ _id: entry[0] | ||
/* | ||
* Check all entries against every provided query selector; Promise based. | ||
*/ | ||
query (queries = {}) { | ||
findAsync (queries = {}) { | ||
return new Promise((resolve, reject) => { | ||
let results = this.querySync(queries); | ||
return (!!results.length ? resolve(results) : reject(new Error('No entries found.'))); | ||
try { | ||
let results = this.find(queries); | ||
return (!!results.length ? resolve(results) : reject(new Error('No entries found.'))); | ||
} catch (error) { | ||
reject(error); | ||
} | ||
}); | ||
} | ||
} | ||
@@ -86,0 +132,0 @@ |
{ | ||
"name": "mapdsl", | ||
"version": "0.0.1", | ||
"description": "A MongoDB inspired Map() DSL.", | ||
"version": "0.0.2", | ||
"description": "A MongoDB inspired ES6 Map() DSL.", | ||
"main": "index.js", | ||
"scripts": { | ||
"test": "echo \"Error: no test specified\" && exit 1" | ||
"test": "mocha" | ||
}, | ||
@@ -17,3 +17,4 @@ "repository": { | ||
"dsl", | ||
"search" | ||
"search", | ||
"es6" | ||
], | ||
@@ -29,3 +30,9 @@ "author": { | ||
}, | ||
"homepage": "https://github.com/LouisT/MapDSL#readme" | ||
"homepage": "https://github.com/LouisT/MapDSL#readme", | ||
"devDependencies": { | ||
"mocha": "^3.4.1" | ||
}, | ||
"dependencies": { | ||
"is-equal": "^1.5.5" | ||
} | ||
} |
MapDSL (WIP) | ||
=== | ||
A __[MongoDB]__ inspired __[Map()]__ DSL. | ||
A __[MongoDB]__ inspired __[ES6 Map()]__ DSL. | ||
This is a ___WIP___; do __NOT__ use in production yet! See [TODO](TODO.md) for more information. | ||
Implemented [Query Operators] | ||
=== | ||
* Comparison | ||
* $eq, $gt, $gte, $lt, $lte, $ne | ||
* Logical | ||
* $or, $and | ||
* Element | ||
* $exists, $type | ||
* Evaluation | ||
* $regex | ||
* Array | ||
### Example: | ||
```javascript | ||
let MapDSL = new (require('./MapDSL'))(), | ||
print = (obj) => { console.log('\n%s', JSON.stringify(obj, true, 4)); }; | ||
let MapDSL = new (require('mapdsl'))(), | ||
util = require('util'), | ||
_print = (obj) => { | ||
console.log('%s\n', util.inspect(obj, { depth: null, showHidden: true })); | ||
}; | ||
@@ -17,7 +33,18 @@ // Start out with some base data. | ||
foo: 7, | ||
bar: 3 | ||
bar: 3, | ||
baz: null, | ||
}); | ||
MapDSL.set('test11',{ | ||
foo: 7, | ||
string: 'Look at me example all the things!' | ||
}); | ||
MapDSL.set('test12',{ | ||
foo: 7, | ||
string: 'Another example string!', | ||
baz: 'qux' | ||
}); | ||
MapDSL.set('test13',{ | ||
foo: 8, | ||
baz: 'qux' | ||
}); | ||
// Fill with junk. | ||
@@ -32,12 +59,38 @@ for (let num = 3; num < 10; num++) { | ||
// Sync! | ||
print(MapDSL.querySync({ foo: { '$gt': 6 }, bar: { '$lt': 10 } })); | ||
print(MapDSL.querySync({ '$gt': 3 })); | ||
print(MapDSL.querySync({ '$eq': 'this is a string' })); | ||
print(MapDSL.querySync({ string: { '$regex': /Things!$/i } })); | ||
print(MapDSL.querySync({ '$regex': /String$/i })); | ||
print(MapDSL.querySync({ '$regex': /String$/ })); | ||
_print(MapDSL.find({ | ||
foo: 8 | ||
})); | ||
_print(MapDSL.find({ | ||
foo: { '$gt': 6 }, | ||
bar: { '$lt': 10 } | ||
})); | ||
_print(MapDSL.find({ | ||
'$gt': 3 | ||
})); | ||
_print(MapDSL.find({ | ||
'$eq': 'this is a string' | ||
})); | ||
_print(MapDSL.find({ | ||
string: { '$regex': /Things!$/i } | ||
})); | ||
_print(MapDSL.find({ | ||
'$regex': /String$/i | ||
})); | ||
_print(MapDSL.find({ | ||
'$regex': /String$/ | ||
})); | ||
_print(MapDSL.find({ | ||
'$and': [{ | ||
foo: { '$eq': 7 }, | ||
}, { | ||
'$or': [ | ||
{ string: { '$regex': /Things!$/i } }, | ||
{ string: { '$regex': /String!$/i } }, | ||
] | ||
}] | ||
})); | ||
// Promise! | ||
MapDSL.query({ foo: { '$gt': 10 }, bar: { '$lt': 10 } }).then((results) => { | ||
print(results); | ||
MapDSL.findAsync({ foo: { '$gt': 2 }, bar: { '$lt': 10 } }).then((results) => { | ||
_print(results); | ||
}).catch((error) => { | ||
@@ -48,3 +101,4 @@ console.log(error); | ||
[MongoDB]: https://docs.mongodb.com/manual/reference/operator/query/#query-selectors | ||
[Map()]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map | ||
[MongoDB]: https://www.mongodb.com/ | ||
[ES6 Map()]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map | ||
[Query Operators]: https://docs.mongodb.com/manual/reference/operator/query/ |
14
TODO.md
TODO | ||
=== | ||
* Add more query selectors. See [MongoDB Query Selectors] for reference. | ||
* Add more query operators. See [MongoDB Query and Projection Operators] for reference. | ||
* Improve the current ones as well. | ||
* Split the (complicated?) query selectors into their own files? | ||
* Add support for custom query selectors. | ||
* Add tests with mocha. | ||
* ~~Split the (complicated?) query selectors into their own files?~~ | ||
* Add support for custom query operators. | ||
* Implement the projection operators. See [Projection Operators] for reference. | ||
* ~~Add tests with mocha.~~ Improve tests! Add better coverage of query operators. | ||
* While the "[is-equal]" lib does what I want, it's a bit big. Find a smaller solution!? | ||
* Everything else. | ||
* Work on the TODO! | ||
[MongoDB Query Selectors]: https://docs.mongodb.com/manual/reference/operator/query/#query-selectors | ||
[MongoDB Query and Projection Operators]: https://docs.mongodb.com/manual/reference/operator/query/ | ||
[Projection Operators]: https://docs.mongodb.com/manual/reference/operator/query/#projection-operators | ||
[is-equal]: https://www.npmjs.com/package/is-equal |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No tests
QualityPackage does not have any tests. This is a strong signal of a poorly maintained or low quality package.
Found 1 instance in 1 package
16689
14
347
1
102
1
1
1
1
+ Addedis-equal@^1.5.5
+ Addedarray-buffer-byte-length@1.0.2(transitive)
+ Addedarraybuffer.prototype.slice@1.0.4(transitive)
+ Addedavailable-typed-arrays@1.0.7(transitive)
+ Addedcall-bind@1.0.8(transitive)
+ Addedcall-bind-apply-helpers@1.0.1(transitive)
+ Addedcall-bound@1.0.3(transitive)
+ Addeddata-view-buffer@1.0.2(transitive)
+ Addeddata-view-byte-length@1.0.2(transitive)
+ Addeddata-view-byte-offset@1.0.1(transitive)
+ Addeddefine-data-property@1.1.4(transitive)
+ Addeddefine-properties@1.2.1(transitive)
+ Addeddunder-proto@1.0.1(transitive)
+ Addedes-abstract@1.23.7(transitive)
+ Addedes-define-property@1.0.1(transitive)
+ Addedes-errors@1.3.0(transitive)
+ Addedes-get-iterator@1.1.3(transitive)
+ Addedes-object-atoms@1.0.0(transitive)
+ Addedes-set-tostringtag@2.0.3(transitive)
+ Addedes-to-primitive@1.3.0(transitive)
+ Addedfor-each@0.3.3(transitive)
+ Addedfunction-bind@1.1.2(transitive)
+ Addedfunction.prototype.name@1.1.8(transitive)
+ Addedfunctions-have-names@1.2.3(transitive)
+ Addedget-intrinsic@1.2.6(transitive)
+ Addedget-symbol-description@1.1.0(transitive)
+ Addedglobalthis@1.0.4(transitive)
+ Addedgopd@1.2.0(transitive)
+ Addedhas-bigints@1.1.0(transitive)
+ Addedhas-property-descriptors@1.0.2(transitive)
+ Addedhas-proto@1.2.0(transitive)
+ Addedhas-symbols@1.1.0(transitive)
+ Addedhas-tostringtag@1.0.2(transitive)
+ Addedhasown@2.0.2(transitive)
+ Addedinternal-slot@1.1.0(transitive)
+ Addedis-arguments@1.2.0(transitive)
+ Addedis-array-buffer@3.0.5(transitive)
+ Addedis-arrow-function@2.0.3(transitive)
+ Addedis-async-function@2.0.0(transitive)
+ Addedis-bigint@1.1.0(transitive)
+ Addedis-boolean-object@1.2.1(transitive)
+ Addedis-callable@1.2.7(transitive)
+ Addedis-data-view@1.0.2(transitive)
+ Addedis-date-object@1.1.0(transitive)
+ Addedis-equal@1.7.0(transitive)
+ Addedis-finalizationregistry@1.1.1(transitive)
+ Addedis-generator-function@1.0.10(transitive)
+ Addedis-map@2.0.3(transitive)
+ Addedis-number-object@1.1.1(transitive)
+ Addedis-regex@1.2.1(transitive)
+ Addedis-set@2.0.3(transitive)
+ Addedis-shared-array-buffer@1.0.4(transitive)
+ Addedis-string@1.1.1(transitive)
+ Addedis-symbol@1.1.1(transitive)
+ Addedis-typed-array@1.1.15(transitive)
+ Addedis-weakmap@2.0.2(transitive)
+ Addedis-weakref@1.1.0(transitive)
+ Addedis-weakset@2.0.4(transitive)
+ Addedisarray@2.0.5(transitive)
+ Addedmath-intrinsics@1.1.0(transitive)
+ Addedobject-inspect@1.13.3(transitive)
+ Addedobject-keys@1.1.1(transitive)
+ Addedobject.assign@4.1.7(transitive)
+ Addedobject.entries@1.1.8(transitive)
+ Addedobject.getprototypeof@1.0.6(transitive)
+ Addedpossible-typed-array-names@1.0.0(transitive)
+ Addedreflect.getprototypeof@1.0.9(transitive)
+ Addedregexp.prototype.flags@1.5.3(transitive)
+ Addedsafe-array-concat@1.1.3(transitive)
+ Addedsafe-regex-test@1.1.0(transitive)
+ Addedset-function-length@1.2.2(transitive)
+ Addedset-function-name@2.0.2(transitive)
+ Addedside-channel@1.1.0(transitive)
+ Addedside-channel-list@1.0.0(transitive)
+ Addedside-channel-map@1.0.1(transitive)
+ Addedside-channel-weakmap@1.0.2(transitive)
+ Addedstop-iteration-iterator@1.1.0(transitive)
+ Addedstring.prototype.trim@1.2.10(transitive)
+ Addedstring.prototype.trimend@1.0.9(transitive)
+ Addedstring.prototype.trimstart@1.0.8(transitive)
+ Addedtyped-array-buffer@1.0.3(transitive)
+ Addedtyped-array-byte-length@1.0.3(transitive)
+ Addedtyped-array-byte-offset@1.0.4(transitive)
+ Addedtyped-array-length@1.0.7(transitive)
+ Addedunbox-primitive@1.1.0(transitive)
+ Addedwhich-boxed-primitive@1.1.1(transitive)
+ Addedwhich-builtin-type@1.2.1(transitive)
+ Addedwhich-collection@1.0.2(transitive)
+ Addedwhich-typed-array@1.1.18(transitive)