objql-object-query-language v3.2.0
ObjQL
ObjQL is a helpful library allowing you to select particular entries from a collection, i.e., an array of objects. An example of code using that is below:
const collection = [
{name: 'Adam', age: 18},
{name: 'Adam', age: 42},
{name: 'Mark', age: 19},
{name: 'Joseph', age: 34},
{name: 'Jack', age: 42},
{name: 'Michael', age: 24}
];
const results = ObjQL
.from(collection)
.select('*')
.where({
age: 18
})
.sort('name')
.limit(2,3);
// => [{name: 'Adam', age: 18}]Currently, the select() method only supports '*' as a first parameter.
It will change in one of the future releases.
Methods must be called in the following order:
from(),select(),where(),sort()andlimit(). The last two may be omitted, however.
Installation
npm i objql-object-query-languageCompound fields
Items in a collection can have additional fields added. To do so, use a callback as a second parameter of the select() method.
.select('*', item => ({
desc: `${item.name} being ${item.age} having a ${item.extra}`
}))Dependencies of compound fields
When some field doesn't have some property, a compound field may have a value that contains undefined, what might not be intended.
As a third parameter of the select() method, you can pass an array of strings - property names that all must be present in item to add compound properties.
.select('*', item => ({
desc: `${item.name} being ${item.age} having a ${item.extra}`
}), ['name', 'age', 'extra'])Shortcuts for Functions
| Function | Shortcut |
|---|---|
{name: ObjQL.equal('John')} | {name: 'John'} |
{name: ObjQL.regExp(/^J/)} | {name: /^J/} |
group: ObjQL.in(['A', 'B', 'C']) | {group: new Set(['A', 'B', 'C'])} |
{age: ObjQL.range(20, 32)} | {age: [20, 32]} |
Functions
General
| Function | Purpose | Example |
|---|---|---|
| equal(value, strict?=true) | match value that equals another one | {age: ObjQL.equal('20', false)} |
| is(value) | match value that is equal to another one (uses Object.is()) | {result: ObjQL.is(NaN)} |
| in(valuesArray) | match value that equals one from an array | {group: ObjQL.in(['A', 'B', 'C', 'D'])} |
| range(min, max) | match value that is from the range <min;max> | {age: ObjQL.range(15, 25)} |
| regExp(re) | match value that matches to a regular expression | {name: ObjQL.regExp(/^.A/i)} |
| like(pattern) | match value that matches to a pattern (% means 0+ chars, ___ means 1 char) | {name: ObjQL.like('%A_a_')} |
| ref(anotherField) | match value by a value of other field | {name: ObjQL.ref('fatherName')} |
| match(fn) | match value by a custom condition | {name: ObjQL.match((val, rec) => val === rec.surname)} |
| size(numberOrRange) | match value by its length or size | {term: ObjQL.size([20, null])} |
| likeArray(valuesArr) | match value that is an array containing all the values from the array passed to the matcher (meanwhile can contain other values) | {flags: ObjQL.likeArray(['canWrite', 'canEdit'])} |
| likeExactArray(valuesArr, checkIndexes?=false) | match value that is an array containing all the values from the array passed to the matcher (meanwhile can't contain other values) | {badges: ObjQL.likeExactArray(['Freshman'])} |
The match() matcher
A callback passed to the match() matcher can accept up to 4 parameters:
- value of a field in a current record
- entire current record
- index of the current record in the entire collection
- entire collection
// get items followed by another item whose
// `result` property is greater than or equal to
// the `result` property of the current item
ObjQL.from(collection)
.select('*')
.where({
name: ObjQL.match((name, item, idx, coll) => {
return (
coll[idx+1] &&
coll[idx+1].result >= item.result
);
})
})Strings
| Function | Purpose | Example |
|---|---|---|
| firstChar(char) | match value by the first character | {city: ObjQL.firstChar('A')} |
| lastChar(char) | match value by the last character | {city: ObjQL.lastChar('Z')} |
| nthChar(char, position) | match value by the n-th character | {city: ObjQL.nthChar('D', 3)} |
| startsWith(substr, caseSensitive?=true) | match value by the beginning | {city: ObjQL.startsWith('Los')} |
| endsWith(substr, caseSensitive?=true) | match value by the end | {city: ObjQL.endsWith('os')} |
| contains(substr, caseSensitive?=true) | match value by a substring | {city: ObjQL.contains('yo')} |
Date
There are functions checking date that can be represented by:
- a particular value (e.g.,
month(4)to match April) - an instance of the
Date() - a timestamp (a number of milliseconds that have passed from 01.01.1970 00:00:00)
- a string in one of the following formats:
YYYY-MM-DD HH:mm:ss.uuuDD.MM.YYYY HH:mm:ss.uuu*MM/DD/YYYY HH:mm:ss.uuu - the
ObjQL.CURRENTconstant
When it comes to the latest three, the following parts are optional: entire time part (
HH:mm:ss.uuu), seconds with milliseconds (ss.uuu) and milliseconds (uuu).
| Function | Purpose | Example |
|---|---|---|
| day(dayIndexOrRange) | match value by a day in date | {birth_date: ObjQL.day(20)} |
| month(monthIndexOrRange) | match value by a month in date | {birth_date: ObjQL.month(12)} |
| year(fullYearOrRange) | match value by a full year (e.g., 1998 rather than 98) | {registered: ObjQL.year(2010)} |
| hour(hourOrRange) | match value by an hour | {orders: ObjQL.hour(15)} |
| minute(minuteOrRange) | match value by a minute | {orders: ObjQL.minute(30)} |
| second(secondOrRange) | match value by a second | {lap: ObjQL.second(10)} |
| millisecond(msOrRange) | match value by a millisecond | {click: ObjQL.millisecond(12)} |
| date(dateFormat, dateValue) | match value by a date | {birth_date: ObjQL.date('DD.MM', '14.02')} |
| weekDay(weekDayIndexOrRange) | match value by a week day (1=Monday, 7=Sunday) | {weekend_visits: ObjQL.weekDay(6)} |
The
dateFormatparameter in thedate()method can consist of the following parts:YYYY- full year,MM- month,DD- day,HH- hour,mm- minute,ss- second,uuu- millisecond.
Examples of matching date
- match entries where the
start_datefield is date whose month is April
where({
start_date: ObjQL.month(4)
})- match entries where the
start_datefield is date whose day is 14th and month is February
where({
start_date: ObjQL.date('DD.MM', '14.02')
})Note that the second parameter may be the standard date. In such a case, it does not have to match a format given as the first parameter. Elements from the first parameter will be used to compare dates:
where({
// pass entire date
// but only compare day and month
start_date: ObjQL.date('DD.MM', '2020-02-14 15:45:30')
})- match entries where the
event_datefield is date whose week day is Friday, Saturday or Sunday
where({
event_date: ObjQL.weekDay([5, 7])
})Array of Numbers
| Function | Purpose | Example |
|---|---|---|
| min(numberOrRange) | match value by minimum value(s) in an array | {height: ObjQL.min([180, null])} |
| max(numberOrRange) | match value by maximum value(s) in an array | {weight: ObjQL.max(100)} |
| avg(numberOrRange) | match value by average value(s) of an array | {test: ObjQL.avg([4, 5])} |
| sum(numberOrRange) | match value by sum of an array items | {width: ObjQL.sum(24)} |
| count(item, numberOrRange) | match value by a number of item occurencies | {comment: ObjQL.count('fuc', [null, 3])} |
| unique(numberOrRange) | match value by a number of unique items | {awards: ObjQL.unique([10, 50])} |
Example ranges:
count('a', [1, 4])- a number of occurencies ofa>= 1 and <= 4count('a', [2, null])- a number of occurencies ofa>= 2count('a', [null, 5])- a number of occurencies ofa<= 5
How do min()/max() work?
const collection = ObjQL.from([
{name: 'John', marks: [3, 4, 6]},
{name: 'Mark', marks: [2, 3, 5]}
]);
const result = collection.select('*').where({
marks: ObjQL.min(2)
});
// only Mark has been matched
// John has not as his minimum value is 3
const result2 = collection.select('*').where({
marks: ObjQL.min([2, 4])
});
// both Mark and John have been matched
// given minimum value is from the range 2-4
const result3 = collection.select('*').where({
marks: ObjQL.min([null, 2])
});
// only Mark has been matched
// minimum value must be less or equal to 2 [null, 2]
const result4 = collection.select('*').where({
marks: ObjQL.min([2, null])
});
// both Mark and John have been matched
// minimum value must be greater or equal to 2 [2, null]Objects
| Function | Purpose | Example |
|---|---|---|
| hasKey(keyName) | match object that has a given key | {config: ObjQL.hasKey('language')} |
| hasKeys(keyNamesArr, mode) | match object that has the given keys: all (if mode equals ALL, it's default value) or some (if mode equals SOME) | {theme: ObjQL.hasKeys(['color', 'background'], 'SOME')} |
| hasValue(value) | match object that has a given value | {theme: ObjQL.hasValue('pink')} |
| hasValues(valuesArr, mode) | match object that has the given values, all or some depending on mode (ALL being default value or SOME) | {config: ObjQL.hasValues(['PL', 'FR'], 'SOME')} |
| hasProp(keyName, value) | match object that has a given key equal to given value | {theme: ObjQL.hasProp('color', 'red')} |
| hasProps(pairArr, mode) | match object that has the given keys equal to a respective value (depending on mode: ALL (default) or SOME) | {config: ObjQL.hasProps([['language', 'PL'], ['location', 'Poland']])} |
Types
| Function | Purpose | Example |
|---|---|---|
| isType(type) | match value by the type (uses Object#toString(), matching is case insensitive) | {pattern: ObjQL.isType('regexp')} |
| isInstanceOf(klazz) | match value that is instance of the given class | {publishedAt: ObjQL.isInstanceOf(Date)} |
| isNull() | match value that equals null | {projects: ObjQL.isNull()} |
| isUndefined() | match value that is undefined | {dob: ObjQL.isUndefined()} |
| isTruthy() | match value that is truthy | {results: ObjQL.isTruthy()} |
| isFalsy() | match value that is falsy | {skills: ObjQL.isFalsy()} |
| isInteger() | match value that is an integer | {progress: ObjQL.isInteger()} |
| isFloat() | match value that is a float | {average: ObjQL.isFloat()} |