joqular
v2.0.4-b
Published
JOQULAR (JavaScript Object Query Language Representation) for JSON data matching, transformation, validation and extraction
Downloads
24
Readme
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 undefined
JOQULAR 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
as
on 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 ifas
equalsnull
. Or, it adds a property with the nameas
and sets it to the average.
$avga - {<property>: {$avg: null||string as}}
- Same as
$avg
, excepttrue
andfalse
are 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
true
and mathcing continues if the value of<property>
on the target is betweenhi
andlo
, optionally inclusive of the boundaries; otherwise, matching fails. The value of the target<property>
can be a Date in addition to anumber
or astring
. The function is polymorphic. The function is polymorphic. If the methodbetween
is available on the value of the target<property>
, it is called withhi
andlo
as 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
<property
using the provided function and either replaces the property value ifas
is null or undefined. Or, it adds a property with the nameas
and sets it to the computed value.
$count - {<property>: {$count: number count}}
- Returns
true
if the value of<property>
equalscount
based on a full evaluation of the underlying iterable on the target ignoringundefined
.
$counta - {<property>: {$counta: number count}}
- Similar to
$count
except that is trusts the.length
or 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>
tovalue
if 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 optionalvalue
is 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
true
and matching continues if any descendant of the property on the target matches the<pattern>
; otherwise, matching fails.
$disjoint - {<property>: {$disjoint: Array array}}
- Returns
true
and 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. Ifarray
has anas
and additional property, it is added to hold the disjunction. To set theas
property 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> == value
or in the case ofobject
, is deep equal to, matching continues; otherwise, matching fails.
$every - {<property>: {$every: (any item,any key,iterable) =>}}
- Returns
true
if the provided function returnstruthy
for every value in theIterable
stored 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 anArray
and if the function returns aPromise
, it will be awaited.
$excludes - {<property>: {$excludes: any value}}
- Converse of
$in
and$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$eq
or$eeq
.
$filter - {<property>: {$filter: function (any value) => ...}}
- Sets
<property>
on target to anArray
after filtering theIterable
value of the property usingf
. Sincef
is an in place operation, noas
alias is available, use$map
for this purpose. Unlike its JavaScript counterpart, generalIterable
values are supported, not justArray
values. If no target<property>
exists or it is not anIterable
, returnsfalse
and 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 anArray
after applying the supplied function to theIterable
value of the property. Unlike its JavaScript counterpart, generalIterable
values are supported, not justArray
values and if the function returns aPromise
, it will be awaited. If no target<property>
exists,false
is returned and matching fails.
$freeze - {<property>: {$freeze: deep}}
- Sets
<property>
on target to frozen version of itself. Ifdeep
is true, applies to child objects also. If value isnull
orundefined
, 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
, returnstrue
and matching continues; otherwise, matching fails. The function is polymorphic, it will work if thecontainer
is anIterable
or supports the methodin
orcontainer
supports the methodincludes
orcontains
.
$includes - {<property>: {$includes: object container}}
- The same as
$in
, except the order is swapped.
$instanceof - {<property>: {$instanceof: string className||function ctor}}
- If a
className
is provided, it is used to look-upctor
in the JOQULAR contructor registry maitained by usingJOQULAR.register(ctor[,name)
andJOQULAR.unregister(ctor[,name)
. If<targetPropertyValue> instanceof ctor
returnstrue
and 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. Ifarray
has anas
and additional property, it is added to hold the intersection. To set theas
property 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.(/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][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 anArray
resulting from mapping theIterable
value of the property using the provided functionf
. Ifas
is provided an additional property is added instead of setting<property>
. Unlike its JavaScript counterpart, generalIterable
values are supported, not justArray
values. If no target<property>
exists,false
is returned and matching fails. The functionf
should take the form(value,index,iterable) => ...
.
$match - {<property>: {$match: any value}}
- If the target
<property>
value isundefined
ornull
fails and matching stops.$match
is polymorphic. If the target<property>
value is aboolean
,number
, orstring
, thevalue
is assumed to be aRegExp
or a string delimited with/
s convertable into aRegExp
; otherwise, the value of thetarget
property must support the methodmatch
ormatches
. If theRegExp
has matches or the method returnstrue
matching continues; otherwise matching fails.
$matches - {<property>: {$matches: any value||Array [any value,string as]}}
- If the target
<property>
value isundefined
ornull
fails and matching stops.$matches
is polymorphic. If the target<property>
value is aboolean
,number
, orstring
, thevalue
is assumed to be aRegExp
or a string delimited with/
s convertable into aRegExp
; otherwise, the value of thetarget
property must support the methodmatch
ormatches
. 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 ifas
equalsnull
. Or, it adds a property with the nameas
and sets it to the max.
$maxa - {<property>: {$max: string||number||boolean value}}
- Same as
$max
, excepttrue
andfalse
are 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() === milliseconds
matching 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 ifas
equalsnull
. Or, it adds a property with the nameas
and sets it to the min. If the value is not anIterable
, matching fails.
$mina - {<property>: {$min: string||number||boolean value}}
- Same as
$min
, excepttrue
andfalse
are 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() === minutes
matching continues; otherwise, matching fails.
$month - {<property>: {$month: number month}}
- If the target
<property>
has a Date value wheregetMonth() === month
matching continues; otherwise, matching fails.
$ne - Alias for $neq
.
$neeq - {<property>: {$neeq: string||number||boolean||object value}}
- If
<targetPropertyValue>!== value
matching continues; otherwise, matching fails.
$neq - {<property>: {$neq: string||number||boolean||object value}}
- If
<targetPropertyValue> != value
or 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
true
and matching continues if the value of<property>
on the target is outsidehi
andlo
. The value of the target<property>
can be a Date in addition to anumber
or astring
. The function is polymorphic. If the methodoutside
is available on the value of the target<property>
, it is called withhi
andlo
as 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 anArray
resulting from reducing theIterable
value of the property using the provided functionf
. Ifaccum
is not provided, the first value of theIterable
is used. Ifas
is provided an additional property is added instead of setting<property>
. Unlike its JavaScript counterpart, generalIterable
values are supported, not justArray
values. If no target<property>
exists,false
is returned and matching fails. The functionf
should 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
true
and matching continues ifsearchPhrase
is found in the value of the target<property>
. The search is conducted using stemmed tokens and trigrams. The stem matching is usesor
unlessstems
is 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
.$search
is polymorphic. If the target<property>
value supports the methodsearch
then it is called withsearchPhrase
as the first argument and{language,stems,trigrams}
as the second. The only language currently supported is "en", English.
$seconds - {<property>: {$seconds: number seconds}}
- Returns
true
if the target<property>
has a Date value wheregetSeconds() === seconds
.
$some - {<property>: {$some: (any item,any key,Iterable iterable) =>}}
- Returns
true
if the provided function returnstruthy
for some value in theIterable
stored 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 anArray
and 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 ias
equalsnull
. Or, it adds a property with the nameas
and 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 ifas
equalsnull
. Or, it adds a property with the nameas
and 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
, excepttrue
andfalse
are 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
true
and matching continues if the target<property>
has a Date value wheregetTime() === time
; otherwise, matching fails.
$true - {<property>: {$true: null}}
- Returns
true
and matching continues; otherwise, matching fails. To compare a value totrue
, use$eq
or$eeq
.
$type - Alias for $typeof
.
$typeof - {<property>: {$typeof: string type}}
- Returns
true
if 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
true
if 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.