https://github.com/marianmeres/condition-builder
For building sql where statements programatically.
https://github.com/marianmeres/condition-builder
conditions sql where
Last synced: 6 days ago
JSON representation
For building sql where statements programatically.
- Host: GitHub
- URL: https://github.com/marianmeres/condition-builder
- Owner: marianmeres
- License: mit
- Created: 2024-09-28T08:23:01.000Z (almost 2 years ago)
- Default Branch: master
- Last Pushed: 2026-04-18T09:53:50.000Z (3 months ago)
- Last Synced: 2026-04-18T11:42:29.183Z (3 months ago)
- Topics: conditions, sql, where
- Language: TypeScript
- Homepage:
- Size: 66.4 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
- Agents: AGENTS.md
Awesome Lists containing this project
README
# @marianmeres/condition-builder
[](https://www.npmjs.com/package/@marianmeres/condition-builder)
[](https://jsr.io/@marianmeres/condition-builder)
[](https://opensource.org/licenses/MIT)
A tool for creating hierarchical logical _conditions_ and _expressions_, mainly
to be used in - but not limited to - an SQL _where_ statement.
## Terminology
### Expression
_Expression_ is the base building block. It consists of `key`, `operator` and `value`.
```ts
`a=b`;
```
### Condition
_Condition_ is a hierarchical collection of one or more _expressions_ or _conditions_
joined by a logical join operator: `and`, `or`, `andNot`, or `orNot`.
```ts
// condition with one expression
`a=b`;
// condition with 2 expressions joined by `or`
`a=b or c=d`;
// condition of multiple hierarchically structured expressions and conditions
`a=b or (c>d and (e {
const { key } = ctx;
const keyWhitelist = ["foo"];
if (!keyWhitelist.includes(key)) {
throw new TypeError(`Key '${key}' not allowed`);
}
},
});
// `foo` key is allowed
c.and("foo", OPERATOR.eq, "1");
// `bar` is not
assertThrows(() => c.and("bar", OPERATOR.neq, "2"));
```
### Rendering
To match the textual representation for any specific format you must provide any of the
`renderKey`, `renderValue`, or `renderOperator` functions.
For example for postgresql dialect you may use something like this:
```ts
const c = new Condition({
// escape identifiers in postgresql dialect
renderKey: (ctx: ExpressionContext) => `"${ctx.key.replaceAll('"', '""')}"`,
// escape values in postgresql dialect
renderValue: (ctx: ExpressionContext) =>
`'${ctx.value.toString().replaceAll("'", "''")}'`,
// read below
// renderOperator(ctx: ExpressionContext): string
});
c.and('fo"o', OPERATOR.eq, "ba'r");
assertEquals(c.toString(), `"fo""o"='ba''r'`);
```
#### Built-in operators rendering
There is a default built-in operator-to-symbol replacement logic (targeting postgresql
dialect), loosely inspired by
[postgrest](https://docs.postgrest.org/en/v12/references/api/tables_views.html).
Any found operator in the map below will be replaced with its symbol. If the operator is
not found in the map, no replacement will happen. You can customize this logic by
providing your own custom `renderOperator` function.
```ts
// default opinionated conversion map of operators to operator symbols.
{
eq: "=",
neq: "!=",
gt: ">",
gte: ">=",
lt: "<",
lte: "<=",
like: " ilike ",
nlike: " not ilike ",
match: "~*",
nmatch: "!~*",
is: " is ",
nis: " is not ",
in: " in ",
nin: " not in ",
// PostgreSQL ltree operators
ltree: "~",
ancestor: "@>",
descendant: "<@",
};
// but you can safely use any operator you see fit...
const e = new Expression("foo", "==", "bar");
assertEquals(e.toString(), "foo==bar");
```
## PostgreSQL presets
For PostgreSQL output, two presets are shipped:
### Inline SQL (`pgRenderers`)
Double-quotes identifiers and single-quote-escapes string literals. Handles
`null`, booleans, numbers, and bigints natively.
```ts
import { Condition, OPERATOR, pgRenderers } from "@marianmeres/condition-builder";
const c = new Condition()
.and('fo"o', OPERATOR.eq, "ba'r")
.and("id", OPERATOR.in, [1, 2, 3])
.or("active", OPERATOR.is, null);
c.toString(pgRenderers);
// "fo""o"='ba''r' and "id" in (1,2,3) or "active" is null
```
### Parameterized queries (`pgParameterized`) — recommended
Emits `$1`, `$2`, … placeholders and collects values into a shared array.
Values never touch the SQL string, which makes this the safest option for
input you don't control.
```ts
import { Condition, OPERATOR, pgParameterized } from "@marianmeres/condition-builder";
const { options, params } = pgParameterized();
const c = new Condition()
.and("id", OPERATOR.in, [1, 2, 3])
.and("name", OPERATOR.eq, "'; drop table users; --");
const sql = c.toString(options);
// "id" in ($1,$2,$3) and "name"=$4
// params: [1, 2, 3, "'; drop table users; --"]
// Pass to your driver:
// await client.query(`select * from users where ${sql}`, params);
```
Pass a custom `startIndex` if you're stitching the condition into a larger
query that already has parameters.
## Changelog
See [CHANGELOG.md](./CHANGELOG.md) for release notes and breaking-change
details.
## API Reference
See [API.md](./API.md) for the complete API documentation.
## Related
[@marianmeres/condition-parser](https://github.com/marianmeres/condition-parser)