@depax/dql
TypeScript icon, indicating that this package has built-in type declarations

1.0.2 • Public • Published

DepaxQL

CircleCI Todos Features Coverage Documentation Report

Installation

Install the package normally using NPM or Yarn.

yarn add @depax/dql

Usage

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) -Infinity
  • Infinity => (number) Infinity
  • true => (boolean) true
  • false => (boolean) false
  • null => null
  • undefined => 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;

  • 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,

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).

Package Sidebar

Install

npm i @depax/dql

Weekly Downloads

7

Version

1.0.2

License

Unlicense

Unpacked Size

39.2 kB

Total Files

59

Last publish

Collaborators

  • johnloveking
  • orgun109uk