crcn / sift.js

Use Mongodb queries in JavaScript
MIT License
1.65k stars 100 forks source link

Discussion: abstract syntax tree #202

Closed stalniy closed 4 years ago

stalniy commented 4 years ago

Hi Craig,

Currently, I’m working on SQL integration in CASL and I need to transform Mongo query into sql query. The standard way to do something like this is through AST. There are 2 steps:

  1. Transform language into AST
  2. Using Iterator or Visitor pattern walk over AST and transform it to whatever language or result you want

So, having AST of Mongo query in casl, I’ll be able to use the same pattern for 2 cases:

  1. Check permissions in runtime
  2. Transform permissions to any database query (other than mongo query)

To do this I need to implement just 2 separate implementations: RuntimeQueryIterator and SQLIterator

So, what do you thing?

Theoretically it should help with Async operators support as well. Your current design is quite similar to what I need the difference is that your objects currently encapsulate data (about operator) and behavior (how to apply this operator).

I know that you refactored the whole package recently and understand that you may have own vision on siftjs future. So, feel free to decline and close this discussion.

crcn commented 4 years ago

Would exposing the operator factory solve your problem? For example:

import {createQueryOperation} from "sift";
const operation = createQueryOperation({ age: { $gt: 1 }});

☝🏻 this is from https://github.com/crcn/sift.js/blob/master/src/core.ts#L398

Operators are basically ASTs - I may need to do some work to expose their raw query values, but that shouldn't be hard. From there, you can just roll your own translator:

import {createQueryOperation} from "sift";
const operation = createQueryOperation({ age: { $gt: 1, $lt: 10 }});
const searchQuery = mongodbQueryToSqlSearch(operation); // age > 1 AND age < 10
stalniy commented 4 years ago

Looks fine, but to make sure that we are on the same page, the end result I expect should be this:

import { createQueryOperation, test } from "sift";
const operation = createQueryOperation({ age: { $gt: 1, $lt: 10 }});
const searchQuery = mongodbQueryToSqlSearch(operation); // age > 1 AND age < 10

const matches  = test(operation, { age: 2 }) // true

Update: the last line is equivalent to sift({ age: { $gt: 1, $lt: 10 } })({ age: 2 })