@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.
- package/README.md +7 -7
- package/dist/src/Config.d.ts +4 -6
- package/dist/src/Config.d.ts.map +1 -1
- package/dist/src/Config.js +1 -1
- package/dist/src/Crdt.d.ts +15 -9
- package/dist/src/Crdt.d.ts.map +1 -1
- package/dist/src/Crdt.js +15 -14
- package/dist/src/Crypto.d.ts +7 -13
- package/dist/src/Crypto.d.ts.map +1 -1
- package/dist/src/Crypto.js +7 -9
- package/dist/src/Db.d.ts +36 -70
- package/dist/src/Db.d.ts.map +1 -1
- package/dist/src/Db.js +45 -51
- package/dist/src/DbWorker.d.ts +13 -14
- package/dist/src/DbWorker.d.ts.map +1 -1
- package/dist/src/DbWorker.js +56 -57
- package/dist/src/Diff.d.ts +3 -1
- package/dist/src/Diff.d.ts.map +1 -1
- package/dist/src/Diff.js +3 -7
- package/dist/src/{Errors.d.ts → ErrorStore.d.ts} +14 -7
- package/dist/src/ErrorStore.d.ts.map +1 -0
- package/dist/src/{Errors.js → ErrorStore.js} +2 -0
- package/dist/src/Evolu.d.ts +316 -58
- package/dist/src/Evolu.d.ts.map +1 -1
- package/dist/src/Evolu.js +199 -185
- package/dist/src/Model.d.ts +47 -57
- package/dist/src/Model.d.ts.map +1 -1
- package/dist/src/Model.js +30 -35
- package/dist/src/OnCompletes.d.ts +11 -0
- package/dist/src/OnCompletes.d.ts.map +1 -0
- package/dist/src/OnCompletes.js +21 -0
- package/dist/src/Owner.d.ts +31 -0
- package/dist/src/Owner.d.ts.map +1 -0
- package/dist/src/Owner.js +20 -0
- package/dist/src/Platform.d.ts +15 -8
- package/dist/src/Platform.d.ts.map +1 -1
- package/dist/src/Platform.js +5 -5
- package/dist/src/Protobuf.d.ts +25 -73
- package/dist/src/Protobuf.d.ts.map +1 -1
- package/dist/src/Protobuf.js +4 -12
- package/dist/src/Public.d.ts +5 -3
- package/dist/src/Public.d.ts.map +1 -1
- package/dist/src/Public.js +1 -0
- package/dist/src/Sqlite.d.ts +8 -11
- package/dist/src/Sqlite.d.ts.map +1 -1
- package/dist/src/Sqlite.js +7 -7
- package/dist/src/Store.d.ts +6 -5
- package/dist/src/Store.d.ts.map +1 -1
- package/dist/src/Store.js +21 -16
- package/dist/src/SyncWorker.d.ts +8 -2
- package/dist/src/SyncWorker.d.ts.map +1 -1
- package/dist/src/SyncWorker.js +12 -19
- package/dist/src/index.d.ts +6 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +6 -2
- package/package.json +23 -13
- package/src/Config.ts +7 -7
- package/src/Crdt.ts +29 -26
- package/src/Crypto.ts +14 -19
- package/src/Db.ts +113 -166
- package/src/DbWorker.ts +110 -140
- package/src/Diff.ts +5 -7
- package/src/{Errors.ts → ErrorStore.ts} +17 -8
- package/src/Evolu.ts +682 -442
- package/src/Model.ts +60 -85
- package/src/OnCompletes.ts +46 -0
- package/src/Owner.ts +65 -0
- package/src/Platform.ts +24 -16
- package/src/Protobuf.ts +25 -73
- package/src/Public.ts +5 -3
- package/src/Sqlite.ts +13 -24
- package/src/Store.ts +36 -24
- package/src/SyncWorker.ts +30 -38
- package/src/index.ts +6 -2
- package/dist/src/Errors.d.ts.map +0 -1
package/dist/src/Evolu.js
CHANGED
|
@@ -1,235 +1,249 @@
|
|
|
1
|
-
import { Context, Effect,
|
|
2
|
-
import
|
|
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 {
|
|
5
|
-
import {
|
|
6
|
-
import { DbWorker
|
|
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 =
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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
|
-
|
|
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
|
-
|
|
49
|
-
|
|
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
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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
|
-
|
|
76
|
-
if (
|
|
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
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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
|
-
|
|
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
|
-
|
|
120
|
+
yield* _(rowsStore.setState(nextState));
|
|
97
121
|
return;
|
|
98
122
|
}
|
|
99
|
-
flushSync(() =>
|
|
100
|
-
|
|
101
|
-
|
|
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
|
|
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
|
-
|
|
116
|
-
return Mutate
|
|
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
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
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
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
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
|
|
186
|
+
return { id };
|
|
144
187
|
});
|
|
145
188
|
}));
|
|
146
|
-
|
|
147
|
-
|
|
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
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
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
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
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
|
-
|
|
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
|
-
|
|
232
|
-
|
|
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
|
-
|
|
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)));
|
package/dist/src/Model.d.ts
CHANGED
|
@@ -1,61 +1,54 @@
|
|
|
1
|
-
import * as
|
|
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
|
-
*
|
|
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:
|
|
8
|
-
export type 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
|
|
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 =
|
|
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) =>
|
|
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
|
-
*
|
|
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:
|
|
31
|
-
export type 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:
|
|
38
|
-
export type 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
|
-
*
|
|
52
|
-
*
|
|
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
|
-
*
|
|
58
|
-
*
|
|
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
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
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:
|
|
72
|
-
export type 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
|
|
71
|
+
* ```ts
|
|
72
|
+
* import * as S from "@effect/schema/Schema";
|
|
80
73
|
* import * as Evolu from "@evolu/react";
|
|
81
74
|
*
|
|
82
|
-
*
|
|
83
|
-
* function foo(value: Evolu.String1000) {}
|
|
75
|
+
* S.parse(Evolu.String1000)(value);
|
|
84
76
|
* ```
|
|
85
77
|
*/
|
|
86
|
-
export declare const String1000:
|
|
87
|
-
export type 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
|
|
85
|
+
* ```ts
|
|
86
|
+
* import * as S from "@effect/schema/Schema";
|
|
95
87
|
* import * as Evolu from "@evolu/react";
|
|
96
88
|
*
|
|
97
|
-
*
|
|
98
|
-
* function foo(value: Evolu.NonEmptyString1000) {}
|
|
89
|
+
* S.parse(Evolu.NonEmptyString1000)(value);
|
|
99
90
|
* ```
|
|
100
91
|
*/
|
|
101
|
-
export declare const NonEmptyString1000:
|
|
102
|
-
export type 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
|
|
99
|
+
* ```ts
|
|
100
|
+
* import * as S from "@effect/schema/Schema";
|
|
110
101
|
* import * as Evolu from "@evolu/react";
|
|
111
102
|
*
|
|
112
|
-
*
|
|
113
|
-
* function foo(value: Evolu.PositiveInt) {}
|
|
103
|
+
* S.parse(Evolu.PositiveInt)(value);
|
|
114
104
|
* ```
|
|
115
105
|
*/
|
|
116
|
-
export declare const PositiveInt:
|
|
117
|
-
export type 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
|
package/dist/src/Model.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Model.d.ts","sourceRoot":"","sources":["../../src/Model.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
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"}
|