turbine-orm 0.32.2 → 0.34.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 (43) hide show
  1. package/README.md +2 -2
  2. package/dist/cjs/dialect.js +1 -0
  3. package/dist/cjs/index-advisor.js +0 -0
  4. package/dist/cjs/index.js +2 -1
  5. package/dist/cjs/mssql.js +3 -0
  6. package/dist/cjs/mysql.js +3 -0
  7. package/dist/cjs/optional-peer-import.cjs +28 -0
  8. package/dist/cjs/powdb-introspect.js +222 -0
  9. package/dist/cjs/powdb.js +446 -55
  10. package/dist/cjs/powql.js +566 -111
  11. package/dist/cjs/query/builder.js +136 -53
  12. package/dist/cjs/query/filters.js +4 -4
  13. package/dist/cjs/schema-builder.js +16 -0
  14. package/dist/cjs/schema-metadata.js +81 -10
  15. package/dist/cjs/sqlite.js +2 -0
  16. package/dist/dialect.d.ts +7 -0
  17. package/dist/dialect.js +1 -0
  18. package/dist/index-advisor.d.ts +15 -1
  19. package/dist/index-advisor.js +0 -0
  20. package/dist/index.d.ts +1 -1
  21. package/dist/index.js +1 -1
  22. package/dist/mssql.js +3 -0
  23. package/dist/mysql.js +3 -0
  24. package/dist/optional-peer-import.cjs +28 -0
  25. package/dist/optional-peer-import.d.cts +19 -0
  26. package/dist/powdb-introspect.d.ts +84 -0
  27. package/dist/powdb-introspect.js +219 -0
  28. package/dist/powdb.d.ts +249 -13
  29. package/dist/powdb.js +438 -54
  30. package/dist/powql.d.ts +113 -6
  31. package/dist/powql.js +568 -113
  32. package/dist/query/builder.d.ts +11 -0
  33. package/dist/query/builder.js +136 -53
  34. package/dist/query/filters.d.ts +3 -3
  35. package/dist/query/filters.js +4 -4
  36. package/dist/query/types.d.ts +50 -6
  37. package/dist/schema-builder.d.ts +46 -1
  38. package/dist/schema-builder.js +15 -0
  39. package/dist/schema-metadata.d.ts +13 -7
  40. package/dist/schema-metadata.js +82 -11
  41. package/dist/schema.d.ts +25 -0
  42. package/dist/sqlite.js +2 -0
  43. package/package.json +3 -3
package/dist/powql.d.ts CHANGED
@@ -53,7 +53,6 @@ export declare class PowqlInterface<T extends object = Record<string, unknown>>
53
53
  private readonly defaultLimit?;
54
54
  private readonly warnOnUnlimited;
55
55
  private readonly onQuery?;
56
- private currentAction;
57
56
  private warnedUnlimited;
58
57
  constructor(pool: PowdbPool, table: string, schema: SchemaMetadata, middlewares?: MiddlewareFn[], options?: QueryInterfaceOptions);
59
58
  /** Resolve a camelCase field name (or raw snake) to its column metadata. */
@@ -81,6 +80,13 @@ export declare class PowqlInterface<T extends object = Record<string, unknown>>
81
80
  */
82
81
  private writeRef;
83
82
  private isFloatCol;
83
+ /**
84
+ * The bound pool's {@link PowdbCapabilities}. Falls back to the trusted-caller
85
+ * default (all feature gates on, `nativeRaw` off) when a directly-constructed
86
+ * pool did not carry them, matching {@link PowdbPool}'s own constructor
87
+ * default so a hand-built test pool never crashes the version gates.
88
+ */
89
+ private get capabilities();
84
90
  /** A predicate that is always false — the empty-`in` / contradiction sentinel. */
85
91
  private alwaysFalse;
86
92
  /**
@@ -90,6 +96,44 @@ export declare class PowqlInterface<T extends object = Record<string, unknown>>
90
96
  private buildWhere;
91
97
  /** Build a single `field: value | operator` condition. */
92
98
  private buildFieldCondition;
99
+ /**
100
+ * PowQL JSON path expression `.col->$a->$b…`, binding EVERY path segment as a
101
+ * positional param (a string segment as a `str` token, an integer index as an
102
+ * `int` token). `->` binds tighter than every operator, so no parens are
103
+ * needed around the path in a comparison. Segments are bound (never inlined)
104
+ * to keep {@link materializePowql}'s `$N`-scan invariant intact: a segment
105
+ * that literally contained `$1` would otherwise be rewritten. Shared by the
106
+ * F1 where-filter path and the F2 orderBy / groupBy path emitters.
107
+ *
108
+ * A digit-only STRING segment (`'0'`) binds as an `int` array index, matching
109
+ * the SQL engines: `JsonFilter.path` is typed `string[]`, so an array index
110
+ * can only be expressed as a digit string, and the SQL builder converts it the
111
+ * same way (`/^\d+$/ → [n]`, query/builder.ts). Without this, PowDB's typed
112
+ * `->` treats `'0'` as a string KEY and silently matches nothing on an array
113
+ * (a wrong result, not an error). Same object-key-`'0'` caveat SQL accepts: a
114
+ * json object whose key is literally `"0"` is addressed as an array index.
115
+ */
116
+ private jsonPathExpr;
117
+ /**
118
+ * Compile a {@link JsonFilter} on a json document column into a PowQL filter
119
+ * (≥ 0.12). Operators PowQL cannot express EXACTLY throw a per-operator E017
120
+ * (never a wrong result): containment (`contains`, and `equals` without a
121
+ * `path`) has no PowQL operator. The mapped shapes:
122
+ * - `{ path, equals: v }` → `P = $n` (typed: string→str, bool→bool,
123
+ * integral number→int, fractional→float; NOT stringified)
124
+ * - `{ path, equals: null }` → `P is null` (matches JSON null AND a missing
125
+ * key, a deliberate divergence from the PG driver, documented on
126
+ * {@link JsonFilter})
127
+ * - `{ path, gt|gte|lt|lte: v }` → `P > $n` … (range ops require `path`; the
128
+ * engine coerces int/float numerically)
129
+ * - `{ hasKey: k }` → `json_type(.col->$n) is not null` (top-level key test,
130
+ * ignoring `path`, mirroring PG `col ? key`; includes keys holding JSON
131
+ * null)
132
+ * A bare `{ path }` with no operators compiles to zero clauses (byte-parity
133
+ * with SQL), so a mutation whose only `where` is a bare `{ path }` is refused
134
+ * by the empty-where guard.
135
+ */
136
+ private buildJsonPathCondition;
93
137
  /** Bind a value, lowercasing for case-insensitive comparisons. */
94
138
  private bind;
95
139
  /** Bind a LIKE pattern (already escaped), lowercasing for insensitive mode. */
@@ -120,17 +164,60 @@ export declare class PowqlInterface<T extends object = Record<string, unknown>>
120
164
  private projectedColumns;
121
165
  /** `{ .c1, .c2, … }` projection clause. */
122
166
  private projection;
123
- /** `order .c1 asc, .c2 desc` clause (empty string when no orderBy). */
167
+ /**
168
+ * `order .c1 asc, .c2 desc` clause (empty string when no orderBy). Supports,
169
+ * besides a plain direction:
170
+ * - {@link JsonPathOrderBy} on a json column (≥ 0.12): `{ data: { path: […],
171
+ * type?, direction? } }` → `order .data->$n asc` (or
172
+ * `cast(.data->$n, "float")` for `type: 'numeric'`);
173
+ * - {@link OrderBySpec} `{ sort, nulls }`: `nulls: 'last'` is accepted as a
174
+ * no-op (PowDB is always nulls-last), `nulls: 'first'` throws E017.
175
+ *
176
+ * PowDB orders missing / JSON-null keys LAST in BOTH directions (an engine
177
+ * contract): for identical cross-engine results pass `nulls: 'last'`
178
+ * explicitly on Postgres, which defaults nulls-first for `desc`.
179
+ */
124
180
  private buildOrder;
125
- /** Run PowQL with optional timeout, emitting a query event either way. */
181
+ /** Compile one {@link JsonPathOrderBy} entry to `order .col->$n asc` (+ optional numeric cast). */
182
+ private buildJsonPathOrder;
183
+ /**
184
+ * Run PowQL with optional timeout, emitting a query event either way. The
185
+ * `action` is passed PER CALL (never read from shared instance state) so the
186
+ * retry-eligibility and the emitted event action stay correct even when a
187
+ * concurrent operation runs on the same cached interface: a WRITE statement
188
+ * carries a write action and can therefore never be mistaken for a replayable
189
+ * read. Read statements pass a read-shaped action from {@link POWQL_READ_ACTIONS}.
190
+ */
126
191
  private exec;
192
+ /**
193
+ * Execute one statement, with the opt-in single stale-frame READ replay. When
194
+ * `retryStaleReads` is on and a first-statement READ fails with the stale-wire
195
+ * {@link isStaleFramePowdbError} ConnectionError (a socket idle-gap "received
196
+ * unexpected frame" that the client cannot recover), the statement is retried
197
+ * exactly once on a fresh pooled connection (the broken one was destroyed).
198
+ * The replay is refused for writes (an ambiguous mutation reply is unsafe to
199
+ * replay) and inside a transaction (a mid-tx statement cannot move connection),
200
+ * so only the read-shaped actions in {@link POWQL_READ_ACTIONS}, outside a
201
+ * `_txScoped` interface, are eligible. `action` is a per-call argument (never
202
+ * `this`-state), so a concurrent op flipping instance fields cannot turn a
203
+ * write into a retryable read.
204
+ */
205
+ private execOnce;
206
+ /** Is `err` a replayable stale-frame failure for THIS (per-call) read-shaped, non-tx action? */
207
+ private shouldRetryStaleRead;
127
208
  private emit;
128
209
  /** Run a method body through the middleware chain (mirrors QueryInterface). */
129
210
  private withMiddleware;
130
- /** Map raw rows to typed entities. */
211
+ /** Map raw rows to typed entities. `native` is the wire that ACTUALLY served
212
+ * this result (threaded from {@link execOnce}, not the pool-level capability),
213
+ * so cells that arrived pre-typed over `queryNativeRaw` (F3) skip the legacy
214
+ * string coercion (a genuine str `"null"` stays `"null"` instead of collapsing
215
+ * to null) while a per-call legacy fallback on a native-capable pool still
216
+ * coerces its string cells correctly. Defaults to the pool capability for the
217
+ * rare caller with no per-result flag (hand-built test pools). */
131
218
  private shape;
132
219
  findMany(args?: FindManyArgs<T>): Promise<T[]>;
133
- /** Build + run the flat findMany select; returns raw rows. */
220
+ /** Build + run the flat findMany select; returns raw rows + the serving wire. */
134
221
  private runFind;
135
222
  findUnique(args: FindUniqueArgs<T>): Promise<T | null>;
136
223
  findFirst(args?: FindManyArgs<T>): Promise<T | null>;
@@ -192,8 +279,28 @@ export declare class PowqlInterface<T extends object = Record<string, unknown>>
192
279
  count(args?: CountArgs<T>): Promise<number>;
193
280
  aggregate(args: AggregateArgs<T>): Promise<AggregateResult<T>>;
194
281
  groupBy(args: GroupByArgs<T>): Promise<Record<string, unknown>[]>;
195
- /** `having <expr>` over group aggregates (count/sum/avg/min/max). */
282
+ /** Validate a JSON-path target (group key / aggregate target): non-empty array of keys/indexes. */
283
+ private assertJsonPath;
284
+ /**
285
+ * `having <expr>` over group aggregates. `_count` compares `count(*)` (parity
286
+ * with the projection); a per-field aggregate re-emits its inner expression
287
+ * (from `aggInner` when the field is a requested aggregate, so a JSON-path
288
+ * aggregate reuses its bound placeholders, else `.field` for a plain column).
289
+ */
196
290
  private buildHaving;
291
+ /**
292
+ * Compile a groupBy `orderBy` into a PowQL `order` body over the group RESULT
293
+ * columns (by-fields, JSON group-key aliases, and requested aggregates). PowQL
294
+ * cannot re-emit an aggregate EXPRESSION in `order` (engine error), but CAN
295
+ * order by a projection alias on a grouped query (probed), so each key maps to
296
+ * its projected alias (`.agg_N` / `.gk_N` / `.col`). Semantics and error
297
+ * surface mirror the SQL `buildGroupByOrderBy` (0.32.2 R3-1): an aggregate not
298
+ * requested in this call, or an unknown by-key, throws E003 listing the valid
299
+ * keys. `nulls: 'first'` stays E017 (PowDB has no NULLS placement grammar).
300
+ */
301
+ private buildGroupOrder;
302
+ /** Resolve a groupBy order direction, refusing `nulls: 'first'` (E017); `nulls: 'last'` is a no-op. */
303
+ private groupOrderDir;
197
304
  findManyStream(): AsyncGenerator<T>;
198
305
  /** Reselect a single row by its single-column primary key value. */
199
306
  private reselectByPk;