0.0.1 • Published 12 months ago
@prostojs/uql v0.0.1
@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
checkFieldcallback to validate/authorize field names. - Optional
castValuecallback to cast raw values to specific types (e.g.boolean,Date, etc.).
- Optional
- 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/uqlUsage
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'- →
$andof{"field":{"$gt":10}}and{"other":{"$ne":"foo"}}(if you convert to Mongo).
- →
License
MIT © 2025 Artem Maltsev and Contributors.
0.0.1
12 months ago