@livestore/common 0.3.0-dev.28 → 0.3.0-dev.29

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 (277) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/__tests__/fixture.d.ts +83 -221
  3. package/dist/__tests__/fixture.d.ts.map +1 -1
  4. package/dist/__tests__/fixture.js +33 -11
  5. package/dist/__tests__/fixture.js.map +1 -1
  6. package/dist/adapter-types.d.ts +22 -15
  7. package/dist/adapter-types.d.ts.map +1 -1
  8. package/dist/adapter-types.js +15 -2
  9. package/dist/adapter-types.js.map +1 -1
  10. package/dist/bounded-collections.d.ts +1 -1
  11. package/dist/bounded-collections.d.ts.map +1 -1
  12. package/dist/debug-info.d.ts.map +1 -1
  13. package/dist/debug-info.js +1 -0
  14. package/dist/debug-info.js.map +1 -1
  15. package/dist/devtools/devtools-messages-client-session.d.ts +21 -21
  16. package/dist/devtools/devtools-messages-common.d.ts +6 -6
  17. package/dist/devtools/devtools-messages-leader.d.ts +45 -45
  18. package/dist/devtools/devtools-messages-leader.d.ts.map +1 -1
  19. package/dist/devtools/devtools-messages-leader.js +11 -11
  20. package/dist/devtools/devtools-messages-leader.js.map +1 -1
  21. package/dist/index.d.ts +2 -5
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +2 -5
  24. package/dist/index.js.map +1 -1
  25. package/dist/leader-thread/LeaderSyncProcessor.d.ts +10 -10
  26. package/dist/leader-thread/LeaderSyncProcessor.d.ts.map +1 -1
  27. package/dist/leader-thread/LeaderSyncProcessor.js +63 -65
  28. package/dist/leader-thread/LeaderSyncProcessor.js.map +1 -1
  29. package/dist/leader-thread/{apply-mutation.d.ts → apply-event.d.ts} +7 -7
  30. package/dist/leader-thread/apply-event.d.ts.map +1 -0
  31. package/dist/leader-thread/apply-event.js +103 -0
  32. package/dist/leader-thread/apply-event.js.map +1 -0
  33. package/dist/leader-thread/eventlog.d.ts +27 -0
  34. package/dist/leader-thread/eventlog.d.ts.map +1 -0
  35. package/dist/leader-thread/eventlog.js +123 -0
  36. package/dist/leader-thread/eventlog.js.map +1 -0
  37. package/dist/leader-thread/leader-worker-devtools.js +18 -18
  38. package/dist/leader-thread/leader-worker-devtools.js.map +1 -1
  39. package/dist/leader-thread/make-leader-thread-layer.d.ts +2 -2
  40. package/dist/leader-thread/make-leader-thread-layer.d.ts.map +1 -1
  41. package/dist/leader-thread/make-leader-thread-layer.js +16 -16
  42. package/dist/leader-thread/make-leader-thread-layer.js.map +1 -1
  43. package/dist/leader-thread/mod.d.ts +1 -1
  44. package/dist/leader-thread/mod.d.ts.map +1 -1
  45. package/dist/leader-thread/mod.js +1 -1
  46. package/dist/leader-thread/mod.js.map +1 -1
  47. package/dist/leader-thread/recreate-db.d.ts.map +1 -1
  48. package/dist/leader-thread/recreate-db.js +6 -8
  49. package/dist/leader-thread/recreate-db.js.map +1 -1
  50. package/dist/leader-thread/types.d.ts +11 -11
  51. package/dist/leader-thread/types.d.ts.map +1 -1
  52. package/dist/materializer-helper.d.ts +23 -0
  53. package/dist/materializer-helper.d.ts.map +1 -0
  54. package/dist/materializer-helper.js +70 -0
  55. package/dist/materializer-helper.js.map +1 -0
  56. package/dist/query-builder/api.d.ts +58 -53
  57. package/dist/query-builder/api.d.ts.map +1 -1
  58. package/dist/query-builder/api.js +3 -5
  59. package/dist/query-builder/api.js.map +1 -1
  60. package/dist/query-builder/astToSql.d.ts.map +1 -1
  61. package/dist/query-builder/astToSql.js +59 -37
  62. package/dist/query-builder/astToSql.js.map +1 -1
  63. package/dist/query-builder/impl.d.ts +2 -3
  64. package/dist/query-builder/impl.d.ts.map +1 -1
  65. package/dist/query-builder/impl.js +48 -46
  66. package/dist/query-builder/impl.js.map +1 -1
  67. package/dist/query-builder/impl.test.d.ts +86 -1
  68. package/dist/query-builder/impl.test.d.ts.map +1 -1
  69. package/dist/query-builder/impl.test.js +244 -36
  70. package/dist/query-builder/impl.test.js.map +1 -1
  71. package/dist/rehydrate-from-eventlog.d.ts +14 -0
  72. package/dist/rehydrate-from-eventlog.d.ts.map +1 -0
  73. package/dist/{rehydrate-from-mutationlog.js → rehydrate-from-eventlog.js} +25 -26
  74. package/dist/rehydrate-from-eventlog.js.map +1 -0
  75. package/dist/schema/EventDef.d.ts +136 -0
  76. package/dist/schema/EventDef.d.ts.map +1 -0
  77. package/dist/schema/EventDef.js +58 -0
  78. package/dist/schema/EventDef.js.map +1 -0
  79. package/dist/schema/EventId.d.ts +2 -2
  80. package/dist/schema/EventId.d.ts.map +1 -1
  81. package/dist/schema/EventId.js +3 -2
  82. package/dist/schema/EventId.js.map +1 -1
  83. package/dist/schema/{MutationEvent.d.ts → LiveStoreEvent.d.ts} +56 -56
  84. package/dist/schema/LiveStoreEvent.d.ts.map +1 -0
  85. package/dist/schema/{MutationEvent.js → LiveStoreEvent.js} +24 -24
  86. package/dist/schema/LiveStoreEvent.js.map +1 -0
  87. package/dist/schema/client-document-def.d.ts +223 -0
  88. package/dist/schema/client-document-def.d.ts.map +1 -0
  89. package/dist/schema/client-document-def.js +170 -0
  90. package/dist/schema/client-document-def.js.map +1 -0
  91. package/dist/schema/client-document-def.test.d.ts +2 -0
  92. package/dist/schema/client-document-def.test.d.ts.map +1 -0
  93. package/dist/schema/client-document-def.test.js +201 -0
  94. package/dist/schema/client-document-def.test.js.map +1 -0
  95. package/dist/schema/db-schema/dsl/mod.d.ts.map +1 -1
  96. package/dist/schema/events.d.ts +2 -0
  97. package/dist/schema/events.d.ts.map +1 -0
  98. package/dist/schema/events.js +2 -0
  99. package/dist/schema/events.js.map +1 -0
  100. package/dist/schema/mod.d.ts +4 -3
  101. package/dist/schema/mod.d.ts.map +1 -1
  102. package/dist/schema/mod.js +4 -3
  103. package/dist/schema/mod.js.map +1 -1
  104. package/dist/schema/schema.d.ts +27 -23
  105. package/dist/schema/schema.d.ts.map +1 -1
  106. package/dist/schema/schema.js +45 -43
  107. package/dist/schema/schema.js.map +1 -1
  108. package/dist/schema/sqlite-state.d.ts +12 -0
  109. package/dist/schema/sqlite-state.d.ts.map +1 -0
  110. package/dist/schema/sqlite-state.js +36 -0
  111. package/dist/schema/sqlite-state.js.map +1 -0
  112. package/dist/schema/system-tables.d.ts +67 -98
  113. package/dist/schema/system-tables.d.ts.map +1 -1
  114. package/dist/schema/system-tables.js +62 -48
  115. package/dist/schema/system-tables.js.map +1 -1
  116. package/dist/schema/table-def.d.ts +26 -96
  117. package/dist/schema/table-def.d.ts.map +1 -1
  118. package/dist/schema/table-def.js +16 -64
  119. package/dist/schema/table-def.js.map +1 -1
  120. package/dist/schema/view.d.ts +3 -0
  121. package/dist/schema/view.d.ts.map +1 -0
  122. package/dist/schema/view.js +3 -0
  123. package/dist/schema/view.js.map +1 -0
  124. package/dist/schema-management/common.d.ts +4 -4
  125. package/dist/schema-management/common.d.ts.map +1 -1
  126. package/dist/schema-management/migrations.d.ts.map +1 -1
  127. package/dist/schema-management/migrations.js +6 -6
  128. package/dist/schema-management/migrations.js.map +1 -1
  129. package/dist/schema-management/validate-mutation-defs.d.ts +3 -3
  130. package/dist/schema-management/validate-mutation-defs.d.ts.map +1 -1
  131. package/dist/schema-management/validate-mutation-defs.js +17 -17
  132. package/dist/schema-management/validate-mutation-defs.js.map +1 -1
  133. package/dist/sync/ClientSessionSyncProcessor.d.ts +7 -7
  134. package/dist/sync/ClientSessionSyncProcessor.d.ts.map +1 -1
  135. package/dist/sync/ClientSessionSyncProcessor.js +31 -30
  136. package/dist/sync/ClientSessionSyncProcessor.js.map +1 -1
  137. package/dist/sync/next/facts.d.ts +19 -19
  138. package/dist/sync/next/facts.d.ts.map +1 -1
  139. package/dist/sync/next/facts.js +2 -2
  140. package/dist/sync/next/facts.js.map +1 -1
  141. package/dist/sync/next/history-dag-common.d.ts +3 -3
  142. package/dist/sync/next/history-dag-common.d.ts.map +1 -1
  143. package/dist/sync/next/history-dag-common.js +1 -1
  144. package/dist/sync/next/history-dag-common.js.map +1 -1
  145. package/dist/sync/next/history-dag.js +1 -1
  146. package/dist/sync/next/history-dag.js.map +1 -1
  147. package/dist/sync/next/rebase-events.d.ts +7 -7
  148. package/dist/sync/next/rebase-events.d.ts.map +1 -1
  149. package/dist/sync/next/rebase-events.js +5 -5
  150. package/dist/sync/next/rebase-events.js.map +1 -1
  151. package/dist/sync/next/test/compact-events.calculator.test.js +38 -33
  152. package/dist/sync/next/test/compact-events.calculator.test.js.map +1 -1
  153. package/dist/sync/next/test/compact-events.test.js +71 -71
  154. package/dist/sync/next/test/compact-events.test.js.map +1 -1
  155. package/dist/sync/next/test/{mutation-fixtures.d.ts → event-fixtures.d.ts} +29 -29
  156. package/dist/sync/next/test/event-fixtures.d.ts.map +1 -0
  157. package/dist/sync/next/test/{mutation-fixtures.js → event-fixtures.js} +60 -25
  158. package/dist/sync/next/test/event-fixtures.js.map +1 -0
  159. package/dist/sync/next/test/mod.d.ts +1 -1
  160. package/dist/sync/next/test/mod.d.ts.map +1 -1
  161. package/dist/sync/next/test/mod.js +1 -1
  162. package/dist/sync/next/test/mod.js.map +1 -1
  163. package/dist/sync/sync.d.ts +3 -3
  164. package/dist/sync/sync.d.ts.map +1 -1
  165. package/dist/sync/syncstate.d.ts +32 -32
  166. package/dist/sync/syncstate.d.ts.map +1 -1
  167. package/dist/sync/syncstate.js +10 -10
  168. package/dist/sync/syncstate.js.map +1 -1
  169. package/dist/sync/syncstate.test.js +5 -5
  170. package/dist/sync/syncstate.test.js.map +1 -1
  171. package/dist/sync/validate-push-payload.d.ts +2 -2
  172. package/dist/sync/validate-push-payload.d.ts.map +1 -1
  173. package/dist/sync/validate-push-payload.js.map +1 -1
  174. package/dist/version.d.ts +1 -1
  175. package/dist/version.js +1 -1
  176. package/package.json +3 -3
  177. package/src/__tests__/fixture.ts +36 -15
  178. package/src/adapter-types.ts +23 -16
  179. package/src/debug-info.ts +1 -0
  180. package/src/devtools/devtools-messages-leader.ts +13 -13
  181. package/src/index.ts +2 -5
  182. package/src/leader-thread/LeaderSyncProcessor.ts +81 -91
  183. package/src/leader-thread/{apply-mutation.ts → apply-event.ts} +50 -74
  184. package/src/leader-thread/eventlog.ts +199 -0
  185. package/src/leader-thread/leader-worker-devtools.ts +18 -18
  186. package/src/leader-thread/make-leader-thread-layer.ts +18 -18
  187. package/src/leader-thread/mod.ts +1 -1
  188. package/src/leader-thread/recreate-db.ts +6 -9
  189. package/src/leader-thread/types.ts +12 -12
  190. package/src/materializer-helper.ts +110 -0
  191. package/src/query-builder/api.ts +79 -105
  192. package/src/query-builder/astToSql.ts +68 -39
  193. package/src/query-builder/impl.test.ts +264 -42
  194. package/src/query-builder/impl.ts +72 -56
  195. package/src/{rehydrate-from-mutationlog.ts → rehydrate-from-eventlog.ts} +33 -40
  196. package/src/schema/EventDef.ts +216 -0
  197. package/src/schema/EventId.ts +5 -3
  198. package/src/schema/{MutationEvent.ts → LiveStoreEvent.ts} +67 -68
  199. package/src/schema/client-document-def.test.ts +239 -0
  200. package/src/schema/client-document-def.ts +444 -0
  201. package/src/schema/db-schema/dsl/mod.ts +0 -1
  202. package/src/schema/events.ts +1 -0
  203. package/src/schema/mod.ts +4 -3
  204. package/src/schema/schema.ts +79 -69
  205. package/src/schema/sqlite-state.ts +62 -0
  206. package/src/schema/system-tables.ts +42 -53
  207. package/src/schema/table-def.ts +53 -209
  208. package/src/schema/view.ts +2 -0
  209. package/src/schema-management/common.ts +4 -4
  210. package/src/schema-management/migrations.ts +8 -9
  211. package/src/schema-management/validate-mutation-defs.ts +22 -24
  212. package/src/sync/ClientSessionSyncProcessor.ts +37 -36
  213. package/src/sync/next/facts.ts +31 -32
  214. package/src/sync/next/history-dag-common.ts +4 -4
  215. package/src/sync/next/history-dag.ts +1 -1
  216. package/src/sync/next/rebase-events.ts +13 -13
  217. package/src/sync/next/test/compact-events.calculator.test.ts +45 -45
  218. package/src/sync/next/test/compact-events.test.ts +73 -73
  219. package/src/sync/next/test/event-fixtures.ts +219 -0
  220. package/src/sync/next/test/mod.ts +1 -1
  221. package/src/sync/sync.ts +3 -3
  222. package/src/sync/syncstate.test.ts +8 -8
  223. package/src/sync/syncstate.ts +19 -19
  224. package/src/sync/validate-push-payload.ts +2 -2
  225. package/src/version.ts +1 -1
  226. package/tmp/pack.tgz +0 -0
  227. package/tsconfig.json +1 -0
  228. package/dist/derived-mutations.d.ts +0 -109
  229. package/dist/derived-mutations.d.ts.map +0 -1
  230. package/dist/derived-mutations.js +0 -54
  231. package/dist/derived-mutations.js.map +0 -1
  232. package/dist/derived-mutations.test.d.ts +0 -2
  233. package/dist/derived-mutations.test.d.ts.map +0 -1
  234. package/dist/derived-mutations.test.js +0 -93
  235. package/dist/derived-mutations.test.js.map +0 -1
  236. package/dist/init-singleton-tables.d.ts +0 -4
  237. package/dist/init-singleton-tables.d.ts.map +0 -1
  238. package/dist/init-singleton-tables.js +0 -16
  239. package/dist/init-singleton-tables.js.map +0 -1
  240. package/dist/leader-thread/apply-mutation.d.ts.map +0 -1
  241. package/dist/leader-thread/apply-mutation.js +0 -122
  242. package/dist/leader-thread/apply-mutation.js.map +0 -1
  243. package/dist/leader-thread/mutationlog.d.ts +0 -27
  244. package/dist/leader-thread/mutationlog.d.ts.map +0 -1
  245. package/dist/leader-thread/mutationlog.js +0 -124
  246. package/dist/leader-thread/mutationlog.js.map +0 -1
  247. package/dist/leader-thread/pull-queue-set.d.ts +0 -7
  248. package/dist/leader-thread/pull-queue-set.d.ts.map +0 -1
  249. package/dist/leader-thread/pull-queue-set.js +0 -38
  250. package/dist/leader-thread/pull-queue-set.js.map +0 -1
  251. package/dist/mutation.d.ts +0 -20
  252. package/dist/mutation.d.ts.map +0 -1
  253. package/dist/mutation.js +0 -68
  254. package/dist/mutation.js.map +0 -1
  255. package/dist/query-info.d.ts +0 -41
  256. package/dist/query-info.d.ts.map +0 -1
  257. package/dist/query-info.js +0 -7
  258. package/dist/query-info.js.map +0 -1
  259. package/dist/rehydrate-from-mutationlog.d.ts +0 -15
  260. package/dist/rehydrate-from-mutationlog.d.ts.map +0 -1
  261. package/dist/rehydrate-from-mutationlog.js.map +0 -1
  262. package/dist/schema/MutationEvent.d.ts.map +0 -1
  263. package/dist/schema/MutationEvent.js.map +0 -1
  264. package/dist/schema/mutations.d.ts +0 -115
  265. package/dist/schema/mutations.d.ts.map +0 -1
  266. package/dist/schema/mutations.js +0 -42
  267. package/dist/schema/mutations.js.map +0 -1
  268. package/dist/sync/next/test/mutation-fixtures.d.ts.map +0 -1
  269. package/dist/sync/next/test/mutation-fixtures.js.map +0 -1
  270. package/src/derived-mutations.test.ts +0 -101
  271. package/src/derived-mutations.ts +0 -170
  272. package/src/init-singleton-tables.ts +0 -24
  273. package/src/leader-thread/mutationlog.ts +0 -202
  274. package/src/mutation.ts +0 -108
  275. package/src/query-info.ts +0 -83
  276. package/src/schema/mutations.ts +0 -193
  277. package/src/sync/next/test/mutation-fixtures.ts +0 -228
@@ -1,10 +1,10 @@
1
- import type { GetValForKey } from '@livestore/utils'
1
+ import type { GetValForKey, SingleOrReadonlyArray } from '@livestore/utils'
2
2
  import { type Option, Predicate, type Schema } from '@livestore/utils/effect'
3
3
 
4
4
  import type { SessionIdSymbol } from '../adapter-types.js'
5
- import type { QueryInfo } from '../query-info.js'
5
+ import type { ClientDocumentTableDef } from '../schema/client-document-def.js'
6
6
  import type { SqliteDsl } from '../schema/db-schema/mod.js'
7
- import type { DbSchema } from '../schema/mod.js'
7
+ import type { State } from '../schema/mod.js'
8
8
  import type { SqlValue } from '../util.js'
9
9
 
10
10
  export type QueryBuilderAst =
@@ -26,28 +26,28 @@ export namespace QueryBuilderAst {
26
26
  readonly orderBy: ReadonlyArray<OrderBy>
27
27
  readonly offset: Option.Option<number>
28
28
  readonly limit: Option.Option<number>
29
- readonly tableDef: DbSchema.TableDefBase
29
+ readonly tableDef: State.SQLite.TableDefBase
30
30
  readonly where: ReadonlyArray<QueryBuilderAst.Where>
31
31
  readonly resultSchemaSingle: Schema.Schema<any>
32
32
  }
33
33
 
34
34
  export interface CountQuery {
35
35
  readonly _tag: 'CountQuery'
36
- readonly tableDef: DbSchema.TableDefBase
36
+ readonly tableDef: State.SQLite.TableDefBase
37
37
  readonly where: ReadonlyArray<QueryBuilderAst.Where>
38
38
  readonly resultSchema: Schema.Schema<number, ReadonlyArray<{ count: number }>>
39
39
  }
40
40
 
41
41
  export interface RowQuery {
42
42
  readonly _tag: 'RowQuery'
43
- readonly tableDef: DbSchema.TableDefBase
44
- readonly id: string | SessionIdSymbol | number
45
- readonly insertValues: Record<string, unknown>
43
+ readonly tableDef: State.SQLite.ClientDocumentTableDef.Any
44
+ readonly id: string | SessionIdSymbol
45
+ readonly explicitDefaultValues: Record<string, unknown>
46
46
  }
47
47
 
48
48
  export interface InsertQuery {
49
49
  readonly _tag: 'InsertQuery'
50
- readonly tableDef: DbSchema.TableDefBase
50
+ readonly tableDef: State.SQLite.TableDefBase
51
51
  readonly values: Record<string, unknown>
52
52
  readonly onConflict: OnConflict | undefined
53
53
  readonly returning: string[] | undefined
@@ -56,7 +56,7 @@ export namespace QueryBuilderAst {
56
56
 
57
57
  export interface OnConflict {
58
58
  /** Conflicting column name */
59
- readonly target: string
59
+ readonly targets: string[]
60
60
  readonly action:
61
61
  | { readonly _tag: 'ignore' }
62
62
  | { readonly _tag: 'replace' }
@@ -68,7 +68,7 @@ export namespace QueryBuilderAst {
68
68
 
69
69
  export interface UpdateQuery {
70
70
  readonly _tag: 'UpdateQuery'
71
- readonly tableDef: DbSchema.TableDefBase
71
+ readonly tableDef: State.SQLite.TableDefBase
72
72
  readonly values: Record<string, unknown>
73
73
  readonly where: ReadonlyArray<QueryBuilderAst.Where>
74
74
  readonly returning: string[] | undefined
@@ -77,7 +77,7 @@ export namespace QueryBuilderAst {
77
77
 
78
78
  export interface DeleteQuery {
79
79
  readonly _tag: 'DeleteQuery'
80
- readonly tableDef: DbSchema.TableDefBase
80
+ readonly tableDef: State.SQLite.TableDefBase
81
81
  readonly where: ReadonlyArray<QueryBuilderAst.Where>
82
82
  readonly returning: string[] | undefined
83
83
  readonly resultSchema: Schema.Schema<any>
@@ -99,27 +99,31 @@ export namespace QueryBuilderAst {
99
99
 
100
100
  export const QueryBuilderAstSymbol = Symbol.for('QueryBuilderAst')
101
101
  export type QueryBuilderAstSymbol = typeof QueryBuilderAstSymbol
102
- export const TypeId = Symbol.for('QueryBuilder')
103
- export type TypeId = typeof TypeId
102
+
103
+ export const QueryBuilderResultSymbol = Symbol.for('QueryBuilderResult')
104
+ export type QueryBuilderResultSymbol = typeof QueryBuilderResultSymbol
105
+
106
+ export const QueryBuilderTypeId = Symbol.for('QueryBuilder')
107
+ export type QueryBuilderTypeId = typeof QueryBuilderTypeId
104
108
 
105
109
  export const isQueryBuilder = (value: unknown): value is QueryBuilder<any, any, any> =>
106
- Predicate.hasProperty(value, TypeId)
110
+ Predicate.hasProperty(value, QueryBuilderTypeId)
107
111
 
108
112
  export type QueryBuilder<
109
113
  TResult,
110
- TTableDef extends DbSchema.TableDefBase,
114
+ TTableDef extends State.SQLite.TableDefBase,
111
115
  /** Used to gradually remove features from the API based on the query context */
112
116
  TWithout extends QueryBuilder.ApiFeature = never,
113
- TQueryInfo extends QueryInfo = QueryInfo.None,
114
117
  > = {
115
- readonly [TypeId]: TypeId
118
+ readonly [QueryBuilderTypeId]: QueryBuilderTypeId
116
119
  readonly [QueryBuilderAstSymbol]: QueryBuilderAst
120
+ readonly ['ResultType']: TResult
117
121
  readonly asSql: () => { query: string; bindValues: SqlValue[] }
118
122
  readonly toString: () => string
119
- } & Omit<QueryBuilder.ApiFull<TResult, TTableDef, TWithout, TQueryInfo>, TWithout>
123
+ } & Omit<QueryBuilder.ApiFull<TResult, TTableDef, TWithout>, TWithout>
120
124
 
121
125
  export namespace QueryBuilder {
122
- export type Any = QueryBuilder<any, any, any, any>
126
+ export type Any = QueryBuilder<any, any, any>
123
127
  export type WhereOps = WhereOps.Equality | WhereOps.Order | WhereOps.Like | WhereOps.In
124
128
 
125
129
  export namespace WhereOps {
@@ -147,7 +151,7 @@ export namespace QueryBuilder {
147
151
  | 'returning'
148
152
  | 'onConflict'
149
153
 
150
- export type WhereParams<TTableDef extends DbSchema.TableDefBase> = Partial<{
154
+ export type WhereParams<TTableDef extends State.SQLite.TableDefBase> = Partial<{
151
155
  [K in keyof TTableDef['sqliteDef']['columns']]:
152
156
  | TTableDef['sqliteDef']['columns'][K]['schema']['Type']
153
157
  | { op: QueryBuilder.WhereOps.SingleValue; value: TTableDef['sqliteDef']['columns'][K]['schema']['Type'] }
@@ -158,40 +162,31 @@ export namespace QueryBuilder {
158
162
  | undefined
159
163
  }>
160
164
 
161
- export type OrderByParams<TTableDef extends DbSchema.TableDefBase> = ReadonlyArray<{
165
+ export type OrderByParams<TTableDef extends State.SQLite.TableDefBase> = ReadonlyArray<{
162
166
  col: keyof TTableDef['sqliteDef']['columns'] & string
163
167
  direction: 'asc' | 'desc'
164
168
  }>
165
169
 
166
- export type ApiFull<
167
- TResult,
168
- TTableDef extends DbSchema.TableDefBase,
169
- TWithout extends ApiFeature,
170
- TQueryInfo extends QueryInfo,
171
- > = {
170
+ export type ApiFull<TResult, TTableDef extends State.SQLite.TableDefBase, TWithout extends ApiFeature> = {
172
171
  /**
173
172
  * `SELECT *` is the default
174
173
  *
175
174
  * Example:
176
175
  * ```ts
177
176
  * db.todos.select('id', 'text', 'completed')
178
- * db.todos.select('id', { pluck: true })
177
+ * db.todos.select('id')
179
178
  * ```
180
179
  */
181
180
  readonly select: {
182
- <TColumn extends keyof TTableDef['sqliteDef']['columns'] & string, TPluck extends boolean = false>(
183
- column: TColumn,
184
- options?: { pluck: TPluck },
181
+ /** Selects and plucks a single column */
182
+ <TColumn extends keyof TTableDef['sqliteDef']['columns'] & string>(
183
+ pluckColumn: TColumn,
185
184
  ): QueryBuilder<
186
- TPluck extends true
187
- ? ReadonlyArray<TTableDef['sqliteDef']['columns'][TColumn]['schema']['Type']>
188
- : ReadonlyArray<{
189
- readonly [K in TColumn]: TTableDef['sqliteDef']['columns'][K]['schema']['Type']
190
- }>,
185
+ ReadonlyArray<TTableDef['sqliteDef']['columns'][TColumn]['schema']['Type']>,
191
186
  TTableDef,
192
- TWithout | 'row' | 'select' | 'returning' | 'onConflict',
193
- TQueryInfo
187
+ TWithout | 'row' | 'select' | 'returning' | 'onConflict'
194
188
  >
189
+ /** Select multiple columns */
195
190
  <TColumns extends keyof TTableDef['sqliteDef']['columns'] & string>(
196
191
  ...columns: TColumns[]
197
192
  // TODO also support arbitrary SQL selects
@@ -201,8 +196,7 @@ export namespace QueryBuilder {
201
196
  readonly [K in TColumns]: TTableDef['sqliteDef']['columns'][K]['schema']['Type']
202
197
  }>,
203
198
  TTableDef,
204
- TWithout | 'row' | 'select' | 'count' | 'returning' | 'onConflict',
205
- TQueryInfo
199
+ TWithout | 'row' | 'select' | 'count' | 'returning' | 'onConflict'
206
200
  >
207
201
  }
208
202
 
@@ -222,18 +216,16 @@ export namespace QueryBuilder {
222
216
  * TODO: Also support `OR`
223
217
  */
224
218
  readonly where: {
225
- <TParams extends QueryBuilder.WhereParams<TTableDef>>(
226
- params: TParams,
227
- ): QueryBuilder<TResult, TTableDef, TWithout | 'row' | 'select', TQueryInfo>
219
+ (params: QueryBuilder.WhereParams<TTableDef>): QueryBuilder<TResult, TTableDef, TWithout | 'row' | 'select'>
228
220
  <TColName extends keyof TTableDef['sqliteDef']['columns']>(
229
221
  col: TColName,
230
222
  value: TTableDef['sqliteDef']['columns'][TColName]['schema']['Type'],
231
- ): QueryBuilder<TResult, TTableDef, TWithout | 'row' | 'select', TQueryInfo>
223
+ ): QueryBuilder<TResult, TTableDef, TWithout | 'row' | 'select'>
232
224
  <TColName extends keyof TTableDef['sqliteDef']['columns']>(
233
225
  col: TColName,
234
226
  op: QueryBuilder.WhereOps,
235
227
  value: TTableDef['sqliteDef']['columns'][TColName]['schema']['Type'],
236
- ): QueryBuilder<TResult, TTableDef, TWithout | 'row' | 'select', TQueryInfo>
228
+ ): QueryBuilder<TResult, TTableDef, TWithout | 'row' | 'select'>
237
229
  }
238
230
 
239
231
  /**
@@ -246,8 +238,7 @@ export namespace QueryBuilder {
246
238
  readonly count: () => QueryBuilder<
247
239
  number,
248
240
  TTableDef,
249
- TWithout | 'row' | 'count' | 'select' | 'orderBy' | 'first' | 'offset' | 'limit' | 'returning' | 'onConflict',
250
- TQueryInfo
241
+ TWithout | 'row' | 'count' | 'select' | 'orderBy' | 'first' | 'offset' | 'limit' | 'returning' | 'onConflict'
251
242
  >
252
243
 
253
244
  /**
@@ -260,10 +251,10 @@ export namespace QueryBuilder {
260
251
  <TColName extends keyof TTableDef['sqliteDef']['columns'] & string>(
261
252
  col: TColName,
262
253
  direction: 'asc' | 'desc',
263
- ): QueryBuilder<TResult, TTableDef, TWithout | 'returning' | 'onConflict', TQueryInfo>
254
+ ): QueryBuilder<TResult, TTableDef, TWithout | 'returning' | 'onConflict'>
264
255
  <TParams extends QueryBuilder.OrderByParams<TTableDef>>(
265
256
  params: TParams,
266
- ): QueryBuilder<TResult, TTableDef, TWithout | 'returning' | 'onConflict', TQueryInfo>
257
+ ): QueryBuilder<TResult, TTableDef, TWithout | 'returning' | 'onConflict'>
267
258
  }
268
259
 
269
260
  /**
@@ -274,12 +265,7 @@ export namespace QueryBuilder {
274
265
  */
275
266
  readonly offset: (
276
267
  offset: number,
277
- ) => QueryBuilder<
278
- TResult,
279
- TTableDef,
280
- TWithout | 'row' | 'offset' | 'orderBy' | 'returning' | 'onConflict',
281
- TQueryInfo
282
- >
268
+ ) => QueryBuilder<TResult, TTableDef, TWithout | 'row' | 'offset' | 'orderBy' | 'returning' | 'onConflict'>
283
269
 
284
270
  /**
285
271
  * Example:
@@ -292,42 +278,26 @@ export namespace QueryBuilder {
292
278
  ) => QueryBuilder<
293
279
  TResult,
294
280
  TTableDef,
295
- TWithout | 'row' | 'limit' | 'offset' | 'first' | 'orderBy' | 'returning' | 'onConflict',
296
- TQueryInfo
281
+ TWithout | 'row' | 'limit' | 'offset' | 'first' | 'orderBy' | 'returning' | 'onConflict'
297
282
  >
298
283
 
299
284
  /**
300
285
  * Example:
301
286
  * ```ts
302
287
  * db.todos.first()
288
+ * db.todos.where('id', '123').first()
303
289
  * ```
290
+ *
291
+ * Query will fail if no rows are returned and no fallback is provided.
304
292
  */
305
- readonly first: <TFallback extends GetSingle<TResult> = never>(options?: {
306
- fallback?: () => TFallback
293
+ readonly first: <TFallback = never>(options?: {
294
+ fallback?: () => TFallback | GetSingle<TResult>
307
295
  }) => QueryBuilder<
308
296
  TFallback | GetSingle<TResult>,
309
297
  TTableDef,
310
- TWithout | 'row' | 'first' | 'orderBy' | 'select' | 'limit' | 'offset' | 'where' | 'returning' | 'onConflict',
311
- TQueryInfo
298
+ TWithout | 'row' | 'first' | 'orderBy' | 'select' | 'limit' | 'offset' | 'where' | 'returning' | 'onConflict'
312
299
  >
313
300
 
314
- /**
315
- * Gets a single row from the table and will create it if it doesn't exist yet.
316
- */
317
- // TODO maybe call `getsert`?
318
- readonly row: TTableDef['options']['isSingleton'] extends true
319
- ? () => QueryBuilder<RowQuery.Result<TTableDef>, TTableDef, QueryBuilder.ApiFeature, QueryInfo.Row>
320
- : TTableDef['options']['deriveMutations']['enabled'] extends false
321
- ? (_: 'Error: Need to enable deriveMutations to use row()') => any
322
- : TTableDef['options']['requiredInsertColumnNames'] extends never
323
- ? (
324
- id: string | SessionIdSymbol | number,
325
- ) => QueryBuilder<RowQuery.Result<TTableDef>, TTableDef, QueryBuilder.ApiFeature, QueryInfo.Row>
326
- : <TOptions extends RowQuery.RequiredColumnsOptions<TTableDef>>(
327
- id: string | SessionIdSymbol | number,
328
- opts: TOptions,
329
- ) => QueryBuilder<RowQuery.Result<TTableDef>, TTableDef, QueryBuilder.ApiFeature, QueryInfo.Row>
330
-
331
301
  /**
332
302
  * Insert a new row into the table
333
303
  *
@@ -341,8 +311,7 @@ export namespace QueryBuilder {
341
311
  ) => QueryBuilder<
342
312
  TResult,
343
313
  TTableDef,
344
- TWithout | 'row' | 'select' | 'count' | 'orderBy' | 'first' | 'offset' | 'limit' | 'where',
345
- QueryInfo.Write
314
+ TWithout | 'row' | 'select' | 'count' | 'orderBy' | 'first' | 'offset' | 'limit' | 'where'
346
315
  >
347
316
 
348
317
  /**
@@ -364,24 +333,22 @@ export namespace QueryBuilder {
364
333
  * NOTE This API doesn't yet support composite primary keys.
365
334
  */
366
335
  readonly onConflict: {
367
- (
368
- target: string,
336
+ <TTarget extends SingleOrReadonlyArray<keyof TTableDef['sqliteDef']['columns']>>(
337
+ target: TTarget,
369
338
  action: 'ignore' | 'replace',
370
339
  ): QueryBuilder<
371
340
  TResult,
372
341
  TTableDef,
373
- TWithout | 'row' | 'select' | 'count' | 'orderBy' | 'first' | 'offset' | 'limit' | 'where',
374
- TQueryInfo
342
+ TWithout | 'row' | 'select' | 'count' | 'orderBy' | 'first' | 'offset' | 'limit' | 'where'
375
343
  >
376
- <TTarget extends keyof TTableDef['sqliteDef']['columns'] & string>(
344
+ <TTarget extends SingleOrReadonlyArray<keyof TTableDef['sqliteDef']['columns']>>(
377
345
  target: TTarget,
378
346
  action: 'update',
379
- updateValues: Partial<TTableDef['schema']['Type']>,
347
+ updateValues: Partial<TTableDef['rowSchema']['Type']>,
380
348
  ): QueryBuilder<
381
349
  TResult,
382
350
  TTableDef,
383
- TWithout | 'row' | 'select' | 'count' | 'orderBy' | 'first' | 'offset' | 'limit' | 'where',
384
- TQueryInfo
351
+ TWithout | 'row' | 'select' | 'count' | 'orderBy' | 'first' | 'offset' | 'limit' | 'where'
385
352
  >
386
353
  }
387
354
 
@@ -411,12 +378,11 @@ export namespace QueryBuilder {
411
378
  * ```
412
379
  */
413
380
  readonly update: (
414
- values: Partial<TTableDef['schema']['Type']>,
381
+ values: Partial<TTableDef['rowSchema']['Type']>,
415
382
  ) => QueryBuilder<
416
383
  TResult,
417
384
  TTableDef,
418
- TWithout | 'row' | 'select' | 'count' | 'orderBy' | 'first' | 'offset' | 'limit' | 'onConflict',
419
- QueryInfo.Write
385
+ TWithout | 'row' | 'select' | 'count' | 'orderBy' | 'first' | 'offset' | 'limit' | 'onConflict'
420
386
  >
421
387
 
422
388
  /**
@@ -432,35 +398,43 @@ export namespace QueryBuilder {
432
398
  readonly delete: () => QueryBuilder<
433
399
  TResult,
434
400
  TTableDef,
435
- TWithout | 'row' | 'select' | 'count' | 'orderBy' | 'first' | 'offset' | 'limit' | 'onConflict',
436
- QueryInfo.Write
401
+ TWithout | 'row' | 'select' | 'count' | 'orderBy' | 'first' | 'offset' | 'limit' | 'onConflict'
437
402
  >
438
403
  }
439
404
  }
440
405
 
441
406
  export namespace RowQuery {
442
- export type RequiredColumnsOptions<TTableDef extends DbSchema.TableDefBase> = {
407
+ export type GetOrCreateOptions<TTableDef extends ClientDocumentTableDef.TraitAny> = {
408
+ default: Partial<TTableDef['Value']>
409
+ }
410
+
411
+ // TODO get rid of this
412
+ export type RequiredColumnsOptions<TTableDef extends State.SQLite.TableDefBase> = {
443
413
  /**
444
414
  * Values to be inserted into the row if it doesn't exist yet
445
415
  */
446
- insertValues: Pick<
416
+ explicitDefaultValues: Pick<
447
417
  SqliteDsl.FromColumns.RowDecodedAll<TTableDef['sqliteDef']['columns']>,
448
418
  SqliteDsl.FromColumns.RequiredInsertColumnNames<Omit<TTableDef['sqliteDef']['columns'], 'id'>>
449
419
  >
450
420
  }
451
421
 
452
- export type Result<TTableDef extends DbSchema.TableDefBase> = TTableDef['options']['isSingleColumn'] extends true
453
- ? GetValForKey<SqliteDsl.FromColumns.RowDecoded<TTableDef['sqliteDef']['columns']>, 'value'>
454
- : SqliteDsl.FromColumns.RowDecoded<TTableDef['sqliteDef']['columns']>
422
+ export type Result<TTableDef extends State.SQLite.TableDefBase> = SqliteDsl.FromColumns.RowDecoded<
423
+ TTableDef['sqliteDef']['columns']
424
+ >
425
+
426
+ export type DocumentResult<TTableDef extends ClientDocumentTableDef.Any> = GetValForKey<
427
+ SqliteDsl.FromColumns.RowDecoded<TTableDef['sqliteDef']['columns']>,
428
+ 'value'
429
+ >
455
430
 
456
- export type ResultEncoded<TTableDef extends DbSchema.TableDefBase> =
457
- TTableDef['options']['isSingleColumn'] extends true
431
+ export type ResultEncoded<TTableDef extends State.SQLite.TableDefBase> =
432
+ TTableDef['options']['isClientDocumentTable'] extends true
458
433
  ? GetValForKey<SqliteDsl.FromColumns.RowEncoded<TTableDef['sqliteDef']['columns']>, 'value'>
459
434
  : SqliteDsl.FromColumns.RowEncoded<TTableDef['sqliteDef']['columns']>
435
+
436
+ export type GetIdColumnType<TTableDef extends State.SQLite.TableDefBase> =
437
+ TTableDef['sqliteDef']['columns']['id']['schema']['Type']
460
438
  }
461
439
 
462
440
  type GetSingle<T> = T extends ReadonlyArray<infer U> ? U : never
463
-
464
- // export type QueryBuilderParamRef = { _tag: 'QueryBuilderParamRef' }
465
- // export type QueryBuilderSelectParams = { [key: string]: QueryBuilderSelectParam }
466
- // export type QueryBuilderSelectParam = boolean | ((ref: QueryBuilderParamRef) => QueryBuilder<any, any>)
@@ -2,14 +2,14 @@ import { shouldNeverHappen } from '@livestore/utils'
2
2
  import { Schema } from '@livestore/utils/effect'
3
3
 
4
4
  import { SessionIdSymbol } from '../adapter-types.js'
5
- import type { DbSchema } from '../schema/mod.js'
5
+ import type { State } from '../schema/mod.js'
6
6
  import type { SqlValue } from '../util.js'
7
7
  import type { QueryBuilderAst } from './api.js'
8
8
 
9
9
  // Helper functions for SQL generation
10
10
  const formatWhereClause = (
11
11
  whereConditions: ReadonlyArray<QueryBuilderAst.Where>,
12
- tableDef: DbSchema.TableDefBase,
12
+ tableDef: State.SQLite.TableDefBase,
13
13
  bindValues: SqlValue[],
14
14
  ): string => {
15
15
  if (whereConditions.length === 0) return ''
@@ -72,52 +72,67 @@ export const astToSql = (ast: QueryBuilderAst): { query: string; bindValues: Sql
72
72
  if (ast._tag === 'InsertQuery') {
73
73
  const columns = Object.keys(ast.values)
74
74
  const placeholders = columns.map(() => '?').join(', ')
75
- const values = Object.values(Schema.encodeSync(ast.tableDef.insertSchema)(ast.values)) as SqlValue[]
75
+ const encodedValues = Schema.encodeSync(ast.tableDef.insertSchema)(ast.values)
76
76
 
77
- bindValues.push(...values)
77
+ // Ensure bind values are added in the same order as columns
78
+ columns.forEach((col) => {
79
+ bindValues.push(encodedValues[col] as SqlValue)
80
+ })
78
81
 
79
- let query = `INSERT INTO '${ast.tableDef.sqliteDef.name}' (${columns.join(', ')}) VALUES (${placeholders})`
82
+ let insertVerb = 'INSERT'
83
+ let conflictClause = '' // Store the ON CONFLICT clause separately
80
84
 
81
85
  // Handle ON CONFLICT clause
82
86
  if (ast.onConflict) {
83
- query += ` ON CONFLICT (${ast.onConflict.target}) `
84
- if (ast.onConflict.action._tag === 'ignore') {
85
- query += 'DO NOTHING'
86
- } else if (ast.onConflict.action._tag === 'replace') {
87
- query += 'DO REPLACE'
87
+ // Handle REPLACE specifically as it changes the INSERT verb
88
+ if (ast.onConflict.action._tag === 'replace') {
89
+ insertVerb = 'INSERT OR REPLACE'
90
+ // For REPLACE, the conflict target is implied and no further clause is needed
88
91
  } else {
89
- // Handle the update record case
90
- const updateValues = ast.onConflict.action.update
91
- const updateCols = Object.keys(updateValues)
92
- if (updateCols.length === 0) {
93
- throw new Error('No update columns provided for ON CONFLICT DO UPDATE')
94
- }
92
+ // Build the ON CONFLICT clause for IGNORE or UPDATE
93
+ conflictClause = ` ON CONFLICT (${ast.onConflict.targets.join(', ')}) `
94
+ if (ast.onConflict.action._tag === 'ignore') {
95
+ conflictClause += 'DO NOTHING'
96
+ } else {
97
+ // Handle the update record case
98
+ const updateValues = ast.onConflict.action.update
99
+ const updateCols = Object.keys(updateValues)
100
+ if (updateCols.length === 0) {
101
+ throw new Error('No update columns provided for ON CONFLICT DO UPDATE')
102
+ }
95
103
 
96
- const updates = updateCols
97
- .map((col) => {
104
+ const updates = updateCols
105
+ .map((col) => {
106
+ const value = updateValues[col]
107
+ // If the value is undefined, use excluded.col
108
+ return value === undefined ? `${col} = excluded.${col}` : `${col} = ?`
109
+ })
110
+ .join(', ')
111
+
112
+ // Add values for the parameters
113
+ updateCols.forEach((col) => {
98
114
  const value = updateValues[col]
99
- // If the value is undefined, use excluded.col
100
- return value === undefined ? `${col} = excluded.${col}` : `${col} = ?`
101
- })
102
- .join(', ')
103
-
104
- // Add values for the parameters
105
- updateCols.forEach((col) => {
106
- const value = updateValues[col]
107
- if (value !== undefined) {
108
- const colDef = ast.tableDef.sqliteDef.columns[col]
109
- if (colDef === undefined) {
110
- throw new Error(`Column ${col} not found`)
115
+ if (value !== undefined) {
116
+ const colDef = ast.tableDef.sqliteDef.columns[col]
117
+ if (colDef === undefined) {
118
+ throw new Error(`Column ${col} not found`)
119
+ }
120
+ const encodedValue = Schema.encodeSync(colDef.schema)(value)
121
+ bindValues.push(encodedValue as SqlValue)
111
122
  }
112
- const encodedValue = Schema.encodeSync(colDef.schema)(value)
113
- bindValues.push(encodedValue as SqlValue)
114
- }
115
- })
123
+ })
116
124
 
117
- query += `DO UPDATE SET ${updates}`
125
+ conflictClause += `DO UPDATE SET ${updates}`
126
+ }
118
127
  }
119
128
  }
120
129
 
130
+ // Construct the main query part
131
+ let query = `${insertVerb} INTO '${ast.tableDef.sqliteDef.name}' (${columns.join(', ')}) VALUES (${placeholders})`
132
+
133
+ // Append the conflict clause if it was generated (i.e., not for REPLACE)
134
+ query += conflictClause
135
+
121
136
  query += formatReturningClause(ast.returning)
122
137
  return { query, bindValues }
123
138
  }
@@ -125,8 +140,21 @@ export const astToSql = (ast: QueryBuilderAst): { query: string; bindValues: Sql
125
140
  // UPDATE query
126
141
  if (ast._tag === 'UpdateQuery') {
127
142
  const setColumns = Object.keys(ast.values)
128
- const setValues = Object.values(Schema.encodeSync(Schema.partial(ast.tableDef.schema))(ast.values))
129
- bindValues.push(...setValues)
143
+
144
+ if (setColumns.length === 0) {
145
+ console.warn(
146
+ `UPDATE query requires at least one column to set (for table ${ast.tableDef.sqliteDef.name}). Running no-op query instead to skip this update query.`,
147
+ )
148
+ return { query: 'SELECT 1', bindValues: [] }
149
+ // return shouldNeverHappen('UPDATE query requires at least one column to set.')
150
+ }
151
+
152
+ const encodedValues = Schema.encodeSync(Schema.partial(ast.tableDef.rowSchema))(ast.values)
153
+
154
+ // Ensure bind values are added in the same order as columns
155
+ setColumns.forEach((col) => {
156
+ bindValues.push(encodedValues[col] as SqlValue)
157
+ })
130
158
 
131
159
  let query = `UPDATE '${ast.tableDef.sqliteDef.name}' SET ${setColumns.map((col) => `${col} = ?`).join(', ')}`
132
160
 
@@ -189,10 +217,11 @@ export const astToSql = (ast: QueryBuilderAst): { query: string; bindValues: Sql
189
217
  : ''
190
218
 
191
219
  const limitStmt = ast.limit._tag === 'Some' ? `LIMIT ?` : ''
192
- if (ast.limit._tag === 'Some') bindValues.push(ast.limit.value)
193
-
194
220
  const offsetStmt = ast.offset._tag === 'Some' ? `OFFSET ?` : ''
221
+
222
+ // Push offset and limit values in the correct order matching the query string
195
223
  if (ast.offset._tag === 'Some') bindValues.push(ast.offset.value)
224
+ if (ast.limit._tag === 'Some') bindValues.push(ast.limit.value)
196
225
 
197
226
  const query = [selectStmt, fromStmt, whereStmt, orderByStmt, offsetStmt, limitStmt]
198
227
  .map((clause) => clause.trim())