turbine-orm 0.19.2 → 0.21.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 (46) hide show
  1. package/README.md +82 -18
  2. package/dist/adapters/cockroachdb.js +4 -9
  3. package/dist/cjs/adapters/cockroachdb.js +4 -9
  4. package/dist/cjs/cli/index.js +6 -3
  5. package/dist/cjs/cli/observe-ui.js +12 -2
  6. package/dist/cjs/cli/observe.js +6 -7
  7. package/dist/cjs/cli/studio.js +6 -7
  8. package/dist/cjs/client.js +33 -20
  9. package/dist/cjs/dialect.js +116 -0
  10. package/dist/cjs/errors.js +19 -1
  11. package/dist/cjs/generate.js +4 -0
  12. package/dist/cjs/index.js +3 -2
  13. package/dist/cjs/introspect.js +20 -0
  14. package/dist/cjs/mssql.js +1338 -0
  15. package/dist/cjs/mysql.js +1052 -0
  16. package/dist/cjs/query/builder.js +293 -73
  17. package/dist/cjs/sqlite.js +849 -0
  18. package/dist/cjs/typed-sql.js +9 -7
  19. package/dist/cli/index.js +6 -3
  20. package/dist/cli/observe-ui.d.ts +1 -1
  21. package/dist/cli/observe-ui.js +12 -2
  22. package/dist/cli/observe.js +7 -8
  23. package/dist/cli/studio.js +7 -8
  24. package/dist/client.d.ts +23 -1
  25. package/dist/client.js +34 -21
  26. package/dist/dialect.d.ts +258 -1
  27. package/dist/dialect.js +83 -0
  28. package/dist/errors.d.ts +12 -0
  29. package/dist/errors.js +17 -0
  30. package/dist/generate.js +4 -0
  31. package/dist/index.d.ts +3 -3
  32. package/dist/index.js +1 -1
  33. package/dist/introspect.d.ts +18 -0
  34. package/dist/introspect.js +19 -0
  35. package/dist/mssql.d.ts +233 -0
  36. package/dist/mssql.js +1298 -0
  37. package/dist/mysql.d.ts +174 -0
  38. package/dist/mysql.js +1012 -0
  39. package/dist/query/builder.d.ts +97 -0
  40. package/dist/query/builder.js +294 -74
  41. package/dist/query/index.d.ts +1 -1
  42. package/dist/sqlite.d.ts +144 -0
  43. package/dist/sqlite.js +842 -0
  44. package/dist/typed-sql.d.ts +7 -5
  45. package/dist/typed-sql.js +9 -7
  46. package/package.json +30 -1
@@ -14,6 +14,12 @@ import type pg from 'pg';
14
14
  import type { Dialect } from '../dialect.js';
15
15
  import type { SchemaMetadata } from '../schema.js';
16
16
  import type { AggregateArgs, AggregateResult, CountArgs, CreateArgs, CreateManyArgs, DeleteArgs, DeleteManyArgs, FindManyArgs, FindManyStreamArgs, FindUniqueArgs, GroupByArgs, QueryResult, TypedWithClause, UpdateArgs, UpdateManyArgs, UpsertArgs, WithClause } from './types.js';
17
+ /**
18
+ * Runs a SQL statement and resolves its raw result. Passed to a
19
+ * {@link DeferredQuery.reselect} plan so it can run the write and the follow-up
20
+ * SELECT through the same timeout/instrumentation path as the primary query.
21
+ */
22
+ export type ReselectExecutor = (sql: string, params: unknown[], preparedName?: string) => Promise<pg.QueryResult>;
17
23
  export interface DeferredQuery<T> {
18
24
  /** SQL text with $1, $2 placeholders */
19
25
  sql: string;
@@ -25,6 +31,15 @@ export interface DeferredQuery<T> {
25
31
  tag: string;
26
32
  /** Prepared statement name (t_<16hex>). Set when SQL cache is enabled. */
27
33
  preparedName?: string;
34
+ /**
35
+ * Execution plan for dialects whose {@link Dialect.resultStrategy} is
36
+ * `'reselect'` (no RETURNING — e.g. MySQL). Owns the statement ordering: it
37
+ * runs the write and the follow-up row-fetching SELECT(s) via `exec`, and
38
+ * resolves the result whose rows {@link DeferredQuery.transform} consumes.
39
+ * Absent for `'returning'`/`'output'` dialects (the statement returns its own
40
+ * rows), so the PostgreSQL path never allocates or consults it.
41
+ */
42
+ reselect?: (exec: ReselectExecutor) => Promise<pg.QueryResult>;
28
43
  }
29
44
  /** Middleware function type — imported from client to avoid circular deps */
30
45
  export type MiddlewareFn = (params: {
@@ -133,6 +148,54 @@ export declare class QueryInterface<T extends object, R extends object = {}> {
133
148
  private q;
134
149
  /** Return the active dialect's placeholder for a 1-indexed parameter position. */
135
150
  private p;
151
+ /**
152
+ * Cast an aggregate expression to an integer/float result type through the
153
+ * active dialect. PostgreSQL keeps the historical postfix cast (`expr::int` /
154
+ * `expr::float`); SQLite (no `::` operator) maps to `CAST(expr AS INTEGER/REAL)`.
155
+ * Falls back to the Postgres postfix cast for dialects without the hook.
156
+ */
157
+ private castAgg;
158
+ /**
159
+ * Build the trailing pagination clause for an OUTER SELECT. PostgreSQL/MySQL/
160
+ * SQLite use ` LIMIT <ph>` and/or ` OFFSET <ph>`. SQL Server has no `LIMIT`, so
161
+ * its dialect implements {@link Dialect.buildLimitOffset} to emit
162
+ * `[ORDER BY (SELECT NULL)] OFFSET <off> ROWS [FETCH NEXT <lim> ROWS ONLY]`.
163
+ * Param-push order (limit before offset) is owned by the caller and unchanged —
164
+ * this only varies the SQL text, so PG output stays byte-identical.
165
+ */
166
+ private buildPagination;
167
+ /**
168
+ * The single-row limit appended to findUnique / findFirst-style lookups. ` LIMIT 1`
169
+ * for PG/MySQL/SQLite; SQL Server routes through {@link Dialect.buildLimitOffset}
170
+ * (literal `1`, no params) → ` ORDER BY (SELECT NULL) OFFSET 0 ROWS FETCH NEXT 1
171
+ * ROWS ONLY`. No params are pushed, so the collect path is unaffected.
172
+ */
173
+ private limitOneClause;
174
+ /**
175
+ * Validate a LIMIT/OFFSET value as a non-negative integer and return it as an
176
+ * inline SQL literal. Used only on `dialect.inlineLimitOffset` engines (MySQL).
177
+ * The input is always a Turbine-controlled pagination value, never a raw user
178
+ * string — and this guard guarantees the output is `String` of a validated
179
+ * integer, so inlining cannot inject SQL.
180
+ */
181
+ private limitOffsetLiteral;
182
+ /**
183
+ * Resolve a LIMIT/OFFSET value to either an inline literal (no param pushed, on
184
+ * `dialect.inlineLimitOffset` engines) or a bound placeholder (the value is
185
+ * pushed to `params`). Build and collect paths both gate on the same flag so
186
+ * the param order stays mirrored; PG/SQLite/SQL Server keep parameterizing and
187
+ * stay byte-identical.
188
+ */
189
+ private paginationRef;
190
+ /**
191
+ * Build an `IN` / `NOT IN` predicate through the active dialect. PostgreSQL
192
+ * keeps the array-param form (`expr = ANY($n)` / `expr != ALL($n)`); other
193
+ * engines (SQLite) use a length-independent single-placeholder form. Paired
194
+ * with {@link inParam}, which supplies the single bound value.
195
+ */
196
+ private inClause;
197
+ /** The single bound parameter for an `IN` list (PG: the array; SQLite: a JSON string). */
198
+ private inParam;
136
199
  /**
137
200
  * Return cache hit/miss statistics for this QueryInterface instance.
138
201
  * Useful for monitoring and benchmarking.
@@ -164,6 +227,33 @@ export declare class QueryInterface<T extends object, R extends object = {}> {
164
227
  * pg driver errors are translated to typed Turbine errors via wrapPgError.
165
228
  */
166
229
  private queryWithTimeout;
230
+ /**
231
+ * Execute a write `DeferredQuery` (create/update/delete/upsert) according to
232
+ * the active dialect's {@link Dialect.resultStrategy}, then apply its
233
+ * transform.
234
+ *
235
+ * - `'returning'` / `'output'`: the statement returns its own affected rows
236
+ * (`RETURNING *` / `OUTPUT INSERTED.*`). Byte-identical to the historical
237
+ * single `queryWithTimeout` + `transform(result)` path — the PostgreSQL
238
+ * route is unchanged.
239
+ * - `'reselect'`: the engine cannot return rows from a write, so the build
240
+ * method attached a {@link DeferredQuery.reselect} plan that runs the
241
+ * write and a follow-up SELECT; the SELECT's rows feed the transform.
242
+ */
243
+ private executeMutation;
244
+ /**
245
+ * Build a `SELECT * ... WHERE <predicate>` that re-fetches the row(s) matched
246
+ * by a write's `where` clause. Used by the `'reselect'` result strategy to
247
+ * return rows from non-RETURNING engines. Reuses the same parameterized WHERE
248
+ * builder as reads, so no user value is interpolated.
249
+ */
250
+ private buildReselectByWhere;
251
+ /**
252
+ * Best-effort extraction of an auto-generated primary key from a write
253
+ * result for `'reselect'` engines (e.g. mysql2's `insertId`). Returns
254
+ * `undefined` when the driver exposes no such field.
255
+ */
256
+ private mutationInsertId;
167
257
  /**
168
258
  * Execute a query through the middleware chain.
169
259
  * If no middlewares are registered, executes directly.
@@ -232,6 +322,13 @@ export declare class QueryInterface<T extends object, R extends object = {}> {
232
322
  buildFindUniqueOrThrow<W extends TypedWithClause<R> = {}>(args: FindUniqueArgs<T, R, W, Record<string, boolean> | undefined, Record<string, boolean> | undefined>): DeferredQuery<T>;
233
323
  create(args: CreateArgs<T, R>): Promise<T>;
234
324
  buildCreate(args: CreateArgs<T>): DeferredQuery<T>;
325
+ /**
326
+ * Build the `'reselect'` plan for {@link buildCreate}: run the INSERT, then
327
+ * `SELECT * WHERE pk = ?`. Returns `undefined` (skipped) unless the active
328
+ * dialect's result strategy is `'reselect'`, so the PostgreSQL/RETURNING path
329
+ * pays nothing. Not yet wired to a real non-RETURNING engine.
330
+ */
331
+ private makeCreateReselect;
235
332
  createMany(args: CreateManyArgs<T>): Promise<T[]>;
236
333
  buildCreateMany(args: CreateManyArgs<T>): DeferredQuery<T[]>;
237
334
  update(args: UpdateArgs<T, R>): Promise<T>;