@livestore/common 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 (68) hide show
  1. package/dist/.tsbuildinfo +1 -0
  2. package/dist/database.d.ts +32 -0
  3. package/dist/database.d.ts.map +1 -0
  4. package/dist/database.js +2 -0
  5. package/dist/database.js.map +1 -0
  6. package/dist/index.d.ts +4 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +4 -0
  9. package/dist/index.js.map +1 -0
  10. package/dist/schema/index.d.ts +42 -0
  11. package/dist/schema/index.d.ts.map +1 -0
  12. package/dist/schema/index.js +42 -0
  13. package/dist/schema/index.js.map +1 -0
  14. package/dist/schema/mutations.d.ts +81 -0
  15. package/dist/schema/mutations.d.ts.map +1 -0
  16. package/dist/schema/mutations.js +29 -0
  17. package/dist/schema/mutations.js.map +1 -0
  18. package/dist/schema/parse-utils.d.ts +6 -0
  19. package/dist/schema/parse-utils.d.ts.map +1 -0
  20. package/dist/schema/parse-utils.js +22 -0
  21. package/dist/schema/parse-utils.js.map +1 -0
  22. package/dist/schema/system-tables.d.ts +76 -0
  23. package/dist/schema/system-tables.d.ts.map +1 -0
  24. package/dist/schema/system-tables.js +12 -0
  25. package/dist/schema/system-tables.js.map +1 -0
  26. package/dist/schema/table-def.d.ts +100 -0
  27. package/dist/schema/table-def.d.ts.map +1 -0
  28. package/dist/schema/table-def.js +76 -0
  29. package/dist/schema/table-def.js.map +1 -0
  30. package/dist/sql-queries/index.d.ts +4 -0
  31. package/dist/sql-queries/index.d.ts.map +1 -0
  32. package/dist/sql-queries/index.js +4 -0
  33. package/dist/sql-queries/index.js.map +1 -0
  34. package/dist/sql-queries/misc.d.ts +2 -0
  35. package/dist/sql-queries/misc.d.ts.map +1 -0
  36. package/dist/sql-queries/misc.js +2 -0
  37. package/dist/sql-queries/misc.js.map +1 -0
  38. package/dist/sql-queries/sql-queries.d.ts +65 -0
  39. package/dist/sql-queries/sql-queries.d.ts.map +1 -0
  40. package/dist/sql-queries/sql-queries.js +181 -0
  41. package/dist/sql-queries/sql-queries.js.map +1 -0
  42. package/dist/sql-queries/sql-query-builder.d.ts +47 -0
  43. package/dist/sql-queries/sql-query-builder.d.ts.map +1 -0
  44. package/dist/sql-queries/sql-query-builder.js +60 -0
  45. package/dist/sql-queries/sql-query-builder.js.map +1 -0
  46. package/dist/sql-queries/types.d.ts +50 -0
  47. package/dist/sql-queries/types.d.ts.map +1 -0
  48. package/dist/sql-queries/types.js +5 -0
  49. package/dist/sql-queries/types.js.map +1 -0
  50. package/dist/util.d.ts +21 -0
  51. package/dist/util.d.ts.map +1 -0
  52. package/dist/util.js +33 -0
  53. package/dist/util.js.map +1 -0
  54. package/package.json +37 -0
  55. package/src/database.ts +37 -0
  56. package/src/index.ts +3 -0
  57. package/src/schema/index.ts +100 -0
  58. package/src/schema/mutations.ts +128 -0
  59. package/src/schema/parse-utils.ts +42 -0
  60. package/src/schema/system-tables.ts +22 -0
  61. package/src/schema/table-def.ts +274 -0
  62. package/src/sql-queries/index.ts +3 -0
  63. package/src/sql-queries/misc.ts +2 -0
  64. package/src/sql-queries/sql-queries.ts +335 -0
  65. package/src/sql-queries/sql-query-builder.ts +135 -0
  66. package/src/sql-queries/types.ts +97 -0
  67. package/src/util.ts +46 -0
  68. package/tsconfig.json +10 -0
@@ -0,0 +1,100 @@
1
+ import { isReadonlyArray } from '@livestore/utils'
2
+ import type { ReadonlyArray } from '@livestore/utils/effect'
3
+ import type { SqliteDsl } from 'effect-db-schema'
4
+
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
@@ -0,0 +1,128 @@
1
+ import { cuid } from '@livestore/utils/cuid'
2
+ import { Schema } from '@livestore/utils/effect'
3
+
4
+ import type { BindValues } from '../sql-queries/sql-queries.js'
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
@@ -0,0 +1,42 @@
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 as __SqliteDsl } from 'effect-db-schema'
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
+ }
@@ -0,0 +1,22 @@
1
+ // import { Schema as __Schema } from '@livestore/utils/effect'
2
+ import { type SqliteAst as __SqliteAst, SqliteDsl } from 'effect-db-schema'
3
+
4
+ import type { FromTable } from './table-def.js'
5
+ import { table } from './table-def.js'
6
+
7
+ export const SCHEMA_META_TABLE = '__livestore_schema'
8
+
9
+ const schemaMetaTable = table(
10
+ SCHEMA_META_TABLE,
11
+ {
12
+ tableName: SqliteDsl.text({ primaryKey: true }),
13
+ schemaHash: SqliteDsl.integer({ nullable: false }),
14
+ /** ISO date format */
15
+ updatedAt: SqliteDsl.text({ nullable: false }),
16
+ },
17
+ { disableAutomaticIdColumn: true },
18
+ )
19
+
20
+ export type SchemaMetaRow = FromTable.RowDecoded<typeof schemaMetaTable>
21
+
22
+ export const systemTables = [schemaMetaTable]
@@ -0,0 +1,274 @@
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 { 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
+ export type StateType = 'singleton' | 'dynamic'
11
+
12
+ export type DefaultSqliteTableDef = SqliteDsl.TableDefinition<string, SqliteDsl.Columns>
13
+ export type DefaultSqliteTableDefConstrained = SqliteDsl.TableDefinition<string, SqliteDsl.ConstraintColumns>
14
+
15
+ // export type TableDefConstraint<
16
+ // TSqliteDef extends DefaultSqliteTableDef = DefaultSqliteTableDef,
17
+ // TIsSingleColumn extends boolean = boolean,
18
+ // TOptions extends TableOptions = TableOptions,
19
+ // > = TableDefBase<TSqliteDef, TIsSingleColumn, TOptions> & { schema: Schema.Schema<any> }
20
+
21
+ // /**
22
+ // * NOTE in the past we used to have a single `TableDef` but there are some TS issues when indroducing
23
+ // * `schema: SqliteDsl.StructSchemaForColumns<TSqliteDef>` so we split it into two types
24
+ // * and only use `TableDefConstraint` in some places
25
+ // */
26
+ // export type TableDefBase<
27
+ // TSqliteDef extends DefaultSqliteTableDef = DefaultSqliteTableDef,
28
+ // TIsSingleColumn extends boolean = boolean,
29
+ // TOptions extends TableOptions = TableOptions,
30
+ // > = {
31
+ // sqliteDef: TSqliteDef
32
+ // // schema: SqliteDsl.StructSchemaForColumns<TSqliteDef>
33
+ // // schema: any;
34
+ // isSingleColumn: TIsSingleColumn
35
+ // options: TOptions
36
+ // }
37
+
38
+ export type TableDef<
39
+ TSqliteDef extends DefaultSqliteTableDef = DefaultSqliteTableDefConstrained,
40
+ TIsSingleColumn extends boolean = boolean,
41
+ TOptions extends TableOptions = TableOptions,
42
+ // NOTE we're not using `SqliteDsl.StructSchemaForColumns<TSqliteDef['columns']>`
43
+ // as we don't want the alias type for users to show up
44
+ TSchema = Schema.Schema<
45
+ SqliteDsl.AnyIfConstained<
46
+ TSqliteDef['columns'],
47
+ { readonly [K in keyof TSqliteDef['columns']]: Schema.Schema.To<TSqliteDef['columns'][K]['schema']> }
48
+ >,
49
+ SqliteDsl.AnyIfConstained<
50
+ TSqliteDef['columns'],
51
+ { readonly [K in keyof TSqliteDef['columns']]: Schema.Schema.From<TSqliteDef['columns'][K]['schema']> }
52
+ >
53
+ >,
54
+ > = {
55
+ sqliteDef: TSqliteDef
56
+ isSingleColumn: TIsSingleColumn
57
+ options: TOptions
58
+ schema: TSchema
59
+ }
60
+
61
+ export type TableOptionsInput = Partial<TableOptions & { indexes: SqliteDsl.Index[] }>
62
+
63
+ export type TableOptions = {
64
+ /**
65
+ * Setting this to true will have the following consequences:
66
+ * - An `id` column will be added with `primaryKey: true` and `"singleton"` as default value and only allowed value
67
+ * - LiveStore will automatically create the singleton row when the table is created
68
+ * - LiveStore will fail if there is already a column defined with `primaryKey: true`
69
+ *
70
+ * @default false
71
+ */
72
+ isSingleton: boolean
73
+ // TODO
74
+ dynamicRegistration: boolean
75
+ disableAutomaticIdColumn: boolean
76
+ }
77
+
78
+ export const table = <
79
+ TName extends string,
80
+ TColumns extends SqliteDsl.Columns | SqliteDsl.ColumnDefinition<any, any>,
81
+ const TOptionsInput extends TableOptionsInput = TableOptionsInput,
82
+ >(
83
+ name: TName,
84
+ columnOrColumns: TColumns,
85
+ // type?: TStateType,
86
+ options?: TOptionsInput,
87
+ ): TableDef<
88
+ SqliteDsl.TableDefinition<
89
+ TName,
90
+ PrettifyFlat<
91
+ WithId<TColumns extends SqliteDsl.Columns ? TColumns : { value: TColumns }, WithDefaults<TOptionsInput>>
92
+ >
93
+ >,
94
+ TColumns extends SqliteDsl.ColumnDefinition<any, any> ? true : false,
95
+ WithDefaults<TOptionsInput>
96
+ > => {
97
+ const tablePath = name
98
+
99
+ const options_: TableOptions = {
100
+ isSingleton: options?.isSingleton ?? false,
101
+ dynamicRegistration: options?.dynamicRegistration ?? false,
102
+ disableAutomaticIdColumn: options?.disableAutomaticIdColumn ?? false,
103
+ }
104
+
105
+ const columns = (
106
+ SqliteDsl.isColumnDefinition(columnOrColumns) ? { value: columnOrColumns } : columnOrColumns
107
+ ) as SqliteDsl.Columns
108
+
109
+ if (options_.disableAutomaticIdColumn === true) {
110
+ if (columns.id === undefined && options_.isSingleton === true) {
111
+ shouldNeverHappen(
112
+ `Cannot create table ${name} with "isSingleton: true" because there is no column with name "id" and "disableAutomaticIdColumn: true" is set`,
113
+ )
114
+ }
115
+ } else if (columns.id === undefined && ReadonlyRecord.some(columns, (_) => _.primaryKey === true) === false) {
116
+ if (options_.isSingleton) {
117
+ columns.id = SqliteDsl.text({ schema: Schema.literal('singleton'), primaryKey: true, default: 'singleton' })
118
+ } else {
119
+ columns.id = SqliteDsl.text({ primaryKey: true })
120
+ }
121
+ }
122
+
123
+ const sqliteDef = SqliteDsl.table(tablePath, columns, options?.indexes ?? [])
124
+
125
+ if (options_.isSingleton) {
126
+ for (const column of sqliteDef.ast.columns) {
127
+ if (column.nullable === false && column.default._tag === 'None') {
128
+ shouldNeverHappen(
129
+ `When creating a singleton table, each column must be either nullable or have a default value. Column '${column.name}' is neither.`,
130
+ )
131
+ }
132
+ }
133
+ }
134
+
135
+ const isSingleColumn = SqliteDsl.isColumnDefinition(columnOrColumns) === true
136
+
137
+ const schema = SqliteDsl.structSchemaForTable(sqliteDef)
138
+ const tableDef = { sqliteDef, isSingleColumn, options: options_, schema } satisfies TableDef
139
+
140
+ // if (dynamicallyRegisteredTables.has(tablePath)) {
141
+ // if (SqliteAst.hash(dynamicallyRegisteredTables.get(tablePath)!.sqliteDef.ast) !== SqliteAst.hash(sqliteDef.ast)) {
142
+ // console.error('previous tableDef', dynamicallyRegisteredTables.get(tablePath), 'new tableDef', sqliteDef.ast)
143
+ // shouldNeverHappen(`Table with name "${name}" was already previously defined with a different definition`)
144
+ // }
145
+ // } else {
146
+ // dynamicallyRegisteredTables.set(tablePath, tableDef)
147
+ // }
148
+
149
+ return tableDef as any
150
+ }
151
+
152
+ export const tableIsSingleton = <TTableDef extends TableDef>(
153
+ tableDef: TTableDef,
154
+ ): tableDef is TTableDef & { options: { isSingleton: true } } => tableDef.options.isSingleton === true
155
+
156
+ export const getDefaultValuesEncoded = <TTableDef extends TableDef>(
157
+ tableDef: TTableDef,
158
+ fallbackValues?: Record<string, any>,
159
+ ) =>
160
+ pipe(
161
+ tableDef.sqliteDef.columns,
162
+ ReadonlyRecord.filter((col, key) => {
163
+ if (fallbackValues?.[key] !== undefined) return true
164
+ if (key === 'id') return false
165
+ return col!.default._tag === 'None' || SqliteDsl.isSqlDefaultValue(col!.default.value) === false
166
+ }),
167
+ ReadonlyRecord.map((column, columnName) =>
168
+ fallbackValues?.[columnName] === undefined
169
+ ? column!.default._tag === 'None'
170
+ ? column!.nullable === true
171
+ ? null
172
+ : shouldNeverHappen(`Column ${columnName} has no default value and is not nullable`)
173
+ : Schema.encodeSync(column!.schema)(column!.default.value)
174
+ : fallbackValues[columnName],
175
+ ),
176
+ )
177
+
178
+ export const getDefaultValuesDecoded = <TTableDef extends TableDef>(
179
+ tableDef: TTableDef,
180
+ fallbackValues?: Record<string, any>,
181
+ ) =>
182
+ pipe(
183
+ tableDef.sqliteDef.columns,
184
+ ReadonlyRecord.filter((col, key) => {
185
+ if (fallbackValues?.[key] !== undefined) return true
186
+ if (key === 'id') return false
187
+ return col!.default._tag === 'None' || SqliteDsl.isSqlDefaultValue(col!.default.value) === false
188
+ }),
189
+ ReadonlyRecord.map((column, columnName) =>
190
+ fallbackValues?.[columnName] === undefined
191
+ ? column!.default._tag === 'None'
192
+ ? column!.nullable === true
193
+ ? null
194
+ : shouldNeverHappen(`Column ${columnName} has no default value and is not nullable`)
195
+ : Schema.validateSync(column!.schema)(column!.default.value)
196
+ : fallbackValues[columnName],
197
+ ),
198
+ )
199
+
200
+ type WithId<TColumns extends SqliteDsl.Columns, TOptions extends TableOptions> = TColumns &
201
+ (TOptions['disableAutomaticIdColumn'] extends true
202
+ ? {}
203
+ : TOptions['isSingleton'] extends true
204
+ ? {
205
+ id: SqliteDsl.ColumnDefinition<'singleton', 'singleton'>
206
+ }
207
+ : {
208
+ id: SqliteDsl.ColumnDefinition<string, string>
209
+ })
210
+
211
+ type WithDefaults<TOptionsInput extends TableOptionsInput> = {
212
+ isSingleton: TOptionsInput['isSingleton'] extends true ? true : false
213
+ dynamicRegistration: TOptionsInput['dynamicRegistration'] extends true ? true : false
214
+ disableAutomaticIdColumn: TOptionsInput['disableAutomaticIdColumn'] extends true ? true : false
215
+ }
216
+
217
+ export namespace FromTable {
218
+ // TODO this sometimes doesn't preserve the order of columns
219
+ export type RowDecoded<TTableDef extends TableDef> = PrettifyFlat<
220
+ Nullable<Pick<RowDecodedAll<TTableDef>, NullableColumnNames<TTableDef>>> &
221
+ Omit<RowDecodedAll<TTableDef>, NullableColumnNames<TTableDef>>
222
+ >
223
+
224
+ export type NullableColumnNames<TTableDef extends TableDef> = FromColumns.NullableColumnNames<
225
+ TTableDef['sqliteDef']['columns']
226
+ >
227
+
228
+ export type Columns<TTableDef extends TableDef> = {
229
+ [K in keyof TTableDef['sqliteDef']['columns']]: TTableDef['sqliteDef']['columns'][K]['columnType']
230
+ }
231
+
232
+ export type RowEncodeNonNullable<TTableDef extends TableDef> = {
233
+ [K in keyof TTableDef['sqliteDef']['columns']]: Schema.Schema.From<TTableDef['sqliteDef']['columns'][K]['schema']>
234
+ }
235
+
236
+ export type RowEncoded<TTableDef extends TableDef> = PrettifyFlat<
237
+ Nullable<Pick<RowEncodeNonNullable<TTableDef>, NullableColumnNames<TTableDef>>> &
238
+ Omit<RowEncodeNonNullable<TTableDef>, NullableColumnNames<TTableDef>>
239
+ >
240
+
241
+ export type RowDecodedAll<TTableDef extends TableDef> = {
242
+ [K in keyof TTableDef['sqliteDef']['columns']]: Schema.Schema.To<TTableDef['sqliteDef']['columns'][K]['schema']>
243
+ }
244
+ }
245
+
246
+ export namespace FromColumns {
247
+ // TODO this sometimes doesn't preserve the order of columns
248
+ export type RowDecoded<TColumns extends SqliteDsl.Columns> = PrettifyFlat<
249
+ Nullable<Pick<RowDecodedAll<TColumns>, NullableColumnNames<TColumns>>> &
250
+ Omit<RowDecodedAll<TColumns>, NullableColumnNames<TColumns>>
251
+ >
252
+
253
+ export type RowDecodedAll<TColumns extends SqliteDsl.Columns> = {
254
+ [K in keyof TColumns]: Schema.Schema.To<TColumns[K]['schema']>
255
+ }
256
+
257
+ export type RowEncoded<TColumns extends SqliteDsl.Columns> = PrettifyFlat<
258
+ Nullable<Pick<RowEncodeNonNullable<TColumns>, NullableColumnNames<TColumns>>> &
259
+ Omit<RowEncodeNonNullable<TColumns>, NullableColumnNames<TColumns>>
260
+ >
261
+
262
+ export type RowEncodeNonNullable<TColumns extends SqliteDsl.Columns> = {
263
+ [K in keyof TColumns]: Schema.Schema.From<TColumns[K]['schema']>
264
+ }
265
+
266
+ export type NullableColumnNames<TColumns extends SqliteDsl.Columns> = keyof {
267
+ [K in keyof TColumns as TColumns[K]['default'] extends true ? K : never]: {}
268
+ }
269
+
270
+ export type RequiredInsertColumnNames<TColumns extends SqliteDsl.Columns> =
271
+ SqliteDsl.FromColumns.RequiredInsertColumnNames<TColumns>
272
+
273
+ export type InsertRowDecoded<TColumns extends SqliteDsl.Columns> = SqliteDsl.FromColumns.InsertRowDecoded<TColumns>
274
+ }
@@ -0,0 +1,3 @@
1
+ export * from './sql-queries.js'
2
+ export * from './sql-query-builder.js'
3
+ export * from './types.js'
@@ -0,0 +1,2 @@
1
+ export const objectEntries = <T extends Record<string, any>>(obj: T): [keyof T & string, T[keyof T]][] =>
2
+ Object.entries(obj) as [keyof T & string, T[keyof T]][]