@delali/sirannon-db 0.3.4-next.62 → 0.3.4
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 +79 -56
- package/dist/backup/index.d.ts +44 -45
- package/dist/backup/index.mjs +7 -7
- package/dist/backup-scheduler/index.d.ts +42 -41
- package/dist/backup-scheduler/index.mjs +4 -4
- package/dist/baseline-Co3iIsN_.d.ts +19 -0
- package/dist/change-tracker-DqCdeEyx.d.ts +128 -0
- package/dist/{chunk-VOSJBZ6Q.mjs → chunk-2ES3DT4A.mjs} +71 -33
- package/dist/{chunk-6CMCO7S4.mjs → chunk-2O3PP4CF.mjs} +1 -1
- package/dist/{chunk-E7Q7HE46.mjs → chunk-3BZLZ47R.mjs} +26 -26
- package/dist/chunk-4KASJKKK.mjs +2501 -0
- package/dist/{chunk-MYNI2WFS.mjs → chunk-52XW3Z76.mjs} +40 -8
- package/dist/chunk-55YRLSM2.mjs +57 -0
- package/dist/{chunk-KDAHYFW7.mjs → chunk-6AOJCNRU.mjs} +5 -5
- package/dist/{chunk-KXTYR2OQ.mjs → chunk-A3PHCO6W.mjs} +39 -111
- package/dist/chunk-ADNWEHGZ.mjs +299 -0
- package/dist/{chunk-2QLXDHAP.mjs → chunk-BLMRNSUG.mjs} +11 -2
- package/dist/chunk-BVMZJOVM.mjs +5 -0
- package/dist/{chunk-IWGIYDMZ.mjs → chunk-BZWDPF4G.mjs} +1 -1
- package/dist/{chunk-YVF2ZJTE.mjs → chunk-CZL4D3BM.mjs} +1 -1
- package/dist/{chunk-7SC2TZAS.mjs → chunk-DX4WGJL7.mjs} +2 -2
- package/dist/{chunk-45MKELYA.mjs → chunk-ESTZZPT5.mjs} +132 -13
- package/dist/{chunk-QP5L5DFJ.mjs → chunk-FJPR2CJX.mjs} +3 -3
- package/dist/chunk-HR7K3GZW.mjs +36 -0
- package/dist/{chunk-LXCGPZPA.mjs → chunk-IEKIYO4V.mjs} +1 -1
- package/dist/{chunk-TUD5CJ76.mjs → chunk-KB4OLJAD.mjs} +26 -19
- package/dist/{chunk-PBRXXISQ.mjs → chunk-KINDFBQP.mjs} +3 -2
- package/dist/{chunk-E6IMX7RS.mjs → chunk-KJLNYOOL.mjs} +2 -2
- package/dist/{chunk-BTTFW4Z4.mjs → chunk-KU32OT4H.mjs} +2 -10
- package/dist/{chunk-JQWGHSEH.mjs → chunk-NVSQ2T5Q.mjs} +71 -70
- package/dist/{chunk-W4EUTJNT.mjs → chunk-NZGSDALX.mjs} +94 -96
- package/dist/{chunk-U445A3C4.mjs → chunk-QGVRRKB2.mjs} +1 -1
- package/dist/{chunk-GYCEJNU4.mjs → chunk-R7GBXNTO.mjs} +1 -1
- package/dist/{chunk-7C36BCSN.mjs → chunk-VDN6FHU4.mjs} +1 -1
- package/dist/{chunk-6IYS4WLH.mjs → chunk-VO3ZWA2G.mjs} +142 -115
- package/dist/chunk-WOMADPM4.mjs +12 -0
- package/dist/{chunk-OUSWVNWT.mjs → chunk-YCMB6GR4.mjs} +1 -1
- package/dist/{chunk-YNTDOFTN.mjs → chunk-YW7IKQ7T.mjs} +1 -1
- package/dist/{chunk-M2BEAH5I.mjs → chunk-ZN4HI5FK.mjs} +126 -72
- package/dist/{chunk-SBL6GN43.mjs → chunk-ZYWI45EN.mjs} +1 -1
- package/dist/client/index.d.ts +135 -137
- package/dist/client/index.mjs +177 -82
- package/dist/client/topology.d.ts +31 -31
- package/dist/client/topology.mjs +42 -23
- package/dist/client-base-BxTocU1x.d.ts +398 -0
- package/dist/client-streams-YKANXMWO.mjs +112 -0
- package/dist/codegen/cli.mjs +4 -4
- package/dist/codegen/index.d.ts +36 -29
- package/dist/codegen/index.mjs +4 -4
- package/dist/core/index.d.ts +130 -115
- package/dist/core/index.mjs +387 -297
- package/dist/core/writer-worker.mjs +3 -3
- package/dist/database-CGDsXW1K.d.ts +959 -0
- package/dist/database-backup-DcLhxoa1.d.ts +143 -0
- package/dist/driver/better-sqlite3.d.ts +11 -10
- package/dist/driver/better-sqlite3.mjs +11 -11
- package/dist/driver/bun.d.ts +9 -8
- package/dist/driver/expo.d.ts +6 -7
- package/dist/driver/node.d.ts +11 -10
- package/dist/driver/node.mjs +13 -11
- package/dist/driver/wa-sqlite.d.ts +6 -6
- package/dist/errors-CJUkQ-KL.d.ts +199 -0
- package/dist/file-migrations/index.d.ts +20 -18
- package/dist/file-migrations/index.mjs +3 -3
- package/dist/forward-rpc-VRWFZXHN.mjs +44 -0
- package/dist/operation-registry-CGhNT-Sn.d.ts +96 -0
- package/dist/primary-wins-CHNOYuN7.d.ts +81 -0
- package/dist/protocol-DFpNNsIT.d.ts +153 -0
- package/dist/query-types-5B02ixH0.d.ts +129 -0
- package/dist/react/index.d.ts +22 -22
- package/dist/replication/coordinator/etcd.d.ts +37 -31
- package/dist/replication/coordinator/etcd.mjs +296 -131
- package/dist/replication/index.d.ts +201 -161
- package/dist/replication/index.mjs +630 -529
- package/dist/restore-options-CH8mE-Tb.d.ts +84 -0
- package/dist/server/index.d.ts +201 -191
- package/dist/server/index.mjs +736 -619
- package/dist/server-options-aYtCkefX.d.ts +317 -0
- package/dist/server-streams-24XL4T43.mjs +254 -0
- package/dist/sirannon-J3EgPVD7.d.ts +179 -0
- package/dist/transport/grpc.d.ts +37 -24
- package/dist/transport/grpc.mjs +83 -3199
- package/dist/transport/memory.d.ts +25 -26
- package/dist/transport/memory.mjs +18 -9
- package/dist/types-BrAiDGOb.d.ts +505 -0
- package/dist/types-CEJG0eFS.d.ts +88 -0
- package/dist/types-Dc8oWlxj.d.ts +1580 -0
- package/dist/types-DqODKeOq.d.ts +123 -0
- package/dist/types-guEKSzMr.d.ts +367 -0
- package/package.json +7 -7
- package/dist/baseline-D93hcIEE.d.ts +0 -17
- package/dist/change-tracker-CjRFuZdB.d.ts +0 -144
- package/dist/client-base-Cmd9EVme.d.ts +0 -397
- package/dist/database-BLQvqjsw.d.ts +0 -917
- package/dist/database-backup-B7oszQ2n.d.ts +0 -141
- package/dist/errors-Dei4GdBb.d.ts +0 -196
- package/dist/operation-registry-oiPuSYI6.d.ts +0 -94
- package/dist/primary-wins-B0np8JS3.d.ts +0 -85
- package/dist/protocol-HI-nY8DD.d.ts +0 -152
- package/dist/query-types-p1liOP-b.d.ts +0 -127
- package/dist/restore-options-CksYsH1l.d.ts +0 -83
- package/dist/server-options-Bj5iJnjx.d.ts +0 -292
- package/dist/sirannon-BPxC5tC2.d.ts +0 -178
- package/dist/types-B0EhgDbr.d.ts +0 -340
- package/dist/types-CbjfRwrK.d.ts +0 -499
- package/dist/types-CjhxcjhA.d.ts +0 -123
- package/dist/types-DPSmjU54.d.ts +0 -1518
- package/dist/types-DTO4CYhW.d.ts +0 -88
package/dist/core/index.mjs
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
import { Transaction, LWWResolver, REMOTE_ORIGIN_NODE_ID, BatchReader, BatchApplier, recordLocalColumnVersions,
|
|
2
|
-
export { Transaction } from '../chunk-
|
|
3
|
-
import { executeBatch, executeBatchSummary, execute, bindParams, executeGroup, query, queryForWire, queryOne } from '../chunk-
|
|
4
|
-
export { execute, executeBatch, query, queryOne } from '../chunk-
|
|
5
|
-
import { tokenizeSql, unsupported, findClauses, readSource, readSortTerms, readWindow, readSelectItems, parameterName } from '../chunk-
|
|
6
|
-
import { reconcileMigrationChecksums, migrationContentChecksum, ensureCdcEpoch, SubscriptionBuilderImpl, ChangeTracker, SubscriptionManager, startPolling, runBulkLoad, TransactionGrouper, PrimedSubscription } from '../chunk-
|
|
7
|
-
export { ChangeTracker, isBulkLoadDurability, runBulkLoad } from '../chunk-
|
|
8
|
-
import { planBackupRestore, backupPiecesSafeToDelete } from '../chunk-
|
|
9
|
-
export { backupPiecesSafeToDelete, planBackupRestore } from '../chunk-
|
|
10
|
-
import { ensureMigrationsTable, prepareUpdateMigrationChecksum, prepareInsertMigration, selectAppliedMigrationsNewestFirst, prepareDeleteMigration, selectAppliedMigrations, tableInfoRows, selectTableSql, selectTableExists, selectMetaValue, upsertMetaValue, SEQ_STRING_RE, replaceMigrationHistory, highestMigrationVersion, selectCountOutboundChanges, ensureMetaTable, ensureChangesTable, ensureBatchApplyTables, PkResolver, selectMaxChangeSeq, selectMaxAppliedSourceSeq, insertMetaValueIfAbsent, selectMaxChangeHlc, updateUnstampedChangeStampsSql, UPSERT_META_VALUE_SQL, setForeignKeysEnabled, IDENTIFIER_RE, validateDdlSafety, ensureStagedChangesTable, upsertStagedChangeSql, selectFirstStagedTransactionEnd, deleteStagedChangesUpToSeq, selectMaxStagedSeq, deleteAllStagedChanges, deleteMetaValue, assertSafeIdentifier, selectStagedChangesInRange } from '../chunk-
|
|
11
|
-
import { ReplicationError } from '../chunk-
|
|
12
|
-
import { MIGRATIONS_TABLE, LIVE_PROBE_TABLE_PREFIX, META_TABLE, CHANGES_TABLE, assertSqlAllowed, INTERNAL_TABLE_PREFIX, eventTimestampToChangedAt, encodeTaggedValues, isReservedIdentifier, decodeTaggedValues, changedAtToEventTimestamp } from '../chunk-
|
|
1
|
+
import { Transaction, LWWResolver, REMOTE_ORIGIN_NODE_ID, BatchReader, BatchApplier, recordLocalColumnVersions, loadPersistedHlc, isWellFormedHlc, HLC_CLOCK_META_KEY } from '../chunk-A3PHCO6W.mjs';
|
|
2
|
+
export { Transaction } from '../chunk-A3PHCO6W.mjs';
|
|
3
|
+
import { runWriterTransaction, executeBatch, executeBatchSummary, execute, bindParams, executeGroup, query, queryForWire, queryOne } from '../chunk-52XW3Z76.mjs';
|
|
4
|
+
export { execute, executeBatch, query, queryOne } from '../chunk-52XW3Z76.mjs';
|
|
5
|
+
import { tokenizeSql, unsupported, findClauses, readSource, readSortTerms, readWindow, readSelectItems, parameterName } from '../chunk-ZYWI45EN.mjs';
|
|
6
|
+
import { reconcileMigrationChecksums, migrationContentChecksum, resolveDeviceRetentionPolicy, ensureCdcEpoch, SubscriptionBuilderImpl, ChangeTracker, SubscriptionManager, startPolling, runBulkLoad, TransactionGrouper, PrimedSubscription } from '../chunk-ZN4HI5FK.mjs';
|
|
7
|
+
export { ChangeTracker, isBulkLoadDurability, runBulkLoad } from '../chunk-ZN4HI5FK.mjs';
|
|
8
|
+
import { planBackupRestore, backupPiecesSafeToDelete } from '../chunk-YW7IKQ7T.mjs';
|
|
9
|
+
export { backupPiecesSafeToDelete, planBackupRestore } from '../chunk-YW7IKQ7T.mjs';
|
|
10
|
+
import { ensureMigrationsTable, prepareUpdateMigrationChecksum, prepareInsertMigration, selectAppliedMigrationsNewestFirst, prepareDeleteMigration, selectAppliedMigrations, tableInfoRows, selectTableSql, selectTableExists, selectMetaValue, upsertMetaValue, SEQ_STRING_RE, replaceMigrationHistory, highestMigrationVersion, selectCountOutboundChanges, ensureMetaTable, ensureChangesTable, ensureBatchApplyTables, PkResolver, selectMaxChangeSeq, selectMaxAppliedSourceSeq, insertMetaValueIfAbsent, HLC, selectMaxChangeHlc, updateUnstampedChangeStampsSql, UPSERT_META_VALUE_SQL, setForeignKeysEnabled, IDENTIFIER_RE, validateDdlSafety, ensureStagedChangesTable, upsertStagedChangeSql, selectFirstStagedTransactionEnd, deleteStagedChangesUpToSeq, selectMaxStagedSeq, deleteAllStagedChanges, deleteMetaValue, assertSafeIdentifier, selectStagedChangesInRange } from '../chunk-ESTZZPT5.mjs';
|
|
11
|
+
import { ReplicationError } from '../chunk-BLMRNSUG.mjs';
|
|
12
|
+
import { MIGRATIONS_TABLE, LIVE_PROBE_TABLE_PREFIX, META_TABLE, CHANGES_TABLE, assertSqlAllowed, INTERNAL_TABLE_PREFIX, eventTimestampToChangedAt, encodeTaggedValues, isReservedIdentifier, decodeTaggedValues, changedAtToEventTimestamp } from '../chunk-2O3PP4CF.mjs';
|
|
13
13
|
import '../chunk-GVCNMPOS.mjs';
|
|
14
|
-
import { defaultStagingDir } from '../chunk-
|
|
15
|
-
export { defineDriver } from '../chunk-
|
|
14
|
+
import { defaultStagingDir } from '../chunk-IEKIYO4V.mjs';
|
|
15
|
+
export { defineDriver } from '../chunk-IEKIYO4V.mjs';
|
|
16
16
|
import { startCopyWithoutHoldingWriter } from '../chunk-W67A4H2E.mjs';
|
|
17
|
-
import { DEFAULT_SYNCHRONOUS } from '../chunk-
|
|
18
|
-
export { DEFAULT_SYNCHRONOUS, isSynchronousLevel, synchronousPragmaValue } from '../chunk-
|
|
19
|
-
import { DEFAULT_CHAIN_NAME } from '../chunk-
|
|
20
|
-
export { DEFAULT_CHAIN_NAME, readBackupChains } from '../chunk-
|
|
17
|
+
import { DEFAULT_SYNCHRONOUS } from '../chunk-YCMB6GR4.mjs';
|
|
18
|
+
export { DEFAULT_SYNCHRONOUS, isSynchronousLevel, synchronousPragmaValue } from '../chunk-YCMB6GR4.mjs';
|
|
19
|
+
import { DEFAULT_CHAIN_NAME } from '../chunk-CZL4D3BM.mjs';
|
|
20
|
+
export { DEFAULT_CHAIN_NAME, readBackupChains } from '../chunk-CZL4D3BM.mjs';
|
|
21
21
|
import { invokeCallerCallback, randomHex } from '../chunk-QBBLSQHQ.mjs';
|
|
22
|
-
import { LAZY_DOWN_SQL, parseMigrationFilename } from '../chunk-
|
|
23
|
-
export { MIGRATION_FILENAME_PATTERN, parseMigrationFilename } from '../chunk-
|
|
24
|
-
import { resolveEffectiveBaseline, planPendingMigrations, SQLITE_USER_VERSION_MAX, applyBaselineOption } from '../chunk-
|
|
25
|
-
import { SirannonError, ConnectionPoolError, MigrationError, ReadOnlyError, MaxDatabasesError, DatabaseAlreadyExistsError, DatabaseNotFoundError, CDCError, WriteOverloadError, ExtensionError } from '../chunk-
|
|
26
|
-
export { BackupError, CDCError, ConnectionPoolError, DatabaseAlreadyExistsError, DatabaseNotFoundError, ExtensionError, ForbiddenSqlError, HookDeniedError, MaxDatabasesError, MigrationError, QueryError, ReadOnlyError, RequestDeniedError, SirannonError, TransactionError, WriteOverloadError } from '../chunk-
|
|
22
|
+
import { LAZY_DOWN_SQL, parseMigrationFilename } from '../chunk-VDN6FHU4.mjs';
|
|
23
|
+
export { MIGRATION_FILENAME_PATTERN, parseMigrationFilename } from '../chunk-VDN6FHU4.mjs';
|
|
24
|
+
import { resolveEffectiveBaseline, planPendingMigrations, SQLITE_USER_VERSION_MAX, applyBaselineOption } from '../chunk-BZWDPF4G.mjs';
|
|
25
|
+
import { SirannonError, ConnectionPoolError, MigrationError, ReadOnlyError, MaxDatabasesError, DatabaseAlreadyExistsError, DatabaseNotFoundError, CDCError, WriteOverloadError, ExtensionError } from '../chunk-KINDFBQP.mjs';
|
|
26
|
+
export { BackupError, CDCError, ConnectionPoolError, DatabaseAlreadyExistsError, DatabaseNotFoundError, ExtensionError, ForbiddenSqlError, HookDeniedError, MaxDatabasesError, MigrationError, QueryError, ReadOnlyError, RequestDeniedError, SirannonError, TransactionError, WriteOverloadError } from '../chunk-KINDFBQP.mjs';
|
|
27
27
|
|
|
28
28
|
// src/core/connection-pool.ts
|
|
29
29
|
async function closeAllSilently(connections) {
|
|
@@ -101,7 +101,7 @@ var ConnectionPool = class _ConnectionPool {
|
|
|
101
101
|
}
|
|
102
102
|
return this.writer;
|
|
103
103
|
}
|
|
104
|
-
/** Returns the writer and every reader,
|
|
104
|
+
/** Returns the writer and every reader, so that the caller can apply an operation to every connection in the pool. */
|
|
105
105
|
connections() {
|
|
106
106
|
if (this.closed) {
|
|
107
107
|
throw new ConnectionPoolError("Connection pool is closed");
|
|
@@ -263,9 +263,10 @@ var DatabaseBackupController = class {
|
|
|
263
263
|
);
|
|
264
264
|
}
|
|
265
265
|
/**
|
|
266
|
-
* Builds the cycle and starts it
|
|
267
|
-
* whole database,
|
|
268
|
-
*
|
|
266
|
+
* Builds the backup cycle and starts it without awaiting the first turn, which
|
|
267
|
+
* copies the whole database, so that the open can return first. When the start
|
|
268
|
+
* fails, this method passes the error to the `onError` callback in the cycle
|
|
269
|
+
* options.
|
|
269
270
|
*/
|
|
270
271
|
startCycle(options) {
|
|
271
272
|
const engine = this.require();
|
|
@@ -318,7 +319,7 @@ var DatabaseBackupController = class {
|
|
|
318
319
|
async piecesSafeToDelete(options) {
|
|
319
320
|
return backupPiecesSafeToDelete(await this.chains(), options);
|
|
320
321
|
}
|
|
321
|
-
/** Stops the cycle
|
|
322
|
+
/** Stops the backup cycle after one last capture, which sends the writes made since the previous turn to the destination. */
|
|
322
323
|
async stopCycle() {
|
|
323
324
|
if (!this.cycle) return;
|
|
324
325
|
const cycle = this.cycle;
|
|
@@ -445,12 +446,14 @@ var SyncStamper = class _SyncStamper {
|
|
|
445
446
|
|
|
446
447
|
// src/core/database-cdc.ts
|
|
447
448
|
var DatabaseCdcController = class {
|
|
448
|
-
constructor(runExclusive, acquireWriter, pollInterval, retention, openSnapshotConnection) {
|
|
449
|
+
constructor(runExclusive, acquireWriter, pollInterval, retention, openSnapshotConnection, deviceRetention, onDispatched) {
|
|
449
450
|
this.runExclusive = runExclusive;
|
|
450
451
|
this.acquireWriter = acquireWriter;
|
|
451
452
|
this.pollInterval = pollInterval;
|
|
452
453
|
this.retention = retention;
|
|
453
454
|
this.openSnapshotConnection = openSnapshotConnection;
|
|
455
|
+
this.deviceRetention = deviceRetention;
|
|
456
|
+
this.onDispatched = onDispatched;
|
|
454
457
|
}
|
|
455
458
|
tracker = null;
|
|
456
459
|
subscriptionManager = null;
|
|
@@ -545,7 +548,7 @@ var DatabaseCdcController = class {
|
|
|
545
548
|
return Transaction.run(writer, fn);
|
|
546
549
|
}
|
|
547
550
|
const state = { sawDdl: false, droppedTables: [] };
|
|
548
|
-
const result = await writer
|
|
551
|
+
const result = await runWriterTransaction(writer, async (txConn) => {
|
|
549
552
|
const value = await fn(new CdcAwareTransaction(txConn, tracker, state));
|
|
550
553
|
await this.applyStamps(txConn);
|
|
551
554
|
return value;
|
|
@@ -563,7 +566,7 @@ var DatabaseCdcController = class {
|
|
|
563
566
|
}
|
|
564
567
|
ensure() {
|
|
565
568
|
const tracker = this.tracker ?? new ChangeTracker({ retention: this.retention });
|
|
566
|
-
const subscriptions = this.subscriptionManager ?? new SubscriptionManager();
|
|
569
|
+
const subscriptions = this.subscriptionManager ?? new SubscriptionManager(this.onDispatched);
|
|
567
570
|
this.tracker = tracker;
|
|
568
571
|
this.subscriptionManager = subscriptions;
|
|
569
572
|
return { tracker, subscriptions };
|
|
@@ -577,7 +580,8 @@ var DatabaseCdcController = class {
|
|
|
577
580
|
this.subscriptionManager,
|
|
578
581
|
this.pollInterval,
|
|
579
582
|
void 0,
|
|
580
|
-
this.runExclusive
|
|
583
|
+
this.runExclusive,
|
|
584
|
+
this.deviceRetention
|
|
581
585
|
);
|
|
582
586
|
}
|
|
583
587
|
};
|
|
@@ -872,6 +876,7 @@ var DatabaseMigrationController = class {
|
|
|
872
876
|
};
|
|
873
877
|
|
|
874
878
|
// src/core/hooks/query-hooks.ts
|
|
879
|
+
var STATEMENT_SUCCEEDED = { failed: false };
|
|
875
880
|
function fireBeforeQueryHooks(parentHooks, localHooks, databaseId, sql, params, options) {
|
|
876
881
|
const hasParent = parentHooks?.has("beforeQuery");
|
|
877
882
|
const hasLocal = localHooks.has("beforeQuery");
|
|
@@ -886,19 +891,13 @@ function fireBeforeQueryHooks(parentHooks, localHooks, databaseId, sql, params,
|
|
|
886
891
|
parentHooks?.invokeSync("beforeQuery", ctx);
|
|
887
892
|
localHooks.invokeSync("beforeQuery", ctx);
|
|
888
893
|
}
|
|
889
|
-
function fireAfterQueryHooks(parentHooks, localHooks, databaseId, sql, params, durationMs) {
|
|
894
|
+
function fireAfterQueryHooks(parentHooks, localHooks, databaseId, sql, params, durationMs, outcome) {
|
|
890
895
|
const hasParent = parentHooks?.has("afterQuery");
|
|
891
896
|
const hasLocal = localHooks.has("afterQuery");
|
|
892
897
|
if (!hasParent && !hasLocal) return;
|
|
893
|
-
const ctx = { databaseId, sql, params, durationMs };
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
} catch {
|
|
897
|
-
}
|
|
898
|
-
try {
|
|
899
|
-
localHooks.invokeSync("afterQuery", ctx);
|
|
900
|
-
} catch {
|
|
901
|
-
}
|
|
898
|
+
const ctx = outcome.failed ? { databaseId, sql, params, durationMs, error: outcome.error } : { databaseId, sql, params, durationMs };
|
|
899
|
+
parentHooks?.invokeSyncIgnoringFailures("afterQuery", ctx);
|
|
900
|
+
localHooks.invokeSyncIgnoringFailures("afterQuery", ctx);
|
|
902
901
|
}
|
|
903
902
|
|
|
904
903
|
// src/core/database-observability.ts
|
|
@@ -916,41 +915,50 @@ var DatabaseObserver = class {
|
|
|
916
915
|
this.fireBefore(sql, params, options);
|
|
917
916
|
const start = performance.now();
|
|
918
917
|
try {
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
918
|
+
const result = await op();
|
|
919
|
+
this.fireAfter(sql, params, performance.now() - start, STATEMENT_SUCCEEDED);
|
|
920
|
+
return result;
|
|
921
|
+
} catch (error) {
|
|
922
|
+
this.fireAfter(sql, params, performance.now() - start, { failed: true, error });
|
|
923
|
+
throw error;
|
|
922
924
|
}
|
|
923
925
|
}
|
|
924
|
-
track(sql, op) {
|
|
926
|
+
track(sql, op, measure) {
|
|
925
927
|
if (!this.metrics) return op();
|
|
926
|
-
return this.metrics.trackQuery(op, { databaseId: this.databaseId, sql });
|
|
928
|
+
return this.metrics.trackQuery(op, { databaseId: this.databaseId, sql }, measure);
|
|
927
929
|
}
|
|
928
930
|
async withTransactionHooks(statements, op) {
|
|
929
931
|
for (const statement of statements) this.fireBefore(statement.sql, statement.params);
|
|
930
932
|
const start = performance.now();
|
|
931
933
|
try {
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
934
|
+
const results = await this.trackEach(statements, op);
|
|
935
|
+
this.fireAfterEach(statements, performance.now() - start, STATEMENT_SUCCEEDED);
|
|
936
|
+
return results;
|
|
937
|
+
} catch (error) {
|
|
938
|
+
this.fireAfterEach(statements, performance.now() - start, { failed: true, error });
|
|
939
|
+
throw error;
|
|
936
940
|
}
|
|
937
941
|
}
|
|
942
|
+
fireAfterEach(statements, durationMs, outcome) {
|
|
943
|
+
for (const statement of statements) this.fireAfter(statement.sql, statement.params, durationMs, outcome);
|
|
944
|
+
}
|
|
938
945
|
trackEach(statements, op) {
|
|
939
946
|
const metrics = this.metrics;
|
|
940
947
|
if (!metrics) return op();
|
|
941
948
|
let run = op;
|
|
942
|
-
|
|
949
|
+
statements.forEach((statement, index) => {
|
|
943
950
|
const inner = run;
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
951
|
+
run = () => metrics.trackQuery(inner, { databaseId: this.databaseId, sql: statement.sql }, (results) => ({
|
|
952
|
+
changes: results[index]?.changes
|
|
953
|
+
}));
|
|
954
|
+
});
|
|
947
955
|
return run();
|
|
948
956
|
}
|
|
949
957
|
fireBefore(sql, params, options) {
|
|
950
958
|
fireBeforeQueryHooks(this.parentHooks, this.localHooks, this.databaseId, sql, params, options);
|
|
951
959
|
}
|
|
952
|
-
fireAfter(sql, params, durationMs) {
|
|
953
|
-
fireAfterQueryHooks(this.parentHooks, this.localHooks, this.databaseId, sql, params, durationMs);
|
|
960
|
+
fireAfter(sql, params, durationMs, outcome) {
|
|
961
|
+
fireAfterQueryHooks(this.parentHooks, this.localHooks, this.databaseId, sql, params, durationMs, outcome);
|
|
954
962
|
}
|
|
955
963
|
};
|
|
956
964
|
|
|
@@ -1301,7 +1309,7 @@ var DatabaseSyncController = class {
|
|
|
1301
1309
|
}
|
|
1302
1310
|
applyLocalPruneBoundary() {
|
|
1303
1311
|
if (this.localPruneBoundary !== null) {
|
|
1304
|
-
this.cdc.changeTracker?.setPruneBoundary(this.localPruneBoundary);
|
|
1312
|
+
this.cdc.changeTracker?.setPruneBoundary("device-sync", this.localPruneBoundary);
|
|
1305
1313
|
}
|
|
1306
1314
|
}
|
|
1307
1315
|
readOutboxBatch(afterSeq, limit) {
|
|
@@ -1579,6 +1587,14 @@ function toError(error) {
|
|
|
1579
1587
|
}
|
|
1580
1588
|
|
|
1581
1589
|
// src/core/database-writes.ts
|
|
1590
|
+
function changesOf(result) {
|
|
1591
|
+
return { changes: result.changes };
|
|
1592
|
+
}
|
|
1593
|
+
function totalChanges(results) {
|
|
1594
|
+
let changes = 0;
|
|
1595
|
+
for (const result of results) changes += result.changes;
|
|
1596
|
+
return { changes };
|
|
1597
|
+
}
|
|
1582
1598
|
var DatabaseWriteController = class {
|
|
1583
1599
|
constructor(deps) {
|
|
1584
1600
|
this.deps = deps;
|
|
@@ -1592,7 +1608,8 @@ var DatabaseWriteController = class {
|
|
|
1592
1608
|
() => writeGate.run(
|
|
1593
1609
|
() => observer.track(
|
|
1594
1610
|
sql,
|
|
1595
|
-
() => writerLock.isHeld() ? groupCommitter.runUngrouped(sql, params) : groupCommitter.submit(sql, params)
|
|
1611
|
+
() => writerLock.isHeld() ? groupCommitter.runUngrouped(sql, params) : groupCommitter.submit(sql, params),
|
|
1612
|
+
changesOf
|
|
1596
1613
|
)
|
|
1597
1614
|
)
|
|
1598
1615
|
);
|
|
@@ -1605,7 +1622,12 @@ var DatabaseWriteController = class {
|
|
|
1605
1622
|
options,
|
|
1606
1623
|
() => writeGate.run(
|
|
1607
1624
|
() => writerLock.run(
|
|
1608
|
-
() => this.runInTransaction(
|
|
1625
|
+
() => this.runInTransaction(
|
|
1626
|
+
pool.acquireWriter(),
|
|
1627
|
+
sql,
|
|
1628
|
+
(txConn) => executeBatch(txConn, sql, paramsBatch),
|
|
1629
|
+
totalChanges
|
|
1630
|
+
)
|
|
1609
1631
|
)
|
|
1610
1632
|
)
|
|
1611
1633
|
);
|
|
@@ -1626,7 +1648,7 @@ var DatabaseWriteController = class {
|
|
|
1626
1648
|
durability: options?.durability,
|
|
1627
1649
|
checkpoint: options?.checkpoint ?? true,
|
|
1628
1650
|
capturesChangeLog,
|
|
1629
|
-
loadRows: () => this.runInTransaction(writer, sql, (txConn) => executeBatchSummary(txConn, sql, paramsBatch))
|
|
1651
|
+
loadRows: () => this.runInTransaction(writer, sql, (txConn) => executeBatchSummary(txConn, sql, paramsBatch), changesOf)
|
|
1630
1652
|
});
|
|
1631
1653
|
})
|
|
1632
1654
|
)
|
|
@@ -1655,15 +1677,16 @@ var DatabaseWriteController = class {
|
|
|
1655
1677
|
return results;
|
|
1656
1678
|
});
|
|
1657
1679
|
}
|
|
1658
|
-
async runInTransaction(writer, sql, run) {
|
|
1680
|
+
async runInTransaction(writer, sql, run, measure) {
|
|
1659
1681
|
const { observer, cdc } = this.deps;
|
|
1660
1682
|
const result = await observer.track(
|
|
1661
1683
|
sql,
|
|
1662
|
-
() => writer
|
|
1684
|
+
() => runWriterTransaction(writer, async (txConn) => {
|
|
1663
1685
|
const value = await run(txConn);
|
|
1664
1686
|
await cdc.applyStamps(txConn);
|
|
1665
1687
|
return value;
|
|
1666
|
-
})
|
|
1688
|
+
}),
|
|
1689
|
+
measure
|
|
1667
1690
|
);
|
|
1668
1691
|
await applyDdlSideEffectsIfRelevant(cdc.changeTracker, writer, sql);
|
|
1669
1692
|
return result;
|
|
@@ -1678,8 +1701,16 @@ var HOOK_CONFIG_MAP = {
|
|
|
1678
1701
|
onDatabaseOpen: "databaseOpen",
|
|
1679
1702
|
onDatabaseClose: "databaseClose",
|
|
1680
1703
|
onBeforeSubscribe: "beforeSubscribe",
|
|
1681
|
-
onBeforeSnapshot: "beforeSnapshot"
|
|
1704
|
+
onBeforeSnapshot: "beforeSnapshot",
|
|
1705
|
+
onBeforePush: "beforePush"
|
|
1682
1706
|
};
|
|
1707
|
+
function callSynchronously(event, hook, ctx) {
|
|
1708
|
+
const result = hook(ctx);
|
|
1709
|
+
if (result == null || typeof result.then !== "function") return;
|
|
1710
|
+
result.then(void 0, () => {
|
|
1711
|
+
});
|
|
1712
|
+
throw new Error(`Hook for '${event}' returned a Promise. Use invoke() for async hooks.`);
|
|
1713
|
+
}
|
|
1683
1714
|
var HookRegistry = class {
|
|
1684
1715
|
hooks = /* @__PURE__ */ new Map();
|
|
1685
1716
|
constructor(config) {
|
|
@@ -1713,9 +1744,17 @@ var HookRegistry = class {
|
|
|
1713
1744
|
if (!list || list.length === 0) return;
|
|
1714
1745
|
const snapshot = list.slice();
|
|
1715
1746
|
for (const hook of snapshot) {
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1747
|
+
callSynchronously(event, hook, ctx);
|
|
1748
|
+
}
|
|
1749
|
+
}
|
|
1750
|
+
invokeSyncIgnoringFailures(event, ctx) {
|
|
1751
|
+
const list = this.hooks.get(event);
|
|
1752
|
+
if (!list || list.length === 0) return;
|
|
1753
|
+
const snapshot = list.slice();
|
|
1754
|
+
for (const hook of snapshot) {
|
|
1755
|
+
try {
|
|
1756
|
+
callSynchronously(event, hook, ctx);
|
|
1757
|
+
} catch {
|
|
1719
1758
|
}
|
|
1720
1759
|
}
|
|
1721
1760
|
}
|
|
@@ -1844,7 +1883,7 @@ var LoadedExtensions = class {
|
|
|
1844
1883
|
await connection.loadExtension(resolvedPath);
|
|
1845
1884
|
}
|
|
1846
1885
|
}
|
|
1847
|
-
/** Loads an extension
|
|
1886
|
+
/** Loads an extension into the pool's connections and every tracked connection, then records its resolved path. */
|
|
1848
1887
|
load(poolConnections, extensionPath) {
|
|
1849
1888
|
return this.runInTurn(async () => {
|
|
1850
1889
|
const resolved = await loadExtension(this.driver, [...poolConnections, ...this.openedConnections], extensionPath);
|
|
@@ -1852,12 +1891,12 @@ var LoadedExtensions = class {
|
|
|
1852
1891
|
});
|
|
1853
1892
|
}
|
|
1854
1893
|
/**
|
|
1855
|
-
* Opens a connection, loads every recorded extension
|
|
1856
|
-
*
|
|
1857
|
-
* tracking and closes the
|
|
1894
|
+
* Opens a connection, loads every recorded extension into it, and returns a
|
|
1895
|
+
* wrapper that forwards each call to it. Closing the wrapper stops the
|
|
1896
|
+
* tracking and closes the connection underneath.
|
|
1858
1897
|
*
|
|
1859
|
-
* @param openConnection -
|
|
1860
|
-
* @returns The
|
|
1898
|
+
* @param openConnection - The function that opens the connection that this database needs.
|
|
1899
|
+
* @returns The wrapper to read and write through.
|
|
1861
1900
|
*/
|
|
1862
1901
|
open(openConnection) {
|
|
1863
1902
|
return this.runInTurn(async () => {
|
|
@@ -1994,7 +2033,9 @@ async function createDatabaseRuntime(id, path, driver, options, internals) {
|
|
|
1994
2033
|
() => pool.acquireWriter(),
|
|
1995
2034
|
options?.cdcPollInterval ?? 50,
|
|
1996
2035
|
options?.cdcRetention ?? 36e5,
|
|
1997
|
-
canOpenSnapshotConnection ? openSnapshotConnection : null
|
|
2036
|
+
canOpenSnapshotConnection ? openSnapshotConnection : null,
|
|
2037
|
+
resolveDeviceRetentionPolicy(options),
|
|
2038
|
+
internals?.metrics?.observeDispatch(id)
|
|
1998
2039
|
);
|
|
1999
2040
|
const sync = new DatabaseSyncController(
|
|
2000
2041
|
(op) => writeGate.run(() => writerLock.run(op)),
|
|
@@ -2068,20 +2109,26 @@ async function closeDatabaseRuntime(runtime, closeListeners) {
|
|
|
2068
2109
|
|
|
2069
2110
|
// src/core/database-lifecycle.ts
|
|
2070
2111
|
var DatabaseLifecycle = class {
|
|
2071
|
-
/**
|
|
2112
|
+
/** The identifier that this database was opened under. */
|
|
2072
2113
|
id;
|
|
2073
|
-
/**
|
|
2114
|
+
/** The file path of the SQLite database. */
|
|
2074
2115
|
path;
|
|
2075
|
-
/** Whether this database
|
|
2116
|
+
/** Whether this database rejects writes. */
|
|
2076
2117
|
readOnly;
|
|
2077
2118
|
/**
|
|
2078
|
-
*
|
|
2119
|
+
* The retention settings that this database was opened with, which form an empty object when the caller set none.
|
|
2120
|
+
*
|
|
2121
|
+
* @internal
|
|
2122
|
+
*/
|
|
2123
|
+
changeRetention;
|
|
2124
|
+
/**
|
|
2125
|
+
* The pool, locks, and controllers that this database sends its work through.
|
|
2079
2126
|
*
|
|
2080
2127
|
* @internal
|
|
2081
2128
|
*/
|
|
2082
2129
|
runtime;
|
|
2083
2130
|
/**
|
|
2084
|
-
*
|
|
2131
|
+
* The functions that Sirannon calls while this database closes.
|
|
2085
2132
|
*
|
|
2086
2133
|
* @internal
|
|
2087
2134
|
*/
|
|
@@ -2092,11 +2139,16 @@ var DatabaseLifecycle = class {
|
|
|
2092
2139
|
this.path = path;
|
|
2093
2140
|
this.runtime = runtime;
|
|
2094
2141
|
this.readOnly = options?.readOnly ?? false;
|
|
2142
|
+
this.changeRetention = {
|
|
2143
|
+
...options?.cdcRetention === void 0 ? {} : { cdcRetention: options.cdcRetention },
|
|
2144
|
+
...options?.deviceCursorRetention === void 0 ? {} : { deviceCursorRetention: options.deviceCursorRetention },
|
|
2145
|
+
...options?.maxChangesHeldForDevice === void 0 ? {} : { maxChangesHeldForDevice: options.maxChangesHeldForDevice }
|
|
2146
|
+
};
|
|
2095
2147
|
}
|
|
2096
2148
|
/**
|
|
2097
|
-
* Registers a function that
|
|
2149
|
+
* Registers a function that Sirannon calls while this database closes.
|
|
2098
2150
|
*
|
|
2099
|
-
* @param fn -
|
|
2151
|
+
* @param fn - The function to call during {@link DatabaseLifecycle.close}.
|
|
2100
2152
|
*
|
|
2101
2153
|
* @internal
|
|
2102
2154
|
*/
|
|
@@ -2105,7 +2157,7 @@ var DatabaseLifecycle = class {
|
|
|
2105
2157
|
this.closeListeners.push(fn);
|
|
2106
2158
|
}
|
|
2107
2159
|
/**
|
|
2108
|
-
* Closes every connection this database
|
|
2160
|
+
* Closes every connection that this database opened, and stops delivering changes to its subscriptions.
|
|
2109
2161
|
*/
|
|
2110
2162
|
async close() {
|
|
2111
2163
|
if (this.closing) return;
|
|
@@ -2113,19 +2165,19 @@ var DatabaseLifecycle = class {
|
|
|
2113
2165
|
await closeDatabaseRuntime(this.runtime, this.closeListeners);
|
|
2114
2166
|
}
|
|
2115
2167
|
/**
|
|
2116
|
-
*
|
|
2168
|
+
* True once {@link DatabaseLifecycle.close} has started on this database.
|
|
2117
2169
|
*/
|
|
2118
2170
|
get closed() {
|
|
2119
2171
|
return this.closing;
|
|
2120
2172
|
}
|
|
2121
2173
|
/**
|
|
2122
|
-
*
|
|
2174
|
+
* The number of read connections in the pool.
|
|
2123
2175
|
*/
|
|
2124
2176
|
get readerCount() {
|
|
2125
2177
|
return this.runtime.pool.readerCount;
|
|
2126
2178
|
}
|
|
2127
2179
|
/**
|
|
2128
|
-
*
|
|
2180
|
+
* Throws when this database is closed, is loading a snapshot, or rejects writes.
|
|
2129
2181
|
*
|
|
2130
2182
|
* @internal
|
|
2131
2183
|
*/
|
|
@@ -2134,7 +2186,7 @@ var DatabaseLifecycle = class {
|
|
|
2134
2186
|
if (this.readOnly) throw new ReadOnlyError(this.id);
|
|
2135
2187
|
}
|
|
2136
2188
|
/**
|
|
2137
|
-
*
|
|
2189
|
+
* Throws when this database is closed or is loading a snapshot.
|
|
2138
2190
|
*
|
|
2139
2191
|
* @internal
|
|
2140
2192
|
*/
|
|
@@ -2148,7 +2200,7 @@ var DatabaseLifecycle = class {
|
|
|
2148
2200
|
}
|
|
2149
2201
|
}
|
|
2150
2202
|
/**
|
|
2151
|
-
*
|
|
2203
|
+
* Throws when this database is closed.
|
|
2152
2204
|
*
|
|
2153
2205
|
* @internal
|
|
2154
2206
|
*/
|
|
@@ -2164,71 +2216,74 @@ var DatabaseBackups = class extends DatabaseLifecycle {
|
|
|
2164
2216
|
/**
|
|
2165
2217
|
* Copies this database to a file while it stays open for reads and writes.
|
|
2166
2218
|
*
|
|
2167
|
-
*
|
|
2168
|
-
*
|
|
2219
|
+
* Sirannon holds the writer only until SQLite copies the first step of pages,
|
|
2220
|
+
* so later writes commit between the steps of the copy and wait for none of it.
|
|
2169
2221
|
*
|
|
2170
|
-
* @param destPath -
|
|
2171
|
-
* @returns The run identifier, the timings, the pages
|
|
2222
|
+
* @param destPath - The path of the file that Sirannon writes the copy to.
|
|
2223
|
+
* @returns The run identifier, the timings, the number of pages copied, and the size of the file in bytes.
|
|
2172
2224
|
*/
|
|
2173
2225
|
async backup(destPath) {
|
|
2174
2226
|
this.ensureOpen();
|
|
2175
2227
|
return this.runtime.backups.backup(destPath);
|
|
2176
2228
|
}
|
|
2177
2229
|
/**
|
|
2178
|
-
* Copies this database to a destination you supply, in fixed-size
|
|
2179
|
-
* while it stays open for reads and writes.
|
|
2230
|
+
* Copies this database to a destination that you supply, in fixed-size
|
|
2231
|
+
* pieces, while it stays open for reads and writes.
|
|
2180
2232
|
*
|
|
2181
|
-
* Sirannon
|
|
2182
|
-
*
|
|
2233
|
+
* Sirannon includes no storage client, so you connect object storage, or any
|
|
2234
|
+
* other store, through the destination.
|
|
2183
2235
|
*
|
|
2184
|
-
*
|
|
2185
|
-
*
|
|
2186
|
-
*
|
|
2187
|
-
*
|
|
2188
|
-
* the two
|
|
2236
|
+
* Where this runtime has the compiled streaming extension, Sirannon sends each
|
|
2237
|
+
* piece to the destination as SQLite writes it, so the copy needs no local
|
|
2238
|
+
* disk. On every other runtime, Sirannon writes one local file first, which
|
|
2239
|
+
* needs local disk equal to the size of the backup.
|
|
2240
|
+
* {@link DatabaseBackups.backupCapabilities} reports which of the two routes
|
|
2241
|
+
* applies to this runtime.
|
|
2189
2242
|
*
|
|
2190
|
-
* @param options -
|
|
2191
|
-
* @returns The run identifier, the timings, what the
|
|
2243
|
+
* @param options - The destination, the naming, the piece size, and the progress callback.
|
|
2244
|
+
* @returns The run identifier, the timings, what the copy wrote, and how many times the copy restarted.
|
|
2192
2245
|
*/
|
|
2193
2246
|
async backupTo(options) {
|
|
2194
2247
|
this.ensureOpen();
|
|
2195
2248
|
return this.runtime.backups.backupTo(options);
|
|
2196
2249
|
}
|
|
2197
2250
|
/**
|
|
2198
|
-
* Reports which backup operations this database's runtime supports, so
|
|
2199
|
-
*
|
|
2251
|
+
* Reports which backup operations this database's runtime supports, so that
|
|
2252
|
+
* you can check them before you start a backup.
|
|
2200
2253
|
*
|
|
2201
|
-
* @returns
|
|
2254
|
+
* @returns Whether this runtime can copy the database, whether a copy needs local disk, and whether it can schedule copies.
|
|
2202
2255
|
*/
|
|
2203
2256
|
backupCapabilities() {
|
|
2204
2257
|
return this.runtime.backups.capabilities();
|
|
2205
2258
|
}
|
|
2206
2259
|
/**
|
|
2207
|
-
* Starts
|
|
2260
|
+
* Starts copying this database to a directory on a cron schedule, and deletes
|
|
2261
|
+
* the oldest copies beyond {@link BackupScheduleOptions.maxFiles}.
|
|
2208
2262
|
*
|
|
2209
|
-
* @param options -
|
|
2263
|
+
* @param options - The cron expression, destination directory, retention, and time zone, with the callbacks that Sirannon calls after each finished copy and after each failure.
|
|
2210
2264
|
*/
|
|
2211
2265
|
scheduleBackup(options) {
|
|
2212
2266
|
this.ensureOpen();
|
|
2213
2267
|
this.runtime.backups.schedule(options);
|
|
2214
2268
|
}
|
|
2215
2269
|
/**
|
|
2216
|
-
*
|
|
2217
|
-
*
|
|
2270
|
+
* Takes one turn of the backup cycle now, without waiting for the interval. A
|
|
2271
|
+
* turn sends any capture that is still waiting, captures the log frames
|
|
2218
2272
|
* written since the previous turn, and then checkpoints the log.
|
|
2219
2273
|
*
|
|
2220
|
-
*
|
|
2221
|
-
*
|
|
2222
|
-
*
|
|
2274
|
+
* Only a database opened with the `backups` option has a cycle, and on any
|
|
2275
|
+
* other database this throws `BACKUP_UNSUPPORTED`. On a node whose replication
|
|
2276
|
+
* group takes its backups from another node, Sirannon writes nothing on the
|
|
2277
|
+
* turn and reports a skip through `onSkip`.
|
|
2223
2278
|
*
|
|
2224
|
-
* @returns What the turn
|
|
2279
|
+
* @returns What Sirannon wrote on the turn, or undefined when it wrote nothing.
|
|
2225
2280
|
*/
|
|
2226
2281
|
async captureBackupChanges() {
|
|
2227
2282
|
this.ensureOpen();
|
|
2228
2283
|
return this.runtime.backups.captureChanges();
|
|
2229
2284
|
}
|
|
2230
2285
|
/**
|
|
2231
|
-
* Lists
|
|
2286
|
+
* Lists the backup chains at the destination.
|
|
2232
2287
|
*
|
|
2233
2288
|
* @returns One entry per chain, newest first, each with its full copy and its change pieces in order.
|
|
2234
2289
|
*/
|
|
@@ -2237,12 +2292,13 @@ var DatabaseBackups = class extends DatabaseLifecycle {
|
|
|
2237
2292
|
return this.runtime.backups.chains();
|
|
2238
2293
|
}
|
|
2239
2294
|
/**
|
|
2240
|
-
*
|
|
2241
|
-
* its recent turns
|
|
2295
|
+
* Returns what this database's backup cycle is doing now, and the outcome of
|
|
2296
|
+
* its recent turns.
|
|
2242
2297
|
*
|
|
2243
|
-
*
|
|
2244
|
-
*
|
|
2245
|
-
* of a large database
|
|
2298
|
+
* You can poll this while a turn that you started with
|
|
2299
|
+
* {@link DatabaseBackups.captureBackupChanges} is still under way, and during
|
|
2300
|
+
* a full copy of a large database, the status includes the pages that SQLite
|
|
2301
|
+
* has copied so far.
|
|
2246
2302
|
*
|
|
2247
2303
|
* @returns Whether a turn is under way, how far it has got, and the last run, skip, and failure.
|
|
2248
2304
|
*/
|
|
@@ -2251,64 +2307,64 @@ var DatabaseBackups = class extends DatabaseLifecycle {
|
|
|
2251
2307
|
return this.runtime.backups.status();
|
|
2252
2308
|
}
|
|
2253
2309
|
/**
|
|
2254
|
-
*
|
|
2255
|
-
*
|
|
2310
|
+
* Fetches one of this database's backups from the destination and checks it
|
|
2311
|
+
* against the record that Sirannon wrote with that backup.
|
|
2256
2312
|
*
|
|
2257
|
-
* A restore
|
|
2258
|
-
*
|
|
2259
|
-
*
|
|
2260
|
-
*
|
|
2261
|
-
*
|
|
2262
|
-
* local storage of its own.
|
|
2313
|
+
* A restore fails on a damaged piece only after the restore has started, so
|
|
2314
|
+
* call this beforehand to check the backup. Sirannon fetches every piece in
|
|
2315
|
+
* order, computes a SHA-256 over the bytes as they arrive, and compares that
|
|
2316
|
+
* digest and the byte count with the record. Sirannon keeps one piece in
|
|
2317
|
+
* memory at a time, so checking a large full copy needs no local disk.
|
|
2263
2318
|
*
|
|
2264
|
-
*
|
|
2265
|
-
*
|
|
2266
|
-
* `BACKUP_DESTINATION_ERROR`.
|
|
2319
|
+
* This method throws `BACKUP_DESTINATION_ERROR` when a piece is missing, or
|
|
2320
|
+
* when the byte count or the digest differs from the record.
|
|
2267
2321
|
*
|
|
2268
|
-
* @param name -
|
|
2269
|
-
* @returns The pieces read,
|
|
2322
|
+
* @param name - The name that the backup is stored under, as each entry from {@link DatabaseBackups.backupChain} gives it.
|
|
2323
|
+
* @returns The number of pieces read, their total size in bytes, and the digest when the backup recorded one.
|
|
2270
2324
|
*/
|
|
2271
2325
|
async verifyBackup(name) {
|
|
2272
2326
|
this.ensureNotClosed();
|
|
2273
2327
|
return this.runtime.backups.verify(name);
|
|
2274
2328
|
}
|
|
2275
2329
|
/**
|
|
2276
|
-
*
|
|
2330
|
+
* Returns where this database's backups are stored.
|
|
2277
2331
|
*
|
|
2278
|
-
*
|
|
2279
|
-
* database from its
|
|
2332
|
+
* Pass the destination, chain name, and deadline from the result to
|
|
2333
|
+
* `restoreBackup` to rebuild this database from its backups at a path that
|
|
2334
|
+
* you name.
|
|
2280
2335
|
*
|
|
2281
|
-
* @returns The destination, the name
|
|
2336
|
+
* @returns The destination, the name that the chains are listed under, and the directory where Sirannon stages captures.
|
|
2282
2337
|
*/
|
|
2283
2338
|
backupLocation() {
|
|
2284
2339
|
this.ensureNotClosed();
|
|
2285
2340
|
return this.runtime.backups.location();
|
|
2286
2341
|
}
|
|
2287
2342
|
/**
|
|
2288
|
-
*
|
|
2343
|
+
* Returns the full copy and the change pieces that a restore to a given
|
|
2344
|
+
* moment would apply.
|
|
2289
2345
|
*
|
|
2290
|
-
* The
|
|
2291
|
-
* the last piece
|
|
2292
|
-
*
|
|
2293
|
-
*
|
|
2346
|
+
* The plan also includes the moment that the restored database would reflect,
|
|
2347
|
+
* which is the capture time of its last piece. Each piece contains every write
|
|
2348
|
+
* from one capture interval, so a restore stops at a piece boundary, which
|
|
2349
|
+
* can fall before the millisecond that you name.
|
|
2294
2350
|
*
|
|
2295
|
-
* @param moment -
|
|
2296
|
-
* @returns The full copy, the change pieces to apply in order, and the moment the result reflects.
|
|
2351
|
+
* @param moment - The moment to restore to, in epoch milliseconds.
|
|
2352
|
+
* @returns The full copy, the change pieces to apply in order, and the moment that the result reflects.
|
|
2297
2353
|
*/
|
|
2298
2354
|
async backupRestorePlan(moment) {
|
|
2299
2355
|
this.ensureNotClosed();
|
|
2300
2356
|
return this.runtime.backups.restorePlan(moment);
|
|
2301
2357
|
}
|
|
2302
2358
|
/**
|
|
2303
|
-
*
|
|
2304
|
-
*
|
|
2305
|
-
* to reach and the answer also covers the older chains a newer full copy
|
|
2306
|
-
* already spans.
|
|
2359
|
+
* Returns the backup records that no restore needs any longer, so that you
|
|
2360
|
+
* can delete them from the destination yourself.
|
|
2307
2361
|
*
|
|
2308
|
-
*
|
|
2362
|
+
* When you pass the earliest moment that a restore must still reach, the list
|
|
2363
|
+
* also includes every chain whose full copy finished before the full copy
|
|
2364
|
+
* that a restore to that moment would start from.
|
|
2309
2365
|
*
|
|
2310
|
-
* @param options -
|
|
2311
|
-
* @returns The records you
|
|
2366
|
+
* @param options - The earliest moment that a restore must still reach.
|
|
2367
|
+
* @returns The records that you can delete, oldest chain first.
|
|
2312
2368
|
*/
|
|
2313
2369
|
async backupPiecesSafeToDelete(options) {
|
|
2314
2370
|
this.ensureNotClosed();
|
|
@@ -2317,12 +2373,18 @@ var DatabaseBackups = class extends DatabaseLifecycle {
|
|
|
2317
2373
|
};
|
|
2318
2374
|
|
|
2319
2375
|
// src/core/database-reads.ts
|
|
2376
|
+
function countRows(rows) {
|
|
2377
|
+
return { rowsReturned: rows.length };
|
|
2378
|
+
}
|
|
2379
|
+
function countRow(row) {
|
|
2380
|
+
return { rowsReturned: row === void 0 ? 0 : 1 };
|
|
2381
|
+
}
|
|
2320
2382
|
function readRows(deps, sql, params, options) {
|
|
2321
2383
|
return deps.observer.withQueryHooks(
|
|
2322
2384
|
sql,
|
|
2323
2385
|
params,
|
|
2324
2386
|
options,
|
|
2325
|
-
() => onReadConnection(deps, sql, (conn) => query(conn, sql, params))
|
|
2387
|
+
() => onReadConnection(deps, sql, (conn) => query(conn, sql, params), countRows)
|
|
2326
2388
|
);
|
|
2327
2389
|
}
|
|
2328
2390
|
function readWireRows(deps, sql, params, options) {
|
|
@@ -2330,7 +2392,7 @@ function readWireRows(deps, sql, params, options) {
|
|
|
2330
2392
|
sql,
|
|
2331
2393
|
params,
|
|
2332
2394
|
options,
|
|
2333
|
-
() => onReadConnection(deps, sql, (conn) => queryForWire(conn, sql, params))
|
|
2395
|
+
() => onReadConnection(deps, sql, (conn) => queryForWire(conn, sql, params), countRows)
|
|
2334
2396
|
);
|
|
2335
2397
|
}
|
|
2336
2398
|
function readOneRow(deps, sql, params, options) {
|
|
@@ -2338,14 +2400,14 @@ function readOneRow(deps, sql, params, options) {
|
|
|
2338
2400
|
sql,
|
|
2339
2401
|
params,
|
|
2340
2402
|
options,
|
|
2341
|
-
() => onReadConnection(deps, sql, (conn) => queryOne(conn, sql, params))
|
|
2403
|
+
() => onReadConnection(deps, sql, (conn) => queryOne(conn, sql, params), countRow)
|
|
2342
2404
|
);
|
|
2343
2405
|
}
|
|
2344
|
-
function onReadConnection(deps, sql, op) {
|
|
2406
|
+
function onReadConnection(deps, sql, op, measure) {
|
|
2345
2407
|
if (deps.pool.readerCount === 0) {
|
|
2346
|
-
return deps.writerLock.run(() => deps.observer.track(sql, () => op(deps.pool.acquireWriter())));
|
|
2408
|
+
return deps.writerLock.run(() => deps.observer.track(sql, () => op(deps.pool.acquireWriter()), measure));
|
|
2347
2409
|
}
|
|
2348
|
-
return deps.observer.track(sql, () => op(deps.pool.acquireReader()));
|
|
2410
|
+
return deps.observer.track(sql, () => op(deps.pool.acquireReader()), measure);
|
|
2349
2411
|
}
|
|
2350
2412
|
|
|
2351
2413
|
// src/core/live/column-collations.ts
|
|
@@ -3430,22 +3492,23 @@ var Database = class _Database extends DatabaseBackups {
|
|
|
3430
3492
|
return this.runtime.sync.applyChanges(batch, resolver);
|
|
3431
3493
|
}
|
|
3432
3494
|
/**
|
|
3433
|
-
* Returns the device-sync port for this database, which
|
|
3434
|
-
*
|
|
3495
|
+
* Returns the device-sync port for this database, which a `SyncController`
|
|
3496
|
+
* calls to apply pulled changes, read unpushed local changes, and store its
|
|
3497
|
+
* push and pull cursors.
|
|
3435
3498
|
*
|
|
3436
|
-
* @returns The port, which
|
|
3499
|
+
* @returns The port, which you can also pass to `downloadDatabaseSnapshot`.
|
|
3437
3500
|
*/
|
|
3438
3501
|
deviceSync() {
|
|
3439
3502
|
this.ensureNotClosed();
|
|
3440
3503
|
return this.runtime.sync.devicePort();
|
|
3441
3504
|
}
|
|
3442
3505
|
/**
|
|
3443
|
-
*
|
|
3506
|
+
* Executes a read and returns every row.
|
|
3444
3507
|
*
|
|
3445
|
-
* @param sql - The statement to
|
|
3446
|
-
* @param params -
|
|
3447
|
-
* @param options -
|
|
3448
|
-
* @returns The rows the statement
|
|
3508
|
+
* @param sql - The statement to execute.
|
|
3509
|
+
* @param params - The values to bind to the statement, named or positional.
|
|
3510
|
+
* @param options - The read concern for this statement.
|
|
3511
|
+
* @returns The rows that the statement returns.
|
|
3449
3512
|
*/
|
|
3450
3513
|
async query(sql, params, options) {
|
|
3451
3514
|
this.ensureOpen();
|
|
@@ -3457,35 +3520,35 @@ var Database = class _Database extends DatabaseBackups {
|
|
|
3457
3520
|
return readWireRows(this.runtime.reads, sql, params, options);
|
|
3458
3521
|
}
|
|
3459
3522
|
/**
|
|
3460
|
-
*
|
|
3523
|
+
* Executes a read and returns its first row.
|
|
3461
3524
|
*
|
|
3462
|
-
* @param sql - The statement to
|
|
3463
|
-
* @param params -
|
|
3464
|
-
* @param options -
|
|
3465
|
-
* @returns The first row, or undefined when the statement
|
|
3525
|
+
* @param sql - The statement to execute.
|
|
3526
|
+
* @param params - The values to bind to the statement, named or positional.
|
|
3527
|
+
* @param options - The read concern for this statement.
|
|
3528
|
+
* @returns The first row, or undefined when the statement returns none.
|
|
3466
3529
|
*/
|
|
3467
3530
|
async queryOne(sql, params, options) {
|
|
3468
3531
|
this.ensureOpen();
|
|
3469
3532
|
return readOneRow(this.runtime.reads, sql, params, options);
|
|
3470
3533
|
}
|
|
3471
3534
|
/**
|
|
3472
|
-
*
|
|
3535
|
+
* Executes one write statement.
|
|
3473
3536
|
*
|
|
3474
|
-
* @param sql - The statement to
|
|
3475
|
-
* @param params -
|
|
3476
|
-
* @param options -
|
|
3477
|
-
* @returns
|
|
3537
|
+
* @param sql - The statement to execute.
|
|
3538
|
+
* @param params - The values to bind to the statement, named or positional.
|
|
3539
|
+
* @param options - The write concern for this statement.
|
|
3540
|
+
* @returns The number of rows that the statement changed, and the row id of the last inserted row.
|
|
3478
3541
|
*/
|
|
3479
3542
|
async execute(sql, params, options) {
|
|
3480
3543
|
this.ensureWritable();
|
|
3481
3544
|
return this.runtime.writes.execute(sql, params, options);
|
|
3482
3545
|
}
|
|
3483
3546
|
/**
|
|
3484
|
-
*
|
|
3547
|
+
* Executes one statement once for each parameter set, inside a single transaction.
|
|
3485
3548
|
*
|
|
3486
|
-
* @param sql - The statement to
|
|
3487
|
-
* @param paramsBatch - One parameter set
|
|
3488
|
-
* @param options -
|
|
3549
|
+
* @param sql - The statement to execute for each parameter set.
|
|
3550
|
+
* @param paramsBatch - One parameter set for each execution.
|
|
3551
|
+
* @param options - The write concern for the transaction.
|
|
3489
3552
|
* @returns One result per parameter set, in order.
|
|
3490
3553
|
*/
|
|
3491
3554
|
async executeBatch(sql, paramsBatch, options) {
|
|
@@ -3493,34 +3556,38 @@ var Database = class _Database extends DatabaseBackups {
|
|
|
3493
3556
|
return this.runtime.writes.executeBatch(sql, paramsBatch, options);
|
|
3494
3557
|
}
|
|
3495
3558
|
/**
|
|
3496
|
-
* Imports many rows
|
|
3559
|
+
* Imports many rows at a relaxed synchronous level, then restores the level that you configured.
|
|
3560
|
+
*
|
|
3561
|
+
* Use this for a load that you can re-run from scratch, and use
|
|
3562
|
+
* {@link Database.executeBatch} where the rows need full durability. Sirannon
|
|
3563
|
+
* holds the writer lock for the whole load and commits every row in one
|
|
3564
|
+
* transaction. Whether the load succeeds or fails, Sirannon restores the
|
|
3565
|
+
* configured level before this method resolves. The result contains totals
|
|
3566
|
+
* for the whole load, so that a large load keeps no per-row results in memory.
|
|
3497
3567
|
*
|
|
3498
|
-
*
|
|
3499
|
-
*
|
|
3500
|
-
*
|
|
3501
|
-
* resolves, whether it succeeds or fails. One transaction covers the whole
|
|
3502
|
-
* batch, and the rows are summed rather than returned one by one to bound
|
|
3503
|
-
* memory on a large load. Like {@link Database.execute}, this writes only to
|
|
3504
|
-
* the local database; under replication the server routes loads through the
|
|
3505
|
-
* engine instead.
|
|
3568
|
+
* Like {@link Database.execute}, this writes to the local database only. A
|
|
3569
|
+
* server whose execution target has no `bulkLoad` method, such as the
|
|
3570
|
+
* replication engine, rejects bulk loads with `BULK_LOAD_UNSUPPORTED`.
|
|
3506
3571
|
*
|
|
3507
|
-
* @param sql - The statement to
|
|
3572
|
+
* @param sql - The statement to execute for each parameter set.
|
|
3508
3573
|
* @param paramsBatch - One parameter set per row.
|
|
3509
|
-
* @param options -
|
|
3510
|
-
* @returns
|
|
3574
|
+
* @param options - The synchronous level during the load, and whether the load ends with a checkpoint.
|
|
3575
|
+
* @returns The number of parameter sets that the load applied, and the number of rows that changed.
|
|
3511
3576
|
*/
|
|
3512
3577
|
async bulkLoad(sql, paramsBatch, options) {
|
|
3513
3578
|
this.ensureWritable();
|
|
3514
3579
|
return this.runtime.writes.bulkLoad(sql, paramsBatch, options);
|
|
3515
3580
|
}
|
|
3516
3581
|
/**
|
|
3517
|
-
*
|
|
3582
|
+
* Executes a fixed list of statements in one transaction, which Sirannon can commit together with other callers' writes.
|
|
3518
3583
|
*
|
|
3519
|
-
*
|
|
3520
|
-
*
|
|
3521
|
-
* transaction
|
|
3584
|
+
* When every statement is an INSERT, UPDATE, DELETE, or REPLACE, Sirannon
|
|
3585
|
+
* groups the transaction with other writes into one commit, and otherwise it
|
|
3586
|
+
* executes the transaction on its own. This method takes the statements up
|
|
3587
|
+
* front, because a group commit that waited on a caller's callback would delay
|
|
3588
|
+
* every other transaction in the group.
|
|
3522
3589
|
*
|
|
3523
|
-
* @param statements - The statements to
|
|
3590
|
+
* @param statements - The statements to execute, in order, each with its own parameters.
|
|
3524
3591
|
* @returns One result per statement, in order.
|
|
3525
3592
|
*/
|
|
3526
3593
|
async executeTransaction(statements) {
|
|
@@ -3529,19 +3596,19 @@ var Database = class _Database extends DatabaseBackups {
|
|
|
3529
3596
|
return this.runtime.writes.executeTransaction(statements);
|
|
3530
3597
|
}
|
|
3531
3598
|
/**
|
|
3532
|
-
*
|
|
3599
|
+
* Calls a function inside one transaction, and commits when the function returns or rolls back when it throws.
|
|
3533
3600
|
*
|
|
3534
|
-
* @param fn -
|
|
3535
|
-
* @returns
|
|
3601
|
+
* @param fn - The function to call with the transaction, which executes its statements through it.
|
|
3602
|
+
* @returns The value that the function returns.
|
|
3536
3603
|
*/
|
|
3537
3604
|
async transaction(fn) {
|
|
3538
3605
|
this.ensureWritable();
|
|
3539
3606
|
return this.runtime.writes.transaction(fn);
|
|
3540
3607
|
}
|
|
3541
3608
|
/**
|
|
3542
|
-
* Starts recording changes to a table so that subscribers and replication
|
|
3609
|
+
* Starts recording changes to a table, so that subscribers and replication receive them.
|
|
3543
3610
|
*
|
|
3544
|
-
* @param table -
|
|
3611
|
+
* @param table - The name of the table to watch.
|
|
3545
3612
|
*/
|
|
3546
3613
|
async watch(table) {
|
|
3547
3614
|
this.ensureWritable();
|
|
@@ -3550,17 +3617,17 @@ var Database = class _Database extends DatabaseBackups {
|
|
|
3550
3617
|
/**
|
|
3551
3618
|
* Stops recording changes to a table.
|
|
3552
3619
|
*
|
|
3553
|
-
* @param table -
|
|
3620
|
+
* @param table - The name of the table to stop watching.
|
|
3554
3621
|
*/
|
|
3555
3622
|
async unwatch(table) {
|
|
3556
3623
|
this.ensureOpen();
|
|
3557
3624
|
await this.runtime.cdc.unwatch(table);
|
|
3558
3625
|
}
|
|
3559
3626
|
/**
|
|
3560
|
-
*
|
|
3561
|
-
* under the writer lock
|
|
3562
|
-
*
|
|
3563
|
-
*
|
|
3627
|
+
* Executes a change-log maintenance write, such as pruning, on the shared
|
|
3628
|
+
* writer connection under the writer lock, so that it queues behind
|
|
3629
|
+
* application writes and never contends with them for SQLite's write lock,
|
|
3630
|
+
* which would block the event loop for the `busy_timeout`.
|
|
3564
3631
|
*
|
|
3565
3632
|
* @internal
|
|
3566
3633
|
*/
|
|
@@ -3574,22 +3641,22 @@ var Database = class _Database extends DatabaseBackups {
|
|
|
3574
3641
|
await this.runtime.cdc.ensureStamping();
|
|
3575
3642
|
}
|
|
3576
3643
|
/**
|
|
3577
|
-
*
|
|
3644
|
+
* Starts building a change subscription on a watched table.
|
|
3578
3645
|
*
|
|
3579
|
-
* @param table -
|
|
3580
|
-
* @returns A builder you narrow with a filter and then subscribe to.
|
|
3646
|
+
* @param table - The name of the watched table.
|
|
3647
|
+
* @returns A builder that you narrow with a filter and then subscribe to.
|
|
3581
3648
|
*/
|
|
3582
3649
|
on(table) {
|
|
3583
3650
|
this.ensureOpen();
|
|
3584
3651
|
return this.runtime.cdc.on(table);
|
|
3585
3652
|
}
|
|
3586
3653
|
/**
|
|
3587
|
-
* Opens a live query that keeps a
|
|
3654
|
+
* Opens a live query that keeps the rows of a single-table SELECT current as that table changes, and watches the table first.
|
|
3588
3655
|
*
|
|
3589
|
-
* @param
|
|
3590
|
-
* @param
|
|
3591
|
-
* @param options -
|
|
3592
|
-
* @returns The live query,
|
|
3656
|
+
* @param sql - The SELECT statement to keep current.
|
|
3657
|
+
* @param params - The values to bind to the statement, named or positional.
|
|
3658
|
+
* @param options - The re-read jitter, the transaction size above which the query re-reads, and the reporter for listener failures.
|
|
3659
|
+
* @returns The live query, holding its first rows and subscribed to changes.
|
|
3593
3660
|
*/
|
|
3594
3661
|
async live(sql, params, options) {
|
|
3595
3662
|
this.ensureWritable();
|
|
@@ -3597,17 +3664,17 @@ var Database = class _Database extends DatabaseBackups {
|
|
|
3597
3664
|
return openLiveQuery({ cdc, watch: (table) => this.watch(table) }, sql, params, options);
|
|
3598
3665
|
}
|
|
3599
3666
|
/**
|
|
3600
|
-
* Applies every migration this database has
|
|
3667
|
+
* Applies every migration that this database has yet to apply, in ascending version order.
|
|
3601
3668
|
*
|
|
3602
3669
|
* @param migrations - The full set of migrations for this database.
|
|
3603
|
-
* @returns
|
|
3670
|
+
* @returns The migrations that this call applied, and the number that the database had already applied.
|
|
3604
3671
|
*/
|
|
3605
3672
|
async migrate(migrations) {
|
|
3606
3673
|
this.ensureOpen();
|
|
3607
3674
|
return this.runtime.migrations.migrate(migrations);
|
|
3608
3675
|
}
|
|
3609
3676
|
/**
|
|
3610
|
-
* Lists the migrations this database has applied.
|
|
3677
|
+
* Lists the migrations that this database has applied.
|
|
3611
3678
|
*
|
|
3612
3679
|
* @returns One entry per applied migration, with its version, name, and checksum.
|
|
3613
3680
|
*/
|
|
@@ -3616,38 +3683,38 @@ var Database = class _Database extends DatabaseBackups {
|
|
|
3616
3683
|
return this.runtime.migrations.applied();
|
|
3617
3684
|
}
|
|
3618
3685
|
/**
|
|
3619
|
-
*
|
|
3686
|
+
* Reverts applied migrations, newest first.
|
|
3620
3687
|
*
|
|
3621
|
-
* @param migrations - The full set of migrations
|
|
3622
|
-
* @param version -
|
|
3623
|
-
* @returns
|
|
3688
|
+
* @param migrations - The full set of migrations, from which the runner takes each down statement.
|
|
3689
|
+
* @param version - The version to roll back to, which stays applied with every version below it; when you omit it, the runner reverts only the newest migration.
|
|
3690
|
+
* @returns The migrations that this call reverted.
|
|
3624
3691
|
*/
|
|
3625
3692
|
async rollback(migrations, version) {
|
|
3626
3693
|
this.ensureOpen();
|
|
3627
3694
|
return this.runtime.migrations.rollback(migrations, version);
|
|
3628
3695
|
}
|
|
3629
3696
|
/**
|
|
3630
|
-
* Loads a SQLite extension into this database.
|
|
3697
|
+
* Loads a compiled SQLite extension into every connection of this database.
|
|
3631
3698
|
*
|
|
3632
|
-
* @param extensionPath -
|
|
3699
|
+
* @param extensionPath - The path to the extension, which the driver resolves to an absolute path.
|
|
3633
3700
|
*/
|
|
3634
3701
|
async loadExtension(extensionPath) {
|
|
3635
3702
|
this.ensureOpen();
|
|
3636
3703
|
await this.runtime.loadExtension(extensionPath);
|
|
3637
3704
|
}
|
|
3638
3705
|
/**
|
|
3639
|
-
* Registers a hook that
|
|
3706
|
+
* Registers a hook that Sirannon calls before each statement on this database; throw from the hook to reject the statement.
|
|
3640
3707
|
*
|
|
3641
|
-
* @param hook -
|
|
3708
|
+
* @param hook - The hook, which Sirannon calls with the statement, its parameters, and its read or write concern.
|
|
3642
3709
|
* @returns A function that removes the hook.
|
|
3643
3710
|
*/
|
|
3644
3711
|
onBeforeQuery(hook) {
|
|
3645
3712
|
return this.runtime.hookRegistry.register("beforeQuery", hook);
|
|
3646
3713
|
}
|
|
3647
3714
|
/**
|
|
3648
|
-
* Registers a hook that
|
|
3715
|
+
* Registers a hook that Sirannon calls after each statement on this database.
|
|
3649
3716
|
*
|
|
3650
|
-
* @param hook -
|
|
3717
|
+
* @param hook - The hook, which Sirannon calls with the statement and its duration.
|
|
3651
3718
|
* @returns A function that removes the hook.
|
|
3652
3719
|
*/
|
|
3653
3720
|
onAfterQuery(hook) {
|
|
@@ -3788,9 +3855,10 @@ var LifecycleManager = class {
|
|
|
3788
3855
|
};
|
|
3789
3856
|
|
|
3790
3857
|
// src/core/lifecycle/tenant.ts
|
|
3791
|
-
var SAFE_ID_PATTERN = /^[a-
|
|
3858
|
+
var SAFE_ID_PATTERN = /^[a-z0-9][a-z0-9_-]*$/;
|
|
3792
3859
|
var MAX_ID_LENGTH = 255;
|
|
3793
3860
|
var MAX_FILENAME_LENGTH = 255;
|
|
3861
|
+
var SAFE_ID_RULE = `1 to ${MAX_ID_LENGTH} lowercase letters, digits, underscores, or hyphens, starting with a letter or a digit`;
|
|
3794
3862
|
function sanitizeTenantId(id) {
|
|
3795
3863
|
if (!id || id.length > MAX_ID_LENGTH) return void 0;
|
|
3796
3864
|
if (!SAFE_ID_PATTERN.test(id)) return void 0;
|
|
@@ -3799,7 +3867,7 @@ function sanitizeTenantId(id) {
|
|
|
3799
3867
|
function tenantPath(basePath, tenantId, extension = ".db") {
|
|
3800
3868
|
const sanitized = sanitizeTenantId(tenantId);
|
|
3801
3869
|
if (!sanitized) {
|
|
3802
|
-
throw new Error(`Invalid tenant ID: '${tenantId}'
|
|
3870
|
+
throw new Error(`Invalid tenant ID: '${tenantId}'. A tenant ID must be ${SAFE_ID_RULE}.`);
|
|
3803
3871
|
}
|
|
3804
3872
|
const filename = `${sanitized}${extension}`;
|
|
3805
3873
|
if (filename.length > MAX_FILENAME_LENGTH) {
|
|
@@ -3828,14 +3896,17 @@ var MetricsCollector = class {
|
|
|
3828
3896
|
constructor(config) {
|
|
3829
3897
|
this.config = config ?? {};
|
|
3830
3898
|
}
|
|
3831
|
-
async trackQuery(fn, context) {
|
|
3899
|
+
async trackQuery(fn, context, measure) {
|
|
3832
3900
|
if (!this.config.onQueryComplete) {
|
|
3833
3901
|
return fn();
|
|
3834
3902
|
}
|
|
3835
3903
|
const start = performance.now();
|
|
3836
3904
|
let failed = false;
|
|
3905
|
+
let outcome = {};
|
|
3837
3906
|
try {
|
|
3838
|
-
|
|
3907
|
+
const result = await fn();
|
|
3908
|
+
if (measure) outcome = measure(result);
|
|
3909
|
+
return result;
|
|
3839
3910
|
} catch (err) {
|
|
3840
3911
|
failed = true;
|
|
3841
3912
|
throw err;
|
|
@@ -3844,6 +3915,7 @@ var MetricsCollector = class {
|
|
|
3844
3915
|
try {
|
|
3845
3916
|
this.config.onQueryComplete({
|
|
3846
3917
|
...context,
|
|
3918
|
+
...outcome,
|
|
3847
3919
|
durationMs,
|
|
3848
3920
|
error: failed
|
|
3849
3921
|
});
|
|
@@ -3867,6 +3939,12 @@ var MetricsCollector = class {
|
|
|
3867
3939
|
} catch {
|
|
3868
3940
|
}
|
|
3869
3941
|
}
|
|
3942
|
+
observeDispatch(databaseId) {
|
|
3943
|
+
if (!this.config.onCDCEvent) return void 0;
|
|
3944
|
+
return (event, subscriberCount) => {
|
|
3945
|
+
this.trackCDCEvent({ databaseId, table: event.table, operation: event.type, subscriberCount });
|
|
3946
|
+
};
|
|
3947
|
+
}
|
|
3870
3948
|
get active() {
|
|
3871
3949
|
return !!(this.config.onQueryComplete || this.config.onConnectionOpen || this.config.onConnectionClose || this.config.onCDCEvent);
|
|
3872
3950
|
}
|
|
@@ -3997,10 +4075,10 @@ var RegistryMigrationSet = class {
|
|
|
3997
4075
|
}
|
|
3998
4076
|
loading = null;
|
|
3999
4077
|
/**
|
|
4000
|
-
*
|
|
4078
|
+
* Returns the migrations, and calls the source function on the first request when the migrations come from a function.
|
|
4001
4079
|
*
|
|
4002
|
-
* @returns The migrations,
|
|
4003
|
-
* @throws
|
|
4080
|
+
* @returns The migrations, or an empty list when the registry has none.
|
|
4081
|
+
* @throws A `MigrationError` with code `MIGRATION_SOURCE_INVALID` when the function returns something other than an array.
|
|
4004
4082
|
*/
|
|
4005
4083
|
load() {
|
|
4006
4084
|
const source = this.source;
|
|
@@ -4026,7 +4104,7 @@ var RegistryMigrationSet = class {
|
|
|
4026
4104
|
return loading;
|
|
4027
4105
|
}
|
|
4028
4106
|
/**
|
|
4029
|
-
* Applies the
|
|
4107
|
+
* Applies the migrations to one database, and skips a read-only database.
|
|
4030
4108
|
*
|
|
4031
4109
|
* @param db - The database to migrate.
|
|
4032
4110
|
*/
|
|
@@ -4038,6 +4116,25 @@ var RegistryMigrationSet = class {
|
|
|
4038
4116
|
}
|
|
4039
4117
|
};
|
|
4040
4118
|
|
|
4119
|
+
// src/core/registry-defaults.ts
|
|
4120
|
+
function withRegistryDefaults(registry, options) {
|
|
4121
|
+
const defaults = {};
|
|
4122
|
+
if (registry.writerWorker !== void 0 && options?.writerWorker === void 0) {
|
|
4123
|
+
defaults.writerWorker = registry.writerWorker;
|
|
4124
|
+
}
|
|
4125
|
+
if (registry.cdcRetention !== void 0 && options?.cdcRetention === void 0) {
|
|
4126
|
+
defaults.cdcRetention = registry.cdcRetention;
|
|
4127
|
+
}
|
|
4128
|
+
if (registry.deviceCursorRetention !== void 0 && options?.deviceCursorRetention === void 0) {
|
|
4129
|
+
defaults.deviceCursorRetention = registry.deviceCursorRetention;
|
|
4130
|
+
}
|
|
4131
|
+
if (registry.maxChangesHeldForDevice !== void 0 && options?.maxChangesHeldForDevice === void 0) {
|
|
4132
|
+
defaults.maxChangesHeldForDevice = registry.maxChangesHeldForDevice;
|
|
4133
|
+
}
|
|
4134
|
+
if (Object.keys(defaults).length === 0) return options;
|
|
4135
|
+
return { ...options, ...defaults };
|
|
4136
|
+
}
|
|
4137
|
+
|
|
4041
4138
|
// src/core/sirannon-offline.ts
|
|
4042
4139
|
async function takeDatabaseOffline(offline) {
|
|
4043
4140
|
await offline.database.close();
|
|
@@ -4085,12 +4182,12 @@ var Sirannon = class {
|
|
|
4085
4182
|
metricsCollector;
|
|
4086
4183
|
lifecycleManager;
|
|
4087
4184
|
migrations;
|
|
4088
|
-
/** The driver, hooks, metrics, lifecycle, migrations, and writer-worker
|
|
4185
|
+
/** The driver, hooks, metrics, lifecycle, migrations, and writer-worker and retention defaults that this registry was constructed with. */
|
|
4089
4186
|
options;
|
|
4090
4187
|
/**
|
|
4091
|
-
*
|
|
4188
|
+
* Creates a registry.
|
|
4092
4189
|
*
|
|
4093
|
-
* @param options -
|
|
4190
|
+
* @param options - The driver, hooks, metrics, lifecycle, migrations, and the defaults for every database that the registry opens.
|
|
4094
4191
|
*/
|
|
4095
4192
|
constructor(options) {
|
|
4096
4193
|
this.options = options;
|
|
@@ -4113,14 +4210,18 @@ var Sirannon = class {
|
|
|
4113
4210
|
get hookRegistry() {
|
|
4114
4211
|
return this._hookRegistry;
|
|
4115
4212
|
}
|
|
4213
|
+
/** @internal */
|
|
4214
|
+
get metrics() {
|
|
4215
|
+
return this.metricsCollector;
|
|
4216
|
+
}
|
|
4116
4217
|
/**
|
|
4117
4218
|
* Opens a database and registers it under an identifier.
|
|
4118
4219
|
*
|
|
4119
|
-
* @param id -
|
|
4120
|
-
* @param path -
|
|
4121
|
-
* @param options -
|
|
4220
|
+
* @param id - The identifier that callers use to reach this database.
|
|
4221
|
+
* @param path - The file path of the SQLite database.
|
|
4222
|
+
* @param options - The pool size, journal mode, synchronous level, and change-capture settings.
|
|
4122
4223
|
* @returns The open database.
|
|
4123
|
-
* @throws
|
|
4224
|
+
* @throws A `DatabaseAlreadyExistsError` when the identifier is already in use, or `DATABASE_OPEN_FAILED` when the open or a registry migration fails.
|
|
4124
4225
|
*/
|
|
4125
4226
|
async open(id, path, options) {
|
|
4126
4227
|
this.ensureOpenAllowed(id);
|
|
@@ -4128,7 +4229,7 @@ var Sirannon = class {
|
|
|
4128
4229
|
throw new DatabaseAlreadyExistsError(id);
|
|
4129
4230
|
}
|
|
4130
4231
|
this.opening.add(id);
|
|
4131
|
-
const resolvedOptions = this.
|
|
4232
|
+
const resolvedOptions = withRegistryDefaults(this.options, options);
|
|
4132
4233
|
let db;
|
|
4133
4234
|
try {
|
|
4134
4235
|
if (this._hookRegistry.has("beforeConnect")) {
|
|
@@ -4169,10 +4270,7 @@ var Sirannon = class {
|
|
|
4169
4270
|
this.openedWith.delete(id);
|
|
4170
4271
|
this.lifecycleManager?.untrack(id);
|
|
4171
4272
|
if (this._hookRegistry.has("databaseClose")) {
|
|
4172
|
-
|
|
4173
|
-
this._hookRegistry.invokeSync("databaseClose", { databaseId: id, path });
|
|
4174
|
-
} catch {
|
|
4175
|
-
}
|
|
4273
|
+
this._hookRegistry.invokeSyncIgnoringFailures("databaseClose", { databaseId: id, path });
|
|
4176
4274
|
}
|
|
4177
4275
|
this.metricsCollector?.trackConnection({
|
|
4178
4276
|
databaseId: id,
|
|
@@ -4185,10 +4283,7 @@ var Sirannon = class {
|
|
|
4185
4283
|
this.openedWith.set(id, resolvedOptions === void 0 ? { path } : { path, options: resolvedOptions });
|
|
4186
4284
|
this.lifecycleManager?.markActive(id);
|
|
4187
4285
|
if (this._hookRegistry.has("databaseOpen")) {
|
|
4188
|
-
|
|
4189
|
-
this._hookRegistry.invokeSync("databaseOpen", { databaseId: id, path });
|
|
4190
|
-
} catch {
|
|
4191
|
-
}
|
|
4286
|
+
this._hookRegistry.invokeSyncIgnoringFailures("databaseOpen", { databaseId: id, path });
|
|
4192
4287
|
}
|
|
4193
4288
|
this.metricsCollector?.trackConnection({
|
|
4194
4289
|
databaseId: id,
|
|
@@ -4198,15 +4293,10 @@ var Sirannon = class {
|
|
|
4198
4293
|
});
|
|
4199
4294
|
return db;
|
|
4200
4295
|
}
|
|
4201
|
-
withRegistryDefaults(options) {
|
|
4202
|
-
const fallback = this.options.writerWorker;
|
|
4203
|
-
if (fallback === void 0 || options?.writerWorker !== void 0) return options;
|
|
4204
|
-
return { ...options, writerWorker: fallback };
|
|
4205
|
-
}
|
|
4206
4296
|
/**
|
|
4207
4297
|
* Closes one database and removes it from the registry.
|
|
4208
4298
|
*
|
|
4209
|
-
* @param id -
|
|
4299
|
+
* @param id - The identifier of the database to close.
|
|
4210
4300
|
*/
|
|
4211
4301
|
async close(id) {
|
|
4212
4302
|
this.ensureRunning();
|
|
@@ -4217,19 +4307,18 @@ var Sirannon = class {
|
|
|
4217
4307
|
await db.close();
|
|
4218
4308
|
}
|
|
4219
4309
|
/**
|
|
4220
|
-
* Closes one database, calls an action
|
|
4221
|
-
*
|
|
4222
|
-
* had before.
|
|
4310
|
+
* Closes one database, calls an action on its file, and then opens that
|
|
4311
|
+
* database again under the same identifier with its earlier settings.
|
|
4223
4312
|
*
|
|
4224
|
-
* A restore rebuilds a database at
|
|
4225
|
-
*
|
|
4226
|
-
*
|
|
4227
|
-
*
|
|
4313
|
+
* A restore rebuilds a database at its current path, so no connection may be
|
|
4314
|
+
* open on that file while Sirannon replaces its bytes. {@link Sirannon.get}
|
|
4315
|
+
* returns undefined for the identifier until the database is open again, and
|
|
4316
|
+
* Sirannon reopens the database even after a failed action.
|
|
4228
4317
|
*
|
|
4229
|
-
* @param id -
|
|
4230
|
-
* @param action -
|
|
4231
|
-
* @returns Whether the action returned,
|
|
4232
|
-
* @throws
|
|
4318
|
+
* @param id - The identifier of the database to take offline.
|
|
4319
|
+
* @param action - The function that Sirannon calls with the database file path once the database is closed.
|
|
4320
|
+
* @returns Whether the action returned, the value that it returned or the error that it threw, and any error that the reopen threw.
|
|
4321
|
+
* @throws A `DatabaseNotFoundError` when no database is open under the identifier, a `ReadOnlyError` when the database is read-only, or the close error when the close fails.
|
|
4233
4322
|
*
|
|
4234
4323
|
* @internal
|
|
4235
4324
|
*/
|
|
@@ -4265,7 +4354,7 @@ var Sirannon = class {
|
|
|
4265
4354
|
/**
|
|
4266
4355
|
* Returns an already-open database.
|
|
4267
4356
|
*
|
|
4268
|
-
* @param id -
|
|
4357
|
+
* @param id - The identifier of the database.
|
|
4269
4358
|
* @returns The database, or undefined when none is open under that identifier.
|
|
4270
4359
|
*/
|
|
4271
4360
|
get(id) {
|
|
@@ -4278,15 +4367,15 @@ var Sirannon = class {
|
|
|
4278
4367
|
return void 0;
|
|
4279
4368
|
}
|
|
4280
4369
|
/**
|
|
4281
|
-
* Returns an open database,
|
|
4370
|
+
* Returns an open database, and opens it through the lifecycle resolver when it is not open yet.
|
|
4282
4371
|
*
|
|
4283
|
-
*
|
|
4284
|
-
*
|
|
4285
|
-
*
|
|
4372
|
+
* An in-process application calls this for a database that the registry opens on first use
|
|
4373
|
+
* through the `lifecycle.autoOpen` resolver, such as one file per tenant. Concurrent calls for
|
|
4374
|
+
* the same unopened identifier share one open, so each call receives the same database or the
|
|
4286
4375
|
* same error.
|
|
4287
4376
|
*
|
|
4288
|
-
* @param id -
|
|
4289
|
-
* @returns The database, or undefined when none is open and the resolver
|
|
4377
|
+
* @param id - The identifier of the database.
|
|
4378
|
+
* @returns The database, or undefined when none is open and the resolver returns no path for it.
|
|
4290
4379
|
*/
|
|
4291
4380
|
async resolve(id) {
|
|
4292
4381
|
const db = this.get(id);
|
|
@@ -4303,29 +4392,30 @@ var Sirannon = class {
|
|
|
4303
4392
|
return inFlight;
|
|
4304
4393
|
}
|
|
4305
4394
|
/**
|
|
4306
|
-
* Returns the registry migration set
|
|
4395
|
+
* Returns the registry's migration set, which Sirannon applies to each writable database as it opens.
|
|
4307
4396
|
*
|
|
4308
|
-
*
|
|
4309
|
-
*
|
|
4397
|
+
* When the set comes from a function, the registry calls that function once and caches the
|
|
4398
|
+
* result, so this returns the same list on every call; after a failed load, the next call
|
|
4399
|
+
* tries again.
|
|
4310
4400
|
*
|
|
4311
|
-
* @returns The migrations declared in `SirannonOptions.migrations`, or an empty list
|
|
4401
|
+
* @returns The migrations declared in `SirannonOptions.migrations`, or an empty list when there are none.
|
|
4312
4402
|
*/
|
|
4313
4403
|
registryMigrations() {
|
|
4314
4404
|
return this.migrations.load();
|
|
4315
4405
|
}
|
|
4316
4406
|
/**
|
|
4317
|
-
*
|
|
4407
|
+
* Returns whether a database is open under an identifier.
|
|
4318
4408
|
*
|
|
4319
|
-
* @param id -
|
|
4320
|
-
* @returns True when the registry
|
|
4409
|
+
* @param id - The identifier to check.
|
|
4410
|
+
* @returns True when the registry has an open database under that identifier.
|
|
4321
4411
|
*/
|
|
4322
4412
|
has(id) {
|
|
4323
4413
|
return this.dbs.has(id);
|
|
4324
4414
|
}
|
|
4325
4415
|
/**
|
|
4326
|
-
* Returns every database this registry
|
|
4416
|
+
* Returns every database that this registry has open.
|
|
4327
4417
|
*
|
|
4328
|
-
* @returns
|
|
4418
|
+
* @returns A copy of the open databases, keyed by identifier.
|
|
4329
4419
|
*/
|
|
4330
4420
|
databases() {
|
|
4331
4421
|
return new Map(this.dbs);
|
|
@@ -4333,9 +4423,9 @@ var Sirannon = class {
|
|
|
4333
4423
|
/**
|
|
4334
4424
|
* Closes every open database and stops the lifecycle timers.
|
|
4335
4425
|
*
|
|
4336
|
-
*
|
|
4337
|
-
* work
|
|
4338
|
-
*
|
|
4426
|
+
* When Sirannon is replacing a database's file, the shutdown waits for that
|
|
4427
|
+
* work to finish, because a process that exits part-way through the
|
|
4428
|
+
* replacement can leave no database at the path.
|
|
4339
4429
|
*/
|
|
4340
4430
|
async shutdown() {
|
|
4341
4431
|
if (this._shutdown) return;
|
|
@@ -4347,45 +4437,45 @@ var Sirannon = class {
|
|
|
4347
4437
|
await closeEveryDatabase(this.dbs);
|
|
4348
4438
|
}
|
|
4349
4439
|
/**
|
|
4350
|
-
* Registers a hook that
|
|
4440
|
+
* Registers a hook that Sirannon calls before each statement on every database in this registry; throw from the hook to reject the statement.
|
|
4351
4441
|
*
|
|
4352
|
-
* @param hook -
|
|
4442
|
+
* @param hook - The hook, which Sirannon calls with the statement, its parameters, and its read or write concern.
|
|
4353
4443
|
* @returns A function that removes the hook.
|
|
4354
4444
|
*/
|
|
4355
4445
|
onBeforeQuery(hook) {
|
|
4356
4446
|
return this._hookRegistry.register("beforeQuery", hook);
|
|
4357
4447
|
}
|
|
4358
4448
|
/**
|
|
4359
|
-
* Registers a hook that
|
|
4449
|
+
* Registers a hook that Sirannon calls after each statement on every database in this registry.
|
|
4360
4450
|
*
|
|
4361
|
-
* @param hook -
|
|
4451
|
+
* @param hook - The hook, which Sirannon calls with the statement and its duration.
|
|
4362
4452
|
* @returns A function that removes the hook.
|
|
4363
4453
|
*/
|
|
4364
4454
|
onAfterQuery(hook) {
|
|
4365
4455
|
return this._hookRegistry.register("afterQuery", hook);
|
|
4366
4456
|
}
|
|
4367
4457
|
/**
|
|
4368
|
-
* Registers a hook that
|
|
4458
|
+
* Registers a hook that Sirannon calls before it opens a database.
|
|
4369
4459
|
*
|
|
4370
|
-
* @param hook -
|
|
4460
|
+
* @param hook - The hook, which Sirannon calls with the database identifier and file path.
|
|
4371
4461
|
* @returns A function that removes the hook.
|
|
4372
4462
|
*/
|
|
4373
4463
|
onBeforeConnect(hook) {
|
|
4374
4464
|
return this._hookRegistry.register("beforeConnect", hook);
|
|
4375
4465
|
}
|
|
4376
4466
|
/**
|
|
4377
|
-
* Registers a hook that
|
|
4467
|
+
* Registers a hook that Sirannon calls once a database is open.
|
|
4378
4468
|
*
|
|
4379
|
-
* @param hook -
|
|
4469
|
+
* @param hook - The hook, which Sirannon calls with the database identifier and file path.
|
|
4380
4470
|
* @returns A function that removes the hook.
|
|
4381
4471
|
*/
|
|
4382
4472
|
onDatabaseOpen(hook) {
|
|
4383
4473
|
return this._hookRegistry.register("databaseOpen", hook);
|
|
4384
4474
|
}
|
|
4385
4475
|
/**
|
|
4386
|
-
* Registers a hook that
|
|
4476
|
+
* Registers a hook that Sirannon calls once a database is closed.
|
|
4387
4477
|
*
|
|
4388
|
-
* @param hook -
|
|
4478
|
+
* @param hook - The hook, which Sirannon calls with the database identifier and file path.
|
|
4389
4479
|
* @returns A function that removes the hook.
|
|
4390
4480
|
*/
|
|
4391
4481
|
onDatabaseClose(hook) {
|