@evolu/common 5.4.7 → 6.0.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.
Files changed (242) hide show
  1. package/README.md +30 -34
  2. package/dist/src/Array.d.ts +17 -0
  3. package/dist/src/Array.d.ts.map +1 -0
  4. package/dist/src/Array.js +12 -0
  5. package/dist/src/Assert.d.ts +68 -0
  6. package/dist/src/Assert.d.ts.map +1 -0
  7. package/dist/src/Assert.js +77 -0
  8. package/dist/src/BigInt.d.ts +20 -0
  9. package/dist/src/BigInt.d.ts.map +1 -0
  10. package/dist/src/BigInt.js +18 -0
  11. package/dist/src/Buffer.d.ts +92 -0
  12. package/dist/src/Buffer.d.ts.map +1 -0
  13. package/dist/src/Buffer.js +62 -0
  14. package/dist/src/Callbacks.d.ts +20 -0
  15. package/dist/src/Callbacks.d.ts.map +1 -0
  16. package/dist/src/Callbacks.js +18 -0
  17. package/dist/src/Console.d.ts +78 -0
  18. package/dist/src/Console.d.ts.map +1 -0
  19. package/dist/src/Console.js +103 -0
  20. package/dist/src/Crypto.d.ts +72 -39
  21. package/dist/src/Crypto.d.ts.map +1 -1
  22. package/dist/src/Crypto.js +89 -54
  23. package/dist/src/Eq.d.ts +97 -0
  24. package/dist/src/Eq.d.ts.map +1 -0
  25. package/dist/src/Eq.js +167 -0
  26. package/dist/src/Error.d.ts +14 -10
  27. package/dist/src/Error.d.ts.map +1 -1
  28. package/dist/src/Error.js +43 -11
  29. package/dist/src/Evolu/Config.d.ts +69 -0
  30. package/dist/src/Evolu/Config.d.ts.map +1 -0
  31. package/dist/src/Evolu/Config.js +9 -0
  32. package/dist/src/Evolu/Db.d.ts +126 -0
  33. package/dist/src/Evolu/Db.d.ts.map +1 -0
  34. package/dist/src/Evolu/Db.js +774 -0
  35. package/dist/src/Evolu/Diff.d.ts +43 -0
  36. package/dist/src/Evolu/Diff.d.ts.map +1 -0
  37. package/dist/src/Evolu/Diff.js +95 -0
  38. package/dist/src/Evolu/Evolu.d.ts +334 -0
  39. package/dist/src/Evolu/Evolu.d.ts.map +1 -0
  40. package/dist/src/Evolu/Evolu.js +434 -0
  41. package/dist/src/Evolu/Internal.d.ts +26 -0
  42. package/dist/src/Evolu/Internal.d.ts.map +1 -0
  43. package/dist/src/Evolu/Internal.js +25 -0
  44. package/dist/src/Evolu/Kysely.d.ts +6 -0
  45. package/dist/src/Evolu/Kysely.d.ts.map +1 -0
  46. package/dist/src/Evolu/Kysely.js +21 -0
  47. package/dist/src/Evolu/Owner.d.ts +155 -0
  48. package/dist/src/Evolu/Owner.d.ts.map +1 -0
  49. package/dist/src/Evolu/Owner.js +126 -0
  50. package/dist/src/Evolu/Platform.d.ts +23 -0
  51. package/dist/src/Evolu/Platform.d.ts.map +1 -0
  52. package/dist/src/Evolu/Platform.js +1 -0
  53. package/dist/src/Evolu/Protocol.d.ts +401 -0
  54. package/dist/src/Evolu/Protocol.d.ts.map +1 -0
  55. package/dist/src/Evolu/Protocol.js +1151 -0
  56. package/dist/src/Evolu/Public.d.ts +18 -0
  57. package/dist/src/Evolu/Public.d.ts.map +1 -0
  58. package/dist/src/Evolu/Public.js +11 -0
  59. package/dist/src/Evolu/PublicKysely.d.ts +148 -0
  60. package/dist/src/Evolu/PublicKysely.d.ts.map +1 -0
  61. package/dist/src/Evolu/PublicKysely.js +185 -0
  62. package/dist/src/Evolu/Query.d.ts +63 -0
  63. package/dist/src/Evolu/Query.d.ts.map +1 -0
  64. package/dist/src/Evolu/Query.js +61 -0
  65. package/dist/src/Evolu/Relay.d.ts +13 -0
  66. package/dist/src/Evolu/Relay.d.ts.map +1 -0
  67. package/dist/src/Evolu/Relay.js +109 -0
  68. package/dist/src/Evolu/Schema.d.ts +201 -0
  69. package/dist/src/Evolu/Schema.d.ts.map +1 -0
  70. package/dist/src/Evolu/Schema.js +150 -0
  71. package/dist/src/Evolu/Storage.d.ts +49 -0
  72. package/dist/src/Evolu/Storage.d.ts.map +1 -0
  73. package/dist/src/Evolu/Storage.js +1111 -0
  74. package/dist/src/Evolu/Sync.d.ts +59 -0
  75. package/dist/src/Evolu/Sync.d.ts.map +1 -0
  76. package/dist/src/Evolu/Sync.js +29 -0
  77. package/dist/src/Evolu/Timestamp.d.ts +106 -0
  78. package/dist/src/Evolu/Timestamp.d.ts.map +1 -0
  79. package/dist/src/Evolu/Timestamp.js +179 -0
  80. package/dist/src/Function.d.ts +54 -0
  81. package/dist/src/Function.d.ts.map +1 -0
  82. package/dist/src/Function.js +38 -0
  83. package/dist/src/ManyToManyMap.d.ts +26 -0
  84. package/dist/src/ManyToManyMap.d.ts.map +1 -0
  85. package/dist/src/ManyToManyMap.js +92 -0
  86. package/dist/src/NanoId.d.ts +27 -0
  87. package/dist/src/NanoId.d.ts.map +1 -0
  88. package/dist/src/NanoId.js +6 -0
  89. package/dist/src/Number.d.ts +42 -0
  90. package/dist/src/Number.d.ts.map +1 -0
  91. package/dist/src/Number.js +55 -0
  92. package/dist/src/Object.d.ts +35 -0
  93. package/dist/src/Object.d.ts.map +1 -0
  94. package/dist/src/Object.js +36 -0
  95. package/dist/src/Order.d.ts +90 -0
  96. package/dist/src/Order.d.ts.map +1 -0
  97. package/dist/src/Order.js +85 -0
  98. package/dist/src/Promise.d.ts +180 -0
  99. package/dist/src/Promise.d.ts.map +1 -0
  100. package/dist/src/Promise.js +176 -0
  101. package/dist/src/Random.d.ts +52 -0
  102. package/dist/src/Random.d.ts.map +1 -0
  103. package/dist/src/Random.js +29 -0
  104. package/dist/src/Ref.d.ts +40 -0
  105. package/dist/src/Ref.d.ts.map +1 -0
  106. package/dist/src/Ref.js +13 -0
  107. package/dist/src/Result.d.ts +421 -0
  108. package/dist/src/Result.d.ts.map +1 -0
  109. package/dist/src/Result.js +357 -0
  110. package/dist/src/Skiplist.d.ts +23 -0
  111. package/dist/src/Skiplist.d.ts.map +1 -0
  112. package/dist/src/Skiplist.js +58 -0
  113. package/dist/src/Sqlite.d.ts +116 -52
  114. package/dist/src/Sqlite.d.ts.map +1 -1
  115. package/dist/src/Sqlite.js +183 -67
  116. package/dist/src/Store.d.ts +45 -8
  117. package/dist/src/Store.d.ts.map +1 -1
  118. package/dist/src/Store.js +33 -17
  119. package/dist/src/String.d.ts +2 -0
  120. package/dist/src/String.d.ts.map +1 -0
  121. package/dist/src/String.js +14 -0
  122. package/dist/src/Time.d.ts +20 -0
  123. package/dist/src/Time.d.ts.map +1 -0
  124. package/dist/src/Time.js +25 -0
  125. package/dist/src/Type.d.ts +1937 -0
  126. package/dist/src/Type.d.ts.map +1 -0
  127. package/dist/src/Type.js +2002 -0
  128. package/dist/src/Types.d.ts +188 -0
  129. package/dist/src/Types.d.ts.map +1 -0
  130. package/dist/src/Types.js +6 -0
  131. package/dist/src/WebSocket.d.ts +112 -0
  132. package/dist/src/WebSocket.d.ts.map +1 -0
  133. package/dist/src/WebSocket.js +139 -0
  134. package/dist/src/Worker.d.ts +44 -0
  135. package/dist/src/Worker.d.ts.map +1 -0
  136. package/dist/src/Worker.js +66 -0
  137. package/dist/src/index.d.ts +24 -11
  138. package/dist/src/index.d.ts.map +1 -1
  139. package/dist/src/index.js +24 -11
  140. package/package.json +29 -38
  141. package/src/Array.ts +39 -0
  142. package/src/Assert.ts +116 -0
  143. package/src/BigInt.ts +29 -0
  144. package/src/Buffer.ts +175 -0
  145. package/src/Callbacks.ts +43 -0
  146. package/src/Console.ts +159 -0
  147. package/src/Crypto.ts +169 -115
  148. package/src/Eq.ts +204 -0
  149. package/src/Error.ts +57 -20
  150. package/src/Evolu/Config.ts +83 -0
  151. package/src/Evolu/Db.ts +1275 -0
  152. package/src/Evolu/Diff.ts +142 -0
  153. package/src/Evolu/Evolu.ts +947 -0
  154. package/src/Evolu/Internal.ts +26 -0
  155. package/src/Evolu/Kysely.ts +38 -0
  156. package/src/Evolu/Owner.ts +296 -0
  157. package/src/Evolu/Platform.ts +27 -0
  158. package/src/Evolu/Protocol.ts +1857 -0
  159. package/src/Evolu/Public.ts +43 -0
  160. package/src/Evolu/PublicKysely.ts +240 -0
  161. package/src/Evolu/Query.ts +167 -0
  162. package/src/Evolu/Relay.ts +142 -0
  163. package/src/Evolu/Schema.ts +417 -0
  164. package/src/Evolu/Storage.ts +1281 -0
  165. package/src/Evolu/Sync.ts +105 -0
  166. package/src/Evolu/Timestamp.ts +311 -0
  167. package/src/Function.ts +58 -0
  168. package/src/ManyToManyMap.ts +140 -0
  169. package/src/NanoId.ts +39 -0
  170. package/src/Number.ts +90 -0
  171. package/src/Object.ts +64 -0
  172. package/src/Order.ts +113 -0
  173. package/src/Promise.ts +295 -0
  174. package/src/Random.ts +68 -0
  175. package/src/Ref.ts +63 -0
  176. package/src/Result.ts +453 -0
  177. package/src/Skiplist.ts +102 -0
  178. package/src/Sqlite.ts +366 -153
  179. package/src/Store.ts +79 -36
  180. package/src/String.ts +10 -0
  181. package/src/Time.ts +36 -0
  182. package/src/Type.ts +3978 -0
  183. package/src/Types.ts +209 -0
  184. package/src/WebSocket.ts +273 -0
  185. package/src/Worker.ts +129 -0
  186. package/src/index.ts +24 -11
  187. package/dist/src/Config.d.ts +0 -56
  188. package/dist/src/Config.d.ts.map +0 -1
  189. package/dist/src/Config.js +0 -39
  190. package/dist/src/Crdt.d.ts +0 -89
  191. package/dist/src/Crdt.d.ts.map +0 -1
  192. package/dist/src/Crdt.js +0 -181
  193. package/dist/src/Db.d.ts +0 -107
  194. package/dist/src/Db.d.ts.map +0 -1
  195. package/dist/src/Db.js +0 -443
  196. package/dist/src/Diff.d.ts +0 -27
  197. package/dist/src/Diff.d.ts.map +0 -1
  198. package/dist/src/Diff.js +0 -84
  199. package/dist/src/Evolu.d.ts +0 -426
  200. package/dist/src/Evolu.d.ts.map +0 -1
  201. package/dist/src/Evolu.js +0 -333
  202. package/dist/src/Model.d.ts +0 -141
  203. package/dist/src/Model.d.ts.map +0 -1
  204. package/dist/src/Model.js +0 -125
  205. package/dist/src/Murmurhash.d.ts +0 -2
  206. package/dist/src/Murmurhash.d.ts.map +0 -1
  207. package/dist/src/Murmurhash.js +0 -60
  208. package/dist/src/Owner.d.ts +0 -33
  209. package/dist/src/Owner.d.ts.map +0 -1
  210. package/dist/src/Owner.js +0 -26
  211. package/dist/src/Platform.d.ts +0 -37
  212. package/dist/src/Platform.d.ts.map +0 -1
  213. package/dist/src/Platform.js +0 -11
  214. package/dist/src/Protobuf.d.ts +0 -81
  215. package/dist/src/Protobuf.d.ts.map +0 -1
  216. package/dist/src/Protobuf.js +0 -92
  217. package/dist/src/Public.d.ts +0 -13
  218. package/dist/src/Public.d.ts.map +0 -1
  219. package/dist/src/Public.js +0 -6
  220. package/dist/src/Socket.d.ts +0 -8
  221. package/dist/src/Socket.d.ts.map +0 -1
  222. package/dist/src/Socket.js +0 -51
  223. package/dist/src/Sql.d.ts +0 -12
  224. package/dist/src/Sql.d.ts.map +0 -1
  225. package/dist/src/Sql.js +0 -30
  226. package/dist/src/Sync.d.ts +0 -70
  227. package/dist/src/Sync.d.ts.map +0 -1
  228. package/dist/src/Sync.js +0 -127
  229. package/src/Config.ts +0 -119
  230. package/src/Crdt.ts +0 -361
  231. package/src/Db.ts +0 -955
  232. package/src/Diff.ts +0 -114
  233. package/src/Evolu.ts +0 -1016
  234. package/src/Model.ts +0 -233
  235. package/src/Murmurhash.ts +0 -70
  236. package/src/Owner.ts +0 -69
  237. package/src/Platform.ts +0 -47
  238. package/src/Protobuf.ts +0 -155
  239. package/src/Public.ts +0 -12
  240. package/src/Socket.ts +0 -83
  241. package/src/Sql.ts +0 -41
  242. package/src/Sync.ts +0 -315
@@ -1,68 +1,163 @@
1
- import * as Console from "effect/Console";
2
- import * as Context from "effect/Context";
3
- import * as Effect from "effect/Effect";
4
- import * as Exit from "effect/Exit";
5
- import * as Layer from "effect/Layer";
6
- import * as Predicate from "effect/Predicate";
7
- export const Sqlite = Context.GenericTag("Sqlite");
8
- export class SqliteFactory extends Context.Tag("SqliteFactory")() {
9
- }
10
- SqliteFactory.Common = Layer.effect(SqliteFactory, Effect.map(SqliteFactory, (platformSqliteFactory) => ({
11
- createSqlite: Effect.logTrace("SqliteFactory createSqlite").pipe(Effect.zipRight(platformSqliteFactory.createSqlite), Effect.map((platformSqlite) => ({
12
- ...platformSqlite,
13
- exec: (query) => platformSqlite.exec(query).pipe(Effect.tap((result) => {
14
- maybeParseJson(result.rows);
15
- }), Effect.tap((result) => ["begin", "rollback", "commit"].includes(query.sql)
16
- ? Effect.logDebug(`SQLiteCommon ${query.sql} transaction`)
17
- : Effect.logDebug(["SQLiteCommon exec", query, result]))),
18
- transaction: (mode) => (effect) => {
19
- // Shared is for readonly queries.
20
- if (mode === "shared")
21
- return platformSqlite.transaction(mode)(effect);
22
- return Effect.flatMap(Sqlite, (sqlite) => Effect.acquireUseRelease(sqlite.exec({ sql: "begin" }), () => effect, (_, exit) => Exit.isFailure(exit)
23
- ? sqlite.exec({ sql: "rollback" })
24
- : sqlite.exec({ sql: "commit" }))).pipe(platformSqlite.transaction(mode));
1
+ import { createTransferableError } from "./Error.js";
2
+ import { err, ok, tryAsync, trySync } from "./Result.js";
3
+ import { Boolean, Null, Number, String, transform, Uint8Array, union, } from "./Type.js";
4
+ /**
5
+ * A value that can be stored in Sqlite.
6
+ *
7
+ * Note that Evolu can't support Int64 because expo-sqlite (and some others) do
8
+ * not support it.
9
+ */
10
+ export const SqliteValue = union(Null, String, Number, Uint8Array);
11
+ /**
12
+ * Creates a fully featured {@link Sqlite} instance from a {@link SqliteDriver}
13
+ * implementation.
14
+ */
15
+ export const createSqlite = (deps) => async (name, options) => tryAsync(async () => {
16
+ const driver = await deps.createSqliteDriver(name, options);
17
+ let isDisposed = false;
18
+ const doRollback = () => trySync(() => {
19
+ deps.console?.log("[sql] rollback");
20
+ driver.exec(sql `rollback;`, true);
21
+ }, createSqliteError);
22
+ const sqlite = {
23
+ exec: (query) => trySync(() => {
24
+ deps.console?.log("[sql]", query);
25
+ const result = maybeLogSqliteQueryExecutionTime(query, () => driver.exec(query, isSqlMutation(query.sql)));
26
+ deps.console?.log("[sql]", result);
27
+ return result;
28
+ }, (error) => ({
29
+ type: "SqliteError",
30
+ error: createTransferableError(error),
31
+ })),
32
+ transaction: (callback) => {
33
+ const transactionResult = trySync(() => {
34
+ deps.console?.log("[sql] begin");
35
+ driver.exec(sql `begin;`, true);
36
+ const result = callback();
37
+ if (!result.ok)
38
+ return result;
39
+ deps.console?.log("[sql] commit");
40
+ driver.exec(sql `commit;`, true);
41
+ return result;
42
+ }, createSqliteError);
43
+ // There was an SqliteError during begin, callback, or commit
44
+ if (!transactionResult.ok) {
45
+ const rollback = doRollback();
46
+ if (!rollback.ok) {
47
+ deps.console?.log("[sql] rollback failed", rollback.error);
48
+ return err({
49
+ type: "SqliteError",
50
+ error: transactionResult.error.error,
51
+ rollbackError: rollback.error.error,
52
+ });
53
+ }
54
+ return transactionResult;
55
+ }
56
+ // Callback returned an error
57
+ if (!transactionResult.value.ok) {
58
+ const rollback = doRollback();
59
+ if (!rollback.ok) {
60
+ deps.console?.log("[sql] rollback failed", rollback.error);
61
+ return err({
62
+ type: "SqliteError",
63
+ error: createTransferableError(transactionResult.value.error),
64
+ rollbackError: rollback.error.error,
65
+ });
66
+ }
67
+ return transactionResult.value;
68
+ }
69
+ return ok(transactionResult.value.value);
25
70
  },
26
- }))),
27
- })));
28
- export const isJsonObjectOrArray = (value) => value !== null && typeof value === "object" && !Predicate.isUint8Array(value);
29
- export const valuesToSqliteValues = (values) => values.map((value) => isJsonObjectOrArray(value) ? JSON.stringify(value) : value);
30
- /** This function mutates for better performance. */
31
- export const maybeParseJson = (rows) => {
32
- parseArray(rows);
33
- };
34
- const parseArray = (a) => {
35
- for (let i = 0; i < a.length; ++i)
36
- a[i] = parse(a[i]);
37
- return a;
71
+ export: () => trySync(() => {
72
+ return driver.export();
73
+ }, (error) => ({
74
+ type: "SqliteError",
75
+ error: createTransferableError(error),
76
+ })),
77
+ [Symbol.dispose]: () => {
78
+ if (isDisposed)
79
+ return;
80
+ isDisposed = true;
81
+ driver[Symbol.dispose]();
82
+ },
83
+ };
84
+ return sqlite;
85
+ }, createSqliteError);
86
+ const createSqliteError = (error) => ({
87
+ type: "SqliteError",
88
+ error: createTransferableError(error),
89
+ });
90
+ const maybeLogSqliteQueryExecutionTime = (query, callback) => {
91
+ if (!query.options?.logQueryExecutionTime) {
92
+ return callback();
93
+ }
94
+ const start = performance.now();
95
+ const result = callback();
96
+ const elapsed = performance.now() - start;
97
+ // eslint-disable-next-line no-console
98
+ console.log(`SqliteQueryExecutionTime: ${elapsed.toString()}ms`, query);
99
+ return result;
38
100
  };
39
- const parse = (o) => {
40
- if (Predicate.isString(o))
41
- return parseString(o);
42
- // eslint-disable-next-line @typescript-eslint/no-unsafe-return
43
- if (Array.isArray(o))
44
- return parseArray(o);
45
- if (typeof o === "object" && o !== null && !Predicate.isUint8Array(o))
46
- return parseObject(o);
47
- return o;
101
+ export const createPreparedStatementsCache = (factory, disposeFn) => {
102
+ let isDisposed = false;
103
+ const cache = new Map();
104
+ return {
105
+ get: (query, alwaysPrepare) => {
106
+ if (alwaysPrepare !== true && !query.options?.prepare)
107
+ return null;
108
+ let statement = cache.get(query.sql);
109
+ if (!statement) {
110
+ statement = factory(query.sql);
111
+ cache.set(query.sql, statement);
112
+ }
113
+ return statement;
114
+ },
115
+ [Symbol.dispose]: () => {
116
+ if (isDisposed)
117
+ return;
118
+ isDisposed = true;
119
+ cache.forEach(disposeFn);
120
+ cache.clear();
121
+ },
122
+ };
48
123
  };
49
- const parseString = (s) => {
50
- if (maybeJson(s))
51
- try {
52
- return parse(JSON.parse(s));
53
- }
54
- catch (err) {
55
- // Nothing to do.
124
+ /** TODO: Docs. */
125
+ export const sql = (strings, ...parameters) => {
126
+ let sql = "";
127
+ const values = [];
128
+ for (let i = 0; i < strings.length; i++) {
129
+ sql += strings[i];
130
+ if (i < parameters.length) {
131
+ const param = parameters[i];
132
+ if (typeof param === "object" && param != null && "type" in param) {
133
+ sql += param.sql;
134
+ }
135
+ else {
136
+ sql += "?";
137
+ values.push(param);
138
+ }
56
139
  }
57
- return s;
140
+ }
141
+ return { sql: sql, parameters: values };
58
142
  };
59
- export const maybeJson = (value) => value.match(/^[[{]/) != null;
60
- const parseObject = (o) => {
61
- for (const key in o)
62
- o[key] = parse(o[key]);
63
- return o;
143
+ sql.identifier = (identifier) => ({
144
+ type: "SqlIdentifier",
145
+ // From Kysely
146
+ sql: `"${identifier.replace(/"/g, '""')}"`,
147
+ });
148
+ /**
149
+ * Insert any string.
150
+ *
151
+ * Sql.raw sometimes breaks auto-formatting because the parser does not consider
152
+ * it valid SQL. A workaround is to remove it, format it, and put it back.
153
+ *
154
+ * **Warning**: This is not escaped.
155
+ */
156
+ sql.raw = (raw) => ({ type: "RawSql", sql: raw });
157
+ sql.prepared = (strings, ...parameters) => {
158
+ const query = sql(strings, ...parameters);
159
+ return { ...query, options: { prepare: true } };
64
160
  };
65
- /** This is good enough detection because SQL strings in Evolu are predictable. */
66
161
  const isSqlMutationRegEx = new RegExp(`\\b(${[
67
162
  "alter",
68
163
  "create",
@@ -71,14 +166,27 @@ const isSqlMutationRegEx = new RegExp(`\\b(${[
71
166
  "insert",
72
167
  "replace",
73
168
  "update",
74
- ].join("|")})\\b`);
75
- export const isSqlMutation = (sql) => isSqlMutationRegEx.test(sql);
76
- export const maybeLogSqliteQueryExecutionTime = (query) => (effect) => {
77
- if (!query.options?.logQueryExecutionTime)
78
- return effect;
79
- return Effect.Do.pipe(Effect.let("start", () => performance.now()), Effect.bind("result", () => effect), Effect.let("elapsed", ({ start }) => performance.now() - start), Effect.tap(({ elapsed }) => Console.log(`QueryExecutionTime: ${elapsed}ms`, query)), Effect.map(({ result }) => result));
169
+ "begin",
170
+ "commit",
171
+ "rollback",
172
+ "pragma",
173
+ "vacuum",
174
+ ].join("|")})\\b`, "i");
175
+ export const isSqlMutation = (sql) => isSqlMutationRegEx.test(sql.replace(/--.*$/gm, ""));
176
+ export const explainSqliteQueryPlan = (deps) => (query) => {
177
+ const result = deps.sqlite.exec({
178
+ ...query,
179
+ sql: `EXPLAIN QUERY PLAN ${query.sql}`,
180
+ });
181
+ if (!result.ok)
182
+ return result;
183
+ // eslint-disable-next-line no-console
184
+ console.log("ExplainQueryPlan", query);
185
+ // eslint-disable-next-line no-console
186
+ console.log(drawSqliteQueryPlan(result.value.rows));
187
+ return ok();
80
188
  };
81
- export const drawSqliteQueryPlan = (rows) => rows
189
+ const drawSqliteQueryPlan = (rows) => rows
82
190
  .map((row) => {
83
191
  let parentId = row.parent;
84
192
  let indent = 0;
@@ -88,8 +196,16 @@ export const drawSqliteQueryPlan = (rows) => rows
88
196
  break;
89
197
  parentId = parent.parent;
90
198
  indent++;
91
- // eslint-disable-next-line no-constant-condition
199
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition, no-constant-condition
92
200
  } while (true);
93
201
  return `${" ".repeat(indent)}${row.detail}`;
94
202
  })
95
203
  .join("\n");
204
+ /**
205
+ * SQLite represents boolean values using `0` (false) and `1` (true) instead of
206
+ * a dedicated boolean type. This transform Type ensures that values conform to
207
+ * SQLite's boolean representation.
208
+ *
209
+ * See: https://www.sqlite.org/quirks.html#no_separate_boolean_datatype
210
+ */
211
+ export const SqliteBoolean = transform(Boolean, union(0, 1), (value) => ok(value ? 1 : 0), (value) => value === 1);
@@ -1,10 +1,47 @@
1
- import * as Effect from "effect/Effect";
2
- export type Listener = () => void;
3
- export type Unsubscribe = () => void;
4
- export interface Store<T> {
5
- readonly subscribe: (listener: Listener) => Unsubscribe;
6
- readonly getState: () => T;
7
- readonly setState: (state: T) => Effect.Effect<void>;
1
+ /**
2
+ * A mutable reference for managing state with change notifications
3
+ *
4
+ * @module
5
+ */
6
+ import { Eq } from "./Eq.js";
7
+ import { Ref } from "./Ref.js";
8
+ /**
9
+ * A store for managing state with change notifications. Extends {@link Ref} with
10
+ * subscriptions. Provides methods to get, set, and modify state, and to notify
11
+ * listeners when the state changes.
12
+ */
13
+ export interface Store<T> extends Ref<T> {
14
+ /**
15
+ * Registers a listener to be called on state changes and returns a function
16
+ * to unsubscribe.
17
+ */
18
+ readonly subscribe: StoreSubscribe;
19
+ /** Returns the current state of the store. */
20
+ readonly get: () => T;
21
+ /**
22
+ * Updates the store's state and notifies all subscribed listeners if the new
23
+ * state differs from the current one.
24
+ */
25
+ readonly set: (state: T) => void;
26
+ /**
27
+ * Modifies the store's state by applying a callback function to the current
28
+ * state and notifies listeners if the state changes.
29
+ */
30
+ readonly modify: (updater: (current: T) => T) => void;
8
31
  }
9
- export declare const makeStore: <T>(initialState: T) => Effect.Effect<Store<T>>;
32
+ /** Registers a listener for state changes, returning an unsubscribe function. */
33
+ export type StoreSubscribe = (listener: StoreListener) => StoreUnsubscribe;
34
+ /** A callback invoked whenever the store's state updates. */
35
+ export type StoreListener = () => void;
36
+ /** A function to remove a previously added listener. */
37
+ export type StoreUnsubscribe = () => void;
38
+ /**
39
+ * Creates a store with the given initial state. The store encapsulates its
40
+ * state, which can be read with `get` and updated with `set` or `modify`. All
41
+ * changes are broadcast to subscribers.
42
+ *
43
+ * By default, state changes are detected using `===` (shallow equality). You
44
+ * can provide a custom equality function as the second argument.
45
+ */
46
+ export declare const createStore: <T>(initialState: T, eq?: Eq<T>) => Store<T>;
10
47
  //# sourceMappingURL=Store.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Store.d.ts","sourceRoot":"","sources":["../../src/Store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,MAAM,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC;AAElC,MAAM,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC;AAErC,MAAM,WAAW,KAAK,CAAC,CAAC;IAEtB,QAAQ,CAAC,SAAS,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,WAAW,CAAC;IACxD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAG3B,QAAQ,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;CACtD;AAED,eAAO,MAAM,SAAS,GAAI,CAAC,gBAAgB,CAAC,KAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CA0BjE,CAAC"}
1
+ {"version":3,"file":"Store.d.ts","sourceRoot":"","sources":["../../src/Store.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,EAAE,EAAY,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAE/B;;;;GAIG;AACH,MAAM,WAAW,KAAK,CAAC,CAAC,CAAE,SAAQ,GAAG,CAAC,CAAC,CAAC;IACtC;;;OAGG;IACH,QAAQ,CAAC,SAAS,EAAE,cAAc,CAAC;IAEnC,8CAA8C;IAC9C,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IAEtB;;;OAGG;IACH,QAAQ,CAAC,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;IAEjC;;;OAGG;IACH,QAAQ,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC;CACvD;AAED,iFAAiF;AACjF,MAAM,MAAM,cAAc,GAAG,CAAC,QAAQ,EAAE,aAAa,KAAK,gBAAgB,CAAC;AAE3E,6DAA6D;AAC7D,MAAM,MAAM,aAAa,GAAG,MAAM,IAAI,CAAC;AAEvC,wDAAwD;AACxD,MAAM,MAAM,gBAAgB,GAAG,MAAM,IAAI,CAAC;AAE1C;;;;;;;GAOG;AACH,eAAO,MAAM,WAAW,GAAI,CAAC,EAC3B,cAAc,CAAC,EACf,KAAI,EAAE,CAAC,CAAC,CAAY,KACnB,KAAK,CAAC,CAAC,CA4BT,CAAC"}
package/dist/src/Store.js CHANGED
@@ -1,23 +1,39 @@
1
- import * as Effect from "effect/Effect";
2
- export const makeStore = (initialState) => Effect.sync(() => {
1
+ /**
2
+ * A mutable reference for managing state with change notifications
3
+ *
4
+ * @module
5
+ */
6
+ import { eqStrict } from "./Eq.js";
7
+ /**
8
+ * Creates a store with the given initial state. The store encapsulates its
9
+ * state, which can be read with `get` and updated with `set` or `modify`. All
10
+ * changes are broadcast to subscribers.
11
+ *
12
+ * By default, state changes are detected using `===` (shallow equality). You
13
+ * can provide a custom equality function as the second argument.
14
+ */
15
+ export const createStore = (initialState, eq = eqStrict) => {
3
16
  const listeners = new Set();
4
17
  let currentState = initialState;
5
- const store = {
6
- subscribe(listener) {
18
+ const updateState = (newState) => {
19
+ if (eq(newState, currentState))
20
+ return;
21
+ currentState = newState;
22
+ listeners.forEach((listener) => {
23
+ listener();
24
+ });
25
+ };
26
+ return {
27
+ subscribe: (listener) => {
7
28
  listeners.add(listener);
8
- return () => {
9
- listeners.delete(listener);
10
- };
29
+ return () => listeners.delete(listener);
30
+ },
31
+ get: () => currentState,
32
+ set: (state) => {
33
+ updateState(state);
11
34
  },
12
- getState() {
13
- return currentState;
35
+ modify: (updater) => {
36
+ updateState(updater(currentState));
14
37
  },
15
- setState: (state) => Effect.sync(() => {
16
- if (state === currentState)
17
- return;
18
- currentState = state;
19
- listeners.forEach((listener) => listener());
20
- }),
21
38
  };
22
- return store;
23
- });
39
+ };
@@ -0,0 +1,2 @@
1
+ export declare const safelyStringifyUnknownValue: (value: unknown) => string;
2
+ //# sourceMappingURL=String.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"String.d.ts","sourceRoot":"","sources":["../../src/String.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,2BAA2B,GAAI,OAAO,OAAO,KAAG,MAS5D,CAAC"}
@@ -0,0 +1,14 @@
1
+ export const safelyStringifyUnknownValue = (value) => {
2
+ if (value === null)
3
+ return "null";
4
+ if (value === undefined)
5
+ return "undefined";
6
+ if (typeof value === "string")
7
+ return `"${value}"`;
8
+ try {
9
+ return JSON.stringify(value);
10
+ }
11
+ catch {
12
+ return globalThis.String(value);
13
+ }
14
+ };
@@ -0,0 +1,20 @@
1
+ /**
2
+ * ⏳
3
+ *
4
+ * @module
5
+ */
6
+ /** Retrieves the current time in milliseconds, similar to `Date.now()`. */
7
+ export interface Time {
8
+ readonly now: () => number;
9
+ }
10
+ export interface TimeDep {
11
+ readonly time: Time;
12
+ }
13
+ /** Creates a {@link Time} using Date.now(). */
14
+ export declare const createTime: () => Time;
15
+ /**
16
+ * Creates a {@link Time} that returns a monotonically increasing number based on
17
+ * a queueMicrotask.
18
+ */
19
+ export declare const createTestTime: () => Time;
20
+ //# sourceMappingURL=Time.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Time.d.ts","sourceRoot":"","sources":["../../src/Time.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,2EAA2E;AAC3E,MAAM,WAAW,IAAI;IACnB,QAAQ,CAAC,GAAG,EAAE,MAAM,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;CACrB;AAED,+CAA+C;AAC/C,eAAO,MAAM,UAAU,QAAO,IAE5B,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,cAAc,QAAO,IAWjC,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * ⏳
3
+ *
4
+ * @module
5
+ */
6
+ /** Creates a {@link Time} using Date.now(). */
7
+ export const createTime = () => ({
8
+ now: () => Date.now(),
9
+ });
10
+ /**
11
+ * Creates a {@link Time} that returns a monotonically increasing number based on
12
+ * a queueMicrotask.
13
+ */
14
+ export const createTestTime = () => {
15
+ let now = 0;
16
+ return {
17
+ now: () => {
18
+ const current = now;
19
+ queueMicrotask(() => {
20
+ now++;
21
+ });
22
+ return current;
23
+ },
24
+ };
25
+ };