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/powdb.d.ts CHANGED
@@ -91,7 +91,21 @@ export declare class PowdbFloatParam {
91
91
  readonly value: number;
92
92
  constructor(value: number);
93
93
  }
94
- /** The four shapes a PowQL result takes over the wire. */
94
+ /**
95
+ * Marker wrapper for a JS object/array bound to a `json` document column. Both
96
+ * transports serialize `value` with `JSON.stringify` and send the text as a
97
+ * `str` param / string literal, exactly how the PowDB docs insert a json
98
+ * document (the engine validates it as JSON text and stores the canonical
99
+ * binary form). Constructed in {@link PowqlInterface.param} when the target
100
+ * column is `json` and the value is a non-null object/array; a JS string
101
+ * written to a json column passes through RAW (same contract as pg jsonb,
102
+ * pass `'"x"'` to store the JSON string `"x"`), and `null` stays `null`.
103
+ */
104
+ export declare class PowdbJsonParam {
105
+ readonly value: unknown;
106
+ constructor(value: unknown);
107
+ }
108
+ /** The four shapes a PowQL result takes over the legacy string wire. */
95
109
  type PowdbResult = {
96
110
  kind: 'rows';
97
111
  columns: string[];
@@ -106,11 +120,73 @@ type PowdbResult = {
106
120
  kind: 'message';
107
121
  message: string;
108
122
  };
123
+ /**
124
+ * Local structural mirror of `@zvndev/powdb-client`'s `WireValue` (the lossless
125
+ * typed cell of the native wire surface). Defined here rather than imported so
126
+ * the optional peer's types never leak into Turbine's published `.d.ts` (a
127
+ * consumer without the peer installed must still `tsc` cleanly, same rule as
128
+ * every other optional-peer type in this module). `empty` = an unset value
129
+ * (distinct, for a json column, from a JSON-null document, which is
130
+ * `{ type: 'json', value: null }`).
131
+ */
132
+ type PowdbWireValue = {
133
+ type: 'empty';
134
+ } | {
135
+ type: 'int';
136
+ value: bigint;
137
+ } | {
138
+ type: 'float';
139
+ value: number;
140
+ } | {
141
+ type: 'bool';
142
+ value: boolean;
143
+ } | {
144
+ type: 'str';
145
+ value: string;
146
+ } | {
147
+ type: 'datetime';
148
+ value: bigint;
149
+ } | {
150
+ type: 'uuid';
151
+ value: Uint8Array;
152
+ } | {
153
+ type: 'bytes';
154
+ value: Uint8Array;
155
+ } | {
156
+ type: 'json';
157
+ value: unknown;
158
+ pj1?: Uint8Array;
159
+ };
160
+ /** The native (lossless typed) result shape, mirroring `RawNativeQueryResult`. */
161
+ type PowdbRawNativeResult = {
162
+ kind: 'rows';
163
+ columns: string[];
164
+ rows: PowdbWireValue[][];
165
+ } | {
166
+ kind: 'scalar';
167
+ value: PowdbWireValue;
168
+ } | {
169
+ kind: 'ok';
170
+ affected: bigint;
171
+ } | {
172
+ kind: 'message';
173
+ message: string;
174
+ };
109
175
  interface PowdbClient {
110
176
  readonly serverVersion: string;
111
177
  query(query: string, params?: PowdbParam[], opts?: {
112
178
  signal?: AbortSignal;
113
179
  }): Promise<PowdbResult>;
180
+ /**
181
+ * Lossless typed wire surface (client ≥ 0.13, server ≥ 0.13). Optional: an
182
+ * older client omits it, so every call site feature-detects
183
+ * `typeof c.queryNativeRaw === 'function'` before using it and falls back to
184
+ * {@link query}. It NEVER retries as a legacy query, replaying an ambiguous
185
+ * mutation is unsafe, so its use is additionally version-gated server-side.
186
+ */
187
+ queryNativeRaw?(query: string, params?: PowdbParam[], opts?: {
188
+ signal?: AbortSignal;
189
+ }): Promise<PowdbRawNativeResult>;
114
190
  close(): Promise<void>;
115
191
  }
116
192
  interface PowdbClientPool {
@@ -159,16 +235,78 @@ export declare function parsePowdbUrl(connectionString: string): PowdbConnOption
159
235
  * prove it is too old).
160
236
  */
161
237
  export declare function assertSupportedPowdbVersion(version: string | undefined): void;
162
- /** PowQL column types Turbine is willing to emit (the four writable scalars). */
163
- export type PowqlType = 'str' | 'int' | 'float' | 'bool';
238
+ /**
239
+ * Feature capabilities of a bound PowDB connection. Resolved once (from the
240
+ * probed server version on the networked transport, or the addon package
241
+ * version on embedded) and carried on the pool so {@link PowqlInterface} can
242
+ * gate PowQL features that only exist on newer engines, an old engine gets a
243
+ * typed {@link UnsupportedFeatureError} (E017) with a version hint instead of a
244
+ * raw PowQL parse error.
245
+ */
246
+ export interface PowdbCapabilities {
247
+ /** Best-known engine version (e.g. `'0.13.0'`), or `null` when unknowable. */
248
+ engineVersion: string | null;
249
+ /** ≥ 0.12: `json` column type, `->` path filters / ordering / grouping. */
250
+ jsonDocs: boolean;
251
+ /** ≥ 0.13: `alter T add index (.col->seg)` expression indexes. */
252
+ docFieldIndexes: boolean;
253
+ /** ≥ 0.10: `schema` / `describe` introspection statements. */
254
+ introspection: boolean;
255
+ /** Networked only: server ≥ 0.13 AND the client exposes `queryNativeRaw`. */
256
+ nativeRaw: boolean;
257
+ }
258
+ /** The feature-gate capability keys (everything except the version/nativeRaw metadata). */
259
+ type PowdbFeatureKey = 'jsonDocs' | 'docFieldIndexes' | 'introspection';
260
+ /**
261
+ * Trusted-caller default: every FEATURE gate on, engine version unknown. Used
262
+ * for a directly-constructed {@link PowdbPool} / {@link PowdbEmbeddedPool} that
263
+ * did not go through {@link turbinePowDB}'s version probe (e.g. an injected
264
+ * pool, or a unit-test pool). `nativeRaw` stays OFF here because it flips the
265
+ * actual wire path and must only be enabled after a real server-version probe,
266
+ * never inferred from a bare construction.
267
+ */
268
+ export declare const ALL_POWDB_CAPABILITIES: PowdbCapabilities;
269
+ /**
270
+ * Derive {@link PowdbCapabilities} from an engine version string. A non-semver /
271
+ * unknown version turns every gate OFF (the E017 hint then tells the caller to
272
+ * upgrade or pass `assumeEngineVersion`). `nativeRaw` requires BOTH the client
273
+ * to expose `queryNativeRaw` (passed in) AND server ≥ 0.13.
274
+ */
275
+ export declare function capabilitiesFromVersion(version: string | undefined | null, opts?: {
276
+ hasNativeRaw?: boolean;
277
+ }): PowdbCapabilities;
278
+ /**
279
+ * Throw a version-hinting {@link UnsupportedFeatureError} (E017) when a gated
280
+ * PowQL feature is used on an engine that does not support it. Keeps old engines
281
+ * getting clean typed errors instead of raw PowQL parse failures.
282
+ */
283
+ export declare function requireCapability(caps: PowdbCapabilities, key: PowdbFeatureKey, feature: string): void;
284
+ /**
285
+ * PowQL column types Turbine emits: the four writable scalars plus PowDB's
286
+ * native `json` document type (added to the map in the 0.12/0.13 parity round,
287
+ * see {@link isJsonColumn}). A `json` column stores a canonical binary document
288
+ * (sorted keys, int/float distinction preserved) that Turbine writes as a JSON
289
+ * string literal and reads back by parsing the canonical JSON text.
290
+ */
291
+ export type PowqlType = 'str' | 'int' | 'float' | 'bool' | 'json';
292
+ /**
293
+ * Does this column map to PowDB's native `json` document type? A Postgres
294
+ * `json`/`jsonb` type (via `dialectType`/`pgType`) is authoritative; otherwise
295
+ * the tsType heuristic (`Record<…>`, `object`, `unknown`, an object/array
296
+ * literal) that the four scalar branches do not claim. Array columns never map
297
+ * to json, a PowDB array only exists INSIDE a json document, so a Postgres
298
+ * array column has no PowDB shape and still throws in {@link powqlColumnType}.
299
+ */
300
+ export declare function isJsonColumn(col: ColumnMetadata): boolean;
164
301
  /**
165
302
  * Map a Turbine column to the PowQL DDL type used in `defineSchema` →
166
303
  * `type T { … }`. Turbine never emits PowDB's `uuid`/`datetime`/`bytes` types,
167
304
  * which cannot hold client-supplied values on the wire (no literal, no cast):
168
305
  * - `Date` → `int` (epoch micros) - `boolean` → `bool`
169
306
  * - integral `number`/`bigint` → `int` - fractional `number` → `float`
307
+ * - JSON / object columns → `json` (native PowDB document type, ≥ 0.12)
170
308
  * - everything else (incl. UUID/PK strings) → `str`
171
- * Array / JSON / bytes columns throw they have no PowDB equivalent.
309
+ * Array (non-json) and bytes columns throw, they have no PowDB equivalent.
172
310
  */
173
311
  export declare function powqlColumnType(col: ColumnMetadata): PowqlType;
174
312
  /**
@@ -198,7 +336,18 @@ export declare const POWQL_KEYWORDS: ReadonlySet<string>;
198
336
  * errors when emitted bare, so quoting is strictly an improvement.
199
337
  */
200
338
  export declare function quotePowqlIdent(name: string): string;
201
- export declare function powqlSchemaDDL(schema: SchemaMetadata): string[];
339
+ /**
340
+ * Options for {@link powqlSchemaDDL}. Additive: with no options the DDL is
341
+ * emitted unconditionally (pure-function callers / tests); pass `capabilities`
342
+ * to gate engine-version-specific features (json columns, and, since the
343
+ * 0.13 parity round, doc-field expression indexes) behind the connection's
344
+ * real capabilities. Doc-field expression index declarations plug into the
345
+ * per-table `indexes` surface consumed here without further signature churn.
346
+ */
347
+ export interface PowqlSchemaDDLOptions {
348
+ capabilities?: PowdbCapabilities;
349
+ }
350
+ export declare function powqlSchemaDDL(schema: SchemaMetadata, opts?: PowqlSchemaDDLOptions): string[];
202
351
  /**
203
352
  * Coerce a single PowDB wire string into the JS value its column type implies.
204
353
  * Every PowDB value arrives as a string; NULL arrives as the bareword `"null"`.
@@ -206,12 +355,26 @@ export declare function powqlSchemaDDL(schema: SchemaMetadata): string[];
206
355
  */
207
356
  export declare function coerceValue(raw: string, col: ColumnMetadata): unknown;
208
357
  /**
209
- * Map one raw PowDB row (snake-cased columns raw wire strings, as produced by
210
- * {@link PowdbPool}) into a typed entity (camelCase fields, coerced values).
211
- * Only the columns present in `raw` are emitted, so partial `select` projections
212
- * round-trip unchanged.
358
+ * Coerce a single cell that arrived over the NATIVE typed wire (decoded from a
359
+ * {@link PowdbWireValue}, so already a JS `bigint`/`number`/`boolean`/`string`/
360
+ * `NativeJson`/`Uint8Array`/`null`, never a bare `"null"` string). Unlike
361
+ * {@link coerceValue} this NEVER collapses the string `"null"` to `null`: an
362
+ * absent value already decoded to `null` (from the `empty` cell), so a genuine
363
+ * str `"null"` stays the string `"null"` (fixes the legacy-wire wart on the
364
+ * native transport). `datetime`-shaped cells (int micros) become `Date`; a
365
+ * bigint on a `number` column follows the int8 safe-integer policy.
366
+ */
367
+ export declare function coerceNativeValue(value: unknown, col: ColumnMetadata): unknown;
368
+ /**
369
+ * Map one raw PowDB row into a typed entity (camelCase fields, coerced values).
370
+ * Only the columns present in `raw` are emitted, so partial `select`
371
+ * projections round-trip unchanged. `native` selects the coercion policy: the
372
+ * default `false` handles the legacy string wire (every cell is a string, via
373
+ * {@link coerceValue}); `true` handles the native typed wire, where non-string
374
+ * cells arrive pre-typed and go through {@link coerceNativeValue} (see F3).
375
+ * Callers on the native transport pass `this.pool.capabilities.nativeRaw`.
213
376
  */
214
- export declare function rowToEntity(raw: Record<string, unknown>, meta: TableMetadata): Record<string, unknown>;
377
+ export declare function rowToEntity(raw: Record<string, unknown>, meta: TableMetadata, native?: boolean): Record<string, unknown>;
215
378
  /**
216
379
  * Translate a PowDB error into a typed Turbine error. Handles BOTH transports,
217
380
  * whose error shapes differ:
@@ -226,6 +389,16 @@ export declare function rowToEntity(raw: Record<string, unknown>, meta: TableMet
226
389
  * fire for both transports), then fall through to the networked `.code` switch.
227
390
  */
228
391
  export declare function wrapPowdbError(err: unknown): Error;
392
+ /**
393
+ * True when `err` is the stale-wire-frame {@link ConnectionError} produced by
394
+ * {@link wrapPowdbError} (its `.cause` is a `protocol_error` PowDBError, or the
395
+ * message carries the invalid-state signature). The opt-in read retry
396
+ * (`retryStaleReads`, evaluated in {@link PowqlInterface}'s exec seam) uses this
397
+ * to decide whether a first-statement READ may be replayed once on a fresh
398
+ * connection; writes are NEVER retried (an ambiguous mutation reply is unsafe
399
+ * to replay, matching the client's own native-path policy).
400
+ */
401
+ export declare function isStaleFramePowdbError(err: unknown): boolean;
229
402
  type QueryArg = string | {
230
403
  name?: string;
231
404
  text: string;
@@ -251,12 +424,31 @@ export interface PowdbPoolOptions {
251
424
  * *after* the transaction has begun.
252
425
  */
253
426
  transactionQueueTimeoutMs?: number;
427
+ /**
428
+ * Feature capabilities of the bound connection. Set by {@link turbinePowDB}
429
+ * from the probed engine version; defaults to {@link ALL_POWDB_CAPABILITIES}
430
+ * (feature gates on, `nativeRaw` off, engine version unknown) for a
431
+ * directly-constructed pool: a "trusted caller".
432
+ */
433
+ capabilities?: PowdbCapabilities;
434
+ /**
435
+ * Opt in to replaying a first-statement READ once, on a fresh connection,
436
+ * when it fails with the stale-wire-frame {@link ConnectionError} (see
437
+ * {@link isStaleFramePowdbError}). Networked only; writes and mid-transaction
438
+ * statements are NEVER retried. Read by {@link PowqlInterface}'s exec seam.
439
+ * Default `false` (typed-error-only).
440
+ */
441
+ retryStaleReads?: boolean;
254
442
  }
255
443
  /**
256
444
  * A {@link PgCompatPool} backed by a `@zvndev/powdb-client` `Pool`. The query
257
- * `text` is **PowQL**, not SQL {@link PowqlInterface} generates it. Rows come
258
- * back as raw strings here; per-column JS coercion happens in `PowqlInterface`
259
- * (it owns the schema metadata).
445
+ * `text` is **PowQL**, not SQL ({@link PowqlInterface} generates it). On the
446
+ * legacy string wire cells come back as strings; when `capabilities.nativeRaw`
447
+ * is set (server 0.13 + a client exposing `queryNativeRaw`) this pool routes
448
+ * through the typed native wire instead, so cells arrive pre-typed (a json int
449
+ * as `bigint`, etc.) and each result is tagged with the wire that served it
450
+ * ({@link PowdbTaggedResult}). Per-column JS coercion still happens in
451
+ * `PowqlInterface` (it owns the schema metadata), keyed on that per-result tag.
260
452
  */
261
453
  export declare class PowdbPool implements PgCompatPool {
262
454
  readonly pool: PowdbClientPool;
@@ -280,7 +472,18 @@ export declare class PowdbPool implements PgCompatPool {
280
472
  * live socket holding the process open until the server's idle timeout.
281
473
  */
282
474
  private readonly checkedOut;
475
+ /** Feature capabilities of the bound server (probed version + native-wire feature-detect). */
476
+ readonly capabilities: PowdbCapabilities;
477
+ /** Opt-in first-statement-read replay on a stale wire frame (read by {@link PowqlInterface}). */
478
+ readonly retryStaleReads: boolean;
283
479
  constructor(pool: PowdbClientPool, toParam?: (v: unknown, i: number) => PowdbParam, options?: PowdbPoolOptions);
480
+ /**
481
+ * Run one statement on `c`, choosing the lossless native typed wire when the
482
+ * server supports it (`capabilities.nativeRaw`) AND this client exposes
483
+ * `queryNativeRaw` (a defensive per-call feature-detect, so a heterogeneous
484
+ * injected pool cannot crash). Otherwise the legacy string wire, unchanged.
485
+ */
486
+ private runOnClient;
284
487
  query(text: QueryArg, values?: unknown[]): Promise<any>;
285
488
  /**
286
489
  * Typed guard mirroring {@link PowdbEmbeddedPool}: after `end()` the driver
@@ -358,6 +561,14 @@ export declare class PowdbEmbeddedPool implements PgCompatPool {
358
561
  private readonly txGate;
359
562
  /** Hold taken by a `begin` issued via `query()` directly (no checked-out client). */
360
563
  private readonly poolHoldRef;
564
+ /**
565
+ * Feature capabilities of the embedded engine (resolved from the addon
566
+ * package version). `nativeRaw` is always false: the embedded addon exposes
567
+ * no native typed-wire surface (its rows are `string[][]`, the legacy wire).
568
+ */
569
+ readonly capabilities: PowdbCapabilities;
570
+ /** Carried for surface uniformity with {@link PowdbPool}; inert on embedded (no protocol_error frames). */
571
+ readonly retryStaleReads: boolean;
361
572
  constructor(db: EmbeddedDatabase, options?: PowdbPoolOptions);
362
573
  /** Materialize `$N` params and hand the PowQL to the in-process engine. */
363
574
  private exec;
@@ -372,6 +583,7 @@ export declare class PowdbEmbeddedPool implements PgCompatPool {
372
583
  connect(): Promise<PgCompatPoolClient>;
373
584
  end(): Promise<void>;
374
585
  }
586
+ export { introspectPowdbDatabase, type PowdbExec, type PowdbIntrospectOptions, } from './powdb-introspect.js';
375
587
  export { PowqlInterface } from './powql.js';
376
588
  /** Options for {@link turbinePowDB}. */
377
589
  export interface TurbinePowdbOptions extends Pick<TurbineConfig, 'logging' | 'defaultLimit' | 'warnOnUnlimited'> {
@@ -385,8 +597,32 @@ export interface TurbinePowdbOptions extends Pick<TurbineConfig, 'logging' | 'de
385
597
  * transactions queue and run one at a time; only a re-entrant
386
598
  * `db.$transaction` (opened inside an active transaction callback) throws
387
599
  * E017 — queueing that shape would deadlock.
600
+ *
601
+ * Ignored when you inject an already-constructed {@link PowdbPool} (it carries
602
+ * its own {@link PowdbPoolOptions}); set it on that pool's constructor instead.
388
603
  */
389
604
  transactionQueueTimeoutMs?: number;
605
+ /**
606
+ * Opt in to replaying a first-statement READ once (on a fresh connection)
607
+ * when it fails with the stale-wire-frame {@link ConnectionError} that a
608
+ * request can hit after a long idle gap. Networked only; WRITES and any
609
+ * statement inside a transaction are NEVER retried (an ambiguous mutation
610
+ * reply is unsafe to replay). Default `false`: the error is surfaced typed
611
+ * so the caller can decide. See the retry recipe in the docs.
612
+ *
613
+ * Ignored when you inject an already-constructed {@link PowdbPool} (it carries
614
+ * its own {@link PowdbPoolOptions}); set it on that pool's constructor instead.
615
+ */
616
+ retryStaleReads?: boolean;
617
+ /**
618
+ * Override the detected engine version used for capability gating. For exotic
619
+ * deployments and injected pools whose version cannot be probed (a non-semver
620
+ * server string, or an addon whose package.json cannot be resolved): pass
621
+ * e.g. `'0.13.0'` to unlock the features that version supports. Without it, an
622
+ * undetectable version turns every version-gated feature OFF (with a hinting
623
+ * E017).
624
+ */
625
+ assumeEngineVersion?: string;
390
626
  /**
391
627
  * Driver-module injection for the networked target forms (URL / host+port):
392
628
  * bypasses the dynamic `import('@zvndev/powdb-client')` and uses this object