@dudousxd/nestjs-filter-drizzle
Version:
Drizzle ORM adapter for @dudousxd/nestjs-filter.
68 lines • 3.59 kB
TypeScript
import type { ColumnFilter } from '@dudousxd/nestjs-filter';
import { Column, type SQL } from 'drizzle-orm';
/** The SQL dialect a query renders for — decides LIKE/ILIKE, casts and escapes. */
export type DrizzleDialect = 'postgres' | 'mysql' | 'sqlite';
/**
* What an operator compares: a real column (its type drives value coercion and
* the `isEmpty` shape) or a developer-provided SQL expression (a computed field,
* a correlated aggregate subquery).
*/
export type OperatorTarget = Column | SQL;
/**
* Coerces a client value to what the column's driver encoder expects.
*
* Drizzle binds a comparison value THROUGH the column (`mapToDriverValue`), so
* a value of the wrong JS type is not merely compared loosely — it can break
* the encoder: a `timestamp` column in `mode: 'date'` calls `.toISOString()` on
* whatever it is handed, and a SQLite boolean encodes the string `'false'` as
* truthy `1`. Query strings and decoded cursors deliver exactly those strings.
* Values that do not parse are passed through untouched (the database then
* reports the mismatch, rather than this layer inventing a value).
*/
export declare function coerceValue(column: Column, value: unknown): unknown;
/**
* Builds a LIKE predicate. The pattern is always a bound parameter, already
* escaped with {@link escapeLike} (backslash escapes). Postgres and MySQL treat
* backslash as the default LIKE escape; SQLite has NO default escape character,
* so the clause is spelled out there — without it `%` in user input would still
* be a wildcard.
*
* Case-insensitive matching uses `ILIKE` on Postgres (index-friendly with a
* trigram index) and `lower(x) LIKE lower(p)` elsewhere.
*/
export declare function likeCondition(target: OperatorTarget, pattern: string, dialect: DrizzleDialect, opts?: {
caseInsensitive?: boolean;
negate?: boolean;
}): SQL;
/**
* Translates ONE `ColumnFilter` operator into a drizzle SQL condition over
* `target`. Every client value is a bound parameter (drizzle's `eq`/`gt`/…
* bind through the column's encoder); nothing client-supplied is inlined.
*
* `isEmpty`/`isNotEmpty` compare against `''` only for string columns — `col =
* ''` on a date or integer column is a type error on Postgres/MySQL — and
* collapse to the NULL check everywhere else.
*/
export declare function buildOperatorCondition(target: OperatorTarget, filter: ColumnFilter, dialect: DrizzleDialect,
/**
* For an expression target whose values are those of a known column (a
* `MIN`/`MAX` over a child column), bind comparison values through that
* column's encoder — so a date compares as the column stores dates (an epoch
* integer on SQLite, a timestamp on Postgres) rather than as a raw JS value.
*/
encoder?: Column): SQL;
/**
* Resolves a leaf filter to its condition — the adapter supplies this, since it
* knows how to reach a field (a root column, or a relation path that needs an
* `EXISTS` subquery). Returning `undefined` drops the leaf (an unresolvable
* field never reaches SQL).
*/
export type LeafResolver = (filter: ColumnFilter) => SQL | undefined;
/**
* Folds a list of `ColumnFilter`s (with arbitrarily nested `AND`/`OR`) into one
* condition: top-level entries are ANDed; a node contributes
* `base AND (...AND) AND (OR₁ OR OR₂ …)`, the same grouping the MikroORM
* adapter emits. A pure group node (no `field`) contributes only its children.
*/
export declare function buildColumnFiltersCondition(filters: ColumnFilter[], leaf: LeafResolver): SQL | undefined;
//# sourceMappingURL=operator-resolver.d.ts.map