@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 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<SchemaForQuery<S>>) => Kysely.SelectQueryBuilder<any, any, QueryRow>;
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 SchemaForQuery<S extends Schema> = {
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: <T extends Schema>() => CreateQuery<T>;
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
@@ -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;AAQjC,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAgB,MAAM,aAAa,CAAC;AACpE,OAAO,EAAE,EAAE,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAO3D,OAAO,EACL,KAAK,EAEL,GAAG,EACH,MAAM,EACN,KAAK,EAEN,MAAM,aAAa,CAAC;AAErB,MAAM,MAAM,WAAW,GAAG,cAAc,CAAC,cAAc,CAAC,KAAK,CAAC,GAAG;IAC/D,QAAQ,CAAC,EAAE,EAAE,EAAE,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,MAAM,GAAG,cAAc,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC;AAEhE,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,MAAM,IAAI,CAC1C,aAAa,EAAE,aAAa,CAAC,CAAC,EAAE,GAAG,CAAC,KACjC,KAAK,CAAC;AAEX,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,MAAM,EAAE,QAAQ,IAAI,CACtD,EAAE,EAAE,qBAAqB,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,KAEzC,MAAM,CAAC,kBAAkB,CAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC;AAEnD,KAAK,qBAAqB,CAAC,EAAE,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC,CAAC;AAE9E,KAAK,cAAc,CAAC,CAAC,SAAS,MAAM,IAAI;IACtC,QAAQ,EAAE,KAAK,IAAI,MAAM,CAAC,GAAG,kBAAkB,CAC7C;QACE,QAAQ,EAAE,MAAM,IAAI,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC;KACtD,GAAG,aAAa,CAClB;CACF,CAAC;AAEF,MAAM,MAAM,kBAAkB,CAAC,CAAC,IAAI;IAClC,QAAQ,EAAE,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI;CAC7D,CAAC;AAEF,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,SAAS,EAAE,UAAU,CAAC;IAC/B,QAAQ,CAAC,SAAS,EAAE,UAAU,CAAC;IAC/B,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC;CACnC;AAED,MAAM,WAAW,KAAK;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;CACzC;AAED,MAAM,MAAM,MAAM,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;AAe1C,eAAO,MAAM,eAAe,wCAGmD,CAAC;AAkBhF,eAAO,MAAM,cAAc,WAEjB,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,WAazB,CAAC;AAEJ;;;;GAIG;AACH,MAAM,WAAW,KAAK;IACpB,8CAA8C;IAC9C,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IAErB,QAAQ,CAAC,aAAa,EAAE,UAAU,CAAC;CACpC;AAED,eAAO,MAAM,KAAK,2BAAoC,CAAC;AAEvD;;GAEG;AACH,MAAM,MAAM,OAAO,GAAG,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;AAEhD,eAAO,MAAM,WAAW,8EAUrB,CAAC;AAEJ,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,IAAI,EAAE,0BAA0B,CAAC;CAC3C;AAED,eAAO,MAAM,8BAA8B;;;;EAMzC,CAAC;AACH,MAAM,MAAM,8BAA8B,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,CACtD,OAAO,8BAA8B,CACtC,CAAC;AAEF,eAAO,MAAM,oCAAoC,8FAShD,CAAC;AAEF,eAAO,MAAM,SAAS,cACT,QAAQ,KAClB,aAAa,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CA0BhC,CAAC;AAEL,eAAO,MAAM,QAAQ,cACR,QAAQ,KAClB,aAAa,CAAC,MAAM,GAAG,KAAK,GAAG,MAAM,EAAE,KAAK,EAAE,KAAK,CA4BlD,CAAC;AA6DL,eAAO,MAAM,YAAY,sBAEtB,aAAa,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,CAUjC,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
+ };
@@ -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: <T extends Schema>() => Context.Tag<Evolu<T>, Evolu<T>>;
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: <T extends Schema>(tables: Tables) => Layer.Layer<Config | Bip39 | NanoId | Time | FlushSync | AppState | DbWorker, never, Evolu<T>>;
69
- export declare const makeEvoluForPlatform: <T extends Schema>(PlatformLayer: Layer.Layer<never, never, DbWorker | Bip39 | NanoId | FlushSync | AppState>, tables: Tables, config?: Partial<Config>) => Evolu<T>;
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
@@ -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
@@ -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;AAC/B,OAAO,EAAE,GAAG,EAAa,MAAM,aAAa,CAAC;AAE7C;;;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;AAE/D;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,MAAM,SAAS,CAAC,QAAQ,SAAS,GAAG,EAAE,YAAY,SAAS,GAAG,IAAI,CACtE,GAAG,EAAE,QAAQ,KACV,aAAa,CAAC,YAAY,CAAC,CAAC;AAEjC,MAAM,MAAM,aAAa,CAAC,CAAC,IAAI,CAAC,GAAG,IAAI,GAAG,KAAK,CAAC;AAEhD,MAAM,MAAM,mBAAmB,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,EAAE,IAAI,GAAG,KAAK,CAAC,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.14",
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.5",
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",
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.45.5",
59
- "effect": "2.0.0-next.50"
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<SchemaForQuery<S>>,
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 SchemaForQuery<S extends Schema> = {
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<SchemaForQuery<Schema>> = new 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
- <T extends Schema>(): CreateQuery<T> =>
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 = <T extends Schema>(): Context.Tag<Evolu<T>, Evolu<T>> =>
64
- Context.Tag<Evolu<T>>("evolu/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 = <T extends Schema>(): Context.Tag<Mutate<T>, Mutate<T>> =>
122
- Context.Tag<Mutate<T>>("evolu/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 = <T extends Schema>(): Layer.Layer<
300
+ const MutateLive = <S extends Schema>(): Layer.Layer<
301
301
  NanoId | OnCompletes | Time | SubscribedQueries | LoadingPromises | DbWorker,
302
302
  never,
303
- Mutate<T>
303
+ Mutate<S>
304
304
  > =>
305
305
  Layer.effect(
306
- Mutate<T>(),
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<T>().of((table, { id, ...values }, onComplete) => {
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 = <T extends Schema>(
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<T>
389
+ Evolu<S>
390
390
  > =>
391
391
  Layer.effect(
392
- Evolu<T>(),
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<T>(),
429
- Layer.use(MutateLive<T>(), Layers),
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<T>["ensureSchema"] = (tables) => {
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<T>().of({
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<T>(),
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<T>,
505
- update: mutate as Update<T>,
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 = <T extends Schema>(
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<T> =>
520
+ ): Evolu<S> =>
521
521
  Effect.provide(
522
- Evolu<T>(),
522
+ Evolu<S>(),
523
523
  Layer.use(
524
- EvoluLive<T>(tables),
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 { Row, maybeJson } from "./Sqlite.js";
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>;