https://github.com/mutaimwiti/logical-compiler
Compile MongoDB-like boolean expressions based on boolean operators AND and OR
https://github.com/mutaimwiti/logical-compiler
bool boolean compile compiler expression logic logical mongo mongodb
Last synced: 2 days ago
JSON representation
Compile MongoDB-like boolean expressions based on boolean operators AND and OR
- Host: GitHub
- URL: https://github.com/mutaimwiti/logical-compiler
- Owner: mutaimwiti
- License: mit
- Created: 2021-01-03T09:30:30.000Z (over 5 years ago)
- Default Branch: main
- Last Pushed: 2026-05-29T19:06:16.000Z (2 days ago)
- Last Synced: 2026-05-29T19:16:16.468Z (2 days ago)
- Topics: bool, boolean, compile, compiler, expression, logic, logical, mongo, mongodb
- Language: JavaScript
- Homepage:
- Size: 177 KB
- Stars: 1
- Watchers: 1
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# logical-compiler
[](https://github.com/mutaimwiti/logical-compiler/actions/workflows/ci.yml)
[](https://www.npmjs.com/package/logical-compiler)
[](https://www.npmjs.com/package/logical-compiler)
[](https://www.npmjs.com/package/logical-compiler)
Compile MongoDB-like boolean expressions based on boolean operators `AND` and `OR`
### Installation
Use one of the two based on your project's dependency manager.
```bash
$ npm install logical-compiler --save
$ yarn add logical-compiler
```
### Getting started
```javascript
import compile from 'logical-compiler';
compile(expression, options);
```
Arguments:
- `expression` - the boolean expression to be executed.
- `options` - an optional object specifying options.
- `fns` - an optional attribute specifying any function(s) used on the expression.
### Operators
#### AND operator
```javascript
let expression = { $and: [true, true] };
compile(expression); // true
expression = { $and: [true, false] };
compile(expression); // false
expression = { $and: [false, true] };
compile(expression); // false
expression = { $and: [false, false] };
compile(expression); // false
```
#### OR operator
```javascript
let expression = { $or: [true, true] };
compile(expression); // true
expression = { $or: [true, false] };
compile(expression); // true
expression = { $or: [false, true] };
compile(expression); // true
expression = { $or: [false, false] };
compile(expression); // false
```
#### NOT operator
`$not` takes a single expression and returns its negation.
```javascript
let expression = { $not: true };
compile(expression); // false
expression = { $not: { $and: [true, true] } };
compile(expression); // false
```
#### NOR operator
`$nor` takes an array and returns the negation of `$or` over it, i.e. `true`
only when every operand is `false`.
```javascript
let expression = { $nor: [false, false] };
compile(expression); // true
expression = { $nor: [false, true] };
compile(expression); // false
```
#### Unrecognized operator
```javascript
const expression = { $someOp: ['x', 'y'] };
compile(expression); // Error: Unrecognized operator: '$someOp'
```
### Primitives
#### undefined
```javascript
compile(); // Error: Expected an expression
```
#### boolean
```javascript
compile(true); // true
compile(false); // false
```
#### string
```javascript
const expression = 'test';
compile(expression); // Error: Unexpected token 'test'
```
#### number
```javascript
const expression = 201;
compile(expression); // Error: Unexpected token '201'
```
### Callbacks
A callback is a function that returns a boolean. If it returns a promise,
`compile` resolves to a promise you `await`.
```javascript
let cb = () => true;
compile(cb); // true
cb = () => Promise.resolve(false);
await compile(cb); // false
```
#### Nested promise callback
```javascript
const expression = {
$and: [true, () => Promise.resolve(true)],
};
await compile(expression); // true
```
### Functions
A function is defined on the `fns` attribute of the `options` argument. It may
return a boolean or a promise.
```javascript
const options = {
fns: {
isEven: (number) => number % 2 === 0,
isEqual: (num1, num2) => Promise.resolve(num1 === num2),
},
};
compile({ isEven: 6 }, options); // true
await compile({ isEqual: [3, 5] }, options); // false
```
#### Nested promise function
```javascript
const options = {
fns: {
authenticated: () => Promise.resolve(true),
},
};
const expression = {
$or: [false, { authenticated: null }],
};
await compile(expression, options); // true
```
#### Undefined function
```javascript
const expression = { someFn: ['x', 'y'] };
compile(expression, options); // Error: Undefined function: 'someFn'
````
### Compound expressions
```javascript
let expression = {
$or: [{ $and: [true, true] }, false],
};
compile(expression); // true
```
```javascript
expression = {
$or: [() => false, () => false],
};
compile(expression); // false
```
```javascript
expression = {
$and: [() => true, true],
};
compile(expression); // true
```
```javascript
expression = {
$or: [
() => false,
false,
{
$and: [true, { $or: [() => true, false] }],
},
],
};
compile(expression); // true
```
```javascript
const options = {
fns: {
any: (target, values) => values.includes(target),
all: (targets, values) => targets.every((target) => values.includes(target)),
},
};
expression = {
$and: [
() => true,
{ $or: [true, false] },
{ any: [5, [1, 3, 4, 6, 7]] }
],
};
compile(expression, options); // false
expression = {
$or: [
() => false,
false,
{ $and: [true, false] },
{
all: [
[3, 4, 7],
[2, 3, 4, 5, 6, 7],
],
},
],
};
compile(expression, options); // true
```
> Operators can be nested in any fashion to achieve the desired logical check.
### Multiple keys (implicit AND)
When an object expression has more than one key, the keys are AND-ed together,
at any nesting depth. This applies to operators and functions alike.
```javascript
const options = {
fns: {
isEven: (number) => number % 2 === 0,
},
};
let expression = { $or: [false, true], isEven: 6 };
compile(expression, options); // true ($or AND isEven)
expression = { $or: [false, true], isEven: 7 };
compile(expression, options); // false ($or is true, but isEven is false)
```
An empty object is not a valid expression and throws:
```javascript
compile({}); // Error: Expected an expression
```
##### IMPORTANT NOTES
1. `compile` returns `boolean` for fully synchronous expressions and `Promise` when any callback or
function returns a promise. `$and` stops at the first `false`; `$or` stops at the first `true`. Later operands
(including async ones) are not evaluated.
2. Callbacks and functions must explicitly return boolean values to avoid the ambiguity of relying on truthiness.
Relying on truthiness would pose a serious loophole because the executable might accidentally resolve to true on a
non-boolean value. If the library encounters a callback that resolves to a non-boolean value, it throws an exception.
See [MDN](https://developer.mozilla.org/en-US/docs/Glossary/Truthy) documentation on truthy values.
### Error handling
All errors thrown by `compile` are instances of `LogicalCompilerError`, a
subclass of `Error` that carries a `.code` field for programmatic handling. The
human-readable `.message` is unchanged.
```javascript
import compile from 'logical-compiler';
try {
compile({ $unknown: [] });
} catch (error) {
error instanceof compile.LogicalCompilerError; // true
error.code; // 'UNRECOGNIZED_OPERATOR'
}
```
Codes: `UNRECOGNIZED_OPERATOR`, `UNDEFINED_FUNCTION`, `UNEXPECTED_TOKEN`,
`UNEXPECTED_RETURN_TYPE`, `EXPECTED_EXPRESSION`.
### TypeScript
Type declarations ship with the package, so no separate `@types` install is
needed. The supporting types `compile.Expression`, `compile.Options`, and
`compile.LogicalCompilerError` are available for use in your own code.
### Licence
[MIT](https://mit-license.org/) © Mutai Mwiti |
[GitHub](https://github.com/mutaimwiti) |
[GitLab](https://gitlab.com/mutaimwiti)
_**DISCLAIMER:**_
_All opinions expressed in this repository are mine and do not reflect any company or organisation I'm involved with._