turbine-orm 0.28.3 → 0.29.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.
- package/dist/cjs/client.js +36 -2
- package/dist/cjs/powdb.js +17 -1
- package/dist/client.d.ts +38 -4
- package/dist/client.js +36 -2
- package/dist/powdb.d.ts +7 -1
- package/dist/powdb.js +17 -1
- package/package.json +1 -1
package/dist/cjs/client.js
CHANGED
|
@@ -911,14 +911,48 @@ class TurbineClient {
|
|
|
911
911
|
* Execute a batch of {@link DeferredQuery} objects atomically inside one
|
|
912
912
|
* transaction. Backs the `$transaction([...])` array overload. Reuses the raw
|
|
913
913
|
* {@link transaction} machinery (BEGIN/COMMIT/ROLLBACK + connection release);
|
|
914
|
-
*
|
|
915
|
-
*
|
|
914
|
+
* each result is passed through its query's `transform`.
|
|
915
|
+
*
|
|
916
|
+
* Execution strategy on the single transaction connection:
|
|
917
|
+
* - **Sequential (default).** Await each statement's reply before sending
|
|
918
|
+
* the next. Safe on every driver; on a networked driver a batch of N
|
|
919
|
+
* costs N round trips.
|
|
920
|
+
* - **Pipelined.** When the checked-out connection advertises
|
|
921
|
+
* {@link PgCompatPoolClient.supportsPipelining} (its `query()` accepts
|
|
922
|
+
* concurrent calls and completes them in FIFO submission order), all
|
|
923
|
+
* statements are dispatched in one write burst and the replies are
|
|
924
|
+
* collected in order — ~1 round trip plus server time. Only taken when
|
|
925
|
+
* the dialect's writes surface rows directly (`resultStrategy` !==
|
|
926
|
+
* 'reselect'): a reselect plan is itself a sequential write+read pair.
|
|
927
|
+
*
|
|
928
|
+
* The two paths share one failure contract: the first (lowest-index) failed
|
|
929
|
+
* statement's error is thrown (wrapped via {@link wrapPgError}) and the
|
|
930
|
+
* surrounding transaction rolls back, so no statement's effect survives. The
|
|
931
|
+
* pipelined path drains every in-flight reply (`Promise.allSettled`) before
|
|
932
|
+
* rethrowing, which keeps the connection's request/reply pairing intact and
|
|
933
|
+
* means ROLLBACK is only issued once no statement is still in flight.
|
|
916
934
|
*/
|
|
917
935
|
async transactionBatch(queries) {
|
|
918
936
|
if (queries.length === 0) {
|
|
919
937
|
return [];
|
|
920
938
|
}
|
|
921
939
|
return this.transaction(async (client) => {
|
|
940
|
+
const pipelined = client.supportsPipelining === true &&
|
|
941
|
+
this.dialect.resultStrategy !== 'reselect';
|
|
942
|
+
if (pipelined) {
|
|
943
|
+
// Dispatch every statement before awaiting any reply. The driver's
|
|
944
|
+
// FIFO guarantee makes settled[i] the reply to queries[i].
|
|
945
|
+
const settled = await Promise.allSettled(queries.map((dq) => client.query(dq.sql, dq.params)));
|
|
946
|
+
const results = [];
|
|
947
|
+
for (let i = 0; i < settled.length; i++) {
|
|
948
|
+
const outcome = settled[i];
|
|
949
|
+
if (outcome.status === 'rejected') {
|
|
950
|
+
throw (0, errors_js_1.wrapPgError)(outcome.reason);
|
|
951
|
+
}
|
|
952
|
+
results.push(queries[i].transform(outcome.value));
|
|
953
|
+
}
|
|
954
|
+
return results;
|
|
955
|
+
}
|
|
922
956
|
const results = [];
|
|
923
957
|
for (const dq of queries) {
|
|
924
958
|
let raw;
|
package/dist/cjs/powdb.js
CHANGED
|
@@ -23,8 +23,14 @@
|
|
|
23
23
|
* `string` PKs hold UUID strings.
|
|
24
24
|
* - **No JSON aggregation / link navigation** — single-query nested `with` is
|
|
25
25
|
* impossible → it degrades to batched N+1 loaders (Phase B).
|
|
26
|
-
* - **Single global write lock; no savepoints/isolation
|
|
26
|
+
* - **Single global write lock; no savepoints/isolation** — nested
|
|
27
27
|
* transactions / isolation / vector / LISTEN-NOTIFY / RLS throw.
|
|
28
|
+
* - **The wire protocol pipelines** — `@zvndev/powdb-client` writes each
|
|
29
|
+
* request frame immediately and matches replies FIFO, so multiple queries
|
|
30
|
+
* may be in flight on one connection. {@link PowdbPool}'s checked-out
|
|
31
|
+
* clients advertise `supportsPipelining`, which lets the batch
|
|
32
|
+
* `$transaction([...])` overload dispatch all statements in one write
|
|
33
|
+
* burst (~1 round trip) instead of one round trip per statement.
|
|
28
34
|
*
|
|
29
35
|
* `@zvndev/powdb-client` is an **optional peer dependency** loaded by dynamic
|
|
30
36
|
* import; `npm i turbine-orm` still pulls only `pg`.
|
|
@@ -511,6 +517,16 @@ class PowdbPool {
|
|
|
511
517
|
const client = await this.pool.acquire();
|
|
512
518
|
let broken = false;
|
|
513
519
|
return {
|
|
520
|
+
// The networked client's query() supports concurrent in-flight calls on
|
|
521
|
+
// one connection: every request frame is written to the socket
|
|
522
|
+
// immediately and replies are matched to callers in FIFO order. That
|
|
523
|
+
// lets the batch `$transaction([...])` path dispatch all statements in
|
|
524
|
+
// one write burst instead of paying a round trip per statement. Safe
|
|
525
|
+
// for the batch's rollback contract because a failed statement leaves
|
|
526
|
+
// the engine's transaction open (no aborted state, no auto-rollback) —
|
|
527
|
+
// later pipelined statements execute inside the same still-open
|
|
528
|
+
// transaction and the final `rollback` discards every effect.
|
|
529
|
+
supportsPipelining: true,
|
|
514
530
|
// biome-ignore lint/suspicious/noExplicitAny: see query() above.
|
|
515
531
|
query: async (text, values) => {
|
|
516
532
|
const { text: powql, params } = normalizeQueryArgs(text, values);
|
package/dist/client.d.ts
CHANGED
|
@@ -57,6 +57,17 @@ export interface PgCompatQueryResult<R = Record<string, unknown>> {
|
|
|
57
57
|
export interface PgCompatPoolClient {
|
|
58
58
|
query<R = Record<string, unknown>>(text: string, values?: unknown[]): Promise<PgCompatQueryResult<R>>;
|
|
59
59
|
release(err?: Error | boolean): void;
|
|
60
|
+
/**
|
|
61
|
+
* Optional driver capability: `true` when `query()` may be called again on
|
|
62
|
+
* this connection while earlier calls are still in flight, with replies
|
|
63
|
+
* delivered to callers in FIFO submission order. Drivers that set this let
|
|
64
|
+
* the batch `$transaction([...])` overload dispatch every statement in one
|
|
65
|
+
* write burst (~1 network round trip plus server time) instead of awaiting
|
|
66
|
+
* each reply before sending the next (N round trips). Leave unset for
|
|
67
|
+
* drivers (node-postgres included) whose batch path must stay strictly
|
|
68
|
+
* sequential.
|
|
69
|
+
*/
|
|
70
|
+
readonly supportsPipelining?: boolean;
|
|
60
71
|
}
|
|
61
72
|
/**
|
|
62
73
|
* Minimal pg-compatible pool. Pass any driver that satisfies this interface
|
|
@@ -564,8 +575,13 @@ export declare class TurbineClient {
|
|
|
564
575
|
* of each query's transformed result; any failure rolls the whole batch back.
|
|
565
576
|
*
|
|
566
577
|
* Unlike {@link pipeline}, this never uses the extended-query pipeline
|
|
567
|
-
* protocol
|
|
568
|
-
* safe on every driver
|
|
578
|
+
* protocol. Statements run on the single transaction connection: strictly
|
|
579
|
+
* sequentially by default (safe on every driver, including HTTP/serverless
|
|
580
|
+
* pools), or — when the checked-out connection advertises
|
|
581
|
+
* {@link PgCompatPoolClient.supportsPipelining} — dispatched in one write
|
|
582
|
+
* burst with replies collected in order, saving a network round trip per
|
|
583
|
+
* statement. Either way the failure contract is identical: the first
|
|
584
|
+
* (lowest-index) failure aborts the batch and rolls everything back.
|
|
569
585
|
*
|
|
570
586
|
* @example
|
|
571
587
|
* ```ts
|
|
@@ -580,8 +596,26 @@ export declare class TurbineClient {
|
|
|
580
596
|
* Execute a batch of {@link DeferredQuery} objects atomically inside one
|
|
581
597
|
* transaction. Backs the `$transaction([...])` array overload. Reuses the raw
|
|
582
598
|
* {@link transaction} machinery (BEGIN/COMMIT/ROLLBACK + connection release);
|
|
583
|
-
*
|
|
584
|
-
*
|
|
599
|
+
* each result is passed through its query's `transform`.
|
|
600
|
+
*
|
|
601
|
+
* Execution strategy on the single transaction connection:
|
|
602
|
+
* - **Sequential (default).** Await each statement's reply before sending
|
|
603
|
+
* the next. Safe on every driver; on a networked driver a batch of N
|
|
604
|
+
* costs N round trips.
|
|
605
|
+
* - **Pipelined.** When the checked-out connection advertises
|
|
606
|
+
* {@link PgCompatPoolClient.supportsPipelining} (its `query()` accepts
|
|
607
|
+
* concurrent calls and completes them in FIFO submission order), all
|
|
608
|
+
* statements are dispatched in one write burst and the replies are
|
|
609
|
+
* collected in order — ~1 round trip plus server time. Only taken when
|
|
610
|
+
* the dialect's writes surface rows directly (`resultStrategy` !==
|
|
611
|
+
* 'reselect'): a reselect plan is itself a sequential write+read pair.
|
|
612
|
+
*
|
|
613
|
+
* The two paths share one failure contract: the first (lowest-index) failed
|
|
614
|
+
* statement's error is thrown (wrapped via {@link wrapPgError}) and the
|
|
615
|
+
* surrounding transaction rolls back, so no statement's effect survives. The
|
|
616
|
+
* pipelined path drains every in-flight reply (`Promise.allSettled`) before
|
|
617
|
+
* rethrowing, which keeps the connection's request/reply pairing intact and
|
|
618
|
+
* means ROLLBACK is only issued once no statement is still in flight.
|
|
585
619
|
*/
|
|
586
620
|
private transactionBatch;
|
|
587
621
|
/**
|
package/dist/client.js
CHANGED
|
@@ -903,14 +903,48 @@ export class TurbineClient {
|
|
|
903
903
|
* Execute a batch of {@link DeferredQuery} objects atomically inside one
|
|
904
904
|
* transaction. Backs the `$transaction([...])` array overload. Reuses the raw
|
|
905
905
|
* {@link transaction} machinery (BEGIN/COMMIT/ROLLBACK + connection release);
|
|
906
|
-
*
|
|
907
|
-
*
|
|
906
|
+
* each result is passed through its query's `transform`.
|
|
907
|
+
*
|
|
908
|
+
* Execution strategy on the single transaction connection:
|
|
909
|
+
* - **Sequential (default).** Await each statement's reply before sending
|
|
910
|
+
* the next. Safe on every driver; on a networked driver a batch of N
|
|
911
|
+
* costs N round trips.
|
|
912
|
+
* - **Pipelined.** When the checked-out connection advertises
|
|
913
|
+
* {@link PgCompatPoolClient.supportsPipelining} (its `query()` accepts
|
|
914
|
+
* concurrent calls and completes them in FIFO submission order), all
|
|
915
|
+
* statements are dispatched in one write burst and the replies are
|
|
916
|
+
* collected in order — ~1 round trip plus server time. Only taken when
|
|
917
|
+
* the dialect's writes surface rows directly (`resultStrategy` !==
|
|
918
|
+
* 'reselect'): a reselect plan is itself a sequential write+read pair.
|
|
919
|
+
*
|
|
920
|
+
* The two paths share one failure contract: the first (lowest-index) failed
|
|
921
|
+
* statement's error is thrown (wrapped via {@link wrapPgError}) and the
|
|
922
|
+
* surrounding transaction rolls back, so no statement's effect survives. The
|
|
923
|
+
* pipelined path drains every in-flight reply (`Promise.allSettled`) before
|
|
924
|
+
* rethrowing, which keeps the connection's request/reply pairing intact and
|
|
925
|
+
* means ROLLBACK is only issued once no statement is still in flight.
|
|
908
926
|
*/
|
|
909
927
|
async transactionBatch(queries) {
|
|
910
928
|
if (queries.length === 0) {
|
|
911
929
|
return [];
|
|
912
930
|
}
|
|
913
931
|
return this.transaction(async (client) => {
|
|
932
|
+
const pipelined = client.supportsPipelining === true &&
|
|
933
|
+
this.dialect.resultStrategy !== 'reselect';
|
|
934
|
+
if (pipelined) {
|
|
935
|
+
// Dispatch every statement before awaiting any reply. The driver's
|
|
936
|
+
// FIFO guarantee makes settled[i] the reply to queries[i].
|
|
937
|
+
const settled = await Promise.allSettled(queries.map((dq) => client.query(dq.sql, dq.params)));
|
|
938
|
+
const results = [];
|
|
939
|
+
for (let i = 0; i < settled.length; i++) {
|
|
940
|
+
const outcome = settled[i];
|
|
941
|
+
if (outcome.status === 'rejected') {
|
|
942
|
+
throw wrapPgError(outcome.reason);
|
|
943
|
+
}
|
|
944
|
+
results.push(queries[i].transform(outcome.value));
|
|
945
|
+
}
|
|
946
|
+
return results;
|
|
947
|
+
}
|
|
914
948
|
const results = [];
|
|
915
949
|
for (const dq of queries) {
|
|
916
950
|
let raw;
|
package/dist/powdb.d.ts
CHANGED
|
@@ -22,8 +22,14 @@
|
|
|
22
22
|
* `string` PKs hold UUID strings.
|
|
23
23
|
* - **No JSON aggregation / link navigation** — single-query nested `with` is
|
|
24
24
|
* impossible → it degrades to batched N+1 loaders (Phase B).
|
|
25
|
-
* - **Single global write lock; no savepoints/isolation
|
|
25
|
+
* - **Single global write lock; no savepoints/isolation** — nested
|
|
26
26
|
* transactions / isolation / vector / LISTEN-NOTIFY / RLS throw.
|
|
27
|
+
* - **The wire protocol pipelines** — `@zvndev/powdb-client` writes each
|
|
28
|
+
* request frame immediately and matches replies FIFO, so multiple queries
|
|
29
|
+
* may be in flight on one connection. {@link PowdbPool}'s checked-out
|
|
30
|
+
* clients advertise `supportsPipelining`, which lets the batch
|
|
31
|
+
* `$transaction([...])` overload dispatch all statements in one write
|
|
32
|
+
* burst (~1 round trip) instead of one round trip per statement.
|
|
27
33
|
*
|
|
28
34
|
* `@zvndev/powdb-client` is an **optional peer dependency** loaded by dynamic
|
|
29
35
|
* import; `npm i turbine-orm` still pulls only `pg`.
|
package/dist/powdb.js
CHANGED
|
@@ -22,8 +22,14 @@
|
|
|
22
22
|
* `string` PKs hold UUID strings.
|
|
23
23
|
* - **No JSON aggregation / link navigation** — single-query nested `with` is
|
|
24
24
|
* impossible → it degrades to batched N+1 loaders (Phase B).
|
|
25
|
-
* - **Single global write lock; no savepoints/isolation
|
|
25
|
+
* - **Single global write lock; no savepoints/isolation** — nested
|
|
26
26
|
* transactions / isolation / vector / LISTEN-NOTIFY / RLS throw.
|
|
27
|
+
* - **The wire protocol pipelines** — `@zvndev/powdb-client` writes each
|
|
28
|
+
* request frame immediately and matches replies FIFO, so multiple queries
|
|
29
|
+
* may be in flight on one connection. {@link PowdbPool}'s checked-out
|
|
30
|
+
* clients advertise `supportsPipelining`, which lets the batch
|
|
31
|
+
* `$transaction([...])` overload dispatch all statements in one write
|
|
32
|
+
* burst (~1 round trip) instead of one round trip per statement.
|
|
27
33
|
*
|
|
28
34
|
* `@zvndev/powdb-client` is an **optional peer dependency** loaded by dynamic
|
|
29
35
|
* import; `npm i turbine-orm` still pulls only `pg`.
|
|
@@ -464,6 +470,16 @@ export class PowdbPool {
|
|
|
464
470
|
const client = await this.pool.acquire();
|
|
465
471
|
let broken = false;
|
|
466
472
|
return {
|
|
473
|
+
// The networked client's query() supports concurrent in-flight calls on
|
|
474
|
+
// one connection: every request frame is written to the socket
|
|
475
|
+
// immediately and replies are matched to callers in FIFO order. That
|
|
476
|
+
// lets the batch `$transaction([...])` path dispatch all statements in
|
|
477
|
+
// one write burst instead of paying a round trip per statement. Safe
|
|
478
|
+
// for the batch's rollback contract because a failed statement leaves
|
|
479
|
+
// the engine's transaction open (no aborted state, no auto-rollback) —
|
|
480
|
+
// later pipelined statements execute inside the same still-open
|
|
481
|
+
// transaction and the final `rollback` discards every effect.
|
|
482
|
+
supportsPipelining: true,
|
|
467
483
|
// biome-ignore lint/suspicious/noExplicitAny: see query() above.
|
|
468
484
|
query: async (text, values) => {
|
|
469
485
|
const { text: powql, params } = normalizeQueryArgs(text, values);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "turbine-orm",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.29.0",
|
|
4
4
|
"description": "Postgres-native TypeScript ORM — runs on Neon, Vercel Postgres, Cloudflare, Supabase. Streaming cursors, typed errors, single-query nested relations. One dependency, no WASM engine",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|