Skip to content

Expression Parser

@rapiq/parser-expression parses an expression language for filters — useful when a single string must carry a complex condition tree (search boxes, saved filters, CLI flags).

sh
npm install @rapiq/core @rapiq/parser-simple @rapiq/parser-expression

The language

Conditions are function-call expressions; and / or / not compose them:

txt
and(eq(name, 'John'), gte(age, '18'))
or(in(status, 'active', 'pending'), gt(age, '65'))
not(eq(name, 'foo'))
contains(user.name, 'Bob')
FunctionMeaningAST operator
eq(field, value)equalEQUAL
lt / lte / gt / gtecomparisonsLESS_THAN, …
in(field, v1, v2, …)in listIN
nin(field, v1, v2, …)not in listNOT_IN
contains(field, value)substringCONTAINS
startsWith(field, value)prefixSTARTS_WITH
endsWith(field, value)suffixENDS_WITH
and(expr, …) / or(expr, …)compoundFilters node
not(expr, …)negationflips operators, andor

Rules:

  • Values are always single-quotedgte(age, '18'), not gte(age, 18). Quoted numerals are coerced to numbers, 'true'/'false' to booleans, 'null' to null. Escape a quote by doubling it ('it''s').
  • Field names allow [A-Za-z0-9_-] with dots for relation paths (user.name).
  • not(...) cannot wrap the match expressions (contains, startsWith, endsWith).

Usage

typescript
import { ExpressionParser } from '@rapiq/parser-expression';

const parser = new ExpressionParser(registry);

const query = parser.parse({
    filters: "and(eq(name, 'John'), gte(age, '18'))",
    sort: '-age',
    pagination: { limit: 25 },
}, { schema: 'user' });

Only the filters parameter uses the expression language — fields, relations, pagination and sort accept the same input as the simple parser, and the whole thing returns the same Query AST.

There is also a standalone parseFilters(input, options) returning just the Filters node.

Errors

Syntax errors and schema violations throw FiltersParseError immediately — the expression parser has no silent-drop mode for malformed expressions.

Released under the MIT License.