piotr-oles/rsql

convert parse expression to Sequelize where condition

GitHubWuYi opened this issue · 2 comments

// parsing
import { parse } from "@rsql/parser";
const expression = parse("year>=2003");

// return
{
type: 'COMPARISON',
left: { type: 'SELECTOR', selector: 'year' },
operator: '>=',
right: { type: 'VALUE', value: '2003' }
}

how to convert the expression to Sequelize where condition ?

You will need a mapping function, similar to the emit function from @rsql/emitter. Instead of producing a string, you should produce a format supported by sequelize :) Here is a pseudo-code to show you direction:

import { Op } from "sequelize";
import {
  EQ,
  GT,
  AND,
  AND_VERBOSE,
  OR,
  OR_VERBOSE,
  isLogicOperator,
  ComparisonNode,
  ExpressionNode,
  isComparisonNode,
  isLogicNode,
  LogicNode,
  SelectorNode,
  ValueNode,
  getSelector,
  getValue
} from "@rsql/ast";

export function mapRsqlToSequelize(node: ExpressionNode): string {
  if (isComparisonNode(node)) {
    return { where: mapComparisionToSequelize(node) };
  } else if (isLogicNode(node)) {
    return { where: mapLogicToSequelize(node) };
  }

  throw new TypeError(`The "expression" has to be a valid "ExpressionNode", ${String(node)} passed.`);
}

function mapComparisonToSequelize(node: ComparisionNode) {
  const selector = getSelector(node);
  const value = getValue(node);

  switch (node.operator) {
    case EQ:
      return { [selector]: value };
    case GT:
      return { [selector]: { [Op.gt]: value } };
     // ...
  }
}

function mapLogicToSequelize(node: LogicNode) {
  const children = [mapRsqlToSequelize(node.left), mapRsqlToSequelize(node.right)];
  switch (node.operator) {
    case AND:
    case AND_VERBORSE:
      return { [Op.and]: children };
    case OR:
    case OR_VERBOSE:
      return { [Op.or]: children };
  }
}

Keep in mind that value is always a string or string[] - so you will probably need some schema metadata to cast it to a proper type (for example to number). I guess you can extract it from sequelize models :)

I'm closing it as there is no activity :)