@livestore/common 0.0.0-snapshot-909cdd1ac2fd591945c2be2b0f53e14d87f3c9d4
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/.tsbuildinfo +1 -0
- package/dist/__tests__/fixture.d.ts +72 -0
- package/dist/__tests__/fixture.d.ts.map +1 -0
- package/dist/__tests__/fixture.js +16 -0
- package/dist/__tests__/fixture.js.map +1 -0
- package/dist/adapter-types.d.ts +202 -0
- package/dist/adapter-types.d.ts.map +1 -0
- package/dist/adapter-types.js +49 -0
- package/dist/adapter-types.js.map +1 -0
- package/dist/bounded-collections.d.ts +36 -0
- package/dist/bounded-collections.d.ts.map +1 -0
- package/dist/bounded-collections.js +98 -0
- package/dist/bounded-collections.js.map +1 -0
- package/dist/debug-info.d.ts +122 -0
- package/dist/debug-info.d.ts.map +1 -0
- package/dist/debug-info.js +47 -0
- package/dist/debug-info.js.map +1 -0
- package/dist/derived-mutations.d.ts +109 -0
- package/dist/derived-mutations.d.ts.map +1 -0
- package/dist/derived-mutations.js +54 -0
- package/dist/derived-mutations.js.map +1 -0
- package/dist/derived-mutations.test.d.ts +2 -0
- package/dist/derived-mutations.test.d.ts.map +1 -0
- package/dist/derived-mutations.test.js +93 -0
- package/dist/derived-mutations.test.js.map +1 -0
- package/dist/devtools/devtools-bridge.d.ts +12 -0
- package/dist/devtools/devtools-bridge.d.ts.map +1 -0
- package/dist/devtools/devtools-bridge.js +2 -0
- package/dist/devtools/devtools-bridge.js.map +1 -0
- package/dist/devtools/devtools-messages.d.ts +705 -0
- package/dist/devtools/devtools-messages.d.ts.map +1 -0
- package/dist/devtools/devtools-messages.js +178 -0
- package/dist/devtools/devtools-messages.js.map +1 -0
- package/dist/devtools/devtools-window-message.d.ts +29 -0
- package/dist/devtools/devtools-window-message.d.ts.map +1 -0
- package/dist/devtools/devtools-window-message.js +33 -0
- package/dist/devtools/devtools-window-message.js.map +1 -0
- package/dist/devtools/index.d.ts +42 -0
- package/dist/devtools/index.d.ts.map +1 -0
- package/dist/devtools/index.js +49 -0
- package/dist/devtools/index.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/init-singleton-tables.d.ts +4 -0
- package/dist/init-singleton-tables.d.ts.map +1 -0
- package/dist/init-singleton-tables.js +16 -0
- package/dist/init-singleton-tables.js.map +1 -0
- package/dist/mutation.d.ts +13 -0
- package/dist/mutation.d.ts.map +1 -0
- package/dist/mutation.js +43 -0
- package/dist/mutation.js.map +1 -0
- package/dist/query-info.d.ts +47 -0
- package/dist/query-info.d.ts.map +1 -0
- package/dist/query-info.js +38 -0
- package/dist/query-info.js.map +1 -0
- package/dist/rehydrate-from-mutationlog.d.ts +14 -0
- package/dist/rehydrate-from-mutationlog.d.ts.map +1 -0
- package/dist/rehydrate-from-mutationlog.js +72 -0
- package/dist/rehydrate-from-mutationlog.js.map +1 -0
- package/dist/schema/index.d.ts +60 -0
- package/dist/schema/index.d.ts.map +1 -0
- package/dist/schema/index.js +66 -0
- package/dist/schema/index.js.map +1 -0
- package/dist/schema/mutations.d.ts +227 -0
- package/dist/schema/mutations.d.ts.map +1 -0
- package/dist/schema/mutations.js +68 -0
- package/dist/schema/mutations.js.map +1 -0
- package/dist/schema/schema-helpers.d.ts +4 -0
- package/dist/schema/schema-helpers.d.ts.map +1 -0
- package/dist/schema/schema-helpers.js +30 -0
- package/dist/schema/schema-helpers.js.map +1 -0
- package/dist/schema/system-tables.d.ts +331 -0
- package/dist/schema/system-tables.d.ts.map +1 -0
- package/dist/schema/system-tables.js +46 -0
- package/dist/schema/system-tables.js.map +1 -0
- package/dist/schema/table-def.d.ts +135 -0
- package/dist/schema/table-def.d.ts.map +1 -0
- package/dist/schema/table-def.js +70 -0
- package/dist/schema/table-def.js.map +1 -0
- package/dist/schema-management/common.d.ts +13 -0
- package/dist/schema-management/common.d.ts.map +1 -0
- package/dist/schema-management/common.js +25 -0
- package/dist/schema-management/common.js.map +1 -0
- package/dist/schema-management/migrations.d.ts +23 -0
- package/dist/schema-management/migrations.d.ts.map +1 -0
- package/dist/schema-management/migrations.js +116 -0
- package/dist/schema-management/migrations.js.map +1 -0
- package/dist/schema-management/validate-mutation-defs.d.ts +8 -0
- package/dist/schema-management/validate-mutation-defs.d.ts.map +1 -0
- package/dist/schema-management/validate-mutation-defs.js +39 -0
- package/dist/schema-management/validate-mutation-defs.js.map +1 -0
- package/dist/sql-queries/index.d.ts +4 -0
- package/dist/sql-queries/index.d.ts.map +1 -0
- package/dist/sql-queries/index.js +4 -0
- package/dist/sql-queries/index.js.map +1 -0
- package/dist/sql-queries/misc.d.ts +2 -0
- package/dist/sql-queries/misc.d.ts.map +1 -0
- package/dist/sql-queries/misc.js +2 -0
- package/dist/sql-queries/misc.js.map +1 -0
- package/dist/sql-queries/sql-queries.d.ts +72 -0
- package/dist/sql-queries/sql-queries.d.ts.map +1 -0
- package/dist/sql-queries/sql-queries.js +191 -0
- package/dist/sql-queries/sql-queries.js.map +1 -0
- package/dist/sql-queries/sql-query-builder.d.ts +47 -0
- package/dist/sql-queries/sql-query-builder.d.ts.map +1 -0
- package/dist/sql-queries/sql-query-builder.js +60 -0
- package/dist/sql-queries/sql-query-builder.js.map +1 -0
- package/dist/sql-queries/types.d.ts +50 -0
- package/dist/sql-queries/types.d.ts.map +1 -0
- package/dist/sql-queries/types.js +5 -0
- package/dist/sql-queries/types.js.map +1 -0
- package/dist/sync/index.d.ts +2 -0
- package/dist/sync/index.d.ts.map +1 -0
- package/dist/sync/index.js +2 -0
- package/dist/sync/index.js.map +1 -0
- package/dist/sync/next/compact-events.d.ts +15 -0
- package/dist/sync/next/compact-events.d.ts.map +1 -0
- package/dist/sync/next/compact-events.js +176 -0
- package/dist/sync/next/compact-events.js.map +1 -0
- package/dist/sync/next/facts.d.ts +37 -0
- package/dist/sync/next/facts.d.ts.map +1 -0
- package/dist/sync/next/facts.js +156 -0
- package/dist/sync/next/facts.js.map +1 -0
- package/dist/sync/next/graphology.d.ts +8 -0
- package/dist/sync/next/graphology.d.ts.map +1 -0
- package/dist/sync/next/graphology.js +36 -0
- package/dist/sync/next/graphology.js.map +1 -0
- package/dist/sync/next/graphology_.d.ts +3 -0
- package/dist/sync/next/graphology_.d.ts.map +1 -0
- package/dist/sync/next/graphology_.js +3 -0
- package/dist/sync/next/graphology_.js.map +1 -0
- package/dist/sync/next/history-dag.d.ts +30 -0
- package/dist/sync/next/history-dag.d.ts.map +1 -0
- package/dist/sync/next/history-dag.js +69 -0
- package/dist/sync/next/history-dag.js.map +1 -0
- package/dist/sync/next/mod.d.ts +5 -0
- package/dist/sync/next/mod.d.ts.map +1 -0
- package/dist/sync/next/mod.js +5 -0
- package/dist/sync/next/mod.js.map +1 -0
- package/dist/sync/next/rebase-events.d.ts +27 -0
- package/dist/sync/next/rebase-events.d.ts.map +1 -0
- package/dist/sync/next/rebase-events.js +41 -0
- package/dist/sync/next/rebase-events.js.map +1 -0
- package/dist/sync/next/test/compact-events.calculator.test.d.ts +2 -0
- package/dist/sync/next/test/compact-events.calculator.test.d.ts.map +1 -0
- package/dist/sync/next/test/compact-events.calculator.test.js +101 -0
- package/dist/sync/next/test/compact-events.calculator.test.js.map +1 -0
- package/dist/sync/next/test/compact-events.test.d.ts +2 -0
- package/dist/sync/next/test/compact-events.test.d.ts.map +1 -0
- package/dist/sync/next/test/compact-events.test.js +201 -0
- package/dist/sync/next/test/compact-events.test.js.map +1 -0
- package/dist/sync/next/test/mod.d.ts +2 -0
- package/dist/sync/next/test/mod.d.ts.map +1 -0
- package/dist/sync/next/test/mod.js +2 -0
- package/dist/sync/next/test/mod.js.map +1 -0
- package/dist/sync/next/test/mutation-fixtures.d.ts +73 -0
- package/dist/sync/next/test/mutation-fixtures.d.ts.map +1 -0
- package/dist/sync/next/test/mutation-fixtures.js +161 -0
- package/dist/sync/next/test/mutation-fixtures.js.map +1 -0
- package/dist/sync/sync.d.ts +45 -0
- package/dist/sync/sync.d.ts.map +1 -0
- package/dist/sync/sync.js +12 -0
- package/dist/sync/sync.js.map +1 -0
- package/dist/util.d.ts +25 -0
- package/dist/util.d.ts.map +1 -0
- package/dist/util.js +38 -0
- package/dist/util.js.map +1 -0
- package/dist/version.d.ts +10 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +12 -0
- package/dist/version.js.map +1 -0
- package/package.json +61 -0
- package/src/__tests__/fixture.ts +23 -0
- package/src/adapter-types.ts +216 -0
- package/src/ambient.d.ts +3 -0
- package/src/bounded-collections.ts +121 -0
- package/src/debug-info.ts +76 -0
- package/src/derived-mutations.test.ts +101 -0
- package/src/derived-mutations.ts +170 -0
- package/src/devtools/devtools-bridge.ts +13 -0
- package/src/devtools/devtools-messages.ts +247 -0
- package/src/devtools/devtools-window-message.ts +27 -0
- package/src/devtools/index.ts +49 -0
- package/src/index.ts +20 -0
- package/src/init-singleton-tables.ts +24 -0
- package/src/mutation.ts +69 -0
- package/src/query-info.ts +104 -0
- package/src/rehydrate-from-mutationlog.ts +131 -0
- package/src/schema/index.ts +144 -0
- package/src/schema/mutations.ts +313 -0
- package/src/schema/schema-helpers.ts +49 -0
- package/src/schema/system-tables.ts +84 -0
- package/src/schema/table-def.ts +312 -0
- package/src/schema-management/common.ts +44 -0
- package/src/schema-management/migrations.ts +188 -0
- package/src/schema-management/validate-mutation-defs.ts +63 -0
- package/src/sql-queries/index.ts +3 -0
- package/src/sql-queries/misc.ts +2 -0
- package/src/sql-queries/sql-queries.ts +359 -0
- package/src/sql-queries/sql-query-builder.ts +135 -0
- package/src/sql-queries/types.ts +97 -0
- package/src/sync/index.ts +1 -0
- package/src/sync/next/ambient.d.ts +3 -0
- package/src/sync/next/compact-events.ts +218 -0
- package/src/sync/next/facts.ts +229 -0
- package/src/sync/next/graphology.ts +49 -0
- package/src/sync/next/graphology_.ts +2 -0
- package/src/sync/next/history-dag.ts +109 -0
- package/src/sync/next/mod.ts +4 -0
- package/src/sync/next/rebase-events.ts +97 -0
- package/src/sync/next/test/compact-events.calculator.test.ts +121 -0
- package/src/sync/next/test/compact-events.test.ts +232 -0
- package/src/sync/next/test/mod.ts +1 -0
- package/src/sync/next/test/mutation-fixtures.ts +230 -0
- package/src/sync/sync.ts +46 -0
- package/src/util.ts +56 -0
- package/src/version.ts +13 -0
- package/tsconfig.json +11 -0
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
import type { Nullable, PrettifyFlat } from '@livestore/db-schema'
|
|
2
|
+
import { SqliteDsl } from '@livestore/db-schema'
|
|
3
|
+
import { shouldNeverHappen } from '@livestore/utils'
|
|
4
|
+
import { ReadonlyRecord, Schema } from '@livestore/utils/effect'
|
|
5
|
+
|
|
6
|
+
import type { DerivedMutationHelperFns } from '../derived-mutations.js'
|
|
7
|
+
import { makeDerivedMutationDefsForTable } from '../derived-mutations.js'
|
|
8
|
+
|
|
9
|
+
export const { blob, boolean, column, datetime, integer, isColumnDefinition, json, real, text } = SqliteDsl
|
|
10
|
+
|
|
11
|
+
export { type SqliteDsl } from '@livestore/db-schema'
|
|
12
|
+
|
|
13
|
+
export type StateType = 'singleton' | 'dynamic'
|
|
14
|
+
|
|
15
|
+
export type DefaultSqliteTableDef = SqliteDsl.TableDefinition<string, SqliteDsl.Columns>
|
|
16
|
+
export type DefaultSqliteTableDefConstrained = SqliteDsl.TableDefinition<string, SqliteDsl.ConstraintColumns>
|
|
17
|
+
|
|
18
|
+
// export type TableDefConstraint<
|
|
19
|
+
// TSqliteDef extends DefaultSqliteTableDef = DefaultSqliteTableDef,
|
|
20
|
+
// TIsSingleColumn extends boolean = boolean,
|
|
21
|
+
// TOptions extends TableOptions = TableOptions,
|
|
22
|
+
// > = TableDefBase<TSqliteDef, TIsSingleColumn, TOptions> & { schema: Schema.Schema<any> }
|
|
23
|
+
|
|
24
|
+
// /**
|
|
25
|
+
// * NOTE in the past we used to have a single `TableDef` but there are some TS issues when indroducing
|
|
26
|
+
// * `schema: SqliteDsl.StructSchemaForColumns<TSqliteDef>` so we split it into two types
|
|
27
|
+
// * and only use `TableDefConstraint` in some places
|
|
28
|
+
// */
|
|
29
|
+
// export type TableDefBase<
|
|
30
|
+
// TSqliteDef extends DefaultSqliteTableDef = DefaultSqliteTableDef,
|
|
31
|
+
// TIsSingleColumn extends boolean = boolean,
|
|
32
|
+
// TOptions extends TableOptions = TableOptions,
|
|
33
|
+
// > = {
|
|
34
|
+
// sqliteDef: TSqliteDef
|
|
35
|
+
// // schema: SqliteDsl.StructSchemaForColumns<TSqliteDef>
|
|
36
|
+
// // schema: any;
|
|
37
|
+
// isSingleColumn: TIsSingleColumn
|
|
38
|
+
// options: TOptions
|
|
39
|
+
// }
|
|
40
|
+
|
|
41
|
+
export type TableDef<
|
|
42
|
+
TSqliteDef extends DefaultSqliteTableDef = DefaultSqliteTableDefConstrained,
|
|
43
|
+
TIsSingleColumn extends boolean = boolean,
|
|
44
|
+
TOptions extends TableOptions = TableOptions,
|
|
45
|
+
// NOTE we're not using `SqliteDsl.StructSchemaForColumns<TSqliteDef['columns']>`
|
|
46
|
+
// as we don't want the alias type for users to show up
|
|
47
|
+
TSchema = Schema.Schema<
|
|
48
|
+
SqliteDsl.AnyIfConstained<
|
|
49
|
+
TSqliteDef['columns'],
|
|
50
|
+
{ readonly [K in keyof TSqliteDef['columns']]: Schema.Schema.Type<TSqliteDef['columns'][K]['schema']> }
|
|
51
|
+
>,
|
|
52
|
+
SqliteDsl.AnyIfConstained<
|
|
53
|
+
TSqliteDef['columns'],
|
|
54
|
+
{ readonly [K in keyof TSqliteDef['columns']]: Schema.Schema.Encoded<TSqliteDef['columns'][K]['schema']> }
|
|
55
|
+
>
|
|
56
|
+
>,
|
|
57
|
+
> = {
|
|
58
|
+
sqliteDef: TSqliteDef
|
|
59
|
+
// TODO move this into options (for now it's duplicated)
|
|
60
|
+
isSingleColumn: TIsSingleColumn
|
|
61
|
+
options: TOptions
|
|
62
|
+
schema: TSchema
|
|
63
|
+
} & (TOptions['deriveMutations']['enabled'] extends true
|
|
64
|
+
? DerivedMutationHelperFns<TSqliteDef['columns'], TOptions>
|
|
65
|
+
: {})
|
|
66
|
+
|
|
67
|
+
export type TableOptionsInput = Partial<
|
|
68
|
+
Omit<TableOptions, 'isSingleColumn' | 'deriveMutations'> & {
|
|
69
|
+
indexes: SqliteDsl.Index[]
|
|
70
|
+
deriveMutations:
|
|
71
|
+
| boolean
|
|
72
|
+
| {
|
|
73
|
+
enabled: true
|
|
74
|
+
localOnly?: boolean
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
>
|
|
78
|
+
|
|
79
|
+
export type TableOptions = {
|
|
80
|
+
/**
|
|
81
|
+
* Setting this to true will have the following consequences:
|
|
82
|
+
* - An `id` column will be added with `primaryKey: true` and `"singleton"` as default value and only allowed value
|
|
83
|
+
* - LiveStore will automatically create the singleton row when booting up
|
|
84
|
+
* - LiveStore will fail if there is already a column defined with `primaryKey: true`
|
|
85
|
+
*
|
|
86
|
+
* @default false
|
|
87
|
+
*/
|
|
88
|
+
isSingleton: boolean
|
|
89
|
+
disableAutomaticIdColumn: boolean
|
|
90
|
+
/**
|
|
91
|
+
* Setting this to true will automatically derive insert, update and delete mutations for this table. Example:
|
|
92
|
+
*
|
|
93
|
+
* ```ts
|
|
94
|
+
* const todos = table('todos', { ... }, { deriveMutations: true })
|
|
95
|
+
* todos.insert({ id: '1', text: 'Hello' })
|
|
96
|
+
* ```
|
|
97
|
+
*
|
|
98
|
+
* This is also a prerequisite for using the `useRow`, `useAtom` and `rowQuery` APIs.
|
|
99
|
+
*
|
|
100
|
+
* Important: When using this option, make sure you're following the "Rules of mutations" for the table schema.
|
|
101
|
+
*/
|
|
102
|
+
deriveMutations:
|
|
103
|
+
| { enabled: false }
|
|
104
|
+
| {
|
|
105
|
+
enabled: true
|
|
106
|
+
/**
|
|
107
|
+
* When set to true, the mutations won't be synced over the network
|
|
108
|
+
*/
|
|
109
|
+
localOnly: boolean
|
|
110
|
+
}
|
|
111
|
+
/** Derived based on whether the table definition has one or more columns (besides the `id` column) */
|
|
112
|
+
isSingleColumn: boolean
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export const table = <
|
|
116
|
+
TName extends string,
|
|
117
|
+
TColumns extends SqliteDsl.Columns | SqliteDsl.ColumnDefinition<any, any>,
|
|
118
|
+
const TOptionsInput extends TableOptionsInput = TableOptionsInput,
|
|
119
|
+
>(
|
|
120
|
+
name: TName,
|
|
121
|
+
columnOrColumns: TColumns,
|
|
122
|
+
options?: TOptionsInput,
|
|
123
|
+
): TableDef<
|
|
124
|
+
SqliteDsl.TableDefinition<
|
|
125
|
+
TName,
|
|
126
|
+
PrettifyFlat<
|
|
127
|
+
WithId<
|
|
128
|
+
TColumns extends SqliteDsl.Columns ? TColumns : { value: TColumns },
|
|
129
|
+
WithDefaults<TOptionsInput, SqliteDsl.IsSingleColumn<TColumns>>
|
|
130
|
+
>
|
|
131
|
+
>
|
|
132
|
+
>,
|
|
133
|
+
SqliteDsl.IsSingleColumn<TColumns>,
|
|
134
|
+
WithDefaults<TOptionsInput, SqliteDsl.IsSingleColumn<TColumns>>
|
|
135
|
+
> => {
|
|
136
|
+
const tablePath = name
|
|
137
|
+
|
|
138
|
+
const options_: TableOptions = {
|
|
139
|
+
isSingleton: options?.isSingleton ?? false,
|
|
140
|
+
disableAutomaticIdColumn: options?.disableAutomaticIdColumn ?? false,
|
|
141
|
+
deriveMutations:
|
|
142
|
+
options?.deriveMutations === true
|
|
143
|
+
? { enabled: true as const, localOnly: false }
|
|
144
|
+
: options?.deriveMutations === false
|
|
145
|
+
? { enabled: false as const }
|
|
146
|
+
: options?.deriveMutations === undefined
|
|
147
|
+
? { enabled: false as const }
|
|
148
|
+
: { enabled: true as const, localOnly: options.deriveMutations.localOnly ?? false },
|
|
149
|
+
isSingleColumn: SqliteDsl.isColumnDefinition(columnOrColumns) === true,
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const columns = (
|
|
153
|
+
SqliteDsl.isColumnDefinition(columnOrColumns) ? { value: columnOrColumns } : columnOrColumns
|
|
154
|
+
) as SqliteDsl.Columns
|
|
155
|
+
|
|
156
|
+
if (options_.disableAutomaticIdColumn === true) {
|
|
157
|
+
if (columns.id === undefined && options_.isSingleton === true) {
|
|
158
|
+
shouldNeverHappen(
|
|
159
|
+
`Cannot create table ${name} with "isSingleton: true" because there is no column with name "id" and "disableAutomaticIdColumn: true" is set`,
|
|
160
|
+
)
|
|
161
|
+
}
|
|
162
|
+
} else if (columns.id === undefined && ReadonlyRecord.some(columns, (_) => _.primaryKey === true) === false) {
|
|
163
|
+
if (options_.isSingleton) {
|
|
164
|
+
columns.id = SqliteDsl.text({ schema: Schema.Literal('singleton'), primaryKey: true, default: 'singleton' })
|
|
165
|
+
} else {
|
|
166
|
+
columns.id = SqliteDsl.text({ primaryKey: true })
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const sqliteDef = SqliteDsl.table(tablePath, columns, options?.indexes ?? [])
|
|
171
|
+
|
|
172
|
+
// TODO also enforce this on the type level
|
|
173
|
+
if (options_.isSingleton) {
|
|
174
|
+
for (const column of sqliteDef.ast.columns) {
|
|
175
|
+
if (column.nullable === false && column.default._tag === 'None') {
|
|
176
|
+
shouldNeverHappen(
|
|
177
|
+
`When creating a singleton table, each column must be either nullable or have a default value. Column '${column.name}' is neither.`,
|
|
178
|
+
)
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const isSingleColumn = SqliteDsl.isColumnDefinition(columnOrColumns) === true
|
|
184
|
+
|
|
185
|
+
const schema = SqliteDsl.structSchemaForTable(sqliteDef)
|
|
186
|
+
const tableDef = { sqliteDef, isSingleColumn, options: options_, schema } satisfies TableDef
|
|
187
|
+
|
|
188
|
+
if (tableHasDerivedMutations(tableDef)) {
|
|
189
|
+
const derivedMutationDefs = makeDerivedMutationDefsForTable(tableDef)
|
|
190
|
+
|
|
191
|
+
tableDef.insert = (valuesOrValue: any) => {
|
|
192
|
+
if (isSingleColumn && options_.isSingleton) {
|
|
193
|
+
return derivedMutationDefs.insert({ id: 'singleton', value: { value: valuesOrValue } })
|
|
194
|
+
} else {
|
|
195
|
+
return derivedMutationDefs.insert(valuesOrValue as any)
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
tableDef.update = (argsOrValues: any) => {
|
|
200
|
+
if (isSingleColumn && options_.isSingleton) {
|
|
201
|
+
return derivedMutationDefs.update({ where: { id: 'singleton' }, values: { value: argsOrValues } as any })
|
|
202
|
+
} else {
|
|
203
|
+
return derivedMutationDefs.update(argsOrValues as any)
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
tableDef.delete = (args: any) => derivedMutationDefs.delete(args)
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return tableDef as any
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export const tableHasDerivedMutations = <TTableDef extends TableDef>(
|
|
214
|
+
tableDef: TTableDef,
|
|
215
|
+
): tableDef is TTableDef & {
|
|
216
|
+
options: { deriveMutations: { enabled: true; localOnly: boolean } }
|
|
217
|
+
} & DerivedMutationHelperFns<TTableDef['sqliteDef']['columns'], TTableDef['options']> =>
|
|
218
|
+
tableDef.options.deriveMutations.enabled === true
|
|
219
|
+
|
|
220
|
+
export const tableIsSingleton = <TTableDef extends TableDef>(
|
|
221
|
+
tableDef: TTableDef,
|
|
222
|
+
): tableDef is TTableDef & { options: { isSingleton: true } } => tableDef.options.isSingleton === true
|
|
223
|
+
|
|
224
|
+
type WithId<TColumns extends SqliteDsl.Columns, TOptions extends TableOptions> = TColumns &
|
|
225
|
+
('id' extends keyof TColumns
|
|
226
|
+
? {}
|
|
227
|
+
: TOptions['disableAutomaticIdColumn'] extends true
|
|
228
|
+
? {}
|
|
229
|
+
: TOptions['isSingleton'] extends true
|
|
230
|
+
? {
|
|
231
|
+
id: SqliteDsl.ColumnDefinition<'singleton', 'singleton'>
|
|
232
|
+
}
|
|
233
|
+
: {
|
|
234
|
+
id: SqliteDsl.ColumnDefinition<string, string>
|
|
235
|
+
})
|
|
236
|
+
|
|
237
|
+
type WithDefaults<TOptionsInput extends TableOptionsInput, TIsSingleColumn extends boolean> = {
|
|
238
|
+
isSingleton: TOptionsInput['isSingleton'] extends true ? true : false
|
|
239
|
+
disableAutomaticIdColumn: TOptionsInput['disableAutomaticIdColumn'] extends true ? true : false
|
|
240
|
+
deriveMutations: TOptionsInput['deriveMutations'] extends true
|
|
241
|
+
? { enabled: true; localOnly: boolean }
|
|
242
|
+
: TOptionsInput['deriveMutations'] extends false
|
|
243
|
+
? { enabled: false }
|
|
244
|
+
: TOptionsInput['deriveMutations'] extends { enabled: true; localOnly?: boolean }
|
|
245
|
+
? {
|
|
246
|
+
enabled: true
|
|
247
|
+
localOnly: TOptionsInput['deriveMutations']['localOnly'] extends true ? true : false
|
|
248
|
+
}
|
|
249
|
+
: never
|
|
250
|
+
isSingleColumn: TIsSingleColumn
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
export namespace FromTable {
|
|
254
|
+
// TODO this sometimes doesn't preserve the order of columns
|
|
255
|
+
export type RowDecoded<TTableDef extends TableDef> = PrettifyFlat<
|
|
256
|
+
Nullable<Pick<RowDecodedAll<TTableDef>, NullableColumnNames<TTableDef>>> &
|
|
257
|
+
Omit<RowDecodedAll<TTableDef>, NullableColumnNames<TTableDef>>
|
|
258
|
+
>
|
|
259
|
+
|
|
260
|
+
export type NullableColumnNames<TTableDef extends TableDef> = FromColumns.NullableColumnNames<
|
|
261
|
+
TTableDef['sqliteDef']['columns']
|
|
262
|
+
>
|
|
263
|
+
|
|
264
|
+
export type Columns<TTableDef extends TableDef> = {
|
|
265
|
+
[K in keyof TTableDef['sqliteDef']['columns']]: TTableDef['sqliteDef']['columns'][K]['columnType']
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
export type RowEncodeNonNullable<TTableDef extends TableDef> = {
|
|
269
|
+
[K in keyof TTableDef['sqliteDef']['columns']]: Schema.Schema.Encoded<
|
|
270
|
+
TTableDef['sqliteDef']['columns'][K]['schema']
|
|
271
|
+
>
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
export type RowEncoded<TTableDef extends TableDef> = PrettifyFlat<
|
|
275
|
+
Nullable<Pick<RowEncodeNonNullable<TTableDef>, NullableColumnNames<TTableDef>>> &
|
|
276
|
+
Omit<RowEncodeNonNullable<TTableDef>, NullableColumnNames<TTableDef>>
|
|
277
|
+
>
|
|
278
|
+
|
|
279
|
+
export type RowDecodedAll<TTableDef extends TableDef> = {
|
|
280
|
+
[K in keyof TTableDef['sqliteDef']['columns']]: Schema.Schema.Type<TTableDef['sqliteDef']['columns'][K]['schema']>
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
export namespace FromColumns {
|
|
285
|
+
// TODO this sometimes doesn't preserve the order of columns
|
|
286
|
+
export type RowDecoded<TColumns extends SqliteDsl.Columns> = PrettifyFlat<
|
|
287
|
+
Nullable<Pick<RowDecodedAll<TColumns>, NullableColumnNames<TColumns>>> &
|
|
288
|
+
Omit<RowDecodedAll<TColumns>, NullableColumnNames<TColumns>>
|
|
289
|
+
>
|
|
290
|
+
|
|
291
|
+
export type RowDecodedAll<TColumns extends SqliteDsl.Columns> = {
|
|
292
|
+
[K in keyof TColumns]: Schema.Schema.Type<TColumns[K]['schema']>
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
export type RowEncoded<TColumns extends SqliteDsl.Columns> = PrettifyFlat<
|
|
296
|
+
Nullable<Pick<RowEncodeNonNullable<TColumns>, NullableColumnNames<TColumns>>> &
|
|
297
|
+
Omit<RowEncodeNonNullable<TColumns>, NullableColumnNames<TColumns>>
|
|
298
|
+
>
|
|
299
|
+
|
|
300
|
+
export type RowEncodeNonNullable<TColumns extends SqliteDsl.Columns> = {
|
|
301
|
+
[K in keyof TColumns]: Schema.Schema.Encoded<TColumns[K]['schema']>
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
export type NullableColumnNames<TColumns extends SqliteDsl.Columns> = keyof {
|
|
305
|
+
[K in keyof TColumns as TColumns[K]['default'] extends true ? K : never]: {}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
export type RequiredInsertColumnNames<TColumns extends SqliteDsl.Columns> =
|
|
309
|
+
SqliteDsl.FromColumns.RequiredInsertColumnNames<TColumns>
|
|
310
|
+
|
|
311
|
+
export type InsertRowDecoded<TColumns extends SqliteDsl.Columns> = SqliteDsl.FromColumns.InsertRowDecoded<TColumns>
|
|
312
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { SynchronousDatabase } from '../adapter-types.js'
|
|
2
|
+
import type { ParamsObject } from '../util.js'
|
|
3
|
+
import { prepareBindValues } from '../util.js'
|
|
4
|
+
|
|
5
|
+
// TODO bring back statement caching
|
|
6
|
+
// will require proper scope-aware cleanup etc (for testing and apps with multiple LiveStore instances)
|
|
7
|
+
// const cachedStmts = new Map<string, PreparedStatement>()
|
|
8
|
+
|
|
9
|
+
export const dbExecute = (db: SynchronousDatabase, queryStr: string, bindValues?: ParamsObject) => {
|
|
10
|
+
// let stmt = cachedStmts.get(queryStr)
|
|
11
|
+
// if (!stmt) {
|
|
12
|
+
const stmt = db.prepare(queryStr)
|
|
13
|
+
// cachedStmts.set(queryStr, stmt)
|
|
14
|
+
// }
|
|
15
|
+
|
|
16
|
+
const preparedBindValues = bindValues ? prepareBindValues(bindValues, queryStr) : undefined
|
|
17
|
+
|
|
18
|
+
stmt.execute(preparedBindValues)
|
|
19
|
+
|
|
20
|
+
stmt.finalize()
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const dbSelect = <T>(db: SynchronousDatabase, queryStr: string, bindValues?: ParamsObject) => {
|
|
24
|
+
// let stmt = cachedStmts.get(queryStr)
|
|
25
|
+
// if (!stmt) {
|
|
26
|
+
const stmt = db.prepare(queryStr)
|
|
27
|
+
// cachedStmts.set(queryStr, stmt)
|
|
28
|
+
// }
|
|
29
|
+
|
|
30
|
+
const res = stmt.select<T>(bindValues ? prepareBindValues(bindValues, queryStr) : undefined)
|
|
31
|
+
stmt.finalize()
|
|
32
|
+
return res
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface SchemaManager {
|
|
36
|
+
getMutationDefInfos: () => ReadonlyArray<MutationDefInfo>
|
|
37
|
+
|
|
38
|
+
setMutationDefInfo: (mutationDefInfo: MutationDefInfo) => void
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export type MutationDefInfo = {
|
|
42
|
+
mutationName: string
|
|
43
|
+
schemaHash: number
|
|
44
|
+
}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { SqliteAst, SqliteDsl } from '@livestore/db-schema'
|
|
2
|
+
import { memoizeByStringifyArgs } from '@livestore/utils'
|
|
3
|
+
import { Effect, Schema as EffectSchema } from '@livestore/utils/effect'
|
|
4
|
+
|
|
5
|
+
import type { SynchronousDatabase } from '../adapter-types.js'
|
|
6
|
+
import type { LiveStoreSchema } from '../schema/index.js'
|
|
7
|
+
import type { SchemaMetaRow, SchemaMutationsMetaRow } from '../schema/system-tables.js'
|
|
8
|
+
import {
|
|
9
|
+
SCHEMA_META_TABLE,
|
|
10
|
+
SCHEMA_MUTATIONS_META_TABLE,
|
|
11
|
+
schemaMetaTable,
|
|
12
|
+
schemaMutationsMetaTable,
|
|
13
|
+
systemTables,
|
|
14
|
+
} from '../schema/system-tables.js'
|
|
15
|
+
import { sql } from '../util.js'
|
|
16
|
+
import type { SchemaManager } from './common.js'
|
|
17
|
+
import { dbExecute, dbSelect } from './common.js'
|
|
18
|
+
import { validateSchema } from './validate-mutation-defs.js'
|
|
19
|
+
|
|
20
|
+
const getMemoizedTimestamp = memoizeByStringifyArgs(() => new Date().toISOString())
|
|
21
|
+
|
|
22
|
+
export const makeSchemaManager = (db: SynchronousDatabase): Effect.Effect<SchemaManager> =>
|
|
23
|
+
Effect.gen(function* () {
|
|
24
|
+
yield* migrateTable({
|
|
25
|
+
db,
|
|
26
|
+
tableAst: schemaMutationsMetaTable.sqliteDef.ast,
|
|
27
|
+
behaviour: 'create-if-not-exists',
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
getMutationDefInfos: () =>
|
|
32
|
+
dbSelect<SchemaMutationsMetaRow>(db, sql`SELECT * FROM ${SCHEMA_MUTATIONS_META_TABLE}`),
|
|
33
|
+
|
|
34
|
+
setMutationDefInfo: (info) => {
|
|
35
|
+
dbExecute(
|
|
36
|
+
db,
|
|
37
|
+
sql`INSERT OR REPLACE INTO ${SCHEMA_MUTATIONS_META_TABLE} (mutationName, schemaHash, updatedAt) VALUES ($mutationName, $schemaHash, $updatedAt)`,
|
|
38
|
+
{
|
|
39
|
+
mutationName: info.mutationName,
|
|
40
|
+
schemaHash: info.schemaHash,
|
|
41
|
+
updatedAt: new Date().toISOString(),
|
|
42
|
+
},
|
|
43
|
+
)
|
|
44
|
+
},
|
|
45
|
+
}
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
// TODO more graceful DB migration (e.g. backup DB before destructive migrations)
|
|
49
|
+
export const migrateDb = ({
|
|
50
|
+
db,
|
|
51
|
+
schema,
|
|
52
|
+
onProgress,
|
|
53
|
+
}: {
|
|
54
|
+
db: SynchronousDatabase
|
|
55
|
+
schema: LiveStoreSchema
|
|
56
|
+
onProgress?: (opts: { done: number; total: number }) => Effect.Effect<void>
|
|
57
|
+
}) =>
|
|
58
|
+
Effect.gen(function* () {
|
|
59
|
+
yield* migrateTable({
|
|
60
|
+
db,
|
|
61
|
+
tableAst: schemaMetaTable.sqliteDef.ast,
|
|
62
|
+
behaviour: 'create-if-not-exists',
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
// TODO enforce that migrating tables isn't allowed once the store is running
|
|
66
|
+
|
|
67
|
+
const schemaManager = yield* makeSchemaManager(db)
|
|
68
|
+
yield* validateSchema(schema, schemaManager)
|
|
69
|
+
|
|
70
|
+
const schemaMetaRows = dbSelect<SchemaMetaRow>(db, sql`SELECT * FROM ${SCHEMA_META_TABLE}`)
|
|
71
|
+
|
|
72
|
+
const dbSchemaHashByTable = Object.fromEntries(
|
|
73
|
+
schemaMetaRows.map(({ tableName, schemaHash }) => [tableName, schemaHash]),
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
const tableDefs = new Set([
|
|
77
|
+
// NOTE it's important the `SCHEMA_META_TABLE` comes first since we're writing to it below
|
|
78
|
+
...systemTables,
|
|
79
|
+
...Array.from(schema.tables.values()).filter((_) => _.sqliteDef.name !== SCHEMA_META_TABLE),
|
|
80
|
+
])
|
|
81
|
+
|
|
82
|
+
const tablesToMigrate = new Set<{ tableAst: SqliteAst.Table; schemaHash: number }>()
|
|
83
|
+
|
|
84
|
+
for (const tableDef of tableDefs) {
|
|
85
|
+
const tableAst = tableDef.sqliteDef.ast
|
|
86
|
+
const tableName = tableAst.name
|
|
87
|
+
const dbSchemaHash = dbSchemaHashByTable[tableName]
|
|
88
|
+
const schemaHash = SqliteAst.hash(tableAst)
|
|
89
|
+
|
|
90
|
+
if (schemaHash !== dbSchemaHash) {
|
|
91
|
+
tablesToMigrate.add({ tableAst, schemaHash })
|
|
92
|
+
|
|
93
|
+
console.log(
|
|
94
|
+
`Schema hash mismatch for table '${tableName}' (DB: ${dbSchemaHash}, expected: ${schemaHash}), migrating table...`,
|
|
95
|
+
)
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
let processedTables = 0
|
|
100
|
+
const tablesCount = tablesToMigrate.size
|
|
101
|
+
|
|
102
|
+
for (const { tableAst, schemaHash } of tablesToMigrate) {
|
|
103
|
+
yield* migrateTable({ db, tableAst, schemaHash, behaviour: 'create-if-not-exists' })
|
|
104
|
+
|
|
105
|
+
if (onProgress !== undefined) {
|
|
106
|
+
processedTables++
|
|
107
|
+
yield* onProgress({ done: processedTables, total: tablesCount })
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
export const migrateTable = ({
|
|
113
|
+
db,
|
|
114
|
+
tableAst,
|
|
115
|
+
schemaHash = SqliteAst.hash(tableAst),
|
|
116
|
+
behaviour,
|
|
117
|
+
skipMetaTable = false,
|
|
118
|
+
}: {
|
|
119
|
+
db: SynchronousDatabase
|
|
120
|
+
tableAst: SqliteAst.Table
|
|
121
|
+
schemaHash?: number
|
|
122
|
+
behaviour: 'drop-and-recreate' | 'create-if-not-exists'
|
|
123
|
+
skipMetaTable?: boolean
|
|
124
|
+
}) =>
|
|
125
|
+
Effect.gen(function* () {
|
|
126
|
+
// console.log(`Migrating table '${tableAst.name}'...`)
|
|
127
|
+
const tableName = tableAst.name
|
|
128
|
+
const columnSpec = makeColumnSpec(tableAst)
|
|
129
|
+
|
|
130
|
+
if (behaviour === 'drop-and-recreate') {
|
|
131
|
+
// TODO need to possibly handle cascading deletes due to foreign keys
|
|
132
|
+
dbExecute(db, sql`drop table if exists ${tableName}`)
|
|
133
|
+
dbExecute(db, sql`create table if not exists ${tableName} (${columnSpec}) strict`)
|
|
134
|
+
} else if (behaviour === 'create-if-not-exists') {
|
|
135
|
+
dbExecute(db, sql`create table if not exists ${tableName} (${columnSpec}) strict`)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
for (const index of tableAst.indexes) {
|
|
139
|
+
dbExecute(db, createIndexFromDefinition(tableName, index))
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (skipMetaTable !== true) {
|
|
143
|
+
const updatedAt = getMemoizedTimestamp()
|
|
144
|
+
|
|
145
|
+
dbExecute(
|
|
146
|
+
db,
|
|
147
|
+
sql`
|
|
148
|
+
INSERT INTO ${SCHEMA_META_TABLE} (tableName, schemaHash, updatedAt) VALUES ($tableName, $schemaHash, $updatedAt)
|
|
149
|
+
ON CONFLICT (tableName) DO UPDATE SET schemaHash = $schemaHash, updatedAt = $updatedAt;
|
|
150
|
+
`,
|
|
151
|
+
{ tableName, schemaHash, updatedAt },
|
|
152
|
+
)
|
|
153
|
+
}
|
|
154
|
+
}).pipe(Effect.withSpan('@livestore/common:migrateTable', { attributes: { tableName: tableAst.name } }))
|
|
155
|
+
|
|
156
|
+
const createIndexFromDefinition = (tableName: string, index: SqliteAst.Index) => {
|
|
157
|
+
const uniqueStr = index.unique ? 'UNIQUE' : ''
|
|
158
|
+
return sql`create ${uniqueStr} index if not exists ${index.name} on ${tableName} (${index.columns.join(', ')})`
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export const makeColumnSpec = (tableAst: SqliteAst.Table) => {
|
|
162
|
+
const primaryKeys = tableAst.columns.filter((_) => _.primaryKey).map((_) => _.name)
|
|
163
|
+
const columnDefStrs = tableAst.columns.map(toSqliteColumnSpec)
|
|
164
|
+
if (primaryKeys.length > 0) {
|
|
165
|
+
columnDefStrs.push(`PRIMARY KEY (${primaryKeys.join(', ')})`)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return columnDefStrs.join(', ')
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/** NOTE primary keys are applied on a table level not on a column level to account for multi-column primary keys */
|
|
172
|
+
const toSqliteColumnSpec = (column: SqliteAst.Column) => {
|
|
173
|
+
const columnTypeStr = column.type._tag
|
|
174
|
+
const nullableStr = column.nullable === false ? 'not null' : ''
|
|
175
|
+
const defaultValueStr = (() => {
|
|
176
|
+
if (column.default._tag === 'None') return ''
|
|
177
|
+
|
|
178
|
+
if (SqliteDsl.isSqlDefaultValue(column.default.value)) return `default ${column.default.value.sql}`
|
|
179
|
+
|
|
180
|
+
const encodeValue = EffectSchema.encodeSync(column.schema)
|
|
181
|
+
const encodedDefaultValue = encodeValue(column.default.value)
|
|
182
|
+
|
|
183
|
+
if (columnTypeStr === 'text') return `default '${encodedDefaultValue}'`
|
|
184
|
+
return `default ${encodedDefaultValue}`
|
|
185
|
+
})()
|
|
186
|
+
|
|
187
|
+
return `${column.name} ${columnTypeStr} ${nullableStr} ${defaultValueStr}`
|
|
188
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { Effect, Schema } from '@livestore/utils/effect'
|
|
2
|
+
|
|
3
|
+
import { UnexpectedError } from '../adapter-types.js'
|
|
4
|
+
import type { LiveStoreSchema } from '../schema/index.js'
|
|
5
|
+
import type { MutationDef } from '../schema/mutations.js'
|
|
6
|
+
import type { MutationDefInfo, SchemaManager } from './common.js'
|
|
7
|
+
|
|
8
|
+
export const validateSchema = (schema: LiveStoreSchema, schemaManager: SchemaManager) =>
|
|
9
|
+
Effect.gen(function* () {
|
|
10
|
+
// Validate mutation definitions
|
|
11
|
+
const registeredMutationDefInfos = schemaManager.getMutationDefInfos()
|
|
12
|
+
|
|
13
|
+
const missingMutationDefs = registeredMutationDefInfos.filter(
|
|
14
|
+
(registeredMutationDefInfo) => !schema.mutations.has(registeredMutationDefInfo.mutationName),
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
if (missingMutationDefs.length > 0) {
|
|
18
|
+
yield* new UnexpectedError({
|
|
19
|
+
cause: `Missing mutation definitions: ${missingMutationDefs.map((info) => info.mutationName).join(', ')}`,
|
|
20
|
+
})
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
for (const [, mutationDef] of schema.mutations) {
|
|
24
|
+
const registeredMutationDefInfo = registeredMutationDefInfos.find(
|
|
25
|
+
(info) => info.mutationName === mutationDef.name,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
validateMutationDef(mutationDef, schemaManager, registeredMutationDefInfo)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Validate table schemas
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
export const validateMutationDef = (
|
|
35
|
+
mutationDef: MutationDef.Any,
|
|
36
|
+
schemaManager: SchemaManager,
|
|
37
|
+
registeredMutationDefInfo: MutationDefInfo | undefined,
|
|
38
|
+
) => {
|
|
39
|
+
const schemaHash = Schema.hash(mutationDef.schema)
|
|
40
|
+
|
|
41
|
+
if (registeredMutationDefInfo === undefined) {
|
|
42
|
+
schemaManager.setMutationDefInfo({
|
|
43
|
+
schemaHash,
|
|
44
|
+
mutationName: mutationDef.name,
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
return
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (schemaHash === registeredMutationDefInfo.schemaHash) return
|
|
51
|
+
|
|
52
|
+
// TODO bring back some form of schema compatibility check (see https://github.com/livestorejs/livestore/issues/69)
|
|
53
|
+
// const newSchemaIsCompatibleWithOldSchema = Schema.isSubType(jsonSchemaDefFromMgmtStore, mutationDef.schema)
|
|
54
|
+
|
|
55
|
+
// if (!newSchemaIsCompatibleWithOldSchema) {
|
|
56
|
+
// shouldNeverHappen(`Schema for mutation ${mutationDef.name} has changed in an incompatible way`)
|
|
57
|
+
// }
|
|
58
|
+
|
|
59
|
+
schemaManager.setMutationDefInfo({
|
|
60
|
+
schemaHash,
|
|
61
|
+
mutationName: mutationDef.name,
|
|
62
|
+
})
|
|
63
|
+
}
|