@livestore/common 0.1.0 → 0.2.0-dev.0
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 -1
- package/dist/__tests__/fixture.d.ts +46 -34
- package/dist/__tests__/fixture.d.ts.map +1 -1
- package/dist/adapter-types.d.ts +1 -1
- package/dist/adapter-types.js +1 -1
- package/dist/derived-mutations.d.ts +4 -4
- package/dist/derived-mutations.d.ts.map +1 -1
- package/dist/derived-mutations.js.map +1 -1
- package/dist/devtools/devtools-messages.d.ts +53 -53
- package/dist/devtools/devtools-messages.js +1 -1
- package/dist/devtools/devtools-messages.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/mutation.d.ts +1 -1
- package/dist/mutation.d.ts.map +1 -1
- package/dist/mutation.js +6 -1
- package/dist/mutation.js.map +1 -1
- package/dist/query-builder/api.d.ts +190 -0
- package/dist/query-builder/api.d.ts.map +1 -0
- package/dist/query-builder/api.js +8 -0
- package/dist/query-builder/api.js.map +1 -0
- package/dist/query-builder/impl.d.ts +12 -0
- package/dist/query-builder/impl.d.ts.map +1 -0
- package/dist/query-builder/impl.js +226 -0
- package/dist/query-builder/impl.js.map +1 -0
- package/dist/query-builder/impl.test.d.ts +2 -0
- package/dist/query-builder/impl.test.d.ts.map +1 -0
- package/dist/query-builder/impl.test.js +183 -0
- package/dist/query-builder/impl.test.js.map +1 -0
- package/dist/query-builder/mod.d.ts +10 -0
- package/dist/query-builder/mod.d.ts.map +1 -0
- package/dist/query-builder/mod.js +10 -0
- package/dist/query-builder/mod.js.map +1 -0
- package/dist/query-info.d.ts +29 -39
- package/dist/query-info.d.ts.map +1 -1
- package/dist/query-info.js +4 -35
- package/dist/query-info.js.map +1 -1
- package/dist/schema/index.d.ts +2 -2
- package/dist/schema/index.d.ts.map +1 -1
- package/dist/schema/index.js +1 -0
- package/dist/schema/index.js.map +1 -1
- package/dist/schema/mutations.d.ts +8 -8
- package/dist/schema/schema-helpers.d.ts +2 -2
- package/dist/schema/schema-helpers.d.ts.map +1 -1
- package/dist/schema/system-tables.d.ts +246 -204
- package/dist/schema/system-tables.d.ts.map +1 -1
- package/dist/schema/table-def.d.ts +45 -24
- package/dist/schema/table-def.d.ts.map +1 -1
- package/dist/schema/table-def.js +10 -1
- package/dist/schema/table-def.js.map +1 -1
- package/dist/sql-queries/sql-queries.d.ts +1 -0
- package/dist/sql-queries/sql-queries.d.ts.map +1 -1
- package/dist/sql-queries/sql-queries.js +8 -5
- package/dist/sql-queries/sql-queries.js.map +1 -1
- package/dist/sync/next/test/mutation-fixtures.d.ts +7 -7
- package/dist/version.d.ts +1 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/package.json +3 -3
- package/src/adapter-types.ts +1 -1
- package/src/derived-mutations.ts +4 -8
- package/src/devtools/devtools-messages.ts +1 -1
- package/src/index.ts +1 -0
- package/src/mutation.ts +9 -2
- package/src/query-builder/api.ts +288 -0
- package/src/query-builder/impl.test.ts +205 -0
- package/src/query-builder/impl.ts +268 -0
- package/src/query-builder/mod.ts +10 -0
- package/src/query-info.ts +66 -93
- package/src/schema/index.ts +4 -2
- package/src/schema/schema-helpers.ts +2 -2
- package/src/schema/table-def.ts +99 -68
- package/src/sql-queries/sql-queries.ts +9 -6
- package/src/version.ts +1 -1
package/src/schema/table-def.ts
CHANGED
@@ -5,76 +5,83 @@ import { ReadonlyRecord, Schema } from '@livestore/utils/effect'
|
|
5
5
|
|
6
6
|
import type { DerivedMutationHelperFns } from '../derived-mutations.js'
|
7
7
|
import { makeDerivedMutationDefsForTable } from '../derived-mutations.js'
|
8
|
+
import type { QueryBuilder } from '../query-builder/mod.js'
|
9
|
+
import { makeQueryBuilder } from '../query-builder/mod.js'
|
8
10
|
|
9
11
|
export const { blob, boolean, column, datetime, integer, isColumnDefinition, json, real, text } = SqliteDsl
|
10
12
|
|
11
|
-
export {
|
13
|
+
export { SqliteDsl } from '@livestore/db-schema'
|
12
14
|
|
13
15
|
export type StateType = 'singleton' | 'dynamic'
|
14
16
|
|
15
17
|
export type DefaultSqliteTableDef = SqliteDsl.TableDefinition<string, SqliteDsl.Columns>
|
16
18
|
export type DefaultSqliteTableDefConstrained = SqliteDsl.TableDefinition<string, SqliteDsl.ConstraintColumns>
|
17
19
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
//
|
26
|
-
|
27
|
-
|
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
|
-
// }
|
20
|
+
export type TableDefBase<
|
21
|
+
TSqliteDef extends DefaultSqliteTableDef = DefaultSqliteTableDefConstrained,
|
22
|
+
TOptions extends TableOptions = TableOptions,
|
23
|
+
TSchema = SqliteDsl.StructSchemaForColumns<TSqliteDef['columns']>,
|
24
|
+
> = {
|
25
|
+
sqliteDef: TSqliteDef
|
26
|
+
options: TOptions
|
27
|
+
// Derived from `sqliteDef`, so only exposed for convenience
|
28
|
+
schema: TSchema
|
29
|
+
}
|
40
30
|
|
41
31
|
export type TableDef<
|
42
32
|
TSqliteDef extends DefaultSqliteTableDef = DefaultSqliteTableDefConstrained,
|
43
|
-
TIsSingleColumn extends boolean = boolean,
|
44
33
|
TOptions extends TableOptions = TableOptions,
|
45
34
|
// NOTE we're not using `SqliteDsl.StructSchemaForColumns<TSqliteDef['columns']>`
|
46
|
-
// as we don't want the alias type for users to show up
|
35
|
+
// as we don't want the alias type for users to show up, so we're redefining it here
|
47
36
|
TSchema = Schema.Schema<
|
48
37
|
SqliteDsl.AnyIfConstained<
|
49
38
|
TSqliteDef['columns'],
|
50
|
-
{ readonly [K in keyof TSqliteDef['columns']]:
|
39
|
+
{ readonly [K in keyof TSqliteDef['columns']]: TSqliteDef['columns'][K]['schema']['Type'] }
|
51
40
|
>,
|
52
41
|
SqliteDsl.AnyIfConstained<
|
53
42
|
TSqliteDef['columns'],
|
54
|
-
{ readonly [K in keyof TSqliteDef['columns']]:
|
43
|
+
{ readonly [K in keyof TSqliteDef['columns']]: TSqliteDef['columns'][K]['schema']['Encoded'] }
|
55
44
|
>
|
56
45
|
>,
|
57
46
|
> = {
|
58
47
|
sqliteDef: TSqliteDef
|
59
|
-
// TODO move this into options (for now it's duplicated)
|
60
|
-
isSingleColumn: TIsSingleColumn
|
61
48
|
options: TOptions
|
49
|
+
// Derived from `sqliteDef`, so only exposed for convenience
|
62
50
|
schema: TSchema
|
51
|
+
query: QueryBuilder<ReadonlyArray<Schema.Schema.Type<TSchema>>, TableDef<TSqliteDef & {}, TOptions>>
|
63
52
|
} & (TOptions['deriveMutations']['enabled'] extends true
|
64
53
|
? DerivedMutationHelperFns<TSqliteDef['columns'], TOptions>
|
65
54
|
: {})
|
66
55
|
|
67
|
-
export type TableOptionsInput = Partial<
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
>
|
56
|
+
export type TableOptionsInput = Partial<{
|
57
|
+
indexes: SqliteDsl.Index[]
|
58
|
+
disableAutomaticIdColumn: boolean
|
59
|
+
isSingleton: boolean
|
60
|
+
deriveMutations:
|
61
|
+
| boolean
|
62
|
+
| {
|
63
|
+
enabled: true
|
64
|
+
localOnly?: boolean
|
65
|
+
}
|
66
|
+
}>
|
67
|
+
|
68
|
+
type ToColumns<TColumns extends SqliteDsl.Columns | SqliteDsl.ColumnDefinition<any, any>> =
|
69
|
+
TColumns extends SqliteDsl.Columns
|
70
|
+
? TColumns
|
71
|
+
: TColumns extends SqliteDsl.ColumnDefinition<any, any>
|
72
|
+
? { value: TColumns }
|
73
|
+
: never
|
74
|
+
|
75
|
+
type ValidateTableOptionsInput<
|
76
|
+
TColumns extends SqliteDsl.Columns | SqliteDsl.ColumnDefinition<any, any>,
|
77
|
+
TOptionsInput extends TableOptionsInput,
|
78
|
+
TPassthroughIfValid,
|
79
|
+
> =
|
80
|
+
SqliteDsl.FromColumns.RequiresInsertValues<ToColumns<TColumns>> extends true
|
81
|
+
? TOptionsInput['isSingleton'] extends true
|
82
|
+
? 'Error: To use `isSingleton: true` with this table, each column must have a default value or be nullable'
|
83
|
+
: TPassthroughIfValid
|
84
|
+
: TPassthroughIfValid
|
78
85
|
|
79
86
|
export type TableOptions = {
|
80
87
|
/**
|
@@ -85,8 +92,10 @@ export type TableOptions = {
|
|
85
92
|
*
|
86
93
|
* @default false
|
87
94
|
*/
|
88
|
-
isSingleton: boolean
|
89
|
-
|
95
|
+
readonly isSingleton: boolean
|
96
|
+
|
97
|
+
readonly disableAutomaticIdColumn: boolean
|
98
|
+
|
90
99
|
/**
|
91
100
|
* Setting this to true will automatically derive insert, update and delete mutations for this table. Example:
|
92
101
|
*
|
@@ -99,7 +108,7 @@ export type TableOptions = {
|
|
99
108
|
*
|
100
109
|
* Important: When using this option, make sure you're following the "Rules of mutations" for the table schema.
|
101
110
|
*/
|
102
|
-
deriveMutations:
|
111
|
+
readonly deriveMutations:
|
103
112
|
| { enabled: false }
|
104
113
|
| {
|
105
114
|
enabled: true
|
@@ -108,30 +117,34 @@ export type TableOptions = {
|
|
108
117
|
*/
|
109
118
|
localOnly: boolean
|
110
119
|
}
|
120
|
+
|
111
121
|
/** Derived based on whether the table definition has one or more columns (besides the `id` column) */
|
112
|
-
isSingleColumn: boolean
|
122
|
+
readonly isSingleColumn: boolean
|
123
|
+
|
124
|
+
/**
|
125
|
+
* Derived based on whether the table definition has one or more columns (besides the `id` column) that require
|
126
|
+
* insert values (i.e. are not nullable and don't have a default value)
|
127
|
+
*
|
128
|
+
* `isSingleton` tables always imply `requiresInsertValues: false`
|
129
|
+
*/
|
130
|
+
readonly requiredInsertColumnNames: string
|
113
131
|
}
|
114
132
|
|
115
133
|
export const table = <
|
116
134
|
TName extends string,
|
117
135
|
TColumns extends SqliteDsl.Columns | SqliteDsl.ColumnDefinition<any, any>,
|
118
|
-
|
136
|
+
TOptionsInput extends TableOptionsInput = TableOptionsInput,
|
119
137
|
>(
|
120
138
|
name: TName,
|
121
139
|
columnOrColumns: TColumns,
|
122
140
|
options?: TOptionsInput,
|
123
|
-
):
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
>
|
131
|
-
>
|
132
|
-
>,
|
133
|
-
SqliteDsl.IsSingleColumn<TColumns>,
|
134
|
-
WithDefaults<TOptionsInput, SqliteDsl.IsSingleColumn<TColumns>>
|
141
|
+
): ValidateTableOptionsInput<
|
142
|
+
TColumns,
|
143
|
+
TOptionsInput,
|
144
|
+
TableDef<
|
145
|
+
SqliteTableDefForInput<TName, TColumns, WithDefaults<TOptionsInput, TColumns>>,
|
146
|
+
WithDefaults<TOptionsInput, TColumns>
|
147
|
+
>
|
135
148
|
> => {
|
136
149
|
const tablePath = name
|
137
150
|
|
@@ -147,6 +160,7 @@ export const table = <
|
|
147
160
|
? { enabled: false as const }
|
148
161
|
: { enabled: true as const, localOnly: options.deriveMutations.localOnly ?? false },
|
149
162
|
isSingleColumn: SqliteDsl.isColumnDefinition(columnOrColumns) === true,
|
163
|
+
requiredInsertColumnNames: 'type-level-only',
|
150
164
|
}
|
151
165
|
|
152
166
|
const columns = (
|
@@ -183,7 +197,14 @@ export const table = <
|
|
183
197
|
const isSingleColumn = SqliteDsl.isColumnDefinition(columnOrColumns) === true
|
184
198
|
|
185
199
|
const schema = SqliteDsl.structSchemaForTable(sqliteDef)
|
186
|
-
const tableDef = { sqliteDef,
|
200
|
+
const tableDef = { sqliteDef, options: options_, schema } satisfies TableDefBase
|
201
|
+
const query = makeQueryBuilder(tableDef)
|
202
|
+
// const tableDef = { ...tableDefBase, query } satisfies TableDef
|
203
|
+
|
204
|
+
// NOTE we're currently patching the existing tableDef object
|
205
|
+
// as it's being used as part of the query builder API
|
206
|
+
// @ts-expect-error TODO properly implement this
|
207
|
+
tableDef.query = query
|
187
208
|
|
188
209
|
if (tableHasDerivedMutations(tableDef)) {
|
189
210
|
const derivedMutationDefs = makeDerivedMutationDefsForTable(tableDef)
|
@@ -210,17 +231,23 @@ export const table = <
|
|
210
231
|
return tableDef as any
|
211
232
|
}
|
212
233
|
|
213
|
-
export const tableHasDerivedMutations = <TTableDef extends
|
234
|
+
export const tableHasDerivedMutations = <TTableDef extends TableDefBase>(
|
214
235
|
tableDef: TTableDef,
|
215
236
|
): tableDef is TTableDef & {
|
216
237
|
options: { deriveMutations: { enabled: true; localOnly: boolean } }
|
217
238
|
} & DerivedMutationHelperFns<TTableDef['sqliteDef']['columns'], TTableDef['options']> =>
|
218
239
|
tableDef.options.deriveMutations.enabled === true
|
219
240
|
|
220
|
-
export const tableIsSingleton = <TTableDef extends
|
241
|
+
export const tableIsSingleton = <TTableDef extends TableDefBase>(
|
221
242
|
tableDef: TTableDef,
|
222
243
|
): tableDef is TTableDef & { options: { isSingleton: true } } => tableDef.options.isSingleton === true
|
223
244
|
|
245
|
+
type SqliteTableDefForInput<
|
246
|
+
TName extends string,
|
247
|
+
TColumns extends SqliteDsl.Columns | SqliteDsl.ColumnDefinition<any, any>,
|
248
|
+
TOptions extends TableOptions,
|
249
|
+
> = SqliteDsl.TableDefinition<TName, PrettifyFlat<WithId<ToColumns<TColumns>, TOptions>>>
|
250
|
+
|
224
251
|
type WithId<TColumns extends SqliteDsl.Columns, TOptions extends TableOptions> = TColumns &
|
225
252
|
('id' extends keyof TColumns
|
226
253
|
? {}
|
@@ -234,7 +261,10 @@ type WithId<TColumns extends SqliteDsl.Columns, TOptions extends TableOptions> =
|
|
234
261
|
id: SqliteDsl.ColumnDefinition<string, string>
|
235
262
|
})
|
236
263
|
|
237
|
-
type WithDefaults<
|
264
|
+
type WithDefaults<
|
265
|
+
TOptionsInput extends TableOptionsInput,
|
266
|
+
TColumns extends SqliteDsl.Columns | SqliteDsl.ColumnDefinition<any, any>,
|
267
|
+
> = {
|
238
268
|
isSingleton: TOptionsInput['isSingleton'] extends true ? true : false
|
239
269
|
disableAutomaticIdColumn: TOptionsInput['disableAutomaticIdColumn'] extends true ? true : false
|
240
270
|
deriveMutations: TOptionsInput['deriveMutations'] extends true
|
@@ -247,36 +277,37 @@ type WithDefaults<TOptionsInput extends TableOptionsInput, TIsSingleColumn exten
|
|
247
277
|
localOnly: TOptionsInput['deriveMutations']['localOnly'] extends true ? true : false
|
248
278
|
}
|
249
279
|
: never
|
250
|
-
isSingleColumn:
|
280
|
+
isSingleColumn: SqliteDsl.IsSingleColumn<TColumns>
|
281
|
+
requiredInsertColumnNames: SqliteDsl.FromColumns.RequiredInsertColumnNames<ToColumns<TColumns>>
|
251
282
|
}
|
252
283
|
|
253
284
|
export namespace FromTable {
|
254
285
|
// TODO this sometimes doesn't preserve the order of columns
|
255
|
-
export type RowDecoded<TTableDef extends
|
286
|
+
export type RowDecoded<TTableDef extends TableDefBase> = PrettifyFlat<
|
256
287
|
Nullable<Pick<RowDecodedAll<TTableDef>, NullableColumnNames<TTableDef>>> &
|
257
288
|
Omit<RowDecodedAll<TTableDef>, NullableColumnNames<TTableDef>>
|
258
289
|
>
|
259
290
|
|
260
|
-
export type NullableColumnNames<TTableDef extends
|
291
|
+
export type NullableColumnNames<TTableDef extends TableDefBase> = FromColumns.NullableColumnNames<
|
261
292
|
TTableDef['sqliteDef']['columns']
|
262
293
|
>
|
263
294
|
|
264
|
-
export type Columns<TTableDef extends
|
295
|
+
export type Columns<TTableDef extends TableDefBase> = {
|
265
296
|
[K in keyof TTableDef['sqliteDef']['columns']]: TTableDef['sqliteDef']['columns'][K]['columnType']
|
266
297
|
}
|
267
298
|
|
268
|
-
export type RowEncodeNonNullable<TTableDef extends
|
299
|
+
export type RowEncodeNonNullable<TTableDef extends TableDefBase> = {
|
269
300
|
[K in keyof TTableDef['sqliteDef']['columns']]: Schema.Schema.Encoded<
|
270
301
|
TTableDef['sqliteDef']['columns'][K]['schema']
|
271
302
|
>
|
272
303
|
}
|
273
304
|
|
274
|
-
export type RowEncoded<TTableDef extends
|
305
|
+
export type RowEncoded<TTableDef extends TableDefBase> = PrettifyFlat<
|
275
306
|
Nullable<Pick<RowEncodeNonNullable<TTableDef>, NullableColumnNames<TTableDef>>> &
|
276
307
|
Omit<RowEncodeNonNullable<TTableDef>, NullableColumnNames<TTableDef>>
|
277
308
|
>
|
278
309
|
|
279
|
-
export type RowDecodedAll<TTableDef extends
|
310
|
+
export type RowDecodedAll<TTableDef extends TableDefBase> = {
|
280
311
|
[K in keyof TTableDef['sqliteDef']['columns']]: Schema.Schema.Type<TTableDef['sqliteDef']['columns'][K]['schema']>
|
281
312
|
}
|
282
313
|
}
|
@@ -58,7 +58,11 @@ export const insertRow = <TColumns extends SqliteDsl.Columns>({
|
|
58
58
|
values: ClientTypes.DecodedValuesForColumns<TColumns>
|
59
59
|
options?: { orReplace: boolean }
|
60
60
|
}): [string, BindValues] => {
|
61
|
-
const stmt = insertRowPrepared({
|
61
|
+
const stmt = insertRowPrepared({
|
62
|
+
tableName,
|
63
|
+
columns,
|
64
|
+
options: { orReplace: options?.orReplace, keys: Object.keys(values) },
|
65
|
+
})
|
62
66
|
|
63
67
|
return [stmt, makeBindValues({ columns, values })]
|
64
68
|
}
|
@@ -70,12 +74,11 @@ export const insertRowPrepared = <TColumns extends SqliteDsl.Columns>({
|
|
70
74
|
}: {
|
71
75
|
tableName: string
|
72
76
|
columns: TColumns
|
73
|
-
options?: { orReplace: boolean }
|
77
|
+
options?: { orReplace: boolean; keys?: string[] }
|
74
78
|
}): string => {
|
75
|
-
const
|
76
|
-
const
|
77
|
-
|
78
|
-
.join(', ')
|
79
|
+
const keys = options?.keys ?? Object.keys(columns)
|
80
|
+
const keysStr = keys.join(', ')
|
81
|
+
const valuesStr = keys.map((key) => `$${key}`).join(', ')
|
79
82
|
|
80
83
|
return sql`INSERT ${options.orReplace ? 'OR REPLACE ' : ''}INTO ${tableName} (${keysStr}) VALUES (${valuesStr})`
|
81
84
|
}
|
package/src/version.ts
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
// import packageJson from '../package.json' with { type: 'json' }
|
3
3
|
// export const liveStoreVersion = packageJson.version
|
4
4
|
|
5
|
-
export const liveStoreVersion = '0.1.0
|
5
|
+
export const liveStoreVersion = '0.1.0' as const
|
6
6
|
|
7
7
|
/**
|
8
8
|
* This version number is incremented whenever the internal storage format changes in a breaking way.
|