@earendil-works/pi-durable 1.2.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 +15 -0
- package/README.md +17 -0
- package/dist/env/index.d.ts +1 -0
- package/dist/env/index.d.ts.map +1 -1
- package/dist/env/index.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/tool.d.ts.map +1 -1
- package/dist/harness/tool.js +1 -1
- package/dist/harness/tool.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 +46 -43
- package/dist/storage/sqlite/storage.js.map +1 -1
- package/dist/tools/image-processor.d.ts +4 -1
- package/dist/tools/image-processor.d.ts.map +1 -1
- package/dist/tools/image-processor.js +8 -18
- package/dist/tools/image-processor.js.map +1 -1
- package/dist/tools/read.d.ts.map +1 -1
- package/dist/tools/read.js +1 -1
- package/dist/tools/read.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/package.json +4 -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,7 +2,8 @@ import { apply } from "@earendil-works/chord/delta";
|
|
|
2
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.
|
|
@@ -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) {
|
|
@@ -173,7 +177,7 @@ export class SqliteStorage {
|
|
|
173
177
|
if (conversation === undefined)
|
|
174
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);
|
|
@@ -197,8 +201,8 @@ export class SqliteStorage {
|
|
|
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)
|
|
@@ -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;
|
|
@@ -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,11 +420,11 @@ 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);
|
|
@@ -430,12 +434,12 @@ export class SqliteStorage {
|
|
|
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)
|
|
@@ -531,7 +534,7 @@ export class SqliteStorage {
|
|
|
531
534
|
if (action.copy !== undefined && actions.has(action.copy.id)) {
|
|
532
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) {
|
|
@@ -636,28 +639,28 @@ export class SqliteStorage {
|
|
|
636
639
|
};
|
|
637
640
|
const parts = addressParts(record);
|
|
638
641
|
await this.claimId(executor, id, "document");
|
|
639
|
-
await executor.run(`INSERT INTO documents
|
|
642
|
+
await executor.run(`INSERT INTO ${this.schema.tables.documents}
|
|
640
643
|
(id, kind, family, key_value, scope_kind, owner_id, created_at, retired_at, record)
|
|
641
644
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, id, parts.kind, parts.family, parts.keyValue, parts.scopeKind, parts.ownerId, seq, action.retire ? seq : null, encodeJson(record));
|
|
642
645
|
}
|
|
643
646
|
else {
|
|
644
|
-
const row = (await executor.get(
|
|
647
|
+
const row = (await executor.get(`SELECT record FROM ${this.schema.tables.documents} WHERE id = ?`, id));
|
|
645
648
|
record = parseJson(row.record);
|
|
646
649
|
}
|
|
647
650
|
if (content !== undefined) {
|
|
648
651
|
if (content.kind === "base" && isCurrentOnly(record)) {
|
|
649
|
-
await executor.run(
|
|
652
|
+
await executor.run(`DELETE FROM ${this.schema.tables.documentRevisions} WHERE document_id = ?`, id);
|
|
650
653
|
}
|
|
651
654
|
const encodedContent = content.kind === "base" ? encodeJson(content.value) : encodeJson(content.ops);
|
|
652
|
-
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);
|
|
653
656
|
}
|
|
654
657
|
if (action.retire) {
|
|
655
658
|
if (action.create === undefined) {
|
|
656
659
|
record = { ...record, retiredAt: seq };
|
|
657
|
-
await executor.run(
|
|
660
|
+
await executor.run(`UPDATE ${this.schema.tables.documents} SET retired_at = ?, record = ? WHERE id = ?`, seq, encodeJson(record), id);
|
|
658
661
|
}
|
|
659
662
|
if (isCurrentOnly(record)) {
|
|
660
|
-
await executor.run(
|
|
663
|
+
await executor.run(`DELETE FROM ${this.schema.tables.documentRevisions} WHERE document_id = ?`, id);
|
|
661
664
|
}
|
|
662
665
|
}
|
|
663
666
|
}
|