@livestore/livestore 0.0.41 → 0.0.42-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.
Files changed (146) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/{inMemoryDatabase.d.ts → MainDatabaseWrapper.d.ts} +11 -18
  3. package/dist/MainDatabaseWrapper.d.ts.map +1 -0
  4. package/dist/{inMemoryDatabase.js → MainDatabaseWrapper.js} +26 -72
  5. package/dist/MainDatabaseWrapper.js.map +1 -0
  6. package/dist/__tests__/react/fixture.d.ts +41 -40
  7. package/dist/__tests__/react/fixture.d.ts.map +1 -1
  8. package/dist/__tests__/react/fixture.js +2 -8
  9. package/dist/__tests__/react/fixture.js.map +1 -1
  10. package/dist/cud.d.ts +9 -9
  11. package/dist/cud.d.ts.map +1 -1
  12. package/dist/cud.js +7 -8
  13. package/dist/cud.js.map +1 -1
  14. package/dist/effect/LiveStore.d.ts +10 -10
  15. package/dist/effect/LiveStore.d.ts.map +1 -1
  16. package/dist/effect/LiveStore.js +2 -11
  17. package/dist/effect/LiveStore.js.map +1 -1
  18. package/dist/global-state.d.ts +2 -2
  19. package/dist/global-state.d.ts.map +1 -1
  20. package/dist/global-state.js.map +1 -1
  21. package/dist/index.d.ts +6 -6
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +4 -3
  24. package/dist/index.js.map +1 -1
  25. package/dist/migrations.d.ts +5 -5
  26. package/dist/migrations.d.ts.map +1 -1
  27. package/dist/migrations.js +37 -21
  28. package/dist/migrations.js.map +1 -1
  29. package/dist/query-info.d.ts +8 -9
  30. package/dist/query-info.d.ts.map +1 -1
  31. package/dist/query-info.js +1 -1
  32. package/dist/query-info.js.map +1 -1
  33. package/dist/react/LiveStoreProvider.d.ts +7 -7
  34. package/dist/react/LiveStoreProvider.d.ts.map +1 -1
  35. package/dist/react/LiveStoreProvider.js +11 -19
  36. package/dist/react/LiveStoreProvider.js.map +1 -1
  37. package/dist/react/useRow.d.ts +6 -6
  38. package/dist/react/useRow.d.ts.map +1 -1
  39. package/dist/react/useRow.js +2 -2
  40. package/dist/react/useRow.js.map +1 -1
  41. package/dist/reactiveQueries/sql.js +2 -2
  42. package/dist/reactiveQueries/sql.js.map +1 -1
  43. package/dist/reactiveQueries/sql.test.js +12 -31
  44. package/dist/reactiveQueries/sql.test.js.map +1 -1
  45. package/dist/row-query.d.ts +6 -6
  46. package/dist/row-query.d.ts.map +1 -1
  47. package/dist/row-query.js +9 -12
  48. package/dist/row-query.js.map +1 -1
  49. package/dist/store.d.ts +18 -18
  50. package/dist/store.d.ts.map +1 -1
  51. package/dist/store.js +80 -86
  52. package/dist/store.js.map +1 -1
  53. package/dist/utils/bounded-collections.d.ts +1 -1
  54. package/dist/utils/bounded-collections.d.ts.map +1 -1
  55. package/dist/utils/bounded-collections.js +2 -1
  56. package/dist/utils/bounded-collections.js.map +1 -1
  57. package/dist/utils/util.d.ts +0 -16
  58. package/dist/utils/util.d.ts.map +1 -1
  59. package/dist/utils/util.js +0 -38
  60. package/dist/utils/util.js.map +1 -1
  61. package/package.json +8 -44
  62. package/src/{inMemoryDatabase.ts → MainDatabaseWrapper.ts} +40 -94
  63. package/src/__tests__/react/fixture.tsx +3 -9
  64. package/src/cud.ts +17 -16
  65. package/src/effect/LiveStore.ts +12 -24
  66. package/src/global-state.ts +3 -2
  67. package/src/index.ts +7 -23
  68. package/src/migrations.ts +51 -34
  69. package/src/query-info.ts +10 -9
  70. package/src/react/LiveStoreProvider.tsx +19 -27
  71. package/src/react/useRow.ts +24 -12
  72. package/src/reactiveQueries/sql.test.ts +12 -31
  73. package/src/reactiveQueries/sql.ts +2 -2
  74. package/src/row-query.ts +32 -29
  75. package/src/store.ts +98 -103
  76. package/src/utils/bounded-collections.ts +3 -2
  77. package/src/utils/util.ts +0 -44
  78. package/tsconfig.json +1 -1
  79. package/vitest.config.js +4 -0
  80. package/dist/inMemoryDatabase.d.ts.map +0 -1
  81. package/dist/inMemoryDatabase.js.map +0 -1
  82. package/dist/schema/index.d.ts +0 -42
  83. package/dist/schema/index.d.ts.map +0 -1
  84. package/dist/schema/index.js +0 -42
  85. package/dist/schema/index.js.map +0 -1
  86. package/dist/schema/mutations.d.ts +0 -81
  87. package/dist/schema/mutations.d.ts.map +0 -1
  88. package/dist/schema/mutations.js +0 -29
  89. package/dist/schema/mutations.js.map +0 -1
  90. package/dist/schema/parse-utils.d.ts +0 -6
  91. package/dist/schema/parse-utils.d.ts.map +0 -1
  92. package/dist/schema/parse-utils.js +0 -22
  93. package/dist/schema/parse-utils.js.map +0 -1
  94. package/dist/schema/system-tables.d.ts +0 -76
  95. package/dist/schema/system-tables.d.ts.map +0 -1
  96. package/dist/schema/system-tables.js +0 -11
  97. package/dist/schema/system-tables.js.map +0 -1
  98. package/dist/schema/table-def.d.ts +0 -100
  99. package/dist/schema/table-def.d.ts.map +0 -1
  100. package/dist/schema/table-def.js +0 -70
  101. package/dist/schema/table-def.js.map +0 -1
  102. package/dist/storage/in-memory/index.d.ts +0 -19
  103. package/dist/storage/in-memory/index.d.ts.map +0 -1
  104. package/dist/storage/in-memory/index.js +0 -16
  105. package/dist/storage/in-memory/index.js.map +0 -1
  106. package/dist/storage/index.d.ts +0 -18
  107. package/dist/storage/index.d.ts.map +0 -1
  108. package/dist/storage/index.js +0 -9
  109. package/dist/storage/index.js.map +0 -1
  110. package/dist/storage/tauri/index.d.ts +0 -23
  111. package/dist/storage/tauri/index.d.ts.map +0 -1
  112. package/dist/storage/tauri/index.js +0 -46
  113. package/dist/storage/tauri/index.js.map +0 -1
  114. package/dist/storage/utils/idb.d.ts +0 -11
  115. package/dist/storage/utils/idb.d.ts.map +0 -1
  116. package/dist/storage/utils/idb.js +0 -71
  117. package/dist/storage/utils/idb.js.map +0 -1
  118. package/dist/storage/web-worker/common.d.ts +0 -11
  119. package/dist/storage/web-worker/common.d.ts.map +0 -1
  120. package/dist/storage/web-worker/common.js +0 -2
  121. package/dist/storage/web-worker/common.js.map +0 -1
  122. package/dist/storage/web-worker/index.d.ts +0 -34
  123. package/dist/storage/web-worker/index.d.ts.map +0 -1
  124. package/dist/storage/web-worker/index.js +0 -134
  125. package/dist/storage/web-worker/index.js.map +0 -1
  126. package/dist/storage/web-worker/make-worker.d.ts +0 -20
  127. package/dist/storage/web-worker/make-worker.d.ts.map +0 -1
  128. package/dist/storage/web-worker/make-worker.js +0 -155
  129. package/dist/storage/web-worker/make-worker.js.map +0 -1
  130. package/dist/storage/web-worker/vite-dev-polyfill.d.ts +0 -2
  131. package/dist/storage/web-worker/vite-dev-polyfill.d.ts.map +0 -1
  132. package/dist/storage/web-worker/vite-dev-polyfill.js +0 -35
  133. package/dist/storage/web-worker/vite-dev-polyfill.js.map +0 -1
  134. package/src/schema/index.ts +0 -100
  135. package/src/schema/mutations.ts +0 -128
  136. package/src/schema/parse-utils.ts +0 -42
  137. package/src/schema/system-tables.ts +0 -21
  138. package/src/schema/table-def.ts +0 -270
  139. package/src/storage/in-memory/index.ts +0 -28
  140. package/src/storage/index.ts +0 -36
  141. package/src/storage/tauri/index.ts +0 -66
  142. package/src/storage/utils/idb.ts +0 -85
  143. package/src/storage/web-worker/common.ts +0 -6
  144. package/src/storage/web-worker/index.ts +0 -185
  145. package/src/storage/web-worker/make-worker.ts +0 -214
  146. package/src/storage/web-worker/vite-dev-polyfill.ts +0 -33
@@ -1,100 +0,0 @@
1
- import type { ReadonlyArray } from '@livestore/utils/effect'
2
- import type { SqliteDsl } from 'effect-db-schema'
3
-
4
- import { isReadonlyArray } from '../utils/util.js'
5
- import {
6
- type MutationDef,
7
- type MutationDefMap,
8
- type MutationDefRecord,
9
- type RawSqlMutation,
10
- rawSqlMutation,
11
- } from './mutations.js'
12
- import { systemTables } from './system-tables.js'
13
- import type { TableDef } from './table-def.js'
14
-
15
- export * from './system-tables.js'
16
- export * as DbSchema from './table-def.js'
17
- export * as ParseUtils from './parse-utils.js'
18
- export * from './mutations.js'
19
-
20
- export type LiveStoreSchema<
21
- TDbSchema extends SqliteDsl.DbSchema = SqliteDsl.DbSchema,
22
- TMutationsDefRecord extends MutationDefRecord = MutationDefRecord,
23
- > = {
24
- /** Only used on type-level */
25
- readonly _DbSchemaType: TDbSchema
26
- /** Only used on type-level */
27
- readonly _MutationDefMapType: TMutationsDefRecord
28
-
29
- readonly tables: Map<string, TableDef>
30
- readonly mutations: MutationDefMap
31
- }
32
-
33
- export type InputSchema = {
34
- readonly tables: Record<string, TableDef> | ReadonlyArray<TableDef>
35
- readonly mutations?: ReadonlyArray<MutationDef.Any> | Record<string, MutationDef.Any>
36
- }
37
-
38
- export const makeSchema = <TInputSchema extends InputSchema>(
39
- /** Note when using the object-notation for tables/mutations, the object keys are ignored and not used as table/mutation names */
40
- schema: TInputSchema,
41
- ): LiveStoreSchema<
42
- DbSchemaFromInputSchemaTables<TInputSchema['tables']>,
43
- MutationDefRecordFromInputSchemaMutations<TInputSchema['mutations']>
44
- > => {
45
- const inputTables: ReadonlyArray<TableDef> = Array.isArray(schema.tables)
46
- ? schema.tables
47
- : // TODO validate that table names are unique in this case
48
- Object.values(schema.tables)
49
-
50
- const tables = new Map<string, TableDef>()
51
-
52
- for (const tableDef of inputTables) {
53
- // TODO validate tables (e.g. index names are unique)
54
- tables.set(tableDef.sqliteDef.ast.name, tableDef)
55
- }
56
-
57
- for (const tableDef of systemTables) {
58
- tables.set(tableDef.sqliteDef.name, tableDef)
59
- }
60
-
61
- const mutations: MutationDefMap = new Map()
62
-
63
- if (isReadonlyArray(schema.mutations)) {
64
- for (const mutation of schema.mutations) {
65
- mutations.set(mutation.name, mutation)
66
- }
67
- } else {
68
- for (const [name, mutation] of Object.entries(schema.mutations ?? {})) {
69
- mutations.set(name, mutation)
70
- }
71
- }
72
-
73
- mutations.set('livestore.RawSql', rawSqlMutation)
74
-
75
- return {
76
- _DbSchemaType: Symbol('livestore.DbSchemaType') as any,
77
- _MutationDefMapType: Symbol('livestore.MutationDefMapType') as any,
78
- tables,
79
- mutations,
80
- } satisfies LiveStoreSchema
81
- }
82
-
83
- /**
84
- * In case of ...
85
- * - array: we use the table name of each array item (= table definition) as the object key
86
- * - object: we discard the keys of the input object and use the table name of each object value (= table definition) as the new object key
87
- */
88
- export type DbSchemaFromInputSchemaTables<TTables extends InputSchema['tables']> =
89
- TTables extends ReadonlyArray<TableDef>
90
- ? { [K in TTables[number] as K['sqliteDef']['name']]: K['sqliteDef'] }
91
- : TTables extends Record<string, TableDef>
92
- ? { [K in keyof TTables as TTables[K]['sqliteDef']['name']]: TTables[K]['sqliteDef'] }
93
- : never
94
-
95
- export type MutationDefRecordFromInputSchemaMutations<TMutations extends InputSchema['mutations']> =
96
- TMutations extends ReadonlyArray<MutationDef.Any>
97
- ? { [K in TMutations[number] as K['name']]: K } & { 'livestore.RawSql': RawSqlMutation }
98
- : TMutations extends { [name: string]: MutationDef.Any }
99
- ? { [K in keyof TMutations as TMutations[K]['name']]: TMutations[K] } & { 'livestore.RawSql': RawSqlMutation }
100
- : never
@@ -1,128 +0,0 @@
1
- import type { BindValues } from '@livestore/sql-queries'
2
- import { cuid } from '@livestore/utils/cuid'
3
- import { Schema } from '@livestore/utils/effect'
4
-
5
- import type { LiveStoreSchema } from './index.js'
6
-
7
- export type MutationDefMap = Map<string | 'livestore.RawSql', MutationDef.Any>
8
- export type MutationDefRecord = {
9
- 'livestore.RawSql': RawSqlMutation
10
- [name: string]: MutationDef.Any
11
- }
12
-
13
- export type InternalMutationSchema<TRecord extends MutationDefRecord = MutationDefRecord> = {
14
- _DefRecord: TRecord
15
-
16
- map: Map<keyof TRecord, TRecord[keyof TRecord]>
17
- schemaHashMap: Map<keyof TRecord, number>
18
- }
19
-
20
- export type MutationDef<TName extends string, TFrom, TTo> = {
21
- name: TName
22
- schema: Schema.Schema<TTo, TFrom>
23
- sql:
24
- | string
25
- | ((args: TTo) =>
26
- | string
27
- | {
28
- sql: string
29
- /** Note args need to be manually encoded to `BindValues` when returning this argument */
30
- bindValues: BindValues
31
- writeTables?: ReadonlySet<string>
32
- })
33
-
34
- /** Helper function to construct mutation event */
35
- (args: TTo): { mutation: TName; args: TTo; id: string }
36
- }
37
-
38
- export namespace MutationDef {
39
- export type Any = MutationDef<string, any, any>
40
- }
41
-
42
- // TODO possibly also allow for mutation event subsumption behaviour
43
- export const defineMutation = <TName extends string, TFrom, TTo>(
44
- name: TName,
45
- schema: Schema.Schema<TTo, TFrom>,
46
- sql: string | ((args: TTo) => string | { sql: string; bindValues: BindValues; writeTables?: ReadonlySet<string> }),
47
- ): MutationDef<TName, TFrom, TTo> => {
48
- const makeEvent = (args: TTo) => ({ mutation: name, args, id: cuid() })
49
-
50
- Object.defineProperty(makeEvent, 'name', { value: name })
51
- Object.defineProperty(makeEvent, 'schema', { value: schema })
52
- Object.defineProperty(makeEvent, 'sql', { value: sql })
53
-
54
- return makeEvent as MutationDef<TName, TFrom, TTo>
55
- }
56
-
57
- export const makeMutationDefRecord = <TInputRecord extends Record<string, MutationDef.Any>>(
58
- inputRecord: TInputRecord,
59
- ): {
60
- [K in TInputRecord[keyof TInputRecord]['name']]: Extract<TInputRecord[keyof TInputRecord], { name: K }>
61
- } => {
62
- const result: any = {}
63
-
64
- for (const [name, def] of Object.entries(inputRecord)) {
65
- result[name] = def
66
- }
67
-
68
- result['livestore.RawSql'] = rawSqlMutation
69
-
70
- return result
71
- }
72
-
73
- export const rawSqlMutation = defineMutation(
74
- 'livestore.RawSql',
75
- Schema.struct({
76
- sql: Schema.string,
77
- bindValues: Schema.optional(Schema.record(Schema.string, Schema.any)),
78
- writeTables: Schema.optional(Schema.readonlySet(Schema.string)),
79
- }),
80
- ({ sql, bindValues, writeTables }) => ({ sql, bindValues: bindValues ?? {}, writeTables }),
81
- )
82
-
83
- export type RawSqlMutation = typeof rawSqlMutation
84
- export type RawSqlMutationEvent = ReturnType<typeof rawSqlMutation>
85
-
86
- export type MutationEvent<TMutationsDef extends MutationDef.Any> = {
87
- mutation: TMutationsDef['name']
88
- args: Schema.Schema.To<TMutationsDef['schema']>
89
- id: string
90
- }
91
-
92
- export namespace MutationEvent {
93
- export type Any = MutationEvent<MutationDef.Any>
94
-
95
- export type ForSchema<TSchema extends LiveStoreSchema> = {
96
- [K in keyof TSchema['_MutationDefMapType']]: MutationEvent<TSchema['_MutationDefMapType'][K]>
97
- }[keyof TSchema['_MutationDefMapType']]
98
- }
99
-
100
- export type MutationEventSchema<TMutationsDefRecord extends MutationDefRecord> = Schema.Schema<
101
- {
102
- [K in keyof TMutationsDefRecord]: {
103
- mutation: K
104
- args: Schema.Schema.To<TMutationsDefRecord[K]['schema']>
105
- id: string
106
- }
107
- }[keyof TMutationsDefRecord],
108
- {
109
- [K in keyof TMutationsDefRecord]: {
110
- mutation: K
111
- args: Schema.Schema.From<TMutationsDefRecord[K]['schema']>
112
- id: string
113
- }
114
- }[keyof TMutationsDefRecord]
115
- >
116
-
117
- export const makeMutationEventSchema = <TMutationsDefRecord extends MutationDefRecord>(
118
- mutationDefRecord: TMutationsDefRecord,
119
- ): MutationEventSchema<TMutationsDefRecord> =>
120
- Schema.union(
121
- ...Object.values(mutationDefRecord).map((def) =>
122
- Schema.struct({
123
- mutation: Schema.literal(def.name),
124
- args: def.schema,
125
- id: Schema.string,
126
- }),
127
- ),
128
- ) as any
@@ -1,42 +0,0 @@
1
- import { shouldNeverHappen } from '@livestore/utils'
2
- import type { ReadonlyArray } from '@livestore/utils/effect'
3
- import { pipe, ReadonlyRecord, Schema, TreeFormatter } from '@livestore/utils/effect'
4
- import { SqliteDsl } from 'effect-db-schema' // eslint-disable-line
5
-
6
- import { type FromColumns, type FromTable, getDefaultValuesDecoded, type TableDef } from './table-def.js'
7
-
8
- export const many = <TTableDef extends TableDef>(
9
- table: TTableDef,
10
- ): ((rawRows: ReadonlyArray<any>) => ReadonlyArray<FromTable.RowDecoded<TTableDef>>) => {
11
- return Schema.decodeSync(Schema.array(table.schema)) as TODO
12
- }
13
-
14
- export const first =
15
- <TTableDef extends TableDef>(
16
- table: TTableDef,
17
- fallback?: FromColumns.InsertRowDecoded<TTableDef['sqliteDef']['columns']>,
18
- ) =>
19
- (rawRows: ReadonlyArray<any>) => {
20
- const rows = Schema.decodeSync(Schema.array(table.schema))(rawRows)
21
-
22
- if (rows.length === 0) {
23
- const schemaDefaultValues = getDefaultValuesDecoded(table)
24
-
25
- const defaultValuesResult = pipe(
26
- table.sqliteDef.columns,
27
- ReadonlyRecord.map((_column, columnName) => (fallback as any)?.[columnName] ?? schemaDefaultValues[columnName]),
28
- Schema.validateEither(table.schema),
29
- )
30
-
31
- if (defaultValuesResult._tag === 'Right') {
32
- return defaultValuesResult.right
33
- } else {
34
- console.error('decode error', TreeFormatter.formatError(defaultValuesResult.left))
35
- return shouldNeverHappen(
36
- `Expected query (for table ${table.sqliteDef.name}) to return at least one result but found none. Also can't fallback to default values as some were not provided.`,
37
- )
38
- }
39
- }
40
-
41
- return rows[0]!
42
- }
@@ -1,21 +0,0 @@
1
- import { type SqliteAst as __SqliteAst, SqliteDsl } from 'effect-db-schema'
2
-
3
- import type { FromTable } from './table-def.js'
4
- import { table } from './table-def.js'
5
-
6
- export const SCHEMA_META_TABLE = '__livestore_schema'
7
-
8
- const schemaMetaTable = table(
9
- SCHEMA_META_TABLE,
10
- {
11
- tableName: SqliteDsl.text({ primaryKey: true }),
12
- schemaHash: SqliteDsl.integer({ nullable: false }),
13
- /** ISO date format */
14
- updatedAt: SqliteDsl.text({ nullable: false }),
15
- },
16
- { disableAutomaticIdColumn: true },
17
- )
18
-
19
- export type SchemaMetaRow = FromTable.RowDecoded<typeof schemaMetaTable>
20
-
21
- export const systemTables = [schemaMetaTable]
@@ -1,270 +0,0 @@
1
- import { shouldNeverHappen } from '@livestore/utils'
2
- import { pipe, ReadonlyRecord, Schema } from '@livestore/utils/effect'
3
- import type { Nullable, PrettifyFlat } from 'effect-db-schema'
4
- import { SqliteAst, SqliteDsl } from 'effect-db-schema'
5
-
6
- export const { blob, boolean, column, datetime, integer, isColumnDefinition, json, real, text } = SqliteDsl
7
-
8
- export { type SqliteDsl } from 'effect-db-schema'
9
-
10
- import { dynamicallyRegisteredTables } from '../global-state.js'
11
-
12
- export type StateType = 'singleton' | 'dynamic'
13
-
14
- export type DefaultSqliteTableDef = SqliteDsl.TableDefinition<string, SqliteDsl.Columns>
15
- export type DefaultSqliteTableDefConstrained = SqliteDsl.TableDefinition<string, SqliteDsl.ConstraintColumns>
16
-
17
- // export type TableDefConstraint<
18
- // TSqliteDef extends DefaultSqliteTableDef = DefaultSqliteTableDef,
19
- // TIsSingleColumn extends boolean = boolean,
20
- // TOptions extends TableOptions = TableOptions,
21
- // > = TableDefBase<TSqliteDef, TIsSingleColumn, TOptions> & { schema: Schema.Schema<any> }
22
-
23
- // /**
24
- // * NOTE in the past we used to have a single `TableDef` but there are some TS issues when indroducing
25
- // * `schema: SqliteDsl.StructSchemaForColumns<TSqliteDef>` so we split it into two types
26
- // * and only use `TableDefConstraint` in some places
27
- // */
28
- // export type TableDefBase<
29
- // TSqliteDef extends DefaultSqliteTableDef = DefaultSqliteTableDef,
30
- // TIsSingleColumn extends boolean = boolean,
31
- // TOptions extends TableOptions = TableOptions,
32
- // > = {
33
- // sqliteDef: TSqliteDef
34
- // // schema: SqliteDsl.StructSchemaForColumns<TSqliteDef>
35
- // // schema: any;
36
- // isSingleColumn: TIsSingleColumn
37
- // options: TOptions
38
- // }
39
-
40
- export type TableDef<
41
- TSqliteDef extends DefaultSqliteTableDef = DefaultSqliteTableDefConstrained,
42
- TIsSingleColumn extends boolean = boolean,
43
- TOptions extends TableOptions = TableOptions,
44
- // NOTE we're not using `SqliteDsl.StructSchemaForColumns<TSqliteDef['columns']>`
45
- // as we don't want the alias type for users to show up
46
- TSchema = Schema.Schema<
47
- SqliteDsl.AnyIfConstained<
48
- TSqliteDef['columns'],
49
- { readonly [K in keyof TSqliteDef['columns']]: Schema.Schema.To<TSqliteDef['columns'][K]['schema']> }
50
- >,
51
- SqliteDsl.AnyIfConstained<
52
- TSqliteDef['columns'],
53
- { readonly [K in keyof TSqliteDef['columns']]: Schema.Schema.From<TSqliteDef['columns'][K]['schema']> }
54
- >
55
- >,
56
- > = {
57
- sqliteDef: TSqliteDef
58
- isSingleColumn: TIsSingleColumn
59
- options: TOptions
60
- schema: TSchema
61
- }
62
-
63
- export type TableOptionsInput = Partial<TableOptions & { indexes: SqliteDsl.Index[] }>
64
-
65
- export type TableOptions = {
66
- /**
67
- * Setting this to true will have the following consequences:
68
- * - An `id` column will be added with `primaryKey: true` and `"singleton"` as default value and only allowed value
69
- * - LiveStore will automatically create the singleton row when the table is created
70
- * - LiveStore will fail if there is already a column defined with `primaryKey: true`
71
- *
72
- * @default false
73
- */
74
- isSingleton: boolean
75
- // TODO
76
- dynamicRegistration: boolean
77
- disableAutomaticIdColumn: boolean
78
- }
79
-
80
- export const table = <
81
- TName extends string,
82
- TColumns extends SqliteDsl.Columns | SqliteDsl.ColumnDefinition<any, any>,
83
- const TOptionsInput extends TableOptionsInput = TableOptionsInput,
84
- >(
85
- name: TName,
86
- columnOrColumns: TColumns,
87
- // type?: TStateType,
88
- options?: TOptionsInput,
89
- ): TableDef<
90
- SqliteDsl.TableDefinition<
91
- TName,
92
- PrettifyFlat<
93
- WithId<TColumns extends SqliteDsl.Columns ? TColumns : { value: TColumns }, WithDefaults<TOptionsInput>>
94
- >
95
- >,
96
- TColumns extends SqliteDsl.ColumnDefinition<any, any> ? true : false,
97
- WithDefaults<TOptionsInput>
98
- > => {
99
- const tablePath = name
100
-
101
- const options_: TableOptions = {
102
- isSingleton: options?.isSingleton ?? false,
103
- dynamicRegistration: options?.dynamicRegistration ?? false,
104
- disableAutomaticIdColumn: options?.disableAutomaticIdColumn ?? false,
105
- }
106
-
107
- const columns = (
108
- SqliteDsl.isColumnDefinition(columnOrColumns) ? { value: columnOrColumns } : columnOrColumns
109
- ) as SqliteDsl.Columns
110
-
111
- if (options_.disableAutomaticIdColumn === true) {
112
- if (columns.id === undefined && options_.isSingleton === true) {
113
- shouldNeverHappen(
114
- `Cannot create table ${name} with "isSingleton: true" because there is no column with name "id" and "disableAutomaticIdColumn: true" is set`,
115
- )
116
- }
117
- } else if (columns.id === undefined && ReadonlyRecord.some(columns, (_) => _.primaryKey === true) === false) {
118
- if (options_.isSingleton) {
119
- columns.id = SqliteDsl.text({ schema: Schema.literal('singleton'), primaryKey: true, default: 'singleton' })
120
- } else {
121
- columns.id = SqliteDsl.text({ primaryKey: true })
122
- }
123
- }
124
-
125
- const sqliteDef = SqliteDsl.table(tablePath, columns, options?.indexes ?? [])
126
-
127
- if (options_.isSingleton) {
128
- for (const column of sqliteDef.ast.columns) {
129
- if (column.nullable === false && column.default._tag === 'None') {
130
- shouldNeverHappen(
131
- `When creating a singleton table, each column must be either nullable or have a default value. Column '${column.name}' is neither.`,
132
- )
133
- }
134
- }
135
- }
136
-
137
- const isSingleColumn = SqliteDsl.isColumnDefinition(columnOrColumns) === true
138
-
139
- const schema = SqliteDsl.structSchemaForTable(sqliteDef)
140
- const tableDef = { sqliteDef, isSingleColumn, options: options_, schema } satisfies TableDef
141
-
142
- if (dynamicallyRegisteredTables.has(tablePath)) {
143
- if (SqliteAst.hash(dynamicallyRegisteredTables.get(tablePath)!.sqliteDef.ast) !== SqliteAst.hash(sqliteDef.ast)) {
144
- console.error('previous tableDef', dynamicallyRegisteredTables.get(tablePath), 'new tableDef', sqliteDef.ast)
145
- shouldNeverHappen(`Table with name "${name}" was already previously defined with a different definition`)
146
- }
147
- } else {
148
- dynamicallyRegisteredTables.set(tablePath, tableDef)
149
- }
150
-
151
- return tableDef as any
152
- }
153
-
154
- export const tableIsSingleton = <TTableDef extends TableDef>(
155
- tableDef: TTableDef,
156
- ): tableDef is TTableDef & { options: { isSingleton: true } } => tableDef.options.isSingleton === true
157
-
158
- export const getDefaultValuesEncoded = <TTableDef extends TableDef>(
159
- tableDef: TTableDef,
160
- fallbackValues?: Record<string, any>,
161
- ) =>
162
- pipe(
163
- tableDef.sqliteDef.columns,
164
- ReadonlyRecord.filter((col, key) => {
165
- if (fallbackValues?.[key] !== undefined) return true
166
- if (key === 'id') return false
167
- return col!.default._tag === 'None' || SqliteDsl.isSqlDefaultValue(col!.default.value) === false
168
- }),
169
- ReadonlyRecord.map((column, columnName) =>
170
- fallbackValues?.[columnName] === undefined
171
- ? column!.default._tag === 'None'
172
- ? column!.nullable === true
173
- ? null
174
- : shouldNeverHappen(`Column ${columnName} has no default value and is not nullable`)
175
- : Schema.encodeSync(column!.schema)(column!.default.value)
176
- : fallbackValues[columnName],
177
- ),
178
- )
179
-
180
- export const getDefaultValuesDecoded = <TTableDef extends TableDef>(tableDef: TTableDef) =>
181
- pipe(
182
- tableDef.sqliteDef.columns,
183
- ReadonlyRecord.filter((_, key) => key !== 'id'),
184
- ReadonlyRecord.filter(
185
- (col) => col!.default._tag === 'None' || SqliteDsl.isSqlDefaultValue(col!.default.value) === false,
186
- ),
187
- ReadonlyRecord.map((column, columnName) =>
188
- column!.default._tag === 'None'
189
- ? column!.nullable === true
190
- ? null
191
- : shouldNeverHappen(`Column ${columnName} has no default value and is not nullable`)
192
- : Schema.validateSync(column!.schema)(column!.default.value),
193
- ),
194
- )
195
-
196
- type WithId<TColumns extends SqliteDsl.Columns, TOptions extends TableOptions> = TColumns &
197
- (TOptions['disableAutomaticIdColumn'] extends true
198
- ? {}
199
- : TOptions['isSingleton'] extends true
200
- ? {
201
- id: SqliteDsl.ColumnDefinition<'singleton', 'singleton'>
202
- }
203
- : {
204
- id: SqliteDsl.ColumnDefinition<string, string>
205
- })
206
-
207
- type WithDefaults<TOptionsInput extends TableOptionsInput> = {
208
- isSingleton: TOptionsInput['isSingleton'] extends true ? true : false
209
- dynamicRegistration: TOptionsInput['dynamicRegistration'] extends true ? true : false
210
- disableAutomaticIdColumn: TOptionsInput['disableAutomaticIdColumn'] extends true ? true : false
211
- }
212
-
213
- export namespace FromTable {
214
- // TODO this sometimes doesn't preserve the order of columns
215
- export type RowDecoded<TTableDef extends TableDef> = PrettifyFlat<
216
- Nullable<Pick<RowDecodedAll<TTableDef>, NullableColumnNames<TTableDef>>> &
217
- Omit<RowDecodedAll<TTableDef>, NullableColumnNames<TTableDef>>
218
- >
219
-
220
- export type NullableColumnNames<TTableDef extends TableDef> = FromColumns.NullableColumnNames<
221
- TTableDef['sqliteDef']['columns']
222
- >
223
-
224
- export type Columns<TTableDef extends TableDef> = {
225
- [K in keyof TTableDef['sqliteDef']['columns']]: TTableDef['sqliteDef']['columns'][K]['columnType']
226
- }
227
-
228
- export type RowEncodeNonNullable<TTableDef extends TableDef> = {
229
- [K in keyof TTableDef['sqliteDef']['columns']]: Schema.Schema.From<TTableDef['sqliteDef']['columns'][K]['schema']>
230
- }
231
-
232
- export type RowEncoded<TTableDef extends TableDef> = PrettifyFlat<
233
- Nullable<Pick<RowEncodeNonNullable<TTableDef>, NullableColumnNames<TTableDef>>> &
234
- Omit<RowEncodeNonNullable<TTableDef>, NullableColumnNames<TTableDef>>
235
- >
236
-
237
- export type RowDecodedAll<TTableDef extends TableDef> = {
238
- [K in keyof TTableDef['sqliteDef']['columns']]: Schema.Schema.To<TTableDef['sqliteDef']['columns'][K]['schema']>
239
- }
240
- }
241
-
242
- export namespace FromColumns {
243
- // TODO this sometimes doesn't preserve the order of columns
244
- export type RowDecoded<TColumns extends SqliteDsl.Columns> = PrettifyFlat<
245
- Nullable<Pick<RowDecodedAll<TColumns>, NullableColumnNames<TColumns>>> &
246
- Omit<RowDecodedAll<TColumns>, NullableColumnNames<TColumns>>
247
- >
248
-
249
- export type RowDecodedAll<TColumns extends SqliteDsl.Columns> = {
250
- [K in keyof TColumns]: Schema.Schema.To<TColumns[K]['schema']>
251
- }
252
-
253
- export type RowEncoded<TColumns extends SqliteDsl.Columns> = PrettifyFlat<
254
- Nullable<Pick<RowEncodeNonNullable<TColumns>, NullableColumnNames<TColumns>>> &
255
- Omit<RowEncodeNonNullable<TColumns>, NullableColumnNames<TColumns>>
256
- >
257
-
258
- export type RowEncodeNonNullable<TColumns extends SqliteDsl.Columns> = {
259
- [K in keyof TColumns]: Schema.Schema.From<TColumns[K]['schema']>
260
- }
261
-
262
- export type NullableColumnNames<TColumns extends SqliteDsl.Columns> = keyof {
263
- [K in keyof TColumns as TColumns[K]['default'] extends true ? K : never]: {}
264
- }
265
-
266
- export type RequiredInsertColumnNames<TColumns extends SqliteDsl.Columns> =
267
- SqliteDsl.FromColumns.RequiredInsertColumnNames<TColumns>
268
-
269
- export type InsertRowDecoded<TColumns extends SqliteDsl.Columns> = SqliteDsl.FromColumns.InsertRowDecoded<TColumns>
270
- }
@@ -1,28 +0,0 @@
1
- import type * as otel from '@opentelemetry/api'
2
-
3
- import type { MutationEvent } from '../../index.js'
4
- import type { PreparedBindValues } from '../../utils/util.js'
5
- import type { Storage, StorageOtelProps } from '../index.js'
6
-
7
- export type StorageOptionsWebInMemory = {
8
- type: 'web-in-memory'
9
- }
10
-
11
- /** NOTE: This storage is currently only used for testing */
12
- export class InMemoryStorage implements Storage {
13
- constructor(readonly otelTracer: otel.Tracer) {}
14
-
15
- static load = async (_options?: StorageOptionsWebInMemory) => {
16
- return ({ otelTracer }: StorageOtelProps) => new InMemoryStorage(otelTracer)
17
- }
18
-
19
- execute = (_query: string, _bindValues?: PreparedBindValues): void => {}
20
-
21
- mutate = (_mutationEventEncoded: MutationEvent.Any, _parentSpan?: otel.Span | undefined) => {}
22
-
23
- getPersistedData = async (): Promise<Uint8Array> => new Uint8Array()
24
-
25
- getMutationLogData = async (): Promise<Uint8Array> => new Uint8Array()
26
-
27
- dangerouslyReset = async () => {}
28
- }
@@ -1,36 +0,0 @@
1
- // A storage represents a raw SQLite database.
2
- // Examples include:
3
- // - A native SQLite process running in a Tauri Rust process
4
- // - A SQL.js WASM version of SQLite running in a web worker
5
- //
6
- // We can send commands to execute various kinds of queries,
7
- // and respond to various events from the database.
8
-
9
- import type * as otel from '@opentelemetry/api'
10
-
11
- import type { MutationEvent } from '../index.js'
12
- import type { PreparedBindValues } from '../utils/util.js'
13
-
14
- export type StorageInit = (otelProps: StorageOtelProps) => Promise<Storage> | Storage
15
-
16
- export interface Storage {
17
- // TODO consider transferables for `bindValues` (e.g. Uint8Array values)
18
- execute(query: string, bindValues?: PreparedBindValues, parentSpan?: otel.Span): void
19
-
20
- // TODO consider transferables for `bindValues` (e.g. Uint8Array values)
21
- mutate(mutationEventEncoded: MutationEvent.Any, parentSpan?: otel.Span): void
22
-
23
- /** Return a snapshot of persisted data from the storage */
24
- getPersistedData(parentSpan?: otel.Span): Promise<Uint8Array>
25
-
26
- getMutationLogData(parentSpan?: otel.Span): Promise<Uint8Array>
27
-
28
- dangerouslyReset(): Promise<void>
29
- }
30
-
31
- export type StorageType = 'tauri' | 'web' | 'web-in-memory'
32
-
33
- export type StorageOtelProps = {
34
- otelTracer: otel.Tracer
35
- parentSpan: otel.Span
36
- }