@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.
@@ -1 +1 @@
1
- {"version":3,"file":"Public.d.ts","sourceRoot":"","sources":["../../src/Public.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACtE,YAAY,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC3D,YAAY,EAAE,oBAAoB,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAC1C,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACvD,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACnE,cAAc,YAAY,CAAC;AAC3B,YAAY,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,YAAY,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC"}
1
+ {"version":3,"file":"Public.d.ts","sourceRoot":"","sources":["../../src/Public.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,QAAQ,CAAC;AAC7B,YAAY,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACtE,YAAY,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC3D,YAAY,EAAE,oBAAoB,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAC1C,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACvD,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,cAAc,YAAY,CAAC;AAC3B,YAAY,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,YAAY,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC"}
@@ -1,4 +1,6 @@
1
+ export { sql } from "kysely";
1
2
  export { jsonArrayFrom, jsonObjectFrom } from "kysely/helpers/sqlite";
2
3
  export { database, table } from "./Db.js";
4
+ export { createIndex } from "./Evolu.js";
3
5
  export * from "./Model.js";
4
6
  export { canUseDom } from "./Platform.js";
package/dist/src/Sql.d.ts CHANGED
@@ -1,13 +1,12 @@
1
- export declare const selectOwner: string;
2
- export declare const createMessageTable: string;
3
- export declare const createMessageTableIndex: string;
4
- export declare const createOwnerTable: string;
5
- export declare const insertOwner: string;
6
- export declare const selectOwnerTimestampAndMerkleTree: string;
7
- export declare const selectLastTimestampForTableRowColumn: string;
8
- export declare const upsertValueIntoTableRowColumn: (table: string, column: string) => string;
9
- export declare const deleteTableRow: (table: string) => string;
10
- export declare const insertIntoMessagesIfNew: string;
11
- export declare const updateOwnerTimestampAndMerkleTree: string;
12
- export declare const selectMessagesToSync: string;
1
+ import { SqliteQuery } from "./Sqlite.js";
2
+ export declare const selectOwner: SqliteQuery;
3
+ export declare const createMessageTable: SqliteQuery;
4
+ export declare const createMessageTableIndex: SqliteQuery;
5
+ export declare const createOwnerTable: SqliteQuery;
6
+ export declare const insertOwner: SqliteQuery;
7
+ export declare const selectOwnerTimestampAndMerkleTree: SqliteQuery;
8
+ export declare const selectLastTimestampForTableRowColumn: SqliteQuery;
9
+ export declare const insertIntoMessagesIfNew: SqliteQuery;
10
+ export declare const updateOwnerTimestampAndMerkleTree: SqliteQuery;
11
+ export declare const selectMessagesToSync: SqliteQuery;
13
12
  //# sourceMappingURL=Sql.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Sql.d.ts","sourceRoot":"","sources":["../../src/Sql.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,WAAW,QAOhB,CAAC;AAET,eAAO,MAAM,kBAAkB,QASvB,CAAC;AAET,eAAO,MAAM,uBAAuB,QAI5B,CAAC;AAET,eAAO,MAAM,gBAAgB,QASrB,CAAC;AAET,eAAO,MAAM,WAAW,QAWhB,CAAC;AAET,eAAO,MAAM,iCAAiC,QAMtC,CAAC;AAET,eAAO,MAAM,oCAAoC,QAazC,CAAC;AAET,eAAO,MAAM,6BAA6B,UACjC,MAAM,UACL,MAAM,KACb,MASK,CAAC;AAET,eAAO,MAAM,cAAc,UAAW,MAAM,KAAG,MAKvC,CAAC;AAET,eAAO,MAAM,uBAAuB,QAM5B,CAAC;AAET,eAAO,MAAM,iCAAiC,QAKtC,CAAC;AAET,eAAO,MAAM,oBAAoB,QASzB,CAAC"}
1
+ {"version":3,"file":"Sql.d.ts","sourceRoot":"","sources":["../../src/Sql.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,eAAO,MAAM,WAAW,EAAE,WAEzB,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,WAEhC,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,WAErC,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,WAE9B,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,WAEzB,CAAC;AAEF,eAAO,MAAM,iCAAiC,EAAE,WAE/C,CAAC;AAEF,eAAO,MAAM,oCAAoC,EAAE,WAElD,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,WAErC,CAAC;AAEF,eAAO,MAAM,iCAAiC,EAAE,WAE/C,CAAC;AAEF,eAAO,MAAM,oBAAoB,EAAE,WAElC,CAAC"}
package/dist/src/Sql.js CHANGED
@@ -1,106 +1,30 @@
1
- // TODO: This file should be generated from a script via Kysely.
2
- // The reason for not using Kysely directly is bundle size.
3
- // [Playground Link](https://kyse.link/?p=b&i=haFkpnNxbGl0ZaF2pjAuMjYuMKFz2gFoaW1wb3J0IHsgR2VuZXJhdGVkIH0gZnJvbSAna3lzZWx5JwoKZGVjbGFyZSBnbG9iYWwgewogIGludGVyZmFjZSBEQiB7CiAgICBldm9sdV9tZXNzYWdlOiB7CiAgICAgIHRpbWVzdGFtcDogc3RyaW5nLAogICAgICB0YWJsZTogc3RyaW5nLAogICAgICByb3c6IHN0cmluZywKICAgICAgY29sdW1uOiBzdHJpbmcsCiAgICAgIHZhbHVlOiB1bmtub3duCiAgICB9LAoKICAgIGV2b2x1X293bmVyOiB7CiAgICAgIGlkOiBzdHJpbmcKICAgICAgbW5lbW9uaWM6IHN0cmluZwogICAgICBlbmNyeXB0aW9uS2V5OiBVaW50OEFycmF5LAogICAgICB0aW1lc3RhbXA6IHN0cmluZywKICAgICAgbWVya2xlVHJlZTogc3RyaW5nCiAgICB9CiAgfQp9oXHaBnhhd2FpdCBreXNlbHkuc2VsZWN0RnJvbSgiZXZvbHVfb3duZXIiKQogIC5zZWxlY3QoWyJpZCIsICJtbmVtb25pYyIsICJlbmNyeXB0aW9uS2V5Il0pCiAgLmV4ZWN1dGUoKQoKYXdhaXQga3lzZWx5LnNjaGVtYQogIC5jcmVhdGVUYWJsZSgnZXZvbHVfbWVzc2FnZScpCiAgLmFkZENvbHVtbigndGltZXN0YW1wJywgJ2Jsb2InLCBjb2wgPT4gY29sLnByaW1hcnlLZXkoKSkKICAuYWRkQ29sdW1uKCd0YWJsZScsICdibG9iJykKICAuYWRkQ29sdW1uKCdyb3cnLCAnYmxvYicpCiAgLmFkZENvbHVtbignY29sdW1uJywgJ2Jsb2InKQogIC5hZGRDb2x1bW4oJ3ZhbHVlJywgJ2Jsb2InKQogIC5leGVjdXRlKCkKCmF3YWl0IGt5c2VseS5zY2hlbWEKICAuY3JlYXRlSW5kZXgoImluZGV4X2V2b2x1X21lc3NhZ2UiKQogIC5vbigiZXZvbHVfbWVzc2FnZSIpCiAgLmNvbHVtbnMoWyJ0YWJsZSIsICJyb3ciLCAiY29sdW1uIiwgInRpbWVzdGFtcCJdKQogIC5leGVjdXRlKCkKCmF3YWl0IGt5c2VseS5zY2hlbWEKICAuY3JlYXRlVGFibGUoJ2V2b2x1X19vd25lcicpCiAgLmFkZENvbHVtbignaWQnLCAnYmxvYicpCiAgLmFkZENvbHVtbignbW5lbW9uaWMnLCAnYmxvYicpCiAgLmFkZENvbHVtbignZW5jcnlwdGlvbktleScsICdibG9iJykKICAuYWRkQ29sdW1uKCd0aW1lc3RhbXAnLCAnYmxvYicpCiAgLmFkZENvbHVtbignbWVya2xlVHJlZScsICdibG9iJykKICAuZXhlY3V0ZSgpCgphd2FpdCBreXNlbHkuaW5zZXJ0SW50bygiZXZvbHVfb3duZXIiKQogIC52YWx1ZXMoewogICAgImlkIjogImIiLAogICAgIm1uZW1vbmljIjogImEiLAogICAgImVuY3J5cHRpb25LZXkiOiBuZXcgVWludDhBcnJheSgpLAogICAgInRpbWVzdGFtcCI6ICJhIiwKICAgICJtZXJrbGVUcmVlIjogImIiCiAgfSkKICAuZXhlY3V0ZSgpCgphd2FpdCBreXNlbHkuc2VsZWN0RnJvbSgiZXZvbHVfb3duZXIiKQogIC5zZWxlY3QoWyJ0aW1lc3RhbXAiLCAibWVya2xlVHJlZSJdKQogIC5leGVjdXRlKCkKCmF3YWl0IGt5c2VseS5zZWxlY3RGcm9tKCJldm9sdV9tZXNzYWdlIikKICAuc2VsZWN0KCJ0aW1lc3RhbXAiKQogIC53aGVyZSgndGFibGUnLCAnPScsICcxJykKICAud2hlcmUoJ3JvdycsICc9JywgJzInKQogIC53aGVyZSgnY29sdW1uJywgJz0nLCAnMycpCiAgLm9yZGVyQnkoInRpbWVzdGFtcCIsICJkZXNjIikKICAubGltaXQoMSkKICAuZXhlY3V0ZVRha2VGaXJzdCgpCgphd2FpdCBreXNlbHkuaW5zZXJ0SW50bygiZXZvbHVfbWVzc2FnZSIpCiAgLnZhbHVlcyh7CiAgICAidGltZXN0YW1wIjogJzEnLAogICAgInRhYmxlIjogJzInLAogICAgInJvdyI6ICczJywKICAgICJjb2x1bW4iOiAnNCcsCiAgICAidmFsdWUiOiAnNScsCiAgfSkKICAub25Db25mbGljdChvYyA9PiBvYy5kb05vdGhpbmcoKSkKICAuZXhlY3V0ZSgpCgphd2FpdCBreXNlbHkudXBkYXRlVGFibGUoImV2b2x1X293bmVyIikKICAuc2V0KHsKICAgICJtZXJrbGVUcmVlIjogJzEnLAogICAgInRpbWVzdGFtcCI6ICIyIgogIH0pCiAgLmV4ZWN1dGUoKQoKYXdhaXQga3lzZWx5LnNlbGVjdEZyb20oImV2b2x1X21lc3NhZ2UiKQogIC5zZWxlY3RBbGwoKQogIC53aGVyZSgidGltZXN0YW1wIiwgIj49IiwgJzEnKQogIC5vcmRlckJ5KCJ0aW1lc3RhbXAiKQogIC5leGVjdXRlKCmhY8M=)
4
- export const selectOwner = `
5
- select
6
- "id",
7
- "mnemonic",
8
- "encryptionKey"
9
- from
10
- "evolu_owner"
11
- `.trim();
12
- export const createMessageTable = `
13
- create table
14
- "evolu_message" (
15
- "timestamp" blob primary key,
16
- "table" blob,
17
- "row" blob,
18
- "column" blob,
19
- "value" blob
20
- );
21
- `.trim();
22
- export const createMessageTableIndex = `
23
- create index "index_evolu_message" on "evolu_message" (
24
- "table", "row", "column", "timestamp"
25
- );
26
- `.trim();
27
- export const createOwnerTable = `
28
- create table
29
- "evolu_owner" (
30
- "id" blob,
31
- "mnemonic" blob,
32
- "encryptionKey" blob,
33
- "timestamp" blob,
34
- "merkleTree" blob
35
- );
36
- `.trim();
37
- export const insertOwner = `
38
- insert into
39
- "evolu_owner" (
40
- "id",
41
- "mnemonic",
42
- "encryptionKey",
43
- "timestamp",
44
- "merkleTree"
45
- )
46
- values
47
- (?, ?, ?, ?, ?);
48
- `.trim();
49
- export const selectOwnerTimestampAndMerkleTree = `
50
- select
51
- "timestamp",
52
- "merkleTree"
53
- from
54
- "evolu_owner"
55
- `.trim();
56
- export const selectLastTimestampForTableRowColumn = `
57
- select
58
- "timestamp"
59
- from
60
- "evolu_message"
61
- where
62
- "table" = ?
63
- and "row" = ?
64
- and "column" = ?
65
- order by
66
- "timestamp" desc
67
- limit
68
- 1
69
- `.trim();
70
- export const upsertValueIntoTableRowColumn = (table, column) => `
71
- insert into
72
- "${table}" ("id", "${column}", "createdAt", "updatedAt")
73
- values
74
- (?, ?, ?, ?)
75
- on conflict do update set
76
- "${column}" = ?,
77
- "updatedAt" = ?
78
- `.trim();
79
- export const deleteTableRow = (table) => `
80
- delete from "${table}"
81
- where
82
- "id" = ?;
83
- `.trim();
84
- export const insertIntoMessagesIfNew = `
85
- insert into
86
- "evolu_message" ("timestamp", "table", "row", "column", "value")
87
- values
88
- (?, ?, ?, ?, ?)
89
- on conflict do nothing
90
- `.trim();
91
- export const updateOwnerTimestampAndMerkleTree = `
92
- update "evolu_owner"
93
- set
94
- "timestamp" = ?,
95
- "merkleTree" = ?
96
- `.trim();
97
- export const selectMessagesToSync = `
98
- select
99
- *
100
- from
101
- "evolu_message"
102
- where
103
- "timestamp" >= ?
104
- order by
105
- "timestamp"
106
- `.trim();
1
+ export const selectOwner = {
2
+ sql: `select "id", "mnemonic", "encryptionKey" from "evolu_owner"`,
3
+ };
4
+ export const createMessageTable = {
5
+ sql: `create table "evolu_message" ("timestamp" blob primary key, "table" blob, "row" blob, "column" blob, "value" blob)`,
6
+ };
7
+ export const createMessageTableIndex = {
8
+ sql: `create index "index_evolu_message" on "evolu_message" ("table", "row", "column", "timestamp" desc)`,
9
+ };
10
+ export const createOwnerTable = {
11
+ sql: `create table "evolu_owner" ("id" blob, "mnemonic" blob, "encryptionKey" blob, "timestamp" blob, "merkleTree" blob)`,
12
+ };
13
+ export const insertOwner = {
14
+ sql: `insert into "evolu_owner" ("id", "mnemonic", "encryptionKey", "timestamp", "merkleTree") values (?, ?, ?, ?, ?)`,
15
+ };
16
+ export const selectOwnerTimestampAndMerkleTree = {
17
+ sql: `select "timestamp", "merkleTree" from "evolu_owner"`,
18
+ };
19
+ export const selectLastTimestampForTableRowColumn = {
20
+ sql: `select "timestamp" from "evolu_message" where "table" = ? and "row" = ? and "column" = ? order by "timestamp" desc limit ?`,
21
+ };
22
+ export const insertIntoMessagesIfNew = {
23
+ sql: `insert into "evolu_message" ("timestamp", "table", "row", "column", "value") values (?, ?, ?, ?, ?) on conflict do nothing`,
24
+ };
25
+ export const updateOwnerTimestampAndMerkleTree = {
26
+ sql: `update "evolu_owner" set "merkleTree" = ?, "timestamp" = ?`,
27
+ };
28
+ export const selectMessagesToSync = {
29
+ sql: `select * from "evolu_message" where "timestamp" >= ? order by "timestamp"`,
30
+ };
@@ -1,13 +1,20 @@
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
  export interface Sqlite {
5
- readonly exec: (arg: string | SqliteQuery) => Effect.Effect<SqliteExecResult>;
6
+ readonly exec: (query: SqliteQuery) => Effect.Effect<SqliteExecResult>;
6
7
  }
7
8
  export declare const Sqlite: Context.Tag<Sqlite, Sqlite>;
8
9
  export interface SqliteQuery {
9
10
  readonly sql: string;
10
- readonly parameters: Value[];
11
+ readonly parameters?: Value[];
12
+ readonly options?: SqliteQueryOptions;
13
+ }
14
+ export interface SqliteQueryOptions {
15
+ readonly logQueryExecutionTime?: boolean;
16
+ /** https://www.sqlite.org/eqp.html */
17
+ readonly logExplainQueryPlan?: boolean;
11
18
  }
12
19
  export type Value = SqliteValue | JsonObjectOrArray;
13
20
  export type SqliteValue = null | string | number | Uint8Array;
@@ -25,9 +32,28 @@ export interface SqliteExecResult {
25
32
  export type SqliteRow = Record<string, SqliteValue>;
26
33
  export declare const isJsonObjectOrArray: Predicate.Refinement<Value, JsonObjectOrArray>;
27
34
  export declare const valuesToSqliteValues: (values: ReadonlyArray<Value>) => SqliteValue[];
28
- export declare const ensureSqliteQuery: (arg: string | SqliteQuery) => SqliteQuery;
29
35
  export declare const maybeParseJson: (rows: SqliteRow[]) => SqliteRow[];
30
36
  export declare const maybeJson: Predicate.Predicate<string>;
31
37
  export declare const isSqlMutation: (sql: string) => boolean;
38
+ export declare const maybeLogSqliteQueryExecutionTime: (query: SqliteQuery) => <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>;
39
+ export type SqliteQueryPlanRow = {
40
+ id: number;
41
+ parent: number;
42
+ detail: string;
43
+ };
44
+ export declare const drawSqliteQueryPlan: (rows: SqliteQueryPlanRow[]) => string;
45
+ export interface SqliteSchema {
46
+ readonly tables: ReadonlyArray<Table>;
47
+ readonly indexes: ReadonlyArray<Index>;
48
+ }
49
+ export interface Table {
50
+ readonly name: string;
51
+ readonly columns: ReadonlyArray<string>;
52
+ }
53
+ export interface Index {
54
+ readonly name: string;
55
+ readonly sql: string;
56
+ }
57
+ export declare const indexEquivalence: Equivalence<Index>;
32
58
  export {};
33
59
  //# sourceMappingURL=Sqlite.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Sqlite.d.ts","sourceRoot":"","sources":["../../src/Sqlite.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAC;AAC1C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,SAAS,MAAM,kBAAkB,CAAC;AAE9C,MAAM,WAAW,MAAM;IACrB,QAAQ,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,KAAK,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC;CAC/E;AAED,eAAO,MAAM,MAAM,6BAAiD,CAAC;AAErE,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,UAAU,EAAE,KAAK,EAAE,CAAC;CAC9B;AAED,MAAM,MAAM,KAAK,GAAG,WAAW,GAAG,iBAAiB,CAAC;AACpD,MAAM,MAAM,WAAW,GAAG,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,UAAU,CAAC;AAC9D,MAAM,MAAM,iBAAiB,GAAG,UAAU,GAAG,SAAS,CAAC;AACvD,KAAK,UAAU,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC;AAC1C,KAAK,SAAS,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;AACrC,KAAK,aAAa,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;AACtD,KAAK,IAAI,GAAG,aAAa,GAAG,UAAU,GAAG,SAAS,CAAC;AAEnD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,SAAS,EAAE,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;AAEpD,eAAO,MAAM,mBAAmB,EAAE,SAAS,CAAC,UAAU,CACpD,KAAK,EACL,iBAAiB,CAE4D,CAAC;AAEhF,eAAO,MAAM,oBAAoB,WACvB,cAAc,KAAK,CAAC,KAC3B,WAAW,EAGX,CAAC;AAEJ,eAAO,MAAM,iBAAiB,QAAS,MAAM,GAAG,WAAW,KAAG,WAG7D,CAAC;AAEF,eAAO,MAAM,cAAc,SAAU,SAAS,EAAE,KAAG,SAAS,EAC1C,CAAC;AA0BnB,eAAO,MAAM,SAAS,EAAE,SAAS,CAAC,SAAS,CAAC,MAAM,CACpB,CAAC;AAoB/B,eAAO,MAAM,aAAa,QAAS,MAAM,KAAG,OACd,CAAC"}
1
+ {"version":3,"file":"Sqlite.d.ts","sourceRoot":"","sources":["../../src/Sqlite.ts"],"names":[],"mappings":"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"}
@@ -1,13 +1,9 @@
1
1
  import * as Context from "effect/Context";
2
+ import * as Effect from "effect/Effect";
2
3
  import * as Predicate from "effect/Predicate";
3
4
  export const Sqlite = Context.GenericTag("@services/Sqlite");
4
5
  export const isJsonObjectOrArray = (value) => value !== null && typeof value === "object" && !Predicate.isUint8Array(value);
5
6
  export const valuesToSqliteValues = (values) => values.map((value) => isJsonObjectOrArray(value) ? JSON.stringify(value) : value);
6
- export const ensureSqliteQuery = (arg) => {
7
- if (typeof arg !== "string")
8
- return arg;
9
- return { sql: arg, parameters: [] };
10
- };
11
7
  export const maybeParseJson = (rows) => parseArray(rows);
12
8
  const parseArray = (a) => {
13
9
  for (let i = 0; i < a.length; ++i)
@@ -51,3 +47,27 @@ const isSqlMutationRegEx = new RegExp(`\\b(${[
51
47
  "update",
52
48
  ].join("|")})\\b`);
53
49
  export const isSqlMutation = (sql) => isSqlMutationRegEx.test(sql);
50
+ export const maybeLogSqliteQueryExecutionTime = (query) => (effect) => {
51
+ if (!query.options?.logQueryExecutionTime)
52
+ return effect;
53
+ return effect.pipe(Effect.tap(() => Effect.log("QueryExecutionTime")),
54
+ // Not using Effect.log because of formating
55
+ // eslint-disable-next-line no-console
56
+ Effect.tap(() => console.log(query.sql)), Effect.withLogSpan("duration"));
57
+ };
58
+ export const drawSqliteQueryPlan = (rows) => rows
59
+ .map((row) => {
60
+ let parentId = row.parent;
61
+ let indent = 0;
62
+ do {
63
+ const parent = rows.find((r) => r.id === parentId);
64
+ if (!parent)
65
+ break;
66
+ parentId = parent.parent;
67
+ indent++;
68
+ // eslint-disable-next-line no-constant-condition
69
+ } while (true);
70
+ return `${" ".repeat(indent)}${row.detail}`;
71
+ })
72
+ .join("\n");
73
+ export const indexEquivalence = (self, that) => self.name === that.name && self.sql === that.sql;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@evolu/common",
3
- "version": "4.0.5",
3
+ "version": "4.1.0",
4
4
  "description": "Local-first platform designed for privacy, ease of use, and no vendor lock-in to sync and backup people's lifetime data",
5
5
  "keywords": [
6
6
  "evolu",
@@ -52,20 +52,20 @@
52
52
  "nanoid": "^5.0.6"
53
53
  },
54
54
  "devDependencies": {
55
- "@effect/schema": "^0.64.5",
55
+ "@effect/schema": "^0.64.9",
56
56
  "@protobuf-ts/plugin": "^2.9.4",
57
57
  "@protobuf-ts/protoc": "^2.9.4",
58
58
  "array-shuffle": "^3.0.0",
59
- "effect": "2.4.7",
59
+ "effect": "2.4.9",
60
60
  "eslint": "^8.57.0",
61
- "typescript": "^5.4.2",
61
+ "typescript": "^5.4.3",
62
62
  "vitest": "^1.4.0",
63
63
  "@evolu/tsconfig": "0.0.2",
64
64
  "eslint-config-evolu": "1.0.0"
65
65
  },
66
66
  "peerDependencies": {
67
- "@effect/schema": "^0.64.5",
68
- "effect": "2.4.7"
67
+ "@effect/schema": "^0.64.9",
68
+ "effect": "2.4.9"
69
69
  },
70
70
  "publishConfig": {
71
71
  "access": "public"
package/src/Config.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import * as Context from "effect/Context";
2
2
  import * as Layer from "effect/Layer";
3
+ import { CreateIndexBuilder } from "kysely";
3
4
 
4
5
  export interface Config {
5
6
  /** Alternate URL to Evolu sync and backup server. */
@@ -23,6 +24,24 @@ export interface Config {
23
24
  * default value is: "Evolu".
24
25
  */
25
26
  readonly name: string;
27
+
28
+ /**
29
+ * Use the `indexes` property to define SQLite indexes.
30
+ *
31
+ * Table and column names are not typed because Kysely doesn't support it.
32
+ *
33
+ * https://medium.com/@JasonWyatt/squeezing-performance-from-sqlite-indexes-indexes-c4e175f3c346
34
+ *
35
+ * @example
36
+ * const indexes = [
37
+ * createIndex("indexTodoCreatedAt").on("todo").column("createdAt"),
38
+ *
39
+ * createIndex("indexTodoCategoryCreatedAt")
40
+ * .on("todoCategory")
41
+ * .column("createdAt"),
42
+ * ];
43
+ */
44
+ readonly indexes: ReadonlyArray<CreateIndexBuilder<any>>;
26
45
  }
27
46
 
28
47
  export const Config = Context.GenericTag<Config>("@services/Config");
@@ -35,6 +54,7 @@ export const ConfigLive = (config?: Partial<Config>): Layer.Layer<Config> =>
35
54
  maxDrift: 5 * 60 * 1000,
36
55
  reloadUrl: "/",
37
56
  name: "Evolu",
57
+ indexes: [],
38
58
  ...config,
39
59
  }),
40
60
  );