turbine-orm 0.16.0 → 0.18.0

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 (41) hide show
  1. package/README.md +180 -12
  2. package/dist/adapters/cockroachdb.js +4 -2
  3. package/dist/adapters/index.js +4 -1
  4. package/dist/adapters/yugabytedb.js +4 -2
  5. package/dist/cjs/adapters/cockroachdb.js +4 -2
  6. package/dist/cjs/adapters/index.js +4 -1
  7. package/dist/cjs/adapters/yugabytedb.js +4 -2
  8. package/dist/cjs/cli/studio.js +5 -1
  9. package/dist/cjs/client.js +164 -0
  10. package/dist/cjs/errors.js +35 -5
  11. package/dist/cjs/generate.js +14 -3
  12. package/dist/cjs/index.js +10 -2
  13. package/dist/cjs/introspect.js +81 -0
  14. package/dist/cjs/nested-write.js +70 -6
  15. package/dist/cjs/query/builder.js +538 -12
  16. package/dist/cjs/realtime.js +147 -0
  17. package/dist/cjs/schema-builder.js +86 -0
  18. package/dist/cjs/schema.js +10 -0
  19. package/dist/cjs/typed-sql.js +149 -0
  20. package/dist/cli/studio.js +5 -1
  21. package/dist/client.d.ts +120 -0
  22. package/dist/client.js +165 -1
  23. package/dist/errors.js +35 -5
  24. package/dist/generate.js +14 -3
  25. package/dist/index.d.ts +4 -2
  26. package/dist/index.js +5 -1
  27. package/dist/introspect.js +81 -0
  28. package/dist/nested-write.js +70 -6
  29. package/dist/query/builder.d.ts +104 -1
  30. package/dist/query/builder.js +539 -13
  31. package/dist/query/index.d.ts +1 -1
  32. package/dist/query/types.d.ts +126 -2
  33. package/dist/realtime.d.ts +71 -0
  34. package/dist/realtime.js +144 -0
  35. package/dist/schema-builder.d.ts +68 -1
  36. package/dist/schema-builder.js +85 -0
  37. package/dist/schema.d.ts +18 -1
  38. package/dist/schema.js +10 -0
  39. package/dist/typed-sql.d.ts +101 -0
  40. package/dist/typed-sql.js +145 -0
  41. package/package.json +17 -15
@@ -114,6 +114,14 @@ export declare class QueryInterface<T extends object, R extends object = {}> {
114
114
  private readonly columnArrayTypeMap;
115
115
  /** Tracks tables that have already triggered a deep-with warning (one-time) */
116
116
  private readonly deepWithWarned;
117
+ /**
118
+ * Per-table memo of date columns keyed by their camelCase FIELD name.
119
+ * `meta.dateColumns` is keyed by raw snake_case column name, which matches
120
+ * top-level rows from pg. Nested relation rows arrive from json_build_object
121
+ * with camelCase keys, so they need this camelCase-keyed set to be coerced
122
+ * to Date as well (otherwise nested dates leak through as strings).
123
+ */
124
+ private readonly camelDateFieldCache;
117
125
  /** True when this QI runs inside an active transaction (set via _txScoped option). */
118
126
  private readonly txScoped;
119
127
  /** Original options reference — forwarded to child QIs in nested writes. */
@@ -251,6 +259,24 @@ export declare class QueryInterface<T extends object, R extends object = {}> {
251
259
  buildCount(args?: CountArgs<T>): DeferredQuery<number>;
252
260
  groupBy(args: GroupByArgs<T>): Promise<Record<string, unknown>[]>;
253
261
  buildGroupBy(args: GroupByArgs<T>): DeferredQuery<Record<string, unknown>[]>;
262
+ /**
263
+ * Build the SQL fragments for a {@link HavingClause}.
264
+ *
265
+ * Each aggregate expression (`COUNT(*)`, `SUM("col")`, etc.) is constructed
266
+ * from a **schema-validated, quoted** column identifier — `this.toColumn()`
267
+ * throws {@link ValidationError} for unknown fields and `this.q()` quotes via
268
+ * the dialect, so no unvalidated identifier ever reaches the SQL string. Every
269
+ * comparison value is pushed onto the shared `params` array and referenced by
270
+ * a `$N` placeholder via {@link buildHavingNumericClauses} — there is no string
271
+ * interpolation of user values.
272
+ */
273
+ private buildHavingClauses;
274
+ /**
275
+ * Convert a single having filter into one or more parameterized SQL
276
+ * comparisons against the given aggregate expression. A bare number is
277
+ * shorthand for equality. Unknown operator keys throw {@link ValidationError}.
278
+ */
279
+ private buildHavingNumericClauses;
254
280
  aggregate(args: AggregateArgs<T>): Promise<AggregateResult<T>>;
255
281
  buildAggregate(args: AggregateArgs<T>): DeferredQuery<AggregateResult<T>>;
256
282
  /**
@@ -311,6 +337,19 @@ export declare class QueryInterface<T extends object, R extends object = {}> {
311
337
  private collectJsonFilterParams;
312
338
  /** Collect params from array filter. Mirrors buildArrayFilterClauses. */
313
339
  private collectArrayFilterParams;
340
+ /**
341
+ * Collect params for an orderBy clause. Only vector KNN ordering pushes a
342
+ * param (the `$n::vector` query vector); plain direction ordering is
343
+ * parameterless. Mirrors buildOrderBy's push order exactly so the cached-SQL
344
+ * param re-collection stays in lockstep.
345
+ */
346
+ private collectOrderByParams;
347
+ /**
348
+ * Collect params for a vector distance WHERE filter. Mirrors
349
+ * {@link buildVectorFilterClauses}: the `$n::vector` query vector first, then
350
+ * the comparison threshold(s).
351
+ */
352
+ private collectVectorFilterParams;
314
353
  /**
315
354
  * Produce a fingerprint for a `with` clause tree. Recursion mirrors
316
355
  * buildSelectWithRelations / buildRelationSubquery.
@@ -368,9 +407,40 @@ export declare class QueryInterface<T extends object, R extends object = {}> {
368
407
  * Each operator key becomes its own clause, all ANDed together.
369
408
  */
370
409
  private buildOperatorClauses;
371
- /** Build ORDER BY clause from an object */
410
+ /**
411
+ * Build ORDER BY clause from an object.
412
+ *
413
+ * Each value is either a plain direction (`'asc'`/`'desc'`) or — for pgvector
414
+ * columns — a `{ distance: { to, metric, direction? } }` KNN ordering object.
415
+ * Vector ordering binds the query vector as a `$n::vector` param, so a `params`
416
+ * array MUST be supplied when a vector ordering may be present (top-level
417
+ * findMany path). When `params` is omitted (groupBy / relation path) a vector
418
+ * ordering throws — KNN ordering is only supported at the top level.
419
+ */
372
420
  private buildOrderBy;
421
+ /**
422
+ * Resolve a {@link VectorMetric} to its pgvector distance operator from a
423
+ * fixed allow-list, validating the target column is actually a `vector`
424
+ * column. Throws {@link ValidationError} for an unknown metric or a
425
+ * non-vector column — a user-supplied string can never become a SQL operator.
426
+ */
427
+ private vectorOperator;
428
+ /**
429
+ * Validate and bind a query vector as a single `$n::vector` parameter.
430
+ * Every element must be a finite number (no NaN / Infinity / strings) so a
431
+ * malformed array can never produce a broken `::vector` literal, and the array
432
+ * is NEVER string-interpolated into the SQL text. Returns the `$n::vector`
433
+ * placeholder string.
434
+ */
435
+ private pushVectorParam;
373
436
  /** Parse a flat row: convert snake_case to camelCase + Date coercion */
437
+ /**
438
+ * Returns the set of camelCase field names for a table's date columns,
439
+ * derived once from `meta.dateColumns` (snake_case) via reverseColumnMap and
440
+ * memoized per table. Used so nested relation rows (camelCase keys) coerce
441
+ * dates the same way top-level rows do.
442
+ */
443
+ private getCamelDateFields;
374
444
  private parseRow;
375
445
  /** Parse a row that may contain JSON nested relation columns */
376
446
  private parseNestedRow;
@@ -509,6 +579,27 @@ export declare class QueryInterface<T extends object, R extends object = {}> {
509
579
  * evaluates to a JSON array (hasMany) or a JSON object (belongsTo/hasOne).
510
580
  */
511
581
  private buildRelationSubquery;
582
+ /**
583
+ * Build the json_agg subquery for a `manyToMany` relation, JOINing the target
584
+ * table through a junction (join) table.
585
+ *
586
+ * Shape (no LIMIT/ORDER):
587
+ * ```sql
588
+ * SELECT COALESCE(json_agg(json_build_object(...)), '[]'::json)
589
+ * FROM <target> <talias>
590
+ * JOIN <junction> <jalias> ON <jalias>.<targetKey> = <talias>.<targetPK>
591
+ * WHERE <jalias>.<sourceKey> = <parentRef>.<referenceKey>
592
+ * ```
593
+ *
594
+ * With LIMIT/ORDER, the rows are wrapped in an inner subquery so the LIMIT
595
+ * applies BEFORE aggregation (identical strategy to hasMany).
596
+ *
597
+ * Cardinality is always 'many' → empty-array fallback, never NULL.
598
+ *
599
+ * IMPORTANT: every `params.push` here MUST be mirrored, in the same order, in
600
+ * {@link collectRelationSubqueryParams} or pipeline batching will desync.
601
+ */
602
+ private buildManyToManySubquery;
512
603
  /**
513
604
  * Get the Postgres type for a column (e.g. 'jsonb', 'text', '_int4').
514
605
  * Used to detect JSONB/array columns for specialized operators.
@@ -530,6 +621,18 @@ export declare class QueryInterface<T extends object, R extends object = {}> {
530
621
  * Supports: has, hasEvery, hasSome, isEmpty.
531
622
  */
532
623
  private buildArrayFilterClauses;
624
+ /**
625
+ * Build SQL clauses for a pgvector distance WHERE filter:
626
+ *
627
+ * `"embedding" <-> $1::vector < $2`
628
+ *
629
+ * The query vector is bound as a `$n::vector` param (never interpolated), the
630
+ * metric maps to an operator via a fixed allow-list, and each comparison
631
+ * threshold (`lt`/`lte`/`gt`/`gte`) is its own bound param. Emits one clause
632
+ * per supplied comparator (all ANDed). Param push order matches
633
+ * {@link collectVectorFilterParams}.
634
+ */
635
+ private buildVectorFilterClauses;
533
636
  /**
534
637
  * Build SQL clause for full-text search using to_tsvector @@ to_tsquery.
535
638
  * The config name is validated to prevent injection (only alphanumeric + underscore).