@evolu/common 6.0.1-preview.33 → 6.0.1-preview.34
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 +2 -2
- package/dist/src/Array.d.ts +3 -3
- package/dist/src/Array.js +3 -3
- package/dist/src/Crypto.d.ts +6 -8
- package/dist/src/Crypto.d.ts.map +1 -1
- package/dist/src/Crypto.js +9 -9
- package/dist/src/Evolu/Db.d.ts.map +1 -1
- package/dist/src/Evolu/Db.js +4 -4
- package/dist/src/Evolu/Evolu.d.ts +9 -4
- package/dist/src/Evolu/Evolu.d.ts.map +1 -1
- package/dist/src/Evolu/Evolu.js +11 -11
- package/dist/src/Evolu/Protocol.d.ts +24 -1
- package/dist/src/Evolu/Protocol.d.ts.map +1 -1
- package/dist/src/Evolu/Protocol.js +59 -30
- package/dist/src/Evolu/Query.d.ts +1 -1
- package/dist/src/Evolu/Query.d.ts.map +1 -1
- package/dist/src/Evolu/Query.js +1 -1
- package/dist/src/Evolu/Schema.d.ts +24 -20
- package/dist/src/Evolu/Schema.d.ts.map +1 -1
- package/dist/src/Evolu/Schema.js +36 -27
- package/dist/src/Evolu/Storage.d.ts +10 -2
- package/dist/src/Evolu/Storage.d.ts.map +1 -1
- package/dist/src/Evolu/Storage.js +18 -4
- package/dist/src/Evolu/Sync.d.ts +2 -1
- package/dist/src/Evolu/Sync.d.ts.map +1 -1
- package/dist/src/Evolu/Sync.js +45 -33
- package/dist/src/Evolu/Timestamp.d.ts +10 -14
- package/dist/src/Evolu/Timestamp.d.ts.map +1 -1
- package/dist/src/Evolu/Timestamp.js +3 -16
- package/dist/src/Object.d.ts +10 -4
- package/dist/src/Object.d.ts.map +1 -1
- package/dist/src/Object.js +9 -3
- package/dist/src/Type.d.ts +56 -14
- package/dist/src/Type.d.ts.map +1 -1
- package/dist/src/Type.js +57 -31
- package/package.json +2 -2
- package/src/Array.ts +3 -3
- package/src/Crypto.ts +11 -9
- package/src/Evolu/Db.ts +7 -7
- package/src/Evolu/Evolu.ts +21 -20
- package/src/Evolu/Protocol.ts +70 -35
- package/src/Evolu/Query.ts +2 -2
- package/src/Evolu/Schema.ts +44 -32
- package/src/Evolu/Storage.ts +40 -2
- package/src/Evolu/Sync.ts +54 -32
- package/src/Evolu/Timestamp.ts +5 -25
- package/src/Object.ts +13 -5
- package/src/Type.ts +57 -35
|
@@ -2,7 +2,7 @@ import * as Kysely from "kysely";
|
|
|
2
2
|
import { ReadonlyRecord } from "../Object.js";
|
|
3
3
|
import { Result } from "../Result.js";
|
|
4
4
|
import { SqliteBoolean, SqliteDep, SqliteError, SqliteQueryOptions, SqliteValue } from "../Sqlite.js";
|
|
5
|
-
import { AnyType,
|
|
5
|
+
import { AnyType, IdBytes, InferErrors, InferInput, InferType, MergeObjectTypeErrors, NullableToOptionalProps, ObjectType, OptionalType, TableId, Type, ValidMutationSize, ValidMutationSizeError } from "../Type.js";
|
|
6
6
|
import { Simplify } from "../Types.js";
|
|
7
7
|
import { OwnerId } from "./Owner.js";
|
|
8
8
|
import { Query, Row } from "./Query.js";
|
|
@@ -53,13 +53,13 @@ export type EvoluSchema = ReadonlyRecord<string, ReadonlyRecord<string, Type<any
|
|
|
53
53
|
*
|
|
54
54
|
* 1. All tables must have an 'id' column
|
|
55
55
|
* 2. The 'id' column must be a branded ID type (created with id() function)
|
|
56
|
-
* 3. Tables cannot use
|
|
56
|
+
* 3. Tables cannot use system column names (createdAt, updatedAt, isDeleted)
|
|
57
57
|
* 4. All column types must be compatible with SQLite (extend SqliteValue)
|
|
58
58
|
*/
|
|
59
59
|
export type ValidateSchema<S extends EvoluSchema> = ValidateSchemaHasId<S> extends never ? ValidateIdColumnType<S> extends never ? ValidateNoDefaultColumns<S> extends never ? ValidateColumnTypes<S> extends never ? S : ValidateColumnTypes<S> : ValidateNoDefaultColumns<S> : ValidateIdColumnType<S> : ValidateSchemaHasId<S>;
|
|
60
60
|
export type ValidateSchemaHasId<S extends EvoluSchema> = keyof S extends infer TableName ? TableName extends keyof S ? "id" extends keyof S[TableName] ? never : SchemaValidationError<`Table "${TableName & string}" is missing required id column.`> : never : never;
|
|
61
61
|
export type ValidateIdColumnType<S extends EvoluSchema> = keyof S extends infer TableName ? TableName extends keyof S ? "id" extends keyof S[TableName] ? S[TableName]["id"] extends TableId<any> ? never : SchemaValidationError<`Table "${TableName & string}" id column must be a branded ID type (created with id("${TableName & string}")).`> : never : never : never;
|
|
62
|
-
export type ValidateNoDefaultColumns<S extends EvoluSchema> = keyof S extends infer TableName ? TableName extends keyof S ? keyof S[TableName] extends infer ColumnName ? ColumnName extends keyof S[TableName] ? ColumnName extends "createdAt" | "updatedAt" | "isDeleted" ? SchemaValidationError<`Table "${TableName & string}" uses
|
|
62
|
+
export type ValidateNoDefaultColumns<S extends EvoluSchema> = keyof S extends infer TableName ? TableName extends keyof S ? keyof S[TableName] extends infer ColumnName ? ColumnName extends keyof S[TableName] ? ColumnName extends "createdAt" | "updatedAt" | "isDeleted" ? SchemaValidationError<`Table "${TableName & string}" uses system column name "${ColumnName & string}". System columns (createdAt, updatedAt, isDeleted) are added automatically.`> : never : never : never : never : never;
|
|
63
63
|
export type ValidateColumnTypes<S extends EvoluSchema> = keyof S extends infer TableName ? TableName extends keyof S ? keyof S[TableName] extends infer ColumnName ? ColumnName extends keyof S[TableName] ? InferType<S[TableName][ColumnName]> extends SqliteValue ? never : SchemaValidationError<`Table "${TableName & string}" column "${ColumnName & string}" type is not compatible with SQLite. Column types must extend SqliteValue (string, number, Uint8Array, or null).`> : never : never : never : never;
|
|
64
64
|
/** Schema validation error that shows clear, readable messages */
|
|
65
65
|
export type SchemaValidationError<Message extends string> = `❌ Schema Error: ${Message}`;
|
|
@@ -68,7 +68,7 @@ export declare const evoluSchemaToDbSchema: (schema: EvoluSchema, indexesConfig?
|
|
|
68
68
|
export type CreateQuery<S extends EvoluSchema> = <R extends Row>(queryCallback: (db: Pick<Kysely.Kysely<{
|
|
69
69
|
[Table in keyof S]: {
|
|
70
70
|
readonly [Column in keyof S[Table]]: Column extends "id" | "createdAt" | "updatedAt" ? InferType<S[Table][Column]> : InferType<S[Table][Column]> | null;
|
|
71
|
-
} &
|
|
71
|
+
} & SystemColumns;
|
|
72
72
|
} & {
|
|
73
73
|
readonly evolu_history: {
|
|
74
74
|
readonly timestamp: TimestampBytes;
|
|
@@ -79,21 +79,20 @@ export type CreateQuery<S extends EvoluSchema> = <R extends Row>(queryCallback:
|
|
|
79
79
|
};
|
|
80
80
|
}>, "selectFrom" | "fn" | "with" | "withRecursive">) => Kysely.SelectQueryBuilder<any, any, R>, options?: SqliteQueryOptions) => Query<Simplify<R>>;
|
|
81
81
|
/**
|
|
82
|
-
*
|
|
82
|
+
* System columns that are implicitly defined by Evolu.
|
|
83
83
|
*
|
|
84
|
-
* - `createdAt`: Set by Evolu
|
|
85
|
-
*
|
|
86
|
-
* - `
|
|
87
|
-
*
|
|
88
|
-
* preserve real update time.
|
|
89
|
-
* - `isDeleted`: Soft delete flag.
|
|
84
|
+
* - `createdAt`: Set by Evolu on row creation, derived from {@link Timestamp}.
|
|
85
|
+
* - `updatedAt`: Set by Evolu on every row change, derived from {@link Timestamp}.
|
|
86
|
+
* - `isDeleted`: Soft delete flag created by Evolu and used by the developer to
|
|
87
|
+
* mark rows as deleted.
|
|
90
88
|
*/
|
|
91
|
-
export declare const
|
|
89
|
+
export declare const SystemColumns: ObjectType<{
|
|
92
90
|
createdAt: import("../Type.js").BrandType<Type<"String", string, string, import("../Type.js").StringError, string, import("../Type.js").StringError>, "DateIso", import("../Type.js").DateIsoError, import("../Type.js").StringError>;
|
|
93
91
|
updatedAt: import("../Type.js").BrandType<Type<"String", string, string, import("../Type.js").StringError, string, import("../Type.js").StringError>, "DateIso", import("../Type.js").DateIsoError, import("../Type.js").StringError>;
|
|
94
92
|
isDeleted: import("../Type.js").UnionType<[Type<"Null", null, null, import("../Type.js").NullError, null, import("../Type.js").NullError>, import("../Type.js").UnionType<[import("../Type.js").LiteralType<0>, import("../Type.js").LiteralType<1>]>]>;
|
|
95
93
|
}>;
|
|
96
|
-
export type
|
|
94
|
+
export type SystemColumns = typeof SystemColumns.Type;
|
|
95
|
+
export declare const systemColumns: string[];
|
|
97
96
|
export type MutationKind = "insert" | "update" | "upsert";
|
|
98
97
|
export type Mutation<S extends EvoluSchema, Kind extends MutationKind> = <TableName extends keyof S>(table: TableName, props: InferInput<ObjectType<MutationMapping<S[TableName], Kind>>>, options?: MutationOptions) => Result<{
|
|
99
98
|
readonly id: S[TableName]["id"]["Type"];
|
|
@@ -154,7 +153,8 @@ export interface MutationChange extends DbChange {
|
|
|
154
153
|
}
|
|
155
154
|
/**
|
|
156
155
|
* Type Factory to create insertable {@link Type}. It makes nullable Types
|
|
157
|
-
* optional, omits Id, and ensures the
|
|
156
|
+
* optional (so they are not required), omits Id, and ensures the
|
|
157
|
+
* {@link maxMutationSize}.
|
|
158
158
|
*
|
|
159
159
|
* ### Example
|
|
160
160
|
*
|
|
@@ -170,7 +170,7 @@ export type InsertableProps<Props extends Record<string, AnyType>> = Omit<Nullab
|
|
|
170
170
|
export type Insertable<Props extends Record<string, AnyType>> = InferInput<ObjectType<InsertableProps<Props>>>;
|
|
171
171
|
/**
|
|
172
172
|
* Type Factory to create updateable {@link Type}. It makes everything except for
|
|
173
|
-
* the `id` column
|
|
173
|
+
* the `id` column optional (so they are not required) and ensures the
|
|
174
174
|
* {@link maxMutationSize}.
|
|
175
175
|
*
|
|
176
176
|
* ### Example
|
|
@@ -195,9 +195,15 @@ export type UpdateableProps<Props extends Record<string, AnyType>> = {
|
|
|
195
195
|
};
|
|
196
196
|
export type Updateable<Props extends Record<string, AnyType>> = InferInput<ObjectType<UpdateableProps<Props>>>;
|
|
197
197
|
/**
|
|
198
|
-
* Type Factory to create upsertable Type. It makes nullable Types optional
|
|
199
|
-
*
|
|
200
|
-
*
|
|
198
|
+
* Type Factory to create an upsertable Type. It makes nullable Types optional
|
|
199
|
+
* (so they are not required) and ensures the {@link maxMutationSize}.
|
|
200
|
+
*
|
|
201
|
+
* Upsert is like insert, except it requires an ID. It's useful for inserting
|
|
202
|
+
* rows with external ID via {@link createIdFromString}.
|
|
203
|
+
*
|
|
204
|
+
* Note that it's not possible to upsert a row with `createdAt` nor `updatedAt`,
|
|
205
|
+
* because they are derived from {@link CrdtMessage} timestamp. For external
|
|
206
|
+
* createdAt, use a different column.
|
|
201
207
|
*
|
|
202
208
|
* ### Example
|
|
203
209
|
*
|
|
@@ -207,14 +213,12 @@ export type Updateable<Props extends Record<string, AnyType>> = InferInput<Objec
|
|
|
207
213
|
* const todo = UpsertableTodo.from({
|
|
208
214
|
* id,
|
|
209
215
|
* title,
|
|
210
|
-
* createdAt: "2023-01-01T00:00:00.000Z",
|
|
211
216
|
* });
|
|
212
217
|
* if (!todo.ok) return; // handle errors
|
|
213
218
|
* ```
|
|
214
219
|
*/
|
|
215
220
|
export declare const upsertable: <Props extends Record<string, AnyType>>(props: Props) => ValidMutationSize<UpsertableProps<Props>>;
|
|
216
221
|
export type UpsertableProps<Props extends Record<string, AnyType>> = NullableToOptionalProps<Props & {
|
|
217
|
-
createdAt: OptionalType<typeof DateIso>;
|
|
218
222
|
isDeleted: OptionalType<typeof SqliteBoolean>;
|
|
219
223
|
}>;
|
|
220
224
|
export type Upsertable<Props extends Record<string, AnyType>> = InferInput<ObjectType<UpsertableProps<Props>>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Schema.d.ts","sourceRoot":"","sources":["../../../src/Evolu/Schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"Schema.d.ts","sourceRoot":"","sources":["../../../src/Evolu/Schema.ts"],"names":[],"mappings":"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"}
|
package/dist/src/Evolu/Schema.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import * as Kysely from "kysely";
|
|
2
|
+
import { assert } from "../Assert.js";
|
|
3
|
+
import { createEqArrayLike, eqString } from "../Eq.js";
|
|
2
4
|
import { mapObject, objectToEntries } from "../Object.js";
|
|
3
5
|
import { ok } from "../Result.js";
|
|
4
6
|
import { sql, SqliteBoolean, } from "../Sqlite.js";
|
|
@@ -19,23 +21,25 @@ export const evoluSchemaToDbSchema = (schema, indexesConfig) => {
|
|
|
19
21
|
return { tables, indexes };
|
|
20
22
|
};
|
|
21
23
|
/**
|
|
22
|
-
*
|
|
24
|
+
* System columns that are implicitly defined by Evolu.
|
|
23
25
|
*
|
|
24
|
-
* - `createdAt`: Set by Evolu
|
|
25
|
-
*
|
|
26
|
-
* - `
|
|
27
|
-
*
|
|
28
|
-
* preserve real update time.
|
|
29
|
-
* - `isDeleted`: Soft delete flag.
|
|
26
|
+
* - `createdAt`: Set by Evolu on row creation, derived from {@link Timestamp}.
|
|
27
|
+
* - `updatedAt`: Set by Evolu on every row change, derived from {@link Timestamp}.
|
|
28
|
+
* - `isDeleted`: Soft delete flag created by Evolu and used by the developer to
|
|
29
|
+
* mark rows as deleted.
|
|
30
30
|
*/
|
|
31
|
-
export const
|
|
31
|
+
export const SystemColumns = object({
|
|
32
32
|
createdAt: DateIso,
|
|
33
33
|
updatedAt: DateIso,
|
|
34
34
|
isDeleted: nullOr(SqliteBoolean),
|
|
35
|
+
// TODO: ownerId
|
|
35
36
|
});
|
|
37
|
+
export const systemColumns = ["createdAt", "updatedAt", "isDeleted"];
|
|
38
|
+
assert(createEqArrayLike(eqString)(objectToEntries(SystemColumns.props).map(([key]) => key), systemColumns), "SystemColumns keys must match systemColumnsKeys");
|
|
36
39
|
/**
|
|
37
40
|
* Type Factory to create insertable {@link Type}. It makes nullable Types
|
|
38
|
-
* optional, omits Id, and ensures the
|
|
41
|
+
* optional (so they are not required), omits Id, and ensures the
|
|
42
|
+
* {@link maxMutationSize}.
|
|
39
43
|
*
|
|
40
44
|
* ### Example
|
|
41
45
|
*
|
|
@@ -53,7 +57,7 @@ export const insertable = (props) => {
|
|
|
53
57
|
};
|
|
54
58
|
/**
|
|
55
59
|
* Type Factory to create updateable {@link Type}. It makes everything except for
|
|
56
|
-
* the `id` column
|
|
60
|
+
* the `id` column optional (so they are not required) and ensures the
|
|
57
61
|
* {@link maxMutationSize}.
|
|
58
62
|
*
|
|
59
63
|
* ### Example
|
|
@@ -76,9 +80,15 @@ export const updateable = (props) => {
|
|
|
76
80
|
return validMutationSize(object(updateableProps));
|
|
77
81
|
};
|
|
78
82
|
/**
|
|
79
|
-
* Type Factory to create upsertable Type. It makes nullable Types optional
|
|
80
|
-
*
|
|
81
|
-
*
|
|
83
|
+
* Type Factory to create an upsertable Type. It makes nullable Types optional
|
|
84
|
+
* (so they are not required) and ensures the {@link maxMutationSize}.
|
|
85
|
+
*
|
|
86
|
+
* Upsert is like insert, except it requires an ID. It's useful for inserting
|
|
87
|
+
* rows with external ID via {@link createIdFromString}.
|
|
88
|
+
*
|
|
89
|
+
* Note that it's not possible to upsert a row with `createdAt` nor `updatedAt`,
|
|
90
|
+
* because they are derived from {@link CrdtMessage} timestamp. For external
|
|
91
|
+
* createdAt, use a different column.
|
|
82
92
|
*
|
|
83
93
|
* ### Example
|
|
84
94
|
*
|
|
@@ -88,7 +98,6 @@ export const updateable = (props) => {
|
|
|
88
98
|
* const todo = UpsertableTodo.from({
|
|
89
99
|
* id,
|
|
90
100
|
* title,
|
|
91
|
-
* createdAt: "2023-01-01T00:00:00.000Z",
|
|
92
101
|
* });
|
|
93
102
|
* if (!todo.ok) return; // handle errors
|
|
94
103
|
* ```
|
|
@@ -96,7 +105,6 @@ export const updateable = (props) => {
|
|
|
96
105
|
export const upsertable = (props) => {
|
|
97
106
|
const propsWithDefaults = {
|
|
98
107
|
...props,
|
|
99
|
-
createdAt: optional(DateIso),
|
|
100
108
|
isDeleted: optional(SqliteBoolean),
|
|
101
109
|
};
|
|
102
110
|
return validMutationSize(nullableToOptional(propsWithDefaults));
|
|
@@ -166,7 +174,7 @@ export const ensureDbSchema = (deps) => (newSchema, currentSchema, options) => {
|
|
|
166
174
|
const currentTable = currentSchema.tables.find((t) => t.name === newTable.name);
|
|
167
175
|
if (!currentTable) {
|
|
168
176
|
queries.push({
|
|
169
|
-
sql:
|
|
177
|
+
sql: createAppTableWithDefaultColumns(newTable),
|
|
170
178
|
parameters: [],
|
|
171
179
|
});
|
|
172
180
|
}
|
|
@@ -202,20 +210,21 @@ export const ensureDbSchema = (deps) => (newSchema, currentSchema, options) => {
|
|
|
202
210
|
}
|
|
203
211
|
return ok();
|
|
204
212
|
};
|
|
205
|
-
const
|
|
206
|
-
|
|
213
|
+
const createAppTableWithDefaultColumns = (table) => {
|
|
214
|
+
return `
|
|
215
|
+
create table ${sql.identifier(table.name).sql} (
|
|
207
216
|
"id" text primary key,
|
|
208
|
-
${columns
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
.join(", ")}
|
|
217
|
+
${table.columns
|
|
218
|
+
.concat(systemColumns)
|
|
219
|
+
.filter((c) => c !== "id")
|
|
220
|
+
// "A column with affinity BLOB does not prefer one storage class over another
|
|
221
|
+
// and no attempt is made to coerce data from one storage class into another."
|
|
222
|
+
// https://www.sqlite.org/datatype3.html
|
|
223
|
+
.map((name) => `${sql.identifier(name).sql} blob`)
|
|
224
|
+
.join(", ")}
|
|
217
225
|
);
|
|
218
226
|
`;
|
|
227
|
+
};
|
|
219
228
|
// https://kysely.dev/docs/recipes/splitting-query-building-and-execution
|
|
220
229
|
export const kysely = new Kysely.Kysely({
|
|
221
230
|
dialect: {
|
|
@@ -4,7 +4,7 @@ import { RandomDep } from "../Random.js";
|
|
|
4
4
|
import { Result } from "../Result.js";
|
|
5
5
|
import { SqliteDep, SqliteError } from "../Sqlite.js";
|
|
6
6
|
import { MaybeAsync } from "../Task.js";
|
|
7
|
-
import { NonNegativeInt, PositiveInt } from "../Type.js";
|
|
7
|
+
import { NonNegativeInt, PositiveInt, TypeError } from "../Type.js";
|
|
8
8
|
import { BaseOwnerError, OwnerId, OwnerIdBytes, OwnerWriteKey } from "./Owner.js";
|
|
9
9
|
import { Timestamp, TimestampBytes } from "./Timestamp.js";
|
|
10
10
|
export interface StorageConfig {
|
|
@@ -163,6 +163,13 @@ export interface CrdtMessage {
|
|
|
163
163
|
readonly timestamp: Timestamp;
|
|
164
164
|
readonly change: DbChange;
|
|
165
165
|
}
|
|
166
|
+
export declare const DbChangeValues: import("../Type.js").RecordType<"String", string, string, import("../Type.js").StringError, string, import("../Type.js").StringError, import("../Type.js").UnionType<[import("../Type.js").Type<"Null", null, null, import("../Type.js").NullError, null, import("../Type.js").NullError>, import("../Type.js").Type<"String", string, string, import("../Type.js").StringError, string, import("../Type.js").StringError>, import("../Type.js").Type<"Number", number, number, import("../Type.js").NumberError, number, import("../Type.js").NumberError>, import("../Type.js").Type<"Uint8Array", Uint8Array<ArrayBufferLike>, Uint8Array<ArrayBufferLike>, import("../Type.js").Uint8ArrayError, Uint8Array<ArrayBufferLike>, import("../Type.js").Uint8ArrayError>]>>;
|
|
167
|
+
export type DbChangeValues = typeof DbChangeValues.Type;
|
|
168
|
+
export declare const ValidDbChangeValues: import("../Type.js").BrandType<import("../Type.js").RecordType<"String", string, string, import("../Type.js").StringError, string, import("../Type.js").StringError, import("../Type.js").UnionType<[import("../Type.js").Type<"Null", null, null, import("../Type.js").NullError, null, import("../Type.js").NullError>, import("../Type.js").Type<"String", string, string, import("../Type.js").StringError, string, import("../Type.js").StringError>, import("../Type.js").Type<"Number", number, number, import("../Type.js").NumberError, number, import("../Type.js").NumberError>, import("../Type.js").Type<"Uint8Array", Uint8Array<ArrayBufferLike>, Uint8Array<ArrayBufferLike>, import("../Type.js").Uint8ArrayError, Uint8Array<ArrayBufferLike>, import("../Type.js").Uint8ArrayError>]>>, "ValidDbChangeValues", ValidDbChangeValuesError, import("../Type.js").RecordError<import("../Type.js").StringError, never> | import("../Type.js").RecordError<import("../Type.js").StringError, import("../Type.js").UnionError<import("../Type.js").Uint8ArrayError | import("../Type.js").NumberError | import("../Type.js").StringError | import("../Type.js").NullError>>>;
|
|
169
|
+
export type ValidDbChangeValues = typeof ValidDbChangeValues.Type;
|
|
170
|
+
export interface ValidDbChangeValuesError extends TypeError<"ValidDbChangeValues"> {
|
|
171
|
+
readonly invalidColumns: ReadonlyArray<string>;
|
|
172
|
+
}
|
|
166
173
|
/**
|
|
167
174
|
* A DbChange is a change to a table row. Together with a unique
|
|
168
175
|
* {@link Timestamp}, it forms a {@link CrdtMessage}.
|
|
@@ -170,7 +177,8 @@ export interface CrdtMessage {
|
|
|
170
177
|
export declare const DbChange: import("../Type.js").ObjectType<{
|
|
171
178
|
table: import("../Type.js").Type<"String", string, string, import("../Type.js").StringError, string, import("../Type.js").StringError>;
|
|
172
179
|
id: import("../Type.js").BrandType<import("../Type.js").Type<"String", string, string, import("../Type.js").StringError, string, import("../Type.js").StringError>, "Id", import("../Type.js").IdError, import("../Type.js").StringError>;
|
|
173
|
-
values: import("../Type.js").RecordType<"String", string, string, import("../Type.js").StringError, string, import("../Type.js").StringError, import("../Type.js").UnionType<[import("../Type.js").Type<"Null", null, null, import("../Type.js").NullError, null, import("../Type.js").NullError>, import("../Type.js").Type<"String", string, string, import("../Type.js").StringError, string, import("../Type.js").StringError>, import("../Type.js").Type<"Number", number, number, import("../Type.js").NumberError, number, import("../Type.js").NumberError>, import("../Type.js").Type<"Uint8Array", Uint8Array<ArrayBufferLike>, Uint8Array<ArrayBufferLike>, import("../Type.js").Uint8ArrayError, Uint8Array<ArrayBufferLike>, import("../Type.js").Uint8ArrayError>]
|
|
180
|
+
values: import("../Type.js").BrandType<import("../Type.js").RecordType<"String", string, string, import("../Type.js").StringError, string, import("../Type.js").StringError, import("../Type.js").UnionType<[import("../Type.js").Type<"Null", null, null, import("../Type.js").NullError, null, import("../Type.js").NullError>, import("../Type.js").Type<"String", string, string, import("../Type.js").StringError, string, import("../Type.js").StringError>, import("../Type.js").Type<"Number", number, number, import("../Type.js").NumberError, number, import("../Type.js").NumberError>, import("../Type.js").Type<"Uint8Array", Uint8Array<ArrayBufferLike>, Uint8Array<ArrayBufferLike>, import("../Type.js").Uint8ArrayError, Uint8Array<ArrayBufferLike>, import("../Type.js").Uint8ArrayError>]>>, "ValidDbChangeValues", ValidDbChangeValuesError, import("../Type.js").RecordError<import("../Type.js").StringError, never> | import("../Type.js").RecordError<import("../Type.js").StringError, import("../Type.js").UnionError<import("../Type.js").Uint8ArrayError | import("../Type.js").NumberError | import("../Type.js").StringError | import("../Type.js").NullError>>>;
|
|
181
|
+
isInsert: import("../Type.js").Type<"Boolean", boolean, boolean, import("../Type.js").BooleanError, boolean, import("../Type.js").BooleanError>;
|
|
174
182
|
}>;
|
|
175
183
|
export type DbChange = typeof DbChange.Type;
|
|
176
184
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Storage.d.ts","sourceRoot":"","sources":["../../../src/Evolu/Storage.ts"],"names":[],"mappings":"AACA,OAAO,
|
|
1
|
+
{"version":3,"file":"Storage.d.ts","sourceRoot":"","sources":["../../../src/Evolu/Storage.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { sha256 } from "@noble/hashes/sha2.js";
|
|
2
|
-
import { firstInArray, isNonEmptyReadonlyArray, } from "../Array.js";
|
|
2
|
+
import { filterArray, firstInArray, isNonEmptyReadonlyArray, } from "../Array.js";
|
|
3
3
|
import { assert } from "../Assert.js";
|
|
4
4
|
import { concatBytes } from "../Buffer.js";
|
|
5
5
|
import { decrement } from "../Number.js";
|
|
6
|
-
import { ok } from "../Result.js";
|
|
6
|
+
import { err, ok } from "../Result.js";
|
|
7
7
|
import { sql, SqliteValue } from "../Sqlite.js";
|
|
8
|
-
import { Id, NonNegativeInt, object, PositiveInt, record, String, } from "../Type.js";
|
|
8
|
+
import { Boolean, brand, Id, NonNegativeInt, object, PositiveInt, record, String, } from "../Type.js";
|
|
9
9
|
import { orderTimestampBytes } from "./Timestamp.js";
|
|
10
|
+
import { systemColumns } from "./Schema.js";
|
|
10
11
|
export const fingerprintSize = NonNegativeInt.orThrow(12);
|
|
11
12
|
/** A fingerprint of an empty range. */
|
|
12
13
|
export const zeroFingerprint = new Uint8Array(fingerprintSize);
|
|
@@ -16,6 +17,18 @@ export const RangeType = {
|
|
|
16
17
|
Skip: 0,
|
|
17
18
|
Timestamps: 2,
|
|
18
19
|
};
|
|
20
|
+
export const DbChangeValues = record(String, SqliteValue);
|
|
21
|
+
const systemColumnsWithIdAndWithoutIsDeleted = filterArray(systemColumns.concat("id"), (column) => column != "isDeleted");
|
|
22
|
+
export const ValidDbChangeValues = brand("ValidDbChangeValues", DbChangeValues, (value) => {
|
|
23
|
+
const invalidColumns = systemColumnsWithIdAndWithoutIsDeleted.filter((key) => key in value);
|
|
24
|
+
if (invalidColumns.length > 0)
|
|
25
|
+
return err({
|
|
26
|
+
type: "ValidDbChangeValues",
|
|
27
|
+
value,
|
|
28
|
+
invalidColumns,
|
|
29
|
+
});
|
|
30
|
+
return ok(value);
|
|
31
|
+
});
|
|
19
32
|
/**
|
|
20
33
|
* A DbChange is a change to a table row. Together with a unique
|
|
21
34
|
* {@link Timestamp}, it forms a {@link CrdtMessage}.
|
|
@@ -23,7 +36,8 @@ export const RangeType = {
|
|
|
23
36
|
export const DbChange = object({
|
|
24
37
|
table: String,
|
|
25
38
|
id: Id,
|
|
26
|
-
values:
|
|
39
|
+
values: ValidDbChangeValues,
|
|
40
|
+
isInsert: Boolean,
|
|
27
41
|
});
|
|
28
42
|
/**
|
|
29
43
|
* Creates a {@link BaseSqliteStorage} implementation.
|
package/dist/src/Evolu/Sync.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { RandomDep } from "../Random.js";
|
|
|
6
6
|
import { Result } from "../Result.js";
|
|
7
7
|
import { SqliteDep, SqliteError } from "../Sqlite.js";
|
|
8
8
|
import { TimeDep } from "../Time.js";
|
|
9
|
+
import { DateIso } from "../Type.js";
|
|
9
10
|
import { CreateWebSocketDep } from "../WebSocket.js";
|
|
10
11
|
import type { PostMessageDep } from "./Db.js";
|
|
11
12
|
import { AppOwner, OwnerEncryptionKey, OwnerId, OwnerIdBytes, OwnerTransport, OwnerWriteKey } from "./Owner.js";
|
|
@@ -68,7 +69,7 @@ export interface ClientStorageDep {
|
|
|
68
69
|
readonly storage: ClientStorage;
|
|
69
70
|
}
|
|
70
71
|
export declare const applyLocalOnlyChange: (deps: SqliteDep & TimeDep) => (change: MutationChange) => Result<void, SqliteError>;
|
|
71
|
-
export declare const applyMessageToTimestampAndHistoryTables: (deps: ClientStorageDep & SqliteDep) => (ownerId: OwnerIdBytes, message: CrdtMessage, strategy: StorageInsertTimestampStrategy) => Result<void, SqliteError>;
|
|
72
|
+
export declare const applyMessageToTimestampAndHistoryTables: (deps: ClientStorageDep & SqliteDep) => (ownerId: OwnerIdBytes, message: CrdtMessage, strategy: StorageInsertTimestampStrategy, date: DateIso) => Result<void, SqliteError>;
|
|
72
73
|
/**
|
|
73
74
|
* TODO: Rework for the new owners API.
|
|
74
75
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Sync.d.ts","sourceRoot":"","sources":["../../../src/Evolu/Sync.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,qBAAqB,EACtB,MAAM,aAAa,CAAC;AAGrB,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EACL,cAAc,EACd,2BAA2B,EAC3B,kBAAkB,EACnB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAA2B,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAGzE,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,OAAO,EAAW,MAAM,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAO,SAAS,EAAE,WAAW,EAAe,MAAM,cAAc,CAAC;AAExE,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"Sync.d.ts","sourceRoot":"","sources":["../../../src/Evolu/Sync.ts"],"names":[],"mappings":"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"}
|
package/dist/src/Evolu/Sync.js
CHANGED
|
@@ -8,11 +8,11 @@ import { createResources } from "../Resources.js";
|
|
|
8
8
|
import { err, ok } from "../Result.js";
|
|
9
9
|
import { sql } from "../Sqlite.js";
|
|
10
10
|
import { createMutex } from "../Task.js";
|
|
11
|
-
import { idBytesToId, idToIdBytes } from "../Type.js";
|
|
11
|
+
import { idBytesToId, idToIdBytes, } from "../Type.js";
|
|
12
12
|
import { ownerIdBytesToOwnerId, ownerIdToOwnerIdBytes, } from "./Owner.js";
|
|
13
13
|
import { applyProtocolMessageAsClient, createProtocolMessageForSync, createProtocolMessageForUnsubscribe, createProtocolMessageFromCrdtMessages, decryptAndDecodeDbChange, encodeAndEncryptDbChange, SubscriptionFlags, } from "./Protocol.js";
|
|
14
|
-
import { createBaseSqliteStorage, getOwnerUsage, getTimestampInsertStrategy, updateOwnerUsage, } from "./Storage.js";
|
|
15
|
-
import { createInitialTimestamp, receiveTimestamp, sendTimestamp, timestampBytesToTimestamp,
|
|
14
|
+
import { createBaseSqliteStorage, DbChange, getOwnerUsage, getTimestampInsertStrategy, updateOwnerUsage, } from "./Storage.js";
|
|
15
|
+
import { createInitialTimestamp, receiveTimestamp, sendTimestamp, timestampBytesToTimestamp, timestampToDateIso, timestampToTimestampBytes, } from "./Timestamp.js";
|
|
16
16
|
export const createSync = (deps) => (config) => {
|
|
17
17
|
let isDisposed = false;
|
|
18
18
|
/** Returns owner data only if actively assigned to at least one transport. */
|
|
@@ -160,7 +160,10 @@ export const createSync = (deps) => (config) => {
|
|
|
160
160
|
return nextTimestamp;
|
|
161
161
|
clockTimestamp = nextTimestamp.value;
|
|
162
162
|
const { ownerId = config.appOwner.id, ...dbChange } = change;
|
|
163
|
-
const message = {
|
|
163
|
+
const message = {
|
|
164
|
+
timestamp: clockTimestamp,
|
|
165
|
+
change: dbChange,
|
|
166
|
+
};
|
|
164
167
|
const messages = ownerMessages.get(ownerId);
|
|
165
168
|
if (messages)
|
|
166
169
|
messages.push(message);
|
|
@@ -209,9 +212,9 @@ export const createClock = (deps) => (initialTimestamp = createInitialTimestamp(
|
|
|
209
212
|
get: () => currentTimestamp,
|
|
210
213
|
save: (timestamp) => {
|
|
211
214
|
currentTimestamp = timestamp;
|
|
212
|
-
const timestampString = timestampToTimestampString(timestamp);
|
|
213
215
|
const result = deps.sqlite.exec(sql.prepared `
|
|
214
|
-
update evolu_config
|
|
216
|
+
update evolu_config
|
|
217
|
+
set "clock" = ${timestampToTimestampBytes(timestamp)};
|
|
215
218
|
`);
|
|
216
219
|
if (!result.ok)
|
|
217
220
|
return result;
|
|
@@ -306,18 +309,25 @@ const createClientStorage = (deps) => (config) => {
|
|
|
306
309
|
assert(rows.length > 0, "Rows must not be empty");
|
|
307
310
|
const { table, id } = rows[0];
|
|
308
311
|
const values = {};
|
|
312
|
+
let isInsert = false;
|
|
309
313
|
for (const r of rows) {
|
|
310
314
|
assert(r.table === table, "All rows must have the same table");
|
|
311
315
|
assert(eqArrayNumber(r.id, id), "All rows must have the same Id");
|
|
312
|
-
|
|
316
|
+
if (r.column === "createdAt") {
|
|
317
|
+
isInsert = true;
|
|
318
|
+
}
|
|
319
|
+
else {
|
|
320
|
+
values[r.column] = r.value;
|
|
321
|
+
}
|
|
313
322
|
}
|
|
314
323
|
const message = {
|
|
315
324
|
timestamp: timestampBytesToTimestamp(timestamp),
|
|
316
|
-
change: {
|
|
325
|
+
change: DbChange.orThrow({
|
|
317
326
|
table: rows[0].table,
|
|
318
327
|
id: idBytesToId(rows[0].id),
|
|
319
328
|
values,
|
|
320
|
-
|
|
329
|
+
isInsert,
|
|
330
|
+
}),
|
|
321
331
|
};
|
|
322
332
|
return encodeAndEncryptDbChange(deps)(message, owner.encryptionKey);
|
|
323
333
|
},
|
|
@@ -329,31 +339,26 @@ const createTransportKey = (transportConfig) => {
|
|
|
329
339
|
return `${transportConfig.type}:${transportConfig.url}`;
|
|
330
340
|
};
|
|
331
341
|
export const applyLocalOnlyChange = (deps) => (change) => {
|
|
332
|
-
const
|
|
333
|
-
table: change.table,
|
|
334
|
-
id: change.id,
|
|
335
|
-
values: change.values,
|
|
336
|
-
};
|
|
337
|
-
const isDeletion = "isDeleted" in dbChange.values && dbChange.values.isDeleted === 1;
|
|
342
|
+
const isDeletion = "isDeleted" in change.values && change.values.isDeleted === 1;
|
|
338
343
|
if (isDeletion) {
|
|
339
344
|
const result = deps.sqlite.exec(sql `
|
|
340
|
-
delete from ${sql.identifier(
|
|
341
|
-
where id = ${
|
|
345
|
+
delete from ${sql.identifier(change.table)}
|
|
346
|
+
where id = ${change.id};
|
|
342
347
|
`);
|
|
343
348
|
if (!result.ok)
|
|
344
349
|
return result;
|
|
345
350
|
}
|
|
346
351
|
else {
|
|
347
|
-
const
|
|
348
|
-
for (const [column, value] of objectToEntries(
|
|
352
|
+
const now = deps.time.nowIso();
|
|
353
|
+
for (const [column, value] of objectToEntries(change.values)) {
|
|
349
354
|
const result = deps.sqlite.exec(sql.prepared `
|
|
350
|
-
insert into ${sql.identifier(
|
|
355
|
+
insert into ${sql.identifier(change.table)}
|
|
351
356
|
("id", ${sql.identifier(column)}, createdAt, updatedAt)
|
|
352
|
-
values (${
|
|
357
|
+
values (${change.id}, ${value}, ${now}, ${now})
|
|
353
358
|
on conflict ("id") do update
|
|
354
359
|
set
|
|
355
360
|
${sql.identifier(column)} = ${value},
|
|
356
|
-
updatedAt = ${
|
|
361
|
+
updatedAt = ${now};
|
|
357
362
|
`);
|
|
358
363
|
if (!result.ok)
|
|
359
364
|
return result;
|
|
@@ -368,13 +373,14 @@ const applyMessages = (deps) => (ownerId, messages) => {
|
|
|
368
373
|
return usageResult;
|
|
369
374
|
let { firstTimestamp, lastTimestamp } = usageResult.value;
|
|
370
375
|
for (const message of messages) {
|
|
371
|
-
const
|
|
376
|
+
const date = timestampToDateIso(message.timestamp);
|
|
377
|
+
const result1 = applyMessageToAppTable(deps)(ownerIdBytes, message, date);
|
|
372
378
|
if (!result1.ok)
|
|
373
379
|
return result1;
|
|
374
380
|
const timestamp = timestampToTimestampBytes(message.timestamp);
|
|
375
381
|
let strategy;
|
|
376
382
|
[strategy, firstTimestamp, lastTimestamp] = getTimestampInsertStrategy(timestamp, firstTimestamp, lastTimestamp);
|
|
377
|
-
const result2 = applyMessageToTimestampAndHistoryTables(deps)(ownerIdBytes, message, strategy);
|
|
383
|
+
const result2 = applyMessageToTimestampAndHistoryTables(deps)(ownerIdBytes, message, strategy, date);
|
|
378
384
|
if (!result2.ok)
|
|
379
385
|
return result2;
|
|
380
386
|
}
|
|
@@ -389,10 +395,12 @@ const applyMessages = (deps) => (ownerId, messages) => {
|
|
|
389
395
|
return updateUsage;
|
|
390
396
|
return ok();
|
|
391
397
|
};
|
|
392
|
-
const applyMessageToAppTable = (deps) => (ownerId, message) => {
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
398
|
+
const applyMessageToAppTable = (deps) => (ownerId, message, date) => {
|
|
399
|
+
let entries = objectToEntries(message.change.values);
|
|
400
|
+
if (message.change.isInsert) {
|
|
401
|
+
entries = [...entries, ["createdAt", date]];
|
|
402
|
+
}
|
|
403
|
+
for (const [column, value] of entries) {
|
|
396
404
|
const result = deps.sqlite.exec(sql.prepared `
|
|
397
405
|
with
|
|
398
406
|
existingTimestamp as (
|
|
@@ -403,17 +411,17 @@ const applyMessageToAppTable = (deps) => (ownerId, message) => {
|
|
|
403
411
|
and "table" = ${message.change.table}
|
|
404
412
|
and "id" = ${idToIdBytes(message.change.id)}
|
|
405
413
|
and "column" = ${column}
|
|
406
|
-
and "timestamp" >= ${timestamp}
|
|
414
|
+
and "timestamp" >= ${timestampToTimestampBytes(message.timestamp)}
|
|
407
415
|
limit 1
|
|
408
416
|
)
|
|
409
417
|
insert into ${sql.identifier(message.change.table)}
|
|
410
418
|
("id", ${sql.identifier(column)}, updatedAt)
|
|
411
|
-
select ${message.change.id}, ${value}, ${
|
|
419
|
+
select ${message.change.id}, ${value}, ${date}
|
|
412
420
|
where not exists (select 1 from existingTimestamp)
|
|
413
421
|
on conflict ("id") do update
|
|
414
422
|
set
|
|
415
423
|
${sql.identifier(column)} = ${value},
|
|
416
|
-
updatedAt = ${
|
|
424
|
+
updatedAt = ${date}
|
|
417
425
|
where not exists (select 1 from existingTimestamp);
|
|
418
426
|
`);
|
|
419
427
|
if (!result.ok)
|
|
@@ -421,13 +429,17 @@ const applyMessageToAppTable = (deps) => (ownerId, message) => {
|
|
|
421
429
|
}
|
|
422
430
|
return ok();
|
|
423
431
|
};
|
|
424
|
-
export const applyMessageToTimestampAndHistoryTables = (deps) => (ownerId, message, strategy) => {
|
|
432
|
+
export const applyMessageToTimestampAndHistoryTables = (deps) => (ownerId, message, strategy, date) => {
|
|
425
433
|
const timestamp = timestampToTimestampBytes(message.timestamp);
|
|
426
434
|
const id = idToIdBytes(message.change.id);
|
|
427
435
|
const result = deps.storage.insertTimestamp(ownerId, timestamp, strategy);
|
|
428
436
|
if (!result.ok)
|
|
429
437
|
return result;
|
|
430
|
-
|
|
438
|
+
let entries = objectToEntries(message.change.values);
|
|
439
|
+
if (message.change.isInsert) {
|
|
440
|
+
entries = [...entries, ["createdAt", date]];
|
|
441
|
+
}
|
|
442
|
+
for (const [column, value] of entries) {
|
|
431
443
|
const result = deps.sqlite.exec(sql.prepared `
|
|
432
444
|
insert into evolu_history
|
|
433
445
|
("ownerId", "table", "id", "column", "value", "timestamp")
|