1.0.1 • Published 5 years ago

uniql v1.0.1

Weekly downloads
3
License
MIT
Repository
github
Last release
5 years ago

UniQL (UNIversal Query Language)

Lets you write a simple query and run it against any datastore, like ElasticSearch and/or MongoDB.

UniQL parses a simple query langauge into an Abstract Syntax Tree that can then be used to compile a query for a given datastore. This is useful if you want a level of abstraction between your queries and how your data is actually stored/searched. You can also use UniQL to execute the same query against multiple datastores at the same time.

For example:

const parse = require( 'uniql' );
const mongoCompile = require( 'uniql-mongodb' );
const esCompile = require( 'uniql-es' );

// parse a uniql query into an AST
const queryAST = parse( '( height <= 20 or ( favorites.color == "green" and height != 25 ) ) and firstname ~= "o.+"' );

// using that AST, compile a mongodb query
const mongoQuery = mongoCompile( queryAST );
console.log( util.inspect( mongoQuery, { depth: null } ) );

// using the same AST, compile an elasticsearch query
const esQuery = esCompile( queryAST );
console.log( util.inspect( esQuery, { depth: null } ) );

For MongoDB, the query generated is:

{ '$or':
   [ { height: { '$lte': 20 } },
     { 'favorites.color': 'green', height: { '$ne': 25 } } ],
  firstname: { '$regex': 'o.+' } }

For ElasticSearch, the same query is:

{ query:
   { filtered:
      { filter:
         [ { bool:
              { must:
                 [ { bool:
                      { should:
                         [ { range: { height: { lte: 20 } } },
                           { bool:
                              { must:
                                 [ { term: { 'favorites.color': 'green' } },
                                   { bool: { must_not: { term: { height: 25 } } } } ] } } ] } },
                   { bool: { must: { regexp: { firstname: 'o.+' } } } } ] } } ] } } }

All generated from one simple query:

( height <= 20 or ( favorites.color == "green" and height != 25 ) ) and firstname ~= "o.+"

Which produces the following AST:

{ type: '&&',
  arguments:
   [ { type: 'EXPRESSION',
       arguments:
        [ { type: '||',
            arguments:
             [ { type: '<=',
                 arguments:
                  [ { type: 'SYMBOL', arguments: [ 'height' ] },
                    { type: 'NUMBER', arguments: [ '20' ] } ] },
               { type: 'EXPRESSION',
                 arguments:
                  [ { type: '&&',
                      arguments:
                       [ { type: '==',
                           arguments:
                            [ { type: 'SYMBOL', arguments: [ 'favorites.color' ] },
                              { type: 'STRING', arguments: [ 'green' ] } ] },
                         { type: '!=',
                           arguments:
                            [ { type: 'SYMBOL', arguments: [ 'height' ] },
                              { type: 'NUMBER', arguments: [ '25' ] } ] } ] } ] } ] } ] },
     { type: 'MATCH',
       arguments:
        [ { type: 'SYMBOL', arguments: [ 'firstname' ] },
          { type: 'STRING', arguments: [ 'o.+' ] } ] } ] }

Using that AST, you can generate queries for various datastores.

Available Compilers

UniQL Query Syntax

ValuesDescription
43, -1.234Numbers
true, falseBooleans
null, undefinedPrimitives
"hello"Strings
foo, a.b.cSymbols (usually a key or column name in your datastore)
OperatorsDescription
x == yEquality
x != yIneqaulity
x ~= "y"Matching evaluated as a RegExp
x < yLess than
x <= yLess than or equal to
x > yGreater than
x >= yGreater than or equal to
x or yBoolean or
x and yBoolean and
not xBoolean not
( x )Expression

Operator precedence follows that of any sane language.

Help and Feedback Wanted

This is an early pass at this. We're very open to getting pull requests to help us improve.

Things we'd love to get to, but would also welcome PRs for:

  • Maybe specifying the grammar using PEG would be cleaner/clearer
  • Improvements/expansions to the query syntax
  • Certain edge case support for things like unary not in the MongoDB driver

Credits

This was inspired by FiltrES which was in turn inspired by Filtrex

1.0.1

5 years ago

1.0.0

5 years ago

0.1.0

9 years ago

0.0.2

9 years ago

0.0.1

9 years ago