uql-orm 0.67.1 → 0.68.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/dist/browser/http/http.js +5 -8
  2. package/dist/browser/querier/httpQuerier.d.ts +9 -9
  3. package/dist/browser/uql-browser.min.js +2 -2
  4. package/dist/browser/uql-browser.min.js.map +9 -8
  5. package/dist/cockroachdb/cockroachDialect.d.ts +6 -4
  6. package/dist/cockroachdb/cockroachDialect.js +7 -3
  7. package/dist/d1/d1Querier.d.ts +5 -5
  8. package/dist/d1/d1QuerierPool.d.ts +3 -3
  9. package/dist/d1/d1SqliteDialect.d.ts +1 -1
  10. package/dist/d1/d1SqliteDialect.js +1 -1
  11. package/dist/dialect/abstractSqlDialect.d.ts +107 -97
  12. package/dist/dialect/abstractSqlDialect.js +250 -293
  13. package/dist/dialect/hydrateColumn.js +33 -30
  14. package/dist/dialect/jsonSql.d.ts +32 -23
  15. package/dist/dialect/jsonSql.js +42 -31
  16. package/dist/dialect/mysqlLikeSqlDialect.d.ts +19 -23
  17. package/dist/dialect/mysqlLikeSqlDialect.js +34 -51
  18. package/dist/dialect/pgLikeSqlDialect.d.ts +24 -17
  19. package/dist/dialect/pgLikeSqlDialect.js +53 -26
  20. package/dist/dialect/vectorCast.d.ts +2 -0
  21. package/dist/dialect/vectorCast.js +25 -5
  22. package/dist/dialect/vectorSqlDialect.d.ts +8 -8
  23. package/dist/dialect/vectorSqlDialect.js +11 -11
  24. package/dist/http/query.d.ts +10 -2
  25. package/dist/http/query.js +26 -1
  26. package/dist/maria/mariaDialect.d.ts +16 -11
  27. package/dist/maria/mariaDialect.js +23 -19
  28. package/dist/migrate/ddl/indexDdl.d.ts +3 -1
  29. package/dist/migrate/ddl/indexDdl.js +5 -1
  30. package/dist/migrate/ddl/mysqlIndexDdl.d.ts +7 -2
  31. package/dist/migrate/ddl/mysqlIndexDdl.js +28 -6
  32. package/dist/migrate/ddl/pgIndexDdl.d.ts +0 -9
  33. package/dist/migrate/ddl/pgIndexDdl.js +2 -6
  34. package/dist/migrate/introspection/abstractSqlSchemaIntrospector.d.ts +12 -1
  35. package/dist/migrate/introspection/abstractSqlSchemaIntrospector.js +13 -3
  36. package/dist/migrate/introspection/mssqlIntrospector.d.ts +2 -9
  37. package/dist/migrate/introspection/mssqlIntrospector.js +2 -9
  38. package/dist/migrate/introspection/mysqlIntrospector.d.ts +2 -9
  39. package/dist/migrate/introspection/mysqlIntrospector.js +2 -8
  40. package/dist/mongo/mongoDialect.d.ts +22 -10
  41. package/dist/mongo/mongoDialect.js +86 -38
  42. package/dist/mssql/mssqlDialect.d.ts +22 -18
  43. package/dist/mssql/mssqlDialect.js +54 -43
  44. package/dist/mysql/mysqlDialect.d.ts +16 -1
  45. package/dist/mysql/mysqlDialect.js +18 -2
  46. package/dist/sqlite/sqliteDialect.d.ts +17 -16
  47. package/dist/sqlite/sqliteDialect.js +35 -39
  48. package/dist/type/dialect.d.ts +0 -4
  49. package/dist/type/entity.d.ts +12 -7
  50. package/dist/type/query.d.ts +29 -24
  51. package/dist/type/queryWhere.d.ts +20 -20
  52. package/dist/type/universalQuerier.d.ts +10 -10
  53. package/dist/type/vector.d.ts +5 -7
  54. package/dist/type/wire.d.ts +9 -0
  55. package/dist/util/dialect.util.d.ts +2 -0
  56. package/dist/util/dialect.util.js +6 -2
  57. package/dist/util/object.util.d.ts +2 -4
  58. package/dist/util/object.util.js +4 -9
  59. package/package.json +2 -2
  60. package/dist/dialect/jsonArrayElemMatchUtils.d.ts +0 -2
  61. package/dist/dialect/jsonArrayElemMatchUtils.js +0 -7
  62. package/dist/dialect/pgVectorMetrics.d.ts +0 -13
  63. package/dist/dialect/pgVectorMetrics.js +0 -17
  64. package/dist/maria/mariaVectorMetrics.d.ts +0 -8
  65. package/dist/maria/mariaVectorMetrics.js +0 -10
@@ -1,6 +1,6 @@
1
- import { type ColumnFamily, type EntityData, type EntityMeta, type EntityWhereMeta, type FieldKey, type FieldOptions, type IsolationLevel, type JsonColumnType, type JsonUpdateOp, type Query, type QueryAggMap, type QueryAggregate, type QueryBuildFn, type QueryComparisonOptions, type QueryConflictPaths, type QueryContext, type QueryContextOptions, type QueryExclude, type QueryGroupMap, type QueryGroupOp, type QueryHavingMap, type QueryOptions, type QueryPage, type QueryPager, QueryRaw, type QueryRawFnOptions, type QuerySearch, type QuerySelectValue, type QuerySizeComparisonOps, type QuerySortMap, type QueryTextSearchOptions, type QueryVectorNear, type QueryWhere, type QueryWhereArray, type QueryWhereOptions, type RelationMeta, type SqlDialectName, type SqlQueryDialect, type Type, type UpdatePayload } from '../type/index.js';
1
+ import { type ColumnFamily, type EntityData, type EntityMeta, type EntityWhereMeta, type FieldKey, type FieldOptions, type IsolationLevel, type JsonColumnType, type JsonUpdateOp, type Query, type QueryAggMap, type QueryAggregate, type QueryBuildFn, type QueryComparisonOptions, type QueryConflictPaths, type QueryContext, type QueryContextOptions, type QueryExclude, type QueryGroupMap, type QueryGroupOp, type QueryHavingMap, type QueryOptions, type QueryPage, type QueryPager, QueryRaw, type QueryRawFnOptions, type QuerySearch, type QuerySelectValue, type QuerySizeComparisonOps, type QuerySortMap, type QueryTextSearchOptions, type QueryWhere, type QueryWhereArray, type QueryWhereOptions, type RelationMeta, type SqlDialectName, type SqlQueryDialect, type Type, type UpdatePayload } from '../type/index.js';
2
2
  import type { HydrateKind } from './hydrateColumn.js';
3
- import { type JsonAccessMode } from './jsonSql.js';
3
+ import { type JsonAccessMode, type JsonSlot } from './jsonSql.js';
4
4
  import { type QueryJoins, type QuerySortOptions } from './queryJoins.js';
5
5
  import { VectorSqlDialect } from './vectorSqlDialect.js';
6
6
  /** How a column's values are bound: see {@link AbstractSqlDialect.persistKind}. */
@@ -171,8 +171,8 @@ export declare abstract class AbstractSqlDialect extends VectorSqlDialect implem
171
171
  protected selectModifier<E>(_q: Query<E>): string;
172
172
  /**
173
173
  * The expression a scalar field is read through in the statement's own rows, the plain column by
174
- * default. MariaDB reads a vector column back with `VEC_ToText`, since selecting it raw yields its
175
- * binary form. A related row's column crosses JSON through {@link carriedFields} instead.
174
+ * default. MariaDB reads a vector column back as hex, since selecting it raw yields its binary form.
175
+ * A related row's column crosses JSON through {@link carriedFields} instead.
176
176
  */
177
177
  protected selectFieldExpr(escapedColumn: string, _field: FieldOptions): string;
178
178
  /**
@@ -224,6 +224,8 @@ export declare abstract class AbstractSqlDialect extends VectorSqlDialect implem
224
224
  /** Renders a `$where` tree without applying entity filters (used for same-scope group-operator recursion). */
225
225
  protected renderWhere<E>(ctx: QueryContext, entity: Type<E>, where?: QueryWhere<E>, opts?: QueryWhereOptions): void;
226
226
  compare<E>(ctx: QueryContext, entity: Type<E>, key: string, val: unknown, opts?: QueryComparisonOptions): void;
227
+ /** Conditions joined by `AND`, parenthesized where there is more than one. */
228
+ private static conjunction;
227
229
  protected compareLogicalOperator<E>(ctx: QueryContext, entity: Type<E>, key: QueryGroupOp, val: QueryWhereArray<E>, opts: QueryComparisonOptions): void;
228
230
  /** Memoizes {@link escapedColumnName}; see there for why it is per dialect instance. */
229
231
  private readonly escapedColumns;
@@ -231,11 +233,13 @@ export declare abstract class AbstractSqlDialect extends VectorSqlDialect implem
231
233
  /** What a `$near` says about the search itself; everything else in it is a bound. */
232
234
  private static readonly VECTOR_QUERY_KEYS;
233
235
  /**
234
- * The runtime half of {@link QueryVectorNear}'s bounds, derived from the map above rather than
235
- * spelled again: both are `QueryOrderedOp`, so `$near` can never accept a comparison the renderer
236
- * below has no operator for.
236
+ * The ordered comparisons, `QueryOrderedOp` at runtime, derived from the map above rather than spelled
237
+ * again: {@link QueryVectorNear}'s bounds, so `$near` never accepts one the renderer has no operator
238
+ * for, and the operators that read a JSON path as a number.
237
239
  */
238
- private static readonly NEAR_BOUND_OPS;
240
+ private static readonly ORDERED_OPS;
241
+ /** The operators an equality compares by value, which a JSON path reads the way that value compares. */
242
+ private static readonly EQUALITY_OPS;
239
243
  /**
240
244
  * Every `$like`-family operator: the pattern it wraps its value in, and whether it ignores case.
241
245
  * Each case-sensitive operator is paired here with the `$i` twin that shares its pattern, so the
@@ -269,51 +273,69 @@ export declare abstract class AbstractSqlDialect extends VectorSqlDialect implem
269
273
  * alias exists only when the field was also selected, which `$where` and `$sort` cannot assume.
270
274
  */
271
275
  private inlinedOperand;
272
- /** One operator of a field's condition. Both come from the query as data, so neither is trusted. */
276
+ /** {@link fieldCondition}, appended. */
273
277
  compareFieldOperator<E>(ctx: QueryContext, entity: Type<E>, key: FieldKey<E>, op: string, val: unknown, opts?: QueryOptions): void;
278
+ /** One operator of a field's condition. Both come from the query as data, so neither is trusted. */
279
+ private fieldCondition;
274
280
  /**
275
281
  * `<operand> <op> <value>` for every operator that needs only its left-hand SQL, shared by a column, a
276
- * `HAVING` expression and a `$size` count; `undefined` for the rest.
277
- */
278
- protected operatorCondition(ctx: QueryContext, operand: string, op: string, val: unknown): string | undefined;
279
- /** {@link operatorCondition}, appended; `false` when `op` needs more than an operand. */
280
- protected appendOperatorCondition(ctx: QueryContext, operand: string, op: string, val: unknown): boolean;
281
- /**
282
- * Build a comparison condition for a JSON field.
283
- * Used by both `$elemMatch` and dot-notation paths.
284
- * All dialect-specific behavior comes from overridable methods on `this`.
285
- */
286
- protected buildJsonFieldCondition(ctx: QueryContext, fieldAccessor: (path: string, mode: JsonAccessMode) => string, jsonPath: string, op: string, value: unknown, asJson?: boolean): string;
287
- private jsonInNin;
288
- /** The bound operand of a JSON comparison: JSON-encoded when comparing against the JSON value. */
289
- protected jsonOperand(ctx: QueryContext, value: unknown, asJson: boolean): string;
290
- /** `$all`: the JSON array at `jsonField` contains every value (also serves element containment). */
291
- protected abstract jsonAll(ctx: QueryContext, jsonField: string, value: unknown): string;
292
- /** `$size`: the length of the JSON array at `jsonField`, compared against `value`. */
293
- protected abstract jsonSize(ctx: QueryContext, jsonField: string, value: number | QuerySizeComparisonOps): string;
294
- /**
295
- * The JSON array at `jsonField` as rows, the `FROM` of an `EXISTS`, under a fresh `alias` so a nested
296
- * one cannot shadow it. `fields` are an object element's keys (MySQL lists them up front), empty for
297
- * scalars, which `asJson` reads as JSON rather than text.
298
- */
299
- protected abstract jsonElemFrom(jsonField: string, fields: readonly string[], alias: string, asJson?: boolean): string;
300
- /**
301
- * References an exploded element under `alias` (the same one passed to the {@link jsonElemFrom}
302
- * call it explodes): the element itself, or one `field` of it. `asJson` asks for the JSON-valued
303
- * form instead of the text one - see {@link isJsonbOp} for when that matters.
304
- */
305
- protected abstract jsonElemRef(alias: string, field?: string, asJson?: boolean): string;
306
- /**
307
- * `$elemMatch`: an element satisfies `match`. Operator keys test a scalar element; a plain object is
308
- * containment, which an index can serve; anything else tests each exploded object's fields.
309
- */
310
- protected jsonElemMatch(ctx: QueryContext, jsonField: string, match: Record<string, unknown>): string;
311
- /**
312
- * How a `$elemMatch` reads one exploded element: {@link jsonPathExpr}'s counterpart, over a column
313
- * of the derived table rather than a path of the document. An empty field names the element itself,
314
- * which is what the operator-only form matches on.
315
- */
316
- private elemAccessor;
282
+ * JSON path, a `HAVING` expression, a count and a distance; `undefined` for the rest. `bind` renders
283
+ * each compared value, a plain placeholder unless a JSON path reads it otherwise.
284
+ */
285
+ protected operatorCondition(ctx: QueryContext, operand: string, op: string, val: unknown, bind?: (value: unknown) => string): string | undefined;
286
+ /** `$all`, `$size` and `$elemMatch`, which read the JSON array at `slot`; `undefined` for the rest. */
287
+ private jsonArrayCondition;
288
+ /** A path of a JSON document, read the way each operator reads it. */
289
+ private jsonPathTarget;
290
+ /** Every operator `target` is compared with, `AND`-joined. */
291
+ private jsonConditions;
292
+ private jsonCondition;
293
+ /**
294
+ * How `op` reads a JSON value: an ordered comparison as a number, an equality as its operand compares,
295
+ * and a pattern or a null check as text.
296
+ */
297
+ private static jsonOperatorMode;
298
+ /** A bound operand of a JSON comparison, read the way `mode` reads the value it is compared with. */
299
+ private jsonOperand;
300
+ /** The JSON value at `slot`, as an array operator reads it. */
301
+ protected jsonValue(slot: JsonSlot): string;
302
+ /**
303
+ * `$all`: the JSON array at `slot` has an element holding each value, as Postgres's `@>` and MySQL's
304
+ * `JSON_CONTAINS` read one: a scalar equal, an array each of its elements, an object each of its keys.
305
+ * Plain JSON goes to {@link jsonContains}; an operator anywhere in it is matched element by element.
306
+ */
307
+ private jsonAll;
308
+ /** `$all` over plain JSON, which an engine with containment of its own spells natively, for an index to serve. */
309
+ protected jsonContains(ctx: QueryContext, slot: JsonSlot, values: readonly unknown[]): string;
310
+ /** One `EXISTS` per value, over the elements of the array at `slot`: a scalar equal, anything else held. */
311
+ private jsonElemsHold;
312
+ /**
313
+ * What the JSON `target` reads satisfies to hold `value`: an array each of its elements, an object each
314
+ * of its keys as a path, and an operator map or a scalar compared as a path is.
315
+ */
316
+ private jsonHolds;
317
+ /** An element of the array at `slot` equal to `value`, both read as JSON. */
318
+ protected jsonElemEquals(ctx: QueryContext, slot: JsonSlot, alias: string, value: unknown): string;
319
+ /** The JSON array at `slot` contains at least one of `values`, each as `$all` reads it. */
320
+ protected jsonAny(ctx: QueryContext, slot: JsonSlot, values: readonly unknown[]): string;
321
+ /** How many elements the JSON array at `slot` has, which `$size` compares. */
322
+ protected abstract jsonLength(slot: JsonSlot): string;
323
+ /** Whether the value at `slot` is a JSON array: the array operators match, and `$pull` changes, no other. */
324
+ protected abstract jsonIsArray(slot: JsonSlot): string;
325
+ /** The JSON array at `slot` as one row per element under `alias`, the `FROM` of an `EXISTS`. */
326
+ protected abstract jsonElemFrom(slot: JsonSlot, alias: string): string;
327
+ /** An exploded element as a JSON document, which its fields are paths into. */
328
+ protected abstract jsonElemDoc(alias: string): string;
329
+ /** An element of the array at `slot` itself, read the way `mode` reads a path: its document, or its root. */
330
+ protected jsonElemValue(_slot: JsonSlot, alias: string, mode: JsonAccessMode): string;
331
+ /**
332
+ * `$elemMatch`: an element holds `match`, as `$all` reads one value, its operators testing the element
333
+ * itself. An element equal to one value, or to one of several, is containment whatever the operator
334
+ * says, which compares by JSON type and is what an array index serves.
335
+ */
336
+ protected jsonElemMatch(ctx: QueryContext, slot: JsonSlot, match: Record<string, unknown>): string;
337
+ /** The optimizer hint a `$elemMatch` subquery opens with, where the engine plans one wrong without it. */
338
+ protected readonly jsonElemHint: string;
317
339
  /**
318
340
  * A JSON-encoded bound parameter, cast to the dialect's JSON type. Only the positional-placeholder
319
341
  * dialects use this - PostgreSQL binds JSON through {@link PgLikeSqlDialect.jsonScalarParam} instead.
@@ -337,10 +359,16 @@ export declare abstract class AbstractSqlDialect extends VectorSqlDialect implem
337
359
  */
338
360
  private collectSortTerms;
339
361
  /**
340
- * The `ORDER BY` operand for one key. A key that is not a field of `meta` - a `raw()` projection, a
341
- * `$select` alias - is an output alias, which is never table-qualified and needs no resolving.
362
+ * The `ORDER BY` operands for one key: a JSON path's in each of {@link jsonSortModes}. A key that is
363
+ * not a field of `meta` - a `raw()` projection, a `$select` alias - is an output alias, which is never
364
+ * table-qualified and needs no resolving.
365
+ */
366
+ private sortColumns;
367
+ /**
368
+ * How a JSON path is sorted by: as the JSON value, which the engine orders by type and a number by its
369
+ * value. An engine that orders JSON as text reads a number first, then the text.
342
370
  */
343
- private sortColumn;
371
+ protected readonly jsonSortModes: readonly JsonAccessMode[];
344
372
  /**
345
373
  * `LIMIT`/`OFFSET`. `sorted` says whether an `ORDER BY` was emitted just before, which
346
374
  * {@link MergeSqlDialect} needs: SQL Server refuses to page a statement that has none.
@@ -392,7 +420,7 @@ export declare abstract class AbstractSqlDialect extends VectorSqlDialect implem
392
420
  protected having(ctx: QueryContext, having: QueryHavingMap, emittedColumns: Record<string, string>): void;
393
421
  private static readonly SORT_DIRECTION_MAP;
394
422
  private resolveSortDirection;
395
- /** Scalar comparison operators shared by `HAVING` conditions and `$size` comparisons. */
423
+ /** Every operator of one `HAVING` condition, `AND`-joined. */
396
424
  protected havingCondition(ctx: QueryContext, expr: string, condition: QueryHavingMap[string]): void;
397
425
  /**
398
426
  * How many rows the filter matched, on every row of the page. A window function runs before
@@ -495,8 +523,16 @@ export declare abstract class AbstractSqlDialect extends VectorSqlDialect implem
495
523
  * `escapedCol` rather than the accumulated expression, values bind once, in key order.
496
524
  */
497
525
  protected jsonPull(ctx: QueryContext, expr: string, escapedCol: string, pull: Record<string, unknown>): string;
498
- /** Wrap `expr` so the array at `key` no longer contains `value`. */
499
- protected abstract jsonPullKey(ctx: QueryContext, expr: string, escapedCol: string, key: string, value: unknown): string;
526
+ /**
527
+ * Wrap `expr` so the array at `key` no longer contains `value`: the array rebuilt from the elements that
528
+ * differ from it, and any other value put back as it is. `JSON_REPLACE` leaves an absent key, and a NULL
529
+ * column, untouched.
530
+ */
531
+ protected jsonPullKey(ctx: QueryContext, expr: string, escapedCol: string, key: string, value: unknown): string;
532
+ /** The elements a `$pull` keeps, back in one array, and an empty one where it keeps none. */
533
+ protected jsonArrayOf(elem: string): string;
534
+ /** Whether an element is not the pulled value, both read as JSON. */
535
+ protected jsonDiffers(elem: string, operand: string): string;
500
536
  /** Shallow assignment of top-level keys, matching PostgreSQL's `jsonb || jsonb`. */
501
537
  protected abstract jsonSet(ctx: QueryContext, expr: string, set: Record<string, unknown>, field?: FieldOptions): string;
502
538
  /** Append one value per array key, creating the array when the key is absent. */
@@ -513,37 +549,16 @@ export declare abstract class AbstractSqlDialect extends VectorSqlDialect implem
513
549
  getRawValue(ctx: QueryContext, opts: QueryRawFnOptions & {
514
550
  value: QueryRaw;
515
551
  }): void;
516
- /**
517
- * Resolves a dot-notation key to its JSON field metadata.
518
- * Shared by `where()` and `sort()` to detect 'column.path' keys where 'column' is a JSON/JSONB field.
519
- *
520
- * @returns resolved metadata or `undefined` if the key is not a JSON dot-notation path
521
- */
522
- protected resolveJsonDotPath<E>(meta: EntityMeta<E>, key: string, prefix?: string): {
523
- jsonPath: string;
524
- column: string;
525
- } | undefined;
552
+ /** A `column.path` key of `meta`'s JSON field as the path it names, shared by `where` and `sort`; else `undefined`. */
553
+ protected resolveJsonDotPath<E>(meta: EntityMeta<E>, key: string, prefix?: string): JsonSlot | undefined;
526
554
  /**
527
555
  * One JSON path, read the way `mode` asks for: the one place the three readings are chosen between,
528
556
  * so `$where`, `$sort` and every operator reach a path the same way. Public because a JSON index
529
557
  * is matched back by its own text, so the migrator's `CREATE INDEX` has to spell it from here too.
530
558
  */
531
- jsonPathExpr(escapedColumn: string, jsonPath: string, mode: JsonAccessMode): string;
532
- /**
533
- * Compare a JSONB dot-notation path, e.g. `'settings.isArchived': { $ne: true }`.
534
- * Receives a pre-resolved `resolveJsonDotPath` result to avoid redundant computation.
535
- */
536
- protected compareJsonPath(ctx: QueryContext, resolved: {
537
- jsonPath: string;
538
- column: string;
539
- }, val: unknown): void;
540
- /**
541
- * Returns SQL that extracts a scalar value from a JSON path.
542
- * Dialects can override this to customize path access syntax while preserving
543
- * the shared comparison/operator pipeline.
544
- */
545
- protected getJsonPathScalarExpr(escapedColumn: string, jsonPath: string): string;
546
- protected getJsonPathJsonbExpr(escapedColumn: string, jsonPath: string): string;
559
+ jsonPathExpr(escapedColumn: string, path: string, mode: JsonAccessMode): string;
560
+ /** A path of the JSON in `escapedColumn`, `''` for the document itself, as its JSON value or its text. */
561
+ protected abstract jsonPathReading(escapedColumn: string, path: string, mode: 'json' | 'text'): string;
547
562
  /**
548
563
  * Normalizes a raw WHERE value into an operator map.
549
564
  * Arrays become `$in`, operator maps pass through, everything else becomes `$eq`.
@@ -624,23 +639,18 @@ export declare abstract class AbstractSqlDialect extends VectorSqlDialect implem
624
639
  /** Filter by relation size: the same subquery, counting instead of testing for existence. */
625
640
  protected compareRelationSize<E>(ctx: QueryContext, entity: Type<E>, relKey: string, sizeVal: number | QuerySizeComparisonOps, rel: RelationMeta, opts: QueryComparisonOptions): void;
626
641
  /**
627
- * `<expr> <op> <value>` for each operator, AND-joined and parenthesized when there is more than
628
- * one. `exprFn` is re-run per operator because what it appends is an expression, not a column:
629
- * a `WHERE` has no output alias to refer back to, so the only way to compare it twice is to spell
630
- * it twice. Shared by `$size`, which counts, and `$near`, which measures a distance.
642
+ * `<expr> <op> <value>` for each bound, `AND`-joined. `expr` is spelled once per bound because it is an
643
+ * expression, not a column: a `WHERE` has no output alias to refer back to. Shared by `$size`, which
644
+ * counts, and `$near`, which measures a distance.
631
645
  */
632
- private buildExprComparison;
646
+ private boundConditions;
633
647
  /**
634
- * Build a complete `$size` comparison expression.
635
- * @param sizeExprFn - function that appends the size expression to ctx (e.g. `JSONB_ARRAY_LENGTH("col")`)
648
+ * A count compared with `size`, a number or its bounds. A count is never NULL, so its equality stays
649
+ * plain rather than the null-safe `$ne` (`IS DISTINCT FROM`, `IS NOT`): same rows, shorter SQL.
636
650
  */
637
- protected buildSizeComparison(ctx: QueryContext, sizeExprFn: () => void, sizeVal: number | QuerySizeComparisonOps): void;
651
+ private sizeCondition;
638
652
  /** `<distance> <op> ?`, the `$where` half of a vector search, its bounds checked here since `/http` input is untyped. */
639
- protected compareVectorNear<E>(ctx: QueryContext, meta: EntityMeta<E>, key: string, near: QueryVectorNear): void;
640
- /** The runtime half of {@link QuerySizeComparisonOps}: what a count can sensibly be compared with. */
641
- private static readonly SIZE_COMPARE_OPS;
642
- /** ` <op> <value>` after a count already written, refusing any operator a count cannot be compared with. */
643
- private appendSizeOp;
653
+ private vectorNearCondition;
644
654
  /** ANSI-style single-quote escaping. MySQL-family dialects override this for backslash escaping. */
645
655
  escape(value: unknown): string;
646
656
  protected get regexpOp(): string;
@@ -658,8 +668,8 @@ export declare abstract class AbstractSqlDialect extends VectorSqlDialect implem
658
668
  */
659
669
  protected get neOp(): string;
660
670
  protected neExpr(field: string, ph: string): string;
661
- /** `operand IN (...)` binding each value, or the constant an empty set reduces to: no value is in it. */
662
- protected formatIn(ctx: QueryContext, operand: string, values: unknown[], negate: boolean): string;
671
+ /** `operand IN (...)` of each value as `bind` renders it, or the constant an empty set reduces to: no value is in it. */
672
+ protected formatIn(_ctx: QueryContext, operand: string, values: unknown[], negate: boolean, bind: (value: unknown) => string): string;
663
673
  /** Reads extracted JSON text as a number, which every engine spells its own way. */
664
674
  protected abstract numericCast(expr: string): string;
665
675
  toString(): string;