@depax/dql v1.0.2
DepaxQL
Installation
Install the package normally using NPM or Yarn.
yarn add @depax/dqlUsage
import dql from "@depax/dql";
const query = dql("fields(a,b),eq(a,c)");
// Or with parameters;
const query = dql("fields($2,$3),$1($2,c)", [ "eq", "a", "b" ]);Converters
Converters provide a means to typecast a value, for example true could be a string or a boolean, so we have converters
which will attempt to correctly typecast. There are two types of converters, auto and callback.
Auto converters
Several auto converters have been defined to try and assume what the value should be. We have an auto converter for
true so we can search for this and if we see a value true then it will get converted to the boolean value of true.
-Infinity=> (number) -InfinityInfinity=> (number) Infinitytrue=> (boolean) truefalse=> (boolean) falsenull=> nullundefined=> undefined
Manual converters
Manual converters are down to the query to apply, so in the above example if we want the string version of true we
would do something like eq(field,string:true).
Note the string:, this is the name of the converter followed by a : then the value.
There are several converters defined;
autoThis is the callback used to perform the auto conversion,boolandbooleanBoolean converters, this will attempt to convert any of true, yes, 1, on to true, otherwise the value will be false,dateThis will try to convert a number or string into a date object,numberThis will attempt to convert the value to a number, if it fails it will use0,reandregexThis will convert the value to a RegExp object,reiandregexiThis will convert the value to a RegExp object and apply theiflag,stringThis will convert the value into a string,
Operators
A query string is made up of different operators, there are the comparitors for comparing a fields value, logical
for combine operators in logic groups such as and and or, and modifiers used for modifiying the results (such as
sorting, limiting, etc).
These are combined using a comma delimited URI encoded string, for example;
fields(displayName,email),and(eq(status,true),eq(email,re:@gmail.com$)),sort(+displayName)This query is to get the fields displayName and email from all users who have a status of true and their email
ends with @gmail.com, and finally should be sorted by their displayName in ascending order.
Comparitors
Comparitor operators (with the exception to in and nin) take in two arguments, the first being the name of the field
and the second being the value. With in and nin the first is the field and every other argument is added into an
array.
eq: Equals - eq(fieldname,value)ne: Not Equals - ne(fieldname,value)lt: Lower than - lt(fieldname,value)lte: Lower than or Equal to - lte(fieldname,value)gt: Greater than - gt(fieldname,value)gte: Greater than or Equal to - gte(fieldname,value)in: In - in(fieldname,a,b,c,d)nin: Not In - nin(fieldname,a,b,c,d)
Logical
Logical operators can only contain either comparitors or other logical operators
and: And - and(eq(a,b),eq(b,c))not: Not - not(eq(a,b),eq(b,c))or: Or - or(eq(a,b),eq(b,c))nor: Not Or - nor(eq(a,b),eq(b,c))
Modifiers
Modifiers provide a means to alter the query, so in the form of limit we can return 25 documents, with an optional
offset, or tell the query to return selected fields, etc.
fields: Select Fields - fields(a,b,c,d)limit: Limit and Offset - limit(25) or limit(25,5)sort: Sort - sort(a,+b,-c)from: From Table/Collection - from(users)
Parameter Tokens
The parser allows for taking in an array of parameter tokens, these can be used for operator names or arguments, the
tokens are prefixed with a $ and then a number, this is the index value of the parameters array starting from 1.
For example;
const query = dql("fields($2,$3),$1($2,c)", [ "eq", "a", "b" ]);will result in a query string like fields(a,b),eq(a,c) as $1 is replaced with eq, $2 is replaced with a and
$3 is replaced with b.
Extending
Additional comparitors, logical and modifiers operators and converters can be added or altered to suit some
requirements.
Comparitor operator
A comparitor is a callback which outputs the field name and the required value, for example the callback for the eq
operator is;
function (args: string, params: TParams): any[] {
let [ field, value ] = args.split(",");
field = ParseParamTokens(field, params);
value = ParseParamTokens(value, params);
return [ field, { $eq: value } ];
}The function will take in a string argument args, this is the arguments passed into the operator, e.g. for
eq(a,b) the args value would be a,b. The second argument params is the param tokens passed into the parser and
is used for token replacement.
In the above function we simply split the args argument by ,, the first element is the name of the field and the
second is the value. We are using a function called ParseParamTokens, this takes in a value and the params and will
attempt to find a matching token if relevant, and perform any relevant converters on it.
We then return an array, the first argument being the name of the field, and the second being the value of that field,
so if we return [ field, { $eq: value } ], this will be added on to the query object like query.selectors[result[0]] = result[1] so
then we would have something like;
{
selectors: {
a: { $eq: "b" }
}
}To add your new comparitor, it just needs to be added to the internal comparitors collection object;
import { ComparisonOperators, TParams } from "@depax/dql";
ComparisonOperators.myop = (args: string, params: TParams): any[] => {
...
};You could also override or delete a comparitor by;
// Override.
ComparisonOperators.eq = (args: string, params: TParams): any[] => {
...
});
// Delete.
delete ComparisonOperators.eq;
// Rename a comparitor.
ComparisonOperators.myop = ComparisonOperators.eq;
delete ComparisonOperators.eq;Logical operator
Logical operators are just simple string matches, e.g. and is added to a $and property, these values are stored in
the LogicalOperators object, and can be added to, altered or deleted;
import { LogicalOperators } from "@depax/dql";
LogicalOperators.myand = "$and";
// Delete.
delete LogicalOperators.and;The parser simply converts the value of the const to a property name, so for example;
LogicalOperators.and = "$and";
// ....
query.selectors[LogicalOperators[match]] = args;which would result in something like;
{
selectors: {
$and: { ... }
}
}Modifier operators
Modifiers user callbacks which can directly manipulate the query object, and again are defined on a const called
ModifierOperators.
A callback would look something like;
import { IQuery, ModifierOperators, ParseParamTokens, TParams } from "@depax/dql";
ModifierOperators.mymodifier = (args: string, params: TParams, query: IQuery): void => {
if (!query.fields) {
query.fields = [];
}
args.split(",")
.forEach((field: string) => {
query.fields.push(ParseParamTokens(field, params));
});
};Again, like before, they can be added, deleted or altered by using the ModifierOperators const;
// Override.
ModifierOperators.from = (args: string, params: TParams, query: IQuery): void => {
...
});
// Delete.
delete ModifierOperators.from;
// Rename.
ModifierOperators.table = ModifierOperators.from;
delete ModifierOperators.from;Converters
Additional converters can be added, or existing ones be deleted or altered as above and will depend on which type of converter is being added/deleted/altered.
Auto converter
To add/delete/alter an auto converter, we use the AutoConverters const object, and we simply use a value repacement,
for example;
import { AutoConverters } from "@depax/dql";
AutoConverters["undefined"] = undefined;
// This will convert the string "undefined" to the undefined reference.We could also use this to put in a form of variable replacement;
AutoConverters.hw = "hello";This will then convert eq(a,hw) into eq(a,hello).
Manual converter
Manual converters are callbacks defined within the Converters const object, this simply gets given a value and is
expected to return a value, for example the boolean converter is as follows;
function (value: any): boolean => {
return [
"true", "yes", 1, "1", "on",
].indexOf(value) > -1;
}So it recieves a value, and returns true if the value is either of true, yes, 1 or on, otherwise it returns
false.
Converters can be added as follows;
import { Converters } from "@depax/dql";
Converters.myconverter = (value: any): any => {
return `hello ${value}`;
};This example will then convert eq(a,myconverter:world) to eq(a,hello world).