This package is a part of ucast ecosystem. It combines @ucast/mongo and @ucast/js into a package that allows to evaluate MongoDB query conditions in JavaScript runtime.
npm i @ucast/mongo2js
# or
yarn add @ucast/mongo2js
# or
pnpm add @ucast/mongo2js
To check that POJO can be matched by Mongo Query:
import { guard } from '@ucast/mongo2js';
const test = guard({
lastName: 'Doe',
age: { $gt: 18 }
});
console.log(test({
firstName: 'John',
lastName: 'Doe',
age: 19
})); // true
You can also get access to parsed Mongo Query AST:
console.log(test.ast); /*
{
operator: 'and',
value: [
{ operator: 'eq', field: 'lastName', value: 'Doe' },
{ operator: 'gt', field: 'age', value: 18 }
]
}
*/
For cases, when you need to test primitive elements, you can use squire
function:
import { squire } from '@ucast/mongo2js';
const test = squire({
$lt: 10,
$gt: 18
});
test(11) // true
test(9) // false
In order to implement a custom operator, you need to create a custom parsing instruction for MongoQueryParser
and custom JsInterpreter
to interpret this operator in JavaScript runtime.
This package re-exports all symbols from @ucast/mongo
and @ucast/js
, so you don't need to install them separately. For example, to add support for json-schema operator:
import {
createFactory,
DocumentCondition,
ParsingInstruction,
JsInterpreter,
} from '@ucast/mongo2js';
import Ajv from 'ajv';
type JSONSchema = object;
const ajv = new Ajv();
const $jsonSchema: ParsingInstruction<JSONSchema> = {
type: 'document',
validate(instruction, value) {
if (!value || typeof value !== 'object') {
throw new Error(`"${instruction.name}" expects to receive an object`)
}
},
parse(instruction, schema) {
return new DocumentCondition(instruction.name, ajv.compile(schema));
}
};
const jsonSchema: JsInterpreter<DocumentCondition<Ajv.ValidateFunction>> = (
condition,
object
) => condition.value(object) as boolean;
const customGuard = createFactory({
$jsonSchema,
}, {
jsonSchema
});
const test = customGuard({
$jsonSchema: {
type: 'object',
properties: {
firstName: { type: 'string' },
lastName: { type: 'string' },
},
required: ['firstName', 'lastName'],
}
});
console.log(test({ firstName: 'John' })); // false, `lastName` is not defined
To create a custom operator which tests primitives (as squire
does), use the
forPrimitives
option:
const customSquire = createFactory({
$custom: {
type: 'field',
}
}, {
custom: (condition, value) => value === (condition.value ? 'on' : 'off')
}, {
forPrimitives: true
});
const test = customGuard({ $custom: true });
console.log(test('on')) // true
This package is written in TypeScript and supports type inference for MongoQuery:
import { guard } from '@ucast/mongo2js';
interface Person {
firstName: string
lastName: string
age: number
}
const test = guard<Person>({ lastName: 'Doe' });
You can also use dot notation to set conditions on deeply nested fields:
import { guard } from '@ucast/mongo2js';
interface Person {
firstName: string
lastName: string
age: number
address: {
city: string
country: string
}
}
type ExtendedPerson = Person & {
'address.city': Person['address']['city']
}
const test = guard<ExtendedPerson>({ lastName: 'Doe' });
Want to file a bug, contribute some code, or improve documentation? Excellent! Read up on guidelines for contributing