joqular v2.0.4-b
joqular
JavaScript Object Query Language Representation - Funny it's mostly JSON.
JOQULAR is a query language specification. Although there is a reference implementation with this site, others are free to write their own drivers.
Like SQL, JOQULAR allows you to mutate the returned records to meet you needs.
Mutation options include property aliasing and redaction, value substitution (including array summaries, sorting, filtering, etc.), adding event handlers, freezing objects and properties.
Matching options include functional testing of both property names and values as well as over 30 built-in predicates.
You can also use JOQULAR to validate objects.
Installation Of Reference Implementation
npm install joqular
Usage
const [<matched>,...] = await JOQULAR.query(<pattern>,<object>,...);const pattern = {name:{$eq:"joe"}},
[matched1] = await JOQULAR.match(pattern,{name:"joe",age:27}), // will resolve to the object with name "joe"
[matched2] = await JOQULAR.match(pattern,{name:"jane",age:27}); // will resolve to undefinedJOQULAR queries can cause mutations. If an object is mutated during a query, a copy is returned. If no mutations occur, the original is returned. If you always want a copy, then do something to force a slight mutation, e.g. add a hidden property with
$define.
For now see the Medium article for more information.
API
Predicates and Functions
All 97 predicates and functions or their aliases could actually be defined in-line; however, functions that are difficult to implement or used frequently are defined as part of JOQULAR. Additionally, by not using in-line functions, most JOQULAR patterns can be transmitted over the wire.
New functions can be added in as little as one line of code, e.g.
JOQULAR.function((value,key,object) => ...,"$myfunction");or
JOQULAR.function(function $myfunction(value,key) { ...} );In the second form you can use a third object argument if you wish, but the this context is also set to the object being tested. In the first form the this context can't be used effectively because it is the context from the point at which the function was defined.
Below is an alphabetical list with minimal documentation. Future documentation will have far more detail and group functions by type. In the meantime, see the index.js in the test directory and review the unit tests.
$ - {<property>:{$: (value,property,object) => ...}
- Calls a function with the property value, name, and object. The function can change the object. Matching continues if the function returns
true.
$and - {<property>:{$and: Array [<pattern>,...]||<logical pattern>}}
Returns true and matching continues if the value of the target <property> satisfies all of the JOQULAR patterns in the Array or a nested logical pattern, e.g. {$or: {$and: ...}; otherwise, matching fails.
$as - {<property>:{$as: string as}}
- Adds a property
ason the target with the value of<property>on the target.
$avg - {<property>: {$avg: null||string as}}
- Assumes the current value of the
<property>on the target is an iterable. Average's the numbers and either replaces the property value with the average ifasequalsnull. Or, it adds a property with the nameasand sets it to the average.
$avga - {<property>: {$avg: null||string as}}
- Same as
$avg, excepttrueandfalseare treated like 1 and 0 respectively and an attempt is made to parse string values as numbers.
$between - {<property>: {$between: [number hi,number lo,boolean inclusive]}}
- Returns
trueand mathcing continues if the value of<property>on the target is betweenhiandlo, optionally inclusive of the boundaries; otherwise, matching fails. The value of the target<property>can be a Date in addition to anumberor astring. The function is polymorphic. The function is polymorphic. If the methodbetweenis available on the value of the target<property>, it is called withhiandloas arguments. Hence, it can be used for geometric objects, 3D space, or other custom classes.
$compute - {<property>: {$compute (value,key,object) => ... || Array [function f,string as]}}
- Computes a value for
<propertyusing the provided function and either replaces the property value ifasis null or undefined. Or, it adds a property with the nameasand sets it to the computed value.
$count - {<property>: {$count: number count}}
- Returns
trueif the value of<property>equalscountbased on a full evaluation of the underlying iterable on the target ignoringundefined.
$counta - {<property>: {$counta: number count}}
- Similar to
$countexcept that is trusts the.lengthor method calls forcount()on the underlying iterable if available.
$date - {<property>: {$date: number dayOfMonth}}
- If the target
<property>has a Date value wheregetDate() === dayOfMonth, matching continues; otherwise, matching fails.
$day - {<property>: {$day: number dayOfWeek}}
- If the target
<property>has a Date value wheregetDay() === dayOfWeek, matching continues; otherwise, matching fails.
$default - {<property>: {$default: any value}}
- Sets value of target
<property>tovalueif it is undefined.
$define - {<property>: {$define: {enumerable,configurable,writable[,value]}}
- Defines the
<property>on the target object using the descriptor provided and sets the value to that of the value already on the target. If the optionalvalueis provided on the descriptor, uses that instead of the current value on the target and creates the property if it does not exist.
$descendant - {<property>: {$descendant: <pattern>}}
- Returns
trueand matching continues if any descendant of the property on the target matches the<pattern>; otherwise, matching fails.
$disjoint - {<property>: {$disjoint: Array array}}
- Returns
trueand matching continues if the array on the target<property>is disjoint (has no values in common) witharray; otherwise, matching fails.
$disjunction - {<property>: {$disjunction: Array array}}
- Sets the
<property>on the target to the disjunction of the array on the target witharray. If the property does not contain an array, matching fails. Ifarrayhas anasand additional property, it is added to hold the disjunction. To set theasproperty on an array, pass in this self evaluating function:((array, as) => { array.as = as; return array; })().
$echoes - {<property>: {$echoes: string value}}
- If
soundex(<targetPropertyValue>)===soundex(value), matching continues; otherwise, matching fails.
$eeq - {<property>: {$eeq: string||number||boolean||object value}}
- If
<targetPropertyValue> === value, matching continues; otherwise, matching fails.
$eq - {<property>: {$eq: string||number||boolean||object value}}
- If
<targetPropertyValue> == valueor in the case ofobject, is deep equal to, matching continues; otherwise, matching fails.
$every - {<property>: {$every: (any item,any key,iterable) =>}}
- Returns
trueif the provided function returnstruthyfor every value in theIterablestored in the target<property>and matching continues; otherwise, matching fails. Fails if the value of the target<property>is not anIterable. Unlike its JavaScript counterpart, the target<property>value can be any type ofIterable, not just anArrayand if the function returns aPromise, it will be awaited.
$excludes - {<property>: {$excludes: any value}}
- Converse of
$inand$includes.
$extract - {<property>: {$extract: <pattern>}}
Replaces the value of the <property> on the target with only the portions of its children explicity referenced in <pattern>.
$false - {<property>: {$false: null}}
- Returns false and matching fails; otherwise, matching continues. To compare a value to
false, use$eqor$eeq.
$filter - {<property>: {$filter: function (any value) => ...}}
- Sets
<property>on target to anArrayafter filtering theIterablevalue of the property usingf. Sincefis an in place operation, noasalias is available, use$mapfor this purpose. Unlike its JavaScript counterpart, generalIterablevalues are supported, not justArrayvalues. If no target<property>exists or it is not anIterable, returnsfalseand matching fails.
$forDescendant - {<property>: {$forDescendant: {<pattern>,function f,number depth=Infinity}}
Walks the descendant tree of the <property on the target, if any. Calls f for every node that matches pattern. Will stop descending at depth or the end of the tree. Automatcially avoids circular structures.
$forEach - {<property>: {$forEach: (value,key,iterable) => ...}}
- Sets
<property>on target to anArrayafter applying the supplied function to theIterablevalue of the property. Unlike its JavaScript counterpart, generalIterablevalues are supported, not justArrayvalues and if the function returns aPromise, it will be awaited. If no target<property>exists,falseis returned and matching fails.
$freeze - {<property>: {$freeze: deep}}
- Sets
<property>on target to frozen version of itself. Ifdeepis true, applies to child objects also. If value isnullorundefined, sets toObject.freeze({}).
$fullYear - {<property>: {$fullYear: number fullYear}}
- If the target
<property>has a Date value wheregetFullYear() === fullYear, matching continues; otherwise, matching fails.
$gt - {<property>: {$gte: string||number||boolean value}}
- If
<targetPropertyValue> > value, matching continues; otherwise, matching fails.
$gte - {<property>: {$gte: string||number||boolean value}}
- If
<targetPropertyValue> >= value, matching continues; otherwise, matching fails.
$hours - {<property>: {$hours: number hours}}
- If the target
<property>has a Date value wheregetHours() === hours, matching continues; otherwise, matching fails.
$in - {<property>: {$in: object container}}
- If the target
<property>value is contained in thecontainer, returnstrueand matching continues; otherwise, matching fails. The function is polymorphic, it will work if thecontaineris anIterableor supports the methodinorcontainersupports the methodincludesorcontains.
$includes - {<property>: {$includes: object container}}
- The same as
$in, except the order is swapped.
$instanceof - {<property>: {$instanceof: string className||function ctor}}
- If a
classNameis provided, it is used to look-upctorin the JOQULAR contructor registry maitained by usingJOQULAR.register(ctor[,name)andJOQULAR.unregister(ctor[,name). If<targetPropertyValue> instanceof ctorreturnstrueand matching continues; otherwise, matching fails.
$intersection - {<property>: {$intersection: Array array}}
- Sets the
<property>on the target to the intersection of the array on the target witharray. If the property does not contain an array, the matching fails. Ifarrayhas anasand additional property, it is added to hold the intersection. To set theasproperty on an array, pass in this self evaluating function:((array, as) => { array.as = as; return array; })().
$intersects - {<property>: {$intersects: Array array}}
- If the array on the target
<property>intersects witharray, matching continues; otherwise, matching fails.
$isAny - {<property>: {$isAny: types=["boolean","function","number","object","string"]}}
- If
types.includes(<targetPropertyValue>)istrue, matching continues; otherwise, matching fails. By default this is all types except "undefined".
$isArray - {<property>: {$isArray: null}}
- If
Array.isArray(<targetPropertyValue>)istrue, matching continues; otherwise, matching fails.
$isCreditCard - {<property>: {$isCreditCard: null}}
- If the value of the target
<property>looks like a credit card number and satifies the Luhn algorithm, matching continues; otherwise, matching fails.
$isEmail - {<property>: {$isEmail: null}}
- If the value of the target
<property>looks like an e-mail address, matching continues; otherwise, matching fails.
$isEven - {<property>: {$isEven: null}}
- If
<targetPropertyValue> % 2 === 0, matching continues; otherwise, matching fails.
$isFrozen - {<property>: {$isFrozen: null}}
- If
Object.isFrozen(<targetPropertyValue>)istrue, matching continues; otherwise, matching fails.
$isIPAddress {<property>: {$isIPAddress: null}}
If the target
<property>satisfies the regular expression istrue, matching continues; otherwise, matching fails.(/^(?:(?:250-5|20-4|01?0-9?).){3}(?:250-5|20-4|01?0-9?)$/m).
$isNaN - {<property>: {$isNan: null}}
- If the value of the target
<property>satisfiesisNaN(value)istrue, matching continues; otherwise, matching fails.
$isOdd - {<property>: {$isOdd: null}}
- If
<targetPropertyValue> % 2 !== 0, matching continues; otherwise, matching fails.
$isSSN - {<property>: {$isSSN: null}}
If the target
<property>value satisfies the regular expression, matching continues; otherwise, matching fails./^\d{3}-?\d{2}-?\d{4}$/.
$length - {<property>: {$length: value}}
- If
<targetPropertyValue>.length === value, matching continues; otherwise, matching fails.
$lt - {<property>: {$lt: string||number||boolean value}}
- If
<targetPropertyValue> < value, matching continues; otherwise, matching fails.
$lte - {<property>: {$lte: string||number||boolean value}}
- If
<targetPropertyValue> <= value, matching continues; otherwise, matching fails.
$lock - {<property>: {$lock: null}}
- Modifies the
<property>on the target to be non-configurable and non-writable.
$map - {<property>: {$map: function f||Array [function f,string as]}}
- Sets
<property>on target to anArrayresulting from mapping theIterablevalue of the property using the provided functionf. Ifasis provided an additional property is added instead of setting<property>. Unlike its JavaScript counterpart, generalIterablevalues are supported, not justArrayvalues. If no target<property>exists,falseis returned and matching fails. The functionfshould take the form(value,index,iterable) => ....
$match - {<property>: {$match: any value}}
- If the target
<property>value isundefinedornullfails and matching stops.$matchis polymorphic. If the target<property>value is aboolean,number, orstring, thevalueis assumed to be aRegExpor a string delimited with/s convertable into aRegExp; otherwise, the value of thetargetproperty must support the methodmatchormatches. If theRegExphas matches or the method returnstruematching continues; otherwise matching fails.
$matches - {<property>: {$matches: any value||Array [any value,string as]}}
- If the target
<property>value isundefinedornullfails and matching stops.$matchesis polymorphic. If the target<property>value is aboolean,number, orstring, thevalueis assumed to be aRegExpor a string delimited with/s convertable into aRegExp; otherwise, the value of thetargetproperty must support the methodmatchormatches. Sets<property>on target to the the result of callingmatches(value)ormatch(value).
$max - {<property>: {$max: string||number||boolean value}}
- Assumes the current value of the
<property>on the target is an iterable. Get's the max and either replaces the property value with the max ifasequalsnull. Or, it adds a property with the nameasand sets it to the max.
$maxa - {<property>: {$max: string||number||boolean value}}
- Same as
$max, excepttrueandfalseare treated like 1 and 0 respectively and an attempt is made to parse string values as numbers.
$milliseconds - {<property>: {$milliseconds: number milliseconds}}
- If the target
<property>has a Date value wheregetMilliseconds() === millisecondsmatching continues; otherwise, matching fails.
$min - {<property>: {$min: string||number||boolean value}}
- Assumes the current value of the
<property>on the target is anIterable. Get's the min and either replaces the property value with the min ifasequalsnull. Or, it adds a property with the nameasand sets it to the min. If the value is not anIterable, matching fails.
$mina - {<property>: {$min: string||number||boolean value}}
- Same as
$min, excepttrueandfalseare treated like 1 and 0 respectively and an attempt is made to parse string values as numbers.
$minutes - {<property>: {$minutes: number minutes}}
- If the target
<property>has a Date value wheregetMinutes() === minutesmatching continues; otherwise, matching fails.
$month - {<property>: {$month: number month}}
- If the target
<property>has a Date value wheregetMonth() === monthmatching continues; otherwise, matching fails.
$ne - Alias for $neq.
$neeq - {<property>: {$neeq: string||number||boolean||object value}}
- If
<targetPropertyValue>!== valuematching continues; otherwise, matching fails.
$neq - {<property>: {$neq: string||number||boolean||object value}}
- If
<targetPropertyValue> != valueor in the case of an object are not deep equal matching continues; otherwise, matching fails.
$nin - {<property>:{$nin: object value}}
- Converse of
$in.
$not - {<property>:{$not: <pattern>}}
Returns true and matching continues is the value of the target <property does not satisfy the JOQULAR pattern; otherwise, matching fails.
$on - {<property>:{$on:{get,set,delete,onError}}}
Adds handlers to the target <property> that are invoked for get, set, and delete. The handlers take the standard form (object,key,value[,oldvalue]) => ... with only set getting oldvalue. If a handler returns a Promise it is NOT awaited.
If onError is provided it should have the signature (error,object,key,value[,oldvalue]) => .... The onError function can chose to swallow the error or re-throw it. Note, if the error is critical and the desrie is to abort the attempted action, the onError handler must be synchronus, i.e. not return a Promise or throw from a timeout.
$or - {<property>:{$or: Array [<pattern>,...]||<logical pattern>}}
Returns true and matching continues if the value of the target <property> satisfies one of the JOQULAR patterns in the Array or a nested logical pattern, e.g. {$or: {$and: ...}; otherwise, matching fails.
$outside - {<property>: {$outside: [number hi,number lo]}}
- Returns
trueand matching continues if the value of<property>on the target is outsidehiandlo. The value of the target<property>can be a Date in addition to anumberor astring. The function is polymorphic. If the methodoutsideis available on the value of the target<property>, it is called withhiandloas arguments. Hence, it can be used for geometric objects, 3D space, or other custom classes.
$readonly - {<property>: {$readonly: null}}
Returns true and continue matching if the <property> exists on the target and is read-only; otherwise, matching fails.
$redact - {<property>: {$redact null||(key,value,object) => ...}}
Deletes the <property> from the target if argument is null or the provided function returns true.
$reduce - {<property>: {$reduce: function f||Array [function f,accum,as]}}
- Sets
<property>on target to anArrayresulting from reducing theIterablevalue of the property using the provided functionf. Ifaccumis not provided, the first value of theIterableis used. Ifasis provided an additional property is added instead of setting<property>. Unlike its JavaScript counterpart, generalIterablevalues are supported, not justArrayvalues. If no target<property>exists,falseis returned and matching fails. The functionfshould take the form(accum,value,index,iterable) => ....
$regexp - {<property>: {$regexp: RegExp regexp}}
Alias for $match.
$return - {<property>: {$return: any value}}
Sets the value on the target <property> to value.
$sample - {<property>: {$sample: number 0.pct||[0.pct,number max=Infinity,string as]}}
Assumes the target <property> is an Iterable and computes a random sample of max size or percentage * size. The sample is stored in the target property unless as is specified to add a property. The pct is a decimal between zero and one. The chance of any given item being picked is independenty equal to the pct. This is because for some iterables the size is not known until the entire iterable has been processed. Be careful not to try and sample an infinitely yielding Iterator without providing a length. If the value of the target <property> is not an iterable, matching fails.
$search - {<property>: {$search: string searchPhrase||[string searchPhrase,number stems,number trigrams=0.8,string language]}
- Returns
trueand matching continues ifsearchPhraseis found in the value of the target<property>. The search is conducted using stemmed tokens and trigrams. The stem matching is usesorunlessstemsis set to a number between zero and 1 to use as a percentage stem match . If stem matching fails, trigram matching is attempted must equal or exceed 80%. To turn off trigram matching, explicitly passtrigrams=1.0.$searchis polymorphic. If the target<property>value supports the methodsearchthen it is called withsearchPhraseas the first argument and{language,stems,trigrams}as the second. The only language currently supported is "en", English.
$seconds - {<property>: {$seconds: number seconds}}
- Returns
trueif the target<property>has a Date value wheregetSeconds() === seconds.
$some - {<property>: {$some: (any item,any key,Iterable iterable) =>}}
- Returns
trueif the provided function returnstruthyfor some value in theIterablestored in the target<property>and matching continues; otherwise, matching fails. Fails if the value of the target<property>is not anIterable. Unlike its JavaScript counterpart, the target<property>value can be any type ofIterable, not just anArrayand if the function returns aPromise, it will be awaited.
$sort - {<property>: {$sort: (any a, any b) => ... || [(any a,any b) => ...,as]}}
- Assumes the current value of the
<property>on the target is an iterable. Sorts the values using the normal JavaScript sort approach and replaces the property value with the sorted value iasequalsnull. Or, it adds a property with the nameasand sets it to the average. If the value of the target<property>is not an iterable, matching fails.
$sum - {<property>: {$sum: null||string as}}
- Assumes the current value of the
<property>on the target is an iterable. Averages the numbers and either replaces the property value with the average ifasequalsnull. Or, it adds a property with the nameasand sets it to the average. If the value of the target<property>is not an iterable, matching fails.
$suma - {<property>: {$sum: null||string as}}
- Same as
$sum, excepttrueandfalseare treated like 1 and 0 respectively and an attempt is made to parse string values as numbers.
$text - {<property>: {$text: string searchPhrase||[string searchPhrase,string language]}
Aliased to $search. Unlike MongoDB, case sensisitivity is not supported and the search uses stems and trigrams.
$time - {<property>: {$time: number time}}
- Returns
trueand matching continues if the target<property>has a Date value wheregetTime() === time; otherwise, matching fails.
$true - {<property>: {$true: null}}
- Returns
trueand matching continues; otherwise, matching fails. To compare a value totrue, use$eqor$eeq.
$type - Alias for $typeof.
$typeof - {<property>: {$typeof: string type}}
- Returns
trueif the value of the target<property>== type.
$UTCDate - {<property>: {$UTCDate: number date}}
- Same as $date, except for UTC value.
$UTCDay -{<property>: {$UTCDay: number day}}
- Same as $day, except for UTC value.
$UTCFullYear - {<property>: {$UTCFullYear: number fullYear}}
- Same as $fullYear, except for UTC value.
$UTCHours -{<property>: {$UTCHours number hours}}
- Same as $hours, except for UTC value.
$UTCMilliseconds -{<property>: {$UTCMilliseconds: number milliseconds}}
- Same as $milliseconds, except for UTC value.
$UTCMinutes -{<property>: {$UTCMinutes: number minutes}}
- Same as $minutes, except for UTC value.
$UTCMonth -{<property>: {$UTCMonth: number month}}
- Same as $month, except for UTC value.
$UTCSeconds -{<property>: {$UTCSeconds: number seconds}}
- Same as $seconds, except for UTC value.
$valid - {<property>: {$valid: (value,key,object) => ... || <pattern>}}
If a function is passed in and returns true matching continues. If a pattern is passed in, JOQULAR confirms the <property> value on the target conforms with the <pattern>. If it does not conform and the pattern contains onError with a function value the function is called with (error,value,key,object). If no onError is provided or its value is not a function, an error is thrown.
$value - {<property>: {$value: (value,key,object)=>...}}
Alias for $compute.
$where - {<property>: {$where: (value,key,object)=>...}}
Alias for $.
$xor - {<property>:{$xor: Array [<pattern>,...]||<logical pattern>}}
Returns true and matching continues if the value of the target <property> satisfies at most one of the JOQULAR patterns in the Array or a nested logical pattern, e.g. {$or: {$and: ...}; otherwise, matching fails.
$year - {<property>: {$year: number year}}
- Returns
trueif the target<property>has a Date value wheregetYear() === year.
Updates
2019-02-15 v2.03b - $length now handles .count, .count(), .size, .size(), .length.
2019-02-12 v2.03b - All functions now have basic documentation.
2019-02-11 v2.02b - Lots of documentation. Started deprecation on method name .match in favor of .query, but both will work for now through aliasing.
2019-02-10 v2.0.1b - .match now returns an array and can take multiple objects to match against. Added event handlers via
$on. Now returns source object if no-mutations have occured.
2019-02-10 v2.0.0b - Initial public reference implementation subsequent to deprecation of JOQULAR as an in memory datastore.