@evolu/common 7.2.3 → 7.4.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/dist/src/Buffer.d.ts +2 -1
- package/dist/src/Buffer.d.ts.map +1 -1
- package/dist/src/Buffer.js +1 -0
- package/dist/src/Callbacks.d.ts +1 -1
- package/dist/src/Callbacks.d.ts.map +1 -1
- package/dist/src/Callbacks.js +1 -1
- package/dist/src/Console.d.ts +1 -9
- package/dist/src/Console.d.ts.map +1 -1
- package/dist/src/Console.js +1 -41
- package/dist/src/Function.d.ts +61 -0
- package/dist/src/Function.d.ts.map +1 -1
- package/dist/src/Function.js +19 -0
- package/dist/src/Object.d.ts +16 -0
- package/dist/src/Object.d.ts.map +1 -1
- package/dist/src/Object.js +16 -0
- package/dist/src/Redacted.d.ts +89 -0
- package/dist/src/Redacted.d.ts.map +1 -0
- package/dist/src/Redacted.js +48 -0
- package/dist/src/Result.d.ts +36 -29
- package/dist/src/Result.d.ts.map +1 -1
- package/dist/src/Sqlite.d.ts +9 -7
- package/dist/src/Sqlite.d.ts.map +1 -1
- package/dist/src/Sqlite.js +8 -0
- package/dist/src/Task.d.ts.map +1 -1
- package/dist/src/Task.js +6 -4
- package/dist/src/Type.d.ts +34 -10
- package/dist/src/Type.d.ts.map +1 -1
- package/dist/src/Type.js +82 -202
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -0
- package/dist/src/local-first/Db.d.ts +1 -5
- package/dist/src/local-first/Db.d.ts.map +1 -1
- package/dist/src/local-first/Db.js +109 -108
- package/dist/src/local-first/Evolu.d.ts +3 -0
- package/dist/src/local-first/Evolu.d.ts.map +1 -1
- package/dist/src/local-first/Evolu.js +6 -7
- package/dist/src/local-first/LocalAuth.d.ts +2 -2
- package/dist/src/local-first/Owner.d.ts +7 -0
- package/dist/src/local-first/Owner.d.ts.map +1 -1
- package/dist/src/local-first/Protocol.d.ts.map +1 -1
- package/dist/src/local-first/Protocol.js +10 -10
- package/dist/src/local-first/Public.d.ts +6 -1
- package/dist/src/local-first/Public.d.ts.map +1 -1
- package/dist/src/local-first/Public.js +6 -1
- package/dist/src/local-first/PublicKysely.js +1 -1
- package/dist/src/local-first/Query.d.ts +54 -6
- package/dist/src/local-first/Query.d.ts.map +1 -1
- package/dist/src/local-first/Query.js +130 -11
- package/dist/src/local-first/Relay.d.ts.map +1 -1
- package/dist/src/local-first/Relay.js +17 -18
- package/dist/src/local-first/Schema.d.ts +15 -14
- package/dist/src/local-first/Schema.d.ts.map +1 -1
- package/dist/src/local-first/Schema.js +43 -51
- package/dist/src/local-first/Storage.d.ts +2 -2
- package/dist/src/local-first/Storage.d.ts.map +1 -1
- package/dist/src/local-first/Storage.js +2 -6
- package/dist/src/local-first/Sync.d.ts +9 -4
- package/dist/src/local-first/Sync.d.ts.map +1 -1
- package/dist/src/local-first/Sync.js +132 -59
- package/dist/src/local-first/index.d.ts +9 -2
- package/dist/src/local-first/index.d.ts.map +1 -1
- package/dist/src/local-first/index.js +9 -2
- package/package.json +3 -4
- package/src/Buffer.ts +2 -1
- package/src/Callbacks.ts +1 -1
- package/src/Console.ts +1 -10
- package/src/Function.ts +74 -0
- package/src/Object.ts +20 -0
- package/src/Redacted.ts +118 -0
- package/src/Result.ts +38 -29
- package/src/Sqlite.ts +18 -7
- package/src/Task.ts +6 -4
- package/src/Type.ts +148 -20
- package/src/index.ts +1 -0
- package/src/local-first/Db.ts +181 -209
- package/src/local-first/Evolu.ts +9 -6
- package/src/local-first/LocalAuth.ts +2 -2
- package/src/local-first/Owner.ts +8 -0
- package/src/local-first/Protocol.ts +10 -16
- package/src/local-first/Public.ts +6 -1
- package/src/local-first/PublicKysely.ts +1 -1
- package/src/local-first/Query.ts +216 -21
- package/src/local-first/Relay.ts +20 -24
- package/src/local-first/Schema.ts +83 -70
- package/src/local-first/Storage.ts +3 -8
- package/src/local-first/Sync.ts +190 -66
- package/src/local-first/index.ts +9 -2
- package/dist/src/local-first/Diff.d.ts +0 -43
- package/dist/src/local-first/Diff.d.ts.map +0 -1
- package/dist/src/local-first/Diff.js +0 -97
- package/src/local-first/Diff.ts +0 -144
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { Brand } from "../Brand.js";
|
|
2
|
-
import {
|
|
2
|
+
import { Result } from "../Result.js";
|
|
3
|
+
import { SqliteDep, SqliteError, SqliteQuery, SqliteRow, SqliteValue } from "../Sqlite.js";
|
|
3
4
|
import { Store, StoreSubscribe } from "../Store.js";
|
|
5
|
+
import { Id } from "../Type.js";
|
|
4
6
|
import { Simplify } from "../Types.js";
|
|
5
7
|
/**
|
|
6
8
|
* A type-safe SQL query.
|
|
@@ -50,15 +52,61 @@ export type QueriesToQueryRowsPromises<Q extends Queries> = {
|
|
|
50
52
|
[P in keyof Q]: Q[P] extends Query<infer R> ? Promise<QueryRows<R>> : never;
|
|
51
53
|
};
|
|
52
54
|
export type QueryRowsMap = ReadonlyMap<Query, ReadonlyArray<Row>>;
|
|
53
|
-
export interface QueryRowsCache {
|
|
54
|
-
readonly set: (queriesRows: ReadonlyArray<readonly [Query, ReadonlyArray<SqliteRow>]>) => void;
|
|
55
|
-
readonly get: () => QueryRowsMap;
|
|
56
|
-
}
|
|
57
|
-
export declare const createQueryRowsCache: () => QueryRowsCache;
|
|
58
55
|
export interface SubscribedQueries {
|
|
59
56
|
subscribe: (query: Query) => StoreSubscribe;
|
|
60
57
|
has: (query: Query) => boolean;
|
|
61
58
|
get: () => ReadonlyArray<Query>;
|
|
62
59
|
}
|
|
63
60
|
export declare const createSubscribedQueries: (rowsStore: Store<QueryRowsMap>) => SubscribedQueries;
|
|
61
|
+
export interface GetQueryRowsCacheDep {
|
|
62
|
+
readonly getQueryRowsCache: GetQueryRowsCache;
|
|
63
|
+
}
|
|
64
|
+
export type GetQueryRowsCache = (tabId: Id) => QueryRowsCache;
|
|
65
|
+
export interface QueryRowsCache {
|
|
66
|
+
readonly set: (queriesRows: ReadonlyArray<readonly [Query, ReadonlyArray<SqliteRow>]>) => void;
|
|
67
|
+
readonly get: () => QueryRowsMap;
|
|
68
|
+
}
|
|
69
|
+
export declare const createGetQueryRowsCache: () => GetQueryRowsCache;
|
|
70
|
+
export declare const loadQueries: (deps: GetQueryRowsCacheDep & SqliteDep) => (tabId: Id, queries: ReadonlyArray<Query>) => Result<ReadonlyArray<QueryPatches>, SqliteError>;
|
|
71
|
+
export interface QueryPatches {
|
|
72
|
+
readonly query: Query;
|
|
73
|
+
readonly patches: ReadonlyArray<Patch>;
|
|
74
|
+
}
|
|
75
|
+
export type Patch = ReplaceAllPatch | ReplaceAtPatch;
|
|
76
|
+
export interface ReplaceAllPatch {
|
|
77
|
+
readonly op: "replaceAll";
|
|
78
|
+
readonly value: ReadonlyArray<Row>;
|
|
79
|
+
}
|
|
80
|
+
export interface ReplaceAtPatch {
|
|
81
|
+
readonly op: "replaceAt";
|
|
82
|
+
readonly index: number;
|
|
83
|
+
readonly value: Row;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* We detect only changes in the whole result and in-place edits. In the future,
|
|
87
|
+
* we will add more heuristics. We will probably not implement the Myers diff
|
|
88
|
+
* algorithm because it's faster to rerender all than to compute many detailed
|
|
89
|
+
* patches. We will only implement logic a developer would implement manually,
|
|
90
|
+
* if necessary.
|
|
91
|
+
*/
|
|
92
|
+
export declare const makePatches: (previousRows: ReadonlyArray<Row> | undefined, nextRows: ReadonlyArray<Row>) => ReadonlyArray<Patch>;
|
|
93
|
+
export declare const applyPatches: (patches: ReadonlyArray<Patch>, current: ReadonlyArray<Row>) => ReadonlyArray<Row>;
|
|
94
|
+
/**
|
|
95
|
+
* A unique identifier prepended to JSON-encoded strings. This allows safe
|
|
96
|
+
* detection and parsing of only those columns that require JSON.parse.
|
|
97
|
+
*
|
|
98
|
+
* The identifier is a cryptographically random Evolu Id, ensuring uniqueness
|
|
99
|
+
* and preventing malicious actors from inserting fake data that could be
|
|
100
|
+
* misinterpreted as JSON by the application.
|
|
101
|
+
*
|
|
102
|
+
* Note: The same queries created by different browser tabs will have different
|
|
103
|
+
* identifiers and thus be considered different and cached separately. This is
|
|
104
|
+
* usually not a big deal, but if needed, the DB cache can be optimized by
|
|
105
|
+
* passing the kyselyJsonIdentifier into the DB worker during initialization,
|
|
106
|
+
* allowing queries to be grouped and recognized across tabs or sessions.
|
|
107
|
+
*
|
|
108
|
+
* See: https://github.com/kysely-org/kysely/issues/1372#issuecomment-2702773948
|
|
109
|
+
*/
|
|
110
|
+
export declare const kyselyJsonIdentifier: string & Brand<"Id">;
|
|
111
|
+
export declare const parseSqliteJsonArray: <T>(arr: ReadonlyArray<T>) => ReadonlyArray<T>;
|
|
64
112
|
//# sourceMappingURL=Query.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Query.d.ts","sourceRoot":"","sources":["../../../src/local-first/Query.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"Query.d.ts","sourceRoot":"","sources":["../../../src/local-first/Query.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AASpC,OAAO,EAAM,MAAM,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAIL,SAAS,EACT,WAAW,EACX,WAAW,EAEX,SAAS,EACT,WAAW,EACZ,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAY,EAAE,EAAU,MAAM,YAAY,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,KAAK,CAAC,CAAC,SAAS,GAAG,GAAG,GAAG,IAAI,MAAM,GAC7C,KAAK,CAAC,OAAO,CAAC,GAAG;IACf;;;;;;;;;;;OAWG;IACH,GAAG,EAAE,CAAC,CAAC;CACR,CAAC;AAEJ;;;GAGG;AACH,eAAO,MAAM,cAAc,GAAI,CAAC,SAAS,GAAG,EAAE,OAAO,WAAW,KAAG,KAAK,CAAC,CAAC,CAYzE,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,CAAC,SAAS,GAAG,EAC5C,OAAO,KAAK,CAAC,CAAC,CAAC,KACd,WAoBF,CAAC;AAEF,MAAM,MAAM,QAAQ,CAAC,CAAC,SAAS,KAAK,IAAI,CAAC,SAAS,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;AAE7E,MAAM,WAAW,GAAG;IAClB,QAAQ,EAAE,GAAG,EAAE,MAAM,GACjB,WAAW,GACX,GAAG,GACH,aAAa,CAAC,GAAG,CAAC,CAAC;CACxB;AAGD,eAAO,MAAM,SAAS,EAAE,aAAa,CAAC,GAAG,CAAM,CAAC;AAEhD,gCAAgC;AAChC,MAAM,MAAM,SAAS,CAAC,CAAC,SAAS,GAAG,GAAG,GAAG,IAAI,aAAa,CACxD,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CACtB,CAAC;AAEF,MAAM,MAAM,OAAO,CAAC,CAAC,SAAS,GAAG,GAAG,GAAG,IAAI,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AAEnE,MAAM,MAAM,kBAAkB,CAAC,CAAC,SAAS,OAAO,IAAI;KACjD,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,GAAG,KAAK;CACnE,CAAC;AAEF,MAAM,MAAM,0BAA0B,CAAC,CAAC,SAAS,OAAO,IAAI;KACzD,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK;CAC5E,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,WAAW,CAAC,KAAK,EAAE,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC;AAElE,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,cAAc,CAAC;IAE5C,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC;IAE/B,GAAG,EAAE,MAAM,aAAa,CAAC,KAAK,CAAC,CAAC;CACjC;AAED,eAAO,MAAM,uBAAuB,GAClC,WAAW,KAAK,CAAC,YAAY,CAAC,KAC7B,iBAwBF,CAAC;AAEF,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,iBAAiB,EAAE,iBAAiB,CAAC;CAC/C;AAED,MAAM,MAAM,iBAAiB,GAAG,CAAC,KAAK,EAAE,EAAE,KAAK,cAAc,CAAC;AAE9D,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,GAAG,EAAE,CACZ,WAAW,EAAE,aAAa,CAAC,SAAS,CAAC,KAAK,EAAE,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,KACnE,IAAI,CAAC;IACV,QAAQ,CAAC,GAAG,EAAE,MAAM,YAAY,CAAC;CAClC;AAED,eAAO,MAAM,uBAAuB,QAAO,iBAiB1C,CAAC;AAEF,eAAO,MAAM,WAAW,GACrB,MAAM,oBAAoB,GAAG,SAAS,MAErC,OAAO,EAAE,EACT,SAAS,aAAa,CAAC,KAAK,CAAC,KAC5B,MAAM,CAAC,aAAa,CAAC,YAAY,CAAC,EAAE,WAAW,CA+BjD,CAAC;AAEJ,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC;CACxC;AAED,MAAM,MAAM,KAAK,GAAG,eAAe,GAAG,cAAc,CAAC;AAErD,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,EAAE,YAAY,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,GAAG,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,EAAE,WAAW,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC;CACrB;AAED;;;;;;GAMG;AACH,eAAO,MAAM,WAAW,GACtB,cAAc,aAAa,CAAC,GAAG,CAAC,GAAG,SAAS,EAC5C,UAAU,aAAa,CAAC,GAAG,CAAC,KAC3B,aAAa,CAAC,KAAK,CAgCrB,CAAC;AAEF,eAAO,MAAM,YAAY,GACvB,SAAS,aAAa,CAAC,KAAK,CAAC,EAC7B,SAAS,aAAa,CAAC,GAAG,CAAC,KAC1B,aAAa,CAAC,GAAG,CAUP,CAAC;AAEd;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,oBAAoB,sBAE/B,CAAC;AAEH,eAAO,MAAM,oBAAoB,GAAI,CAAC,EACpC,KAAK,aAAa,CAAC,CAAC,CAAC,KACpB,aAAa,CAAC,CAAC,CAMjB,CAAC"}
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { bytesToHex, hexToBytes } from "../Buffer.js";
|
|
2
|
-
import {
|
|
2
|
+
import { createRandomBytes } from "../Crypto.js";
|
|
3
|
+
import { createRecord, isPlainObject, objectToEntries, } from "../Object.js";
|
|
4
|
+
import { ok } from "../Result.js";
|
|
5
|
+
import { eqSqliteValue, explainSqliteQueryPlan, } from "../Sqlite.js";
|
|
6
|
+
import { createId, String } from "../Type.js";
|
|
3
7
|
/**
|
|
4
8
|
* Evolu serializes {@link SqliteQuery} into a string to be easily used as a key
|
|
5
9
|
* and for comparison.
|
|
@@ -27,16 +31,6 @@ export const deserializeQuery = (query) => {
|
|
|
27
31
|
};
|
|
28
32
|
// To preserve identity.
|
|
29
33
|
export const emptyRows = [];
|
|
30
|
-
export const createQueryRowsCache = () => {
|
|
31
|
-
let queryRowsCache = new Map();
|
|
32
|
-
const cache = {
|
|
33
|
-
set: (queriesRows) => {
|
|
34
|
-
queryRowsCache = new Map([...queryRowsCache, ...queriesRows]);
|
|
35
|
-
},
|
|
36
|
-
get: () => queryRowsCache,
|
|
37
|
-
};
|
|
38
|
-
return cache;
|
|
39
|
-
};
|
|
40
34
|
export const createSubscribedQueries = (rowsStore) => {
|
|
41
35
|
const subscribedQueryMap = new Map();
|
|
42
36
|
const subscribedQueries = {
|
|
@@ -59,3 +53,128 @@ export const createSubscribedQueries = (rowsStore) => {
|
|
|
59
53
|
};
|
|
60
54
|
return subscribedQueries;
|
|
61
55
|
};
|
|
56
|
+
export const createGetQueryRowsCache = () => {
|
|
57
|
+
const tabQueryRowsCacheMap = new Map();
|
|
58
|
+
return (tabId) => {
|
|
59
|
+
let cache = tabQueryRowsCacheMap.get(tabId);
|
|
60
|
+
if (!cache) {
|
|
61
|
+
let queryRowsCache = new Map();
|
|
62
|
+
cache = {
|
|
63
|
+
set: (queriesRows) => {
|
|
64
|
+
queryRowsCache = new Map([...queryRowsCache, ...queriesRows]);
|
|
65
|
+
},
|
|
66
|
+
get: () => queryRowsCache,
|
|
67
|
+
};
|
|
68
|
+
tabQueryRowsCacheMap.set(tabId, cache);
|
|
69
|
+
}
|
|
70
|
+
return cache;
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
export const loadQueries = (deps) => (tabId, queries) => {
|
|
74
|
+
const queriesRows = [];
|
|
75
|
+
for (const query of queries) {
|
|
76
|
+
const sqlQuery = deserializeQuery(query);
|
|
77
|
+
const result = deps.sqlite.exec(sqlQuery);
|
|
78
|
+
if (!result.ok)
|
|
79
|
+
return result;
|
|
80
|
+
queriesRows.push([query, result.value.rows]);
|
|
81
|
+
if (sqlQuery.options?.logExplainQueryPlan) {
|
|
82
|
+
explainSqliteQueryPlan(deps)(sqlQuery);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
const queryRowsCache = deps.getQueryRowsCache(tabId);
|
|
86
|
+
const previousState = queryRowsCache.get();
|
|
87
|
+
queryRowsCache.set(queriesRows);
|
|
88
|
+
const currentState = queryRowsCache.get();
|
|
89
|
+
const queryPatchesArray = queries.map((query) => ({
|
|
90
|
+
query,
|
|
91
|
+
patches: makePatches(previousState.get(query), currentState.get(query) ?? emptyRows),
|
|
92
|
+
}));
|
|
93
|
+
return ok(queryPatchesArray);
|
|
94
|
+
};
|
|
95
|
+
/**
|
|
96
|
+
* We detect only changes in the whole result and in-place edits. In the future,
|
|
97
|
+
* we will add more heuristics. We will probably not implement the Myers diff
|
|
98
|
+
* algorithm because it's faster to rerender all than to compute many detailed
|
|
99
|
+
* patches. We will only implement logic a developer would implement manually,
|
|
100
|
+
* if necessary.
|
|
101
|
+
*/
|
|
102
|
+
export const makePatches = (previousRows, nextRows) => {
|
|
103
|
+
if (previousRows === undefined)
|
|
104
|
+
return [{ op: "replaceAll", value: nextRows }];
|
|
105
|
+
// TODO: Detect prepend and append, it's cheap.
|
|
106
|
+
if (previousRows.length !== nextRows.length) {
|
|
107
|
+
return [{ op: "replaceAll", value: nextRows }];
|
|
108
|
+
}
|
|
109
|
+
const length = previousRows.length;
|
|
110
|
+
const replaceAtPatches = [];
|
|
111
|
+
for (let i = 0; i < length; i++) {
|
|
112
|
+
const previousRow = previousRows[i];
|
|
113
|
+
const nextRow = nextRows[i];
|
|
114
|
+
// We expect the same shape for both rows.
|
|
115
|
+
for (const key in previousRow)
|
|
116
|
+
if (!eqSqliteValue(previousRow[key], nextRow[key])) {
|
|
117
|
+
replaceAtPatches.push({ op: "replaceAt", value: nextRow, index: i });
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (length > 0 && replaceAtPatches.length === length) {
|
|
122
|
+
return [{ op: "replaceAll", value: nextRows }];
|
|
123
|
+
}
|
|
124
|
+
return replaceAtPatches;
|
|
125
|
+
};
|
|
126
|
+
export const applyPatches = (patches, current) => patches.reduce((next, patch) => {
|
|
127
|
+
switch (patch.op) {
|
|
128
|
+
case "replaceAll":
|
|
129
|
+
return parseSqliteJsonArray(patch.value);
|
|
130
|
+
case "replaceAt": {
|
|
131
|
+
const parsedRow = parseSqliteJsonArray([patch.value])[0];
|
|
132
|
+
return next.toSpliced(patch.index, 1, parsedRow);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}, current);
|
|
136
|
+
/**
|
|
137
|
+
* A unique identifier prepended to JSON-encoded strings. This allows safe
|
|
138
|
+
* detection and parsing of only those columns that require JSON.parse.
|
|
139
|
+
*
|
|
140
|
+
* The identifier is a cryptographically random Evolu Id, ensuring uniqueness
|
|
141
|
+
* and preventing malicious actors from inserting fake data that could be
|
|
142
|
+
* misinterpreted as JSON by the application.
|
|
143
|
+
*
|
|
144
|
+
* Note: The same queries created by different browser tabs will have different
|
|
145
|
+
* identifiers and thus be considered different and cached separately. This is
|
|
146
|
+
* usually not a big deal, but if needed, the DB cache can be optimized by
|
|
147
|
+
* passing the kyselyJsonIdentifier into the DB worker during initialization,
|
|
148
|
+
* allowing queries to be grouped and recognized across tabs or sessions.
|
|
149
|
+
*
|
|
150
|
+
* See: https://github.com/kysely-org/kysely/issues/1372#issuecomment-2702773948
|
|
151
|
+
*/
|
|
152
|
+
export const kyselyJsonIdentifier = createId({
|
|
153
|
+
randomBytes: createRandomBytes(),
|
|
154
|
+
});
|
|
155
|
+
export const parseSqliteJsonArray = (arr) => {
|
|
156
|
+
const result = new Array(arr.length);
|
|
157
|
+
for (let i = 0; i < arr.length; ++i) {
|
|
158
|
+
result[i] = parse(arr[i]);
|
|
159
|
+
}
|
|
160
|
+
return result;
|
|
161
|
+
};
|
|
162
|
+
const parse = (obj) => {
|
|
163
|
+
if (String.is(obj) && obj.startsWith(kyselyJsonIdentifier)) {
|
|
164
|
+
return JSON.parse(obj.slice(kyselyJsonIdentifier.length));
|
|
165
|
+
}
|
|
166
|
+
if (Array.isArray(obj)) {
|
|
167
|
+
return parseSqliteJsonArray(obj);
|
|
168
|
+
}
|
|
169
|
+
if (isPlainObject(obj)) {
|
|
170
|
+
return parseObject(obj);
|
|
171
|
+
}
|
|
172
|
+
return obj;
|
|
173
|
+
};
|
|
174
|
+
const parseObject = (obj) => {
|
|
175
|
+
const result = createRecord();
|
|
176
|
+
for (const key in obj) {
|
|
177
|
+
result[key] = parse(obj[key]);
|
|
178
|
+
}
|
|
179
|
+
return result;
|
|
180
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Relay.d.ts","sourceRoot":"","sources":["../../../src/local-first/Relay.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,OAAO,EAAW,MAAM,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAO,SAAS,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3D,OAAO,EAAwB,UAAU,EAAS,MAAM,YAAY,CAAC;AACrE,OAAO,EAAe,UAAU,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EACL,OAAO,EAIR,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,EAEL,6BAA6B,EAI7B,iBAAiB,EACjB,OAAO,EACP,aAAa,EAGd,MAAM,cAAc,CAAC;AAGtB,MAAM,WAAW,WAAY,SAAQ,aAAa,EAAE,aAAa;IAC/D;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,UAAU,CAAC;IAE3B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA0CG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,UAAU,CAAC,OAAO,CAAC,CAAC;CACrE;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,KAAM,SAAQ,UAAU;CAAG;AAE5C,eAAO,MAAM,wBAAwB,GAClC,MAAM,iBAAiB,GAAG,kBAAkB,MAC5C,QAAQ,6BAA6B,KAAG,
|
|
1
|
+
{"version":3,"file":"Relay.d.ts","sourceRoot":"","sources":["../../../src/local-first/Relay.ts"],"names":[],"mappings":"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"}
|
|
@@ -89,10 +89,8 @@ export const createRelaySqliteStorage = (deps) => (config) => {
|
|
|
89
89
|
const { storedBytes } = usage.value;
|
|
90
90
|
const incomingBytes = newMessages.reduce((sum, m) => sum + m.change.length, 0);
|
|
91
91
|
const newStoredBytes = PositiveInt.orThrow((storedBytes ?? 0) + incomingBytes);
|
|
92
|
-
const
|
|
93
|
-
const isWithinQuota = isAsync(
|
|
94
|
-
? await withinQuotaResult
|
|
95
|
-
: withinQuotaResult;
|
|
92
|
+
const result = config.isOwnerWithinQuota(ownerId, newStoredBytes);
|
|
93
|
+
const isWithinQuota = isAsync(result) ? await result : result;
|
|
96
94
|
if (!isWithinQuota) {
|
|
97
95
|
return err({ type: "StorageQuotaError", ownerId });
|
|
98
96
|
}
|
|
@@ -102,21 +100,22 @@ export const createRelaySqliteStorage = (deps) => (config) => {
|
|
|
102
100
|
let strategy;
|
|
103
101
|
[strategy, firstTimestamp, lastTimestamp] =
|
|
104
102
|
getTimestampInsertStrategy(timestamp, firstTimestamp, lastTimestamp);
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
103
|
+
{
|
|
104
|
+
const result = sqliteStorageBase.insertTimestamp(ownerIdBytes, timestamp, strategy);
|
|
105
|
+
if (!result.ok)
|
|
106
|
+
return result;
|
|
107
|
+
}
|
|
108
|
+
{
|
|
109
|
+
const result = deps.sqlite.exec(sql `
|
|
110
|
+
insert into evolu_message ("ownerId", "timestamp", "change")
|
|
111
|
+
values (${ownerIdBytes}, ${timestamp}, ${change})
|
|
112
|
+
on conflict do nothing;
|
|
113
|
+
`);
|
|
114
|
+
if (!result.ok)
|
|
115
|
+
return result;
|
|
116
|
+
}
|
|
115
117
|
}
|
|
116
|
-
|
|
117
|
-
if (!updateUsage.ok)
|
|
118
|
-
return updateUsage;
|
|
119
|
-
return ok();
|
|
118
|
+
return updateOwnerUsage(deps)(ownerIdBytes, newStoredBytes, firstTimestamp, lastTimestamp);
|
|
120
119
|
});
|
|
121
120
|
})();
|
|
122
121
|
if (!result.ok && result.error.type !== "AbortError") {
|
|
@@ -6,7 +6,7 @@ import { AnyType, IdBytes, InferErrors, InferInput, InferType, MergeObjectTypeEr
|
|
|
6
6
|
import { Simplify } from "../Types.js";
|
|
7
7
|
import { OwnerId } from "./Owner.js";
|
|
8
8
|
import { Query, Row } from "./Query.js";
|
|
9
|
-
import { DbChange } from "./Storage.js";
|
|
9
|
+
import type { DbChange } from "./Storage.js";
|
|
10
10
|
import { TimestampBytes } from "./Timestamp.js";
|
|
11
11
|
/**
|
|
12
12
|
* Defines the schema of an Evolu database.
|
|
@@ -77,6 +77,13 @@ export type CreateQuery<S extends EvoluSchema> = <R extends Row>(queryCallback:
|
|
|
77
77
|
readonly column: string;
|
|
78
78
|
readonly value: SqliteValue;
|
|
79
79
|
};
|
|
80
|
+
readonly evolu_message_quarantine: {
|
|
81
|
+
readonly timestamp: TimestampBytes;
|
|
82
|
+
readonly table: string;
|
|
83
|
+
readonly id: IdBytes;
|
|
84
|
+
readonly column: string;
|
|
85
|
+
readonly value: SqliteValue;
|
|
86
|
+
};
|
|
80
87
|
}>, "selectFrom" | "fn" | "with" | "withRecursive">) => Kysely.SelectQueryBuilder<any, any, R>, options?: SqliteQueryOptions) => Query<Simplify<R>>;
|
|
81
88
|
/**
|
|
82
89
|
* System columns that are implicitly defined by Evolu.
|
|
@@ -94,7 +101,8 @@ export declare const SystemColumns: ObjectType<{
|
|
|
94
101
|
ownerId: import("../Type.js").BrandType<import("../Type.js").BrandType<Type<"String", string, string, import("../Type.js").StringError, string, import("../Type.js").StringError>, "Id", import("../Type.js").IdError, import("../Type.js").StringError>, "OwnerId", import("../Type.js").BrandWithoutRefineError<"OwnerId", import("../Type.js").StringError | import("../Type.js").IdError>, never>;
|
|
95
102
|
}>;
|
|
96
103
|
export type SystemColumns = typeof SystemColumns.Type;
|
|
97
|
-
export declare const systemColumns: string
|
|
104
|
+
export declare const systemColumns: ReadonlySet<string>;
|
|
105
|
+
export declare const systemColumnsWithId: readonly string[];
|
|
98
106
|
export type MutationKind = "insert" | "update" | "upsert";
|
|
99
107
|
export type Mutation<S extends EvoluSchema, Kind extends MutationKind> = <TableName extends keyof S>(table: TableName, props: InferInput<ObjectType<MutationMapping<S[TableName], Kind>>>, options?: MutationOptions) => Result<{
|
|
100
108
|
readonly id: S[TableName]["id"]["Type"];
|
|
@@ -231,33 +239,26 @@ export type InferMutationTypeErrors<T extends Record<string, AnyType>> = InferCo
|
|
|
231
239
|
export type InferColumnErrors<T extends Record<string, AnyType>, M extends MutationKind> = {
|
|
232
240
|
[Column in keyof MutationMapping<T, M>]: InferErrors<MutationMapping<T, M>[Column]>;
|
|
233
241
|
}[keyof MutationMapping<T, M>];
|
|
234
|
-
export declare const DbTable: ObjectType<{
|
|
235
|
-
name: Type<"String", string, string, import("../Type.js").StringError, string, import("../Type.js").StringError>;
|
|
236
|
-
columns: import("../Type.js").ArrayType<Type<"String", string, string, import("../Type.js").StringError, string, import("../Type.js").StringError>>;
|
|
237
|
-
}>;
|
|
238
|
-
export type DbTable = typeof DbTable.Type;
|
|
239
242
|
export declare const DbIndex: ObjectType<{
|
|
240
243
|
name: Type<"String", string, string, import("../Type.js").StringError, string, import("../Type.js").StringError>;
|
|
241
244
|
sql: Type<"String", string, string, import("../Type.js").StringError, string, import("../Type.js").StringError>;
|
|
242
245
|
}>;
|
|
243
246
|
export type DbIndex = typeof DbIndex.Type;
|
|
244
247
|
export declare const DbSchema: ObjectType<{
|
|
245
|
-
tables: import("../Type.js").
|
|
246
|
-
name: Type<"String", string, string, import("../Type.js").StringError, string, import("../Type.js").StringError>;
|
|
247
|
-
columns: import("../Type.js").ArrayType<Type<"String", string, string, import("../Type.js").StringError, string, import("../Type.js").StringError>>;
|
|
248
|
-
}>>;
|
|
248
|
+
tables: import("../Type.js").RecordType<"String", string, string, import("../Type.js").StringError, string, import("../Type.js").StringError, import("../Type.js").SetType<Type<"String", string, string, import("../Type.js").StringError, string, import("../Type.js").StringError>>>;
|
|
249
249
|
indexes: import("../Type.js").ArrayType<ObjectType<{
|
|
250
250
|
name: Type<"String", string, string, import("../Type.js").StringError, string, import("../Type.js").StringError>;
|
|
251
251
|
sql: Type<"String", string, string, import("../Type.js").StringError, string, import("../Type.js").StringError>;
|
|
252
252
|
}>>;
|
|
253
253
|
}>;
|
|
254
254
|
export type DbSchema = typeof DbSchema.Type;
|
|
255
|
+
export interface DbSchemaDep {
|
|
256
|
+
readonly dbSchema: DbSchema;
|
|
257
|
+
}
|
|
255
258
|
/** Get the current database schema by reading SQLite metadata. */
|
|
256
259
|
export declare const getDbSchema: (deps: SqliteDep) => ({ allIndexes }?: {
|
|
257
260
|
allIndexes?: boolean;
|
|
258
261
|
}) => Result<DbSchema, SqliteError>;
|
|
259
|
-
export declare const ensureDbSchema: (deps: SqliteDep) => (newSchema: DbSchema, currentSchema
|
|
260
|
-
ignoreIndexes: boolean;
|
|
261
|
-
}) => Result<void, SqliteError>;
|
|
262
|
+
export declare const ensureDbSchema: (deps: SqliteDep) => (newSchema: DbSchema, currentSchema?: DbSchema) => Result<void, SqliteError>;
|
|
262
263
|
export declare const kysely: Kysely.Kysely<unknown>;
|
|
263
264
|
//# sourceMappingURL=Schema.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Schema.d.ts","sourceRoot":"","sources":["../../../src/local-first/Schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC;AACjC,OAAO,
|
|
1
|
+
{"version":3,"file":"Schema.d.ts","sourceRoot":"","sources":["../../../src/local-first/Schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC;AACjC,OAAO,EAIL,cAAc,EACf,MAAM,cAAc,CAAC;AACtB,OAAO,EAAM,MAAM,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAGL,aAAa,EACb,SAAS,EACT,WAAW,EAEX,kBAAkB,EAClB,WAAW,EACZ,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,OAAO,EAIP,OAAO,EACP,WAAW,EACX,UAAU,EACV,SAAS,EAET,qBAAqB,EAErB,uBAAuB,EAGvB,UAAU,EAGV,YAAY,EAIZ,OAAO,EACP,IAAI,EACJ,iBAAiB,EAEjB,sBAAsB,EACvB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAY,OAAO,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,KAAK,EAAe,QAAQ,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAa,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAG3D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,MAAM,MAAM,WAAW,GAAG,cAAc,CACtC,MAAM,EAEN,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,CAC3D,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,cAAc,CAAC,CAAC,SAAS,WAAW,IAC9C,mBAAmB,CAAC,CAAC,CAAC,SAAS,KAAK,GAChC,oBAAoB,CAAC,CAAC,CAAC,SAAS,KAAK,GACnC,uBAAuB,CAAC,CAAC,CAAC,SAAS,KAAK,GACtC,mBAAmB,CAAC,CAAC,CAAC,SAAS,KAAK,GAClC,CAAC,GACD,mBAAmB,CAAC,CAAC,CAAC,GACxB,uBAAuB,CAAC,CAAC,CAAC,GAC5B,oBAAoB,CAAC,CAAC,CAAC,GACzB,mBAAmB,CAAC,CAAC,CAAC,CAAC;AAE7B,MAAM,MAAM,mBAAmB,CAAC,CAAC,SAAS,WAAW,IACnD,MAAM,CAAC,SAAS,MAAM,SAAS,GAC3B,SAAS,SAAS,MAAM,CAAC,GACvB,IAAI,SAAS,MAAM,CAAC,CAAC,SAAS,CAAC,GAC7B,KAAK,GACL,qBAAqB,CAAC,UAAU,SAAS,GAAG,MAAM,kCAAkC,CAAC,GACvF,KAAK,GACP,KAAK,CAAC;AAEZ,MAAM,MAAM,oBAAoB,CAAC,CAAC,SAAS,WAAW,IACpD,MAAM,CAAC,SAAS,MAAM,SAAS,GAC3B,SAAS,SAAS,MAAM,CAAC,GACvB,IAAI,SAAS,MAAM,CAAC,CAAC,SAAS,CAAC,GAC7B,CAAC,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,SAAS,OAAO,CAAC,GAAG,CAAC,GACrC,KAAK,GACL,qBAAqB,CAAC,UAAU,SAAS,GAAG,MAAM,2DAA2D,SAAS,GAAG,MAAM,MAAM,CAAC,GACxI,KAAK,GACP,KAAK,GACP,KAAK,CAAC;AAEZ,MAAM,MAAM,uBAAuB,CAAC,CAAC,SAAS,WAAW,IACvD,MAAM,CAAC,SAAS,MAAM,SAAS,GAC3B,SAAS,SAAS,MAAM,CAAC,GACvB,MAAM,CAAC,CAAC,SAAS,CAAC,SAAS,MAAM,UAAU,GACzC,UAAU,SAAS,MAAM,CAAC,CAAC,SAAS,CAAC,GACnC,UAAU,SACN,WAAW,GACX,WAAW,GACX,WAAW,GACX,SAAS,GACX,qBAAqB,CAAC,UAAU,SAAS,GAAG,MAAM,8BAA8B,UAAU,GAAG,MAAM,uFAAuF,CAAC,GAC3L,KAAK,GACP,KAAK,GACP,KAAK,GACP,KAAK,GACP,KAAK,CAAC;AAEZ,MAAM,MAAM,mBAAmB,CAAC,CAAC,SAAS,WAAW,IACnD,MAAM,CAAC,SAAS,MAAM,SAAS,GAC3B,SAAS,SAAS,MAAM,CAAC,GACvB,MAAM,CAAC,CAAC,SAAS,CAAC,SAAS,MAAM,UAAU,GACzC,UAAU,SAAS,MAAM,CAAC,CAAC,SAAS,CAAC,GACnC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,UAAU,CAAC,CAAC,SAAS,WAAW,GACrD,KAAK,GACL,qBAAqB,CAAC,UAAU,SAAS,GAAG,MAAM,aAAa,UAAU,GAAG,MAAM,mHAAmH,CAAC,GACxM,KAAK,GACP,KAAK,GACP,KAAK,GACP,KAAK,CAAC;AAEZ,kEAAkE;AAClE,MAAM,MAAM,qBAAqB,CAAC,OAAO,SAAS,MAAM,IACtD,mBAAmB,OAAO,EAAE,CAAC;AAE/B,MAAM,MAAM,aAAa,GAAG,CAC1B,MAAM,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,CAAC,kBAAkB,KACrD,aAAa,CAAC,MAAM,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC;AAEnD,eAAO,MAAM,qBAAqB,GAChC,QAAQ,WAAW,EACnB,gBAAgB,aAAa,KAC5B,QAgBF,CAAC;AAEF,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,WAAW,IAAI,CAAC,CAAC,SAAS,GAAG,EAC7D,aAAa,EAAE,CACb,EAAE,EAAE,IAAI,CACN,MAAM,CAAC,MAAM,CACX;KACG,KAAK,IAAI,MAAM,CAAC,GAAG;QAClB,QAAQ,EAAE,MAAM,IAAI,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,MAAM,SAAS,IAAI,GACpD,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,aAAa;CAClB,GAAG;IACF,QAAQ,CAAC,aAAa,EAAE;QACtB,QAAQ,CAAC,SAAS,EAAE,cAAc,CAAC;QACnC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QACxB,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;QACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QACxB,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;KAC7B,CAAC;IACF,QAAQ,CAAC,wBAAwB,EAAE;QACjC,QAAQ,CAAC,SAAS,EAAE,cAAc,CAAC;QACnC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;QACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QACxB,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;KAC7B,CAAC;CACH,CACF,EACD,YAAY,GAAG,IAAI,GAAG,MAAM,GAAG,eAAe,CAC/C,KACE,MAAM,CAAC,kBAAkB,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,EAC3C,OAAO,CAAC,EAAE,kBAAkB,KACzB,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;AAExB;;;;;;;;GAQG;AACH,eAAO,MAAM,aAAa;;;;;EAKxB,CAAC;AACH,MAAM,MAAM,aAAa,GAAG,OAAO,aAAa,CAAC,IAAI,CAAC;AAEtD,eAAO,MAAM,aAAa,qBAEzB,CAAC;AAEF,eAAO,MAAM,mBAAmB,mBAAqC,CAAC;AAEtE,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE1D,MAAM,MAAM,QAAQ,CAAC,CAAC,SAAS,WAAW,EAAE,IAAI,SAAS,YAAY,IAAI,CACvE,SAAS,SAAS,MAAM,CAAC,EAEzB,KAAK,EAAE,SAAS,EAChB,KAAK,EAAE,UAAU,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,EAClE,OAAO,CAAC,EAAE,eAAe,KACtB,MAAM,CACT;IAAE,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAA;CAAE,EACzC,sBAAsB,GACtB,qBAAqB,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CACzE,CAAC;AAEF,MAAM,MAAM,eAAe,CACzB,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,CAAC,SAAS,YAAY,IACpB,CAAC,SAAS,QAAQ,GAClB,eAAe,CAAC,CAAC,CAAC,GAClB,CAAC,SAAS,QAAQ,GAChB,eAAe,CAAC,CAAC,CAAC,GAClB,eAAe,CAAC,CAAC,CAAC,CAAC;AAEzB,MAAM,WAAW,eAAe;IAC9B;;;;OAIG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IAEjC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAgCG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAE3B;;;;;OAKG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,CAAC;CACjC;AAED,MAAM,WAAW,cAAe,SAAQ,QAAQ;IAC9C,6EAA6E;IAC7E,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACxC;AAED;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,UAAU,GAAI,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9D,OAAO,KAAK,KACX,iBAAiB,CAAC,eAAe,CAAC,KAAK,CAAC,CAI1C,CAAC;AAEF,MAAM,MAAM,eAAe,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,IAAI,CACvE,uBAAuB,CAAC,KAAK,CAAC,EAC9B,IAAI,CACL,CAAC;AAEF,MAAM,MAAM,UAAU,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,UAAU,CACxE,UAAU,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,CACnC,CAAC;AAEF;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,UAAU,GAAI,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9D,OAAO,KAAK,KACX,iBAAiB,CAAC,eAAe,CAAC,KAAK,CAAC,CAM1C,CAAC;AAEF,MAAM,MAAM,eAAe,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI;KAClE,CAAC,IAAI,MAAM,KAAK,GAAG,CAAC,SAAS,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;CACvE,GAAG;IAAE,SAAS,EAAE,YAAY,CAAC,OAAO,aAAa,CAAC,CAAA;CAAE,CAAC;AAEtD,MAAM,MAAM,UAAU,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,UAAU,CACxE,UAAU,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,CACnC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,UAAU,GAAI,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9D,OAAO,KAAK,KACX,iBAAiB,CAAC,eAAe,CAAC,KAAK,CAAC,CAM1C,CAAC;AAEF,MAAM,MAAM,eAAe,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAC/D,uBAAuB,CACrB,KAAK,GAAG;IACN,SAAS,EAAE,YAAY,CAAC,OAAO,aAAa,CAAC,CAAC;CAC/C,CACF,CAAC;AAEJ,MAAM,MAAM,UAAU,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,UAAU,CACxE,UAAU,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,CACnC,CAAC;AAEF,MAAM,MAAM,qBAAqB,CAAC,CAAC,SAAS,WAAW,IAAI;KACxD,KAAK,IAAI,MAAM,CAAC,GAAG,uBAAuB,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;CACtD,CAAC,MAAM,CAAC,CAAC,CAAC;AAEX,MAAM,MAAM,uBAAuB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IACjE,iBAAiB,CAAC,CAAC,EAAE,QAAQ,CAAC,GAC9B,iBAAiB,CAAC,CAAC,EAAE,QAAQ,CAAC,GAC9B,iBAAiB,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;AAEnC,MAAM,MAAM,iBAAiB,CAC3B,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,CAAC,SAAS,YAAY,IACpB;KACD,MAAM,IAAI,MAAM,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,WAAW,CAClD,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAC9B;CACF,CAAC,MAAM,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAE/B,eAAO,MAAM,OAAO;;;EAAwC,CAAC;AAC7D,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,IAAI,CAAC;AAE1C,eAAO,MAAM,QAAQ;;;;;;EAGnB,CAAC;AACH,MAAM,MAAM,QAAQ,GAAG,OAAO,QAAQ,CAAC,IAAI,CAAC;AAI5C,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;CAC7B;AAED,kEAAkE;AAClE,eAAO,MAAM,WAAW,GACrB,MAAM,SAAS,MACf,iBAAwB;IAAE,UAAU,CAAC,EAAE,OAAO,CAAA;CAAO,KAAG,MAAM,CAC7D,QAAQ,EACR,WAAW,CAyDZ,CAAC;AAKJ,eAAO,MAAM,cAAc,GACxB,MAAM,SAAS,MAEd,WAAW,QAAQ,EACnB,gBAAgB,QAAQ,KACvB,MAAM,CAAC,IAAI,EAAE,WAAW,CAoD1B,CAAC;AAqBJ,eAAO,MAAM,MAAM,wBASjB,CAAC"}
|
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
import * as Kysely from "kysely";
|
|
2
|
-
import { mapObject,
|
|
2
|
+
import { createRecord, getProperty, mapObject, } from "../Object.js";
|
|
3
3
|
import { ok } from "../Result.js";
|
|
4
4
|
import { sql, SqliteBoolean, } from "../Sqlite.js";
|
|
5
|
-
import { array, DateIso, nullableToOptional, nullOr, object, omit, optional, String, validMutationSize, } from "../Type.js";
|
|
5
|
+
import { array, DateIso, nullableToOptional, nullOr, object, omit, optional, record, set, String, validMutationSize, } from "../Type.js";
|
|
6
6
|
import { OwnerId } from "./Owner.js";
|
|
7
|
+
import { readonly } from "../Function.js";
|
|
7
8
|
export const evoluSchemaToDbSchema = (schema, indexesConfig) => {
|
|
8
|
-
const tables =
|
|
9
|
-
name: tableName,
|
|
10
|
-
columns: objectToEntries(table)
|
|
11
|
-
.filter(([k]) => k !== "id")
|
|
12
|
-
.map(([k]) => k),
|
|
13
|
-
}));
|
|
9
|
+
const tables = mapObject(schema, (table) => new Set(Object.keys(table).filter((k) => k !== "id")));
|
|
14
10
|
const indexes = indexesConfig
|
|
15
11
|
? indexesConfig(createIndex).map((index) => ({
|
|
16
12
|
name: index.toOperationNode().name.name,
|
|
@@ -34,7 +30,8 @@ export const SystemColumns = object({
|
|
|
34
30
|
isDeleted: nullOr(SqliteBoolean),
|
|
35
31
|
ownerId: OwnerId,
|
|
36
32
|
});
|
|
37
|
-
export const systemColumns = Object.keys(SystemColumns.props);
|
|
33
|
+
export const systemColumns = readonly(new Set(Object.keys(SystemColumns.props)));
|
|
34
|
+
export const systemColumnsWithId = readonly([...systemColumns, "id"]);
|
|
38
35
|
/**
|
|
39
36
|
* Type Factory to create insertable {@link Type}. It makes nullable Types
|
|
40
37
|
* optional (so they are not required), omits Id, and ensures the
|
|
@@ -108,18 +105,14 @@ export const upsertable = (props) => {
|
|
|
108
105
|
};
|
|
109
106
|
return validMutationSize(nullableToOptional(propsWithDefaults));
|
|
110
107
|
};
|
|
111
|
-
export const DbTable = object({
|
|
112
|
-
name: String,
|
|
113
|
-
columns: array(String),
|
|
114
|
-
});
|
|
115
108
|
export const DbIndex = object({ name: String, sql: String });
|
|
116
109
|
export const DbSchema = object({
|
|
117
|
-
tables:
|
|
110
|
+
tables: record(String, set(String)),
|
|
118
111
|
indexes: array(DbIndex),
|
|
119
112
|
});
|
|
120
113
|
/** Get the current database schema by reading SQLite metadata. */
|
|
121
114
|
export const getDbSchema = (deps) => ({ allIndexes = false } = {}) => {
|
|
122
|
-
const
|
|
115
|
+
const tables = createRecord();
|
|
123
116
|
const tableAndColumnInfoRows = deps.sqlite.exec(sql `
|
|
124
117
|
select
|
|
125
118
|
sqlite_master.name as tableName,
|
|
@@ -132,11 +125,8 @@ export const getDbSchema = (deps) => ({ allIndexes = false } = {}) => {
|
|
|
132
125
|
return tableAndColumnInfoRows;
|
|
133
126
|
tableAndColumnInfoRows.value.rows.forEach((row) => {
|
|
134
127
|
const { tableName, columnName } = row;
|
|
135
|
-
|
|
136
|
-
map.set(tableName, []);
|
|
137
|
-
map.get(tableName)?.push(columnName);
|
|
128
|
+
(tables[tableName] ??= new Set()).add(columnName);
|
|
138
129
|
});
|
|
139
|
-
const tables = Array.from(map, ([name, columns]) => ({ name, columns }));
|
|
140
130
|
const indexesRows = deps.sqlite.exec(allIndexes
|
|
141
131
|
? sql `
|
|
142
132
|
select name, sql
|
|
@@ -167,38 +157,40 @@ export const getDbSchema = (deps) => ({ allIndexes = false } = {}) => {
|
|
|
167
157
|
return ok({ tables, indexes });
|
|
168
158
|
};
|
|
169
159
|
const indexesAreEqual = (self, that) => self.name === that.name && self.sql === that.sql;
|
|
170
|
-
export const ensureDbSchema = (deps) => (newSchema, currentSchema
|
|
160
|
+
export const ensureDbSchema = (deps) => (newSchema, currentSchema) => {
|
|
171
161
|
const queries = [];
|
|
172
|
-
|
|
173
|
-
const
|
|
174
|
-
if (!
|
|
175
|
-
|
|
162
|
+
if (!currentSchema) {
|
|
163
|
+
const dbSchema = getDbSchema(deps)();
|
|
164
|
+
if (!dbSchema.ok)
|
|
165
|
+
return dbSchema;
|
|
166
|
+
currentSchema = dbSchema.value;
|
|
167
|
+
}
|
|
168
|
+
for (const [tableName, newColumns] of Object.entries(newSchema.tables)) {
|
|
169
|
+
const currentColumns = getProperty(currentSchema.tables, tableName);
|
|
170
|
+
if (!currentColumns) {
|
|
171
|
+
queries.push(createAppTable(tableName, newColumns));
|
|
176
172
|
}
|
|
177
173
|
else {
|
|
178
|
-
|
|
179
|
-
.filter((newColumn) => !currentTable.columns.includes(newColumn))
|
|
180
|
-
.forEach((newColumn) => {
|
|
174
|
+
for (const newColumn of newColumns.difference(currentColumns)) {
|
|
181
175
|
queries.push(sql `
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
}
|
|
176
|
+
alter table ${sql.identifier(tableName)}
|
|
177
|
+
add column ${sql.identifier(newColumn)} any;
|
|
178
|
+
`);
|
|
179
|
+
}
|
|
186
180
|
}
|
|
187
|
-
});
|
|
188
|
-
if (options?.ignoreIndexes !== true) {
|
|
189
|
-
// Remove current indexes that are not in the newSchema.
|
|
190
|
-
currentSchema.indexes
|
|
191
|
-
.filter((currentIndex) => !newSchema.indexes.some((newIndex) => indexesAreEqual(newIndex, currentIndex)))
|
|
192
|
-
.forEach((index) => {
|
|
193
|
-
queries.push(sql `drop index ${sql.identifier(index.name)};`);
|
|
194
|
-
});
|
|
195
|
-
// Add new indexes that are not in the currentSchema.
|
|
196
|
-
newSchema.indexes
|
|
197
|
-
.filter((newIndex) => !currentSchema.indexes.some((currentIndex) => indexesAreEqual(newIndex, currentIndex)))
|
|
198
|
-
.forEach((newIndex) => {
|
|
199
|
-
queries.push({ sql: `${newIndex.sql};`, parameters: [] });
|
|
200
|
-
});
|
|
201
181
|
}
|
|
182
|
+
// Remove current indexes that are not in the newSchema.
|
|
183
|
+
currentSchema.indexes
|
|
184
|
+
.filter((currentIndex) => !newSchema.indexes.some((newIndex) => indexesAreEqual(newIndex, currentIndex)))
|
|
185
|
+
.forEach((index) => {
|
|
186
|
+
queries.push(sql `drop index ${sql.identifier(index.name)};`);
|
|
187
|
+
});
|
|
188
|
+
// Add new indexes that are not in the currentSchema.
|
|
189
|
+
newSchema.indexes
|
|
190
|
+
.filter((newIndex) => !currentSchema.indexes.some((currentIndex) => indexesAreEqual(newIndex, currentIndex)))
|
|
191
|
+
.forEach((newIndex) => {
|
|
192
|
+
queries.push({ sql: `${newIndex.sql};`, parameters: [] });
|
|
193
|
+
});
|
|
202
194
|
for (const query of queries) {
|
|
203
195
|
const result = deps.sqlite.exec(query);
|
|
204
196
|
if (!result.ok)
|
|
@@ -206,17 +198,17 @@ export const ensureDbSchema = (deps) => (newSchema, currentSchema, options) => {
|
|
|
206
198
|
}
|
|
207
199
|
return ok();
|
|
208
200
|
};
|
|
209
|
-
const createAppTable = (
|
|
210
|
-
create table ${sql.identifier(
|
|
201
|
+
const createAppTable = (tableName, columns) => sql `
|
|
202
|
+
create table ${sql.identifier(tableName)} (
|
|
211
203
|
"id" text,
|
|
212
|
-
${sql.raw(`${systemColumns
|
|
213
|
-
.concat(table.columns)
|
|
214
|
-
.filter((c) => c !== "id")
|
|
204
|
+
${sql.raw(`${[...systemColumns, ...columns]
|
|
215
205
|
// With strict tables and any type, data is preserved exactly as received
|
|
216
206
|
// without any type affinity coercion. This allows storing any data type
|
|
217
207
|
// while maintaining strict null enforcement for primary key columns.
|
|
208
|
+
// TODO: Use proper SQLite types for system columns (text for createdAt,
|
|
209
|
+
// updatedAt, ownerId, integer for isDeleted) instead of "any".
|
|
218
210
|
.map((name) => `${sql.identifier(name).sql} any`)
|
|
219
|
-
.join(", ")}`)}
|
|
211
|
+
.join(", ")}, `)}
|
|
220
212
|
primary key ("ownerId", "id")
|
|
221
213
|
)
|
|
222
214
|
without rowid, strict;
|
|
@@ -165,7 +165,7 @@ export interface CrdtMessage {
|
|
|
165
165
|
}
|
|
166
166
|
export declare const DbChangeValues: import("../Type.js").RecordType<"String", string, string, import("../Type.js").StringError, string, import("../Type.js").StringError, import("../Type.js").UnionType<[import("../Type.js").Type<"Null", null, null, import("../Type.js").NullError, null, import("../Type.js").NullError>, import("../Type.js").Type<"String", string, string, import("../Type.js").StringError, string, import("../Type.js").StringError>, import("../Type.js").Type<"Number", number, number, import("../Type.js").NumberError, number, import("../Type.js").NumberError>, import("../Type.js").Type<"Uint8Array", Uint8Array<ArrayBufferLike>, Uint8Array<ArrayBufferLike>, import("../Type.js").Uint8ArrayError, Uint8Array<ArrayBufferLike>, import("../Type.js").Uint8ArrayError>]>>;
|
|
167
167
|
export type DbChangeValues = typeof DbChangeValues.Type;
|
|
168
|
-
export declare const ValidDbChangeValues: import("../Type.js").BrandType<import("../Type.js").RecordType<"String", string, string, import("../Type.js").StringError, string, import("../Type.js").StringError, import("../Type.js").UnionType<[import("../Type.js").Type<"Null", null, null, import("../Type.js").NullError, null, import("../Type.js").NullError>, import("../Type.js").Type<"String", string, string, import("../Type.js").StringError, string, import("../Type.js").StringError>, import("../Type.js").Type<"Number", number, number, import("../Type.js").NumberError, number, import("../Type.js").NumberError>, import("../Type.js").Type<"Uint8Array", Uint8Array<ArrayBufferLike>, Uint8Array<ArrayBufferLike>, import("../Type.js").Uint8ArrayError, Uint8Array<ArrayBufferLike>, import("../Type.js").Uint8ArrayError>]>>, "ValidDbChangeValues", ValidDbChangeValuesError, import("../Type.js").RecordError<import("../Type.js").StringError, never> | import("../Type.js").RecordError<import("../Type.js").StringError, import("../Type.js").UnionError<import("../Type.js").
|
|
168
|
+
export declare const ValidDbChangeValues: import("../Type.js").BrandType<import("../Type.js").RecordType<"String", string, string, import("../Type.js").StringError, string, import("../Type.js").StringError, import("../Type.js").UnionType<[import("../Type.js").Type<"Null", null, null, import("../Type.js").NullError, null, import("../Type.js").NullError>, import("../Type.js").Type<"String", string, string, import("../Type.js").StringError, string, import("../Type.js").StringError>, import("../Type.js").Type<"Number", number, number, import("../Type.js").NumberError, number, import("../Type.js").NumberError>, import("../Type.js").Type<"Uint8Array", Uint8Array<ArrayBufferLike>, Uint8Array<ArrayBufferLike>, import("../Type.js").Uint8ArrayError, Uint8Array<ArrayBufferLike>, import("../Type.js").Uint8ArrayError>]>>, "ValidDbChangeValues", ValidDbChangeValuesError, import("../Type.js").RecordError<import("../Type.js").StringError, never> | import("../Type.js").RecordError<import("../Type.js").StringError, import("../Type.js").UnionError<import("../Type.js").StringError | import("../Type.js").NumberError | import("../Type.js").Uint8ArrayError | import("../Type.js").NullError>>>;
|
|
169
169
|
export type ValidDbChangeValues = typeof ValidDbChangeValues.Type;
|
|
170
170
|
export interface ValidDbChangeValuesError extends TypeError<"ValidDbChangeValues"> {
|
|
171
171
|
readonly invalidColumns: ReadonlyArray<string>;
|
|
@@ -177,7 +177,7 @@ export interface ValidDbChangeValuesError extends TypeError<"ValidDbChangeValues
|
|
|
177
177
|
export declare const DbChange: import("../Type.js").ObjectType<{
|
|
178
178
|
table: import("../Type.js").Type<"String", string, string, import("../Type.js").StringError, string, import("../Type.js").StringError>;
|
|
179
179
|
id: import("../Type.js").BrandType<import("../Type.js").Type<"String", string, string, import("../Type.js").StringError, string, import("../Type.js").StringError>, "Id", import("../Type.js").IdError, import("../Type.js").StringError>;
|
|
180
|
-
values: import("../Type.js").BrandType<import("../Type.js").RecordType<"String", string, string, import("../Type.js").StringError, string, import("../Type.js").StringError, import("../Type.js").UnionType<[import("../Type.js").Type<"Null", null, null, import("../Type.js").NullError, null, import("../Type.js").NullError>, import("../Type.js").Type<"String", string, string, import("../Type.js").StringError, string, import("../Type.js").StringError>, import("../Type.js").Type<"Number", number, number, import("../Type.js").NumberError, number, import("../Type.js").NumberError>, import("../Type.js").Type<"Uint8Array", Uint8Array<ArrayBufferLike>, Uint8Array<ArrayBufferLike>, import("../Type.js").Uint8ArrayError, Uint8Array<ArrayBufferLike>, import("../Type.js").Uint8ArrayError>]>>, "ValidDbChangeValues", ValidDbChangeValuesError, import("../Type.js").RecordError<import("../Type.js").StringError, never> | import("../Type.js").RecordError<import("../Type.js").StringError, import("../Type.js").UnionError<import("../Type.js").
|
|
180
|
+
values: import("../Type.js").BrandType<import("../Type.js").RecordType<"String", string, string, import("../Type.js").StringError, string, import("../Type.js").StringError, import("../Type.js").UnionType<[import("../Type.js").Type<"Null", null, null, import("../Type.js").NullError, null, import("../Type.js").NullError>, import("../Type.js").Type<"String", string, string, import("../Type.js").StringError, string, import("../Type.js").StringError>, import("../Type.js").Type<"Number", number, number, import("../Type.js").NumberError, number, import("../Type.js").NumberError>, import("../Type.js").Type<"Uint8Array", Uint8Array<ArrayBufferLike>, Uint8Array<ArrayBufferLike>, import("../Type.js").Uint8ArrayError, Uint8Array<ArrayBufferLike>, import("../Type.js").Uint8ArrayError>]>>, "ValidDbChangeValues", ValidDbChangeValuesError, import("../Type.js").RecordError<import("../Type.js").StringError, never> | import("../Type.js").RecordError<import("../Type.js").StringError, import("../Type.js").UnionError<import("../Type.js").StringError | import("../Type.js").NumberError | import("../Type.js").Uint8ArrayError | import("../Type.js").NullError>>>;
|
|
181
181
|
isInsert: import("../Type.js").Type<"Boolean", boolean, boolean, import("../Type.js").BooleanError, boolean, import("../Type.js").BooleanError>;
|
|
182
182
|
isDelete: import("../Type.js").UnionType<[import("../Type.js").Type<"Null", null, null, import("../Type.js").NullError, null, import("../Type.js").NullError>, import("../Type.js").Type<"Boolean", boolean, boolean, import("../Type.js").BooleanError, boolean, import("../Type.js").BooleanError>]>;
|
|
183
183
|
}>;
|