@evolu/common 1.0.14 → 1.0.15
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/dist/src/Db.d.ts +38 -3
- package/dist/src/Db.d.ts.map +1 -1
- package/dist/src/Db.js +11 -0
- package/dist/src/Evolu.d.ts +3 -3
- package/dist/src/Model.d.ts +0 -25
- package/dist/src/Model.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/Db.ts +68 -4
- package/src/Evolu.ts +22 -22
- package/src/Model.ts +1 -30
package/dist/src/Db.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as S from "@effect/schema/Schema";
|
|
2
2
|
import { Brand, Context, Effect, ReadonlyRecord } from "effect";
|
|
3
3
|
import * as Kysely from "kysely";
|
|
4
|
+
import { Simplify } from "kysely";
|
|
4
5
|
import { Bip39, Mnemonic, NanoId } from "./Crypto.js";
|
|
5
6
|
import { Id, SqliteBoolean, SqliteDate } from "./Model.js";
|
|
6
7
|
import { Query, Row, Sqlite, Value } from "./Sqlite.js";
|
|
@@ -9,9 +10,9 @@ export type TableSchema = ReadonlyRecord.ReadonlyRecord<Value> & {
|
|
|
9
10
|
};
|
|
10
11
|
export type Schema = ReadonlyRecord.ReadonlyRecord<TableSchema>;
|
|
11
12
|
export type CreateQuery<S extends Schema> = (queryCallback: QueryCallback<S, Row>) => Query;
|
|
12
|
-
export type QueryCallback<S extends Schema, QueryRow> = (db: KyselyWithoutMutation<
|
|
13
|
+
export type QueryCallback<S extends Schema, QueryRow> = (db: KyselyWithoutMutation<QuerySchema<S>>) => Kysely.SelectQueryBuilder<any, any, QueryRow>;
|
|
13
14
|
type KyselyWithoutMutation<DB> = Pick<Kysely.Kysely<DB>, "selectFrom" | "fn">;
|
|
14
|
-
type
|
|
15
|
+
type QuerySchema<S extends Schema> = {
|
|
15
16
|
readonly [Table in keyof S]: NullableExceptOfId<{
|
|
16
17
|
readonly [Column in keyof S[Table]]: S[Table][Column];
|
|
17
18
|
} & CommonColumns>;
|
|
@@ -24,12 +25,45 @@ export interface CommonColumns {
|
|
|
24
25
|
readonly updatedAt: SqliteDate;
|
|
25
26
|
readonly isDeleted: SqliteBoolean;
|
|
26
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* Filter and map array items in one step with the correct return type and
|
|
30
|
+
* without unreliable TypeScript type guards.
|
|
31
|
+
*
|
|
32
|
+
* ### Examples
|
|
33
|
+
*
|
|
34
|
+
* ```
|
|
35
|
+
* useQuery(
|
|
36
|
+
* (db) => db.selectFrom("todo").selectAll(),
|
|
37
|
+
* // Filter and map nothing.
|
|
38
|
+
* (row) => row,
|
|
39
|
+
* );
|
|
40
|
+
*
|
|
41
|
+
* useQuery(
|
|
42
|
+
* (db) => db.selectFrom("todo").selectAll(),
|
|
43
|
+
* // Filter items with title != null.
|
|
44
|
+
* // Note the title type isn't nullable anymore in rows.
|
|
45
|
+
* ({ title, ...rest }) => title != null && { title, ...rest },
|
|
46
|
+
* );
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
export type FilterMap<QueryRow extends Row, FilterMapRow extends Row> = (row: QueryRow) => FilterMapRow | null | false;
|
|
50
|
+
export interface QueryResult<FilterMapRow extends Row> {
|
|
51
|
+
/**
|
|
52
|
+
* Rows from the database. They can be filtered and mapped by `filterMap`.
|
|
53
|
+
*/
|
|
54
|
+
readonly rows: ReadonlyArray<Readonly<Simplify<ExcludeNullAndFalse<FilterMapRow>>>>;
|
|
55
|
+
/**
|
|
56
|
+
* The first row from `rows`. For empty rows, it's null.
|
|
57
|
+
*/
|
|
58
|
+
readonly firstRow: Readonly<Simplify<ExcludeNullAndFalse<FilterMapRow>>> | null;
|
|
59
|
+
}
|
|
60
|
+
type ExcludeNullAndFalse<T> = Exclude<T, null | false>;
|
|
27
61
|
export interface Table {
|
|
28
62
|
readonly name: string;
|
|
29
63
|
readonly columns: ReadonlyArray<string>;
|
|
30
64
|
}
|
|
31
65
|
export type Tables = ReadonlyArray<Table>;
|
|
32
|
-
export declare const makeCreateQuery: <
|
|
66
|
+
export declare const makeCreateQuery: <S extends Schema>() => CreateQuery<S>;
|
|
33
67
|
export declare const schemaToTables: (schema: S.Schema<any, any>) => Tables;
|
|
34
68
|
/**
|
|
35
69
|
* `Owner` represents the Evolu database owner. Evolu auto-generates `Owner`
|
|
@@ -62,5 +96,6 @@ export declare const someDefectToNoSuchTableOrColumnError: <R, E, A>(self: Effec
|
|
|
62
96
|
export declare const makeOwner: (mnemonic?: Mnemonic) => Effect.Effect<Bip39, never, Owner>;
|
|
63
97
|
export declare const lazyInit: (mnemonic?: Mnemonic) => Effect.Effect<Sqlite | Bip39 | NanoId, never, Owner>;
|
|
64
98
|
export declare const ensureSchema: (tables: Tables) => Effect.Effect<Sqlite, never, void>;
|
|
99
|
+
export declare const makeCacheFilterMap: () => <QueryRow extends Row, FilterMapRow extends Row>(filterMap: FilterMap<QueryRow, FilterMapRow>) => FilterMap<QueryRow, FilterMapRow>;
|
|
65
100
|
export {};
|
|
66
101
|
//# sourceMappingURL=Db.d.ts.map
|
package/dist/src/Db.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Db.d.ts","sourceRoot":"","sources":["../../src/Db.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,CAAC,MAAM,uBAAuB,CAAC;AAG3C,OAAO,EACL,KAAK,EACL,OAAO,EACP,MAAM,EAKN,cAAc,EAGf,MAAM,QAAQ,CAAC;AAChB,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"Db.d.ts","sourceRoot":"","sources":["../../src/Db.ts"],"names":[],"mappings":"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"}
|
package/dist/src/Db.js
CHANGED
|
@@ -110,3 +110,14 @@ const createTable = ({ name, columns, }) => Effect.flatMap(Sqlite, (sqlite) => s
|
|
|
110
110
|
export const ensureSchema = (tables) => Effect.flatMap(getTables, (existingTables) => Effect.forEach(tables, (tableDefinition) => existingTables.includes(tableDefinition.name)
|
|
111
111
|
? updateTable(tableDefinition)
|
|
112
112
|
: createTable(tableDefinition), { discard: true }));
|
|
113
|
+
export const makeCacheFilterMap = () => {
|
|
114
|
+
const cache = new WeakMap();
|
|
115
|
+
return (filterMap) => (row) => {
|
|
116
|
+
let cachedRow = cache.get(row);
|
|
117
|
+
if (cachedRow === undefined) {
|
|
118
|
+
cachedRow = filterMap(row);
|
|
119
|
+
cache.set(row, cachedRow);
|
|
120
|
+
}
|
|
121
|
+
return cachedRow;
|
|
122
|
+
};
|
|
123
|
+
};
|
package/dist/src/Evolu.d.ts
CHANGED
|
@@ -27,7 +27,7 @@ export interface Evolu<S extends Schema> {
|
|
|
27
27
|
readonly ownerActions: OwnerActions;
|
|
28
28
|
readonly ensureSchema: (tables: Tables) => void;
|
|
29
29
|
}
|
|
30
|
-
export declare const Evolu: <
|
|
30
|
+
export declare const Evolu: <S extends Schema>() => Context.Tag<Evolu<S>, Evolu<S>>;
|
|
31
31
|
type ErrorStore = Store<EvoluError | null>;
|
|
32
32
|
type OwnerStore = Store<Owner | null>;
|
|
33
33
|
interface QueryStore {
|
|
@@ -65,7 +65,7 @@ interface RestoreOwnerError {
|
|
|
65
65
|
readonly _tag: "RestoreOwnerError";
|
|
66
66
|
}
|
|
67
67
|
export declare const loadingPromisesPromiseProp = "rows";
|
|
68
|
-
export declare const EvoluLive: <
|
|
69
|
-
export declare const makeEvoluForPlatform: <
|
|
68
|
+
export declare const EvoluLive: <S extends Schema>(tables: Tables) => Layer.Layer<Config | Bip39 | NanoId | Time | FlushSync | AppState | DbWorker, never, Evolu<S>>;
|
|
69
|
+
export declare const makeEvoluForPlatform: <S extends Schema>(PlatformLayer: Layer.Layer<never, never, DbWorker | Bip39 | NanoId | FlushSync | AppState>, tables: Tables, config?: Partial<Config>) => Evolu<S>;
|
|
70
70
|
export {};
|
|
71
71
|
//# sourceMappingURL=Evolu.d.ts.map
|
package/dist/src/Model.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import * as Schema from "@effect/schema/Schema";
|
|
2
2
|
import { Brand } from "effect";
|
|
3
|
-
import { Row } from "./Sqlite.js";
|
|
4
3
|
/**
|
|
5
4
|
* Branded Id Schema for any table Id.
|
|
6
5
|
* To create Id Schema for a specific table, use {@link id}.
|
|
@@ -116,28 +115,4 @@ export type NonEmptyString1000 = Schema.Schema.To<typeof NonEmptyString1000>;
|
|
|
116
115
|
*/
|
|
117
116
|
export declare const PositiveInt: Schema.BrandSchema<number, number & Brand.Brand<"PositiveInt">>;
|
|
118
117
|
export type PositiveInt = Schema.Schema.To<typeof PositiveInt>;
|
|
119
|
-
/**
|
|
120
|
-
* Filter and map array items in one step with the correct return type and
|
|
121
|
-
* without unreliable TypeScript type guards.
|
|
122
|
-
*
|
|
123
|
-
* ### Examples
|
|
124
|
-
*
|
|
125
|
-
* ```
|
|
126
|
-
* useQuery(
|
|
127
|
-
* (db) => db.selectFrom("todo").selectAll(),
|
|
128
|
-
* // Filter and map nothing.
|
|
129
|
-
* (row) => row,
|
|
130
|
-
* );
|
|
131
|
-
*
|
|
132
|
-
* useQuery(
|
|
133
|
-
* (db) => db.selectFrom("todo").selectAll(),
|
|
134
|
-
* // Filter items with title != null.
|
|
135
|
-
* // Note the title type isn't nullable anymore in rows.
|
|
136
|
-
* ({ title, ...rest }) => title != null && { title, ...rest },
|
|
137
|
-
* );
|
|
138
|
-
* ```
|
|
139
|
-
*/
|
|
140
|
-
export type FilterMap<QueryRow extends Row, FilterMapRow extends Row> = (row: QueryRow) => OrNullOrFalse<FilterMapRow>;
|
|
141
|
-
export type OrNullOrFalse<T> = T | null | false;
|
|
142
|
-
export type ExcludeNullAndFalse<T> = Exclude<T, null | false>;
|
|
143
118
|
//# 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,MAAM,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;
|
|
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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@evolu/common",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.15",
|
|
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",
|
|
@@ -42,12 +42,12 @@
|
|
|
42
42
|
"nanoid": "^5.0.2"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
-
"@effect/schema": "0.
|
|
45
|
+
"@effect/schema": "0.46.1",
|
|
46
46
|
"@protobuf-ts/plugin": "^2.9.1",
|
|
47
47
|
"@protobuf-ts/protoc": "^2.9.1",
|
|
48
48
|
"array-shuffle": "^3.0.0",
|
|
49
49
|
"better-sqlite3": "^9.0.0",
|
|
50
|
-
"effect": "2.0.0-next.
|
|
50
|
+
"effect": "2.0.0-next.52",
|
|
51
51
|
"eslint": "^8.52.0",
|
|
52
52
|
"typescript": "^5.2.2",
|
|
53
53
|
"vitest": "^0.34.6",
|
|
@@ -55,8 +55,8 @@
|
|
|
55
55
|
"eslint-config-evolu": "0.0.2"
|
|
56
56
|
},
|
|
57
57
|
"peerDependencies": {
|
|
58
|
-
"@effect/schema": "0.
|
|
59
|
-
"effect": "2.0.0-next.
|
|
58
|
+
"@effect/schema": "0.46.1",
|
|
59
|
+
"effect": "2.0.0-next.52"
|
|
60
60
|
},
|
|
61
61
|
"publishConfig": {
|
|
62
62
|
"access": "public"
|
package/src/Db.ts
CHANGED
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
pipe,
|
|
16
16
|
} from "effect";
|
|
17
17
|
import * as Kysely from "kysely";
|
|
18
|
+
import { Simplify } from "kysely";
|
|
18
19
|
import { urlAlphabet } from "nanoid";
|
|
19
20
|
import {
|
|
20
21
|
initialMerkleTree,
|
|
@@ -50,13 +51,13 @@ export type CreateQuery<S extends Schema> = (
|
|
|
50
51
|
) => Query;
|
|
51
52
|
|
|
52
53
|
export type QueryCallback<S extends Schema, QueryRow> = (
|
|
53
|
-
db: KyselyWithoutMutation<
|
|
54
|
+
db: KyselyWithoutMutation<QuerySchema<S>>,
|
|
54
55
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
55
56
|
) => Kysely.SelectQueryBuilder<any, any, QueryRow>;
|
|
56
57
|
|
|
57
58
|
type KyselyWithoutMutation<DB> = Pick<Kysely.Kysely<DB>, "selectFrom" | "fn">;
|
|
58
59
|
|
|
59
|
-
type
|
|
60
|
+
type QuerySchema<S extends Schema> = {
|
|
60
61
|
readonly [Table in keyof S]: NullableExceptOfId<
|
|
61
62
|
{
|
|
62
63
|
readonly [Column in keyof S[Table]]: S[Table][Column];
|
|
@@ -74,6 +75,48 @@ export interface CommonColumns {
|
|
|
74
75
|
readonly isDeleted: SqliteBoolean;
|
|
75
76
|
}
|
|
76
77
|
|
|
78
|
+
/**
|
|
79
|
+
* Filter and map array items in one step with the correct return type and
|
|
80
|
+
* without unreliable TypeScript type guards.
|
|
81
|
+
*
|
|
82
|
+
* ### Examples
|
|
83
|
+
*
|
|
84
|
+
* ```
|
|
85
|
+
* useQuery(
|
|
86
|
+
* (db) => db.selectFrom("todo").selectAll(),
|
|
87
|
+
* // Filter and map nothing.
|
|
88
|
+
* (row) => row,
|
|
89
|
+
* );
|
|
90
|
+
*
|
|
91
|
+
* useQuery(
|
|
92
|
+
* (db) => db.selectFrom("todo").selectAll(),
|
|
93
|
+
* // Filter items with title != null.
|
|
94
|
+
* // Note the title type isn't nullable anymore in rows.
|
|
95
|
+
* ({ title, ...rest }) => title != null && { title, ...rest },
|
|
96
|
+
* );
|
|
97
|
+
* ```
|
|
98
|
+
*/
|
|
99
|
+
export type FilterMap<QueryRow extends Row, FilterMapRow extends Row> = (
|
|
100
|
+
row: QueryRow,
|
|
101
|
+
) => FilterMapRow | null | false;
|
|
102
|
+
|
|
103
|
+
export interface QueryResult<FilterMapRow extends Row> {
|
|
104
|
+
/**
|
|
105
|
+
* Rows from the database. They can be filtered and mapped by `filterMap`.
|
|
106
|
+
*/
|
|
107
|
+
readonly rows: ReadonlyArray<
|
|
108
|
+
Readonly<Simplify<ExcludeNullAndFalse<FilterMapRow>>>
|
|
109
|
+
>;
|
|
110
|
+
/**
|
|
111
|
+
* The first row from `rows`. For empty rows, it's null.
|
|
112
|
+
*/
|
|
113
|
+
readonly firstRow: Readonly<
|
|
114
|
+
Simplify<ExcludeNullAndFalse<FilterMapRow>>
|
|
115
|
+
> | null;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
type ExcludeNullAndFalse<T> = Exclude<T, null | false>;
|
|
119
|
+
|
|
77
120
|
export interface Table {
|
|
78
121
|
readonly name: string;
|
|
79
122
|
readonly columns: ReadonlyArray<string>;
|
|
@@ -83,7 +126,7 @@ export type Tables = ReadonlyArray<Table>;
|
|
|
83
126
|
|
|
84
127
|
const commonColumns = ["createdAt", "updatedAt", "isDeleted"];
|
|
85
128
|
|
|
86
|
-
const kysely: Kysely.Kysely<
|
|
129
|
+
const kysely: Kysely.Kysely<QuerySchema<Schema>> = new Kysely.Kysely({
|
|
87
130
|
dialect: {
|
|
88
131
|
createAdapter: () => new Kysely.SqliteAdapter(),
|
|
89
132
|
createDriver: () => new Kysely.DummyDriver(),
|
|
@@ -95,7 +138,7 @@ const kysely: Kysely.Kysely<SchemaForQuery<Schema>> = new Kysely.Kysely({
|
|
|
95
138
|
});
|
|
96
139
|
|
|
97
140
|
export const makeCreateQuery =
|
|
98
|
-
<
|
|
141
|
+
<S extends Schema>(): CreateQuery<S> =>
|
|
99
142
|
(queryCallback) =>
|
|
100
143
|
queryObjectToQuery(queryCallback(kysely as never).compile() as QueryObject);
|
|
101
144
|
|
|
@@ -325,3 +368,24 @@ export const ensureSchema = (
|
|
|
325
368
|
{ discard: true },
|
|
326
369
|
),
|
|
327
370
|
);
|
|
371
|
+
|
|
372
|
+
export const makeCacheFilterMap = (): (<
|
|
373
|
+
QueryRow extends Row,
|
|
374
|
+
FilterMapRow extends Row,
|
|
375
|
+
>(
|
|
376
|
+
filterMap: FilterMap<QueryRow, FilterMapRow>,
|
|
377
|
+
) => FilterMap<QueryRow, FilterMapRow>) => {
|
|
378
|
+
const cache = new WeakMap<Row, Row | null | false>();
|
|
379
|
+
|
|
380
|
+
return <QueryRow extends Row, FilterMapRow extends Row>(
|
|
381
|
+
filterMap: FilterMap<QueryRow, FilterMapRow>,
|
|
382
|
+
): FilterMap<QueryRow, FilterMapRow> =>
|
|
383
|
+
(row: QueryRow) => {
|
|
384
|
+
let cachedRow = cache.get(row);
|
|
385
|
+
if (cachedRow === undefined) {
|
|
386
|
+
cachedRow = filterMap(row);
|
|
387
|
+
cache.set(row, cachedRow);
|
|
388
|
+
}
|
|
389
|
+
return cachedRow as FilterMapRow | null | false;
|
|
390
|
+
};
|
|
391
|
+
};
|
package/src/Evolu.ts
CHANGED
|
@@ -60,8 +60,8 @@ export interface Evolu<S extends Schema> {
|
|
|
60
60
|
readonly ensureSchema: (tables: Tables) => void;
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
export const Evolu = <
|
|
64
|
-
Context.Tag<Evolu<
|
|
63
|
+
export const Evolu = <S extends Schema>(): Context.Tag<Evolu<S>, Evolu<S>> =>
|
|
64
|
+
Context.Tag<Evolu<S>>("evolu/Evolu");
|
|
65
65
|
|
|
66
66
|
type ErrorStore = Store<EvoluError | null>;
|
|
67
67
|
|
|
@@ -118,8 +118,8 @@ type Mutate<S extends Schema> = <
|
|
|
118
118
|
readonly id: U[T]["id"];
|
|
119
119
|
};
|
|
120
120
|
|
|
121
|
-
const Mutate = <
|
|
122
|
-
Context.Tag<Mutate<
|
|
121
|
+
const Mutate = <S extends Schema>(): Context.Tag<Mutate<S>, Mutate<S>> =>
|
|
122
|
+
Context.Tag<Mutate<S>>("evolu/Mutate");
|
|
123
123
|
|
|
124
124
|
type SchemaForMutate<S extends Schema> = {
|
|
125
125
|
readonly [Table in keyof S]: NullableExceptOfId<
|
|
@@ -297,13 +297,13 @@ const QueryStoreLive = Layer.effect(
|
|
|
297
297
|
}),
|
|
298
298
|
);
|
|
299
299
|
|
|
300
|
-
const MutateLive = <
|
|
300
|
+
const MutateLive = <S extends Schema>(): Layer.Layer<
|
|
301
301
|
NanoId | OnCompletes | Time | SubscribedQueries | LoadingPromises | DbWorker,
|
|
302
302
|
never,
|
|
303
|
-
Mutate<
|
|
303
|
+
Mutate<S>
|
|
304
304
|
> =>
|
|
305
305
|
Layer.effect(
|
|
306
|
-
Mutate<
|
|
306
|
+
Mutate<S>(),
|
|
307
307
|
Effect.gen(function* (_) {
|
|
308
308
|
const nanoid = yield* _(NanoId);
|
|
309
309
|
const onCompletes = yield* _(OnCompletes);
|
|
@@ -314,7 +314,7 @@ const MutateLive = <T extends Schema>(): Layer.Layer<
|
|
|
314
314
|
|
|
315
315
|
const queue: Array<MutateItem> = [];
|
|
316
316
|
|
|
317
|
-
return Mutate<
|
|
317
|
+
return Mutate<S>().of((table, { id, ...values }, onComplete) => {
|
|
318
318
|
const isInsert = id == null;
|
|
319
319
|
if (isInsert) id = Effect.runSync(nanoid.nanoid) as never;
|
|
320
320
|
|
|
@@ -381,15 +381,15 @@ const OwnerActionsLive = Layer.effect(
|
|
|
381
381
|
}),
|
|
382
382
|
);
|
|
383
383
|
|
|
384
|
-
export const EvoluLive = <
|
|
384
|
+
export const EvoluLive = <S extends Schema>(
|
|
385
385
|
tables: Tables,
|
|
386
386
|
): Layer.Layer<
|
|
387
387
|
DbWorker | Bip39 | Config | FlushSync | NanoId | Time | AppState,
|
|
388
388
|
never,
|
|
389
|
-
Evolu<
|
|
389
|
+
Evolu<S>
|
|
390
390
|
> =>
|
|
391
391
|
Layer.effect(
|
|
392
|
-
Evolu<
|
|
392
|
+
Evolu<S>(),
|
|
393
393
|
Effect.gen(function* (_) {
|
|
394
394
|
const dbWorker = yield* _(DbWorker);
|
|
395
395
|
const appState = yield* _(AppState);
|
|
@@ -425,8 +425,8 @@ export const EvoluLive = <T extends Schema>(
|
|
|
425
425
|
).pipe(Effect.runSync);
|
|
426
426
|
|
|
427
427
|
const mutate = Effect.provide(
|
|
428
|
-
Mutate<
|
|
429
|
-
Layer.use(MutateLive<
|
|
428
|
+
Mutate<S>(),
|
|
429
|
+
Layer.use(MutateLive<S>(), Layers),
|
|
430
430
|
).pipe(Effect.runSync);
|
|
431
431
|
|
|
432
432
|
const ownerActions = Effect.provide(
|
|
@@ -434,7 +434,7 @@ export const EvoluLive = <T extends Schema>(
|
|
|
434
434
|
Layer.use(OwnerActionsLive, Layers),
|
|
435
435
|
).pipe(Effect.runSync);
|
|
436
436
|
|
|
437
|
-
const ensureSchema: Evolu<
|
|
437
|
+
const ensureSchema: Evolu<S>["ensureSchema"] = (tables) => {
|
|
438
438
|
dbWorker.postMessage({ _tag: "ensureSchema", tables });
|
|
439
439
|
};
|
|
440
440
|
|
|
@@ -486,14 +486,14 @@ export const EvoluLive = <T extends Schema>(
|
|
|
486
486
|
appState.onReconnect(sync);
|
|
487
487
|
sync();
|
|
488
488
|
|
|
489
|
-
return Evolu<
|
|
489
|
+
return Evolu<S>().of({
|
|
490
490
|
subscribeError: errorStore.subscribe,
|
|
491
491
|
getError: errorStore.getState,
|
|
492
492
|
|
|
493
493
|
subscribeOwner: ownerStore.subscribe,
|
|
494
494
|
getOwner: ownerStore.getState,
|
|
495
495
|
|
|
496
|
-
createQuery: makeCreateQuery<
|
|
496
|
+
createQuery: makeCreateQuery<S>(),
|
|
497
497
|
subscribeQuery: queryStore.subscribe,
|
|
498
498
|
getQuery: queryStore.getState,
|
|
499
499
|
loadQuery: queryStore.loadQuery,
|
|
@@ -501,15 +501,15 @@ export const EvoluLive = <T extends Schema>(
|
|
|
501
501
|
subscribeSyncState: syncStateStore.subscribe,
|
|
502
502
|
getSyncState: syncStateStore.getState,
|
|
503
503
|
|
|
504
|
-
create: mutate as Create<
|
|
505
|
-
update: mutate as Update<
|
|
504
|
+
create: mutate as Create<S>,
|
|
505
|
+
update: mutate as Update<S>,
|
|
506
506
|
ownerActions,
|
|
507
507
|
ensureSchema,
|
|
508
508
|
});
|
|
509
509
|
}),
|
|
510
510
|
);
|
|
511
511
|
|
|
512
|
-
export const makeEvoluForPlatform = <
|
|
512
|
+
export const makeEvoluForPlatform = <S extends Schema>(
|
|
513
513
|
PlatformLayer: Layer.Layer<
|
|
514
514
|
never,
|
|
515
515
|
never,
|
|
@@ -517,11 +517,11 @@ export const makeEvoluForPlatform = <T extends Schema>(
|
|
|
517
517
|
>,
|
|
518
518
|
tables: Tables,
|
|
519
519
|
config?: Partial<Config>,
|
|
520
|
-
): Evolu<
|
|
520
|
+
): Evolu<S> =>
|
|
521
521
|
Effect.provide(
|
|
522
|
-
Evolu<
|
|
522
|
+
Evolu<S>(),
|
|
523
523
|
Layer.use(
|
|
524
|
-
EvoluLive<
|
|
524
|
+
EvoluLive<S>(tables),
|
|
525
525
|
Layer.mergeAll(PlatformLayer, ConfigLive(config), TimeLive),
|
|
526
526
|
),
|
|
527
527
|
).pipe(Effect.runSync);
|
package/src/Model.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as Schema from "@effect/schema/Schema";
|
|
2
2
|
import { Brand } from "effect";
|
|
3
|
-
import {
|
|
3
|
+
import { maybeJson } from "./Sqlite.js";
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Branded Id Schema for any table Id.
|
|
@@ -181,32 +181,3 @@ export const PositiveInt = Schema.number.pipe(
|
|
|
181
181
|
Schema.brand("PositiveInt"),
|
|
182
182
|
);
|
|
183
183
|
export type PositiveInt = Schema.Schema.To<typeof PositiveInt>;
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Filter and map array items in one step with the correct return type and
|
|
187
|
-
* without unreliable TypeScript type guards.
|
|
188
|
-
*
|
|
189
|
-
* ### Examples
|
|
190
|
-
*
|
|
191
|
-
* ```
|
|
192
|
-
* useQuery(
|
|
193
|
-
* (db) => db.selectFrom("todo").selectAll(),
|
|
194
|
-
* // Filter and map nothing.
|
|
195
|
-
* (row) => row,
|
|
196
|
-
* );
|
|
197
|
-
*
|
|
198
|
-
* useQuery(
|
|
199
|
-
* (db) => db.selectFrom("todo").selectAll(),
|
|
200
|
-
* // Filter items with title != null.
|
|
201
|
-
* // Note the title type isn't nullable anymore in rows.
|
|
202
|
-
* ({ title, ...rest }) => title != null && { title, ...rest },
|
|
203
|
-
* );
|
|
204
|
-
* ```
|
|
205
|
-
*/
|
|
206
|
-
export type FilterMap<QueryRow extends Row, FilterMapRow extends Row> = (
|
|
207
|
-
row: QueryRow,
|
|
208
|
-
) => OrNullOrFalse<FilterMapRow>;
|
|
209
|
-
|
|
210
|
-
export type OrNullOrFalse<T> = T | null | false;
|
|
211
|
-
|
|
212
|
-
export type ExcludeNullAndFalse<T> = Exclude<T, null | false>;
|