@evolu/common 6.0.1-preview.1 → 6.0.1-preview.3
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/src/Evolu/Db.d.ts +5 -5
- package/dist/src/Evolu/Db.d.ts.map +1 -1
- package/dist/src/Evolu/Db.js +68 -61
- package/dist/src/Evolu/Schema.d.ts +1 -1
- package/dist/src/Evolu/Schema.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/Evolu/Db.ts +77 -66
- package/src/Evolu/Schema.ts +1 -1
package/dist/src/Evolu/Db.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ import { Worker } from "../Worker.js";
|
|
|
14
14
|
import { Config } from "./Config.js";
|
|
15
15
|
import { QueryPatches } from "./Diff.js";
|
|
16
16
|
import { AppOwner, OwnerRow } from "./Owner.js";
|
|
17
|
-
import { Base64Url256, CrdtMessage, DbChange, ProtocolError, Storage } from "./Protocol.js";
|
|
17
|
+
import { Base64Url256, BinaryOwnerId, CrdtMessage, DbChange, ProtocolError, Storage } from "./Protocol.js";
|
|
18
18
|
import { Query } from "./Query.js";
|
|
19
19
|
import { SqliteStorageBase } from "./Storage.js";
|
|
20
20
|
import { CreateSyncDep } from "./Sync.js";
|
|
@@ -105,14 +105,14 @@ export declare const getDbSchema: (deps: SqliteDep) => ({ allIndexes }?: {
|
|
|
105
105
|
}) => Result<DbSchema, SqliteError>;
|
|
106
106
|
export interface DbSnapshot {
|
|
107
107
|
readonly schema: DbSchema;
|
|
108
|
-
readonly
|
|
109
|
-
rows: ReadonlyArray<SqliteRow>;
|
|
108
|
+
readonly tables: Array<{
|
|
110
109
|
name: string;
|
|
110
|
+
rows: ReadonlyArray<SqliteRow>;
|
|
111
111
|
}>;
|
|
112
112
|
}
|
|
113
|
-
export declare const getDbSnapshot: (deps: SqliteDep) =>
|
|
113
|
+
export declare const getDbSnapshot: (deps: SqliteDep) => DbSnapshot;
|
|
114
114
|
export declare const createAppTable: (tableName: string, columns: ReadonlyArray<string>) => SafeSql;
|
|
115
|
-
export declare const applyMessageToTimestampAndHistoryTables: (deps: SqliteDep &
|
|
115
|
+
export declare const applyMessageToTimestampAndHistoryTables: (deps: SqliteDep & ClientStorageDep) => (ownerId: BinaryOwnerId, message: CrdtMessage) => Result<void, SqliteError>;
|
|
116
116
|
export declare const maybeMigrateToVersion0: (deps: SqliteDep) => (schema: DbSchema) => Result<{
|
|
117
117
|
readonly messages: ReadonlyArray<CrdtMessage>;
|
|
118
118
|
readonly mnemonic: Mnemonic;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Db.d.ts","sourceRoot":"","sources":["../../../src/Evolu/Db.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"Db.d.ts","sourceRoot":"","sources":["../../../src/Evolu/Db.ts"],"names":[],"mappings":"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"}
|
package/dist/src/Evolu/Db.js
CHANGED
|
@@ -232,7 +232,6 @@ export const createDbWorkerForPlatform = (platformDeps) => {
|
|
|
232
232
|
onCompleteId: message.onCompleteId,
|
|
233
233
|
reload: message.reload,
|
|
234
234
|
});
|
|
235
|
-
deps.sqlite[Symbol.dispose]();
|
|
236
235
|
break;
|
|
237
236
|
}
|
|
238
237
|
case "ensureDbSchema": {
|
|
@@ -324,24 +323,22 @@ export const getDbSchema = (deps) => ({ allIndexes = false } = {}) => {
|
|
|
324
323
|
return ok({ tables, indexes });
|
|
325
324
|
};
|
|
326
325
|
const indexesAreEqual = (self, that) => self.name === that.name && self.sql === that.sql;
|
|
327
|
-
// TODO: Move
|
|
326
|
+
// TODO: Move to test helpers.
|
|
328
327
|
export const getDbSnapshot = (deps) => {
|
|
329
328
|
const schema = getDbSchema(deps)({ allIndexes: true });
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
const rows = [];
|
|
329
|
+
assert(schema.ok, "bug");
|
|
330
|
+
const tables = [];
|
|
333
331
|
for (const table of schema.value.tables) {
|
|
334
332
|
const result = deps.sqlite.exec(sql `
|
|
335
333
|
select * from ${sql.identifier(table.name)};
|
|
336
334
|
`);
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
rows.push({
|
|
340
|
-
rows: result.value.rows,
|
|
335
|
+
assert(result.ok, "bug");
|
|
336
|
+
tables.push({
|
|
341
337
|
name: table.name,
|
|
338
|
+
rows: result.value.rows,
|
|
342
339
|
});
|
|
343
340
|
}
|
|
344
|
-
return
|
|
341
|
+
return { schema: schema.value, tables };
|
|
345
342
|
};
|
|
346
343
|
const ensureDbSchema = (deps) => (newSchema, currentSchema, options) => {
|
|
347
344
|
const queries = [];
|
|
@@ -434,39 +431,35 @@ const initializeDb = (deps) => (mnemonic) => {
|
|
|
434
431
|
values ('protocolVersion', ${protocolVersion});
|
|
435
432
|
`,
|
|
436
433
|
/**
|
|
437
|
-
* The History table stores all values per timestamp, table,
|
|
438
|
-
* column
|
|
439
|
-
*
|
|
440
|
-
*
|
|
441
|
-
*
|
|
442
|
-
* and DbChange to leverage a covering index. Hence, every value change
|
|
443
|
-
* has its timestamp, table, row, and column. In the future, we will
|
|
444
|
-
* rethink that and store history more efficiently.
|
|
445
|
-
*
|
|
446
|
-
* There is no need to use `OwnerId` on the client, because timestamps
|
|
447
|
-
* (which include a `NodeId`) are globally unique. The relay needs
|
|
448
|
-
* `OwnerId` because it hosts multiple apps/owners, but client storage
|
|
449
|
-
* represents one DB, and even when it hosts multiple owners, their
|
|
450
|
-
* timestamps remain unique.
|
|
434
|
+
* The History table stores all values per ownerId, timestamp, table, id,
|
|
435
|
+
* and column for conflict-free merging using last-write-win CRDT.
|
|
436
|
+
* Denormalizes Timestamp and DbChange for covering index performance.
|
|
437
|
+
* Time travel is available when last-write-win isn't desired. Future
|
|
438
|
+
* optimization will store history more efficiently.
|
|
451
439
|
*/
|
|
452
440
|
sql `
|
|
453
441
|
create table evolu_history (
|
|
454
|
-
"
|
|
442
|
+
"ownerId" blob not null,
|
|
455
443
|
"table" text not null,
|
|
456
|
-
"
|
|
444
|
+
"id" blob not null,
|
|
457
445
|
"column" text not null,
|
|
446
|
+
"timestamp" blob not null,
|
|
458
447
|
"value" any
|
|
459
448
|
)
|
|
460
449
|
strict;
|
|
461
450
|
`,
|
|
462
451
|
sql `
|
|
463
|
-
create index
|
|
452
|
+
create index evolu_history_ownerId_timestamp on evolu_history (
|
|
453
|
+
"ownerId",
|
|
454
|
+
"timestamp"
|
|
455
|
+
);
|
|
464
456
|
`,
|
|
465
457
|
sql `
|
|
466
|
-
create unique index
|
|
467
|
-
"
|
|
468
|
-
"column",
|
|
458
|
+
create unique index evolu_history_ownerId_table_id_column_timestampDesc on evolu_history (
|
|
459
|
+
"ownerId",
|
|
469
460
|
"table",
|
|
461
|
+
"id",
|
|
462
|
+
"column",
|
|
470
463
|
"timestamp" desc
|
|
471
464
|
);
|
|
472
465
|
`,
|
|
@@ -490,7 +483,14 @@ const initializeDb = (deps) => (mnemonic) => {
|
|
|
490
483
|
const ownerRow = createOwnerRow(deps)(appOwner);
|
|
491
484
|
const result = deps.sqlite.exec(sql `
|
|
492
485
|
insert into evolu_owner
|
|
493
|
-
(
|
|
486
|
+
(
|
|
487
|
+
"mnemonic",
|
|
488
|
+
"id",
|
|
489
|
+
"encryptionKey",
|
|
490
|
+
"createdAt",
|
|
491
|
+
"writeKey",
|
|
492
|
+
"timestamp"
|
|
493
|
+
)
|
|
494
494
|
values
|
|
495
495
|
(
|
|
496
496
|
${ownerRow.mnemonic},
|
|
@@ -523,16 +523,15 @@ const applyChanges = (deps) => (changes, onChange) => {
|
|
|
523
523
|
assertNonEmptyReadonlyArray(messages);
|
|
524
524
|
return ok(messages);
|
|
525
525
|
};
|
|
526
|
-
const applyMessages = (deps) => (messages, lastTimestamp
|
|
526
|
+
const applyMessages = (deps) => (messages, lastTimestamp) => {
|
|
527
|
+
const ownerId = ownerIdToBinaryOwnerId(deps.ownerRowRef.get().id);
|
|
527
528
|
for (const message of messages) {
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
if (!apply2.ok)
|
|
535
|
-
return apply2;
|
|
529
|
+
const result1 = applyMessageToAppTable(deps)(ownerId, message);
|
|
530
|
+
if (!result1.ok)
|
|
531
|
+
return result1;
|
|
532
|
+
const result2 = applyMessageToTimestampAndHistoryTables(deps)(ownerId, message);
|
|
533
|
+
if (!result2.ok)
|
|
534
|
+
return result2;
|
|
536
535
|
}
|
|
537
536
|
const timestamp = timestampToTimestampString(lastTimestamp);
|
|
538
537
|
deps.ownerRowRef.modify((owner) => ({ ...owner, timestamp }));
|
|
@@ -543,44 +542,44 @@ const applyMessages = (deps) => (messages, lastTimestamp, options = {}) => {
|
|
|
543
542
|
return saveTimestamp;
|
|
544
543
|
return ok();
|
|
545
544
|
};
|
|
546
|
-
const applyMessageToAppTable = (deps) => (message) => {
|
|
545
|
+
const applyMessageToAppTable = (deps) => (ownerId, message) => {
|
|
547
546
|
const date = new Date(message.timestamp.millis).toISOString();
|
|
548
547
|
const timestamp = timestampToBinaryTimestamp(message.timestamp);
|
|
549
548
|
for (const [column, value] of objectToEntries(message.change.values)) {
|
|
550
549
|
const result = deps.sqlite.exec(sql.prepared `
|
|
551
550
|
with
|
|
552
551
|
lastTimestamp as (
|
|
553
|
-
select timestamp
|
|
552
|
+
select "timestamp"
|
|
554
553
|
from evolu_history
|
|
555
554
|
where
|
|
556
|
-
"
|
|
557
|
-
and "column" = ${column}
|
|
555
|
+
"ownerId" = ${ownerId}
|
|
558
556
|
and "table" = ${message.change.table}
|
|
559
|
-
|
|
557
|
+
and "id" = ${message.change.id}
|
|
558
|
+
and "column" = ${column}
|
|
559
|
+
order by "timestamp" desc
|
|
560
560
|
limit 1
|
|
561
561
|
)
|
|
562
562
|
insert into ${sql.identifier(message.change.table)}
|
|
563
563
|
("id", ${sql.identifier(column)}, createdAt, updatedAt)
|
|
564
564
|
select ${message.change.id}, ${value}, ${date}, ${date}
|
|
565
565
|
where
|
|
566
|
-
(select timestamp from lastTimestamp) is null
|
|
567
|
-
or (select timestamp from lastTimestamp) < ${timestamp}
|
|
566
|
+
(select "timestamp" from lastTimestamp) is null
|
|
567
|
+
or (select "timestamp" from lastTimestamp) < ${timestamp}
|
|
568
568
|
on conflict ("id") do update
|
|
569
569
|
set
|
|
570
570
|
${sql.identifier(column)} = ${value},
|
|
571
571
|
updatedAt = ${date}
|
|
572
572
|
where
|
|
573
|
-
(select timestamp from lastTimestamp) is null
|
|
574
|
-
or (select timestamp from lastTimestamp) < ${timestamp};
|
|
573
|
+
(select "timestamp" from lastTimestamp) is null
|
|
574
|
+
or (select "timestamp" from lastTimestamp) < ${timestamp};
|
|
575
575
|
`);
|
|
576
576
|
if (!result.ok)
|
|
577
577
|
return result;
|
|
578
578
|
}
|
|
579
579
|
return ok();
|
|
580
580
|
};
|
|
581
|
-
export const applyMessageToTimestampAndHistoryTables = (deps) => (message) => {
|
|
581
|
+
export const applyMessageToTimestampAndHistoryTables = (deps) => (ownerId, message) => {
|
|
582
582
|
const timestamp = timestampToBinaryTimestamp(message.timestamp);
|
|
583
|
-
const ownerId = ownerIdToBinaryOwnerId(deps.ownerRowRef.get().id);
|
|
584
583
|
const id = idToBinaryId(message.change.id);
|
|
585
584
|
const result = deps.storage.insertTimestamp(ownerId, timestamp);
|
|
586
585
|
if (!result.ok)
|
|
@@ -588,9 +587,16 @@ export const applyMessageToTimestampAndHistoryTables = (deps) => (message) => {
|
|
|
588
587
|
for (const [column, value] of Object.entries(message.change.values)) {
|
|
589
588
|
const result = deps.sqlite.exec(sql.prepared `
|
|
590
589
|
insert into evolu_history
|
|
591
|
-
("
|
|
590
|
+
("ownerId", "table", "id", "column", "value", "timestamp")
|
|
592
591
|
values
|
|
593
|
-
(
|
|
592
|
+
(
|
|
593
|
+
${ownerId},
|
|
594
|
+
${message.change.table},
|
|
595
|
+
${id},
|
|
596
|
+
${column},
|
|
597
|
+
${value},
|
|
598
|
+
${timestamp}
|
|
599
|
+
)
|
|
594
600
|
on conflict do nothing;
|
|
595
601
|
`);
|
|
596
602
|
if (!result.ok)
|
|
@@ -631,7 +637,7 @@ export const maybeMigrateToVersion0 = (deps) => (schema) => {
|
|
|
631
637
|
if (!mnemonicAndLastTimestamp.ok)
|
|
632
638
|
return mnemonicAndLastTimestamp;
|
|
633
639
|
const messagesRows = deps.sqlite.exec(sql `
|
|
634
|
-
select "timestamp", "table", "
|
|
640
|
+
select "timestamp", "table", "id", "column", "value" from evolu_message;
|
|
635
641
|
`);
|
|
636
642
|
if (!messagesRows.ok)
|
|
637
643
|
return messagesRows;
|
|
@@ -646,7 +652,7 @@ export const maybeMigrateToVersion0 = (deps) => (schema) => {
|
|
|
646
652
|
const messages = messagesRows.value.rows.map((message) => ({
|
|
647
653
|
timestamp: timestampStringToTimestamp(message.timestamp),
|
|
648
654
|
change: {
|
|
649
|
-
id: message.
|
|
655
|
+
id: message.id,
|
|
650
656
|
table: message.table,
|
|
651
657
|
values: { [message.column]: message.value },
|
|
652
658
|
},
|
|
@@ -706,6 +712,7 @@ const createClientStorage = (deps) => (options) => {
|
|
|
706
712
|
validateWriteKey: constFalse,
|
|
707
713
|
writeMessages: (_ownerId, messages) => {
|
|
708
714
|
// TODO: Get owner by _ownerId when we support more.
|
|
715
|
+
// Use ownerId!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
709
716
|
const owner = deps.ownerRowRef.get();
|
|
710
717
|
const decodedAndDecryptedMessages = [];
|
|
711
718
|
for (const message of messages) {
|
|
@@ -742,11 +749,11 @@ const createClientStorage = (deps) => (options) => {
|
|
|
742
749
|
deps.postMessage({ type: "onReceive" });
|
|
743
750
|
return true;
|
|
744
751
|
},
|
|
745
|
-
readDbChange: (
|
|
752
|
+
readDbChange: (ownerId, timestamp) => {
|
|
746
753
|
const result = deps.sqlite.exec(sql `
|
|
747
|
-
select "table", "
|
|
754
|
+
select "table", "id", "column", "value"
|
|
748
755
|
from evolu_history
|
|
749
|
-
where "timestamp" = ${timestamp};
|
|
756
|
+
where "ownerId" = ${ownerId} and "timestamp" = ${timestamp};
|
|
750
757
|
`);
|
|
751
758
|
if (!result.ok) {
|
|
752
759
|
deps.postMessage({ type: "onError", error: result.error });
|
|
@@ -754,16 +761,16 @@ const createClientStorage = (deps) => (options) => {
|
|
|
754
761
|
}
|
|
755
762
|
const { rows } = result.value;
|
|
756
763
|
assert(rows.length > 0, "Rows must not be empty");
|
|
757
|
-
const { table,
|
|
764
|
+
const { table, id } = rows[0];
|
|
758
765
|
const values = {};
|
|
759
766
|
for (const r of rows) {
|
|
760
767
|
assert(r.table === table, "All rows must have the same table");
|
|
761
|
-
assert(eqArrayNumber(r.
|
|
768
|
+
assert(eqArrayNumber(r.id, id), "All rows must have the same Id");
|
|
762
769
|
values[r.column] = r.value;
|
|
763
770
|
}
|
|
764
771
|
const change = {
|
|
765
772
|
table: rows[0].table,
|
|
766
|
-
id: binaryIdToId(rows[0].
|
|
773
|
+
id: binaryIdToId(rows[0].id),
|
|
767
774
|
values,
|
|
768
775
|
};
|
|
769
776
|
const { encryptionKey } = deps.ownerRowRef.get();
|
|
@@ -61,7 +61,7 @@ export type CreateQuery<S extends EvoluSchema> = <R extends Row>(queryCallback:
|
|
|
61
61
|
readonly evolu_history: {
|
|
62
62
|
readonly timestamp: BinaryTimestamp;
|
|
63
63
|
readonly table: keyof S;
|
|
64
|
-
readonly
|
|
64
|
+
readonly id: BinaryId;
|
|
65
65
|
readonly column: string;
|
|
66
66
|
readonly value: SqliteValue;
|
|
67
67
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Schema.d.ts","sourceRoot":"","sources":["../../../src/Evolu/Schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,kBAAkB,EAAE,MAAM,QAAQ,CAAC;AAEpD,OAAO,EAA8B,cAAc,EAAE,MAAM,cAAc,CAAC;AAC1E,OAAO,EAAW,MAAM,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC9E,OAAO,EACL,OAAO,EAEP,SAAS,EAKT,WAAW,EACX,UAAU,EACV,SAAS,EACT,qBAAqB,EAErB,uBAAuB,EAGvB,UAAU,EAGV,YAAY,EAEZ,IAAI,EACJ,SAAS,EAEV,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAW,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAiB,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,EAAY,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC/D,OAAO,EAEL,QAAQ,EAET,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEjD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,MAAM,MAAM,WAAW,GAAG,cAAc,CACtC,MAAM,EACN,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,GAAG;IACtD,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;CAC5C,CACF,CAAC;AAEF,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,WAAW,IAAI,CAAC,CAAC,SAAS,GAAG,EAC7D,aAAa,EAAE,CACb,EAAE,EAAE,IAAI,CACN,MAAM,CACJ;KACG,KAAK,IAAI,MAAM,CAAC,GAAG;QAClB,QAAQ,EAAE,MAAM,IAAI,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,MAAM,SACvC,IAAI,GACJ,WAAW,GACX,WAAW,GACX,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,GAC3B,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,IAAI;KACvC,GAAG,cAAc;CACnB,GAAG;IACF,QAAQ,CAAC,aAAa,EAAE;QACtB,QAAQ,CAAC,SAAS,EAAE,eAAe,CAAC;QACpC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QACxB,QAAQ,CAAC,
|
|
1
|
+
{"version":3,"file":"Schema.d.ts","sourceRoot":"","sources":["../../../src/Evolu/Schema.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@evolu/common",
|
|
3
|
-
"version": "6.0.1-preview.
|
|
3
|
+
"version": "6.0.1-preview.3",
|
|
4
4
|
"description": "TypeScript library and local-first framework",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"evolu",
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"better-sqlite3": "^11.10.0",
|
|
58
58
|
"shx": "^0.3.4",
|
|
59
59
|
"typescript": "^5.8.3",
|
|
60
|
-
"vitest": "^3.2.
|
|
60
|
+
"vitest": "^3.2.3",
|
|
61
61
|
"ws": "^8.18.2",
|
|
62
62
|
"@evolu/tsconfig": "0.0.2"
|
|
63
63
|
},
|
package/src/Evolu/Db.ts
CHANGED
|
@@ -54,6 +54,7 @@ import {
|
|
|
54
54
|
Base64Url256,
|
|
55
55
|
BinaryId,
|
|
56
56
|
binaryIdToId,
|
|
57
|
+
BinaryOwnerId,
|
|
57
58
|
CrdtMessage,
|
|
58
59
|
createProtocolMessageForSync,
|
|
59
60
|
createProtocolMessageFromCrdtMessages,
|
|
@@ -496,7 +497,6 @@ export const createDbWorkerForPlatform = (
|
|
|
496
497
|
onCompleteId: message.onCompleteId,
|
|
497
498
|
reload: message.reload,
|
|
498
499
|
});
|
|
499
|
-
deps.sqlite[Symbol.dispose]();
|
|
500
500
|
|
|
501
501
|
break;
|
|
502
502
|
}
|
|
@@ -621,34 +621,32 @@ const indexesAreEqual = (self: DbIndex, that: DbIndex): boolean =>
|
|
|
621
621
|
|
|
622
622
|
export interface DbSnapshot {
|
|
623
623
|
readonly schema: DbSchema;
|
|
624
|
-
readonly
|
|
625
|
-
rows: ReadonlyArray<SqliteRow>;
|
|
624
|
+
readonly tables: Array<{
|
|
626
625
|
name: string;
|
|
626
|
+
rows: ReadonlyArray<SqliteRow>;
|
|
627
627
|
}>;
|
|
628
628
|
}
|
|
629
629
|
|
|
630
|
-
// TODO: Move
|
|
631
|
-
export const getDbSnapshot = (
|
|
632
|
-
deps: SqliteDep,
|
|
633
|
-
): Result<DbSnapshot, SqliteError> => {
|
|
630
|
+
// TODO: Move to test helpers.
|
|
631
|
+
export const getDbSnapshot = (deps: SqliteDep): DbSnapshot => {
|
|
634
632
|
const schema = getDbSchema(deps)({ allIndexes: true });
|
|
635
|
-
|
|
633
|
+
assert(schema.ok, "bug");
|
|
636
634
|
|
|
637
|
-
const
|
|
635
|
+
const tables = [];
|
|
638
636
|
|
|
639
637
|
for (const table of schema.value.tables) {
|
|
640
638
|
const result = deps.sqlite.exec(sql`
|
|
641
639
|
select * from ${sql.identifier(table.name)};
|
|
642
640
|
`);
|
|
643
|
-
|
|
641
|
+
assert(result.ok, "bug");
|
|
644
642
|
|
|
645
|
-
|
|
646
|
-
rows: result.value.rows,
|
|
643
|
+
tables.push({
|
|
647
644
|
name: table.name,
|
|
645
|
+
rows: result.value.rows,
|
|
648
646
|
});
|
|
649
647
|
}
|
|
650
648
|
|
|
651
|
-
return
|
|
649
|
+
return { schema: schema.value, tables };
|
|
652
650
|
};
|
|
653
651
|
|
|
654
652
|
const ensureDbSchema =
|
|
@@ -787,41 +785,37 @@ const initializeDb =
|
|
|
787
785
|
`,
|
|
788
786
|
|
|
789
787
|
/**
|
|
790
|
-
* The History table stores all values per timestamp, table,
|
|
791
|
-
* column
|
|
792
|
-
*
|
|
793
|
-
*
|
|
794
|
-
*
|
|
795
|
-
* and DbChange to leverage a covering index. Hence, every value change
|
|
796
|
-
* has its timestamp, table, row, and column. In the future, we will
|
|
797
|
-
* rethink that and store history more efficiently.
|
|
798
|
-
*
|
|
799
|
-
* There is no need to use `OwnerId` on the client, because timestamps
|
|
800
|
-
* (which include a `NodeId`) are globally unique. The relay needs
|
|
801
|
-
* `OwnerId` because it hosts multiple apps/owners, but client storage
|
|
802
|
-
* represents one DB, and even when it hosts multiple owners, their
|
|
803
|
-
* timestamps remain unique.
|
|
788
|
+
* The History table stores all values per ownerId, timestamp, table, id,
|
|
789
|
+
* and column for conflict-free merging using last-write-win CRDT.
|
|
790
|
+
* Denormalizes Timestamp and DbChange for covering index performance.
|
|
791
|
+
* Time travel is available when last-write-win isn't desired. Future
|
|
792
|
+
* optimization will store history more efficiently.
|
|
804
793
|
*/
|
|
805
794
|
sql`
|
|
806
795
|
create table evolu_history (
|
|
807
|
-
"
|
|
796
|
+
"ownerId" blob not null,
|
|
808
797
|
"table" text not null,
|
|
809
|
-
"
|
|
798
|
+
"id" blob not null,
|
|
810
799
|
"column" text not null,
|
|
800
|
+
"timestamp" blob not null,
|
|
811
801
|
"value" any
|
|
812
802
|
)
|
|
813
803
|
strict;
|
|
814
804
|
`,
|
|
815
805
|
|
|
816
806
|
sql`
|
|
817
|
-
create index
|
|
807
|
+
create index evolu_history_ownerId_timestamp on evolu_history (
|
|
808
|
+
"ownerId",
|
|
809
|
+
"timestamp"
|
|
810
|
+
);
|
|
818
811
|
`,
|
|
819
812
|
|
|
820
813
|
sql`
|
|
821
|
-
create unique index
|
|
822
|
-
"
|
|
823
|
-
"column",
|
|
814
|
+
create unique index evolu_history_ownerId_table_id_column_timestampDesc on evolu_history (
|
|
815
|
+
"ownerId",
|
|
824
816
|
"table",
|
|
817
|
+
"id",
|
|
818
|
+
"column",
|
|
825
819
|
"timestamp" desc
|
|
826
820
|
);
|
|
827
821
|
`,
|
|
@@ -847,7 +841,14 @@ const initializeDb =
|
|
|
847
841
|
|
|
848
842
|
const result = deps.sqlite.exec(sql`
|
|
849
843
|
insert into evolu_owner
|
|
850
|
-
(
|
|
844
|
+
(
|
|
845
|
+
"mnemonic",
|
|
846
|
+
"id",
|
|
847
|
+
"encryptionKey",
|
|
848
|
+
"createdAt",
|
|
849
|
+
"writeKey",
|
|
850
|
+
"timestamp"
|
|
851
|
+
)
|
|
851
852
|
values
|
|
852
853
|
(
|
|
853
854
|
${ownerRow.mnemonic},
|
|
@@ -910,16 +911,18 @@ const applyMessages =
|
|
|
910
911
|
(
|
|
911
912
|
messages: ReadonlyArray<CrdtMessage>,
|
|
912
913
|
lastTimestamp: Timestamp,
|
|
913
|
-
options: { isMigrationFromVersion0?: boolean } = {},
|
|
914
914
|
): Result<void, SqliteError> => {
|
|
915
|
+
const ownerId = ownerIdToBinaryOwnerId(deps.ownerRowRef.get().id);
|
|
916
|
+
|
|
915
917
|
for (const message of messages) {
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
if (!apply1.ok) return apply1;
|
|
919
|
-
}
|
|
918
|
+
const result1 = applyMessageToAppTable(deps)(ownerId, message);
|
|
919
|
+
if (!result1.ok) return result1;
|
|
920
920
|
|
|
921
|
-
const
|
|
922
|
-
|
|
921
|
+
const result2 = applyMessageToTimestampAndHistoryTables(deps)(
|
|
922
|
+
ownerId,
|
|
923
|
+
message,
|
|
924
|
+
);
|
|
925
|
+
if (!result2.ok) return result2;
|
|
923
926
|
}
|
|
924
927
|
|
|
925
928
|
const timestamp = timestampToTimestampString(lastTimestamp);
|
|
@@ -933,8 +936,8 @@ const applyMessages =
|
|
|
933
936
|
};
|
|
934
937
|
|
|
935
938
|
const applyMessageToAppTable =
|
|
936
|
-
(deps: SqliteDep) =>
|
|
937
|
-
(message: CrdtMessage): Result<void, SqliteError> => {
|
|
939
|
+
(deps: SqliteDep & OwnerRowRefDep) =>
|
|
940
|
+
(ownerId: BinaryOwnerId, message: CrdtMessage): Result<void, SqliteError> => {
|
|
938
941
|
const date = new Date(message.timestamp.millis).toISOString();
|
|
939
942
|
const timestamp = timestampToBinaryTimestamp(message.timestamp);
|
|
940
943
|
|
|
@@ -942,28 +945,29 @@ const applyMessageToAppTable =
|
|
|
942
945
|
const result = deps.sqlite.exec(sql.prepared`
|
|
943
946
|
with
|
|
944
947
|
lastTimestamp as (
|
|
945
|
-
select timestamp
|
|
948
|
+
select "timestamp"
|
|
946
949
|
from evolu_history
|
|
947
950
|
where
|
|
948
|
-
"
|
|
949
|
-
and "column" = ${column}
|
|
951
|
+
"ownerId" = ${ownerId}
|
|
950
952
|
and "table" = ${message.change.table}
|
|
951
|
-
|
|
953
|
+
and "id" = ${message.change.id}
|
|
954
|
+
and "column" = ${column}
|
|
955
|
+
order by "timestamp" desc
|
|
952
956
|
limit 1
|
|
953
957
|
)
|
|
954
958
|
insert into ${sql.identifier(message.change.table)}
|
|
955
959
|
("id", ${sql.identifier(column)}, createdAt, updatedAt)
|
|
956
960
|
select ${message.change.id}, ${value}, ${date}, ${date}
|
|
957
961
|
where
|
|
958
|
-
(select timestamp from lastTimestamp) is null
|
|
959
|
-
or (select timestamp from lastTimestamp) < ${timestamp}
|
|
962
|
+
(select "timestamp" from lastTimestamp) is null
|
|
963
|
+
or (select "timestamp" from lastTimestamp) < ${timestamp}
|
|
960
964
|
on conflict ("id") do update
|
|
961
965
|
set
|
|
962
966
|
${sql.identifier(column)} = ${value},
|
|
963
967
|
updatedAt = ${date}
|
|
964
968
|
where
|
|
965
|
-
(select timestamp from lastTimestamp) is null
|
|
966
|
-
or (select timestamp from lastTimestamp) < ${timestamp};
|
|
969
|
+
(select "timestamp" from lastTimestamp) is null
|
|
970
|
+
or (select "timestamp" from lastTimestamp) < ${timestamp};
|
|
967
971
|
`);
|
|
968
972
|
|
|
969
973
|
if (!result.ok) return result;
|
|
@@ -973,10 +977,9 @@ const applyMessageToAppTable =
|
|
|
973
977
|
};
|
|
974
978
|
|
|
975
979
|
export const applyMessageToTimestampAndHistoryTables =
|
|
976
|
-
(deps: SqliteDep &
|
|
977
|
-
(message: CrdtMessage): Result<void, SqliteError> => {
|
|
980
|
+
(deps: SqliteDep & ClientStorageDep) =>
|
|
981
|
+
(ownerId: BinaryOwnerId, message: CrdtMessage): Result<void, SqliteError> => {
|
|
978
982
|
const timestamp = timestampToBinaryTimestamp(message.timestamp);
|
|
979
|
-
const ownerId = ownerIdToBinaryOwnerId(deps.ownerRowRef.get().id);
|
|
980
983
|
const id = idToBinaryId(message.change.id);
|
|
981
984
|
|
|
982
985
|
const result = deps.storage.insertTimestamp(ownerId, timestamp);
|
|
@@ -985,9 +988,16 @@ export const applyMessageToTimestampAndHistoryTables =
|
|
|
985
988
|
for (const [column, value] of Object.entries(message.change.values)) {
|
|
986
989
|
const result = deps.sqlite.exec(sql.prepared`
|
|
987
990
|
insert into evolu_history
|
|
988
|
-
("
|
|
991
|
+
("ownerId", "table", "id", "column", "value", "timestamp")
|
|
989
992
|
values
|
|
990
|
-
(
|
|
993
|
+
(
|
|
994
|
+
${ownerId},
|
|
995
|
+
${message.change.table},
|
|
996
|
+
${id},
|
|
997
|
+
${column},
|
|
998
|
+
${value},
|
|
999
|
+
${timestamp}
|
|
1000
|
+
)
|
|
991
1001
|
on conflict do nothing;
|
|
992
1002
|
`);
|
|
993
1003
|
if (!result.ok) return result;
|
|
@@ -1063,11 +1073,11 @@ export const maybeMigrateToVersion0 =
|
|
|
1063
1073
|
const messagesRows = deps.sqlite.exec<{
|
|
1064
1074
|
timestamp: TimestampString;
|
|
1065
1075
|
table: Base64Url256;
|
|
1066
|
-
|
|
1076
|
+
id: Id;
|
|
1067
1077
|
column: Base64Url256;
|
|
1068
1078
|
value: SqliteValue;
|
|
1069
1079
|
}>(sql`
|
|
1070
|
-
select "timestamp", "table", "
|
|
1080
|
+
select "timestamp", "table", "id", "column", "value" from evolu_message;
|
|
1071
1081
|
`);
|
|
1072
1082
|
|
|
1073
1083
|
if (!messagesRows.ok) return messagesRows;
|
|
@@ -1083,7 +1093,7 @@ export const maybeMigrateToVersion0 =
|
|
|
1083
1093
|
const messages = messagesRows.value.rows.map((message) => ({
|
|
1084
1094
|
timestamp: timestampStringToTimestamp(message.timestamp),
|
|
1085
1095
|
change: {
|
|
1086
|
-
id: message.
|
|
1096
|
+
id: message.id,
|
|
1087
1097
|
table: message.table,
|
|
1088
1098
|
values: { [message.column]: message.value },
|
|
1089
1099
|
},
|
|
@@ -1179,6 +1189,7 @@ const createClientStorage =
|
|
|
1179
1189
|
|
|
1180
1190
|
writeMessages: (_ownerId, messages) => {
|
|
1181
1191
|
// TODO: Get owner by _ownerId when we support more.
|
|
1192
|
+
// Use ownerId!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
1182
1193
|
const owner = deps.ownerRowRef.get();
|
|
1183
1194
|
const decodedAndDecryptedMessages: Array<CrdtMessage> = [];
|
|
1184
1195
|
|
|
@@ -1231,16 +1242,16 @@ const createClientStorage =
|
|
|
1231
1242
|
return true;
|
|
1232
1243
|
},
|
|
1233
1244
|
|
|
1234
|
-
readDbChange: (
|
|
1245
|
+
readDbChange: (ownerId, timestamp) => {
|
|
1235
1246
|
const result = deps.sqlite.exec<{
|
|
1236
1247
|
table: Base64Url256;
|
|
1237
|
-
|
|
1248
|
+
id: BinaryId;
|
|
1238
1249
|
column: Base64Url256;
|
|
1239
1250
|
value: SqliteValue;
|
|
1240
1251
|
}>(sql`
|
|
1241
|
-
select "table", "
|
|
1252
|
+
select "table", "id", "column", "value"
|
|
1242
1253
|
from evolu_history
|
|
1243
|
-
where "timestamp" = ${timestamp};
|
|
1254
|
+
where "ownerId" = ${ownerId} and "timestamp" = ${timestamp};
|
|
1244
1255
|
`);
|
|
1245
1256
|
if (!result.ok) {
|
|
1246
1257
|
deps.postMessage({ type: "onError", error: result.error });
|
|
@@ -1250,18 +1261,18 @@ const createClientStorage =
|
|
|
1250
1261
|
const { rows } = result.value;
|
|
1251
1262
|
assert(rows.length > 0, "Rows must not be empty");
|
|
1252
1263
|
|
|
1253
|
-
const { table,
|
|
1264
|
+
const { table, id } = rows[0];
|
|
1254
1265
|
const values: Record<string, SqliteValue> = {};
|
|
1255
1266
|
|
|
1256
1267
|
for (const r of rows) {
|
|
1257
1268
|
assert(r.table === table, "All rows must have the same table");
|
|
1258
|
-
assert(eqArrayNumber(r.
|
|
1269
|
+
assert(eqArrayNumber(r.id, id), "All rows must have the same Id");
|
|
1259
1270
|
values[r.column] = r.value;
|
|
1260
1271
|
}
|
|
1261
1272
|
|
|
1262
1273
|
const change: DbChange = {
|
|
1263
1274
|
table: rows[0].table,
|
|
1264
|
-
id: binaryIdToId(rows[0].
|
|
1275
|
+
id: binaryIdToId(rows[0].id),
|
|
1265
1276
|
values,
|
|
1266
1277
|
};
|
|
1267
1278
|
|
package/src/Evolu/Schema.ts
CHANGED
|
@@ -104,7 +104,7 @@ export type CreateQuery<S extends EvoluSchema> = <R extends Row>(
|
|
|
104
104
|
readonly evolu_history: {
|
|
105
105
|
readonly timestamp: BinaryTimestamp;
|
|
106
106
|
readonly table: keyof S;
|
|
107
|
-
readonly
|
|
107
|
+
readonly id: BinaryId;
|
|
108
108
|
readonly column: string;
|
|
109
109
|
readonly value: SqliteValue;
|
|
110
110
|
};
|