import { ComparisonOperatorExpression as KyselyComparisonOperatorExpression } from 'kysely'; import { TrigramOperator } from '../types/dream.js'; import CurriedOpsStatement from './curried-ops-statement.js'; import OpsStatement from './ops-statement.js'; type ArrayOperatorType = 'in' | 'not in'; declare const ops: { /** * Creates an `OpsStatement` with an arbitrary Kysely comparison operator or trigram operator. * Use this as an escape hatch when none of the named helpers cover your use case. * * @param operator - Any Kysely comparison operator (e.g. `'='`, `'<'`) or trigram operator. * @param value - The value to compare against. * @returns An `OpsStatement` wrapping the given operator and value. * * @example * User.where({ name: ops.expression('like', '%ello%') }) */ expression: )[number] : T>(operator: Operator, value: T) => OpsStatement; /** * Creates an `OpsStatement` that checks whether a JSONB column contains the given object * using the PostgreSQL `@>` (contains) operator. * * @param searchObj - A plain object whose key/value pairs must be present in the JSONB column. * @returns An `OpsStatement` using `@> ::jsonb`. * * @example * Post.where({ metadata: ops.jsonb({ published: true }) }) */ jsonb: (searchObj: object) => OpsStatement<"@>", import("kysely").RawBuilder, undefined>; /** * Creates an `OpsStatement` for a SQL `IN` clause, matching rows whose column value * is one of the provided array elements. * * @param arr - The array of values to match against. * @returns An `OpsStatement` using the `in` operator. * * @example * User.where({ status: ops.in(['active', 'pending']) }) */ in: (arr: T) => OpsStatement<"in", T[number], undefined>; /** * Creates a `CurriedOpsStatement` that checks whether a PostgreSQL array column contains * the given value using `@> ARRAY[value]::type`. The column type is resolved at query-build * time from the Dream model's schema. * * Throws `AnyRequiresArrayColumn` if the target column is not a database array type. * * @param value - The scalar value that must be present in the array column. * @returns A `CurriedOpsStatement` that resolves to an `OpsStatement` once bound to a model and field. * * @example * Post.where({ tags: ops.any('typescript') }) */ any: (value: AnyT) => CurriedOpsStatement; /** * Creates an `OpsStatement` using the SQL `LIKE` operator for case-sensitive pattern matching. * Use `%` as a wildcard in the pattern string. * * **User-supplied patterns:** the value is bound as a parameter (no SQL * injection), but `%`, `_`, and `\` in the bound value are still interpreted * as wildcards by the SQL engine. Wrap user input with `ops.like.escape` * if you need literal matching: * * User.where({ name: ops.like(`%${ops.like.escape(query)}%`) }) * * `ops.like.escape` escapes the three metacharacters that PostgreSQL's * `LIKE` / `ILIKE` operators treat as wildcards (`\`, `%`, `_`) so the * returned string matches literally. The same helper applies to all four * LIKE-family ops (`like`, `ilike`, `not.like`, `not.ilike`); it is exposed * here as the canonical entry point. If a caller uses `ESCAPE '...'` with * a non-default character this helper will not be appropriate. * * @param like - The pattern string (e.g. `'%hello%'`). * @returns An `OpsStatement` using the `like` operator. * * @example * User.where({ name: ops.like('%alice%') }) */ like: ((like: string) => OpsStatement<"like", string, undefined>) & { escape: (input: string) => string; }; /** * Creates an `OpsStatement` using the SQL `ILIKE` operator for case-insensitive pattern matching. * Use `%` as a wildcard in the pattern string. * * **User-supplied patterns:** the value is bound as a parameter (no SQL * injection), but `%`, `_`, and `\` in the bound value are still interpreted * as wildcards by the SQL engine. Wrap user input with `ops.like.escape` * if you need literal matching. * * @param ilike - The pattern string (e.g. `'%hello%'`). * @returns An `OpsStatement` using the `ilike` operator. * * @example * User.where({ name: ops.ilike('%alice%') }) */ ilike: (ilike: string) => OpsStatement<"ilike", string, undefined>; /** * Creates an `OpsStatement` that matches a column against a POSIX regular expression. * By default the match is case-sensitive (`~`); pass `{ caseInsensitive: true }` to use `~*`. * * @param match - The regular expression pattern. * @param options.caseInsensitive - When `true`, uses the `~*` operator instead of `~`. Defaults to `false`. * @returns An `OpsStatement` using `~` or `~*`. * * @example * User.where({ email: ops.match('^admin', { caseInsensitive: true }) }) */ match: (match: string, { caseInsensitive }?: { caseInsensitive?: boolean; }) => OpsStatement<"~" | "~*", string, undefined>; /** * Creates an `OpsStatement` using the `=` operator for strict equality. * * **Array columns:** passing an array means literal array equality — the * whole array is bound as a single parameter, so the column must match * element-for-element, in order. This is the opt-in counterpart to a bare * array in a where clause (`Post.where({ tags: ['a', 'b'] })`), which means * `IN`, and to `ops.any`, which tests for containment of a single element. * Element types are constrained by the column, so an enum array column * rejects a string that is not a member of its enum. * * Note that PostgreSQL defines no equality operator for `json` (as opposed * to `jsonb`), so `ops.equal` against a `json[]` column raises at the * database. * * @param equal - The value the column must equal. * @returns An `OpsStatement` using the `=` operator. * * @example * User.where({ role: ops.equal('admin') }) * * @example * // matches only rows whose tags column is exactly ['a', 'b'], in that order * Post.where({ tags: ops.equal(['a', 'b']) }) */ equal: (equal: T) => OpsStatement<"=", T, undefined>; /** * Creates an `OpsStatement` using the `<` operator. * * @param lessThan - The value the column must be less than. * @returns An `OpsStatement` using the `<` operator. * * @example * Order.where({ total: ops.lessThan(100) }) */ lessThan: (lessThan: T) => OpsStatement<"<", T, undefined>; /** * Creates an `OpsStatement` using the `<=` operator. * * @param lessThanOrEqualTo - The value the column must be less than or equal to. * @returns An `OpsStatement` using the `<=` operator. * * @example * Order.where({ total: ops.lessThanOrEqualTo(100) }) */ lessThanOrEqualTo: (lessThanOrEqualTo: T) => OpsStatement<"<=", T, undefined>; /** * Creates an `OpsStatement` using the `>` operator. * * @param greaterThan - The value the column must be greater than. * @returns An `OpsStatement` using the `>` operator. * * @example * Order.where({ total: ops.greaterThan(50) }) */ greaterThan: (greaterThan: T) => OpsStatement<">", T, undefined>; /** * Creates an `OpsStatement` using the `>=` operator. * * @param greaterThanOrEqualTo - The value the column must be greater than or equal to. * @returns An `OpsStatement` using the `>=` operator. * * @example * Order.where({ total: ops.greaterThanOrEqualTo(50) }) */ greaterThanOrEqualTo: (greaterThanOrEqualTo: T) => OpsStatement<">=", T, undefined>; /** * Creates an `OpsStatement` for PostgreSQL trigram similarity (`%` operator). * Rows are included when the similarity score meets or exceeds `score`. * * Requires the `pg_trgm` extension to be enabled. * * @param similarity - The string to compare against the column. * @param options.score - Minimum similarity threshold (0–1). Defaults to `0.3`. * @returns An `OpsStatement` using the `%` trigram operator. * * @example * User.where({ name: ops.similarity('alice', { score: 0.4 }) }) */ similarity: (similarity: string, { score }?: { score?: number; }) => OpsStatement<"%", string, { score: number; }>; /** * Creates an `OpsStatement` for PostgreSQL word similarity (`<%` operator). * Rows are included when the word similarity score meets or exceeds `score`. * * Requires the `pg_trgm` extension to be enabled. * * @param similarity - The string to compare against the column. * @param options.score - Minimum word similarity threshold (0–1). Defaults to `0.5`. * @returns An `OpsStatement` using the `<%` trigram operator. * * @example * Article.where({ title: ops.wordSimilarity('postgres', { score: 0.6 }) }) */ wordSimilarity: (similarity: string, { score }?: { score?: number; }) => OpsStatement<"<%", string, { score: number; }>; /** * Creates an `OpsStatement` for PostgreSQL strict word similarity (`<<%` operator). * Rows are included when the strict word similarity score meets or exceeds `score`. * * Requires the `pg_trgm` extension to be enabled. * * @param similarity - The string to compare against the column. * @param options.score - Minimum strict word similarity threshold (0–1). Defaults to `0.6`. * @returns An `OpsStatement` using the `<<%` trigram operator. * * @example * Article.where({ title: ops.strictWordSimilarity('postgres', { score: 0.7 }) }) */ strictWordSimilarity: (similarity: string, { score }?: { score?: number; }) => OpsStatement<"<<%", string, { score: number; }>; /** Negated variants of the standard comparison operators. */ not: { /** * Creates an `OpsStatement` for a SQL `NOT IN` clause, excluding rows whose column value * is one of the provided array elements. * * @param arr - The array of values to exclude. * @returns An `OpsStatement` using the `not in` operator. * * @example * User.where({ status: ops.not.in(['banned', 'deleted']) }) */ in: (arr: T) => OpsStatement<"not in", T[number], undefined>; /** * Creates an `OpsStatement` using the `NOT LIKE` operator for case-sensitive pattern exclusion. * * **User-supplied patterns:** see the note on `ops.like`. Wrap user input * with `ops.like.escape` for literal matching. * * @param like - The pattern string (e.g. `'%spam%'`). * @returns An `OpsStatement` using the `not like` operator. * * @example * User.where({ email: ops.not.like('%@example.com') }) */ like: (like: string) => OpsStatement<"not like", string, undefined>; /** * Creates an `OpsStatement` using the `NOT ILIKE` operator for case-insensitive pattern exclusion. * * **User-supplied patterns:** see the note on `ops.ilike`. Wrap user input * with `ops.like.escape` for literal matching. * * @param ilike - The pattern string (e.g. `'%spam%'`). * @returns An `OpsStatement` using the `not ilike` operator. * * @example * User.where({ email: ops.not.ilike('%@example.com') }) */ ilike: (ilike: string) => OpsStatement<"not ilike", string, undefined>; /** * Creates an `OpsStatement` that excludes rows matching a POSIX regular expression. * By default the match is case-sensitive (`!~`); pass `{ caseInsensitive: true }` to use `!~*`. * * @param match - The regular expression pattern. * @param options.caseInsensitive - When `true`, uses `!~*` instead of `!~`. Defaults to `false`. * @returns An `OpsStatement` using `!~` or `!~*`. * * @example * User.where({ email: ops.not.match('^admin', { caseInsensitive: true }) }) */ match: (match: string, { caseInsensitive }?: { caseInsensitive?: boolean; }) => OpsStatement<"!~" | "!~*", string, undefined>; /** * Creates an `OpsStatement` using the `!=` operator for inequality. * * **Array columns:** as with `ops.equal`, passing an array compares against * the whole array rather than against its elements. * * @param equal - The value the column must not equal. * @returns An `OpsStatement` using the `!=` operator. * * @example * User.where({ role: ops.not.equal('guest') }) */ equal: (equal: T) => OpsStatement<"!=", T, undefined>; /** * Creates an `OpsStatement` that negates `<`, equivalent to `>=`. * * @param lessThan - The value used as the lower bound (inclusive). * @returns An `OpsStatement` using `>=`. * * @example * Order.where({ total: ops.not.lessThan(100) }) // total >= 100 */ lessThan: (lessThan: T) => OpsStatement<">=", T, undefined>; /** * Creates an `OpsStatement` that negates `<=`, equivalent to `>`. * * @param lessThanOrEqualTo - The value used as the lower bound (exclusive). * @returns An `OpsStatement` using `>`. * * @example * Order.where({ total: ops.not.lessThanOrEqualTo(100) }) // total > 100 */ lessThanOrEqualTo: (lessThanOrEqualTo: T) => OpsStatement<">", T, undefined>; /** * Creates an `OpsStatement` that negates `>`, equivalent to `<=`. * * @param greaterThan - The value used as the upper bound (inclusive). * @returns An `OpsStatement` using `<=`. * * @example * Order.where({ total: ops.not.greaterThan(50) }) // total <= 50 */ greaterThan: (greaterThan: T) => OpsStatement<"<=", T, undefined>; /** * Creates an `OpsStatement` that negates `>=`, equivalent to `<`. * * @param greaterThanOrEqualTo - The value used as the upper bound (exclusive). * @returns An `OpsStatement` using `<`. * * @example * Order.where({ total: ops.not.greaterThanOrEqualTo(50) }) // total < 50 */ greaterThanOrEqualTo: (greaterThanOrEqualTo: T) => OpsStatement<"<", T, undefined>; }; }; export default ops;