@prostojs/uql
TypeScript icon, indicating that this package has built-in type declarations

0.0.1 • Public • Published

@prostojs/uql

Universal Query Language (UQL) parser designed for URLs.
Parses user-friendly query strings (like field=5&field2='text'|exists(extraField)) into an AST or a MongoDB query.
Automatically extracts $controls (e.g. $page=2, $limit=100, etc.) from the query string.

Features

  • AST-based: Parse into an abstract syntax tree representing logical AND/OR conditions, comparison operators, and exists(...).
  • Easy integration: Convert the AST to your own format or directly to a MongoDB query.
  • Configurable:
    • Optional checkField callback to validate/authorize field names.
    • Optional castValue callback to cast raw values to specific types (e.g. boolean, Date, etc.).
  • Quoted strings: Supports explicit quoting via single '...' or double "...".
  • Handles =, !=, >, >=, <, <=, exists(...), !exists(...), grouping with parentheses, logical AND (&) and OR (|).

Installation

# with npm
npm install @prostojs/uql

# or with pnpm
pnpm add @prostojs/uql

Usage

1. Basic Parsing

import { UqlParser } from "@prostojs/uql";

const parser = new UqlParser();

// e.g. "field=5&field2='hello'|exists(extraField)"
const result = parser.parse("(field>5|field2='hello')&exists(extraField)&$page=2");

console.log(result.controls); 
// { page: 2 }

console.log(JSON.stringify(result.ast, null, 2));
// Example AST:
// {
//   "type": "and",
//   "items": [
//     {
//       "type": "or",
//       "items": [
//         {
//           "type": "condition",
//           "field": "field",
//           "operator": "gt",
//           "value": 5
//         },
//         {
//           "type": "condition",
//           "field": "field2",
//           "operator": "eq",
//           "value": "hello"
//         }
//       ]
//     },
//     {
//       "type": "condition",
//       "field": "extraField",
//       "operator": "exists"
//     }
//   ]
// }

The parser returns an object with:

  • ast: The parsed abstract syntax tree.
  • controls: A record of the “control” parameters (any top-level key that starts with $).

2. Casting Field Values

By default, the parser:

  • Parses numeric-looking values (e.g. 123) as numbers.
  • Leaves everything else as strings.
  • An empty value (field=) is interpreted as "" (empty string).

If you want your own casting logic (like converting "true"true), pass a castValue function:

import { UqlParser } from "@prostojs/uql";

const parserWithCast = new UqlParser({
  castValue(fieldName, operator, rawValue) {
    if (rawValue === "true") return true;
    if (rawValue === "false") return false;
    // fallback
    return rawValue;
  },
});

const result = parserWithCast.parse("flag=true&flag2=false");

console.log(JSON.stringify(result.ast, null, 2));
// {
//   "type": "and",
//   "items": [
//     {
//       "type": "condition",
//       "field": "flag",
//       "operator": "eq",
//       "value": true
//     },
//     {
//       "type": "condition",
//       "field": "flag2",
//       "operator": "eq",
//       "value": false
//     }
//   ]
// }

3. Validating Fields

You can validate or authorize field names by providing a checkField callback:

const parserWithFieldCheck = new UqlParser({
  checkField(fieldName) {
    if (!["allowedField", "someOther"].includes(fieldName)) {
      throw new Error(`Field ${fieldName} is not allowed!`);
    }
    return true;
  },
});

try {
  parserWithFieldCheck.parse("secret=123");
} catch (error) {
  console.error(error.message);
  // Field secret is not allowed!
}

4. Convert to MongoDB Query

This package also ships with a helper uqlToMongoQuery() (in @prostojs/uql/mongo) to convert the resulting AST into a Mongo query object:

import { UqlParser } from "@prostojs/uql";
import { uqlToMongoQuery } from "@prostojs/uql/mongo";

const parser = new UqlParser();
const { ast, controls } = parser.parse("(field>5|field2='hello')&exists(extraField)");

if (ast) {
  const mongoQuery = uqlToMongoQuery(ast);
  console.log(JSON.stringify(mongoQuery, null, 2));
  // {
  //   "$and": [
  //     {
  //       "$or": [
  //         { "field": { "$gt": 5 } },
  //         { "field": "hello" }
  //       ]
  //     },
  //     {
  //       "extraField": { "$exists": true }
  //     }
  //   ]
  // }
}

5. Examples

  • field=123 → AST: {"type":"condition","field":"field","operator":"eq","value":123}
  • field='123'value: "123" (explicit string)
  • !exists(field){"type":"condition","field":"field","operator":"exists","negateExists":true}
  • field>10&other!='foo'
    • $and of {"field":{"$gt":10}} and {"other":{"$ne":"foo"}} (if you convert to Mongo).

License

MIT © 2025 Artem Maltsev and Contributors.

Readme

Keywords

Package Sidebar

Install

npm i @prostojs/uql

Weekly Downloads

3

Version

0.0.1

License

MIT

Unpacked Size

32.2 kB

Total Files

9

Last publish

Collaborators

  • mav-rik