turbine-orm 0.81.0 → 0.90.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/README.md +26 -25
- package/dist/checkout.d.ts +27 -2
- package/dist/checkout.js +75 -4
- package/dist/cjs/checkout.d.ts +27 -2
- package/dist/cjs/checkout.js +76 -3
- package/dist/cjs/cli/code-first-tags.d.ts +62 -0
- package/dist/cjs/cli/code-first-tags.js +124 -0
- package/dist/cjs/cli/compile-query.js +9 -0
- package/dist/cjs/cli/config.d.ts +35 -6
- package/dist/cjs/cli/config.js +17 -1
- package/dist/cjs/cli/destructive.d.ts +7 -4
- package/dist/cjs/cli/destructive.js +224 -20
- package/dist/cjs/cli/error-catalog.js +36 -0
- package/dist/cjs/cli/error-text.d.ts +15 -0
- package/dist/cjs/cli/error-text.js +40 -0
- package/dist/cjs/cli/index.d.ts +62 -4
- package/dist/cjs/cli/index.js +568 -108
- package/dist/cjs/cli/local-server-guard.d.ts +53 -0
- package/dist/cjs/cli/local-server-guard.js +119 -0
- package/dist/cjs/cli/local-server-output.d.ts +41 -0
- package/dist/cjs/cli/local-server-output.js +103 -0
- package/dist/cjs/cli/mcp.d.ts +8 -0
- package/dist/cjs/cli/mcp.js +121 -32
- package/dist/cjs/cli/migrate.d.ts +113 -5
- package/dist/cjs/cli/migrate.js +270 -21
- package/dist/cjs/cli/observe.d.ts +6 -1
- package/dist/cjs/cli/observe.js +85 -55
- package/dist/cjs/cli/pii-predicate-guard.d.ts +43 -23
- package/dist/cjs/cli/pii-predicate-guard.js +98 -37
- package/dist/cjs/cli/prisma-resolve.js +17 -13
- package/dist/cjs/cli/prisma-schema.js +12 -4
- package/dist/cjs/cli/studio-ui.generated.js +1 -1
- package/dist/cjs/cli/studio.d.ts +14 -2
- package/dist/cjs/cli/studio.js +244 -69
- package/dist/cjs/cli/ui.d.ts +1 -1
- package/dist/cjs/client.d.ts +558 -85
- package/dist/cjs/client.js +1270 -395
- package/dist/cjs/connection-guard.d.ts +13 -0
- package/dist/cjs/connection-guard.js +28 -0
- package/dist/cjs/connection-url.d.ts +51 -16
- package/dist/cjs/connection-url.js +67 -34
- package/dist/cjs/diagnostics.d.ts +81 -0
- package/dist/cjs/diagnostics.js +147 -0
- package/dist/cjs/dialect.d.ts +449 -20
- package/dist/cjs/dialect.js +117 -76
- package/dist/cjs/engine-config.d.ts +7 -6
- package/dist/cjs/errors.d.ts +126 -6
- package/dist/cjs/errors.js +256 -13
- package/dist/cjs/generate.d.ts +57 -7
- package/dist/cjs/generate.js +635 -279
- package/dist/cjs/global-filters-config.d.ts +59 -0
- package/dist/cjs/global-filters-config.js +367 -0
- package/dist/cjs/index.d.ts +9 -4
- package/dist/cjs/index.js +10 -2
- package/dist/cjs/introspect.d.ts +31 -6
- package/dist/cjs/introspect.js +108 -50
- package/dist/cjs/log-codes.d.ts +12 -0
- package/dist/cjs/log-codes.js +77 -0
- package/dist/cjs/logger.d.ts +87 -0
- package/dist/cjs/logger.js +98 -0
- package/dist/cjs/mssql.d.ts +8 -5
- package/dist/cjs/mssql.js +352 -65
- package/dist/cjs/mysql.d.ts +3 -5
- package/dist/cjs/mysql.js +420 -70
- package/dist/cjs/nested-write.d.ts +3 -0
- package/dist/cjs/nested-write.js +179 -114
- package/dist/cjs/pipeline-submittable.d.ts +12 -0
- package/dist/cjs/pipeline-submittable.js +118 -44
- package/dist/cjs/pipeline.js +21 -26
- package/dist/cjs/powdb-introspect.d.ts +5 -2
- package/dist/cjs/powdb-introspect.js +20 -15
- package/dist/cjs/powdb-shared.d.ts +36 -5
- package/dist/cjs/powdb-shared.js +67 -8
- package/dist/cjs/powdb.d.ts +4 -0
- package/dist/cjs/powdb.js +183 -51
- package/dist/cjs/powql.d.ts +394 -51
- package/dist/cjs/powql.js +1829 -284
- package/dist/cjs/prisma-compat.d.ts +23 -15
- package/dist/cjs/prisma-compat.js +507 -372
- package/dist/cjs/query/aggregates.d.ts +17 -1
- package/dist/cjs/query/aggregates.js +261 -29
- package/dist/cjs/query/batched-loader.d.ts +25 -6
- package/dist/cjs/query/batched-loader.js +103 -20
- package/dist/cjs/query/builder.d.ts +325 -184
- package/dist/cjs/query/builder.js +1452 -490
- package/dist/cjs/query/column-ref.d.ts +61 -0
- package/dist/cjs/query/column-ref.js +73 -0
- package/dist/cjs/query/compound-unique.d.ts +21 -0
- package/dist/cjs/query/compound-unique.js +98 -18
- package/dist/cjs/query/deferred.d.ts +53 -16
- package/dist/cjs/query/expr.d.ts +217 -0
- package/dist/cjs/query/expr.js +859 -0
- package/dist/cjs/query/filters.d.ts +155 -53
- package/dist/cjs/query/filters.js +613 -76
- package/dist/cjs/query/index.d.ts +2 -0
- package/dist/cjs/query/index.js +7 -1
- package/dist/cjs/query/json-value.d.ts +43 -0
- package/dist/cjs/query/json-value.js +59 -0
- package/dist/cjs/query/normalize-args.d.ts +87 -0
- package/dist/cjs/query/normalize-args.js +527 -0
- package/dist/cjs/query/option-surface.d.ts +16 -4
- package/dist/cjs/query/option-surface.js +57 -14
- package/dist/cjs/query/relation-names.d.ts +14 -0
- package/dist/cjs/query/relation-names.js +77 -18
- package/dist/cjs/query/relations.d.ts +30 -3
- package/dist/cjs/query/relations.js +219 -63
- package/dist/cjs/query/row-lock.d.ts +49 -0
- package/dist/cjs/query/row-lock.js +138 -0
- package/dist/cjs/query/sql-comment.d.ts +161 -0
- package/dist/cjs/query/sql-comment.js +381 -0
- package/dist/cjs/query/stream-idle.d.ts +132 -0
- package/dist/cjs/query/stream-idle.js +212 -0
- package/dist/cjs/query/table-client.d.ts +101 -0
- package/dist/cjs/query/table-client.js +74 -0
- package/dist/cjs/query/types.d.ts +677 -298
- package/dist/cjs/query/utils.d.ts +105 -6
- package/dist/cjs/query/utils.js +426 -19
- package/dist/cjs/query/warn-registry.d.ts +18 -0
- package/dist/cjs/query/warn-registry.js +18 -0
- package/dist/cjs/query/where-compile.d.ts +138 -14
- package/dist/cjs/query/where-compile.js +513 -29
- package/dist/cjs/query/where.d.ts +159 -59
- package/dist/cjs/query/where.js +716 -246
- package/dist/cjs/query/writes.d.ts +112 -50
- package/dist/cjs/query/writes.js +1498 -200
- package/dist/cjs/query-events.d.ts +4 -2
- package/dist/cjs/query-events.js +3 -1
- package/dist/cjs/realtime.d.ts +7 -3
- package/dist/cjs/realtime.js +13 -2
- package/dist/cjs/schema-builder.d.ts +55 -4
- package/dist/cjs/schema-builder.js +382 -18
- package/dist/cjs/schema-metadata.d.ts +21 -1
- package/dist/cjs/schema-metadata.js +29 -7
- package/dist/cjs/schema-sql.d.ts +75 -5
- package/dist/cjs/schema-sql.js +497 -45
- package/dist/cjs/schema.d.ts +26 -5
- package/dist/cjs/schema.js +110 -13
- package/dist/cjs/sql-placeholders.d.ts +56 -0
- package/dist/cjs/sql-placeholders.js +204 -0
- package/dist/cjs/sqlite.d.ts +75 -20
- package/dist/cjs/sqlite.js +593 -95
- package/dist/cjs/supplied-pool-types.d.ts +48 -0
- package/dist/cjs/supplied-pool-types.js +256 -0
- package/dist/cjs/transaction-control.d.ts +51 -0
- package/dist/cjs/transaction-control.js +316 -0
- package/dist/cjs/transaction-state.d.ts +342 -0
- package/dist/cjs/transaction-state.js +707 -0
- package/dist/cjs/typed-sql.d.ts +37 -3
- package/dist/cjs/typed-sql.js +102 -8
- package/dist/cli/code-first-tags.d.ts +62 -0
- package/dist/cli/code-first-tags.js +120 -0
- package/dist/cli/compile-query.js +9 -0
- package/dist/cli/config.d.ts +35 -6
- package/dist/cli/config.js +16 -1
- package/dist/cli/destructive.d.ts +7 -4
- package/dist/cli/destructive.js +224 -20
- package/dist/cli/error-catalog.js +36 -0
- package/dist/cli/error-text.d.ts +15 -0
- package/dist/cli/error-text.js +37 -0
- package/dist/cli/index.d.ts +62 -4
- package/dist/cli/index.js +569 -112
- package/dist/cli/local-server-guard.d.ts +53 -0
- package/dist/cli/local-server-guard.js +113 -0
- package/dist/cli/local-server-output.d.ts +41 -0
- package/dist/cli/local-server-output.js +98 -0
- package/dist/cli/mcp.d.ts +8 -0
- package/dist/cli/mcp.js +121 -34
- package/dist/cli/migrate.d.ts +113 -5
- package/dist/cli/migrate.js +261 -21
- package/dist/cli/observe.d.ts +6 -1
- package/dist/cli/observe.js +84 -54
- package/dist/cli/pii-predicate-guard.d.ts +43 -23
- package/dist/cli/pii-predicate-guard.js +100 -35
- package/dist/cli/prisma-resolve.js +15 -11
- package/dist/cli/prisma-schema.js +12 -4
- package/dist/cli/studio-ui.generated.js +1 -1
- package/dist/cli/studio.d.ts +14 -2
- package/dist/cli/studio.js +246 -71
- package/dist/cli/ui.d.ts +1 -1
- package/dist/client.d.ts +558 -85
- package/dist/client.js +1275 -400
- package/dist/connection-guard.d.ts +13 -0
- package/dist/connection-guard.js +27 -0
- package/dist/connection-url.d.ts +51 -16
- package/dist/connection-url.js +63 -34
- package/dist/diagnostics.d.ts +81 -0
- package/dist/diagnostics.js +144 -0
- package/dist/dialect.d.ts +449 -20
- package/dist/dialect.js +115 -43
- package/dist/engine-config.d.ts +7 -6
- package/dist/errors.d.ts +126 -6
- package/dist/errors.js +252 -12
- package/dist/generate.d.ts +57 -7
- package/dist/generate.js +635 -281
- package/dist/global-filters-config.d.ts +59 -0
- package/dist/global-filters-config.js +361 -0
- package/dist/index.d.ts +9 -4
- package/dist/index.js +4 -2
- package/dist/introspect.d.ts +31 -6
- package/dist/introspect.js +106 -50
- package/dist/log-codes.d.ts +12 -0
- package/dist/log-codes.js +74 -0
- package/dist/logger.d.ts +87 -0
- package/dist/logger.js +93 -0
- package/dist/mssql.d.ts +8 -5
- package/dist/mssql.js +354 -67
- package/dist/mysql.d.ts +3 -5
- package/dist/mysql.js +423 -73
- package/dist/nested-write.d.ts +3 -0
- package/dist/nested-write.js +177 -112
- package/dist/pipeline-submittable.d.ts +12 -0
- package/dist/pipeline-submittable.js +117 -44
- package/dist/pipeline.js +21 -26
- package/dist/powdb-introspect.d.ts +5 -2
- package/dist/powdb-introspect.js +21 -16
- package/dist/powdb-shared.d.ts +36 -5
- package/dist/powdb-shared.js +65 -8
- package/dist/powdb.d.ts +4 -0
- package/dist/powdb.js +183 -51
- package/dist/powql.d.ts +394 -51
- package/dist/powql.js +1836 -291
- package/dist/prisma-compat.d.ts +23 -15
- package/dist/prisma-compat.js +508 -373
- package/dist/query/aggregates.d.ts +17 -1
- package/dist/query/aggregates.js +263 -32
- package/dist/query/batched-loader.d.ts +25 -6
- package/dist/query/batched-loader.js +101 -21
- package/dist/query/builder.d.ts +325 -184
- package/dist/query/builder.js +1458 -495
- package/dist/query/column-ref.d.ts +61 -0
- package/dist/query/column-ref.js +66 -0
- package/dist/query/compound-unique.d.ts +21 -0
- package/dist/query/compound-unique.js +97 -19
- package/dist/query/deferred.d.ts +53 -16
- package/dist/query/expr.d.ts +217 -0
- package/dist/query/expr.js +848 -0
- package/dist/query/filters.d.ts +155 -53
- package/dist/query/filters.js +597 -72
- package/dist/query/index.d.ts +2 -0
- package/dist/query/index.js +4 -0
- package/dist/query/json-value.d.ts +43 -0
- package/dist/query/json-value.js +54 -0
- package/dist/query/normalize-args.d.ts +87 -0
- package/dist/query/normalize-args.js +517 -0
- package/dist/query/option-surface.d.ts +16 -4
- package/dist/query/option-surface.js +56 -13
- package/dist/query/relation-names.d.ts +14 -0
- package/dist/query/relation-names.js +77 -19
- package/dist/query/relations.d.ts +30 -3
- package/dist/query/relations.js +220 -67
- package/dist/query/row-lock.d.ts +49 -0
- package/dist/query/row-lock.js +131 -0
- package/dist/query/sql-comment.d.ts +161 -0
- package/dist/query/sql-comment.js +374 -0
- package/dist/query/stream-idle.d.ts +132 -0
- package/dist/query/stream-idle.js +203 -0
- package/dist/query/table-client.d.ts +101 -0
- package/dist/query/table-client.js +70 -0
- package/dist/query/types.d.ts +677 -298
- package/dist/query/utils.d.ts +105 -6
- package/dist/query/utils.js +414 -18
- package/dist/query/warn-registry.d.ts +18 -0
- package/dist/query/warn-registry.js +18 -0
- package/dist/query/where-compile.d.ts +138 -14
- package/dist/query/where-compile.js +508 -31
- package/dist/query/where.d.ts +159 -59
- package/dist/query/where.js +711 -248
- package/dist/query/writes.d.ts +112 -50
- package/dist/query/writes.js +1496 -202
- package/dist/query-events.d.ts +4 -2
- package/dist/query-events.js +3 -1
- package/dist/realtime.d.ts +7 -3
- package/dist/realtime.js +13 -2
- package/dist/schema-builder.d.ts +55 -4
- package/dist/schema-builder.js +381 -18
- package/dist/schema-metadata.d.ts +21 -1
- package/dist/schema-metadata.js +28 -7
- package/dist/schema-sql.d.ts +75 -5
- package/dist/schema-sql.js +494 -44
- package/dist/schema.d.ts +26 -5
- package/dist/schema.js +109 -13
- package/dist/sql-placeholders.d.ts +56 -0
- package/dist/sql-placeholders.js +200 -0
- package/dist/sqlite.d.ts +75 -20
- package/dist/sqlite.js +597 -99
- package/dist/supplied-pool-types.d.ts +48 -0
- package/dist/supplied-pool-types.js +247 -0
- package/dist/transaction-control.d.ts +51 -0
- package/dist/transaction-control.js +311 -0
- package/dist/transaction-state.d.ts +342 -0
- package/dist/transaction-state.js +696 -0
- package/dist/typed-sql.d.ts +37 -3
- package/dist/typed-sql.js +100 -8
- package/package.json +7 -4
- package/skills/turbine-orm/SKILL.md +56 -6
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* turbine-orm: the abandoned-stream idle guard.
|
|
4
|
+
*
|
|
5
|
+
* A cursor stream holds a checked-out connection between pulls (and, on
|
|
6
|
+
* PostgreSQL, an open transaction whose snapshot pins the xmin horizon for the
|
|
7
|
+
* whole database). A consumer that stops pulling without calling `return()`
|
|
8
|
+
* leaves the stream suspended at a `yield` forever, and a suspended generator
|
|
9
|
+
* runs no code, so nothing would ever release either. This guard is the code
|
|
10
|
+
* that runs instead: a timer that notices the consumer has asked for nothing for
|
|
11
|
+
* the configured time and closes the stream from outside.
|
|
12
|
+
*
|
|
13
|
+
* The consuming generator owns the {@link StreamIdleState}: it sets `suspended`
|
|
14
|
+
* around each yield and bumps `pulls` when the consumer resumes it. That is two
|
|
15
|
+
* writes per yield and no timer work, which is what keeps a per-row stream as
|
|
16
|
+
* cheap as before (a timer refreshed per row costs about 15% per row; a
|
|
17
|
+
* `setTimeout` per row more than doubles it).
|
|
18
|
+
*
|
|
19
|
+
* Leaf module: imports errors.ts only, so it stays in the serverless graph
|
|
20
|
+
* without pulling anything node-only.
|
|
21
|
+
*/
|
|
22
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
+
exports.StreamIdleGuard = exports.MAX_STREAM_IDLE_TIMEOUT_MS = exports.STREAM_IDLE_BACKSTOP_GRACE_MS = exports.DEFAULT_STREAM_IDLE_TIMEOUT_MS = void 0;
|
|
24
|
+
exports.resolveStreamIdleTimeout = resolveStreamIdleTimeout;
|
|
25
|
+
exports.newStreamIdleState = newStreamIdleState;
|
|
26
|
+
exports.streamIdleExpiredError = streamIdleExpiredError;
|
|
27
|
+
exports.streamBackstopStatement = streamBackstopStatement;
|
|
28
|
+
exports.watchStreamConnection = watchStreamConnection;
|
|
29
|
+
const errors_js_1 = require("../errors.js");
|
|
30
|
+
/** The default for `streamIdleTimeoutMs` (client) and `idleTimeoutMs` (per call). */
|
|
31
|
+
exports.DEFAULT_STREAM_IDLE_TIMEOUT_MS = 300_000;
|
|
32
|
+
/**
|
|
33
|
+
* How much later than the idle timeout the PostgreSQL server-side limit fires.
|
|
34
|
+
* The client timer always expires a stream first (it ticks at most every
|
|
35
|
+
* {@link MAX_TICK_MS}, half this grace), so the server limit only acts when the
|
|
36
|
+
* process has stopped running timers: frozen between serverless invocations,
|
|
37
|
+
* or an event loop blocked for longer than the grace.
|
|
38
|
+
*/
|
|
39
|
+
exports.STREAM_IDLE_BACKSTOP_GRACE_MS = 10_000;
|
|
40
|
+
/**
|
|
41
|
+
* The largest idle timeout accepted. PostgreSQL's
|
|
42
|
+
* `idle_in_transaction_session_timeout` is a 32-bit count of milliseconds, and
|
|
43
|
+
* the backstop adds the grace to it.
|
|
44
|
+
*/
|
|
45
|
+
exports.MAX_STREAM_IDLE_TIMEOUT_MS = 2_147_483_647 - exports.STREAM_IDLE_BACKSTOP_GRACE_MS;
|
|
46
|
+
/** The longest gap between two idle checks, so expiry lands within 5 s of the timeout. */
|
|
47
|
+
const MAX_TICK_MS = 5_000;
|
|
48
|
+
/**
|
|
49
|
+
* Validate an idle timeout: a whole number of milliseconds from 0 (disabled)
|
|
50
|
+
* to {@link MAX_STREAM_IDLE_TIMEOUT_MS}, else E003. `undefined` means "not
|
|
51
|
+
* set here", so the caller falls back to the next level.
|
|
52
|
+
*/
|
|
53
|
+
function resolveStreamIdleTimeout(value, name) {
|
|
54
|
+
if (value === undefined)
|
|
55
|
+
return undefined;
|
|
56
|
+
if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < 0 || value > exports.MAX_STREAM_IDLE_TIMEOUT_MS) {
|
|
57
|
+
throw new errors_js_1.ValidationError(`Invalid ${name}: ${typeof value === 'string' ? JSON.stringify(value) : String(value)}. Expected a whole ` +
|
|
58
|
+
`number of milliseconds from 0 (no idle timeout) to ${exports.MAX_STREAM_IDLE_TIMEOUT_MS}.`);
|
|
59
|
+
}
|
|
60
|
+
return value;
|
|
61
|
+
}
|
|
62
|
+
function newStreamIdleState() {
|
|
63
|
+
return { pulls: 0, suspended: false, rows: 0, expired: undefined };
|
|
64
|
+
}
|
|
65
|
+
/** The E002 the next pull on an expired stream throws. */
|
|
66
|
+
function streamIdleExpiredError(action, table, timeoutMs, unit) {
|
|
67
|
+
return new errors_js_1.TimeoutError(timeoutMs, 'Stream', {
|
|
68
|
+
message: `${action} on "${table}" was closed after ${timeoutMs} ms with no ${unit} requested: its cursor and ` +
|
|
69
|
+
`connection were released so an abandoned stream cannot hold a pooled connection and the database's ` +
|
|
70
|
+
`snapshot. Consume faster, raise streamIdleTimeoutMs (client) or idleTimeoutMs (this call), or pass 0 ` +
|
|
71
|
+
'to disable.',
|
|
72
|
+
outcome: 'not-executed',
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* The PostgreSQL server-side limit for a stream's own transaction:
|
|
77
|
+
* `idle_in_transaction_session_timeout` set to the idle timeout plus the grace,
|
|
78
|
+
* TRANSACTION-LOCAL (`set_config(..., true)`), so it ends with the stream's
|
|
79
|
+
* COMMIT and cannot reach another client through a transaction pooler.
|
|
80
|
+
*
|
|
81
|
+
* A stricter limit already in force (a role or server setting below ours) is
|
|
82
|
+
* kept, so a stream never loosens what the operator configured. The value is a
|
|
83
|
+
* validated integer, never caller text: a GUC value cannot be a bind parameter.
|
|
84
|
+
* Reading `pg_settings` rather than calling `set_config` directly also means an
|
|
85
|
+
* engine without the setting gets no row and no error.
|
|
86
|
+
*/
|
|
87
|
+
function streamBackstopStatement(timeoutMs) {
|
|
88
|
+
const limit = timeoutMs + exports.STREAM_IDLE_BACKSTOP_GRACE_MS;
|
|
89
|
+
if (!Number.isSafeInteger(limit) || limit <= exports.STREAM_IDLE_BACKSTOP_GRACE_MS || limit > 2_147_483_647) {
|
|
90
|
+
throw new errors_js_1.ValidationError(`Invalid stream idle timeout ${String(timeoutMs)} for the server-side limit.`);
|
|
91
|
+
}
|
|
92
|
+
return ("SELECT set_config('idle_in_transaction_session_timeout', CASE WHEN s.setting::bigint > 0 AND " +
|
|
93
|
+
`s.setting::bigint < ${limit} THEN s.setting ELSE '${limit}' END, true) FROM pg_settings s ` +
|
|
94
|
+
"WHERE s.name = 'idle_in_transaction_session_timeout'");
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* The timer half of the guard. One per open cursor stream, `unref()`ed so it
|
|
98
|
+
* never keeps a process alive.
|
|
99
|
+
*
|
|
100
|
+
* It ticks every `min(timeout / 4, 5 s)`. A tick that finds the stream
|
|
101
|
+
* suspended with no pull since the previous tick counts as idle; enough idle
|
|
102
|
+
* ticks in a row to cover the timeout expire the stream, so expiry lands
|
|
103
|
+
* between 1x the timeout and the timeout plus one tick. Time Turbine spends
|
|
104
|
+
* fetching never counts, because the stream is not suspended then.
|
|
105
|
+
*
|
|
106
|
+
* With `keepalive` set (PostgreSQL, where {@link streamBackstopStatement} is
|
|
107
|
+
* in force), a tick also sends a no-op statement when the connection has been
|
|
108
|
+
* quiet for half the timeout. A consumer that pulls rows of an already-fetched
|
|
109
|
+
* batch slowly is alive while the server sees an idle transaction; without the
|
|
110
|
+
* keepalive the server limit would end a stream the consumer is still reading.
|
|
111
|
+
* The server limit therefore only fires when this timer cannot run.
|
|
112
|
+
*/
|
|
113
|
+
class StreamIdleGuard {
|
|
114
|
+
state;
|
|
115
|
+
timeoutMs;
|
|
116
|
+
expiredError;
|
|
117
|
+
onExpire;
|
|
118
|
+
keepalive;
|
|
119
|
+
timer;
|
|
120
|
+
idleTicksToExpire;
|
|
121
|
+
lastPulls;
|
|
122
|
+
idleTicks = 0;
|
|
123
|
+
lastStatementAt = Date.now();
|
|
124
|
+
statementsInFlight = 0;
|
|
125
|
+
keepaliveInFlight = false;
|
|
126
|
+
/** Settles once an expired stream's cleanup has run (connection released). */
|
|
127
|
+
expiry;
|
|
128
|
+
constructor(state, timeoutMs, expiredError, onExpire, keepalive) {
|
|
129
|
+
this.state = state;
|
|
130
|
+
this.timeoutMs = timeoutMs;
|
|
131
|
+
this.expiredError = expiredError;
|
|
132
|
+
this.onExpire = onExpire;
|
|
133
|
+
this.keepalive = keepalive;
|
|
134
|
+
const tickMs = Math.max(1, Math.min(Math.floor(timeoutMs / 4), MAX_TICK_MS));
|
|
135
|
+
this.idleTicksToExpire = Math.ceil(timeoutMs / tickMs);
|
|
136
|
+
this.lastPulls = state.pulls;
|
|
137
|
+
this.timer = setInterval(() => this.tick(), tickMs);
|
|
138
|
+
this.timer.unref?.();
|
|
139
|
+
}
|
|
140
|
+
/** Bracket a statement on the stream's connection, so the keepalive knows it is busy. */
|
|
141
|
+
statementStarted() {
|
|
142
|
+
this.statementsInFlight++;
|
|
143
|
+
this.lastStatementAt = Date.now();
|
|
144
|
+
}
|
|
145
|
+
statementSettled() {
|
|
146
|
+
this.statementsInFlight--;
|
|
147
|
+
this.lastStatementAt = Date.now();
|
|
148
|
+
}
|
|
149
|
+
stop() {
|
|
150
|
+
clearInterval(this.timer);
|
|
151
|
+
}
|
|
152
|
+
tick() {
|
|
153
|
+
if (this.expiry)
|
|
154
|
+
return;
|
|
155
|
+
if (!this.state.suspended || this.state.pulls !== this.lastPulls) {
|
|
156
|
+
this.lastPulls = this.state.pulls;
|
|
157
|
+
this.idleTicks = 0;
|
|
158
|
+
}
|
|
159
|
+
else if (++this.idleTicks >= this.idleTicksToExpire) {
|
|
160
|
+
this.stop();
|
|
161
|
+
// Set before any await, so a pull that races the cleanup already sees it.
|
|
162
|
+
this.state.expired = this.expiredError();
|
|
163
|
+
this.expiry = this.onExpire();
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
if (this.keepalive &&
|
|
167
|
+
!this.keepaliveInFlight &&
|
|
168
|
+
this.statementsInFlight === 0 &&
|
|
169
|
+
Date.now() - this.lastStatementAt >= this.timeoutMs / 2) {
|
|
170
|
+
this.keepaliveInFlight = true;
|
|
171
|
+
this.statementStarted();
|
|
172
|
+
// A failed keepalive is not reported here: the stream's next statement
|
|
173
|
+
// meets the same broken connection and reports it with context.
|
|
174
|
+
this.keepalive()
|
|
175
|
+
.catch(() => undefined)
|
|
176
|
+
.finally(() => {
|
|
177
|
+
this.keepaliveInFlight = false;
|
|
178
|
+
this.statementSettled();
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
exports.StreamIdleGuard = StreamIdleGuard;
|
|
184
|
+
/**
|
|
185
|
+
* The stream's connection, as the dialect sees it, with two additions: every
|
|
186
|
+
* statement is reported to the guard (for the keepalive), and, when `backstop`
|
|
187
|
+
* is given, the dialect's own BEGIN carries {@link streamBackstopStatement} in
|
|
188
|
+
* the same simple-protocol round trip, so the limit is in force from the
|
|
189
|
+
* transaction's first statement at no extra cost. Matching the exact BEGIN text
|
|
190
|
+
* the dialect emits keeps the dialect itself unchanged; the live backstop test
|
|
191
|
+
* fails if that text ever stops matching.
|
|
192
|
+
*/
|
|
193
|
+
function watchStreamConnection(base, guard, backstop) {
|
|
194
|
+
let backstopSent = false;
|
|
195
|
+
return {
|
|
196
|
+
query: async (text, values) => {
|
|
197
|
+
let sql = text;
|
|
198
|
+
if (backstop && !backstopSent && values === undefined && text === backstop.begin) {
|
|
199
|
+
backstopSent = true;
|
|
200
|
+
sql = `${text}; ${backstop.statement}`;
|
|
201
|
+
}
|
|
202
|
+
const g = guard();
|
|
203
|
+
g?.statementStarted();
|
|
204
|
+
try {
|
|
205
|
+
return await base.query(sql, values);
|
|
206
|
+
}
|
|
207
|
+
finally {
|
|
208
|
+
g?.statementSettled();
|
|
209
|
+
}
|
|
210
|
+
},
|
|
211
|
+
};
|
|
212
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* turbine-orm, the table accessor contract.
|
|
3
|
+
*
|
|
4
|
+
* `db.users` is a `QueryInterface` on the SQL engines and a `PowqlInterface` on
|
|
5
|
+
* PowDB. The second is a parallel class, not a subclass, so without a shared
|
|
6
|
+
* type the compiler cannot see a method one engine has and the other lacks, and
|
|
7
|
+
* the user meets it as `TypeError: ... is not a function` at run time.
|
|
8
|
+
*
|
|
9
|
+
* {@link TableClient} is that shared type. It is DERIVED from QueryInterface
|
|
10
|
+
* (a `Pick` of the classified methods), so the SQL builder stays the one source
|
|
11
|
+
* of truth for every signature, and `PowqlInterface implements TableClient`
|
|
12
|
+
* makes a missing or mismatched method a build error.
|
|
13
|
+
*
|
|
14
|
+
* Type-only imports: this module emits {@link TABLE_METHODS} and nothing else,
|
|
15
|
+
* so it adds no edge to the import graph.
|
|
16
|
+
*/
|
|
17
|
+
import type { QueryInterface } from './builder.js';
|
|
18
|
+
import type { DefaultInputTypes, TableInputTypes } from './types.js';
|
|
19
|
+
/**
|
|
20
|
+
* How a table method is routed.
|
|
21
|
+
*
|
|
22
|
+
* - `read`: may be served by a read replica (`READ_OPERATIONS` in client.ts is
|
|
23
|
+
* derived from these).
|
|
24
|
+
* - `write`: always runs on the primary.
|
|
25
|
+
* - `deferred`: returns a `DeferredQuery` for `db.pipeline()` /
|
|
26
|
+
* `$transaction([...])` without running anything.
|
|
27
|
+
* - `primary`: anything else on the accessor; runs on the primary.
|
|
28
|
+
*/
|
|
29
|
+
export type TableMethodKind = 'read' | 'write' | 'deferred' | 'primary';
|
|
30
|
+
/**
|
|
31
|
+
* Every public method of a table accessor, with its routing class.
|
|
32
|
+
*
|
|
33
|
+
* `satisfies` refuses a key QueryInterface does not have; the exhaustiveness
|
|
34
|
+
* check below refuses a QueryInterface member missing from here.
|
|
35
|
+
*/
|
|
36
|
+
export declare const TABLE_METHODS: {
|
|
37
|
+
readonly findMany: "read";
|
|
38
|
+
readonly findFirst: "read";
|
|
39
|
+
readonly findFirstOrThrow: "read";
|
|
40
|
+
readonly findUnique: "read";
|
|
41
|
+
readonly findUniqueOrThrow: "read";
|
|
42
|
+
readonly count: "read";
|
|
43
|
+
readonly aggregate: "read";
|
|
44
|
+
readonly groupBy: "read";
|
|
45
|
+
readonly findManyStream: "read";
|
|
46
|
+
readonly findManyStreamBatches: "read";
|
|
47
|
+
readonly explain: "primary";
|
|
48
|
+
readonly cacheStats: "primary";
|
|
49
|
+
readonly create: "write";
|
|
50
|
+
readonly createMany: "write";
|
|
51
|
+
readonly update: "write";
|
|
52
|
+
readonly updateMany: "write";
|
|
53
|
+
readonly delete: "write";
|
|
54
|
+
readonly deleteMany: "write";
|
|
55
|
+
readonly upsert: "write";
|
|
56
|
+
readonly buildFindMany: "deferred";
|
|
57
|
+
readonly buildFindFirst: "deferred";
|
|
58
|
+
readonly buildFindFirstOrThrow: "deferred";
|
|
59
|
+
readonly buildFindUnique: "deferred";
|
|
60
|
+
readonly buildFindUniqueOrThrow: "deferred";
|
|
61
|
+
readonly buildCount: "deferred";
|
|
62
|
+
readonly buildAggregate: "deferred";
|
|
63
|
+
readonly buildGroupBy: "deferred";
|
|
64
|
+
readonly buildCreate: "deferred";
|
|
65
|
+
readonly buildCreateMany: "deferred";
|
|
66
|
+
readonly buildUpdate: "deferred";
|
|
67
|
+
readonly buildUpdateMany: "deferred";
|
|
68
|
+
readonly buildDelete: "deferred";
|
|
69
|
+
readonly buildDeleteMany: "deferred";
|
|
70
|
+
readonly buildUpsert: "deferred";
|
|
71
|
+
};
|
|
72
|
+
/** A method name in the table accessor contract. */
|
|
73
|
+
export type TableMethod = keyof typeof TABLE_METHODS;
|
|
74
|
+
/**
|
|
75
|
+
* Public QueryInterface members that are SQL-engine internals (cache
|
|
76
|
+
* fingerprinting, the upsert lookup decision, a test hook), deliberately
|
|
77
|
+
* outside the accessor contract, so PowDB need not implement them.
|
|
78
|
+
*/
|
|
79
|
+
export type SqlInternalMember = 'collectWhereParams' | 'fingerprintWhere' | 'withFingerprint' | 'upsertNeedsLookup' | 'resetUnlimitedWarnings';
|
|
80
|
+
/** Public QueryInterface members classified neither as a table method nor as internal. */
|
|
81
|
+
type Unclassified = Exclude<keyof QueryInterface<object>, TableMethod | SqlInternalMember>;
|
|
82
|
+
/**
|
|
83
|
+
* Fails the build, naming the member, when QueryInterface gains a public
|
|
84
|
+
* member nobody classified: add it to TABLE_METHODS (and to PowqlInterface) or
|
|
85
|
+
* to SqlInternalMember.
|
|
86
|
+
*/
|
|
87
|
+
type AssertEveryMemberClassified<U extends never> = U;
|
|
88
|
+
export type EveryQueryInterfaceMemberClassified = AssertEveryMemberClassified<Unclassified>;
|
|
89
|
+
/** The table accessor contract every engine's accessor class implements. */
|
|
90
|
+
export type TableClient<T extends object, R extends object = {}, M extends TableInputTypes = DefaultInputTypes<T, R>> = Pick<QueryInterface<T, R, M>, TableMethod>;
|
|
91
|
+
/**
|
|
92
|
+
* View a factory-built accessor as the `QueryInterface` the client's public
|
|
93
|
+
* `table()` type names.
|
|
94
|
+
*
|
|
95
|
+
* Sound because the exhaustiveness check above guarantees `TableClient` holds
|
|
96
|
+
* every public QueryInterface member except the SQL internals, which nothing
|
|
97
|
+
* outside the SQL builder reaches through an accessor without first checking
|
|
98
|
+
* the member exists. The cast hides only private members.
|
|
99
|
+
*/
|
|
100
|
+
export declare function asQueryInterface<T extends object>(client: TableClient<T>): QueryInterface<T>;
|
|
101
|
+
export {};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* turbine-orm, the table accessor contract.
|
|
4
|
+
*
|
|
5
|
+
* `db.users` is a `QueryInterface` on the SQL engines and a `PowqlInterface` on
|
|
6
|
+
* PowDB. The second is a parallel class, not a subclass, so without a shared
|
|
7
|
+
* type the compiler cannot see a method one engine has and the other lacks, and
|
|
8
|
+
* the user meets it as `TypeError: ... is not a function` at run time.
|
|
9
|
+
*
|
|
10
|
+
* {@link TableClient} is that shared type. It is DERIVED from QueryInterface
|
|
11
|
+
* (a `Pick` of the classified methods), so the SQL builder stays the one source
|
|
12
|
+
* of truth for every signature, and `PowqlInterface implements TableClient`
|
|
13
|
+
* makes a missing or mismatched method a build error.
|
|
14
|
+
*
|
|
15
|
+
* Type-only imports: this module emits {@link TABLE_METHODS} and nothing else,
|
|
16
|
+
* so it adds no edge to the import graph.
|
|
17
|
+
*/
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
exports.TABLE_METHODS = void 0;
|
|
20
|
+
exports.asQueryInterface = asQueryInterface;
|
|
21
|
+
/**
|
|
22
|
+
* Every public method of a table accessor, with its routing class.
|
|
23
|
+
*
|
|
24
|
+
* `satisfies` refuses a key QueryInterface does not have; the exhaustiveness
|
|
25
|
+
* check below refuses a QueryInterface member missing from here.
|
|
26
|
+
*/
|
|
27
|
+
exports.TABLE_METHODS = {
|
|
28
|
+
findMany: 'read',
|
|
29
|
+
findFirst: 'read',
|
|
30
|
+
findFirstOrThrow: 'read',
|
|
31
|
+
findUnique: 'read',
|
|
32
|
+
findUniqueOrThrow: 'read',
|
|
33
|
+
count: 'read',
|
|
34
|
+
aggregate: 'read',
|
|
35
|
+
groupBy: 'read',
|
|
36
|
+
findManyStream: 'read',
|
|
37
|
+
findManyStreamBatches: 'read',
|
|
38
|
+
explain: 'primary',
|
|
39
|
+
cacheStats: 'primary',
|
|
40
|
+
create: 'write',
|
|
41
|
+
createMany: 'write',
|
|
42
|
+
update: 'write',
|
|
43
|
+
updateMany: 'write',
|
|
44
|
+
delete: 'write',
|
|
45
|
+
deleteMany: 'write',
|
|
46
|
+
upsert: 'write',
|
|
47
|
+
buildFindMany: 'deferred',
|
|
48
|
+
buildFindFirst: 'deferred',
|
|
49
|
+
buildFindFirstOrThrow: 'deferred',
|
|
50
|
+
buildFindUnique: 'deferred',
|
|
51
|
+
buildFindUniqueOrThrow: 'deferred',
|
|
52
|
+
buildCount: 'deferred',
|
|
53
|
+
buildAggregate: 'deferred',
|
|
54
|
+
buildGroupBy: 'deferred',
|
|
55
|
+
buildCreate: 'deferred',
|
|
56
|
+
buildCreateMany: 'deferred',
|
|
57
|
+
buildUpdate: 'deferred',
|
|
58
|
+
buildUpdateMany: 'deferred',
|
|
59
|
+
buildDelete: 'deferred',
|
|
60
|
+
buildDeleteMany: 'deferred',
|
|
61
|
+
buildUpsert: 'deferred',
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* View a factory-built accessor as the `QueryInterface` the client's public
|
|
65
|
+
* `table()` type names.
|
|
66
|
+
*
|
|
67
|
+
* Sound because the exhaustiveness check above guarantees `TableClient` holds
|
|
68
|
+
* every public QueryInterface member except the SQL internals, which nothing
|
|
69
|
+
* outside the SQL builder reaches through an accessor without first checking
|
|
70
|
+
* the member exists. The cast hides only private members.
|
|
71
|
+
*/
|
|
72
|
+
function asQueryInterface(client) {
|
|
73
|
+
return client;
|
|
74
|
+
}
|