@earendil-works/pi-durable 1.1.0 → 1.3.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/CHANGELOG.md +55 -0
- package/README.md +164 -11
- package/dist/codemode/codemode.d.ts +173 -0
- package/dist/codemode/codemode.d.ts.map +1 -0
- package/dist/codemode/codemode.js +886 -0
- package/dist/codemode/codemode.js.map +1 -0
- package/dist/codemode/describe.d.ts +38 -0
- package/dist/codemode/describe.d.ts.map +1 -0
- package/dist/codemode/describe.js +119 -0
- package/dist/codemode/describe.js.map +1 -0
- package/dist/codemode/index.d.ts +3 -0
- package/dist/codemode/index.d.ts.map +1 -0
- package/dist/codemode/index.js +3 -0
- package/dist/codemode/index.js.map +1 -0
- package/dist/codemode/models.d.ts +28 -0
- package/dist/codemode/models.d.ts.map +1 -0
- package/dist/codemode/models.js +231 -0
- package/dist/codemode/models.js.map +1 -0
- package/dist/codemode/output.d.ts +41 -0
- package/dist/codemode/output.d.ts.map +1 -0
- package/dist/codemode/output.js +167 -0
- package/dist/codemode/output.js.map +1 -0
- package/dist/env/index.d.ts +43 -0
- package/dist/env/index.d.ts.map +1 -1
- package/dist/env/index.js.map +1 -1
- package/dist/errors.d.ts +20 -3
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +34 -5
- package/dist/errors.js.map +1 -1
- package/dist/harness/agent.d.ts +5 -2
- package/dist/harness/agent.d.ts.map +1 -1
- package/dist/harness/agent.js +69 -25
- package/dist/harness/agent.js.map +1 -1
- package/dist/harness/compaction.d.ts +6 -1
- package/dist/harness/compaction.d.ts.map +1 -1
- package/dist/harness/compaction.js +10 -7
- package/dist/harness/compaction.js.map +1 -1
- package/dist/harness/context.d.ts +5 -0
- package/dist/harness/context.d.ts.map +1 -1
- package/dist/harness/context.js +46 -12
- package/dist/harness/context.js.map +1 -1
- package/dist/harness/events.d.ts +35 -15
- package/dist/harness/events.d.ts.map +1 -1
- package/dist/harness/events.js +77 -23
- package/dist/harness/events.js.map +1 -1
- package/dist/harness/generation.d.ts +2 -0
- package/dist/harness/generation.d.ts.map +1 -1
- package/dist/harness/generation.js +31 -8
- package/dist/harness/generation.js.map +1 -1
- package/dist/harness/harness.d.ts +7 -0
- package/dist/harness/harness.d.ts.map +1 -1
- package/dist/harness/harness.js +53 -26
- package/dist/harness/harness.js.map +1 -1
- package/dist/harness/inbox.d.ts +16 -4
- package/dist/harness/inbox.d.ts.map +1 -1
- package/dist/harness/inbox.js +26 -3
- package/dist/harness/inbox.js.map +1 -1
- package/dist/harness/live.d.ts +74 -17
- package/dist/harness/live.d.ts.map +1 -1
- package/dist/harness/live.js +66 -14
- package/dist/harness/live.js.map +1 -1
- package/dist/harness/scheduler.d.ts +18 -5
- package/dist/harness/scheduler.d.ts.map +1 -1
- package/dist/harness/scheduler.js +696 -163
- package/dist/harness/scheduler.js.map +1 -1
- package/dist/harness/submissions.d.ts +7 -4
- package/dist/harness/submissions.d.ts.map +1 -1
- package/dist/harness/submissions.js +32 -13
- package/dist/harness/submissions.js.map +1 -1
- package/dist/harness/task-graph.d.ts +1 -1
- package/dist/harness/task-graph.d.ts.map +1 -1
- package/dist/harness/task-graph.js +15 -10
- package/dist/harness/task-graph.js.map +1 -1
- package/dist/harness/tool.d.ts +45 -5
- package/dist/harness/tool.d.ts.map +1 -1
- package/dist/harness/tool.js +378 -63
- package/dist/harness/tool.js.map +1 -1
- package/dist/harness/types.d.ts +153 -13
- package/dist/harness/types.d.ts.map +1 -1
- package/dist/harness/types.js.map +1 -1
- package/dist/harness/util.d.ts +6 -1
- package/dist/harness/util.d.ts.map +1 -1
- package/dist/harness/util.js +5 -2
- package/dist/harness/util.js.map +1 -1
- package/dist/harness/view.d.ts +6 -2
- package/dist/harness/view.d.ts.map +1 -1
- package/dist/harness/view.js +22 -12
- package/dist/harness/view.js.map +1 -1
- package/dist/images/cloudflare.d.ts +4 -0
- package/dist/images/cloudflare.d.ts.map +1 -0
- package/dist/images/cloudflare.js +9 -0
- package/dist/images/cloudflare.js.map +1 -0
- package/dist/images/exif.d.ts +3 -0
- package/dist/images/exif.d.ts.map +1 -0
- package/dist/images/exif.js +71 -0
- package/dist/images/exif.js.map +1 -0
- package/dist/images/index.d.ts +18 -0
- package/dist/images/index.d.ts.map +1 -0
- package/dist/images/index.js +125 -0
- package/dist/images/index.js.map +1 -0
- package/dist/images/node-worker.d.ts +17 -0
- package/dist/images/node-worker.d.ts.map +1 -0
- package/dist/images/node-worker.js +16 -0
- package/dist/images/node-worker.js.map +1 -0
- package/dist/images/node.d.ts +21 -0
- package/dist/images/node.d.ts.map +1 -0
- package/dist/images/node.js +121 -0
- package/dist/images/node.js.map +1 -0
- package/dist/index.d.ts +6 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/search.d.ts +13 -0
- package/dist/search.d.ts.map +1 -0
- package/dist/search.js +85 -0
- package/dist/search.js.map +1 -0
- package/dist/session/observation.d.ts +10 -3
- package/dist/session/observation.d.ts.map +1 -1
- package/dist/session/observation.js +24 -34
- package/dist/session/observation.js.map +1 -1
- package/dist/session/session.d.ts +68 -5
- package/dist/session/session.d.ts.map +1 -1
- package/dist/session/session.js +461 -49
- package/dist/session/session.js.map +1 -1
- package/dist/session/transaction.d.ts.map +1 -1
- package/dist/session/transaction.js +1 -0
- package/dist/session/transaction.js.map +1 -1
- package/dist/storage/jsonl/storage.d.ts +4 -0
- package/dist/storage/jsonl/storage.d.ts.map +1 -1
- package/dist/storage/jsonl/storage.js +2 -1
- package/dist/storage/jsonl/storage.js.map +1 -1
- package/dist/storage/memory.d.ts.map +1 -1
- package/dist/storage/memory.js +8 -10
- package/dist/storage/memory.js.map +1 -1
- package/dist/storage/scan.d.ts.map +1 -1
- package/dist/storage/scan.js +5 -4
- package/dist/storage/scan.js.map +1 -1
- package/dist/storage/sqlite/cloudflare.d.ts +17 -5
- package/dist/storage/sqlite/cloudflare.d.ts.map +1 -1
- package/dist/storage/sqlite/cloudflare.js +57 -21
- package/dist/storage/sqlite/cloudflare.js.map +1 -1
- package/dist/storage/sqlite/index.d.ts +1 -1
- package/dist/storage/sqlite/index.d.ts.map +1 -1
- package/dist/storage/sqlite/index.js.map +1 -1
- package/dist/storage/sqlite/migrations.d.ts +5 -1
- package/dist/storage/sqlite/migrations.d.ts.map +1 -1
- package/dist/storage/sqlite/migrations.js +94 -84
- package/dist/storage/sqlite/migrations.js.map +1 -1
- package/dist/storage/sqlite/node.d.ts +6 -4
- package/dist/storage/sqlite/node.d.ts.map +1 -1
- package/dist/storage/sqlite/node.js +6 -2
- package/dist/storage/sqlite/node.js.map +1 -1
- package/dist/storage/sqlite/schema.d.ts +47 -0
- package/dist/storage/sqlite/schema.d.ts.map +1 -0
- package/dist/storage/sqlite/schema.js +57 -0
- package/dist/storage/sqlite/schema.js.map +1 -0
- package/dist/storage/sqlite/storage.d.ts +9 -1
- package/dist/storage/sqlite/storage.d.ts.map +1 -1
- package/dist/storage/sqlite/storage.js +56 -55
- package/dist/storage/sqlite/storage.js.map +1 -1
- package/dist/testing/env-conformance.d.ts.map +1 -1
- package/dist/testing/env-conformance.js +100 -0
- package/dist/testing/env-conformance.js.map +1 -1
- package/dist/testing/runner.d.ts +1 -1
- package/dist/testing/runner.d.ts.map +1 -1
- package/dist/testing/runner.js.map +1 -1
- package/dist/testing/storage-conformance.d.ts.map +1 -1
- package/dist/testing/storage-conformance.js +3 -2
- package/dist/testing/storage-conformance.js.map +1 -1
- package/dist/testing/types.d.ts +2 -0
- package/dist/testing/types.d.ts.map +1 -1
- package/dist/testing/types.js.map +1 -1
- package/dist/tool-search/index.d.ts +2 -0
- package/dist/tool-search/index.d.ts.map +1 -0
- package/dist/tool-search/index.js +2 -0
- package/dist/tool-search/index.js.map +1 -0
- package/dist/tool-search/tool-search.d.ts +23 -0
- package/dist/tool-search/tool-search.d.ts.map +1 -0
- package/dist/tool-search/tool-search.js +84 -0
- package/dist/tool-search/tool-search.js.map +1 -0
- package/dist/tools/bash.d.ts +10 -2
- package/dist/tools/bash.d.ts.map +1 -1
- package/dist/tools/bash.js +27 -9
- package/dist/tools/bash.js.map +1 -1
- package/dist/tools/edit.js +1 -1
- package/dist/tools/edit.js.map +1 -1
- package/dist/tools/image-processor.d.ts +50 -0
- package/dist/tools/image-processor.d.ts.map +1 -0
- package/dist/tools/image-processor.js +20 -0
- package/dist/tools/image-processor.js.map +1 -0
- package/dist/tools/image.d.ts +8 -0
- package/dist/tools/image.d.ts.map +1 -1
- package/dist/tools/image.js +47 -0
- package/dist/tools/image.js.map +1 -1
- package/dist/tools/index.d.ts +25 -2
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +13 -5
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/read.d.ts +10 -2
- package/dist/tools/read.d.ts.map +1 -1
- package/dist/tools/read.js +88 -29
- package/dist/tools/read.js.map +1 -1
- package/dist/tools/write.js +1 -1
- package/dist/tools/write.js.map +1 -1
- package/dist/truncate.d.ts +3 -2
- package/dist/truncate.d.ts.map +1 -1
- package/dist/truncate.js +4 -34
- package/dist/truncate.js.map +1 -1
- package/dist/types.d.ts +59 -5
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +43 -4
- package/dist/harness/output.d.ts +0 -69
- package/dist/harness/output.d.ts.map +0 -1
- package/dist/harness/output.js +0 -318
- package/dist/harness/output.js.map +0 -1
|
@@ -2,9 +2,17 @@ import type { Context, JsonValue } from "@earendil-works/chord";
|
|
|
2
2
|
import type { ConversationId, ConversationQuery, ConversationRecord, Cursor, DocumentAddress, DocumentId, DocumentPoint, DocumentQuery, DocumentRecord, EntryId, EntryQuery, EntryRecord, Id, Page, Seq, Storage, StorageWrite, StoredDocument, SubmissionId, SubmissionQuery, SubmissionRecord, TaskId, TaskQuery, TaskRecord } from "../../types.ts";
|
|
3
3
|
import type { SqliteDatabase } from "./database.ts";
|
|
4
4
|
type StoredTask = TaskRecord<JsonValue, JsonValue, JsonValue>;
|
|
5
|
+
export type SqliteStorageOptions = {
|
|
6
|
+
/**
|
|
7
|
+
* Prefix for every table and index in the durable schema. It must be a SQLite identifier and must not use
|
|
8
|
+
* SQLite's reserved `sqlite_` prefix. Existing data is not migrated when this changes.
|
|
9
|
+
*/
|
|
10
|
+
readonly prefix?: string;
|
|
11
|
+
};
|
|
5
12
|
/** Portable SQLite implementation of the Pico storage contract. */
|
|
6
13
|
export declare class SqliteStorage implements Storage {
|
|
7
14
|
private readonly db;
|
|
15
|
+
private readonly schema;
|
|
8
16
|
private nextId;
|
|
9
17
|
private closed;
|
|
10
18
|
private closing;
|
|
@@ -12,7 +20,7 @@ export declare class SqliteStorage implements Storage {
|
|
|
12
20
|
private readsDrained;
|
|
13
21
|
private constructor();
|
|
14
22
|
/** Initialize storage over an owned SQLite database facade. */
|
|
15
|
-
static open(db: SqliteDatabase): Promise<SqliteStorage>;
|
|
23
|
+
static open(db: SqliteDatabase, options?: SqliteStorageOptions): Promise<SqliteStorage>;
|
|
16
24
|
commit(writes: readonly StorageWrite[], _context: Context): Promise<Seq>;
|
|
17
25
|
mintId<I extends Id<string>>(): Promise<I>;
|
|
18
26
|
conversation(id: ConversationId, _context: Context): Promise<ConversationRecord | undefined>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../../src/storage/sqlite/storage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAIhE,OAAO,KAAK,EACX,cAAc,EACd,iBAAiB,EACjB,kBAAkB,EAClB,MAAM,EACN,eAAe,EAGf,UAAU,EACV,aAAa,EACb,aAAa,EACb,cAAc,EACd,OAAO,EACP,UAAU,EACV,WAAW,EACX,EAAE,EAEF,IAAI,EAEJ,GAAG,EACH,OAAO,EACP,YAAY,EACZ,cAAc,EACd,YAAY,EACZ,eAAe,EACf,gBAAgB,EAChB,MAAM,EACN,SAAS,EACT,UAAU,EACV,MAAM,gBAAgB,CAAC;AAExB,OAAO,KAAK,EAAE,cAAc,EAA+B,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../../src/storage/sqlite/storage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAIhE,OAAO,KAAK,EACX,cAAc,EACd,iBAAiB,EACjB,kBAAkB,EAClB,MAAM,EACN,eAAe,EAGf,UAAU,EACV,aAAa,EACb,aAAa,EACb,cAAc,EACd,OAAO,EACP,UAAU,EACV,WAAW,EACX,EAAE,EAEF,IAAI,EAEJ,GAAG,EACH,OAAO,EACP,YAAY,EACZ,cAAc,EACd,YAAY,EACZ,eAAe,EACf,gBAAgB,EAChB,MAAM,EACN,SAAS,EACT,UAAU,EACV,MAAM,gBAAgB,CAAC;AAExB,OAAO,KAAK,EAAE,cAAc,EAA+B,MAAM,eAAe,CAAC;AAIjF,KAAK,UAAU,GAAG,UAAU,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;AAwB9D,MAAM,MAAM,oBAAoB,GAAG;IAClC;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAiFF,mEAAmE;AACnE,qBAAa,aAAc,YAAW,OAAO;IAC5C,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAiB;IACpC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAe;IACtC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,OAAO,CAA4B;IAC3C,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,YAAY,CAA2B;IAE/C,OAAO,eAIN;IAED,+DAA+D;IAC/D,OAAa,IAAI,CAAC,EAAE,EAAE,cAAc,EAAE,OAAO,GAAE,oBAAyB,GAAG,OAAO,CAAC,aAAa,CAAC,CAiBhG;IAEK,MAAM,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,EAAE,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,CAuB7E;IAEK,MAAM,CAAC,CAAC,SAAS,EAAE,CAAC,MAAM,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAI/C;IAEK,YAAY,CAAC,EAAE,EAAE,cAAc,EAAE,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,kBAAkB,GAAG,SAAS,CAAC,CAIjG;IAEK,iBAAiB,CACtB,KAAK,EAAE,iBAAiB,EACxB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,QAAQ,EAAE,OAAO,GACf,OAAO,CAAC,IAAI,CAAC,kBAAkB,EAAE,MAAM,CAAC,CAAC,CAwB3C;IAED,KAAK,CAAC,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC;QAAE,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;QAAC,QAAQ,CAAC,SAAS,EAAE,GAAG,CAAA;KAAE,GAAG,SAAS,CAAC,CAAC;IACpH,KAAK,CACJ,cAAc,EAAE,cAAc,EAC9B,EAAE,EAAE,OAAO,EACX,OAAO,EAAE,OAAO,GACd,OAAO,CAAC;QAAE,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;QAAC,QAAQ,CAAC,SAAS,EAAE,GAAG,CAAA;KAAE,GAAG,SAAS,CAAC,CAAC;IASjF,oBAAoB,CACnB,cAAc,EAAE,cAAc,EAC9B,iBAAiB,EAAE,OAAO,GAAG,SAAS,EACtC,QAAQ,EAAE,OAAO,GACf,OAAO,CAAC,CAAC,WAAW,GAAG;QAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;KAAE,CAAC,GAAG,SAAS,CAAC,CAEjE;IAED,WAAW,CACV,KAAK,EAAE,UAAU,EACjB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,QAAQ,EAAE,OAAO,GACf,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAEpC;YAEa,SAAS;YAoCT,oBAAoB;YA0BpB,WAAW;IAqCzB,6GAA6G;YAC/F,oBAAoB;IAyC5B,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAIzE;IAEK,SAAS,CACd,KAAK,EAAE,SAAS,EAChB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,QAAQ,EAAE,OAAO,GACf,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAoCnC;IAEK,UAAU,CAAC,EAAE,EAAE,YAAY,EAAE,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAI3F;IAEK,eAAe,CACpB,KAAK,EAAE,eAAe,EACtB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,QAAQ,EAAE,OAAO,GACf,OAAO,CAAC,IAAI,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAC,CAwBzC;IAEK,mBAAmB,CACxB,cAAc,EAAE,cAAc,EAC9B,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,OAAO,GACf,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAQvC;IAEK,YAAY,CACjB,OAAO,EAAE,eAAe,EACxB,EAAE,EAAE,aAAa,EACjB,QAAQ,EAAE,OAAO,GACf,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC,CAgBrC;IAEK,QAAQ,CAAC,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,aAAa,EAAE,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC,CAIxG;IAEK,aAAa,CAClB,KAAK,EAAE,aAAa,EACpB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,QAAQ,EAAE,OAAO,GACf,OAAO,CAAC,IAAI,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC,CAwBvC;IAED,KAAK,CAAC,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAMtC;YAEa,aAAa;IAS3B;;;OAGG;YACW,SAAS;YAUT,gBAAgB;YAKhB,mBAAmB;IAqCjC,OAAO,CAAC,eAAe;YAST,cAAc;IAuB5B,OAAO,CAAC,sBAAsB;YA+ChB,oBAAoB;YAqCpB,iBAAiB;YAoBjB,eAAe;YA6Df,OAAO;YAQP,oBAAoB;IA0FlC,OAAO,CAAC,UAAU;CAGlB"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { apply } from "@earendil-works/chord/delta";
|
|
2
|
-
import {
|
|
2
|
+
import { StorageRequestError } from "../../errors.js";
|
|
3
3
|
import { idFromNumber, seqFromNumber } from "../../ids.js";
|
|
4
4
|
import { nextCursor, scanStart } from "../scan.js";
|
|
5
|
-
import {
|
|
5
|
+
import { applySqliteMigrationsForSchema } from "./migrations.js";
|
|
6
|
+
import { createSqliteSchema } from "./schema.js";
|
|
6
7
|
const parseJson = (value) => JSON.parse(value);
|
|
7
8
|
const encodeJson = (value) => JSON.stringify(value);
|
|
8
9
|
// Some SQLite bindings replace lone UTF-16 surrogates. JSON encoding keeps indexed identities lossless.
|
|
@@ -12,7 +13,7 @@ const cursorId = (cursor) => {
|
|
|
12
13
|
if (after === undefined)
|
|
13
14
|
return undefined;
|
|
14
15
|
if (typeof after !== "number" || !Number.isSafeInteger(after))
|
|
15
|
-
throw new
|
|
16
|
+
throw new StorageRequestError("Invalid storage cursor");
|
|
16
17
|
return idFromNumber(after);
|
|
17
18
|
};
|
|
18
19
|
const page = (values, limit, order = "ascending") => {
|
|
@@ -72,23 +73,26 @@ const writeId = (write) => {
|
|
|
72
73
|
/** Portable SQLite implementation of the Pico storage contract. */
|
|
73
74
|
export class SqliteStorage {
|
|
74
75
|
db;
|
|
76
|
+
schema;
|
|
75
77
|
nextId;
|
|
76
78
|
closed = false;
|
|
77
79
|
closing;
|
|
78
80
|
admittedReads = 0;
|
|
79
81
|
readsDrained;
|
|
80
|
-
constructor(db, nextId) {
|
|
82
|
+
constructor(db, schema, nextId) {
|
|
81
83
|
this.db = db;
|
|
84
|
+
this.schema = schema;
|
|
82
85
|
this.nextId = nextId;
|
|
83
86
|
}
|
|
84
87
|
/** Initialize storage over an owned SQLite database facade. */
|
|
85
|
-
static async open(db) {
|
|
88
|
+
static async open(db, options = {}) {
|
|
86
89
|
try {
|
|
87
|
-
|
|
88
|
-
|
|
90
|
+
const schema = createSqliteSchema(options.prefix);
|
|
91
|
+
await applySqliteMigrationsForSchema(db, schema);
|
|
92
|
+
const metadata = await db.get(`SELECT next_id, next_seq FROM ${schema.tables.durableMetadata} WHERE singleton = 1`);
|
|
89
93
|
if (metadata === undefined)
|
|
90
94
|
throw new Error("Durable SQLite metadata is missing");
|
|
91
|
-
return new SqliteStorage(db, Number(metadata.next_id));
|
|
95
|
+
return new SqliteStorage(db, schema, Number(metadata.next_id));
|
|
92
96
|
}
|
|
93
97
|
catch (error) {
|
|
94
98
|
try {
|
|
@@ -105,7 +109,7 @@ export class SqliteStorage {
|
|
|
105
109
|
const documentActions = this.prepareDocumentActions(writes);
|
|
106
110
|
const candidateNextId = this.candidateNextId(writes);
|
|
107
111
|
const seq = await this.db.transaction(async (transaction) => {
|
|
108
|
-
const metadata = await transaction.get(
|
|
112
|
+
const metadata = await transaction.get(`SELECT next_id, next_seq FROM ${this.schema.tables.durableMetadata} WHERE singleton = 1`);
|
|
109
113
|
if (metadata === undefined)
|
|
110
114
|
throw new Error("Durable SQLite metadata is missing");
|
|
111
115
|
const committedSeq = seqFromNumber(metadata.next_seq);
|
|
@@ -114,7 +118,7 @@ export class SqliteStorage {
|
|
|
114
118
|
for (const write of writes)
|
|
115
119
|
await this.applyTableWrite(transaction, write, committedSeq);
|
|
116
120
|
await this.applyDocumentActions(transaction, documentActions, committedSeq);
|
|
117
|
-
await transaction.run(
|
|
121
|
+
await transaction.run(`UPDATE ${this.schema.tables.durableMetadata} SET next_id = ?, next_seq = ? WHERE singleton = 1`, String(Math.max(Number(metadata.next_id), candidateNextId)), committedSeq + 1);
|
|
118
122
|
return committedSeq;
|
|
119
123
|
});
|
|
120
124
|
this.nextId = Math.max(this.nextId, candidateNextId);
|
|
@@ -128,7 +132,7 @@ export class SqliteStorage {
|
|
|
128
132
|
}
|
|
129
133
|
async conversation(id, _context) {
|
|
130
134
|
this.assertOpen();
|
|
131
|
-
const row = await this.db.get(
|
|
135
|
+
const row = await this.db.get(`SELECT record FROM ${this.schema.tables.conversations} WHERE id = ?`, id);
|
|
132
136
|
return row === undefined ? undefined : parseJson(row.record);
|
|
133
137
|
}
|
|
134
138
|
async scanConversations(query, limit, cursor, _context) {
|
|
@@ -146,7 +150,7 @@ export class SqliteStorage {
|
|
|
146
150
|
params.push(query.ownerTaskId);
|
|
147
151
|
}
|
|
148
152
|
params.push(limit + 1);
|
|
149
|
-
const rows = await this.db.all(`SELECT record FROM conversations WHERE ${clauses.join(" AND ")} ORDER BY id ${scan.direction} LIMIT ?`, ...params);
|
|
153
|
+
const rows = await this.db.all(`SELECT record FROM ${this.schema.tables.conversations} WHERE ${clauses.join(" AND ")} ORDER BY id ${scan.direction} LIMIT ?`, ...params);
|
|
150
154
|
return page(rows.map((row) => parseJson(row.record)), limit, start.order);
|
|
151
155
|
}
|
|
152
156
|
entry(idOrConversationId, idOrContext, context) {
|
|
@@ -165,15 +169,15 @@ export class SqliteStorage {
|
|
|
165
169
|
? idFromNumber(idOrContext)
|
|
166
170
|
: undefined;
|
|
167
171
|
if (id === undefined)
|
|
168
|
-
throw new
|
|
172
|
+
throw new StorageRequestError("Storage.entry() requires an entry ID");
|
|
169
173
|
let conversation;
|
|
170
174
|
if (context !== undefined) {
|
|
171
175
|
const conversationId = idFromNumber(idOrConversationId);
|
|
172
176
|
conversation = await this.readConversation(conversationId);
|
|
173
177
|
if (conversation === undefined)
|
|
174
|
-
throw new
|
|
178
|
+
throw new StorageRequestError(`Unknown conversation: ${conversationId}`);
|
|
175
179
|
}
|
|
176
|
-
const row = await this.db.get(
|
|
180
|
+
const row = await this.db.get(`SELECT record, commit_seq FROM ${this.schema.tables.entries} WHERE id = ?`, id);
|
|
177
181
|
if (row === undefined)
|
|
178
182
|
return undefined;
|
|
179
183
|
const entry = parseJson(row.record);
|
|
@@ -193,12 +197,12 @@ export class SqliteStorage {
|
|
|
193
197
|
async readLatestHeadMarker(conversationId, atOrBeforeEntryId) {
|
|
194
198
|
let conversation = await this.readConversation(conversationId);
|
|
195
199
|
if (conversation === undefined)
|
|
196
|
-
throw new
|
|
200
|
+
throw new StorageRequestError(`Unknown conversation: ${conversationId}`);
|
|
197
201
|
let upper = atOrBeforeEntryId;
|
|
198
202
|
while (true) {
|
|
199
203
|
const row = upper === undefined
|
|
200
|
-
? await this.db.get(
|
|
201
|
-
: await this.db.get(
|
|
204
|
+
? await this.db.get(`SELECT record FROM ${this.schema.tables.entries} WHERE conversation_id = ? AND head IS NOT NULL ORDER BY id DESC LIMIT 1`, conversation.id)
|
|
205
|
+
: await this.db.get(`SELECT record FROM ${this.schema.tables.entries} WHERE conversation_id = ? AND head IS NOT NULL AND id <= ? ORDER BY id DESC LIMIT 1`, conversation.id, upper);
|
|
202
206
|
if (row !== undefined)
|
|
203
207
|
return parseJson(row.record);
|
|
204
208
|
if (conversation.parent === undefined)
|
|
@@ -213,7 +217,7 @@ export class SqliteStorage {
|
|
|
213
217
|
return this.readEntriesAscending(query, limit, after);
|
|
214
218
|
let conversation = await this.readConversation(query.conversationId);
|
|
215
219
|
if (conversation === undefined)
|
|
216
|
-
throw new
|
|
220
|
+
throw new StorageRequestError(`Unknown conversation: ${query.conversationId}`);
|
|
217
221
|
let upper = query.maxEntryId;
|
|
218
222
|
if (after !== undefined)
|
|
219
223
|
upper = Math.min(upper ?? Number.MAX_SAFE_INTEGER, after - 1);
|
|
@@ -230,7 +234,7 @@ export class SqliteStorage {
|
|
|
230
234
|
params.push(upper);
|
|
231
235
|
}
|
|
232
236
|
params.push(limit + 1 - values.length);
|
|
233
|
-
const rows = await this.db.all(`SELECT record FROM entries WHERE ${clauses.join(" AND ")} ORDER BY id DESC LIMIT ?`, ...params);
|
|
237
|
+
const rows = await this.db.all(`SELECT record FROM ${this.schema.tables.entries} WHERE ${clauses.join(" AND ")} ORDER BY id DESC LIMIT ?`, ...params);
|
|
234
238
|
values.push(...rows.map((row) => parseJson(row.record)));
|
|
235
239
|
if (values.length > limit || conversation.parent === undefined)
|
|
236
240
|
break;
|
|
@@ -246,7 +250,7 @@ export class SqliteStorage {
|
|
|
246
250
|
const segments = [];
|
|
247
251
|
let conversation = await this.readConversation(query.conversationId);
|
|
248
252
|
if (conversation === undefined)
|
|
249
|
-
throw new
|
|
253
|
+
throw new StorageRequestError(`Unknown conversation: ${query.conversationId}`);
|
|
250
254
|
let upper = query.maxEntryId;
|
|
251
255
|
while (true) {
|
|
252
256
|
segments.push({ conversationId: conversation.id, upper });
|
|
@@ -273,7 +277,7 @@ export class SqliteStorage {
|
|
|
273
277
|
params.push(segment.upper);
|
|
274
278
|
}
|
|
275
279
|
params.push(limit + 1 - values.length);
|
|
276
|
-
const rows = await this.db.all(`SELECT record FROM entries WHERE ${clauses.join(" AND ")} ORDER BY id ASC LIMIT ?`, ...params);
|
|
280
|
+
const rows = await this.db.all(`SELECT record FROM ${this.schema.tables.entries} WHERE ${clauses.join(" AND ")} ORDER BY id ASC LIMIT ?`, ...params);
|
|
277
281
|
values.push(...rows.map((row) => parseJson(row.record)));
|
|
278
282
|
if (values.length > limit)
|
|
279
283
|
break;
|
|
@@ -282,7 +286,7 @@ export class SqliteStorage {
|
|
|
282
286
|
}
|
|
283
287
|
async task(id, _context) {
|
|
284
288
|
this.assertOpen();
|
|
285
|
-
const row = await this.db.get(
|
|
289
|
+
const row = await this.db.get(`SELECT record FROM ${this.schema.tables.tasks} WHERE id = ?`, id);
|
|
286
290
|
return row === undefined ? undefined : parseJson(row.record);
|
|
287
291
|
}
|
|
288
292
|
async scanTasks(query, limit, cursor, _context) {
|
|
@@ -312,12 +316,12 @@ export class SqliteStorage {
|
|
|
312
316
|
params.push(query.background ? 1 : 0);
|
|
313
317
|
}
|
|
314
318
|
params.push(limit + 1);
|
|
315
|
-
const rows = await this.db.all(`SELECT record FROM tasks WHERE ${clauses.join(" AND ")} ORDER BY id ${scan.direction} LIMIT ?`, ...params);
|
|
319
|
+
const rows = await this.db.all(`SELECT record FROM ${this.schema.tables.tasks} WHERE ${clauses.join(" AND ")} ORDER BY id ${scan.direction} LIMIT ?`, ...params);
|
|
316
320
|
return page(rows.map((row) => parseJson(row.record)), limit, start.order);
|
|
317
321
|
}
|
|
318
322
|
async submission(id, _context) {
|
|
319
323
|
this.assertOpen();
|
|
320
|
-
const row = await this.db.get(
|
|
324
|
+
const row = await this.db.get(`SELECT record FROM ${this.schema.tables.submissions} WHERE id = ?`, id);
|
|
321
325
|
return row === undefined ? undefined : parseJson(row.record);
|
|
322
326
|
}
|
|
323
327
|
async scanSubmissions(query, limit, cursor, _context) {
|
|
@@ -335,22 +339,22 @@ export class SqliteStorage {
|
|
|
335
339
|
params.push(query.status);
|
|
336
340
|
}
|
|
337
341
|
params.push(limit + 1);
|
|
338
|
-
const rows = await this.db.all(`SELECT record FROM submissions WHERE ${clauses.join(" AND ")} ORDER BY id ${scan.direction} LIMIT ?`, ...params);
|
|
342
|
+
const rows = await this.db.all(`SELECT record FROM ${this.schema.tables.submissions} WHERE ${clauses.join(" AND ")} ORDER BY id ${scan.direction} LIMIT ?`, ...params);
|
|
339
343
|
return page(rows.map((row) => parseJson(row.record)), limit, start.order);
|
|
340
344
|
}
|
|
341
345
|
async submissionByRequest(conversationId, requestId, _context) {
|
|
342
346
|
this.assertOpen();
|
|
343
|
-
const row = await this.db.get(
|
|
347
|
+
const row = await this.db.get(`SELECT record FROM ${this.schema.tables.submissions} WHERE conversation_id = ? AND request_id = ?`, conversationId, encodeIndexedString(requestId));
|
|
344
348
|
return row === undefined ? undefined : parseJson(row.record);
|
|
345
349
|
}
|
|
346
350
|
async findDocument(address, at, _context) {
|
|
347
351
|
this.assertOpen();
|
|
348
352
|
const parts = addressParts(address);
|
|
349
353
|
const sql = at === "current"
|
|
350
|
-
? `SELECT record FROM documents
|
|
354
|
+
? `SELECT record FROM ${this.schema.tables.documents}
|
|
351
355
|
WHERE kind = ? AND scope_kind = ? AND owner_id = ? AND family = ? AND key_value = ?
|
|
352
356
|
AND retired_at IS NULL ORDER BY created_at DESC LIMIT 1`
|
|
353
|
-
: `SELECT record FROM documents
|
|
357
|
+
: `SELECT record FROM ${this.schema.tables.documents}
|
|
354
358
|
WHERE kind = ? AND scope_kind = ? AND owner_id = ? AND family = ? AND key_value = ?
|
|
355
359
|
AND created_at <= ? AND (retired_at IS NULL OR retired_at > ?)
|
|
356
360
|
ORDER BY created_at DESC LIMIT 1`;
|
|
@@ -382,7 +386,7 @@ export class SqliteStorage {
|
|
|
382
386
|
params.push(query.at, query.at);
|
|
383
387
|
}
|
|
384
388
|
params.push(limit + 1);
|
|
385
|
-
const rows = await this.db.all(`SELECT record FROM documents WHERE ${clauses.join(" AND ")} ORDER BY id LIMIT ?`, ...params);
|
|
389
|
+
const rows = await this.db.all(`SELECT record FROM ${this.schema.tables.documents} WHERE ${clauses.join(" AND ")} ORDER BY id LIMIT ?`, ...params);
|
|
386
390
|
return page(rows.map((row) => parseJson(row.record)), limit);
|
|
387
391
|
}
|
|
388
392
|
close(_context) {
|
|
@@ -416,26 +420,26 @@ export class SqliteStorage {
|
|
|
416
420
|
}
|
|
417
421
|
}
|
|
418
422
|
async readConversation(id) {
|
|
419
|
-
const row = await this.db.get(
|
|
423
|
+
const row = await this.db.get(`SELECT record FROM ${this.schema.tables.conversations} WHERE id = ?`, id);
|
|
420
424
|
return row === undefined ? undefined : parseJson(row.record);
|
|
421
425
|
}
|
|
422
426
|
async materializeDocument(executor, id, at) {
|
|
423
|
-
const row = await executor.get(
|
|
427
|
+
const row = await executor.get(`SELECT record FROM ${this.schema.tables.documents} WHERE id = ?`, id);
|
|
424
428
|
if (row === undefined)
|
|
425
429
|
return undefined;
|
|
426
430
|
const record = parseJson(row.record);
|
|
427
431
|
if (at !== "current" && isCurrentOnly(record)) {
|
|
428
|
-
throw new
|
|
432
|
+
throw new StorageRequestError(`Document ${id} does not retain historical content`);
|
|
429
433
|
}
|
|
430
434
|
if (!isAliveAt(record, at))
|
|
431
435
|
return undefined;
|
|
432
436
|
const upper = at === "current" ? Number.MAX_SAFE_INTEGER : at;
|
|
433
|
-
const base = await executor.get(`SELECT seq, kind, version, content FROM
|
|
437
|
+
const base = await executor.get(`SELECT seq, kind, version, content FROM ${this.schema.tables.documentRevisions}
|
|
434
438
|
WHERE document_id = ? AND kind = 'base' AND seq <= ? ORDER BY seq DESC LIMIT 1`, id, upper);
|
|
435
439
|
if (base === undefined)
|
|
436
440
|
throw new Error(`Document ${id} is missing a required base`);
|
|
437
441
|
let value = parseJson(base.content);
|
|
438
|
-
const tail = await executor.all(`SELECT seq, kind, version, content FROM
|
|
442
|
+
const tail = await executor.all(`SELECT seq, kind, version, content FROM ${this.schema.tables.documentRevisions}
|
|
439
443
|
WHERE document_id = ? AND seq > ? AND seq <= ? ORDER BY seq`, id, base.seq, upper);
|
|
440
444
|
for (const revision of tail) {
|
|
441
445
|
if (revision.kind !== "delta" || revision.version !== base.version) {
|
|
@@ -462,8 +466,7 @@ export class SqliteStorage {
|
|
|
462
466
|
const document = write.type === "document.create" || write.type === "document.copy";
|
|
463
467
|
const table = document ? "document" : write.type;
|
|
464
468
|
const id = document ? write.record.id : write.value.id;
|
|
465
|
-
const existing = (await executor.get(
|
|
466
|
-
?.record_type;
|
|
469
|
+
const existing = (await executor.get(`SELECT record_type FROM ${this.schema.tables.recordIds} WHERE id = ?`, id))?.record_type;
|
|
467
470
|
const earlier = claimed.get(id);
|
|
468
471
|
if (table === "conversation" || table === "entry" || table === "document") {
|
|
469
472
|
if (existing !== undefined)
|
|
@@ -529,9 +532,9 @@ export class SqliteStorage {
|
|
|
529
532
|
const liveCounts = new Map();
|
|
530
533
|
for (const [id, action] of actions) {
|
|
531
534
|
if (action.copy !== undefined && actions.has(action.copy.id)) {
|
|
532
|
-
throw new
|
|
535
|
+
throw new Error(`Document copy ${id} source is changed in the copy batch`);
|
|
533
536
|
}
|
|
534
|
-
const row = await executor.get(
|
|
537
|
+
const row = await executor.get(`SELECT record FROM ${this.schema.tables.documents} WHERE id = ?`, id);
|
|
535
538
|
const existing = row === undefined ? undefined : parseJson(row.record);
|
|
536
539
|
if (action.create === undefined && existing === undefined)
|
|
537
540
|
throw new Error(`Unknown document: ${id}`);
|
|
@@ -540,7 +543,7 @@ export class SqliteStorage {
|
|
|
540
543
|
if (existing?.retiredAt !== undefined)
|
|
541
544
|
throw new Error(`Document ${id} is retired`);
|
|
542
545
|
if (action.content?.kind === "delta") {
|
|
543
|
-
const previous = await executor.get(
|
|
546
|
+
const previous = await executor.get(`SELECT version FROM ${this.schema.tables.documentRevisions} WHERE document_id = ? ORDER BY seq DESC LIMIT 1`, id);
|
|
544
547
|
if (previous === undefined)
|
|
545
548
|
throw new Error(`Document ${id} delta has no base`);
|
|
546
549
|
if (previous.version !== action.content.version) {
|
|
@@ -565,7 +568,7 @@ export class SqliteStorage {
|
|
|
565
568
|
}
|
|
566
569
|
async currentDocumentId(executor, address) {
|
|
567
570
|
const parts = addressParts(address);
|
|
568
|
-
const id = (await executor.get(`SELECT id FROM documents
|
|
571
|
+
const id = (await executor.get(`SELECT id FROM ${this.schema.tables.documents}
|
|
569
572
|
WHERE kind = ? AND scope_kind = ? AND owner_id = ? AND family = ? AND key_value = ? AND retired_at IS NULL
|
|
570
573
|
LIMIT 1`, parts.kind, parts.scopeKind, parts.ownerId, parts.family, parts.keyValue))?.id;
|
|
571
574
|
return id === undefined ? undefined : idFromNumber(id);
|
|
@@ -574,15 +577,15 @@ export class SqliteStorage {
|
|
|
574
577
|
switch (write.type) {
|
|
575
578
|
case "conversation":
|
|
576
579
|
await this.claimId(executor, write.value.id, "conversation");
|
|
577
|
-
await executor.run(
|
|
580
|
+
await executor.run(`INSERT INTO ${this.schema.tables.conversations} (id, owner_conversation_id, owner_task_id, record) VALUES (?, ?, ?, ?)`, write.value.id, write.value.owner?.conversationId ?? null, write.value.owner?.taskId ?? null, encodeJson(write.value));
|
|
578
581
|
break;
|
|
579
582
|
case "entry":
|
|
580
583
|
await this.claimId(executor, write.value.id, "entry");
|
|
581
|
-
await executor.run(
|
|
584
|
+
await executor.run(`INSERT INTO ${this.schema.tables.entries} (id, conversation_id, head, commit_seq, record) VALUES (?, ?, ?, ?, ?)`, write.value.id, write.value.conversationId, write.value.head ?? null, seq, encodeJson(write.value));
|
|
582
585
|
break;
|
|
583
586
|
case "task":
|
|
584
587
|
await this.claimId(executor, write.value.id, "task");
|
|
585
|
-
await executor.run(`INSERT INTO tasks (id, conversation_id, kind, status, abort_requested, background, record)
|
|
588
|
+
await executor.run(`INSERT INTO ${this.schema.tables.tasks} (id, conversation_id, kind, status, abort_requested, background, record)
|
|
586
589
|
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
587
590
|
ON CONFLICT(id) DO UPDATE SET conversation_id = excluded.conversation_id, kind = excluded.kind,
|
|
588
591
|
status = excluded.status, abort_requested = excluded.abort_requested,
|
|
@@ -590,7 +593,7 @@ export class SqliteStorage {
|
|
|
590
593
|
break;
|
|
591
594
|
case "submission":
|
|
592
595
|
await this.claimId(executor, write.value.id, "submission");
|
|
593
|
-
await executor.run(`INSERT INTO submissions (id, conversation_id, request_id, status, record) VALUES (?, ?, ?, ?, ?)
|
|
596
|
+
await executor.run(`INSERT INTO ${this.schema.tables.submissions} (id, conversation_id, request_id, status, record) VALUES (?, ?, ?, ?, ?)
|
|
594
597
|
ON CONFLICT(id) DO UPDATE SET conversation_id = excluded.conversation_id,
|
|
595
598
|
request_id = excluded.request_id, status = excluded.status, record = excluded.record`, write.value.id, write.value.conversationId, write.value.requestId === undefined ? null : encodeIndexedString(write.value.requestId), write.value.status, encodeJson(write.value));
|
|
596
599
|
break;
|
|
@@ -602,7 +605,7 @@ export class SqliteStorage {
|
|
|
602
605
|
}
|
|
603
606
|
}
|
|
604
607
|
async claimId(executor, id, table) {
|
|
605
|
-
await executor.run(
|
|
608
|
+
await executor.run(`INSERT OR IGNORE INTO ${this.schema.tables.recordIds} (id, record_type) VALUES (?, ?)`, id, table);
|
|
606
609
|
}
|
|
607
610
|
async applyDocumentActions(executor, actions, seq) {
|
|
608
611
|
for (const [id, action] of actions) {
|
|
@@ -624,9 +627,7 @@ export class SqliteStorage {
|
|
|
624
627
|
content = { kind: "base", version: stored.version, value: stored.value };
|
|
625
628
|
}
|
|
626
629
|
catch (error) {
|
|
627
|
-
|
|
628
|
-
throw error;
|
|
629
|
-
throw new StorageRejected(`Document copy ${id} was rejected`, { cause: error });
|
|
630
|
+
throw new Error(`Document copy ${id} was rejected`, { cause: error });
|
|
630
631
|
}
|
|
631
632
|
}
|
|
632
633
|
let record;
|
|
@@ -638,28 +639,28 @@ export class SqliteStorage {
|
|
|
638
639
|
};
|
|
639
640
|
const parts = addressParts(record);
|
|
640
641
|
await this.claimId(executor, id, "document");
|
|
641
|
-
await executor.run(`INSERT INTO documents
|
|
642
|
+
await executor.run(`INSERT INTO ${this.schema.tables.documents}
|
|
642
643
|
(id, kind, family, key_value, scope_kind, owner_id, created_at, retired_at, record)
|
|
643
644
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, id, parts.kind, parts.family, parts.keyValue, parts.scopeKind, parts.ownerId, seq, action.retire ? seq : null, encodeJson(record));
|
|
644
645
|
}
|
|
645
646
|
else {
|
|
646
|
-
const row = (await executor.get(
|
|
647
|
+
const row = (await executor.get(`SELECT record FROM ${this.schema.tables.documents} WHERE id = ?`, id));
|
|
647
648
|
record = parseJson(row.record);
|
|
648
649
|
}
|
|
649
650
|
if (content !== undefined) {
|
|
650
651
|
if (content.kind === "base" && isCurrentOnly(record)) {
|
|
651
|
-
await executor.run(
|
|
652
|
+
await executor.run(`DELETE FROM ${this.schema.tables.documentRevisions} WHERE document_id = ?`, id);
|
|
652
653
|
}
|
|
653
654
|
const encodedContent = content.kind === "base" ? encodeJson(content.value) : encodeJson(content.ops);
|
|
654
|
-
await executor.run(
|
|
655
|
+
await executor.run(`INSERT INTO ${this.schema.tables.documentRevisions} (document_id, seq, kind, version, content) VALUES (?, ?, ?, ?, ?)`, id, seq, content.kind, content.version, encodedContent);
|
|
655
656
|
}
|
|
656
657
|
if (action.retire) {
|
|
657
658
|
if (action.create === undefined) {
|
|
658
659
|
record = { ...record, retiredAt: seq };
|
|
659
|
-
await executor.run(
|
|
660
|
+
await executor.run(`UPDATE ${this.schema.tables.documents} SET retired_at = ?, record = ? WHERE id = ?`, seq, encodeJson(record), id);
|
|
660
661
|
}
|
|
661
662
|
if (isCurrentOnly(record)) {
|
|
662
|
-
await executor.run(
|
|
663
|
+
await executor.run(`DELETE FROM ${this.schema.tables.documentRevisions} WHERE document_id = ?`, id);
|
|
663
664
|
}
|
|
664
665
|
}
|
|
665
666
|
}
|