@evolu/common 1.0.17 → 2.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 (75) hide show
  1. package/README.md +7 -7
  2. package/dist/src/Config.d.ts +4 -6
  3. package/dist/src/Config.d.ts.map +1 -1
  4. package/dist/src/Config.js +1 -1
  5. package/dist/src/Crdt.d.ts +15 -9
  6. package/dist/src/Crdt.d.ts.map +1 -1
  7. package/dist/src/Crdt.js +15 -14
  8. package/dist/src/Crypto.d.ts +7 -13
  9. package/dist/src/Crypto.d.ts.map +1 -1
  10. package/dist/src/Crypto.js +7 -9
  11. package/dist/src/Db.d.ts +36 -70
  12. package/dist/src/Db.d.ts.map +1 -1
  13. package/dist/src/Db.js +45 -51
  14. package/dist/src/DbWorker.d.ts +13 -14
  15. package/dist/src/DbWorker.d.ts.map +1 -1
  16. package/dist/src/DbWorker.js +56 -57
  17. package/dist/src/Diff.d.ts +3 -1
  18. package/dist/src/Diff.d.ts.map +1 -1
  19. package/dist/src/Diff.js +3 -7
  20. package/dist/src/{Errors.d.ts → ErrorStore.d.ts} +14 -7
  21. package/dist/src/ErrorStore.d.ts.map +1 -0
  22. package/dist/src/{Errors.js → ErrorStore.js} +2 -0
  23. package/dist/src/Evolu.d.ts +316 -58
  24. package/dist/src/Evolu.d.ts.map +1 -1
  25. package/dist/src/Evolu.js +199 -185
  26. package/dist/src/Model.d.ts +47 -57
  27. package/dist/src/Model.d.ts.map +1 -1
  28. package/dist/src/Model.js +30 -35
  29. package/dist/src/OnCompletes.d.ts +11 -0
  30. package/dist/src/OnCompletes.d.ts.map +1 -0
  31. package/dist/src/OnCompletes.js +21 -0
  32. package/dist/src/Owner.d.ts +31 -0
  33. package/dist/src/Owner.d.ts.map +1 -0
  34. package/dist/src/Owner.js +20 -0
  35. package/dist/src/Platform.d.ts +15 -8
  36. package/dist/src/Platform.d.ts.map +1 -1
  37. package/dist/src/Platform.js +5 -5
  38. package/dist/src/Protobuf.d.ts +25 -73
  39. package/dist/src/Protobuf.d.ts.map +1 -1
  40. package/dist/src/Protobuf.js +4 -12
  41. package/dist/src/Public.d.ts +5 -3
  42. package/dist/src/Public.d.ts.map +1 -1
  43. package/dist/src/Public.js +1 -0
  44. package/dist/src/Sqlite.d.ts +8 -11
  45. package/dist/src/Sqlite.d.ts.map +1 -1
  46. package/dist/src/Sqlite.js +7 -7
  47. package/dist/src/Store.d.ts +6 -5
  48. package/dist/src/Store.d.ts.map +1 -1
  49. package/dist/src/Store.js +21 -16
  50. package/dist/src/SyncWorker.d.ts +8 -2
  51. package/dist/src/SyncWorker.d.ts.map +1 -1
  52. package/dist/src/SyncWorker.js +12 -19
  53. package/dist/src/index.d.ts +6 -2
  54. package/dist/src/index.d.ts.map +1 -1
  55. package/dist/src/index.js +6 -2
  56. package/package.json +23 -13
  57. package/src/Config.ts +7 -7
  58. package/src/Crdt.ts +29 -26
  59. package/src/Crypto.ts +14 -19
  60. package/src/Db.ts +113 -166
  61. package/src/DbWorker.ts +110 -140
  62. package/src/Diff.ts +5 -7
  63. package/src/{Errors.ts → ErrorStore.ts} +17 -8
  64. package/src/Evolu.ts +682 -442
  65. package/src/Model.ts +60 -85
  66. package/src/OnCompletes.ts +46 -0
  67. package/src/Owner.ts +65 -0
  68. package/src/Platform.ts +24 -16
  69. package/src/Protobuf.ts +25 -73
  70. package/src/Public.ts +5 -3
  71. package/src/Sqlite.ts +13 -24
  72. package/src/Store.ts +36 -24
  73. package/src/SyncWorker.ts +30 -38
  74. package/src/index.ts +6 -2
  75. package/dist/src/Errors.d.ts.map +0 -1
package/dist/src/Evolu.js CHANGED
@@ -1,235 +1,249 @@
1
- import { Context, Effect, Either, Function, Layer, Number, Option, ReadonlyArray, absurd, pipe, } from "effect";
2
- import { Config, ConfigLive } from "./Config.js";
1
+ import { Context, Effect, Function, Layer, Match, Number, ReadonlyArray, pipe, } from "effect";
2
+ import * as Kysely from "kysely";
3
+ import { Config } from "./Config.js";
3
4
  import { Time, TimeLive } from "./Crdt.js";
4
- import { Bip39, NanoId } from "./Crypto.js";
5
- import { makeCreateQuery, } from "./Db.js";
6
- import { DbWorker, } from "./DbWorker.js";
5
+ import { NanoId, NanoIdLive } from "./Crypto.js";
6
+ import { RowsStore, RowsStoreLive, emptyRows, queryResultFromRows, schemaToTables, serializeQuery, } from "./Db.js";
7
+ import { DbWorker } from "./DbWorker.js";
7
8
  import { applyPatches } from "./Diff.js";
9
+ import { makeErrorStore } from "./ErrorStore.js";
8
10
  import { cast } from "./Model.js";
11
+ import { OnCompletes, OnCompletesLive } from "./OnCompletes.js";
9
12
  import { AppState, FlushSync } from "./Platform.js";
10
13
  import { makeStore } from "./Store.js";
11
- export const Evolu = () => Context.Tag("evolu/Evolu");
12
- const QueryStore = Context.Tag("evolu/QueryStore");
13
- const Mutate = () => Context.Tag("evolu/Mutate");
14
- const OwnerActions = Context.Tag("evolu/OwnerActions");
15
- const SubscribedQueries = Context.Tag("evolu/SubscribedQueries");
16
- const OnCompletes = Context.Tag("evolu/OnCompletes");
17
- const LoadingPromises = Context.Tag("evolu/LoadingPromises");
18
- export const loadingPromisesPromiseProp = "rows";
19
- const LoadingPromisesLive = Layer.effect(LoadingPromises, Effect.sync(() => {
14
+ export const Evolu = Context.Tag();
15
+ const kysely = new Kysely.Kysely({
16
+ dialect: {
17
+ createAdapter: () => new Kysely.SqliteAdapter(),
18
+ createDriver: () => new Kysely.DummyDriver(),
19
+ createIntrospector() {
20
+ throw "Not implemeneted";
21
+ },
22
+ createQueryCompiler: () => new Kysely.SqliteQueryCompiler(),
23
+ },
24
+ });
25
+ export const makeCreateQuery = () => (queryCallback) => pipe(queryCallback(kysely).compile(), ({ sql, parameters }) => ({
26
+ sql,
27
+ parameters: parameters,
28
+ }), (query) => serializeQuery(query));
29
+ export const LoadingPromises = Context.Tag();
30
+ export const LoadingPromiseLive = Layer.effect(LoadingPromises, Effect.gen(function* (_) {
31
+ const subscribedQueries = yield* _(SubscribedQueries);
20
32
  const promises = new Map();
21
- const getPromise = (query) => {
22
- const item = promises.get(query);
23
- if (item)
24
- return { promise: item.promise, isNew: false };
25
- let resolve = Function.constVoid;
26
- const promise = new Promise((_resolve) => {
27
- resolve = _resolve;
28
- });
29
- promises.set(query, { promise, resolve });
30
- return { promise, isNew: true };
31
- };
32
- const resolvePromise = (query, rows) => {
33
- const item = promises.get(query);
34
- if (!item)
35
- return;
36
- // It's similar to what React will do.
37
- void Object.assign(item.promise, { [loadingPromisesPromiseProp]: rows });
38
- item.resolve(rows);
39
- };
40
- const releasePromises = (ignoreQueries) => {
41
- [...promises.keys()].forEach((query) => {
42
- if (!ignoreQueries.includes(query))
33
+ return LoadingPromises.of({
34
+ get(query) {
35
+ let isNew = false;
36
+ let promiseWithResolve = promises.get(query);
37
+ if (!promiseWithResolve) {
38
+ isNew = true;
39
+ let resolve = Function.constVoid;
40
+ const promise = new Promise((_resolve) => {
41
+ resolve = _resolve;
42
+ });
43
+ promiseWithResolve = { promise, resolve, releaseOnResolve: false };
44
+ promises.set(query, promiseWithResolve);
45
+ }
46
+ return {
47
+ promise: promiseWithResolve.promise,
48
+ isNew,
49
+ };
50
+ },
51
+ resolve(query, rows) {
52
+ const promiseWithResolve = promises.get(query);
53
+ if (!promiseWithResolve)
54
+ return;
55
+ const result = queryResultFromRows(rows);
56
+ if (promiseWithResolve.promise.status !== "fulfilled")
57
+ promiseWithResolve.resolve(result);
58
+ else
59
+ promiseWithResolve.promise = Promise.resolve(result);
60
+ setPromiseAsResolved(promiseWithResolve.promise)(result);
61
+ if (promiseWithResolve.releaseOnResolve)
43
62
  promises.delete(query);
44
- });
45
- };
46
- return { getPromise, resolvePromise, releasePromises };
63
+ },
64
+ release() {
65
+ const keep = subscribedQueries.getSubscribedQueries();
66
+ promises.forEach((promiseWithResolve, query) => {
67
+ if (keep.includes(query))
68
+ return;
69
+ if (promiseWithResolve.promise.status === "fulfilled")
70
+ promises.delete(query);
71
+ else
72
+ promiseWithResolve.releaseOnResolve = true;
73
+ });
74
+ },
75
+ });
47
76
  }));
48
- const QueryStoreLive = Layer.effect(QueryStore, Effect.gen(function* (_) {
49
- const subscribedQueries = yield* _(SubscribedQueries);
77
+ // "For example, a data framework can set the status and value fields on a promise
78
+ // preemptively, before passing to React, so that React can unwrap it without waiting
79
+ // a microtask."
80
+ // https://github.com/acdlite/rfcs/blob/first-class-promises/text/0000-first-class-support-for-promises.md
81
+ const setPromiseAsResolved = (promise) => (value) => {
82
+ Object.assign(promise, { status: "fulfilled", value });
83
+ };
84
+ const LoadQuery = Context.Tag();
85
+ const LoadQueryLive = Layer.effect(LoadQuery, Effect.gen(function* (_) {
50
86
  const loadingPromises = yield* _(LoadingPromises);
51
87
  const dbWorker = yield* _(DbWorker);
52
- const flushSync = yield* _(FlushSync);
53
- const onCompletes = yield* _(OnCompletes);
54
- const rowsCacheStore = makeStore(new Map());
55
- const queue = new Set();
56
- const subscribe = (query) => (listen) => {
57
- if (query == null)
58
- return Function.constVoid;
59
- subscribedQueries.set(query, Number.increment(subscribedQueries.get(query) ?? 0));
60
- const unsubscribe = rowsCacheStore.subscribe(listen);
61
- return () => {
62
- // `as number`, because React mount/unmount are symmetric.
63
- const count = subscribedQueries.get(query);
64
- if (count > 1)
65
- subscribedQueries.set(query, Number.decrement(count));
66
- else
67
- subscribedQueries.delete(query);
68
- unsubscribe();
69
- };
70
- };
71
- const getState = (query) => (query && rowsCacheStore.getState().get(query)) || null;
72
- const loadQuery = (query) => {
73
- const { promise, isNew } = loadingPromises.getPromise(query);
88
+ let queries = [];
89
+ return LoadQuery.of((query) => {
90
+ const { promise, isNew } = loadingPromises.get(query);
74
91
  if (isNew)
75
- queue.add(query);
76
- if (queue.size === 1) {
92
+ queries = [...queries, query];
93
+ if (queries.length === 1) {
77
94
  queueMicrotask(() => {
78
- const queries = [...queue];
79
- queue.clear();
80
95
  if (ReadonlyArray.isNonEmptyReadonlyArray(queries))
81
96
  dbWorker.postMessage({ _tag: "query", queries });
97
+ queries = [];
82
98
  });
83
99
  }
84
100
  return promise;
85
- };
86
- const onQuery = ({ queriesPatches, onCompleteIds, }) => {
87
- const state = rowsCacheStore.getState();
88
- const nextState = pipe(queriesPatches, ReadonlyArray.map(({ query, patches }) => [query, applyPatches(patches)(state.get(query) || [])]), (a) => new Map([...state, ...a]));
89
- // Resolve all Promises belonging to queries.
101
+ });
102
+ }));
103
+ const OnQuery = Context.Tag();
104
+ const OnQueryLive = Layer.effect(OnQuery, Effect.gen(function* (_) {
105
+ const rowsStore = yield* _(RowsStore);
106
+ const loadingPromises = yield* _(LoadingPromises);
107
+ const flushSync = yield* _(FlushSync);
108
+ const onCompletes = yield* _(OnCompletes);
109
+ return OnQuery.of(({ queriesPatches, onCompleteIds }) => Effect.gen(function* (_) {
110
+ const currentState = rowsStore.getState();
111
+ const nextState = pipe(queriesPatches, ReadonlyArray.map(({ query, patches }) => [
112
+ query,
113
+ applyPatches(patches)(currentState.get(query) || emptyRows()),
114
+ ]), (map) => new Map([...currentState, ...map]));
90
115
  queriesPatches.forEach(({ query }) => {
91
- const rows = nextState.get(query) || [];
92
- loadingPromises.resolvePromise(query, rows);
116
+ loadingPromises.resolve(query, nextState.get(query) || emptyRows());
93
117
  });
94
118
  // No mutation is using onComplete, so we don't need flushSync.
95
119
  if (onCompleteIds.length === 0) {
96
- rowsCacheStore.setState(nextState);
120
+ yield* _(rowsStore.setState(nextState));
97
121
  return;
98
122
  }
99
- flushSync(() => rowsCacheStore.setState(nextState));
100
- ReadonlyArray.filterMap(onCompleteIds, (id) => {
101
- const onComplete = onCompletes.get(id);
102
- onCompletes.delete(id);
103
- return Option.fromNullable(onComplete);
104
- }).forEach((onComplete) => onComplete());
105
- };
106
- return { subscribe, getState, loadQuery, onQuery };
123
+ flushSync(() => rowsStore.setState(nextState).pipe(Effect.runSync));
124
+ yield* _(onCompletes.complete(onCompleteIds));
125
+ }));
107
126
  }));
108
- const MutateLive = () => Layer.effect(Mutate(), Effect.gen(function* (_) {
127
+ export const SubscribedQueries = Context.Tag();
128
+ export const SubscribedQueriesLive = Layer.effect(SubscribedQueries, Effect.gen(function* (_) {
129
+ const rowsStore = yield* _(RowsStore);
130
+ const subscribedQueries = new Map();
131
+ return SubscribedQueries.of({
132
+ subscribeQuery: (query) => (listener) => {
133
+ subscribedQueries.set(query, Number.increment(subscribedQueries.get(query) ?? 0));
134
+ const unsubscribe = rowsStore.subscribe(listener);
135
+ return () => {
136
+ const count = subscribedQueries.get(query);
137
+ if (count != null && count > 1)
138
+ subscribedQueries.set(query, Number.decrement(count));
139
+ else
140
+ subscribedQueries.delete(query);
141
+ unsubscribe();
142
+ };
143
+ },
144
+ getQuery: (query) => queryResultFromRows(rowsStore.getState().get(query) || emptyRows()),
145
+ getSubscribedQueries: () => ReadonlyArray.fromIterable(subscribedQueries.keys()),
146
+ });
147
+ }));
148
+ const Mutate = Context.Tag();
149
+ const MutateLive = Layer.effect(Mutate, Effect.gen(function* (_) {
109
150
  const nanoid = yield* _(NanoId);
110
151
  const onCompletes = yield* _(OnCompletes);
111
152
  const time = yield* _(Time);
112
153
  const subscribedQueries = yield* _(SubscribedQueries);
113
154
  const loadingPromises = yield* _(LoadingPromises);
114
155
  const dbWorker = yield* _(DbWorker);
115
- const queue = [];
116
- return Mutate().of((table, { id, ...values }, onComplete) => {
156
+ let mutations = [];
157
+ return Mutate.of((table, { id, ...values }, onComplete) => {
117
158
  const isInsert = id == null;
118
159
  if (isInsert)
119
160
  id = Effect.runSync(nanoid.nanoid);
120
- let onCompleteId = null;
121
- if (onComplete) {
122
- onCompleteId = Effect.runSync(nanoid.nanoid);
123
- onCompletes.set(onCompleteId, onComplete);
124
- }
125
- queue.push({
126
- table: table.toString(),
127
- id: id,
128
- values,
129
- isInsert,
130
- now: cast(new Date(Effect.runSync(time.now))),
131
- onCompleteId,
132
- });
133
- if (queue.length === 1)
161
+ const onCompleteId = onComplete
162
+ ? onCompletes.add(onComplete).pipe(Effect.runSync)
163
+ : null;
164
+ mutations = [
165
+ ...mutations,
166
+ {
167
+ table: table.toString(),
168
+ id,
169
+ values,
170
+ isInsert,
171
+ now: cast(new Date(Effect.runSync(time.now))),
172
+ onCompleteId,
173
+ },
174
+ ];
175
+ if (mutations.length === 1)
134
176
  queueMicrotask(() => {
135
- const items = [...queue];
136
- queue.length = 0;
137
- const queries = Array.from(subscribedQueries.keys());
138
- // Just wipe-out LoadingPromises unused queries.
139
- loadingPromises.releasePromises(queries);
140
- if (ReadonlyArray.isNonEmptyReadonlyArray(items))
141
- dbWorker.postMessage({ _tag: "mutate", items, queries });
177
+ if (ReadonlyArray.isNonEmptyReadonlyArray(mutations))
178
+ dbWorker.postMessage({
179
+ _tag: "mutate",
180
+ mutations,
181
+ queries: subscribedQueries.getSubscribedQueries(),
182
+ });
183
+ loadingPromises.release();
184
+ mutations = [];
142
185
  });
143
- return { id: id };
186
+ return { id };
144
187
  });
145
188
  }));
146
- const OwnerActionsLive = Layer.effect(OwnerActions, Effect.gen(function* (_) {
147
- const dbWorker = yield* _(DbWorker);
148
- const bip39 = yield* _(Bip39);
149
- const reset = () => {
150
- dbWorker.postMessage({ _tag: "reset" });
151
- };
152
- const restore = (mnemonic) => bip39.parse(mnemonic).pipe(Effect.flatMap((mnemonic) => Effect.sync(() => {
153
- dbWorker.postMessage({ _tag: "reset", mnemonic });
154
- return Either.right(undefined);
155
- })), Effect.catchTag("InvalidMnemonicError", () => Effect.succeed(Either.left({ _tag: "RestoreOwnerError" }))), Effect.runPromise);
156
- return { reset, restore };
157
- }));
158
- export const EvoluLive = (tables) => Layer.effect(Evolu(), Effect.gen(function* (_) {
189
+ /** EvoluCommon is without side effects, so it's unit-testable. */
190
+ const EvoluCommon = Layer.effect(Evolu, Effect.gen(function* (_) {
159
191
  const dbWorker = yield* _(DbWorker);
192
+ const errorStore = yield* _(makeErrorStore);
193
+ const loadQuery = yield* _(LoadQuery);
194
+ const onQuery = yield* _(OnQuery);
195
+ const { subscribeQuery, getQuery, getSubscribedQueries } = yield* _(SubscribedQueries);
196
+ const syncStateStore = yield* _(makeStore({ _tag: "SyncStateInitial" }));
197
+ const mutate = yield* _(Mutate);
198
+ const ownerStore = yield* _(makeStore(null));
199
+ const loadingPromises = yield* _(LoadingPromises);
160
200
  const appState = yield* _(AppState);
161
- const config = yield* _(Config);
162
- const subscribedQueries = new Map();
163
- const onCompletes = new Map();
164
- const loadingPromises = Effect.provide(LoadingPromises, LoadingPromisesLive).pipe(Effect.runSync);
165
- const errorStore = makeStore(null);
166
- const ownerStore = makeStore(null);
167
- const syncStateStore = makeStore({
168
- _tag: "SyncStateInitial",
201
+ dbWorker.onMessage = (output) => Match.value(output).pipe(Match.tagsExhaustive({
202
+ onError: ({ error }) => errorStore.setState(error),
203
+ onQuery,
204
+ onOwner: ({ owner }) => ownerStore.setState(owner),
205
+ onSyncState: ({ state }) => syncStateStore.setState(state),
206
+ onReceive: () => Effect.sync(() => {
207
+ loadingPromises.release();
208
+ const queries = getSubscribedQueries();
209
+ if (ReadonlyArray.isNonEmptyReadonlyArray(queries))
210
+ dbWorker.postMessage({ _tag: "query", queries });
211
+ }),
212
+ onResetOrRestore: () => appState.reset,
213
+ }), Effect.runSync);
214
+ dbWorker.postMessage({
215
+ _tag: "init",
216
+ config: yield* _(Config),
169
217
  });
170
- const Layers = Layer.mergeAll(Layer.succeed(DbWorker, dbWorker), Layer.succeed(SubscribedQueries, subscribedQueries), Layer.succeed(OnCompletes, onCompletes), Layer.succeed(LoadingPromises, loadingPromises), Layer.succeed(FlushSync, yield* _(FlushSync)), Layer.succeed(NanoId, yield* _(NanoId)), Layer.succeed(Time, yield* _(Time)), Layer.succeed(Bip39, yield* _(Bip39)));
171
- const queryStore = Effect.provide(QueryStore, Layer.use(QueryStoreLive, Layers)).pipe(Effect.runSync);
172
- const mutate = Effect.provide(Mutate(), Layer.use(MutateLive(), Layers)).pipe(Effect.runSync);
173
- const ownerActions = Effect.provide(OwnerActions, Layer.use(OwnerActionsLive, Layers)).pipe(Effect.runSync);
174
- const ensureSchema = (tables) => {
175
- dbWorker.postMessage({ _tag: "ensureSchema", tables });
176
- };
177
- const getSubscribedQueries = () => Array.from(subscribedQueries.keys());
178
- dbWorker.onMessage = (output) => {
179
- // console.log(output);
180
- switch (output._tag) {
181
- case "onError":
182
- if (process.env.NODE_ENV === "development")
183
- // JSON.stringify, because Expo console needs strings.
184
- // eslint-disable-next-line no-console
185
- console.warn(JSON.stringify(output.error, null, 2));
186
- errorStore.setState(output.error);
187
- break;
188
- case "onOwner":
189
- ownerStore.setState(output.owner);
190
- break;
191
- case "onQuery":
192
- queryStore.onQuery(output);
193
- break;
194
- case "onReceive": {
195
- const queries = getSubscribedQueries();
196
- if (ReadonlyArray.isNonEmptyReadonlyArray(queries))
197
- dbWorker.postMessage({ _tag: "query", queries });
198
- break;
199
- }
200
- case "onResetOrRestore":
201
- Effect.runSync(appState.reset);
202
- break;
203
- case "onSyncState":
204
- syncStateStore.setState(output.state);
205
- break;
206
- default:
207
- absurd(output);
208
- }
209
- };
210
- dbWorker.postMessage({ _tag: "init", config, tables });
211
- appState.onFocus(() => {
212
- // `queries` to refresh subscribed queries when a tab is changed.
213
- dbWorker.postMessage({ _tag: "sync", queries: getSubscribedQueries() });
218
+ appState.init({
219
+ onFocus: () => {
220
+ dbWorker.postMessage({ _tag: "sync", queries: getSubscribedQueries() });
221
+ },
222
+ onReconnect: () => {
223
+ dbWorker.postMessage({ _tag: "sync", queries: [] });
224
+ },
214
225
  });
215
- const sync = () => dbWorker.postMessage({ _tag: "sync", queries: [] });
216
- appState.onReconnect(sync);
217
- sync();
218
- return Evolu().of({
226
+ return Evolu.of({
219
227
  subscribeError: errorStore.subscribe,
220
228
  getError: errorStore.getState,
229
+ createQuery: makeCreateQuery(),
230
+ loadQuery,
231
+ loadQueries: (queries) => queries.map(loadQuery),
232
+ subscribeQuery,
233
+ getQuery,
221
234
  subscribeOwner: ownerStore.subscribe,
222
235
  getOwner: ownerStore.getState,
223
- createQuery: makeCreateQuery(),
224
- subscribeQuery: queryStore.subscribe,
225
- getQuery: queryStore.getState,
226
- loadQuery: queryStore.loadQuery,
227
236
  subscribeSyncState: syncStateStore.subscribe,
228
237
  getSyncState: syncStateStore.getState,
229
238
  create: mutate,
230
239
  update: mutate,
231
- ownerActions,
232
- ensureSchema,
240
+ resetOwner: () => dbWorker.postMessage({ _tag: "reset" }),
241
+ restoreOwner: (mnemonic) => dbWorker.postMessage({ _tag: "reset", mnemonic }),
242
+ ensureSchema: (schema) => dbWorker.postMessage({
243
+ _tag: "ensureSchema",
244
+ tables: schemaToTables(schema),
245
+ }),
233
246
  });
234
- }));
235
- export const makeEvoluForPlatform = (PlatformLayer, tables, config) => Effect.provide(Evolu(), Layer.use(EvoluLive(tables), Layer.mergeAll(PlatformLayer, ConfigLive(config), TimeLive))).pipe(Effect.runSync);
247
+ })).pipe(Layer.use(Layer.mergeAll(LoadQueryLive, OnQueryLive, MutateLive)), Layer.use(LoadingPromiseLive), Layer.use(SubscribedQueriesLive), Layer.use(Layer.merge(RowsStoreLive, OnCompletesLive)));
248
+ /** EvoluCommonLive has only platform independent side-effects. */
249
+ export const EvoluCommonLive = EvoluCommon.pipe(Layer.use(Layer.merge(TimeLive, NanoIdLive)));
@@ -1,61 +1,54 @@
1
- import * as Schema from "@effect/schema/Schema";
1
+ import * as S from "@effect/schema/Schema";
2
2
  import { Brand } from "effect";
3
3
  /**
4
- * Branded Id Schema for any table Id.
5
- * To create Id Schema for a specific table, use {@link id}.
4
+ * Branded Id Schema for any table Id. To create Id Schema for a specific table,
5
+ * use {@link id}.
6
6
  */
7
- export declare const Id: Schema.BrandSchema<string, string & Brand.Brand<"Id">>;
8
- export type Id = Schema.Schema.To<typeof Id>;
7
+ export declare const Id: S.BrandSchema<string, string & Brand.Brand<"Id">>;
8
+ export type Id = S.Schema.To<typeof Id>;
9
9
  /**
10
10
  * A factory function to create {@link Id} Schema for a specific table.
11
11
  *
12
12
  * ### Example
13
13
  *
14
- * ```
15
- * import * as Schema from "@effect/schema/Schema";
14
+ * ```ts
15
+ * import * as S from "@effect/schema/Schema";
16
16
  * import * as Evolu from "@evolu/react";
17
17
  *
18
18
  * const TodoId = Evolu.id("Todo");
19
- * type TodoId = Schema.Schema.To<typeof TodoId>;
20
- *
21
- * if (!Schema.is(TodoId)(value)) return;
19
+ * type TodoId = S.Schema.To<typeof TodoId>;
22
20
  * ```
23
21
  */
24
- export declare const id: <T extends string>(table: T) => Schema.BrandSchema<string, string & Brand.Brand<"Id"> & Brand.Brand<T>>;
22
+ export declare const id: <T extends string>(table: T) => S.BrandSchema<string, string & Brand.Brand<"Id"> & Brand.Brand<T>>;
25
23
  /**
26
- * SQLite doesn't support the Date type, so Evolu uses SqliteDate instead.
27
- * Use the {@link cast} helper to cast SqliteDate from Date and back.
24
+ * SQLite doesn't support the Date type, so Evolu uses SqliteDate instead. Use
25
+ * the {@link cast} helper to cast SqliteDate from Date and back.
28
26
  * https://www.sqlite.org/quirks.html#no_separate_datetime_datatype
29
27
  */
30
- export declare const SqliteDate: Schema.BrandSchema<string, string & Brand.Brand<"SqliteDate">>;
31
- export type SqliteDate = Schema.Schema.To<typeof SqliteDate>;
28
+ export declare const SqliteDate: S.BrandSchema<string, string & Brand.Brand<"SqliteDate">>;
29
+ export type SqliteDate = S.Schema.To<typeof SqliteDate>;
32
30
  /**
33
31
  * SQLite doesn't support the boolean type, so Evolu uses SqliteBoolean instead.
34
32
  * Use the {@link cast} helper to cast SqliteBoolean from boolean and back.
35
33
  * https://www.sqlite.org/quirks.html#no_separate_boolean_datatype
36
34
  */
37
- export declare const SqliteBoolean: Schema.BrandSchema<number, number & Brand.Brand<"SqliteBoolean">>;
38
- export type SqliteBoolean = Schema.Schema.To<typeof SqliteBoolean>;
39
- /**
40
- * SQLite doesn't support Date nor Boolean types, so Evolu emulates them
41
- * with {@link SqliteBoolean} and {@link SqliteDate}.
42
- *
43
- * For {@link SqliteBoolean}, you can use JavaScript boolean.
44
- * For {@link SqliteDate}, you can use JavaScript Date.
45
- */
46
- export type CastableForMutate<T> = {
47
- readonly [K in keyof T]: T[K] extends SqliteBoolean ? boolean | SqliteBoolean : T[K] extends null | SqliteBoolean ? null | boolean | SqliteBoolean : T[K] extends SqliteDate ? Date | SqliteDate : T[K] extends null | SqliteDate ? null | Date | SqliteDate : T[K];
48
- };
35
+ export declare const SqliteBoolean: S.BrandSchema<number, number & Brand.Brand<"SqliteBoolean">>;
36
+ export type SqliteBoolean = S.Schema.To<typeof SqliteBoolean>;
49
37
  /**
50
- * A helper for casting types not supported by SQLite.
51
- * SQLite doesn't support Date nor Boolean types, so Evolu emulates them
52
- * with {@link SqliteBoolean} and {@link SqliteDate}.
38
+ * A helper for casting types not supported by SQLite. SQLite doesn't support
39
+ * Date nor Boolean types, so Evolu emulates them with {@link SqliteBoolean} and
40
+ * {@link SqliteDate}.
53
41
  *
54
42
  * ### Example
55
43
  *
56
- * ```
57
- * // isDeleted is SqliteBoolean
58
- * .where("isDeleted", "is not", cast(true))
44
+ * ```ts
45
+ * const allTodosNotDeleted = evolu.createQuery((db) =>
46
+ * db
47
+ * .selectFrom("todo")
48
+ * .selectAll()
49
+ * // isDeleted is SqliteBoolean
50
+ * .where("isDeleted", "is not", Evolu.cast(true)),
51
+ * );
59
52
  * ```
60
53
  */
61
54
  export declare function cast(value: boolean): SqliteBoolean;
@@ -63,56 +56,53 @@ export declare function cast(value: SqliteBoolean): boolean;
63
56
  export declare function cast(value: Date): SqliteDate;
64
57
  export declare function cast(value: SqliteDate): Date;
65
58
  /**
66
- * String schema represents a string that is not stringified JSON. Using
67
- * String schema for strings stored in SQLite is crucial to ensure a stored
68
- * string is not automatically parsed to a JSON object or array when
69
- * retrieved. Use String schema for all string-based schemas.
59
+ * String schema represents a string that is not stringified JSON. Using String
60
+ * schema for strings stored in SQLite is crucial to ensure a stored string is
61
+ * not automatically parsed to a JSON object or array when retrieved. Use String
62
+ * schema for all string-based schemas.
70
63
  */
71
- export declare const String: Schema.BrandSchema<string, string & Brand.Brand<"String">>;
72
- export type String = Schema.Schema.To<typeof String>;
64
+ export declare const String: S.BrandSchema<string, string & Brand.Brand<"String">>;
65
+ export type String = S.Schema.To<typeof String>;
73
66
  /**
74
67
  * A string with a maximum length of 1000 characters.
75
68
  *
76
69
  * ### Example
77
70
  *
78
- * ```
79
- * import * as Schema from "@effect/schema/Schema";
71
+ * ```ts
72
+ * import * as S from "@effect/schema/Schema";
80
73
  * import * as Evolu from "@evolu/react";
81
74
  *
82
- * if (!Schema.is(Evolu.String1000)(value)) return;
83
- * function foo(value: Evolu.String1000) {}
75
+ * S.parse(Evolu.String1000)(value);
84
76
  * ```
85
77
  */
86
- export declare const String1000: Schema.BrandSchema<string, string & Brand.Brand<"String"> & Brand.Brand<"String1000">>;
87
- export type String1000 = Schema.Schema.To<typeof String1000>;
78
+ export declare const String1000: S.BrandSchema<string, string & Brand.Brand<"String"> & Brand.Brand<"String1000">>;
79
+ export type String1000 = S.Schema.To<typeof String1000>;
88
80
  /**
89
81
  * A nonempty string with a maximum length of 1000 characters.
90
82
  *
91
83
  * ### Example
92
84
  *
93
- * ```
94
- * import * as Schema from "@effect/schema/Schema";
85
+ * ```ts
86
+ * import * as S from "@effect/schema/Schema";
95
87
  * import * as Evolu from "@evolu/react";
96
88
  *
97
- * if (!Schema.is(Evolu.NonEmptyString1000)(value)) return;
98
- * function foo(value: Evolu.NonEmptyString1000) {}
89
+ * S.parse(Evolu.NonEmptyString1000)(value);
99
90
  * ```
100
91
  */
101
- export declare const NonEmptyString1000: Schema.BrandSchema<string, string & Brand.Brand<"String"> & Brand.Brand<"NonEmptyString1000">>;
102
- export type NonEmptyString1000 = Schema.Schema.To<typeof NonEmptyString1000>;
92
+ export declare const NonEmptyString1000: S.BrandSchema<string, string & Brand.Brand<"String"> & Brand.Brand<"NonEmptyString1000">>;
93
+ export type NonEmptyString1000 = S.Schema.To<typeof NonEmptyString1000>;
103
94
  /**
104
95
  * A positive integer.
105
96
  *
106
97
  * ### Example
107
98
  *
108
- * ```
109
- * import * as Schema from "@effect/schema/Schema";
99
+ * ```ts
100
+ * import * as S from "@effect/schema/Schema";
110
101
  * import * as Evolu from "@evolu/react";
111
102
  *
112
- * if (!Schema.is(Evolu.PositiveInt)(value)) return;
113
- * function foo(value: Evolu.PositiveInt) {}
103
+ * S.parse(Evolu.PositiveInt)(value);
114
104
  * ```
115
105
  */
116
- export declare const PositiveInt: Schema.BrandSchema<number, number & Brand.Brand<"PositiveInt">>;
117
- export type PositiveInt = Schema.Schema.To<typeof PositiveInt>;
106
+ export declare const PositiveInt: S.BrandSchema<number, number & Brand.Brand<"PositiveInt">>;
107
+ export type PositiveInt = S.Schema.To<typeof PositiveInt>;
118
108
  //# sourceMappingURL=Model.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Model.d.ts","sourceRoot":"","sources":["../../src/Model.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAG/B;;;GAGG;AACH,eAAO,MAAM,EAAE,wDAGd,CAAC;AACF,MAAM,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;AAE7C;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,EAAE,yGAGe,CAAC;AAE/B;;;;GAIG;AACH,eAAO,MAAM,UAAU,gEAGtB,CAAC;AACF,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,UAAU,CAAC,CAAC;AAE7D;;;;GAIG;AACH,eAAO,MAAM,aAAa,mEAIzB,CAAC;AACF,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,aAAa,CAAC,CAAC;AAEnE;;;;;;GAMG;AACH,MAAM,MAAM,iBAAiB,CAAC,CAAC,IAAI;IACjC,QAAQ,EAAE,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,aAAa,GAC/C,OAAO,GAAG,aAAa,GACvB,CAAC,CAAC,CAAC,CAAC,SAAS,IAAI,GAAG,aAAa,GACjC,IAAI,GAAG,OAAO,GAAG,aAAa,GAC9B,CAAC,CAAC,CAAC,CAAC,SAAS,UAAU,GACvB,IAAI,GAAG,UAAU,GACjB,CAAC,CAAC,CAAC,CAAC,SAAS,IAAI,GAAG,UAAU,GAC9B,IAAI,GAAG,IAAI,GAAG,UAAU,GACxB,CAAC,CAAC,CAAC,CAAC;CACT,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,wBAAgB,IAAI,CAAC,KAAK,EAAE,OAAO,GAAG,aAAa,CAAC;AACpD,wBAAgB,IAAI,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC;AACpD,wBAAgB,IAAI,CAAC,KAAK,EAAE,IAAI,GAAG,UAAU,CAAC;AAC9C,wBAAgB,IAAI,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;AAW9C;;;;;GAKG;AACH,eAAO,MAAM,MAAM,4DAclB,CAAC;AACF,MAAM,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,MAAM,CAAC,CAAC;AAErD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,UAAU,wFAGtB,CAAC;AACF,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,UAAU,CAAC,CAAC;AAE7D;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,kBAAkB,gGAI9B,CAAC;AACF,MAAM,MAAM,kBAAkB,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE7E;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,WAAW,iEAIvB,CAAC;AACF,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,WAAW,CAAC,CAAC"}
1
+ {"version":3,"file":"Model.d.ts","sourceRoot":"","sources":["../../src/Model.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,uBAAuB,CAAC;AAC3C,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAG/B;;;GAGG;AACH,eAAO,MAAM,EAAE,mDAAyD,CAAC;AACzE,MAAM,MAAM,EAAE,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;AAExC;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,EAAE,oGAGU,CAAC;AAE1B;;;;GAIG;AACH,eAAO,MAAM,UAAU,2DAGtB,CAAC;AACF,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,UAAU,CAAC,CAAC;AAExD;;;;GAIG;AACH,eAAO,MAAM,aAAa,8DAIzB,CAAC;AACF,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,aAAa,CAAC,CAAC;AAE9D;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,IAAI,CAAC,KAAK,EAAE,OAAO,GAAG,aAAa,CAAC;AACpD,wBAAgB,IAAI,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC;AACpD,wBAAgB,IAAI,CAAC,KAAK,EAAE,IAAI,GAAG,UAAU,CAAC;AAC9C,wBAAgB,IAAI,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;AAW9C;;;;;GAKG;AACH,eAAO,MAAM,MAAM,uDAclB,CAAC;AACF,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,MAAM,CAAC,CAAC;AAEhD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,UAAU,mFAAwD,CAAC;AAChF,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,UAAU,CAAC,CAAC;AAExD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,kBAAkB,2FAI9B,CAAC;AACF,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAExE;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,WAAW,4DAIvB,CAAC;AACF,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,WAAW,CAAC,CAAC"}