turbine-orm 0.49.0 → 0.50.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 (157) hide show
  1. package/README.md +122 -39
  2. package/dist/cjs/adapters/cockroachdb.d.ts +39 -0
  3. package/dist/cjs/adapters/index.d.ts +110 -0
  4. package/dist/cjs/adapters/yugabytedb.d.ts +51 -0
  5. package/dist/cjs/cli/config.d.ts +181 -0
  6. package/dist/cjs/cli/config.js +32 -6
  7. package/dist/cjs/cli/destructive.d.ts +38 -0
  8. package/dist/cjs/cli/index.d.ts +359 -0
  9. package/dist/cjs/cli/index.js +228 -56
  10. package/dist/cjs/cli/loader.d.ts +61 -0
  11. package/dist/cjs/cli/mcp.d.ts +42 -0
  12. package/dist/cjs/cli/migrate.d.ts +356 -0
  13. package/dist/cjs/cli/migrate.js +131 -40
  14. package/dist/cjs/cli/observe-ui.d.ts +1 -0
  15. package/dist/cjs/cli/observe-ui.js +14 -5
  16. package/dist/cjs/cli/observe.d.ts +25 -0
  17. package/dist/cjs/cli/observe.js +49 -12
  18. package/dist/cjs/cli/pii-tags.d.ts +53 -0
  19. package/dist/cjs/cli/prisma-report.d.ts +33 -0
  20. package/dist/cjs/cli/prisma-report.js +73 -0
  21. package/dist/cjs/cli/prisma-resolve.d.ts +106 -0
  22. package/dist/cjs/cli/prisma-resolve.js +1 -0
  23. package/dist/cjs/cli/prisma-schema.d.ts +176 -0
  24. package/dist/cjs/cli/prisma-schema.js +82 -4
  25. package/dist/cjs/cli/rate-limit.d.ts +32 -0
  26. package/dist/cjs/cli/rate-limit.js +45 -0
  27. package/dist/cjs/cli/studio-demo.d.ts +43 -0
  28. package/dist/cjs/cli/studio-ui.generated.d.ts +1 -0
  29. package/dist/cjs/cli/studio.d.ts +207 -0
  30. package/dist/cjs/cli/studio.js +136 -71
  31. package/dist/cjs/cli/ui.d.ts +73 -0
  32. package/dist/cjs/cli/ui.js +51 -9
  33. package/dist/cjs/client.d.ts +837 -0
  34. package/dist/cjs/client.js +3 -0
  35. package/dist/cjs/dialect.d.ts +516 -0
  36. package/dist/cjs/dialect.js +37 -12
  37. package/dist/cjs/errors.d.ts +370 -0
  38. package/dist/cjs/generate.d.ts +137 -0
  39. package/dist/cjs/generate.js +39 -6
  40. package/dist/cjs/index-advisor.d.ts +153 -0
  41. package/dist/cjs/index-stats.d.ts +384 -0
  42. package/dist/cjs/index.d.ts +55 -0
  43. package/dist/cjs/index.js +7 -2
  44. package/dist/cjs/introspect.d.ts +269 -0
  45. package/dist/cjs/mssql.d.ts +232 -0
  46. package/dist/cjs/mssql.js +6 -0
  47. package/dist/cjs/mysql.d.ts +173 -0
  48. package/dist/cjs/mysql.js +16 -0
  49. package/dist/cjs/nested-write.d.ts +96 -0
  50. package/dist/cjs/nested-write.js +414 -24
  51. package/dist/cjs/observe.d.ts +115 -0
  52. package/dist/cjs/optional-peer-import.d.cts +72 -0
  53. package/dist/cjs/pipeline-submittable.d.ts +93 -0
  54. package/dist/cjs/pipeline.d.ts +71 -0
  55. package/dist/cjs/powdb-introspect.d.ts +84 -0
  56. package/dist/cjs/powdb.d.ts +931 -0
  57. package/dist/cjs/powdb.js +106 -21
  58. package/dist/cjs/powql.d.ts +592 -0
  59. package/dist/cjs/powql.js +42 -6
  60. package/dist/cjs/prisma-compat.d.ts +283 -0
  61. package/dist/cjs/prisma-compat.js +167 -9
  62. package/dist/cjs/query/aggregates.d.ts +92 -0
  63. package/dist/cjs/query/aggregates.js +7 -3
  64. package/dist/cjs/query/batched-loader.d.ts +193 -0
  65. package/dist/cjs/query/builder.d.ts +849 -0
  66. package/dist/cjs/query/builder.js +571 -65
  67. package/dist/cjs/query/compound-unique.d.ts +51 -0
  68. package/dist/cjs/query/deferred.d.ts +223 -0
  69. package/dist/cjs/query/filters.d.ts +201 -0
  70. package/dist/cjs/query/index.d.ts +14 -0
  71. package/dist/cjs/query/index.js +6 -1
  72. package/dist/cjs/query/relations.d.ts +609 -0
  73. package/dist/cjs/query/relations.js +693 -46
  74. package/dist/cjs/query/types.d.ts +1300 -0
  75. package/dist/cjs/query/utils.d.ts +209 -0
  76. package/dist/cjs/query/utils.js +208 -1
  77. package/dist/cjs/query/warn-registry.d.ts +68 -0
  78. package/dist/cjs/query/warn-registry.js +9 -0
  79. package/dist/cjs/query/where-compile.d.ts +139 -0
  80. package/dist/cjs/query/where.d.ts +548 -0
  81. package/dist/cjs/query/where.js +58 -22
  82. package/dist/cjs/query/writes.d.ts +172 -0
  83. package/dist/cjs/query/writes.js +105 -12
  84. package/dist/cjs/realtime.d.ts +70 -0
  85. package/dist/cjs/schema-builder.d.ts +354 -0
  86. package/dist/cjs/schema-metadata.d.ts +83 -0
  87. package/dist/cjs/schema-sql.d.ts +217 -0
  88. package/dist/cjs/schema-sql.js +23 -5
  89. package/dist/cjs/schema.d.ts +356 -0
  90. package/dist/cjs/schema.js +125 -0
  91. package/dist/cjs/seed.d.ts +15 -0
  92. package/dist/cjs/serverless.d.ts +142 -0
  93. package/dist/cjs/sqlite.d.ts +143 -0
  94. package/dist/cjs/sqlite.js +4 -0
  95. package/dist/cjs/typed-sql.d.ts +102 -0
  96. package/dist/cli/config.d.ts +18 -4
  97. package/dist/cli/config.js +31 -6
  98. package/dist/cli/index.d.ts +123 -0
  99. package/dist/cli/index.js +223 -58
  100. package/dist/cli/migrate.d.ts +59 -10
  101. package/dist/cli/migrate.js +128 -41
  102. package/dist/cli/observe-ui.d.ts +1 -1
  103. package/dist/cli/observe-ui.js +14 -5
  104. package/dist/cli/observe.d.ts +7 -1
  105. package/dist/cli/observe.js +48 -12
  106. package/dist/cli/prisma-report.d.ts +14 -0
  107. package/dist/cli/prisma-report.js +72 -0
  108. package/dist/cli/prisma-resolve.d.ts +6 -0
  109. package/dist/cli/prisma-resolve.js +1 -0
  110. package/dist/cli/prisma-schema.d.ts +62 -2
  111. package/dist/cli/prisma-schema.js +81 -4
  112. package/dist/cli/rate-limit.d.ts +32 -0
  113. package/dist/cli/rate-limit.js +40 -0
  114. package/dist/cli/studio.d.ts +5 -5
  115. package/dist/cli/studio.js +135 -70
  116. package/dist/cli/ui.d.ts +1 -1
  117. package/dist/cli/ui.js +51 -9
  118. package/dist/client.d.ts +40 -0
  119. package/dist/client.js +3 -0
  120. package/dist/dialect.d.ts +17 -1
  121. package/dist/dialect.js +37 -12
  122. package/dist/generate.js +40 -7
  123. package/dist/index.d.ts +1 -1
  124. package/dist/index.js +1 -1
  125. package/dist/mssql.js +6 -0
  126. package/dist/mysql.js +16 -0
  127. package/dist/nested-write.d.ts +2 -0
  128. package/dist/nested-write.js +415 -25
  129. package/dist/powdb.d.ts +4 -2
  130. package/dist/powdb.js +106 -21
  131. package/dist/powql.d.ts +5 -0
  132. package/dist/powql.js +42 -6
  133. package/dist/prisma-compat.d.ts +2 -0
  134. package/dist/prisma-compat.js +166 -8
  135. package/dist/query/aggregates.js +7 -3
  136. package/dist/query/builder.d.ts +292 -21
  137. package/dist/query/builder.js +570 -64
  138. package/dist/query/deferred.d.ts +39 -0
  139. package/dist/query/index.d.ts +1 -1
  140. package/dist/query/index.js +1 -1
  141. package/dist/query/relations.d.ts +173 -5
  142. package/dist/query/relations.js +688 -47
  143. package/dist/query/types.d.ts +123 -39
  144. package/dist/query/utils.d.ts +116 -0
  145. package/dist/query/utils.js +198 -0
  146. package/dist/query/warn-registry.d.ts +9 -0
  147. package/dist/query/warn-registry.js +9 -0
  148. package/dist/query/where.d.ts +38 -1
  149. package/dist/query/where.js +58 -23
  150. package/dist/query/writes.d.ts +42 -1
  151. package/dist/query/writes.js +104 -13
  152. package/dist/schema-sql.d.ts +14 -0
  153. package/dist/schema-sql.js +23 -5
  154. package/dist/schema.d.ts +38 -0
  155. package/dist/schema.js +123 -0
  156. package/dist/sqlite.js +4 -0
  157. package/package.json +77 -28
@@ -0,0 +1,51 @@
1
+ /**
2
+ * turbine-orm — Prisma-style compound-unique `where` selectors.
3
+ *
4
+ * Prisma lets a `findUnique`-family `where` address a multi-column unique
5
+ * constraint through a single synthetic key holding the member columns:
6
+ *
7
+ * ```ts
8
+ * db.members.findUnique({ where: { orgId_userId: { orgId: 1, userId: 7 } } })
9
+ * // ≡ where: { orgId: 1, userId: 7 } → WHERE "org_id" = $1 AND "user_id" = $2
10
+ * ```
11
+ *
12
+ * {@link expandCompoundUniqueWhere} rewrites such a selector into the equivalent
13
+ * column conjunction BEFORE the where is fingerprinted / SQL-compiled, so the
14
+ * template cache only ever sees the canonical expanded form (no new cache-key
15
+ * segment, and the expanded shape shares its entry with the spelled-out form).
16
+ *
17
+ * Selector NAMES come from the table metadata, in priority order:
18
+ * 1. a composite primary key (length ≥ 2);
19
+ * 2. each composite `uniqueColumns` entry (introspected composite UNIQUE
20
+ * constraints);
21
+ * 3. each composite UNIQUE index in `indexes` (`unique && !docPath &&
22
+ * !partial`, the ONLY composite-unique source a `defineSchema` code-first
23
+ * client has, since `defineSchema` records single-column uniques in
24
+ * `uniqueColumns` and composite uniques as declared unique indexes). A
25
+ * PARTIAL unique index is skipped: it only guarantees uniqueness over its
26
+ * predicate's rows, not table-wide, so it cannot address a single row.
27
+ *
28
+ * For every column set two lookup names are registered (both mapping to the same
29
+ * ordered FIELD list): the underscore join of the camelCase FIELD names
30
+ * (`orgId_userId`, Prisma's default) and, when different, the underscore join of
31
+ * the raw snake_case column names (`org_id_user_id`).
32
+ *
33
+ * Collision rules (deterministic, documented):
34
+ * - a synthetic name equal to a real field / column / relation name is never
35
+ * registered (real members always win);
36
+ * - two DIFFERENT column sets producing the same name drop that name entirely.
37
+ *
38
+ * The map is pure metadata, so it is computed lazily and memoized per
39
+ * {@link TableMetadata} in a module-level `WeakMap`.
40
+ */
41
+ import type { TableMetadata } from '../schema.js';
42
+ /**
43
+ * Expand any Prisma compound-unique selector keys in `where` into their column
44
+ * conjunction. Returns the SAME object reference when nothing expands (the
45
+ * byte-identical fast path), else a shallow clone with the selector keys
46
+ * replaced. A selector key whose members do not exactly match the constraint's
47
+ * fields throws a {@link ValidationError} (E003) naming the required members; a
48
+ * non-selector unknown key is left untouched to fall through to the existing
49
+ * unknown-column error at SQL-build time.
50
+ */
51
+ export declare function expandCompoundUniqueWhere(meta: TableMetadata, where: Record<string, unknown>): Record<string, unknown>;
@@ -0,0 +1,223 @@
1
+ /**
2
+ * turbine-orm — Deferred query + QueryInterface option types
3
+ *
4
+ * Split from builder.ts so the class file focuses on SQL assembly / execution.
5
+ */
6
+ import type pg from 'pg';
7
+ import type { Dialect } from '../dialect.js';
8
+ import type { SchemaMetadata } from '../schema.js';
9
+ import type { QueryInterface } from './builder.js';
10
+ import type { GlobalFilters, RelationLoadStrategy } from './types.js';
11
+ /**
12
+ * Runs a SQL statement and resolves its raw result. Passed to a
13
+ * {@link DeferredQuery.reselect} plan so it can run the write and the follow-up
14
+ * SELECT through the same timeout/instrumentation path as the primary query.
15
+ */
16
+ export type ReselectExecutor = (sql: string, params: unknown[], preparedName?: string) => Promise<pg.QueryResult>;
17
+ export interface DeferredQuery<T> {
18
+ /** SQL text with $1, $2 placeholders */
19
+ sql: string;
20
+ /** Bound parameter values */
21
+ params: unknown[];
22
+ /** How to transform the raw pg.QueryResult into the final value */
23
+ transform: (result: pg.QueryResult) => T;
24
+ /** Tag for debugging / logging */
25
+ tag: string;
26
+ /** Prepared statement name (t_<16hex>). Set when SQL cache is enabled. */
27
+ preparedName?: string;
28
+ /**
29
+ * Execution plan for dialects whose {@link Dialect.resultStrategy} is
30
+ * `'reselect'` (no RETURNING — e.g. MySQL). Owns the statement ordering: it
31
+ * runs the write and the follow-up row-fetching SELECT(s) via `exec`, and
32
+ * resolves the result whose rows {@link DeferredQuery.transform} consumes.
33
+ * Absent for `'returning'`/`'output'` dialects (the statement returns its own
34
+ * rows), so the PostgreSQL path never allocates or consults it.
35
+ */
36
+ reselect?: (exec: ReselectExecutor) => Promise<pg.QueryResult>;
37
+ }
38
+ /** Middleware function type — imported from client to avoid circular deps */
39
+ export type MiddlewareFn = (params: {
40
+ model: string;
41
+ action: string;
42
+ args: Record<string, unknown>;
43
+ }, next: (params: {
44
+ model: string;
45
+ action: string;
46
+ args: Record<string, unknown>;
47
+ }) => Promise<unknown>) => Promise<unknown>;
48
+ /** Emitted after every query execution (success or failure). */
49
+ export interface QueryEvent {
50
+ sql: string;
51
+ params: unknown[];
52
+ duration: number;
53
+ model: string;
54
+ action: string;
55
+ rows: number;
56
+ timestamp: Date;
57
+ error?: Error;
58
+ /**
59
+ * Set to `'auto-batched'` on the statements of a query whose
60
+ * `relationLoadStrategy: 'auto'` engaged the per-relation batched fallback
61
+ * (the base statement and every batched follow-up). Absent for the plain join
62
+ * path, explicit `'join'`/`'batched'`, and non-auto queries, so production
63
+ * observability can see exactly which queries the auto default re-planned.
64
+ */
65
+ strategy?: 'auto-batched';
66
+ }
67
+ export type QueryEventListener = (event: QueryEvent) => void;
68
+ /** Options passed from TurbineClient to QueryInterface */
69
+ export interface QueryInterfaceOptions {
70
+ /** Default LIMIT applied to findMany() when no limit is specified */
71
+ defaultLimit?: number;
72
+ /**
73
+ * Log a one-time warning when {@link QueryInterface.findMany} is called
74
+ * without a `limit`. Defaults to `true` so that accidental unbounded
75
+ * queries are surfaced loudly during development. Pass `false` to silence
76
+ * the warning entirely (e.g. for CLI tooling that intentionally streams
77
+ * full tables), or a per-table map (`{ userProfiles: false }`) to silence
78
+ * only the tables that intentionally read full sets — unlisted tables keep
79
+ * the default. Map keys accept BOTH the camelCase accessor name
80
+ * (`userProfiles`) and the snake_case table name (`user_profiles`); the
81
+ * snake_case entry wins if both are present. Individual calls can also
82
+ * override via `findMany({ warnOnUnlimited: false })`.
83
+ */
84
+ warnOnUnlimited?: boolean | Record<string, boolean>;
85
+ /**
86
+ * Enable prepared statements. When true, queries are submitted with a
87
+ * `{ name, text, values }` object to the pg driver, which caches the
88
+ * parse+plan on the server per connection.
89
+ *
90
+ * Default: `true` for Turbine-owned pools, `false` for external pools
91
+ * (serverless drivers may not support named statements).
92
+ */
93
+ preparedStatements?: boolean;
94
+ /**
95
+ * Enable the SQL template cache. When true, repeated queries with the
96
+ * same shape (same keys, operators, relations, different values) reuse
97
+ * cached SQL text instead of rebuilding from scratch.
98
+ *
99
+ * Default: `true`. Set to `false` as a nuclear kill switch.
100
+ *
101
+ * Dev-mode safety net: when `NODE_ENV !== 'production'`, every cache HIT is
102
+ * cross-checked by rebuilding the SQL + params fresh and comparing them
103
+ * against the cache-hit result, catching any drift between the fingerprint,
104
+ * SQL-build, and param-collect paths (which has silently corrupted results
105
+ * before). A mismatch throws a `ValidationError` (E003). This runs only
106
+ * outside production, so it never touches the production hot path. Set the
107
+ * env var `TURBINE_DISABLE_CACHE_CHECK=1` to opt out when dev traffic is
108
+ * perf-sensitive.
109
+ *
110
+ * Production sampling: the check is off in production by default. Set
111
+ * `TURBINE_CACHE_CHECK_SAMPLE` to a float in `(0,1]` to re-verify that
112
+ * fraction of cache hits under real load (e.g. `0.001` for one in a
113
+ * thousand). A sampled mismatch logs `console.error` once per distinct
114
+ * fingerprint AND throws the same `ValidationError` (E003). `0`, unset, or an
115
+ * unparseable value keeps the check fully off.
116
+ */
117
+ sqlCache?: boolean;
118
+ /**
119
+ * Maximum number of distinct SQL templates the per-table LRU cache retains.
120
+ *
121
+ * Default: `1000`. Raise it for apps with a very large number of distinct
122
+ * query SHAPES (not values, since values are parameterized and never fragment the
123
+ * cache) to lift the hit rate at the cost of memory; lower it to cap memory.
124
+ * `0` disables the cache entirely, exactly like `sqlCache: false`. A negative
125
+ * value is ignored (treated as the default). Applied per QueryInterface (one
126
+ * per table).
127
+ */
128
+ sqlCacheSize?: number;
129
+ /** SQL dialect implementation. Defaults to PostgreSQL. */
130
+ dialect?: Dialect;
131
+ /**
132
+ * Interpret offset-less timestamp strings (Postgres `timestamp` without
133
+ * time zone, and the JSON emitted by nested-relation subqueries) as UTC.
134
+ * This is the Prisma/Rails/Django convention and makes results independent
135
+ * of the server's local time zone. Default: `true`. Set `false` to restore
136
+ * the pre-0.26 behavior (JS local-time interpretation).
137
+ */
138
+ utcTimestamps?: boolean;
139
+ /**
140
+ * Client-level default relation-loading strategy for `with` clauses; a
141
+ * per-query `relationLoadStrategy` arg overrides it. On SQL engines the default
142
+ * is `'join'` (one single-statement `json_agg` query). On PowDB the default is
143
+ * the batched loaders, and `'join'` opts INTO native server-side joins where
144
+ * eligible (ineligible relations fall back to the loaders per-relation and
145
+ * silently; see the PowDB docs).
146
+ */
147
+ relationLoadStrategy?: RelationLoadStrategy;
148
+ /**
149
+ * When `true`, every to-many `with` relation that carries no explicit
150
+ * `orderBy` is loaded ordered by the target table's primary key ascending, so
151
+ * unordered child arrays come back in a deterministic order (json_agg / batched
152
+ * loaders otherwise leave child-array order engine-dependent). An explicit
153
+ * per-relation `orderBy` always wins, and a per-query `stableRelationOrder`
154
+ * overrides this default. Default `false`; when off the emitted SQL is
155
+ * byte-identical to before. SQL engines only (PowDB keeps its own defaults).
156
+ */
157
+ stableRelationOrder?: boolean;
158
+ /**
159
+ * When `true`, a `findMany` that paginates (`limit` / `take` / `offset`) but
160
+ * declares no `orderBy` is ordered by the table's primary key ascending
161
+ * (every column of a composite PK, in declaration order), making its pages
162
+ * deterministic. An explicit `orderBy` always wins, PK-less tables are left
163
+ * alone, and `distinct` / `cursor` shapes are skipped.
164
+ *
165
+ * Default `false` in core: an unordered `LIMIT` is non-deterministic, but
166
+ * adding an `ORDER BY` to SQL that existing applications already emit changes
167
+ * both the rows a page returns and the plan the engine picks, so the fix is
168
+ * opt-in until a major. `turbine-orm/prisma-compat` defaults it ON, since
169
+ * matching Prisma's semantics is that layer's contract. When off, the emitted
170
+ * SQL is byte-identical to before.
171
+ */
172
+ implicitPkOrdering?: boolean;
173
+ /**
174
+ * Parent-row ceiling for the `relationLoadStrategy: 'auto'` to-one rule: a
175
+ * to-one relation stays in the single-statement join when the query's `limit`
176
+ * bounds the parent set at or under this many rows, and loads batched when the
177
+ * query is unbounded or bounded above it (a correlated to-one subquery is
178
+ * re-evaluated per parent row regardless of indexing). Defaults to
179
+ * `AUTO_TO_ONE_JOIN_MAX_ROWS` (1000); `0` sends every unbounded-or-limited
180
+ * to-one relation batched. Ignored under an explicit `'join'` / `'batched'`.
181
+ */
182
+ autoToOneJoinMaxRows?: number;
183
+ /**
184
+ * Round-trip time to the database, in milliseconds, used to DERIVE the
185
+ * `relationLoadStrategy: 'auto'` to-one threshold instead of guessing a row
186
+ * count. Prefer this over `autoToOneJoinMaxRows`: the break-even between the
187
+ * single-statement join and the batched follow-up is
188
+ * `roundTripMs / AUTO_JOIN_PENALTY_MS_PER_ROW`, and measurement shows the
189
+ * per-row penalty is a constant of the plan while the break-even moves ~17x
190
+ * between a loopback link and a 2.7ms one. Set it to what `ping` says (a
191
+ * Unix socket is ~0.05, same-region managed Postgres ~0.5-2, cross-region
192
+ * ~30-60). Defaults to `AUTO_ASSUMED_ROUND_TRIP_MS` (0.7ms, same-region),
193
+ * which reproduces the historical 1000-row threshold exactly. Overridden by
194
+ * an explicit `autoToOneJoinMaxRows`; only consulted under `'auto'`.
195
+ */
196
+ autoRoundTripMs?: number;
197
+ /**
198
+ * How nested-relation subqueries encode each row's JSON: `'object'` (default,
199
+ * `json_build_object`) or `'positional'` (`json_build_array`, key-less — see
200
+ * {@link Dialect.buildJsonArray}). Positional is Postgres-only in v1; a
201
+ * `with` clause on any other dialect throws `UnsupportedFeatureError` (E017).
202
+ */
203
+ jsonEncoding?: 'object' | 'positional';
204
+ /**
205
+ * Automatic WHERE filters keyed by table accessor, AND-merged into every
206
+ * query on that table and every relation subquery targeting it (soft-delete /
207
+ * multi-tenancy). Function values are evaluated at query-build time. See
208
+ * {@link GlobalFilters}.
209
+ */
210
+ globalFilters?: GlobalFilters;
211
+ /** @internal Set by TransactionClient — signals that this QI runs inside an active transaction. */
212
+ _txScoped?: boolean;
213
+ /** @internal Callback from TurbineClient for query event emission. */
214
+ _onQuery?: (event: QueryEvent) => void;
215
+ /**
216
+ * @internal Factory that builds the per-table query interface. Defaults to
217
+ * `new QueryInterface` (the SQL path). Non-SQL backends (PowDB) supply a
218
+ * factory returning a structurally-compatible interface that generates their
219
+ * own query language instead of SQL. The SQL dialects never set this, so their
220
+ * `table()` behavior is byte-identical.
221
+ */
222
+ queryInterfaceFactory?: (pool: pg.Pool, table: string, schema: SchemaMetadata, middlewares: MiddlewareFn[], options: QueryInterfaceOptions) => QueryInterface<object>;
223
+ }
@@ -0,0 +1,201 @@
1
+ /**
2
+ * turbine-orm — Where-filter type guards and shape helpers
3
+ *
4
+ * Pure detection / fingerprint utilities used by the query builder's WHERE
5
+ * compiler. Kept out of builder.ts so the class file stays about SQL assembly
6
+ * and execution rather than filter-shape bookkeeping.
7
+ */
8
+ import type { ArrayFilter, ColumnRef, JsonFilter, JsonPathOrderBy, OrderBySpec, OrderDirection, RelationPickOrderBy, TextSearchFilter, VectorFilter, VectorOrderBy, WhereOperator } from './types.js';
9
+ /** Check if a value is a where operator object (has at least one known operator key) */
10
+ export declare function isWhereOperator(value: unknown): value is WhereOperator;
11
+ /**
12
+ * True for a *plain object literal* that reached an equality fallthrough
13
+ * without matching any known filter shape — the misspelled-operator case.
14
+ * Class instances (Buffer for bytea, Decimal wrappers, ...) are legitimate
15
+ * bind values and return false, as do arrays and Dates.
16
+ */
17
+ export declare function isUnmatchedPlainObject(value: unknown): boolean;
18
+ /**
19
+ * Operator keys that accept a {@link ColumnRef} (`{ col: 'otherField' }`)
20
+ * value for column-to-column comparison. `in`/`notIn` and the LIKE operators
21
+ * take values only.
22
+ */
23
+ export declare const COLUMN_REF_OPERATORS: Set<string>;
24
+ /**
25
+ * Check if an operator value is a column reference: a plain object whose ONLY
26
+ * key is `col` with a string value. Anything else (extra keys, non-string
27
+ * `col`) is treated as a plain value so JSON payloads that merely contain a
28
+ * `col` property keep their equality meaning.
29
+ */
30
+ export declare function isColumnRef(value: unknown): value is ColumnRef;
31
+ /**
32
+ * Fingerprint the SHAPE of a where-operator object. Null-valued `equals` /
33
+ * `not` compile to parameterless `IS NULL` / `IS NOT NULL` (different SQL, no
34
+ * param pushed), so null-ness is part of the shape — without it a cache entry
35
+ * warmed by `{ not: 5 }` would serve `{ not: null }` with a desynced param list.
36
+ *
37
+ * Column references ({@link ColumnRef}) compile the referenced column into the
38
+ * SQL TEXT (no param bound), so the referenced field name is part of the shape
39
+ *: `{ equals: { col: 'a' } }` and `{ equals: { col: 'b' } }` must never share
40
+ * a cache entry. The name is JSON-encoded so exotic field names cannot collide
41
+ * with other fingerprint tokens.
42
+ */
43
+ export declare function fingerprintOperatorShape(value: WhereOperator): string;
44
+ /**
45
+ * Guard for the value of an `equals` operator reaching the plain-equality
46
+ * operator path. A plain object literal can only legitimately be an equality
47
+ * value on a json/jsonb column — and those route to the JSONB filter branch
48
+ * BEFORE the operator branch, so any plain object that reaches here is a
49
+ * mistake (e.g. `{ equals: { foo: 1 } }` on a text column). Shared by the
50
+ * SQL-build path and the cache-hit param-collect path so a warmed cache can
51
+ * never skip the check.
52
+ */
53
+ export declare function assertBindableEqualsOperand(value: unknown, column: string): void;
54
+ /**
55
+ * Object keys in sorted order, mirroring the canonical order used by every
56
+ * cache fingerprint. The SQL-build and cache-hit param-collect paths MUST
57
+ * enumerate object keys in this exact order: fingerprints sort keys, so two
58
+ * where clauses with the same fields in different insertion order share one
59
+ * cache entry — if build/collect iterated insertion order, the cached SQL's
60
+ * `$N` placeholders would bind the wrong values (cross-tenant-leak class).
61
+ * Array order (OR/AND members) is positional and is never sorted.
62
+ */
63
+ export declare function sortedKeys(obj: Record<string, unknown>): string[];
64
+ /** {@link sortedKeys}, but yielding `[key, value]` pairs. */
65
+ export declare function sortedEntries<V>(obj: Record<string, V>): [string, V][];
66
+ /** Known atomic-update operator keys — used to detect operator objects vs plain JSON values */
67
+ export declare const UPDATE_OPERATOR_KEYS: Set<string>;
68
+ /** Known JSONB operator keys */
69
+ export declare const JSONB_OPERATOR_KEYS: Set<string>;
70
+ /**
71
+ * JSON range comparison operators → SQL comparison tokens, in the FIXED order
72
+ * the build and collect paths iterate them. These keys are deliberately NOT in
73
+ * {@link JSONB_OPERATOR_KEYS}: `gt`/`gte`/`lt`/`lte` overlap with
74
+ * `WhereOperator`, so a bare `{ gt: 5 }` must keep its column-comparison
75
+ * meaning. They only compile as JSON range ops when the object is already a
76
+ * {@link JsonFilter} (detected via `path` / `equals` / `contains` / `hasKey`),
77
+ * and they always require `path`.
78
+ */
79
+ export declare const JSON_RANGE_OPERATORS: Record<'gt' | 'gte' | 'lt' | 'lte', string>;
80
+ /**
81
+ * Value-invariant shape fingerprint for a {@link JsonFilter}. Range operators
82
+ * are annotated with the comparison value's kind (`#n` numeric / `#s` string)
83
+ * because a numeric comparison compiles to a `::numeric` cast — a different
84
+ * SQL text than the text comparison — so the two must never share a cached
85
+ * SQL entry.
86
+ */
87
+ export declare function fingerprintJsonFilterShape(filter: JsonFilter): string;
88
+ /**
89
+ * JSONB operator keys that are *unique* to {@link JsonFilter} — they cannot
90
+ * appear in any other where-filter shape, so the presence of one of these is
91
+ * an unambiguous signal that the user meant a JSON filter. Used by the
92
+ * strict-validation path so that `{ contains: 'foo' }` (which is also a valid
93
+ * `WhereOperator` for LIKE) is not misclassified. Note `equals` is NOT in this
94
+ * set: on non-JSON columns it is a plain equality operator (`WhereOperator`),
95
+ * so it must fall through instead of throwing.
96
+ */
97
+ export declare const JSONB_UNIQUE_KEYS: Set<string>;
98
+ /** Check if a value is a JSONB filter object */
99
+ export declare function isJsonFilter(value: unknown): value is JsonFilter;
100
+ /**
101
+ * Returns the first JSON-unique key found in `value`, or `null` if none.
102
+ * Used to drive the strict-validation error message.
103
+ */
104
+ export declare function findJsonUniqueKey(value: object): string | null;
105
+ /** Known Array operator keys */
106
+ export declare const ARRAY_OPERATOR_KEYS: Set<string>;
107
+ /**
108
+ * Array operator keys that are *unique* to {@link ArrayFilter}. None of the
109
+ * array operators currently overlap with `WhereOperator` or `JsonFilter`, so
110
+ * this set equals {@link ARRAY_OPERATOR_KEYS}; it is kept as a separate
111
+ * constant so a future overlap (e.g. a `contains` for arrays) is easy to
112
+ * carve out.
113
+ */
114
+ export declare const ARRAY_UNIQUE_KEYS: Set<string>;
115
+ /**
116
+ * Value-invariant shape fingerprint for an {@link ArrayFilter} (the INNER part,
117
+ * without the `arr(...)` wrapper the where fingerprint adds). The boolean
118
+ * `isEmpty` operator changes the SQL shape (`= '{}'` vs `<> '{}'`), so its
119
+ * concrete value is part of the shape; the other operators are value-invariant.
120
+ */
121
+ export declare function fingerprintArrayFilterShape(filter: ArrayFilter): string;
122
+ /** Check if a value is an Array filter object */
123
+ export declare function isArrayFilter(value: unknown): value is ArrayFilter;
124
+ /**
125
+ * Returns the first array-unique key found in `value`, or `null` if none.
126
+ * Used to drive the strict-validation error message.
127
+ */
128
+ export declare function findArrayUniqueKey(value: object): string | null;
129
+ /** Known text search operator keys */
130
+ export declare const TEXT_SEARCH_KEYS: Set<string>;
131
+ /** Check if a value is a TextSearchFilter object */
132
+ export declare function isTextSearchFilter(value: unknown): value is TextSearchFilter;
133
+ /**
134
+ * Validate a text search config name. Only alphanumeric characters and
135
+ * underscores are allowed to prevent SQL injection via the config parameter.
136
+ */
137
+ export declare function validateTextSearchConfig(config: string): boolean;
138
+ /**
139
+ * pgvector distance metric → operator allow-list. This is the ONLY mapping
140
+ * from a user-supplied metric token to a SQL operator; any token not present
141
+ * here is rejected, so a user value can never become an arbitrary operator.
142
+ *
143
+ * - `l2` → `<->` (Euclidean / L2 distance)
144
+ * - `cosine` → `<=>` (cosine distance)
145
+ * - `ip` → `<#>` (negative inner product)
146
+ */
147
+ export declare const VECTOR_METRIC_OPERATORS: Record<string, string>;
148
+ /** Comparison keys allowed on a {@link VectorDistanceFilter}. */
149
+ export declare const VECTOR_DISTANCE_COMPARATORS: Record<string, string>;
150
+ /** Check if a value is a vector distance WHERE filter: `{ distance: { to, metric } }` */
151
+ export declare function isVectorFilter(value: unknown): value is VectorFilter;
152
+ /** Check if an orderBy value is a vector KNN ordering: `{ distance: { to, metric } }` */
153
+ export declare function isVectorOrderBy(value: unknown): value is VectorOrderBy;
154
+ /** Check if an orderBy value is an explicit `{ sort, nulls? }` spec. */
155
+ export declare function isOrderBySpec(value: unknown): value is OrderBySpec;
156
+ /**
157
+ * Check if an orderBy value is a JSON-path ordering: `{ path: [...] }` with an
158
+ * ARRAY path. The array requirement disambiguates from relation orderBy values
159
+ * (whose entries are directions/specs keyed by target column: a target column
160
+ * literally named `path` maps to a string direction, never an array), and the
161
+ * `distance`/`sort` exclusions keep vector and spec shapes out.
162
+ */
163
+ export declare function isJsonPathOrderBy(value: unknown): value is JsonPathOrderBy;
164
+ /**
165
+ * Check if an orderBy value is a pick-row relation ordering:
166
+ * `{ pick: { orderBy, ... }, by, direction?, nulls?, plan? }`. The full shape
167
+ * is required (`pick` must be an object carrying `orderBy`, `by` must be
168
+ * present, and no keys outside `{ pick, by, direction, nulls, plan }`), so a to-one
169
+ * relation whose target has real columns literally named `pick` and `by`
170
+ * (whose values are direction strings or `{ sort, nulls }` specs, never an
171
+ * object with `orderBy`) still falls through to column ordering. `distance`
172
+ * (vector), `sort` (OrderBySpec), and a top-level array `path` (JSON-path
173
+ * ordering) are excluded up front.
174
+ */
175
+ export declare function isRelationPickOrderBy(value: unknown): value is RelationPickOrderBy;
176
+ /**
177
+ * Flatten an orderBy input into an ordered list of `[field, value]` entries.
178
+ *
179
+ * Accepts BOTH the classic single-object form (`{ a: 'asc', b: 'desc' }`,
180
+ * whose insertion order is authoritative) and the Prisma-style array form
181
+ * (`[{ a: 'asc' }, { b: 'desc' }]`, whose array order is authoritative). The
182
+ * array form removes the reliance on JS object key iteration order for
183
+ * multi-key sorts. Each array element may carry one or more keys; they expand
184
+ * left-to-right. `undefined`/non-object elements are skipped.
185
+ *
186
+ * Undefined-VALUED entries are preserved (mirroring `Object.entries`) so each
187
+ * consumer keeps its own `dir !== undefined` filtering exactly as before. This
188
+ * is THE single flattening authority: every ORDER BY compile / collect /
189
+ * fingerprint path routes through it so the array and object forms stay in
190
+ * lockstep across build, param-collect, and cache-key fingerprint.
191
+ */
192
+ export declare function orderByEntries(orderBy: unknown): [string, unknown][];
193
+ /**
194
+ * Normalize an orderBy value into `{ direction, nulls }`. Accepts a plain
195
+ * direction string or an {@link OrderBySpec}. Used by every ORDER BY compile
196
+ * path (findMany, groupBy, relation inner subqueries).
197
+ */
198
+ export declare function normalizeOrderBy(value: OrderDirection | OrderBySpec): {
199
+ dir: 'ASC' | 'DESC';
200
+ nulls?: 'first' | 'last';
201
+ };
@@ -0,0 +1,14 @@
1
+ /**
2
+ * turbine-orm — Query builder barrel
3
+ *
4
+ * Re-exports every public symbol from the query submodules so that
5
+ * `import { … } from './query/index.js'` is a drop-in replacement for the
6
+ * former monolithic `import { … } from './query.js'`.
7
+ */
8
+ export type { AggregateArgs, AggregateResult, ArrayFilter, ColumnRef, ConnectOrCreateOp, CountArgs, CreateArgs, CreateDataInput, CreateManyArgs, DeleteArgs, DeleteManyArgs, FieldResult, FindManyArgs, FindManyStreamArgs, FindUniqueArgs, GlobalFilters, GroupByAggregateSpec, GroupByArgs, GroupByDistinctOn, GroupByResult, HavingClause, JsonFilter, JsonPathAggregateTarget, JsonPathGroupKey, JsonPathOrderBy, NestedCreateOp, NestedUpdateOp, NestedUpdateOpItem, NestedUpsertOpItem, OmitResult, OrderByClause, OrderByObject, OrderDirection, QueryResult, RelationDescriptor, RelationFilter, RelationLoadStrategy, RelationPickBy, RelationPickOrderBy, SelectResult, SkipGlobalFilters, TextSearchFilter, TypedWithClause, UpdateArgs, UpdateDataInput, UpdateInput, UpdateManyArgs, UpdateOperatorInput, UpsertArgs, VectorDistanceFilter, VectorFilter, VectorMetric, VectorOrderBy, VectorOrderByDistance, WhereClause, WhereOperator, WhereValue, WithClause, WithOptions, WithOrderByObject, WithResult, } from './types.js';
9
+ export type { BuiltStatement, BulkInsertStatementInput, ColumnDefinitionInput, ColumnTypeInput, CreateIndexStatementInput, CreateTableStatementInput, Dialect, InsertStatementInput, UpsertStatementInput, } from '../dialect.js';
10
+ export { postgresDialect } from '../dialect.js';
11
+ export type { SqlCacheEntry } from './utils.js';
12
+ export { buildCorrelation, escapeLike, escSingleQuote, fnv1a64Hex, LRUCache, OPERATOR_KEYS, quoteIdent, sqlToPreparedName, } from './utils.js';
13
+ export type { DeferredQuery, MiddlewareFn, QueryEvent, QueryEventListener, QueryInterfaceOptions, ReselectExecutor, } from './builder.js';
14
+ export { AUTO_ASSUMED_ROUND_TRIP_MS, AUTO_JOIN_PENALTY_MS_PER_ROW, AUTO_TO_ONE_JOIN_MAX_ROWS, AUTO_TO_ONE_JOIN_ROWS_MAX, AUTO_TO_ONE_JOIN_ROWS_MIN, QueryInterface, } from './builder.js';
@@ -7,7 +7,7 @@
7
7
  * former monolithic `import { … } from './query.js'`.
8
8
  */
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
- exports.QueryInterface = exports.sqlToPreparedName = exports.quoteIdent = exports.OPERATOR_KEYS = exports.LRUCache = exports.fnv1a64Hex = exports.escSingleQuote = exports.escapeLike = exports.buildCorrelation = exports.postgresDialect = void 0;
10
+ exports.QueryInterface = exports.AUTO_TO_ONE_JOIN_ROWS_MIN = exports.AUTO_TO_ONE_JOIN_ROWS_MAX = exports.AUTO_TO_ONE_JOIN_MAX_ROWS = exports.AUTO_JOIN_PENALTY_MS_PER_ROW = exports.AUTO_ASSUMED_ROUND_TRIP_MS = exports.sqlToPreparedName = exports.quoteIdent = exports.OPERATOR_KEYS = exports.LRUCache = exports.fnv1a64Hex = exports.escSingleQuote = exports.escapeLike = exports.buildCorrelation = exports.postgresDialect = void 0;
11
11
  var dialect_js_1 = require("../dialect.js");
12
12
  Object.defineProperty(exports, "postgresDialect", { enumerable: true, get: function () { return dialect_js_1.postgresDialect; } });
13
13
  var utils_js_1 = require("./utils.js");
@@ -20,4 +20,9 @@ Object.defineProperty(exports, "OPERATOR_KEYS", { enumerable: true, get: functio
20
20
  Object.defineProperty(exports, "quoteIdent", { enumerable: true, get: function () { return utils_js_1.quoteIdent; } });
21
21
  Object.defineProperty(exports, "sqlToPreparedName", { enumerable: true, get: function () { return utils_js_1.sqlToPreparedName; } });
22
22
  var builder_js_1 = require("./builder.js");
23
+ Object.defineProperty(exports, "AUTO_ASSUMED_ROUND_TRIP_MS", { enumerable: true, get: function () { return builder_js_1.AUTO_ASSUMED_ROUND_TRIP_MS; } });
24
+ Object.defineProperty(exports, "AUTO_JOIN_PENALTY_MS_PER_ROW", { enumerable: true, get: function () { return builder_js_1.AUTO_JOIN_PENALTY_MS_PER_ROW; } });
25
+ Object.defineProperty(exports, "AUTO_TO_ONE_JOIN_MAX_ROWS", { enumerable: true, get: function () { return builder_js_1.AUTO_TO_ONE_JOIN_MAX_ROWS; } });
26
+ Object.defineProperty(exports, "AUTO_TO_ONE_JOIN_ROWS_MAX", { enumerable: true, get: function () { return builder_js_1.AUTO_TO_ONE_JOIN_ROWS_MAX; } });
27
+ Object.defineProperty(exports, "AUTO_TO_ONE_JOIN_ROWS_MIN", { enumerable: true, get: function () { return builder_js_1.AUTO_TO_ONE_JOIN_ROWS_MIN; } });
23
28
  Object.defineProperty(exports, "QueryInterface", { enumerable: true, get: function () { return builder_js_1.QueryInterface; } });