@enbox/dwn-sql-store 0.0.10 → 0.0.11
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/esm/src/data-store-s3.js +12 -21
- package/dist/esm/src/data-store-s3.js.map +1 -1
- package/dist/esm/src/data-store-sql.js +14 -37
- package/dist/esm/src/data-store-sql.js.map +1 -1
- package/dist/esm/src/main.js +1 -0
- package/dist/esm/src/main.js.map +1 -1
- package/dist/esm/src/message-store-sql.js +13 -107
- package/dist/esm/src/message-store-sql.js.map +1 -1
- package/dist/esm/src/migration-provider.js +36 -0
- package/dist/esm/src/migration-provider.js.map +1 -0
- package/dist/esm/src/migration-runner.js +26 -88
- package/dist/esm/src/migration-runner.js.map +1 -1
- package/dist/esm/src/migrations/001-initial-schema.js +4 -5
- package/dist/esm/src/migrations/001-initial-schema.js.map +1 -1
- package/dist/esm/src/migrations/002-content-addressed-datastore.js +3 -4
- package/dist/esm/src/migrations/002-content-addressed-datastore.js.map +1 -1
- package/dist/esm/src/migrations/003-add-squash-column.js +3 -4
- package/dist/esm/src/migrations/003-add-squash-column.js.map +1 -1
- package/dist/esm/src/migrations/index.js +14 -6
- package/dist/esm/src/migrations/index.js.map +1 -1
- package/dist/esm/src/resumable-task-store-sql.js +14 -21
- package/dist/esm/src/resumable-task-store-sql.js.map +1 -1
- package/dist/esm/src/state-index-sql.js +17 -58
- package/dist/esm/src/state-index-sql.js.map +1 -1
- package/dist/types/src/data-store-s3.d.ts.map +1 -1
- package/dist/types/src/data-store-sql.d.ts.map +1 -1
- package/dist/types/src/main.d.ts +1 -0
- package/dist/types/src/main.d.ts.map +1 -1
- package/dist/types/src/message-store-sql.d.ts +0 -8
- package/dist/types/src/message-store-sql.d.ts.map +1 -1
- package/dist/types/src/migration-provider.d.ts +36 -0
- package/dist/types/src/migration-provider.d.ts.map +1 -0
- package/dist/types/src/migration-runner.d.ts +13 -39
- package/dist/types/src/migration-runner.d.ts.map +1 -1
- package/dist/types/src/migrations/001-initial-schema.d.ts +3 -3
- package/dist/types/src/migrations/001-initial-schema.d.ts.map +1 -1
- package/dist/types/src/migrations/002-content-addressed-datastore.d.ts +2 -2
- package/dist/types/src/migrations/002-content-addressed-datastore.d.ts.map +1 -1
- package/dist/types/src/migrations/003-add-squash-column.d.ts +2 -2
- package/dist/types/src/migrations/003-add-squash-column.d.ts.map +1 -1
- package/dist/types/src/migrations/index.d.ts +12 -4
- package/dist/types/src/migrations/index.d.ts.map +1 -1
- package/dist/types/src/resumable-task-store-sql.d.ts.map +1 -1
- package/dist/types/src/state-index-sql.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/data-store-s3.ts +14 -25
- package/src/data-store-sql.ts +15 -44
- package/src/main.ts +1 -0
- package/src/message-store-sql.ts +14 -113
- package/src/migration-provider.ts +52 -0
- package/src/migration-runner.ts +33 -123
- package/src/migrations/001-initial-schema.ts +6 -7
- package/src/migrations/002-content-addressed-datastore.ts +5 -6
- package/src/migrations/003-add-squash-column.ts +5 -7
- package/src/migrations/index.ts +15 -7
- package/src/resumable-task-store-sql.ts +16 -25
- package/src/state-index-sql.ts +18 -62
package/src/migrations/index.ts
CHANGED
|
@@ -1,15 +1,23 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { DwnMigrationFactory } from '../migration-provider.js';
|
|
2
2
|
|
|
3
3
|
import { migration001InitialSchema } from './001-initial-schema.js';
|
|
4
4
|
import { migration002ContentAddressedDatastore } from './002-content-addressed-datastore.js';
|
|
5
5
|
import { migration003AddSquashColumn } from './003-add-squash-column.js';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
* All migrations in sequential order.
|
|
9
|
-
*
|
|
8
|
+
* All DWN store migrations in sequential order.
|
|
9
|
+
*
|
|
10
|
+
* Each entry is a `[name, factory]` tuple where the factory is a
|
|
11
|
+
* {@link DwnMigrationFactory} that receives the dialect and returns a
|
|
12
|
+
* standard Kysely `Migration`. The `DwnMigrationProvider` resolves these
|
|
13
|
+
* into the `Record<string, Migration>` that Kysely's `Migrator` expects.
|
|
14
|
+
*
|
|
15
|
+
* **Ordering contract:** Entries MUST be sorted by name (lexicographic).
|
|
16
|
+
* Kysely's `Migrator` sorts by key as well, but maintaining order here
|
|
17
|
+
* makes the source of truth explicit and human-readable.
|
|
10
18
|
*/
|
|
11
|
-
export const
|
|
12
|
-
migration001InitialSchema,
|
|
13
|
-
migration002ContentAddressedDatastore,
|
|
14
|
-
migration003AddSquashColumn,
|
|
19
|
+
export const allDwnMigrations: ReadonlyArray<readonly [name: string, factory: DwnMigrationFactory]> = [
|
|
20
|
+
['001-initial-schema', migration001InitialSchema],
|
|
21
|
+
['002-content-addressed-datastore', migration002ContentAddressedDatastore],
|
|
22
|
+
['003-add-squash-column', migration003AddSquashColumn],
|
|
15
23
|
];
|
|
@@ -4,7 +4,7 @@ import type { ManagedResumableTask, ResumableTaskStore } from '@enbox/dwn-sdk-js
|
|
|
4
4
|
|
|
5
5
|
import { Cid } from '@enbox/dwn-sdk-js';
|
|
6
6
|
import { executeWithTransaction } from './utils/transaction.js';
|
|
7
|
-
import { Kysely } from 'kysely';
|
|
7
|
+
import { Kysely, sql } from 'kysely';
|
|
8
8
|
|
|
9
9
|
export class ResumableTaskStoreSql implements ResumableTaskStore {
|
|
10
10
|
private static readonly taskTimeoutInSeconds = 60;
|
|
@@ -23,31 +23,22 @@ export class ResumableTaskStoreSql implements ResumableTaskStore {
|
|
|
23
23
|
|
|
24
24
|
this.#db = new Kysely<DwnDatabaseType>({ dialect: this.#dialect });
|
|
25
25
|
|
|
26
|
-
// if
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
if (tableExists) {
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// else create the table and corresponding indexes
|
|
34
|
-
|
|
35
|
-
const table = this.#db.schema
|
|
36
|
-
.createTable(tableName)
|
|
37
|
-
.ifNotExists() // kept to show supported by all dialects in contrast to ifNotExists() below, though not needed due to hasTable() check above
|
|
38
|
-
.addColumn('id', 'varchar(255)', (col) => col.primaryKey())
|
|
39
|
-
.addColumn('task', 'text')
|
|
40
|
-
.addColumn('timeout', 'bigint')
|
|
41
|
-
.addColumn('retryCount', 'integer');
|
|
42
|
-
|
|
43
|
-
await table.execute();
|
|
26
|
+
// Fail fast if migrations have not been run — tables must already exist.
|
|
27
|
+
await this.#assertTablesExist();
|
|
28
|
+
}
|
|
44
29
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
30
|
+
/**
|
|
31
|
+
* Verifies that the required tables exist by executing a zero-row SELECT.
|
|
32
|
+
* Throws a clear error directing the caller to run migrations first.
|
|
33
|
+
*/
|
|
34
|
+
async #assertTablesExist(): Promise<void> {
|
|
35
|
+
try {
|
|
36
|
+
await sql`SELECT 1 FROM ${sql.table('resumableTasks')} LIMIT 0`.execute(this.#db!);
|
|
37
|
+
} catch {
|
|
38
|
+
throw new Error(
|
|
39
|
+
'ResumableTaskStoreSql: table \'resumableTasks\' does not exist. Run DWN store migrations before opening stores.'
|
|
40
|
+
);
|
|
41
|
+
}
|
|
51
42
|
}
|
|
52
43
|
|
|
53
44
|
async close(): Promise<void> {
|
package/src/state-index-sql.ts
CHANGED
|
@@ -16,9 +16,9 @@ import type { KeyValues } from '@enbox/dwn-sdk-js';
|
|
|
16
16
|
import type { StateIndex } from '@enbox/dwn-sdk-js';
|
|
17
17
|
|
|
18
18
|
import { initDefaultHashes } from '@enbox/dwn-sdk-js';
|
|
19
|
-
import { Kysely } from 'kysely';
|
|
20
19
|
import { SMTStoreSql } from './smt-store-sql.js';
|
|
21
20
|
import { SparseMerkleTree } from '@enbox/dwn-sdk-js';
|
|
21
|
+
import { Kysely, sql } from 'kysely';
|
|
22
22
|
|
|
23
23
|
export class StateIndexSql implements StateIndex {
|
|
24
24
|
#dialect: Dialect;
|
|
@@ -51,68 +51,24 @@ export class StateIndexSql implements StateIndex {
|
|
|
51
51
|
// Ensure default hashes are initialized for the SMT
|
|
52
52
|
await initDefaultHashes();
|
|
53
53
|
|
|
54
|
-
//
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
if (!nodesTableExists) {
|
|
58
|
-
await this.#db.schema
|
|
59
|
-
.createTable(nodesTableName)
|
|
60
|
-
.ifNotExists()
|
|
61
|
-
.addColumn('tenant', 'varchar(255)', (col) => col.notNull())
|
|
62
|
-
.addColumn('scope', 'varchar(200)', (col) => col.notNull())
|
|
63
|
-
.addColumn('nodeHash', 'varchar(64)', (col) => col.notNull())
|
|
64
|
-
.addColumn('nodeType', 'varchar(10)', (col) => col.notNull())
|
|
65
|
-
.addColumn('leftHash', 'varchar(64)')
|
|
66
|
-
.addColumn('rightHash', 'varchar(64)')
|
|
67
|
-
.addColumn('leafKeyHash', 'varchar(64)')
|
|
68
|
-
.addColumn('leafValueCid', 'varchar(60)')
|
|
69
|
-
.execute();
|
|
70
|
-
|
|
71
|
-
// Not UNIQUE because the delete-then-insert upsert pattern in SMTStoreSql
|
|
72
|
-
// can race under concurrent access, causing duplicate key violations.
|
|
73
|
-
await this.#db.schema
|
|
74
|
-
.createIndex('index_stateIndexNodes_tenant_scope_nodeHash')
|
|
75
|
-
.on(nodesTableName)
|
|
76
|
-
.columns(['tenant', 'scope', 'nodeHash'])
|
|
77
|
-
.execute();
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// ─── Create stateIndexRoots table ─────────────────────────────────────
|
|
81
|
-
const rootsTableName = 'stateIndexRoots';
|
|
82
|
-
const rootsTableExists = await this.#dialect.hasTable(this.#db, rootsTableName);
|
|
83
|
-
if (!rootsTableExists) {
|
|
84
|
-
await this.#db.schema
|
|
85
|
-
.createTable(rootsTableName)
|
|
86
|
-
.ifNotExists()
|
|
87
|
-
.addColumn('tenant', 'varchar(255)', (col) => col.notNull())
|
|
88
|
-
.addColumn('scope', 'varchar(200)', (col) => col.notNull())
|
|
89
|
-
.addColumn('rootHash', 'varchar(64)', (col) => col.notNull())
|
|
90
|
-
.execute();
|
|
91
|
-
|
|
92
|
-
await this.#db.schema
|
|
93
|
-
.createIndex('index_stateIndexRoots_tenant_scope')
|
|
94
|
-
.on(rootsTableName)
|
|
95
|
-
.columns(['tenant', 'scope'])
|
|
96
|
-
.execute();
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// ─── Create stateIndexMeta table ──────────────────────────────────────
|
|
100
|
-
const metaTableName = 'stateIndexMeta';
|
|
101
|
-
const metaTableExists = await this.#dialect.hasTable(this.#db, metaTableName);
|
|
102
|
-
if (!metaTableExists) {
|
|
103
|
-
await this.#db.schema
|
|
104
|
-
.createTable(metaTableName)
|
|
105
|
-
.ifNotExists()
|
|
106
|
-
.addColumn('tenant', 'varchar(255)', (col) => col.notNull())
|
|
107
|
-
.addColumn('messageCid', 'varchar(60)', (col) => col.notNull())
|
|
108
|
-
.addColumn('protocol', 'varchar(200)')
|
|
109
|
-
.execute();
|
|
54
|
+
// Fail fast if migrations have not been run — tables must already exist.
|
|
55
|
+
await this.#assertTablesExist();
|
|
56
|
+
}
|
|
110
57
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
58
|
+
/**
|
|
59
|
+
* Verifies that the required tables exist by executing a zero-row SELECT.
|
|
60
|
+
* Throws a clear error directing the caller to run migrations first.
|
|
61
|
+
*/
|
|
62
|
+
async #assertTablesExist(): Promise<void> {
|
|
63
|
+
const tables = ['stateIndexNodes', 'stateIndexRoots', 'stateIndexMeta'] as const;
|
|
64
|
+
for (const table of tables) {
|
|
65
|
+
try {
|
|
66
|
+
await sql`SELECT 1 FROM ${sql.table(table)} LIMIT 0`.execute(this.#db!);
|
|
67
|
+
} catch {
|
|
68
|
+
throw new Error(
|
|
69
|
+
`StateIndexSql: table '${table}' does not exist. Run DWN store migrations before opening stores.`
|
|
70
|
+
);
|
|
71
|
+
}
|
|
116
72
|
}
|
|
117
73
|
}
|
|
118
74
|
|