turbine-orm 0.34.0 → 0.35.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 +26 -4
- package/dist/cjs/dialect.js +1 -0
- package/dist/cjs/errors.js +41 -1
- package/dist/cjs/index.js +3 -2
- package/dist/cjs/mssql.js +5 -0
- package/dist/cjs/mysql.js +4 -0
- package/dist/cjs/powdb.js +156 -24
- package/dist/cjs/powql.js +448 -39
- package/dist/cjs/query/builder.js +60 -0
- package/dist/cjs/sqlite.js +3 -0
- package/dist/client.d.ts +32 -5
- package/dist/client.js +26 -4
- package/dist/dialect.d.ts +13 -0
- package/dist/dialect.js +1 -0
- package/dist/errors.d.ts +36 -0
- package/dist/errors.js +39 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/mssql.js +5 -0
- package/dist/mysql.js +4 -0
- package/dist/powdb.d.ts +115 -9
- package/dist/powdb.js +157 -25
- package/dist/powql.d.ts +133 -3
- package/dist/powql.js +449 -40
- package/dist/query/builder.d.ts +36 -1
- package/dist/query/builder.js +60 -0
- package/dist/query/deferred.d.ts +6 -2
- package/dist/query/types.d.ts +10 -6
- package/dist/sqlite.js +3 -0
- package/package.json +3 -3
|
@@ -177,6 +177,11 @@ class QueryInterface {
|
|
|
177
177
|
warnOnUnlimited;
|
|
178
178
|
utcTimestamps;
|
|
179
179
|
preparedStatementsEnabled;
|
|
180
|
+
/**
|
|
181
|
+
* Whether the SQL template cache is active. Set once in the constructor.
|
|
182
|
+
* Mutable (not `readonly`) only so {@link withSqlCacheDisabled} can flip it
|
|
183
|
+
* off around a single synchronous compile (see {@link explain}).
|
|
184
|
+
*/
|
|
180
185
|
sqlCacheEnabled;
|
|
181
186
|
dialect;
|
|
182
187
|
/** Client-level default relation-loading strategy ('join' unless configured). */
|
|
@@ -870,6 +875,61 @@ class QueryInterface {
|
|
|
870
875
|
return deferred.transform(result);
|
|
871
876
|
});
|
|
872
877
|
}
|
|
878
|
+
/**
|
|
879
|
+
* Return the engine's query plan for a {@link findMany}-shaped query as plain
|
|
880
|
+
* text lines: a diagnostic surface for inspecting how the database will run a
|
|
881
|
+
* query (index usage, join strategy, scan type).
|
|
882
|
+
*
|
|
883
|
+
* The compiled SELECT is prefixed with the dialect's explain syntax
|
|
884
|
+
* (Postgres `EXPLAIN`, SQLite `EXPLAIN QUERY PLAN`, MySQL `EXPLAIN
|
|
885
|
+
* FORMAT=TREE`) and run as a read. The findMany args are compiled with the
|
|
886
|
+
* SQL template cache disabled, so an explain never reads or writes the shared
|
|
887
|
+
* cache. Middleware is NOT applied: the returned rows are plan text, not
|
|
888
|
+
* entity rows. Each result row is flattened to one line by joining its column
|
|
889
|
+
* values with a single space (Postgres returns one `QUERY PLAN` text column,
|
|
890
|
+
* SQLite's `EXPLAIN QUERY PLAN` returns four, MySQL's tree format one).
|
|
891
|
+
*
|
|
892
|
+
* Only `findMany` shapes are supported (where / orderBy / with / limit /
|
|
893
|
+
* pagination). Engines whose plan cannot be requested in-band from a compiled
|
|
894
|
+
* query (SQL Server, whose SHOWPLAN is a session toggle) throw
|
|
895
|
+
* {@link UnsupportedFeatureError} (E017).
|
|
896
|
+
*
|
|
897
|
+
* The plan text itself is engine-owned and NOT covered by semver: its content
|
|
898
|
+
* and formatting can change with the underlying database version.
|
|
899
|
+
*/
|
|
900
|
+
async explain(args) {
|
|
901
|
+
const explainSyntax = this.dialect.explainQuery;
|
|
902
|
+
if (!explainSyntax) {
|
|
903
|
+
throw new errors_js_1.UnsupportedFeatureError('explain()', this.dialect.name, 'This engine cannot explain a compiled query in-band.');
|
|
904
|
+
}
|
|
905
|
+
// Compile the findMany SQL with the cache disabled: the prefixed EXPLAIN
|
|
906
|
+
// statement is a one-off diagnostic and must never read or write the shared
|
|
907
|
+
// query-template cache.
|
|
908
|
+
const deferred = this.withSqlCacheDisabled(() => this.buildFindMany(args));
|
|
909
|
+
const sql = `${explainSyntax.prefix} ${deferred.sql}`;
|
|
910
|
+
this.currentAction = 'explain';
|
|
911
|
+
// No preparedName: keep the diagnostic statement out of the prepared path.
|
|
912
|
+
const result = await this.queryWithTimeout(sql, deferred.params, args?.timeout);
|
|
913
|
+
return result.rows.map((row) => Object.values(row)
|
|
914
|
+
.map((value) => (typeof value === 'string' ? value : String(value)))
|
|
915
|
+
.join(' '));
|
|
916
|
+
}
|
|
917
|
+
/**
|
|
918
|
+
* Run `fn` with the SQL template cache forced off, restoring the prior state
|
|
919
|
+
* afterward. Used by {@link explain}, whose one-off prefixed statement must
|
|
920
|
+
* neither read nor write the shared cache. `fn` is synchronous, so no query
|
|
921
|
+
* interleaves between the toggle and its restore.
|
|
922
|
+
*/
|
|
923
|
+
withSqlCacheDisabled(fn) {
|
|
924
|
+
const prev = this.sqlCacheEnabled;
|
|
925
|
+
this.sqlCacheEnabled = false;
|
|
926
|
+
try {
|
|
927
|
+
return fn();
|
|
928
|
+
}
|
|
929
|
+
finally {
|
|
930
|
+
this.sqlCacheEnabled = prev;
|
|
931
|
+
}
|
|
932
|
+
}
|
|
873
933
|
/**
|
|
874
934
|
* Emit a one-time `console.warn` when {@link findMany} is called without an
|
|
875
935
|
* explicit `limit`/`take` and `warnOnUnlimited` has not been disabled.
|
package/dist/cjs/sqlite.js
CHANGED
|
@@ -380,6 +380,9 @@ exports.sqliteDialect = {
|
|
|
380
380
|
supportsAdvisoryLock: false,
|
|
381
381
|
// No FROM-clause LATERAL: the opt-in lateral pick plan is Postgres-only.
|
|
382
382
|
supportsLateralJoin: false,
|
|
383
|
+
// SQLite explains a compiled query with `EXPLAIN QUERY PLAN` (four columns:
|
|
384
|
+
// id, parent, notused, detail), overriding the inherited Postgres `EXPLAIN`.
|
|
385
|
+
explainQuery: { prefix: 'EXPLAIN QUERY PLAN' },
|
|
383
386
|
// json_group_array / json_object have no inline ORDER BY argument, so every
|
|
384
387
|
// ordered to-many relation is forced through the inner-subquery rewrite.
|
|
385
388
|
aggSupportsInlineOrderBy: false,
|
package/dist/client.d.ts
CHANGED
|
@@ -181,13 +181,17 @@ export interface TurbineConfig {
|
|
|
181
181
|
* Default strategy for resolving `with`-clause relations, applied to every
|
|
182
182
|
* `findMany`/`findUnique`/`findFirst` unless overridden per query.
|
|
183
183
|
*
|
|
184
|
-
* - `'join'
|
|
185
|
-
* `json_agg(json_build_object(...))` subqueries.
|
|
186
|
-
*
|
|
184
|
+
* - `'join'`: one SQL statement using correlated
|
|
185
|
+
* `json_agg(json_build_object(...))` subqueries. On PowDB, `'join'` opts
|
|
186
|
+
* into native server-side joins where eligible instead.
|
|
187
|
+
* - `'batched'`: run the base query, then one flat follow-up query per
|
|
187
188
|
* relation (`WHERE fk = ANY($1)`), stitching children client-side. Wins
|
|
188
189
|
* when child FK columns are unindexed or result sets are large.
|
|
189
190
|
*
|
|
190
|
-
* Precedence: per-query `relationLoadStrategy` arg > this config >
|
|
191
|
+
* Precedence: per-query `relationLoadStrategy` arg > this config > the engine
|
|
192
|
+
* default. On SQL engines the default is `'join'`; on PowDB the default is the
|
|
193
|
+
* batched loaders (an ineligible relation falls back to them silently even
|
|
194
|
+
* under `'join'`).
|
|
191
195
|
*/
|
|
192
196
|
relationLoadStrategy?: RelationLoadStrategy;
|
|
193
197
|
/**
|
|
@@ -341,11 +345,34 @@ export declare class TransactionClient {
|
|
|
341
345
|
readonly schema: SchemaMetadata;
|
|
342
346
|
private readonly middlewares;
|
|
343
347
|
private readonly queryOptions?;
|
|
348
|
+
/**
|
|
349
|
+
* The parent pool this transaction runs on. Only its `readonly` and
|
|
350
|
+
* `capabilities` are read (both PowDB-only flags), so the transaction-scoped
|
|
351
|
+
* proxy pool built by {@link createTxPool} carries them through: without this
|
|
352
|
+
* a read-only client's `$transaction` writes bypass the E018 guard, and an
|
|
353
|
+
* older-engine client falls back to ALL_POWDB_CAPABILITIES inside the tx
|
|
354
|
+
* (emitting join PowQL a pre-0.13 engine rejects). Undefined / absent flags
|
|
355
|
+
* for a plain pg pool leave the proxy unchanged.
|
|
356
|
+
*/
|
|
357
|
+
private readonly sourcePool?;
|
|
344
358
|
private readonly tableCache;
|
|
345
359
|
private savepointCounter;
|
|
346
360
|
/** Active SQL dialect — owns savepoint keywords and raw-SQL placeholders. */
|
|
347
361
|
private readonly dialect;
|
|
348
|
-
constructor(client: pg.PoolClient, schema: SchemaMetadata, middlewares: Middleware[], queryOptions?: QueryInterfaceOptions | undefined
|
|
362
|
+
constructor(client: pg.PoolClient, schema: SchemaMetadata, middlewares: Middleware[], queryOptions?: QueryInterfaceOptions | undefined,
|
|
363
|
+
/**
|
|
364
|
+
* The parent pool this transaction runs on. Only its `readonly` and
|
|
365
|
+
* `capabilities` are read (both PowDB-only flags), so the transaction-scoped
|
|
366
|
+
* proxy pool built by {@link createTxPool} carries them through: without this
|
|
367
|
+
* a read-only client's `$transaction` writes bypass the E018 guard, and an
|
|
368
|
+
* older-engine client falls back to ALL_POWDB_CAPABILITIES inside the tx
|
|
369
|
+
* (emitting join PowQL a pre-0.13 engine rejects). Undefined / absent flags
|
|
370
|
+
* for a plain pg pool leave the proxy unchanged.
|
|
371
|
+
*/
|
|
372
|
+
sourcePool?: {
|
|
373
|
+
readonly readonly?: boolean;
|
|
374
|
+
readonly capabilities?: unknown;
|
|
375
|
+
} | undefined);
|
|
349
376
|
/**
|
|
350
377
|
* Get a QueryInterface for a table within this transaction.
|
|
351
378
|
* Uses the dedicated transaction connection instead of the pool.
|
package/dist/client.js
CHANGED
|
@@ -104,15 +104,27 @@ export class TransactionClient {
|
|
|
104
104
|
schema;
|
|
105
105
|
middlewares;
|
|
106
106
|
queryOptions;
|
|
107
|
+
sourcePool;
|
|
107
108
|
tableCache = new Map();
|
|
108
109
|
savepointCounter = 0;
|
|
109
110
|
/** Active SQL dialect — owns savepoint keywords and raw-SQL placeholders. */
|
|
110
111
|
dialect;
|
|
111
|
-
constructor(client, schema, middlewares, queryOptions
|
|
112
|
+
constructor(client, schema, middlewares, queryOptions,
|
|
113
|
+
/**
|
|
114
|
+
* The parent pool this transaction runs on. Only its `readonly` and
|
|
115
|
+
* `capabilities` are read (both PowDB-only flags), so the transaction-scoped
|
|
116
|
+
* proxy pool built by {@link createTxPool} carries them through: without this
|
|
117
|
+
* a read-only client's `$transaction` writes bypass the E018 guard, and an
|
|
118
|
+
* older-engine client falls back to ALL_POWDB_CAPABILITIES inside the tx
|
|
119
|
+
* (emitting join PowQL a pre-0.13 engine rejects). Undefined / absent flags
|
|
120
|
+
* for a plain pg pool leave the proxy unchanged.
|
|
121
|
+
*/
|
|
122
|
+
sourcePool) {
|
|
112
123
|
this.client = client;
|
|
113
124
|
this.schema = schema;
|
|
114
125
|
this.middlewares = middlewares;
|
|
115
126
|
this.queryOptions = queryOptions;
|
|
127
|
+
this.sourcePool = sourcePool;
|
|
116
128
|
this.dialect = queryOptions?.dialect ?? postgresDialect;
|
|
117
129
|
// Auto-create typed table accessors for all tables in the schema
|
|
118
130
|
for (const tableName of Object.keys(schema.tables)) {
|
|
@@ -192,7 +204,7 @@ export class TransactionClient {
|
|
|
192
204
|
const client = this.client;
|
|
193
205
|
// Return a minimal pool-compatible object that routes queries
|
|
194
206
|
// through the transaction client
|
|
195
|
-
|
|
207
|
+
const txPool = {
|
|
196
208
|
query: async (textOrConfig, values) => {
|
|
197
209
|
try {
|
|
198
210
|
if (typeof textOrConfig === 'string') {
|
|
@@ -209,6 +221,14 @@ export class TransactionClient {
|
|
|
209
221
|
},
|
|
210
222
|
connect: () => Promise.resolve(client),
|
|
211
223
|
};
|
|
224
|
+
// Carry the parent pool's PowDB-only flags through so a transaction-scoped
|
|
225
|
+
// PowqlInterface reads the same read-only guard and capabilities it would
|
|
226
|
+
// outside the transaction (a plain pg pool has neither, so nothing changes).
|
|
227
|
+
if (this.sourcePool?.readonly !== undefined)
|
|
228
|
+
txPool.readonly = this.sourcePool.readonly;
|
|
229
|
+
if (this.sourcePool?.capabilities !== undefined)
|
|
230
|
+
txPool.capabilities = this.sourcePool.capabilities;
|
|
231
|
+
return txPool;
|
|
212
232
|
}
|
|
213
233
|
}
|
|
214
234
|
// ---------------------------------------------------------------------------
|
|
@@ -876,8 +896,10 @@ export class TurbineClient {
|
|
|
876
896
|
await client.query(cfg.sql, cfg.params);
|
|
877
897
|
}
|
|
878
898
|
}
|
|
879
|
-
// Create the transaction client with typed table accessors
|
|
880
|
-
|
|
899
|
+
// Create the transaction client with typed table accessors. Pass the
|
|
900
|
+
// parent pool so its read-only guard + PowDB capabilities flow into the
|
|
901
|
+
// transaction-scoped proxy pool (see TransactionClient.createTxPool).
|
|
902
|
+
const tx = new TransactionClient(client, this.schema, this.middlewares, this.queryOptions, this.pool);
|
|
881
903
|
// Dynamically attach table accessors to tx
|
|
882
904
|
for (const tableName of Object.keys(this.schema.tables)) {
|
|
883
905
|
const camelName = tableName.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
|
package/dist/dialect.d.ts
CHANGED
|
@@ -302,6 +302,19 @@ export interface Dialect {
|
|
|
302
302
|
* lateral plan (else E017). PostgreSQL only in this release.
|
|
303
303
|
*/
|
|
304
304
|
readonly supportsLateralJoin?: boolean;
|
|
305
|
+
/**
|
|
306
|
+
* How this dialect surfaces a query plan for a compiled SELECT. When present,
|
|
307
|
+
* `QueryInterface.explain()` prepends `prefix` (plus a single space) to the
|
|
308
|
+
* compiled findMany SQL and runs it as a read, returning the plan text lines.
|
|
309
|
+
* PostgreSQL / CockroachDB / YugabyteDB and MySQL use `EXPLAIN`, SQLite
|
|
310
|
+
* `EXPLAIN QUERY PLAN`. Absent means the engine
|
|
311
|
+
* cannot explain a compiled query in-band (SQL Server, whose SHOWPLAN needs a
|
|
312
|
+
* separate session toggle), so `QueryInterface.explain()` throws E017.
|
|
313
|
+
* Optional: dialects that predate this hook keep throwing E017.
|
|
314
|
+
*/
|
|
315
|
+
readonly explainQuery?: {
|
|
316
|
+
prefix: string;
|
|
317
|
+
};
|
|
305
318
|
/** Build a dialect-specific RETURNING clause. Return an empty string when unsupported. */
|
|
306
319
|
buildReturningClause(selection?: string): string;
|
|
307
320
|
/** Build a single-row INSERT statement. Inputs are SQL-ready quoted fragments. */
|
package/dist/dialect.js
CHANGED
package/dist/errors.d.ts
CHANGED
|
@@ -23,6 +23,7 @@ export declare const TurbineErrorCode: {
|
|
|
23
23
|
readonly OPTIMISTIC_LOCK: "TURBINE_E015";
|
|
24
24
|
readonly EXCLUSION_VIOLATION: "TURBINE_E016";
|
|
25
25
|
readonly UNSUPPORTED_FEATURE: "TURBINE_E017";
|
|
26
|
+
readonly READ_ONLY: "TURBINE_E018";
|
|
26
27
|
};
|
|
27
28
|
export type TurbineErrorCode = (typeof TurbineErrorCode)[keyof typeof TurbineErrorCode];
|
|
28
29
|
/** Base error class for all Turbine errors */
|
|
@@ -303,6 +304,41 @@ export declare class UnsupportedFeatureError extends TurbineError {
|
|
|
303
304
|
readonly dialect: string;
|
|
304
305
|
constructor(feature: string, dialect: string, hint?: string);
|
|
305
306
|
}
|
|
307
|
+
/**
|
|
308
|
+
* Thrown when a write or DDL statement is refused because the target is
|
|
309
|
+
* read-only. Two shapes reach here, both on PowDB:
|
|
310
|
+
* - an embedded database opened read-only for snapshot serving refuses a write
|
|
311
|
+
* with `readonly mode: statement requires a writer …`;
|
|
312
|
+
* - a networked read-only role refuses a write with `permission denied: role
|
|
313
|
+
* '<role>' cannot execute write statements` (translated by `wrapPowdbError`).
|
|
314
|
+
* It is also raised locally, before the wire, when a write is issued on a pool
|
|
315
|
+
* the caller marked read-only (fail-fast). The message carries the engine text
|
|
316
|
+
* plus a hint to route writes to a writable primary.
|
|
317
|
+
*
|
|
318
|
+
* NOT retryable: the same write against the same read-only target fails
|
|
319
|
+
* identically; route it to a writable primary instead.
|
|
320
|
+
*/
|
|
321
|
+
export declare class ReadOnlyError extends TurbineError {
|
|
322
|
+
/**
|
|
323
|
+
* Why the write was refused. `'snapshot'`: the database itself is read-only
|
|
324
|
+
* (snapshot serving, an embedded `readonly: true` open, or the client-level
|
|
325
|
+
* fail-fast flag), so NOTHING can write here and writes must route to the
|
|
326
|
+
* primary. `'rbac'`: the database is writable but THIS connection's role may
|
|
327
|
+
* not write (per-connection permission), so re-authenticating may suffice.
|
|
328
|
+
*/
|
|
329
|
+
readonly reason: 'snapshot' | 'rbac';
|
|
330
|
+
/**
|
|
331
|
+
* @param detail human-readable description of the refused write (the engine
|
|
332
|
+
* message, or a local fail-fast description). A "route writes to a writable
|
|
333
|
+
* primary" hint is always appended.
|
|
334
|
+
* @param options optional driver `cause` to preserve when wrapping a refusal,
|
|
335
|
+
* and the refusal `reason` (default `'snapshot'`).
|
|
336
|
+
*/
|
|
337
|
+
constructor(detail: string, options?: {
|
|
338
|
+
cause?: unknown;
|
|
339
|
+
reason?: 'snapshot' | 'rbac';
|
|
340
|
+
});
|
|
341
|
+
}
|
|
306
342
|
/**
|
|
307
343
|
* Translate a pg driver error into a typed Turbine error.
|
|
308
344
|
* If the error doesn't match a known constraint code, returns it unchanged.
|
package/dist/errors.js
CHANGED
|
@@ -23,6 +23,7 @@ export const TurbineErrorCode = {
|
|
|
23
23
|
OPTIMISTIC_LOCK: 'TURBINE_E015',
|
|
24
24
|
EXCLUSION_VIOLATION: 'TURBINE_E016',
|
|
25
25
|
UNSUPPORTED_FEATURE: 'TURBINE_E017',
|
|
26
|
+
READ_ONLY: 'TURBINE_E018',
|
|
26
27
|
};
|
|
27
28
|
/**
|
|
28
29
|
* Prefix a human message with its stable error code so logs are greppable
|
|
@@ -479,6 +480,44 @@ export class UnsupportedFeatureError extends TurbineError {
|
|
|
479
480
|
this.dialect = dialect;
|
|
480
481
|
}
|
|
481
482
|
}
|
|
483
|
+
/**
|
|
484
|
+
* Thrown when a write or DDL statement is refused because the target is
|
|
485
|
+
* read-only. Two shapes reach here, both on PowDB:
|
|
486
|
+
* - an embedded database opened read-only for snapshot serving refuses a write
|
|
487
|
+
* with `readonly mode: statement requires a writer …`;
|
|
488
|
+
* - a networked read-only role refuses a write with `permission denied: role
|
|
489
|
+
* '<role>' cannot execute write statements` (translated by `wrapPowdbError`).
|
|
490
|
+
* It is also raised locally, before the wire, when a write is issued on a pool
|
|
491
|
+
* the caller marked read-only (fail-fast). The message carries the engine text
|
|
492
|
+
* plus a hint to route writes to a writable primary.
|
|
493
|
+
*
|
|
494
|
+
* NOT retryable: the same write against the same read-only target fails
|
|
495
|
+
* identically; route it to a writable primary instead.
|
|
496
|
+
*/
|
|
497
|
+
export class ReadOnlyError extends TurbineError {
|
|
498
|
+
/**
|
|
499
|
+
* Why the write was refused. `'snapshot'`: the database itself is read-only
|
|
500
|
+
* (snapshot serving, an embedded `readonly: true` open, or the client-level
|
|
501
|
+
* fail-fast flag), so NOTHING can write here and writes must route to the
|
|
502
|
+
* primary. `'rbac'`: the database is writable but THIS connection's role may
|
|
503
|
+
* not write (per-connection permission), so re-authenticating may suffice.
|
|
504
|
+
*/
|
|
505
|
+
reason;
|
|
506
|
+
/**
|
|
507
|
+
* @param detail human-readable description of the refused write (the engine
|
|
508
|
+
* message, or a local fail-fast description). A "route writes to a writable
|
|
509
|
+
* primary" hint is always appended.
|
|
510
|
+
* @param options optional driver `cause` to preserve when wrapping a refusal,
|
|
511
|
+
* and the refusal `reason` (default `'snapshot'`).
|
|
512
|
+
*/
|
|
513
|
+
constructor(detail, options) {
|
|
514
|
+
super(TurbineErrorCode.READ_ONLY, `[turbine] ${detail} Route writes to a writable primary.`, {
|
|
515
|
+
cause: options?.cause,
|
|
516
|
+
});
|
|
517
|
+
this.name = 'ReadOnlyError';
|
|
518
|
+
this.reason = options?.reason ?? 'snapshot';
|
|
519
|
+
}
|
|
520
|
+
}
|
|
482
521
|
/**
|
|
483
522
|
* Parse column names out of a pg `detail` string like:
|
|
484
523
|
* "Key (email)=(foo@bar) already exists."
|
package/dist/index.d.ts
CHANGED
|
@@ -37,13 +37,13 @@ export { alloydb, cockroachdb, postgresql, timescale, yugabytedb } from './adapt
|
|
|
37
37
|
export { type Middleware, type MiddlewareNext, type MiddlewareParams, type PgCompatPool, type PgCompatPoolClient, type PgCompatQueryResult, type RetryOptions, TransactionClient, type TransactionOptions, TurbineClient, type TurbineConfig, type TurbineDriver, withRetry, } from './client.js';
|
|
38
38
|
export type { BuiltStatement, BulkInsertStatementInput, ColumnDefinitionInput, ColumnTypeInput, CreateIndexStatementInput, CreateTableStatementInput, Dialect, DialectIntrospector, DialectMigrator, DialectName, InsertStatementInput, IntrospectOptions as DialectIntrospectOptions, ResultStrategy, StreamableConnection, UpsertStatementInput, } from './dialect.js';
|
|
39
39
|
export { postgresDialect } from './dialect.js';
|
|
40
|
-
export { CheckConstraintError, CircularRelationError, ConnectionError, DeadlockError, type ErrorMessageMode, ExclusionConstraintError, ForeignKeyError, getErrorMessageMode, MigrationError, NotFoundError, NotNullViolationError, OptimisticLockError, PipelineError, type PipelineResultSlot, RelationError, SerializationFailureError, setErrorMessageMode, TimeoutError, TurbineError, TurbineErrorCode, UniqueConstraintError, UnsupportedFeatureError, ValidationError, wrapPgError, } from './errors.js';
|
|
40
|
+
export { CheckConstraintError, CircularRelationError, ConnectionError, DeadlockError, type ErrorMessageMode, ExclusionConstraintError, ForeignKeyError, getErrorMessageMode, MigrationError, NotFoundError, NotNullViolationError, OptimisticLockError, PipelineError, type PipelineResultSlot, ReadOnlyError, RelationError, SerializationFailureError, setErrorMessageMode, TimeoutError, TurbineError, TurbineErrorCode, UniqueConstraintError, UnsupportedFeatureError, ValidationError, wrapPgError, } from './errors.js';
|
|
41
41
|
export { type GenerateOptions, generate } from './generate.js';
|
|
42
42
|
export { type IntrospectOptions, introspect } from './introspect.js';
|
|
43
43
|
export { executeNestedCreate, executeNestedUpdate, hasRelationFields, type NestedWriteContext, } from './nested-write.js';
|
|
44
44
|
export type { ObserveConfig, ObserveHandle } from './observe.js';
|
|
45
45
|
export { executePipeline, type PipelineOptions, type PipelineResults, pipelineSupported } from './pipeline.js';
|
|
46
|
-
export { type AggregateArgs, type AggregateResult, type ArrayFilter, type ColumnRef, type ConnectOrCreateOp, type CountArgs, type CreateArgs, type CreateDataInput, type CreateManyArgs, type DeferredQuery, type DeleteArgs, type DeleteManyArgs, type FieldResult, type FindManyArgs, type FindManyStreamArgs, type FindUniqueArgs, type GlobalFilters, type GroupByAggregateSpec, type GroupByArgs, type GroupByDistinctOn, type HavingClause, type JsonFilter, type JsonPathAggregateTarget, type JsonPathGroupKey, type JsonPathOrderBy, type MiddlewareFn, type NestedCreateOp, type NestedUpdateOp, type NestedUpdateOpItem, type NestedUpsertOpItem, type OmitResult, type OrderByClause, type OrderDirection, type QueryEvent, type QueryEventListener, QueryInterface, type QueryResult, type RelationDescriptor, type RelationFilter, type RelationPickBy, type RelationPickOrderBy, type SelectResult, type SkipGlobalFilters, type TextSearchFilter, type TypedWithClause, type UpdateArgs, type UpdateDataInput, type UpdateInput, type UpdateManyArgs, type UpdateOperatorInput, type UpsertArgs, type VectorDistanceFilter, type VectorFilter, type VectorMetric, type VectorOrderBy, type VectorOrderByDistance, type WhereClause, type WhereOperator, type WhereValue, type WithClause, type WithOptions, type WithResult, } from './query/index.js';
|
|
46
|
+
export { type AggregateArgs, type AggregateResult, type ArrayFilter, type ColumnRef, type ConnectOrCreateOp, type CountArgs, type CreateArgs, type CreateDataInput, type CreateManyArgs, type DeferredQuery, type DeleteArgs, type DeleteManyArgs, type FieldResult, type FindManyArgs, type FindManyStreamArgs, type FindUniqueArgs, type GlobalFilters, type GroupByAggregateSpec, type GroupByArgs, type GroupByDistinctOn, type HavingClause, type JsonFilter, type JsonPathAggregateTarget, type JsonPathGroupKey, type JsonPathOrderBy, type MiddlewareFn, type NestedCreateOp, type NestedUpdateOp, type NestedUpdateOpItem, type NestedUpsertOpItem, type OmitResult, type OrderByClause, type OrderDirection, type QueryEvent, type QueryEventListener, QueryInterface, type QueryResult, type RelationDescriptor, type RelationFilter, type RelationLoadStrategy, type RelationPickBy, type RelationPickOrderBy, type SelectResult, type SkipGlobalFilters, type TextSearchFilter, type TypedWithClause, type UpdateArgs, type UpdateDataInput, type UpdateInput, type UpdateManyArgs, type UpdateOperatorInput, type UpsertArgs, type VectorDistanceFilter, type VectorFilter, type VectorMetric, type VectorOrderBy, type VectorOrderByDistance, type WhereClause, type WhereOperator, type WhereValue, type WithClause, type WithOptions, type WithResult, } from './query/index.js';
|
|
47
47
|
export { type ActiveSubscription, type NotificationHandler, type Subscription, validateChannel } from './realtime.js';
|
|
48
48
|
export type { CheckMetadata, ColumnMetadata, IndexMetadata, ReferentialAction, RelationDef, SchemaMetadata, TableMetadata, } from './schema.js';
|
|
49
49
|
export { camelToSnake, isDateType, normalizeKeyColumns, pgArrayType, pgTypeToTs, singularize, snakeToCamel, snakeToPascal, } from './schema.js';
|
package/dist/index.js
CHANGED
|
@@ -37,7 +37,7 @@ export { alloydb, cockroachdb, postgresql, timescale, yugabytedb } from './adapt
|
|
|
37
37
|
export { TransactionClient, TurbineClient, withRetry, } from './client.js';
|
|
38
38
|
export { postgresDialect } from './dialect.js';
|
|
39
39
|
// Error types
|
|
40
|
-
export { CheckConstraintError, CircularRelationError, ConnectionError, DeadlockError, ExclusionConstraintError, ForeignKeyError, getErrorMessageMode, MigrationError, NotFoundError, NotNullViolationError, OptimisticLockError, PipelineError, RelationError, SerializationFailureError, setErrorMessageMode, TimeoutError, TurbineError, TurbineErrorCode, UniqueConstraintError, UnsupportedFeatureError, ValidationError, wrapPgError, } from './errors.js';
|
|
40
|
+
export { CheckConstraintError, CircularRelationError, ConnectionError, DeadlockError, ExclusionConstraintError, ForeignKeyError, getErrorMessageMode, MigrationError, NotFoundError, NotNullViolationError, OptimisticLockError, PipelineError, ReadOnlyError, RelationError, SerializationFailureError, setErrorMessageMode, TimeoutError, TurbineError, TurbineErrorCode, UniqueConstraintError, UnsupportedFeatureError, ValidationError, wrapPgError, } from './errors.js';
|
|
41
41
|
// Code generation
|
|
42
42
|
export { generate } from './generate.js';
|
|
43
43
|
// Introspection
|
package/dist/mssql.js
CHANGED
|
@@ -472,6 +472,11 @@ export const mssqlDialect = {
|
|
|
472
472
|
supportsLateralJoin: false,
|
|
473
473
|
// sp_getapplock / sp_releaseapplock exist (used by a future migrate adapter).
|
|
474
474
|
supportsAdvisoryLock: true,
|
|
475
|
+
// No in-band EXPLAIN: SQL Server's SHOWPLAN is a session toggle
|
|
476
|
+
// (SET SHOWPLAN_ALL ON), not a statement prefix, so a compiled query cannot
|
|
477
|
+
// be explained in one round-trip. Override the inherited Postgres `EXPLAIN`
|
|
478
|
+
// to absent → QueryInterface.explain() throws E017.
|
|
479
|
+
explainQuery: undefined,
|
|
475
480
|
// FOR JSON over zero rows is NULL → coalesced in the relation override.
|
|
476
481
|
aggSupportsInlineOrderBy: false,
|
|
477
482
|
jsonPathSupport: 'limited',
|
package/dist/mysql.js
CHANGED
|
@@ -373,6 +373,10 @@ export const mysqlDialect = {
|
|
|
373
373
|
supportsLateralJoin: false,
|
|
374
374
|
// GET_LOCK / RELEASE_LOCK exist (used by a future migrate adapter).
|
|
375
375
|
supportsAdvisoryLock: true,
|
|
376
|
+
// Plain `EXPLAIN` (one row of tabular plan columns) works on every supported
|
|
377
|
+
// MySQL 8.0.x; the readable `FORMAT=TREE` variant only exists from 8.0.16 and
|
|
378
|
+
// the engine floor here is 8.0.0. Plan text is a diagnostic, not a contract.
|
|
379
|
+
explainQuery: { prefix: 'EXPLAIN' },
|
|
376
380
|
// JSON_ARRAYAGG has no inline ORDER BY argument → force the inner-subquery
|
|
377
381
|
// rewrite for every ordered to-many relation.
|
|
378
382
|
aggSupportsInlineOrderBy: false,
|
package/dist/powdb.d.ts
CHANGED
|
@@ -252,11 +252,13 @@ export interface PowdbCapabilities {
|
|
|
252
252
|
docFieldIndexes: boolean;
|
|
253
253
|
/** ≥ 0.10: `schema` / `describe` introspection statements. */
|
|
254
254
|
introspection: boolean;
|
|
255
|
+
/** ≥ 0.13: server-side joins, hash-accelerated and bounded. */
|
|
256
|
+
serverJoins: boolean;
|
|
255
257
|
/** Networked only: server ≥ 0.13 AND the client exposes `queryNativeRaw`. */
|
|
256
258
|
nativeRaw: boolean;
|
|
257
259
|
}
|
|
258
260
|
/** The feature-gate capability keys (everything except the version/nativeRaw metadata). */
|
|
259
|
-
type PowdbFeatureKey = 'jsonDocs' | 'docFieldIndexes' | 'introspection';
|
|
261
|
+
type PowdbFeatureKey = 'jsonDocs' | 'docFieldIndexes' | 'introspection' | 'serverJoins';
|
|
260
262
|
/**
|
|
261
263
|
* Trusted-caller default: every FEATURE gate on, engine version unknown. Used
|
|
262
264
|
* for a directly-constructed {@link PowdbPool} / {@link PowdbEmbeddedPool} that
|
|
@@ -439,6 +441,15 @@ export interface PowdbPoolOptions {
|
|
|
439
441
|
* Default `false` (typed-error-only).
|
|
440
442
|
*/
|
|
441
443
|
retryStaleReads?: boolean;
|
|
444
|
+
/**
|
|
445
|
+
* Mark this pool read-only: {@link PowqlInterface}'s exec seam then fails a
|
|
446
|
+
* write (or a tx-control `begin`) fast with a {@link ReadOnlyError} (E018)
|
|
447
|
+
* before it reaches the wire. An `{ embedded, readonly: true }` target forces
|
|
448
|
+
* this true; a networked pool bound to a read-only role can also set it so
|
|
449
|
+
* writes are rejected locally instead of round-tripping to the engine's
|
|
450
|
+
* refusal. Default `false`.
|
|
451
|
+
*/
|
|
452
|
+
readonly?: boolean;
|
|
442
453
|
}
|
|
443
454
|
/**
|
|
444
455
|
* A {@link PgCompatPool} backed by a `@zvndev/powdb-client` `Pool`. The query
|
|
@@ -476,6 +487,13 @@ export declare class PowdbPool implements PgCompatPool {
|
|
|
476
487
|
readonly capabilities: PowdbCapabilities;
|
|
477
488
|
/** Opt-in first-statement-read replay on a stale wire frame (read by {@link PowqlInterface}). */
|
|
478
489
|
readonly retryStaleReads: boolean;
|
|
490
|
+
/**
|
|
491
|
+
* True when the caller marked this pool read-only (`readonly: true`). Read by
|
|
492
|
+
* {@link PowqlInterface}'s exec seam to fail writes fast with E018 before the
|
|
493
|
+
* wire; the engine's own read-only-role refusal (mapped by
|
|
494
|
+
* {@link wrapPowdbError}) is the backstop for raw / injected paths.
|
|
495
|
+
*/
|
|
496
|
+
readonly readonly: boolean;
|
|
479
497
|
constructor(pool: PowdbClientPool, toParam?: (v: unknown, i: number) => PowdbParam, options?: PowdbPoolOptions);
|
|
480
498
|
/**
|
|
481
499
|
* Run one statement on `c`, choosing the lossless native typed wire when the
|
|
@@ -503,6 +521,14 @@ interface EmbeddedQueryResult {
|
|
|
503
521
|
affected?: bigint;
|
|
504
522
|
message?: string;
|
|
505
523
|
}
|
|
524
|
+
/**
|
|
525
|
+
* The embedded addon's native typed result (`@zvndev/powdb-embedded` ≥ 0.14).
|
|
526
|
+
* Mirrors {@link PowdbRawNativeResult}, the same tagged {@link PowdbWireValue}
|
|
527
|
+
* cells (embedded `bytes` arrive as a `Buffer`, which IS a `Uint8Array`, so the
|
|
528
|
+
* decode path is unchanged), including the `message` kind for DDL / status
|
|
529
|
+
* replies, which {@link adaptNativeResult}'s default branch handles at runtime.
|
|
530
|
+
*/
|
|
531
|
+
type EmbeddedNativeResult = PowdbRawNativeResult;
|
|
506
532
|
/** A single in-process embedded database handle (`@zvndev/powdb-embedded`). */
|
|
507
533
|
interface EmbeddedDatabase {
|
|
508
534
|
query(powql: string): EmbeddedQueryResult;
|
|
@@ -511,6 +537,32 @@ interface EmbeddedDatabase {
|
|
|
511
537
|
isPoisoned(): boolean;
|
|
512
538
|
/** WAL durability selector — `@zvndev/powdb-embedded` ≥ 0.7.1. */
|
|
513
539
|
setSyncMode?(mode: string): void;
|
|
540
|
+
/**
|
|
541
|
+
* Lossless typed native wire (`@zvndev/powdb-embedded` ≥ 0.14). All optional
|
|
542
|
+
* and feature-detected: an older addon omits them, so {@link PowdbEmbeddedPool}
|
|
543
|
+
* falls back to {@link materializePowql} + {@link query}. `queryWithParams`
|
|
544
|
+
* binds positional `$N` params as {@link PowdbParam} values (the NativeParam
|
|
545
|
+
* union) instead of materializing literals.
|
|
546
|
+
*/
|
|
547
|
+
queryNative?(powql: string): EmbeddedNativeResult;
|
|
548
|
+
queryReadonlyNative?(powql: string): EmbeddedNativeResult;
|
|
549
|
+
queryWithParams?(powql: string, params: PowdbParam[]): EmbeddedNativeResult;
|
|
550
|
+
/** Checkpoint-flushing close (`@zvndev/powdb-embedded` ≥ 0.14). Optional (feature-detected). */
|
|
551
|
+
close?(): void;
|
|
552
|
+
}
|
|
553
|
+
interface EmbeddedModule {
|
|
554
|
+
Database: {
|
|
555
|
+
open(dir: string): EmbeddedDatabase;
|
|
556
|
+
/** Open with a per-query memory budget — `@zvndev/powdb-embedded` ≥ 0.7.1. */
|
|
557
|
+
openWithMemoryLimit?(dir: string, limitBytes: number): EmbeddedDatabase;
|
|
558
|
+
/**
|
|
559
|
+
* Open a read-only handle for snapshot serving (`@zvndev/powdb-embedded` ≥
|
|
560
|
+
* 0.14). Optional (feature-detected); a write through such a handle is
|
|
561
|
+
* refused with `readonly mode: statement requires a writer …` (→ E018).
|
|
562
|
+
*/
|
|
563
|
+
openReadOnly?(dir: string): EmbeddedDatabase;
|
|
564
|
+
openReadOnlyWithMemoryLimit?(dir: string, limitBytes: number): EmbeddedDatabase;
|
|
565
|
+
};
|
|
514
566
|
}
|
|
515
567
|
/**
|
|
516
568
|
* Encode a JS value as a **PowQL literal** for the embedded driver, which takes
|
|
@@ -539,10 +591,14 @@ export declare function encodePowqlLiteral(value: unknown): string;
|
|
|
539
591
|
export declare function materializePowql(powql: string, params: unknown[]): string;
|
|
540
592
|
/**
|
|
541
593
|
* A {@link PgCompatPool} backed by an in-process `@zvndev/powdb-embedded`
|
|
542
|
-
* `Database`.
|
|
543
|
-
*
|
|
544
|
-
*
|
|
545
|
-
*
|
|
594
|
+
* `Database`. On the addon's typed native wire (≥ 0.14, when
|
|
595
|
+
* `capabilities.nativeRaw` is set) this pool binds positional `$N` params via
|
|
596
|
+
* `queryWithParams` and decodes the typed cells, exactly like the networked
|
|
597
|
+
* transport. On an older addon (no `queryWithParams`) it falls back to the
|
|
598
|
+
* legacy string wire, which takes **no params array** (its `query(powql)`
|
|
599
|
+
* accepts only a string), so each positional `$N` is materialized into a PowQL
|
|
600
|
+
* literal via {@link materializePowql} before the text is handed to the engine.
|
|
601
|
+
* One handle, single connection: transaction keywords (`begin`/`commit`/
|
|
546
602
|
* `rollback`) are issued serially as ordinary queries.
|
|
547
603
|
*/
|
|
548
604
|
export declare class PowdbEmbeddedPool implements PgCompatPool {
|
|
@@ -563,14 +619,24 @@ export declare class PowdbEmbeddedPool implements PgCompatPool {
|
|
|
563
619
|
private readonly poolHoldRef;
|
|
564
620
|
/**
|
|
565
621
|
* Feature capabilities of the embedded engine (resolved from the addon
|
|
566
|
-
* package version). `nativeRaw` is
|
|
567
|
-
*
|
|
622
|
+
* package version). `nativeRaw` is true when the addon is ≥ 0.14 and the
|
|
623
|
+
* opened handle exposes `queryWithParams` (the typed native wire); an older
|
|
624
|
+
* addon has no such method, so it stays false and the legacy string wire is
|
|
625
|
+
* used.
|
|
568
626
|
*/
|
|
569
627
|
readonly capabilities: PowdbCapabilities;
|
|
570
628
|
/** Carried for surface uniformity with {@link PowdbPool}; inert on embedded (no protocol_error frames). */
|
|
571
629
|
readonly retryStaleReads: boolean;
|
|
630
|
+
/**
|
|
631
|
+
* True when this pool was opened read-only (an `{ embedded, readonly: true }`
|
|
632
|
+
* target, or a directly-constructed pool passed `readonly: true`). Read by
|
|
633
|
+
* {@link PowqlInterface}'s exec seam to fail writes fast with E018 before the
|
|
634
|
+
* wire; the engine's own refusal (mapped by {@link wrapPowdbError}) is the
|
|
635
|
+
* backstop for raw / injected paths.
|
|
636
|
+
*/
|
|
637
|
+
readonly readonly: boolean;
|
|
572
638
|
constructor(db: EmbeddedDatabase, options?: PowdbPoolOptions);
|
|
573
|
-
/**
|
|
639
|
+
/** Run the PowQL on the in-process engine, choosing the native or legacy wire. */
|
|
574
640
|
private exec;
|
|
575
641
|
/**
|
|
576
642
|
* Run one statement, gating transaction control. `holdRef` scopes the gate
|
|
@@ -586,7 +652,17 @@ export declare class PowdbEmbeddedPool implements PgCompatPool {
|
|
|
586
652
|
export { introspectPowdbDatabase, type PowdbExec, type PowdbIntrospectOptions, } from './powdb-introspect.js';
|
|
587
653
|
export { PowqlInterface } from './powql.js';
|
|
588
654
|
/** Options for {@link turbinePowDB}. */
|
|
589
|
-
export interface TurbinePowdbOptions extends Pick<TurbineConfig, 'logging' | 'defaultLimit' | 'warnOnUnlimited'> {
|
|
655
|
+
export interface TurbinePowdbOptions extends Pick<TurbineConfig, 'logging' | 'defaultLimit' | 'warnOnUnlimited' | 'relationLoadStrategy'> {
|
|
656
|
+
/**
|
|
657
|
+
* Client-level default `with`-relation load strategy. On PowDB the default is
|
|
658
|
+
* the batched N+1 loaders; setting `'join'` opts INTO native PowQL server-side
|
|
659
|
+
* joins for eligible top-level relations (ineligible ones, e.g. a paged parent
|
|
660
|
+
* or a nested `with`, fall back to the loaders per-relation and silently). A
|
|
661
|
+
* per-query `relationLoadStrategy` arg still overrides this. Requires an engine
|
|
662
|
+
* that advertises `serverJoins` (PowDB ≥ 0.13); a per-query `'join'` on an
|
|
663
|
+
* older engine throws E017, a client-level default silently falls back.
|
|
664
|
+
*/
|
|
665
|
+
relationLoadStrategy?: TurbineConfig['relationLoadStrategy'];
|
|
590
666
|
/** Max pooled connections (default 10). Networked transport only. */
|
|
591
667
|
connectionLimit?: number;
|
|
592
668
|
/**
|
|
@@ -623,6 +699,18 @@ export interface TurbinePowdbOptions extends Pick<TurbineConfig, 'logging' | 'de
|
|
|
623
699
|
* E017).
|
|
624
700
|
*/
|
|
625
701
|
assumeEngineVersion?: string;
|
|
702
|
+
/**
|
|
703
|
+
* Mark the client read-only: a write (or a transaction `begin`) fails fast
|
|
704
|
+
* locally with a {@link ReadOnlyError} (E018) before it reaches the wire,
|
|
705
|
+
* rather than round-tripping to the engine's refusal. Works on both
|
|
706
|
+
* transports (a networked pool bound to a read-only role, or an embedded
|
|
707
|
+
* handle). An `{ embedded, readonly: true }` target implies this. Default
|
|
708
|
+
* `false`.
|
|
709
|
+
*
|
|
710
|
+
* Ignored when you inject an already-constructed {@link PowdbPool} (it carries
|
|
711
|
+
* its own {@link PowdbPoolOptions}); set it on that pool's constructor instead.
|
|
712
|
+
*/
|
|
713
|
+
readonly?: boolean;
|
|
626
714
|
/**
|
|
627
715
|
* Driver-module injection for the networked target forms (URL / host+port):
|
|
628
716
|
* bypasses the dynamic `import('@zvndev/powdb-client')` and uses this object
|
|
@@ -630,6 +718,14 @@ export interface TurbinePowdbOptions extends Pick<TurbineConfig, 'logging' | 'de
|
|
|
630
718
|
* connections) and advanced embedding; everyday callers never set it.
|
|
631
719
|
*/
|
|
632
720
|
powdbClientModule?: PowdbModule;
|
|
721
|
+
/**
|
|
722
|
+
* Driver-module injection for the **embedded** target form (`{ embedded }`):
|
|
723
|
+
* bypasses the dynamic `import('@zvndev/powdb-embedded')` and uses this object
|
|
724
|
+
* as the addon module instead. Intended for tests (a fake `Database` factory
|
|
725
|
+
* that records how the handle was opened) and advanced embedding; everyday
|
|
726
|
+
* callers never set it. The symmetric counterpart to {@link powdbClientModule}.
|
|
727
|
+
*/
|
|
728
|
+
powdbEmbeddedModule?: EmbeddedModule;
|
|
633
729
|
}
|
|
634
730
|
/**
|
|
635
731
|
* Selects the **embedded** transport — an in-process `@zvndev/powdb-embedded`
|
|
@@ -655,6 +751,16 @@ export interface TurbinePowdbEmbeddedTarget {
|
|
|
655
751
|
syncMode?: 'full' | 'normal' | 'off';
|
|
656
752
|
/** Per-query memory budget in bytes (requires `@zvndev/powdb-embedded` ≥ 0.7.1). */
|
|
657
753
|
memoryLimit?: number;
|
|
754
|
+
/**
|
|
755
|
+
* Open the data directory read-only for snapshot serving (requires
|
|
756
|
+
* `@zvndev/powdb-embedded` ≥ 0.14: `openReadOnly` / `openReadOnlyWithMemoryLimit`).
|
|
757
|
+
* A write through a read-only handle is refused by the engine with
|
|
758
|
+
* `readonly mode: statement requires a writer …` (→ {@link ReadOnlyError}, E018),
|
|
759
|
+
* and Turbine additionally fails writes fast locally (this implies the pool's
|
|
760
|
+
* `readonly` flag). Meaningless together with `syncMode` (a read-only engine
|
|
761
|
+
* never writes), setting both throws a {@link ValidationError}.
|
|
762
|
+
*/
|
|
763
|
+
readonly?: boolean;
|
|
658
764
|
}
|
|
659
765
|
/**
|
|
660
766
|
* Bind Turbine to PowDB. `target` is one of:
|