@evolu/common 4.0.5 → 4.1.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/README.md +6 -0
- package/dist/src/Config.d.ts +18 -0
- package/dist/src/Config.d.ts.map +1 -1
- package/dist/src/Config.js +1 -0
- package/dist/src/Db.d.ts +5 -9
- package/dist/src/Db.d.ts.map +1 -1
- package/dist/src/Db.js +108 -31
- package/dist/src/DbWorker.d.ts +3 -4
- package/dist/src/DbWorker.d.ts.map +1 -1
- package/dist/src/DbWorker.js +42 -22
- package/dist/src/Evolu.d.ts +4 -2
- package/dist/src/Evolu.d.ts.map +1 -1
- package/dist/src/Evolu.js +18 -6
- package/dist/src/Public.d.ts +2 -0
- package/dist/src/Public.d.ts.map +1 -1
- package/dist/src/Public.js +2 -0
- package/dist/src/Sql.d.ts +11 -12
- package/dist/src/Sql.d.ts.map +1 -1
- package/dist/src/Sql.js +30 -106
- package/dist/src/Sqlite.d.ts +29 -3
- package/dist/src/Sqlite.d.ts.map +1 -1
- package/dist/src/Sqlite.js +25 -5
- package/package.json +6 -6
- package/src/Config.ts +20 -0
- package/src/Db.ts +154 -78
- package/src/DbWorker.ts +57 -38
- package/src/Evolu.ts +36 -9
- package/src/Public.ts +2 -0
- package/src/Sql.ts +41 -123
- package/src/Sqlite.ts +65 -7
package/src/Sql.ts
CHANGED
|
@@ -1,123 +1,41 @@
|
|
|
1
|
-
//
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
"
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
"
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
export const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
export const insertOwner = `
|
|
43
|
-
insert into
|
|
44
|
-
"evolu_owner" (
|
|
45
|
-
"id",
|
|
46
|
-
"mnemonic",
|
|
47
|
-
"encryptionKey",
|
|
48
|
-
"timestamp",
|
|
49
|
-
"merkleTree"
|
|
50
|
-
)
|
|
51
|
-
values
|
|
52
|
-
(?, ?, ?, ?, ?);
|
|
53
|
-
`.trim();
|
|
54
|
-
|
|
55
|
-
export const selectOwnerTimestampAndMerkleTree = `
|
|
56
|
-
select
|
|
57
|
-
"timestamp",
|
|
58
|
-
"merkleTree"
|
|
59
|
-
from
|
|
60
|
-
"evolu_owner"
|
|
61
|
-
`.trim();
|
|
62
|
-
|
|
63
|
-
export const selectLastTimestampForTableRowColumn = `
|
|
64
|
-
select
|
|
65
|
-
"timestamp"
|
|
66
|
-
from
|
|
67
|
-
"evolu_message"
|
|
68
|
-
where
|
|
69
|
-
"table" = ?
|
|
70
|
-
and "row" = ?
|
|
71
|
-
and "column" = ?
|
|
72
|
-
order by
|
|
73
|
-
"timestamp" desc
|
|
74
|
-
limit
|
|
75
|
-
1
|
|
76
|
-
`.trim();
|
|
77
|
-
|
|
78
|
-
export const upsertValueIntoTableRowColumn = (
|
|
79
|
-
table: string,
|
|
80
|
-
column: string,
|
|
81
|
-
): string =>
|
|
82
|
-
`
|
|
83
|
-
insert into
|
|
84
|
-
"${table}" ("id", "${column}", "createdAt", "updatedAt")
|
|
85
|
-
values
|
|
86
|
-
(?, ?, ?, ?)
|
|
87
|
-
on conflict do update set
|
|
88
|
-
"${column}" = ?,
|
|
89
|
-
"updatedAt" = ?
|
|
90
|
-
`.trim();
|
|
91
|
-
|
|
92
|
-
export const deleteTableRow = (table: string): string =>
|
|
93
|
-
`
|
|
94
|
-
delete from "${table}"
|
|
95
|
-
where
|
|
96
|
-
"id" = ?;
|
|
97
|
-
`.trim();
|
|
98
|
-
|
|
99
|
-
export const insertIntoMessagesIfNew = `
|
|
100
|
-
insert into
|
|
101
|
-
"evolu_message" ("timestamp", "table", "row", "column", "value")
|
|
102
|
-
values
|
|
103
|
-
(?, ?, ?, ?, ?)
|
|
104
|
-
on conflict do nothing
|
|
105
|
-
`.trim();
|
|
106
|
-
|
|
107
|
-
export const updateOwnerTimestampAndMerkleTree = `
|
|
108
|
-
update "evolu_owner"
|
|
109
|
-
set
|
|
110
|
-
"timestamp" = ?,
|
|
111
|
-
"merkleTree" = ?
|
|
112
|
-
`.trim();
|
|
113
|
-
|
|
114
|
-
export const selectMessagesToSync = `
|
|
115
|
-
select
|
|
116
|
-
*
|
|
117
|
-
from
|
|
118
|
-
"evolu_message"
|
|
119
|
-
where
|
|
120
|
-
"timestamp" >= ?
|
|
121
|
-
order by
|
|
122
|
-
"timestamp"
|
|
123
|
-
`.trim();
|
|
1
|
+
// this file is generated by generateSql script
|
|
2
|
+
import { SqliteQuery } from "./Sqlite.js";
|
|
3
|
+
export const selectOwner: SqliteQuery = {
|
|
4
|
+
sql: `select "id", "mnemonic", "encryptionKey" from "evolu_owner"`,
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export const createMessageTable: SqliteQuery = {
|
|
8
|
+
sql: `create table "evolu_message" ("timestamp" blob primary key, "table" blob, "row" blob, "column" blob, "value" blob)`,
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const createMessageTableIndex: SqliteQuery = {
|
|
12
|
+
sql: `create index "index_evolu_message" on "evolu_message" ("table", "row", "column", "timestamp" desc)`,
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export const createOwnerTable: SqliteQuery = {
|
|
16
|
+
sql: `create table "evolu_owner" ("id" blob, "mnemonic" blob, "encryptionKey" blob, "timestamp" blob, "merkleTree" blob)`,
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const insertOwner: SqliteQuery = {
|
|
20
|
+
sql: `insert into "evolu_owner" ("id", "mnemonic", "encryptionKey", "timestamp", "merkleTree") values (?, ?, ?, ?, ?)`,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const selectOwnerTimestampAndMerkleTree: SqliteQuery = {
|
|
24
|
+
sql: `select "timestamp", "merkleTree" from "evolu_owner"`,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const selectLastTimestampForTableRowColumn: SqliteQuery = {
|
|
28
|
+
sql: `select "timestamp" from "evolu_message" where "table" = ? and "row" = ? and "column" = ? order by "timestamp" desc limit ?`,
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export const insertIntoMessagesIfNew: SqliteQuery = {
|
|
32
|
+
sql: `insert into "evolu_message" ("timestamp", "table", "row", "column", "value") values (?, ?, ?, ?, ?) on conflict do nothing`,
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export const updateOwnerTimestampAndMerkleTree: SqliteQuery = {
|
|
36
|
+
sql: `update "evolu_owner" set "merkleTree" = ?, "timestamp" = ?`,
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export const selectMessagesToSync: SqliteQuery = {
|
|
40
|
+
sql: `select * from "evolu_message" where "timestamp" >= ? order by "timestamp"`,
|
|
41
|
+
};
|
package/src/Sqlite.ts
CHANGED
|
@@ -1,16 +1,24 @@
|
|
|
1
1
|
import * as Context from "effect/Context";
|
|
2
2
|
import * as Effect from "effect/Effect";
|
|
3
|
+
import { Equivalence } from "effect/Equivalence";
|
|
3
4
|
import * as Predicate from "effect/Predicate";
|
|
4
5
|
|
|
5
6
|
export interface Sqlite {
|
|
6
|
-
readonly exec: (
|
|
7
|
+
readonly exec: (query: SqliteQuery) => Effect.Effect<SqliteExecResult>;
|
|
7
8
|
}
|
|
8
9
|
|
|
9
10
|
export const Sqlite = Context.GenericTag<Sqlite>("@services/Sqlite");
|
|
10
11
|
|
|
11
12
|
export interface SqliteQuery {
|
|
12
13
|
readonly sql: string;
|
|
13
|
-
readonly parameters
|
|
14
|
+
readonly parameters?: Value[];
|
|
15
|
+
readonly options?: SqliteQueryOptions;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface SqliteQueryOptions {
|
|
19
|
+
readonly logQueryExecutionTime?: boolean;
|
|
20
|
+
/** https://www.sqlite.org/eqp.html */
|
|
21
|
+
readonly logExplainQueryPlan?: boolean;
|
|
14
22
|
}
|
|
15
23
|
|
|
16
24
|
export type Value = SqliteValue | JsonObjectOrArray;
|
|
@@ -41,11 +49,6 @@ export const valuesToSqliteValues = (
|
|
|
41
49
|
isJsonObjectOrArray(value) ? JSON.stringify(value) : value,
|
|
42
50
|
);
|
|
43
51
|
|
|
44
|
-
export const ensureSqliteQuery = (arg: string | SqliteQuery): SqliteQuery => {
|
|
45
|
-
if (typeof arg !== "string") return arg;
|
|
46
|
-
return { sql: arg, parameters: [] };
|
|
47
|
-
};
|
|
48
|
-
|
|
49
52
|
export const maybeParseJson = (rows: SqliteRow[]): SqliteRow[] =>
|
|
50
53
|
parseArray(rows);
|
|
51
54
|
|
|
@@ -96,3 +99,58 @@ const isSqlMutationRegEx = new RegExp(
|
|
|
96
99
|
|
|
97
100
|
export const isSqlMutation = (sql: string): boolean =>
|
|
98
101
|
isSqlMutationRegEx.test(sql);
|
|
102
|
+
|
|
103
|
+
export const maybeLogSqliteQueryExecutionTime =
|
|
104
|
+
(query: SqliteQuery) =>
|
|
105
|
+
<A, E, R>(effect: Effect.Effect<A, E, R>): Effect.Effect<A, E, R> => {
|
|
106
|
+
if (!query.options?.logQueryExecutionTime) return effect;
|
|
107
|
+
return effect.pipe(
|
|
108
|
+
Effect.tap(() => Effect.log("QueryExecutionTime")),
|
|
109
|
+
// Not using Effect.log because of formating
|
|
110
|
+
// eslint-disable-next-line no-console
|
|
111
|
+
Effect.tap(() => console.log(query.sql)),
|
|
112
|
+
Effect.withLogSpan("duration"),
|
|
113
|
+
);
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
export type SqliteQueryPlanRow = {
|
|
117
|
+
id: number;
|
|
118
|
+
parent: number;
|
|
119
|
+
detail: string;
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
export const drawSqliteQueryPlan = (rows: SqliteQueryPlanRow[]): string =>
|
|
123
|
+
rows
|
|
124
|
+
.map((row) => {
|
|
125
|
+
let parentId = row.parent;
|
|
126
|
+
let indent = 0;
|
|
127
|
+
|
|
128
|
+
do {
|
|
129
|
+
const parent = rows.find((r) => r.id === parentId);
|
|
130
|
+
if (!parent) break;
|
|
131
|
+
parentId = parent.parent;
|
|
132
|
+
indent++;
|
|
133
|
+
// eslint-disable-next-line no-constant-condition
|
|
134
|
+
} while (true);
|
|
135
|
+
|
|
136
|
+
return `${" ".repeat(indent)}${row.detail}`;
|
|
137
|
+
})
|
|
138
|
+
.join("\n");
|
|
139
|
+
|
|
140
|
+
export interface SqliteSchema {
|
|
141
|
+
readonly tables: ReadonlyArray<Table>;
|
|
142
|
+
readonly indexes: ReadonlyArray<Index>;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export interface Table {
|
|
146
|
+
readonly name: string;
|
|
147
|
+
readonly columns: ReadonlyArray<string>;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export interface Index {
|
|
151
|
+
readonly name: string;
|
|
152
|
+
readonly sql: string;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export const indexEquivalence: Equivalence<Index> = (self, that) =>
|
|
156
|
+
self.name === that.name && self.sql === that.sql;
|