@livestore/common 0.1.0 → 0.2.0-dev.1

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.
Files changed (73) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/__tests__/fixture.d.ts +46 -34
  3. package/dist/__tests__/fixture.d.ts.map +1 -1
  4. package/dist/adapter-types.d.ts +1 -1
  5. package/dist/adapter-types.js +1 -1
  6. package/dist/derived-mutations.d.ts +4 -4
  7. package/dist/derived-mutations.d.ts.map +1 -1
  8. package/dist/derived-mutations.js.map +1 -1
  9. package/dist/devtools/devtools-messages.d.ts +45 -45
  10. package/dist/devtools/devtools-messages.js +1 -1
  11. package/dist/devtools/devtools-messages.js.map +1 -1
  12. package/dist/index.d.ts +1 -0
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +1 -0
  15. package/dist/index.js.map +1 -1
  16. package/dist/mutation.d.ts +1 -1
  17. package/dist/mutation.d.ts.map +1 -1
  18. package/dist/mutation.js +6 -1
  19. package/dist/mutation.js.map +1 -1
  20. package/dist/query-builder/api.d.ts +190 -0
  21. package/dist/query-builder/api.d.ts.map +1 -0
  22. package/dist/query-builder/api.js +8 -0
  23. package/dist/query-builder/api.js.map +1 -0
  24. package/dist/query-builder/impl.d.ts +12 -0
  25. package/dist/query-builder/impl.d.ts.map +1 -0
  26. package/dist/query-builder/impl.js +226 -0
  27. package/dist/query-builder/impl.js.map +1 -0
  28. package/dist/query-builder/impl.test.d.ts +2 -0
  29. package/dist/query-builder/impl.test.d.ts.map +1 -0
  30. package/dist/query-builder/impl.test.js +183 -0
  31. package/dist/query-builder/impl.test.js.map +1 -0
  32. package/dist/query-builder/mod.d.ts +10 -0
  33. package/dist/query-builder/mod.d.ts.map +1 -0
  34. package/dist/query-builder/mod.js +10 -0
  35. package/dist/query-builder/mod.js.map +1 -0
  36. package/dist/query-info.d.ts +29 -39
  37. package/dist/query-info.d.ts.map +1 -1
  38. package/dist/query-info.js +4 -35
  39. package/dist/query-info.js.map +1 -1
  40. package/dist/schema/index.d.ts +2 -2
  41. package/dist/schema/index.d.ts.map +1 -1
  42. package/dist/schema/index.js +1 -0
  43. package/dist/schema/index.js.map +1 -1
  44. package/dist/schema/schema-helpers.d.ts +2 -2
  45. package/dist/schema/schema-helpers.d.ts.map +1 -1
  46. package/dist/schema/system-tables.d.ts +246 -204
  47. package/dist/schema/system-tables.d.ts.map +1 -1
  48. package/dist/schema/table-def.d.ts +45 -24
  49. package/dist/schema/table-def.d.ts.map +1 -1
  50. package/dist/schema/table-def.js +10 -1
  51. package/dist/schema/table-def.js.map +1 -1
  52. package/dist/sql-queries/sql-queries.d.ts +1 -0
  53. package/dist/sql-queries/sql-queries.d.ts.map +1 -1
  54. package/dist/sql-queries/sql-queries.js +8 -5
  55. package/dist/sql-queries/sql-queries.js.map +1 -1
  56. package/dist/version.d.ts +1 -1
  57. package/dist/version.js +1 -1
  58. package/package.json +3 -3
  59. package/src/adapter-types.ts +1 -1
  60. package/src/derived-mutations.ts +4 -8
  61. package/src/devtools/devtools-messages.ts +1 -1
  62. package/src/index.ts +1 -0
  63. package/src/mutation.ts +9 -2
  64. package/src/query-builder/api.ts +288 -0
  65. package/src/query-builder/impl.test.ts +205 -0
  66. package/src/query-builder/impl.ts +268 -0
  67. package/src/query-builder/mod.ts +10 -0
  68. package/src/query-info.ts +66 -93
  69. package/src/schema/index.ts +4 -2
  70. package/src/schema/schema-helpers.ts +2 -2
  71. package/src/schema/table-def.ts +99 -68
  72. package/src/sql-queries/sql-queries.ts +9 -6
  73. package/src/version.ts +1 -1
@@ -0,0 +1,268 @@
1
+ import { Option, Predicate, Schema } from '@livestore/utils/effect'
2
+
3
+ import type { QueryInfo } from '../query-info.js'
4
+ import type { DbSchema } from '../schema/index.js'
5
+ import type { QueryBuilder, QueryBuilderAst } from './api.js'
6
+ import { QueryBuilderAstSymbol, TypeId } from './api.js'
7
+
8
+ export const makeQueryBuilder = <TResult, TTableDef extends DbSchema.TableDefBase>(
9
+ tableDef: TTableDef,
10
+ ast: QueryBuilderAst = emptyAst(tableDef),
11
+ ): QueryBuilder<TResult, TTableDef, never, QueryInfo.None> => {
12
+ const api = {
13
+ // eslint-disable-next-line prefer-arrow/prefer-arrow-functions
14
+ select() {
15
+ assertQueryBuilderAst(ast)
16
+
17
+ // eslint-disable-next-line prefer-rest-params
18
+ const params = [...arguments]
19
+
20
+ if (params.length === 2 && typeof params[0] === 'string' && typeof params[1] === 'object') {
21
+ const [col, options] = params as any as [string, { pluck: boolean }]
22
+ return makeQueryBuilder(tableDef, {
23
+ ...ast,
24
+ resultSchemaSingle: options.pluck ? ast.resultSchemaSingle.pipe(Schema.pluck(col)) : ast.resultSchemaSingle,
25
+ select: { columns: [col] },
26
+ })
27
+ }
28
+
29
+ const columns = params as unknown as ReadonlyArray<string>
30
+
31
+ return makeQueryBuilder(tableDef, {
32
+ ...ast,
33
+ resultSchemaSingle:
34
+ columns.length === 0 ? ast.resultSchemaSingle : ast.resultSchemaSingle.pipe(Schema.pick(...columns)),
35
+ select: { columns },
36
+ }) as any
37
+ },
38
+ // eslint-disable-next-line prefer-arrow/prefer-arrow-functions
39
+ where() {
40
+ if (isRowQuery(ast)) return invalidQueryBuilder()
41
+
42
+ if (arguments.length === 1) {
43
+ // eslint-disable-next-line prefer-rest-params
44
+ const params = arguments[0]
45
+ const newOps = Object.entries(params)
46
+ .filter(([, value]) => value !== undefined)
47
+ .map<QueryBuilderAst.Where>(([col, value]) =>
48
+ Predicate.hasProperty(value, 'op') && Predicate.hasProperty(value, 'value')
49
+ ? ({ col, op: value.op, value: value.value } as any)
50
+ : { col, op: '=', value },
51
+ )
52
+
53
+ return makeQueryBuilder(tableDef, {
54
+ ...ast,
55
+ where: [...ast.where, ...newOps],
56
+ }) as any
57
+ }
58
+
59
+ // eslint-disable-next-line prefer-rest-params
60
+ const [col, opOrValue, valueOrUndefined] = arguments
61
+ const op = valueOrUndefined === undefined ? '=' : opOrValue
62
+ const value = valueOrUndefined === undefined ? opOrValue : valueOrUndefined
63
+ return makeQueryBuilder(tableDef, {
64
+ ...ast,
65
+ where: [...ast.where, { col, op, value }],
66
+ })
67
+ },
68
+ // eslint-disable-next-line prefer-arrow/prefer-arrow-functions
69
+ orderBy() {
70
+ assertQueryBuilderAst(ast)
71
+
72
+ if (arguments.length === 0 || arguments.length > 2) return invalidQueryBuilder()
73
+
74
+ if (arguments.length === 1) {
75
+ // eslint-disable-next-line prefer-rest-params
76
+ const params = arguments[0] as QueryBuilder.OrderByParams<TTableDef>
77
+ return makeQueryBuilder(tableDef, {
78
+ ...ast,
79
+ orderBy: [...ast.orderBy, ...params],
80
+ })
81
+ }
82
+
83
+ // eslint-disable-next-line prefer-rest-params
84
+ const [col, direction] = arguments as any as [keyof TTableDef['sqliteDef']['columns'] & string, 'asc' | 'desc']
85
+
86
+ return makeQueryBuilder(tableDef, {
87
+ ...ast,
88
+ orderBy: [...ast.orderBy, { col, direction }],
89
+ }) as any
90
+ },
91
+ limit: (limit) => {
92
+ assertQueryBuilderAst(ast)
93
+
94
+ return makeQueryBuilder(tableDef, { ...ast, limit: Option.some(limit) })
95
+ },
96
+ offset: (offset) => {
97
+ assertQueryBuilderAst(ast)
98
+
99
+ return makeQueryBuilder(tableDef, { ...ast, offset: Option.some(offset) })
100
+ },
101
+ count: () => {
102
+ if (isRowQuery(ast)) return invalidQueryBuilder()
103
+
104
+ return makeQueryBuilder(tableDef, {
105
+ ...ast,
106
+ resultSchema: Schema.Struct({ count: Schema.Number }).pipe(
107
+ Schema.pluck('count'),
108
+ Schema.Array,
109
+ Schema.headOrElse(),
110
+ ),
111
+ _tag: 'CountQuery',
112
+ })
113
+ },
114
+ first: (options) => {
115
+ assertQueryBuilderAst(ast)
116
+
117
+ if (ast.limit._tag === 'Some') return invalidQueryBuilder(`.first() can't be called after .limit()`)
118
+
119
+ return makeQueryBuilder(tableDef, {
120
+ ...ast,
121
+ limit: Option.some(1),
122
+ pickFirst: options?.fallback ? { fallback: options.fallback } : false,
123
+ })
124
+ },
125
+ // eslint-disable-next-line prefer-arrow/prefer-arrow-functions
126
+ row() {
127
+ // eslint-disable-next-line prefer-rest-params
128
+ const params = [...arguments]
129
+
130
+ let id: string
131
+
132
+ if (tableDef.options.isSingleton) {
133
+ id = tableDef.sqliteDef.columns.id!.default.pipe(Option.getOrThrow)
134
+ } else {
135
+ id = params[0] as string
136
+ if (id === undefined) {
137
+ invalidQueryBuilder(`Id missing for row query on non-singleton table ${tableDef.sqliteDef.name}`)
138
+ }
139
+ }
140
+
141
+ // TODO validate all required columns are present and values are matching the schema
142
+ const insertValues: Record<string, unknown> = params[1]?.insertValues ?? {}
143
+
144
+ return makeQueryBuilder(tableDef, {
145
+ _tag: 'RowQuery',
146
+ id,
147
+ tableDef,
148
+ insertValues,
149
+ }) as any
150
+ },
151
+ } satisfies QueryBuilder.ApiFull<TResult, TTableDef, never, QueryInfo.None>
152
+
153
+ return {
154
+ [TypeId]: TypeId,
155
+ [QueryBuilderAstSymbol]: ast,
156
+ asSql: () => astToSql(ast),
157
+ toString: () => astToSql(ast).query,
158
+ ...api,
159
+ } satisfies QueryBuilder<TResult, TTableDef>
160
+ }
161
+
162
+ const emptyAst = (tableDef: DbSchema.TableDefBase) =>
163
+ ({
164
+ _tag: 'SelectQuery',
165
+ columns: [],
166
+ pickFirst: false,
167
+ select: { columns: [] },
168
+ orderBy: [],
169
+ offset: Option.none(),
170
+ limit: Option.none(),
171
+ tableDef,
172
+ where: [],
173
+ resultSchemaSingle: tableDef.schema,
174
+ }) satisfies QueryBuilderAst
175
+
176
+ const astToSql = (ast: QueryBuilderAst) => {
177
+ if (isRowQuery(ast)) {
178
+ // TODO
179
+ return { query: `SELECT * FROM '${ast.tableDef.sqliteDef.name}' WHERE id = ?`, bindValues: [ast.id as TODO] }
180
+ }
181
+
182
+ const bindValues: unknown[] = []
183
+
184
+ // TODO bind values
185
+ const whereStmt =
186
+ ast.where.length > 0
187
+ ? `WHERE ${ast.where
188
+ .map(({ col, op, value }) => {
189
+ if (value === null) {
190
+ if (op !== '=' && op !== '!=') {
191
+ throw new Error(`Unsupported operator for NULL value: ${op}`)
192
+ }
193
+ const opStmt = op === '=' ? 'IS' : 'IS NOT'
194
+ return `${col} ${opStmt} NULL`
195
+ } else {
196
+ const colDef = ast.tableDef.sqliteDef.columns[col]
197
+ if (colDef === undefined) {
198
+ throw new Error(`Column ${col} not found`)
199
+ }
200
+ const encodedValue = Schema.encodeSync(colDef.schema)(value)
201
+ bindValues.push(encodedValue)
202
+ return `${col} ${op} ?`
203
+ }
204
+ })
205
+ .join(' AND ')}`
206
+ : ''
207
+
208
+ if (ast._tag === 'CountQuery') {
209
+ const selectFromStmt = `SELECT COUNT(*) as count FROM '${ast.tableDef.sqliteDef.name}'`
210
+ const query = [selectFromStmt, whereStmt].filter((_) => _.length > 0).join(' ')
211
+ return { query, bindValues }
212
+ }
213
+ const columnsStmt = ast.select.columns.length === 0 ? '*' : ast.select.columns.join(', ')
214
+ const selectStmt = `SELECT ${columnsStmt}`
215
+ const fromStmt = `FROM '${ast.tableDef.sqliteDef.name}'`
216
+
217
+ const orderByStmt =
218
+ ast.orderBy.length > 0
219
+ ? `ORDER BY ${ast.orderBy.map(({ col, direction }) => `${col} ${direction}`).join(', ')}`
220
+ : ''
221
+
222
+ const limitStmt = ast.limit._tag === 'Some' ? `LIMIT ?` : ''
223
+ if (ast.limit._tag === 'Some') bindValues.push(ast.limit.value)
224
+
225
+ const offsetStmt = ast.offset._tag === 'Some' ? `OFFSET ?` : ''
226
+ if (ast.offset._tag === 'Some') bindValues.push(ast.offset.value)
227
+
228
+ const query = [selectStmt, fromStmt, whereStmt, orderByStmt, offsetStmt, limitStmt]
229
+ .map((_) => _.trim())
230
+ .filter((_) => _.length > 0)
231
+ .join(' ')
232
+
233
+ // TODO bind values
234
+ return { query, bindValues }
235
+ }
236
+
237
+ // eslint-disable-next-line prefer-arrow/prefer-arrow-functions
238
+ function assertQueryBuilderAst(ast: QueryBuilderAst): asserts ast is QueryBuilderAst.SelectQuery {
239
+ if (ast._tag !== 'SelectQuery') {
240
+ throw new Error('Expected SelectQuery but got ' + ast._tag)
241
+ }
242
+ }
243
+
244
+ const isRowQuery = (ast: QueryBuilderAst): ast is QueryBuilderAst.RowQuery => ast._tag === 'RowQuery'
245
+
246
+ export const invalidQueryBuilder = (msg?: string) => {
247
+ throw new Error('Invalid query builder' + (msg ? `: ${msg}` : ''))
248
+ }
249
+
250
+ export const getResultSchema = (qb: QueryBuilder<any, any, any>) => {
251
+ const queryAst = qb[QueryBuilderAstSymbol]
252
+ if (queryAst._tag === 'SelectQuery') {
253
+ const arraySchema = Schema.Array(queryAst.resultSchemaSingle)
254
+ if (queryAst.pickFirst !== false) {
255
+ return arraySchema.pipe(Schema.headOrElse(queryAst.pickFirst.fallback))
256
+ }
257
+
258
+ return arraySchema
259
+ } else if (queryAst._tag === 'CountQuery') {
260
+ return Schema.Struct({ count: Schema.Number }).pipe(Schema.pluck('count'), Schema.Array, Schema.headOrElse())
261
+ } else {
262
+ if (queryAst.tableDef.options.isSingleColumn) {
263
+ return queryAst.tableDef.schema.pipe(Schema.pluck('value'), Schema.Array, Schema.headOrElse())
264
+ } else {
265
+ return queryAst.tableDef.schema.pipe(Schema.Array, Schema.headOrElse())
266
+ }
267
+ }
268
+ }
@@ -0,0 +1,10 @@
1
+ export * from './api.js'
2
+ export * from './impl.js'
3
+
4
+ /**
5
+ * Design decisions:
6
+ *
7
+ * - Close abstraction to SQLite to provide a simple & convenient API with predictable behaviour
8
+ * - Use table schema definitions to parse, map & validate query results
9
+ * - Implementation detail: Separate type-level & AST-based runtime implementation
10
+ */
package/src/query-info.ts CHANGED
@@ -1,5 +1,3 @@
1
- import type { Schema } from '@livestore/utils/effect'
2
-
3
1
  import type { SessionIdSymbol } from './adapter-types.js'
4
2
  import type { DbSchema } from './schema/index.js'
5
3
 
@@ -8,98 +6,73 @@ import type { DbSchema } from './schema/index.js'
8
6
  * - a whole row
9
7
  * - a single column value
10
8
  * - a sub value in a JSON column
9
+ *
10
+ * This information is currently only used for derived mutations.
11
11
  */
12
- export type QueryInfo<TTableDef extends DbSchema.TableDef = DbSchema.TableDef> =
13
- | QueryInfoNone
14
- | QueryInfoRow<TTableDef>
15
- | QueryInfoColJsonValue<TTableDef, GetJsonColumn<TTableDef>>
16
- | QueryInfoCol<TTableDef, keyof TTableDef['sqliteDef']['columns']>
17
-
18
- export type QueryInfoNone = {
19
- _tag: 'None'
20
- }
21
-
22
- export type QueryInfoRow<TTableDef extends DbSchema.TableDef> = {
23
- _tag: 'Row'
24
- table: TTableDef
25
- id: string | SessionIdSymbol
26
- }
27
-
28
- export type QueryInfoCol<
29
- TTableDef extends DbSchema.TableDef,
30
- TColName extends keyof TTableDef['sqliteDef']['columns'],
31
- > = {
32
- _tag: 'Col'
33
- table: TTableDef
34
- id: string | SessionIdSymbol
35
- column: TColName
36
- }
37
-
38
- export type QueryInfoColJsonValue<TTableDef extends DbSchema.TableDef, TColName extends GetJsonColumn<TTableDef>> = {
39
- _tag: 'ColJsonValue'
40
- table: TTableDef
41
- id: string | SessionIdSymbol
42
- column: TColName
43
- /**
44
- * example: `$.tabs[3].items[2]` (`$` referring to the column value)
45
- */
46
- jsonPath: string
47
- }
48
-
49
- type GetJsonColumn<TTableDef extends DbSchema.TableDef> = keyof {
50
- [ColName in keyof TTableDef['sqliteDef']['columns'] as TTableDef['sqliteDef']['columns'][ColName]['columnType'] extends 'text'
51
- ? ColName
52
- : never]: {}
12
+ export type QueryInfo = QueryInfo.None | QueryInfo.Row | QueryInfo.Col | QueryInfo.ColJsonValue
13
+ // export type QueryInfo<TTableDef extends DbSchema.TableDefBase = DbSchema.TableDefBase> =
14
+ // | QueryInfo.None
15
+ // | QueryInfo.Row<TTableDef>
16
+ // | QueryInfo.ColJsonValue<TTableDef, GetJsonColumn<TTableDef>>
17
+ // | QueryInfo.Col<TTableDef, keyof TTableDef['sqliteDef']['columns']>
18
+
19
+ export namespace QueryInfo {
20
+ export type None = {
21
+ _tag: 'None'
22
+ }
23
+
24
+ export type Row = {
25
+ _tag: 'Row'
26
+ table: DbSchema.TableDefBase
27
+ id: string | SessionIdSymbol
28
+ }
29
+
30
+ export type Col = {
31
+ _tag: 'Col'
32
+ table: DbSchema.TableDefBase
33
+ id: string | SessionIdSymbol
34
+ column: string
35
+ }
36
+
37
+ export type ColJsonValue = {
38
+ _tag: 'ColJsonValue'
39
+ table: DbSchema.TableDefBase
40
+ id: string | SessionIdSymbol
41
+ column: string
42
+ /**
43
+ * example: `$.tabs[3].items[2]` (`$` referring to the column value)
44
+ */
45
+ jsonPath: string
46
+ }
47
+
48
+ // NOTE maybe we want to bring back type-params back like below
49
+ // export type Row<TTableDef extends DbSchema.TableDefBase> = {
50
+ // _tag: 'Row'
51
+ // table: TTableDef
52
+ // id: string | SessionIdSymbol
53
+ // }
54
+
55
+ // export type Col<TTableDef extends DbSchema.TableDefBase, TColName extends keyof TTableDef['sqliteDef']['columns']> = {
56
+ // _tag: 'Col'
57
+ // table: TTableDef
58
+ // id: string | SessionIdSymbol
59
+ // column: TColName
60
+ // }
61
+
62
+ // export type ColJsonValue<TTableDef extends DbSchema.TableDefBase, TColName extends GetJsonColumn<TTableDef>> = {
63
+ // _tag: 'ColJsonValue'
64
+ // table: TTableDef
65
+ // id: string | SessionIdSymbol
66
+ // column: TColName
67
+ // /**
68
+ // * example: `$.tabs[3].items[2]` (`$` referring to the column value)
69
+ // */
70
+ // jsonPath: string
71
+ // }
53
72
  }
54
73
 
55
- export type UpdateValueForPath<TQueryInfo extends QueryInfo> = TQueryInfo extends { _tag: 'Row' }
56
- ? Partial<DbSchema.FromTable.RowDecodedAll<TQueryInfo['table']>>
57
- : TQueryInfo extends { _tag: 'Col' }
58
- ? Schema.Schema.Type<TQueryInfo['table']['sqliteDef']['columns'][TQueryInfo['column']]['schema']>
59
- : TQueryInfo extends { _tag: 'ColJsonValue' }
60
- ? { TODO: true }
61
- : never
62
-
63
- // export const mutationForQueryInfo = <const TQueryInfo extends QueryInfo>(
64
- // queryInfo: TQueryInfo,
65
- // value: UpdateValueForPath<TQueryInfo>,
66
- // ): RawSqlMutationEvent => {
67
- // if (queryInfo._tag === 'ColJsonValue' || queryInfo._tag === 'None') {
68
- // return notYetImplemented('TODO')
69
- // }
70
-
71
- // const sqliteTableDef = queryInfo.table.sqliteDef
72
- // const id = queryInfo.id
73
-
74
- // const { columnNames, bindValues } = (() => {
75
- // if (queryInfo._tag === 'Row') {
76
- // const columnNames = Object.keys(value)
77
-
78
- // const partialStructSchema = queryInfo.table.schema.pipe(Schema.pick(...columnNames))
79
-
80
- // // const columnNames = Object.keys(value)
81
- // const encodedBindValues = Schema.encodeEither(partialStructSchema)(value)
82
- // if (encodedBindValues._tag === 'Left') {
83
- // return shouldNeverHappen(encodedBindValues.left.toString())
84
- // } else {
85
- // return { columnNames, bindValues: encodedBindValues.right }
86
- // }
87
- // } else if (queryInfo._tag === 'Col') {
88
- // const columnName = queryInfo.column
89
- // const columnSchema =
90
- // sqliteTableDef.columns[columnName]?.schema ?? shouldNeverHappen(`Column ${columnName} not found`)
91
- // const bindValues = { [columnName]: Schema.encodeSync(columnSchema)(value) }
92
- // return { columnNames: [columnName], bindValues }
93
- // } else {
94
- // return shouldNeverHappen()
95
- // }
96
- // })()
97
-
98
- // const updateClause = columnNames.map((columnName) => `${columnName} = $${columnName}`).join(', ')
99
-
100
- // const whereClause = `where id = '${id}'`
101
- // const sql = `UPDATE ${sqliteTableDef.name} SET ${updateClause} ${whereClause}`
102
- // const writeTables = new Set<string>([queryInfo.table.sqliteDef.name])
103
-
104
- // return rawSqlMutation({ sql, bindValues, writeTables })
74
+ // type GetJsonColumn<TTableDef extends DbSchema.TableDefBase> = keyof {
75
+ // [ColName in keyof TTableDef['sqliteDef']['columns'] as TTableDef['sqliteDef']['columns'][ColName]['columnType'] extends 'text'
76
+ // ? ColName
77
+ // : never]: {}
105
78
  // }
@@ -12,7 +12,8 @@ import {
12
12
  rawSqlMutation,
13
13
  } from './mutations.js'
14
14
  import { systemTables } from './system-tables.js'
15
- import { type TableDef, tableHasDerivedMutations } from './table-def.js'
15
+ import type { TableDef, TableDefBase } from './table-def.js'
16
+ import { tableHasDerivedMutations } from './table-def.js'
16
17
 
17
18
  export * from './system-tables.js'
18
19
  export * as DbSchema from './table-def.js'
@@ -41,7 +42,7 @@ export type LiveStoreSchema<
41
42
  }
42
43
 
43
44
  export type InputSchema = {
44
- readonly tables: Record<string, TableDef> | ReadonlyArray<TableDef>
45
+ readonly tables: Record<string, TableDefBase> | ReadonlyArray<TableDefBase>
45
46
  readonly mutations?: ReadonlyArray<MutationDef.Any> | Record<string, MutationDef.Any>
46
47
  /**
47
48
  * Can be used to isolate multiple LiveStore apps running in the same origin
@@ -72,6 +73,7 @@ export const makeSchema = <TInputSchema extends InputSchema>(
72
73
  }
73
74
 
74
75
  for (const tableDef of systemTables) {
76
+ // @ts-expect-error TODO fix type level issue
75
77
  tables.set(tableDef.sqliteDef.name, tableDef)
76
78
  }
77
79
 
@@ -2,7 +2,7 @@ import { SqliteDsl } from '@livestore/db-schema'
2
2
  import { shouldNeverHappen } from '@livestore/utils'
3
3
  import { pipe, ReadonlyRecord, Schema } from '@livestore/utils/effect'
4
4
 
5
- import type { TableDef } from './table-def.js'
5
+ import type { TableDef, TableDefBase } from './table-def.js'
6
6
 
7
7
  export const getDefaultValuesEncoded = <TTableDef extends TableDef>(
8
8
  tableDef: TTableDef,
@@ -26,7 +26,7 @@ export const getDefaultValuesEncoded = <TTableDef extends TableDef>(
26
26
  ),
27
27
  )
28
28
 
29
- export const getDefaultValuesDecoded = <TTableDef extends TableDef>(
29
+ export const getDefaultValuesDecoded = <TTableDef extends TableDefBase>(
30
30
  tableDef: TTableDef,
31
31
  fallbackValues?: Record<string, any>,
32
32
  ) =>