A simple string Query Language parser.
npm install @depax/dql





Install the package normally using NPM or Yarn.
``sh`
yarn add @depax/dql
`js
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 provide a means to typecast a value, for example true could be a string or a boolean, so we have convertersauto
which will attempt to correctly typecast. There are two types of converters, 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 weeq(field,string:true)
would do something like .
Note the string:, this is the name of the converter followed by a : then the value.
There are several converters defined;
- auto This is the callback used to perform the auto conversion,bool
- and boolean Boolean converters, this will attempt to convert any of true, yes, 1, on to true, otherwise the value will be false,date
- This will try to convert a number or string into a date object,number
- This will attempt to convert the value to a number, if it fails it will use 0,re
- and regex This will convert the value to a RegExp object,rei
- and regexi This will convert the value to a RegExp object and apply the i flag,string
- This will convert the value into a string,
A query string is made up of different operators, there are the comparitors for comparing a fields value, logicaland
for combine operators in logic groups such as 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@gmail.com
ends with , 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 fieldin
and the second being the value. With 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 optionalfields
offset, or tell the query to return selected , 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)
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;
`js`
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.
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;
`js
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. foreq(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 theParseParamTokens
second is the value. We are using a function called , 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;
`js`
{
selectors: {
a: { $eq: "b" }
}
}
To add your new comparitor, it just needs to be added to the internal comparitors collection object;
`js
import { ComparisonOperators, TParams } from "@depax/dql";
ComparisonOperators.myop = (args: string, params: TParams): any[] => {
...
};
`
You could also override or delete a comparitor by;
`js
// 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 inLogicalOperators
the object, and can be added to, altered or deleted;
`js
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;
`js
LogicalOperators.and = "$and";
// ....
query.selectors[LogicalOperators[match]] = args;
`
which would result in something like;
`js`
{
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;
`js
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;
`js
// 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;
`js
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;
`js`
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 isboolean
expected to return a value, for example the converter is as follows;
`js`
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;
`js
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)`.