@livestore/common 0.4.0-dev.18 → 0.4.0-dev.19

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 (286) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/ClientSessionLeaderThreadProxy.d.ts +10 -10
  3. package/dist/ClientSessionLeaderThreadProxy.d.ts.map +1 -1
  4. package/dist/adapter-types.d.ts +5 -5
  5. package/dist/adapter-types.d.ts.map +1 -1
  6. package/dist/devtools/devtools-messages-client-session.d.ts +28 -23
  7. package/dist/devtools/devtools-messages-client-session.d.ts.map +1 -1
  8. package/dist/devtools/devtools-messages-client-session.js +2 -2
  9. package/dist/devtools/devtools-messages-client-session.js.map +1 -1
  10. package/dist/devtools/devtools-messages-common.d.ts +6 -6
  11. package/dist/devtools/devtools-messages-leader.d.ts +33 -28
  12. package/dist/devtools/devtools-messages-leader.d.ts.map +1 -1
  13. package/dist/devtools/devtools-messages-leader.js +8 -8
  14. package/dist/devtools/devtools-messages-leader.js.map +1 -1
  15. package/dist/errors.d.ts +6 -6
  16. package/dist/errors.d.ts.map +1 -1
  17. package/dist/errors.js +7 -7
  18. package/dist/errors.js.map +1 -1
  19. package/dist/leader-thread/LeaderSyncProcessor.d.ts +2 -2
  20. package/dist/leader-thread/LeaderSyncProcessor.d.ts.map +1 -1
  21. package/dist/leader-thread/LeaderSyncProcessor.js +28 -28
  22. package/dist/leader-thread/LeaderSyncProcessor.js.map +1 -1
  23. package/dist/leader-thread/eventlog.d.ts +13 -13
  24. package/dist/leader-thread/eventlog.d.ts.map +1 -1
  25. package/dist/leader-thread/eventlog.js +12 -11
  26. package/dist/leader-thread/eventlog.js.map +1 -1
  27. package/dist/leader-thread/leader-worker-devtools.d.ts +2 -2
  28. package/dist/leader-thread/leader-worker-devtools.d.ts.map +1 -1
  29. package/dist/leader-thread/leader-worker-devtools.js +3 -3
  30. package/dist/leader-thread/leader-worker-devtools.js.map +1 -1
  31. package/dist/leader-thread/make-leader-thread-layer.d.ts +2 -2
  32. package/dist/leader-thread/make-leader-thread-layer.d.ts.map +1 -1
  33. package/dist/leader-thread/make-leader-thread-layer.js +10 -8
  34. package/dist/leader-thread/make-leader-thread-layer.js.map +1 -1
  35. package/dist/leader-thread/materialize-event.d.ts +1 -1
  36. package/dist/leader-thread/materialize-event.d.ts.map +1 -1
  37. package/dist/leader-thread/materialize-event.js +2 -2
  38. package/dist/leader-thread/materialize-event.js.map +1 -1
  39. package/dist/leader-thread/recreate-db.d.ts +2 -2
  40. package/dist/leader-thread/recreate-db.d.ts.map +1 -1
  41. package/dist/leader-thread/recreate-db.js +5 -5
  42. package/dist/leader-thread/recreate-db.js.map +1 -1
  43. package/dist/leader-thread/shutdown-channel.d.ts +2 -2
  44. package/dist/leader-thread/shutdown-channel.d.ts.map +1 -1
  45. package/dist/leader-thread/shutdown-channel.js +2 -2
  46. package/dist/leader-thread/shutdown-channel.js.map +1 -1
  47. package/dist/leader-thread/types.d.ts +15 -15
  48. package/dist/leader-thread/types.d.ts.map +1 -1
  49. package/dist/make-client-session.d.ts +2 -2
  50. package/dist/make-client-session.d.ts.map +1 -1
  51. package/dist/materializer-helper.d.ts +5 -5
  52. package/dist/materializer-helper.d.ts.map +1 -1
  53. package/dist/materializer-helper.js.map +1 -1
  54. package/dist/rematerialize-from-eventlog.d.ts +2 -2
  55. package/dist/rematerialize-from-eventlog.d.ts.map +1 -1
  56. package/dist/rematerialize-from-eventlog.js +6 -6
  57. package/dist/rematerialize-from-eventlog.js.map +1 -1
  58. package/dist/schema/EventDef/define.d.ts +147 -0
  59. package/dist/schema/EventDef/define.d.ts.map +1 -0
  60. package/dist/schema/EventDef/define.js +139 -0
  61. package/dist/schema/EventDef/define.js.map +1 -0
  62. package/dist/schema/EventDef/event-def.d.ts +106 -0
  63. package/dist/schema/EventDef/event-def.d.ts.map +1 -0
  64. package/dist/schema/EventDef/event-def.js +2 -0
  65. package/dist/schema/EventDef/event-def.js.map +1 -0
  66. package/dist/schema/EventDef/facts.d.ts +118 -0
  67. package/dist/schema/EventDef/facts.d.ts.map +1 -0
  68. package/dist/schema/EventDef/facts.js +53 -0
  69. package/dist/schema/EventDef/facts.js.map +1 -0
  70. package/dist/schema/EventDef/materializer.d.ts +155 -0
  71. package/dist/schema/EventDef/materializer.d.ts.map +1 -0
  72. package/dist/schema/EventDef/materializer.js +83 -0
  73. package/dist/schema/EventDef/materializer.js.map +1 -0
  74. package/dist/schema/EventDef/mod.d.ts +5 -0
  75. package/dist/schema/EventDef/mod.d.ts.map +1 -0
  76. package/dist/schema/EventDef/mod.js +5 -0
  77. package/dist/schema/EventDef/mod.js.map +1 -0
  78. package/dist/schema/EventSequenceNumber/client.d.ts +136 -0
  79. package/dist/schema/EventSequenceNumber/client.d.ts.map +1 -0
  80. package/dist/schema/{EventSequenceNumber.js → EventSequenceNumber/client.js} +86 -39
  81. package/dist/schema/EventSequenceNumber/client.js.map +1 -0
  82. package/dist/schema/EventSequenceNumber/global.d.ts +15 -0
  83. package/dist/schema/EventSequenceNumber/global.d.ts.map +1 -0
  84. package/dist/schema/EventSequenceNumber/global.js +14 -0
  85. package/dist/schema/EventSequenceNumber/global.js.map +1 -0
  86. package/dist/schema/EventSequenceNumber/mod.d.ts +37 -0
  87. package/dist/schema/EventSequenceNumber/mod.d.ts.map +1 -0
  88. package/dist/schema/EventSequenceNumber/mod.js +37 -0
  89. package/dist/schema/EventSequenceNumber/mod.js.map +1 -0
  90. package/dist/schema/EventSequenceNumber.test.js +41 -41
  91. package/dist/schema/EventSequenceNumber.test.js.map +1 -1
  92. package/dist/schema/{LiveStoreEvent.d.ts → LiveStoreEvent/client.d.ts} +84 -101
  93. package/dist/schema/LiveStoreEvent/client.d.ts.map +1 -0
  94. package/dist/schema/{LiveStoreEvent.js → LiveStoreEvent/client.js} +69 -52
  95. package/dist/schema/LiveStoreEvent/client.js.map +1 -0
  96. package/dist/schema/LiveStoreEvent/for-event-def.d.ts +52 -0
  97. package/dist/schema/LiveStoreEvent/for-event-def.d.ts.map +1 -0
  98. package/dist/schema/LiveStoreEvent/for-event-def.js +2 -0
  99. package/dist/schema/LiveStoreEvent/for-event-def.js.map +1 -0
  100. package/dist/schema/LiveStoreEvent/global.d.ts +36 -0
  101. package/dist/schema/LiveStoreEvent/global.d.ts.map +1 -0
  102. package/dist/schema/LiveStoreEvent/global.js +31 -0
  103. package/dist/schema/LiveStoreEvent/global.js.map +1 -0
  104. package/dist/schema/LiveStoreEvent/input.d.ts +46 -0
  105. package/dist/schema/LiveStoreEvent/input.d.ts.map +1 -0
  106. package/dist/schema/LiveStoreEvent/input.js +26 -0
  107. package/dist/schema/LiveStoreEvent/input.js.map +1 -0
  108. package/dist/schema/LiveStoreEvent/mod.d.ts +5 -0
  109. package/dist/schema/LiveStoreEvent/mod.d.ts.map +1 -0
  110. package/dist/schema/LiveStoreEvent/mod.js +5 -0
  111. package/dist/schema/LiveStoreEvent/mod.js.map +1 -0
  112. package/dist/schema/events.d.ts +1 -1
  113. package/dist/schema/events.d.ts.map +1 -1
  114. package/dist/schema/events.js +1 -1
  115. package/dist/schema/events.js.map +1 -1
  116. package/dist/schema/mod.d.ts +3 -3
  117. package/dist/schema/mod.d.ts.map +1 -1
  118. package/dist/schema/mod.js +3 -3
  119. package/dist/schema/mod.js.map +1 -1
  120. package/dist/schema/schema.d.ts +1 -1
  121. package/dist/schema/schema.d.ts.map +1 -1
  122. package/dist/schema/state/sqlite/client-document-def.d.ts +1 -1
  123. package/dist/schema/state/sqlite/client-document-def.d.ts.map +1 -1
  124. package/dist/schema/state/sqlite/client-document-def.js +2 -2
  125. package/dist/schema/state/sqlite/client-document-def.js.map +1 -1
  126. package/dist/schema/state/sqlite/client-document-def.test.js.map +1 -1
  127. package/dist/schema/state/sqlite/column-def.js +13 -0
  128. package/dist/schema/state/sqlite/column-def.js.map +1 -1
  129. package/dist/schema/state/sqlite/column-def.test.js +2 -1
  130. package/dist/schema/state/sqlite/column-def.test.js.map +1 -1
  131. package/dist/schema/state/sqlite/mod.d.ts +2 -2
  132. package/dist/schema/state/sqlite/mod.d.ts.map +1 -1
  133. package/dist/schema/state/sqlite/mod.js +1 -1
  134. package/dist/schema/state/sqlite/mod.js.map +1 -1
  135. package/dist/schema/state/sqlite/query-builder/api.d.ts +12 -8
  136. package/dist/schema/state/sqlite/query-builder/api.d.ts.map +1 -1
  137. package/dist/schema/state/sqlite/query-builder/astToSql.d.ts.map +1 -1
  138. package/dist/schema/state/sqlite/query-builder/astToSql.js +18 -11
  139. package/dist/schema/state/sqlite/query-builder/astToSql.js.map +1 -1
  140. package/dist/schema/state/sqlite/query-builder/impl.test.js +119 -90
  141. package/dist/schema/state/sqlite/query-builder/impl.test.js.map +1 -1
  142. package/dist/schema/state/sqlite/system-tables/eventlog-tables.js +5 -5
  143. package/dist/schema/state/sqlite/system-tables/eventlog-tables.js.map +1 -1
  144. package/dist/schema/state/sqlite/system-tables/state-tables.js +3 -3
  145. package/dist/schema/state/sqlite/system-tables/state-tables.js.map +1 -1
  146. package/dist/schema/unknown-events.d.ts +3 -3
  147. package/dist/schema/unknown-events.d.ts.map +1 -1
  148. package/dist/schema-management/migrations.d.ts +2 -2
  149. package/dist/schema-management/migrations.d.ts.map +1 -1
  150. package/dist/schema-management/migrations.js.map +1 -1
  151. package/dist/schema-management/validate-schema.d.ts +3 -3
  152. package/dist/schema-management/validate-schema.d.ts.map +1 -1
  153. package/dist/schema-management/validate-schema.js +2 -2
  154. package/dist/schema-management/validate-schema.js.map +1 -1
  155. package/dist/sqlite-types.d.ts +3 -3
  156. package/dist/sqlite-types.d.ts.map +1 -1
  157. package/dist/sync/ClientSessionSyncProcessor.d.ts +5 -5
  158. package/dist/sync/ClientSessionSyncProcessor.d.ts.map +1 -1
  159. package/dist/sync/ClientSessionSyncProcessor.js +12 -12
  160. package/dist/sync/ClientSessionSyncProcessor.js.map +1 -1
  161. package/dist/sync/errors.d.ts +9 -4
  162. package/dist/sync/errors.d.ts.map +1 -1
  163. package/dist/sync/errors.js +6 -6
  164. package/dist/sync/errors.js.map +1 -1
  165. package/dist/sync/mock-sync-backend.d.ts +6 -6
  166. package/dist/sync/mock-sync-backend.d.ts.map +1 -1
  167. package/dist/sync/mock-sync-backend.js +4 -4
  168. package/dist/sync/mock-sync-backend.js.map +1 -1
  169. package/dist/sync/next/compact-events.js +2 -2
  170. package/dist/sync/next/compact-events.js.map +1 -1
  171. package/dist/sync/next/facts.d.ts +5 -5
  172. package/dist/sync/next/facts.d.ts.map +1 -1
  173. package/dist/sync/next/facts.js.map +1 -1
  174. package/dist/sync/next/history-dag-common.d.ts +5 -5
  175. package/dist/sync/next/history-dag-common.d.ts.map +1 -1
  176. package/dist/sync/next/history-dag-common.js +5 -5
  177. package/dist/sync/next/history-dag-common.js.map +1 -1
  178. package/dist/sync/next/history-dag.d.ts.map +1 -1
  179. package/dist/sync/next/history-dag.js +8 -8
  180. package/dist/sync/next/history-dag.js.map +1 -1
  181. package/dist/sync/next/rebase-events.d.ts +5 -5
  182. package/dist/sync/next/rebase-events.d.ts.map +1 -1
  183. package/dist/sync/next/rebase-events.js +5 -5
  184. package/dist/sync/next/rebase-events.js.map +1 -1
  185. package/dist/sync/next/test/event-fixtures.d.ts +2 -2
  186. package/dist/sync/next/test/event-fixtures.d.ts.map +1 -1
  187. package/dist/sync/next/test/event-fixtures.js +9 -9
  188. package/dist/sync/next/test/event-fixtures.js.map +1 -1
  189. package/dist/sync/sync-backend-kv.d.ts +3 -3
  190. package/dist/sync/sync-backend-kv.d.ts.map +1 -1
  191. package/dist/sync/sync-backend-kv.js +3 -3
  192. package/dist/sync/sync-backend-kv.js.map +1 -1
  193. package/dist/sync/sync-backend.d.ts +9 -9
  194. package/dist/sync/sync-backend.d.ts.map +1 -1
  195. package/dist/sync/syncstate.d.ts +55 -42
  196. package/dist/sync/syncstate.d.ts.map +1 -1
  197. package/dist/sync/syncstate.js +42 -42
  198. package/dist/sync/syncstate.js.map +1 -1
  199. package/dist/sync/syncstate.test.js +40 -40
  200. package/dist/sync/syncstate.test.js.map +1 -1
  201. package/dist/sync/validate-push-payload.d.ts +1 -1
  202. package/dist/sync/validate-push-payload.d.ts.map +1 -1
  203. package/dist/sync/validate-push-payload.js +2 -2
  204. package/dist/sync/validate-push-payload.js.map +1 -1
  205. package/dist/testing/event-factory.d.ts +3 -3
  206. package/dist/testing/event-factory.d.ts.map +1 -1
  207. package/dist/testing/event-factory.js +5 -7
  208. package/dist/testing/event-factory.js.map +1 -1
  209. package/dist/version.d.ts +1 -1
  210. package/dist/version.js +1 -1
  211. package/package.json +4 -4
  212. package/src/ClientSessionLeaderThreadProxy.ts +10 -10
  213. package/src/adapter-types.ts +5 -5
  214. package/src/devtools/devtools-messages-client-session.ts +2 -2
  215. package/src/devtools/devtools-messages-leader.ts +8 -8
  216. package/src/errors.ts +11 -13
  217. package/src/leader-thread/LeaderSyncProcessor.ts +54 -56
  218. package/src/leader-thread/eventlog.ts +21 -26
  219. package/src/leader-thread/leader-worker-devtools.ts +3 -3
  220. package/src/leader-thread/make-leader-thread-layer.ts +12 -10
  221. package/src/leader-thread/materialize-event.ts +3 -3
  222. package/src/leader-thread/recreate-db.ts +6 -6
  223. package/src/leader-thread/shutdown-channel.ts +2 -2
  224. package/src/leader-thread/types.ts +15 -15
  225. package/src/make-client-session.ts +2 -2
  226. package/src/materializer-helper.ts +5 -5
  227. package/src/rematerialize-from-eventlog.ts +6 -6
  228. package/src/schema/EventDef/define.ts +201 -0
  229. package/src/schema/EventDef/event-def.ts +120 -0
  230. package/src/schema/EventDef/facts.ts +135 -0
  231. package/src/schema/EventDef/materializer.ts +172 -0
  232. package/src/schema/EventDef/mod.ts +4 -0
  233. package/src/schema/EventSequenceNumber/client.ts +257 -0
  234. package/src/schema/EventSequenceNumber/global.ts +19 -0
  235. package/src/schema/EventSequenceNumber/mod.ts +37 -0
  236. package/src/schema/EventSequenceNumber.test.ts +68 -50
  237. package/src/schema/LiveStoreEvent/client.ts +221 -0
  238. package/src/schema/LiveStoreEvent/for-event-def.ts +60 -0
  239. package/src/schema/LiveStoreEvent/global.ts +45 -0
  240. package/src/schema/LiveStoreEvent/input.ts +63 -0
  241. package/src/schema/LiveStoreEvent/mod.ts +4 -0
  242. package/src/schema/events.ts +1 -1
  243. package/src/schema/mod.ts +3 -3
  244. package/src/schema/schema.ts +1 -1
  245. package/src/schema/state/sqlite/client-document-def.test.ts +2 -2
  246. package/src/schema/state/sqlite/client-document-def.ts +3 -3
  247. package/src/schema/state/sqlite/column-def.test.ts +2 -1
  248. package/src/schema/state/sqlite/column-def.ts +17 -0
  249. package/src/schema/state/sqlite/mod.ts +2 -2
  250. package/src/schema/state/sqlite/query-builder/api.ts +12 -8
  251. package/src/schema/state/sqlite/query-builder/astToSql.ts +20 -11
  252. package/src/schema/state/sqlite/query-builder/impl.test.ts +122 -90
  253. package/src/schema/state/sqlite/system-tables/eventlog-tables.ts +5 -5
  254. package/src/schema/state/sqlite/system-tables/state-tables.ts +3 -3
  255. package/src/schema/unknown-events.ts +3 -3
  256. package/src/schema-management/migrations.ts +2 -2
  257. package/src/schema-management/validate-schema.ts +3 -3
  258. package/src/sqlite-types.ts +3 -3
  259. package/src/sync/ClientSessionSyncProcessor.ts +17 -17
  260. package/src/sync/errors.ts +6 -6
  261. package/src/sync/mock-sync-backend.ts +16 -16
  262. package/src/sync/next/compact-events.ts +2 -2
  263. package/src/sync/next/facts.ts +6 -6
  264. package/src/sync/next/history-dag-common.ts +8 -8
  265. package/src/sync/next/history-dag.ts +14 -10
  266. package/src/sync/next/rebase-events.ts +11 -11
  267. package/src/sync/next/test/event-fixtures.ts +11 -11
  268. package/src/sync/sync-backend-kv.ts +3 -3
  269. package/src/sync/sync-backend.ts +9 -9
  270. package/src/sync/syncstate.test.ts +46 -46
  271. package/src/sync/syncstate.ts +59 -55
  272. package/src/sync/validate-push-payload.ts +4 -4
  273. package/src/testing/event-factory.ts +10 -12
  274. package/src/version.ts +1 -1
  275. package/dist/schema/EventDef.d.ts +0 -126
  276. package/dist/schema/EventDef.d.ts.map +0 -1
  277. package/dist/schema/EventDef.js +0 -46
  278. package/dist/schema/EventDef.js.map +0 -1
  279. package/dist/schema/EventSequenceNumber.d.ts +0 -89
  280. package/dist/schema/EventSequenceNumber.d.ts.map +0 -1
  281. package/dist/schema/EventSequenceNumber.js.map +0 -1
  282. package/dist/schema/LiveStoreEvent.d.ts.map +0 -1
  283. package/dist/schema/LiveStoreEvent.js.map +0 -1
  284. package/src/schema/EventDef.ts +0 -222
  285. package/src/schema/EventSequenceNumber.ts +0 -208
  286. package/src/schema/LiveStoreEvent.ts +0 -286
@@ -179,6 +179,10 @@ const getColumnForSchema = (schema: Schema.Schema.AnyNoContext, nullable = false
179
179
  return SqliteDsl.real({ schema: coreSchema, nullable })
180
180
  }
181
181
 
182
+ if (isUint8ArraySchema(coreAst) || isUint8ArraySchema(encodedAst)) {
183
+ return SqliteDsl.blob({ schema: Schema.Uint8ArrayFromSelf as Schema.Schema<Uint8Array<ArrayBuffer>>, nullable })
184
+ }
185
+
182
186
  const literalColumn = getLiteralColumnDefinition(encodedAst, coreSchema, nullable, coreAst)
183
187
  if (literalColumn) return literalColumn
184
188
 
@@ -263,3 +267,16 @@ const getLiteralValueType = (
263
267
  ? literalType
264
268
  : null
265
269
  }
270
+
271
+ const isUint8ArraySchema = (ast: SchemaAST.AST): boolean => {
272
+ const identifier = SchemaAST.getIdentifierAnnotation(ast)
273
+ if (Option.isSome(identifier) && identifier.value.includes('Uint8Array')) {
274
+ return true
275
+ }
276
+
277
+ if (SchemaAST.isTupleType(ast)) {
278
+ return ast.elements.length === 0 && ast.rest.length === 1 && SchemaAST.isNumberKeyword(ast.rest[0]!.type)
279
+ }
280
+
281
+ return false
282
+ }
@@ -1,14 +1,14 @@
1
1
  import { shouldNeverHappen } from '@livestore/utils'
2
2
 
3
3
  import type { MigrationOptions } from '../../../adapter-types.ts'
4
- import type { Materializer } from '../../EventDef.ts'
4
+ import type { Materializer } from '../../EventDef/mod.ts'
5
5
  import type { InternalState } from '../../schema.ts'
6
6
  import { ClientDocumentTableDefSymbol, tableIsClientDocumentTable } from './client-document-def.ts'
7
7
  import { SqliteAst } from './db-schema/mod.ts'
8
8
  import { stateSystemTables } from './system-tables/state-tables.ts'
9
9
  import type { TableDef, TableDefBase } from './table-def.ts'
10
10
 
11
- export * from '../../EventDef.ts'
11
+ export * from '../../EventDef/mod.ts'
12
12
  export {
13
13
  type ClientDocumentTableDef,
14
14
  ClientDocumentTableDefSymbol,
@@ -347,22 +347,26 @@ export namespace QueryBuilder {
347
347
  >
348
348
 
349
349
  /**
350
- * Example: If the row already exists, it will be ignored.
350
+ * Upsert: insert a row, or handle conflicts on existing rows.
351
+ * Equivalent to SQLite's `INSERT ... ON CONFLICT` clause.
352
+ *
353
+ * Actions:
354
+ * - `'ignore'`: Skip the insert if a row with the same key exists
355
+ * - `'replace'`: Delete the existing row and insert the new one
356
+ * - `'update'`: Update specific columns on the existing row
357
+ *
351
358
  * ```ts
359
+ * // Ignore: skip if row exists
352
360
  * db.todos.insert({ id: '123', text: 'Buy milk', status: 'active' }).onConflict('id', 'ignore')
353
- * ```
354
361
  *
355
- * Example: If the row already exists, it will be replaced.
356
- * ```ts
362
+ * // Replace: delete existing row and insert new one
357
363
  * db.todos.insert({ id: '123', text: 'Buy milk', status: 'active' }).onConflict('id', 'replace')
358
- * ```
359
364
  *
360
- * Example: If the row already exists, it will be updated.
361
- * ```ts
365
+ * // Update: merge specific columns into existing row
362
366
  * db.todos.insert({ id: '123', text: 'Buy milk', status: 'active' }).onConflict('id', 'update', { text: 'Buy soy milk' })
363
367
  * ```
364
368
  *
365
- * NOTE This API doesn't yet support composite primary keys.
369
+ * NOTE: Composite primary keys are not yet supported.
366
370
  */
367
371
  readonly onConflict: {
368
372
  <TTarget extends SingleOrReadonlyArray<keyof TTableDef['sqliteDef']['columns']>>(
@@ -7,6 +7,8 @@ import type { State } from '../../../mod.ts'
7
7
  import type { QueryBuilderAst } from './api.ts'
8
8
 
9
9
  // Helper functions for SQL generation
10
+ const quoteIdentifier = (identifier: string): string => `"${identifier.replace(/"/g, '""')}"`
11
+
10
12
  const formatWhereClause = (
11
13
  whereConditions: ReadonlyArray<QueryBuilderAst.Where>,
12
14
  tableDef: State.SQLite.TableDefBase,
@@ -16,13 +18,15 @@ const formatWhereClause = (
16
18
 
17
19
  const whereClause = whereConditions
18
20
  .map(({ col, op, value }) => {
21
+ const quotedCol = quoteIdentifier(col)
22
+
19
23
  // Handle NULL values
20
24
  if (value === null) {
21
25
  if (op !== '=' && op !== '!=') {
22
26
  throw new Error(`Unsupported operator for NULL value: ${op}`)
23
27
  }
24
28
  const opStmt = op === '=' ? 'IS' : 'IS NOT'
25
- return `${col} ${opStmt} NULL`
29
+ return `${quotedCol} ${opStmt} NULL`
26
30
  }
27
31
 
28
32
  // Get column definition and encode value
@@ -48,11 +52,11 @@ const formatWhereClause = (
48
52
  const encodedValues = value.map((v) => Schema.encodeSync(colDef.schema)(v)) as SqlValue[]
49
53
  bindValues.push(...encodedValues)
50
54
  const placeholders = encodedValues.map(() => '?').join(', ')
51
- return `${col} ${op} (${placeholders})`
55
+ return `${quotedCol} ${op} (${placeholders})`
52
56
  } else {
53
57
  const encodedValue = Schema.encodeSync(colDef.schema)(value)
54
58
  bindValues.push(encodedValue as SqlValue)
55
- return `${col} ${op} ?`
59
+ return `${quotedCol} ${op} ?`
56
60
  }
57
61
  })
58
62
  .join(' AND ')
@@ -62,7 +66,7 @@ const formatWhereClause = (
62
66
 
63
67
  const formatReturningClause = (returning?: string[]): string => {
64
68
  if (!returning || returning.length === 0) return ''
65
- return ` RETURNING ${returning.join(', ')}`
69
+ return ` RETURNING ${returning.map(quoteIdentifier).join(', ')}`
66
70
  }
67
71
 
68
72
  export const astToSql = (ast: QueryBuilderAst): { query: string; bindValues: SqlValue[]; usedTables: Set<string> } => {
@@ -72,6 +76,7 @@ export const astToSql = (ast: QueryBuilderAst): { query: string; bindValues: Sql
72
76
  // INSERT query
73
77
  if (ast._tag === 'InsertQuery') {
74
78
  const columns = Object.keys(ast.values)
79
+ const quotedColumns = columns.map(quoteIdentifier)
75
80
  const placeholders = columns.map(() => '?').join(', ')
76
81
  const encodedValues = Schema.encodeSync(ast.tableDef.insertSchema)(ast.values)
77
82
 
@@ -91,7 +96,8 @@ export const astToSql = (ast: QueryBuilderAst): { query: string; bindValues: Sql
91
96
  // For REPLACE, the conflict target is implied and no further clause is needed
92
97
  } else {
93
98
  // Build the ON CONFLICT clause for IGNORE or UPDATE
94
- conflictClause = ` ON CONFLICT (${ast.onConflict.targets.join(', ')}) `
99
+ const conflictTargets = ast.onConflict.targets.map(quoteIdentifier).join(', ')
100
+ conflictClause = ` ON CONFLICT (${conflictTargets}) `
95
101
  if (ast.onConflict.action._tag === 'ignore') {
96
102
  conflictClause += 'DO NOTHING'
97
103
  } else {
@@ -105,8 +111,9 @@ export const astToSql = (ast: QueryBuilderAst): { query: string; bindValues: Sql
105
111
  const updates = updateCols
106
112
  .map((col) => {
107
113
  const value = updateValues[col]
114
+ const quotedCol = quoteIdentifier(col)
108
115
  // If the value is undefined, use excluded.col
109
- return value === undefined ? `${col} = excluded.${col}` : `${col} = ?`
116
+ return value === undefined ? `${quotedCol} = excluded.${quotedCol}` : `${quotedCol} = ?`
110
117
  })
111
118
  .join(', ')
112
119
 
@@ -129,7 +136,7 @@ export const astToSql = (ast: QueryBuilderAst): { query: string; bindValues: Sql
129
136
  }
130
137
 
131
138
  // Construct the main query part
132
- let query = `${insertVerb} INTO '${ast.tableDef.sqliteDef.name}' (${columns.join(', ')}) VALUES (${placeholders})`
139
+ let query = `${insertVerb} INTO '${ast.tableDef.sqliteDef.name}' (${quotedColumns.join(', ')}) VALUES (${placeholders})`
133
140
 
134
141
  // Append the conflict clause if it was generated (i.e., not for REPLACE)
135
142
  query += conflictClause
@@ -157,7 +164,9 @@ export const astToSql = (ast: QueryBuilderAst): { query: string; bindValues: Sql
157
164
  bindValues.push(encodedValues[col] as SqlValue)
158
165
  })
159
166
 
160
- let query = `UPDATE '${ast.tableDef.sqliteDef.name}' SET ${setColumns.map((col) => `${col} = ?`).join(', ')}`
167
+ let query = `UPDATE '${ast.tableDef.sqliteDef.name}' SET ${setColumns
168
+ .map((col) => `${quoteIdentifier(col)} = ?`)
169
+ .join(', ')}`
161
170
 
162
171
  const whereClause = formatWhereClause(ast.where, ast.tableDef, bindValues)
163
172
  if (whereClause) query += ` ${whereClause}`
@@ -201,21 +210,21 @@ export const astToSql = (ast: QueryBuilderAst): { query: string; bindValues: Sql
201
210
  const encodedId = ast.id === SessionIdSymbol ? ast.id : Schema.encodeSync(idColDef.schema)(ast.id)
202
211
 
203
212
  return {
204
- query: `SELECT * FROM '${ast.tableDef.sqliteDef.name}' WHERE id = ?`,
213
+ query: `SELECT * FROM '${ast.tableDef.sqliteDef.name}' WHERE ${quoteIdentifier('id')} = ?`,
205
214
  bindValues: [encodedId as SqlValue],
206
215
  usedTables,
207
216
  }
208
217
  }
209
218
 
210
219
  // SELECT query
211
- const columnsStmt = ast.select.columns.length === 0 ? '*' : ast.select.columns.join(', ')
220
+ const columnsStmt = ast.select.columns.length === 0 ? '*' : ast.select.columns.map(quoteIdentifier).join(', ')
212
221
  const selectStmt = `SELECT ${columnsStmt}`
213
222
  const fromStmt = `FROM '${ast.tableDef.sqliteDef.name}'`
214
223
  const whereStmt = formatWhereClause(ast.where, ast.tableDef, bindValues)
215
224
 
216
225
  const orderByStmt =
217
226
  ast.orderBy.length > 0
218
- ? `ORDER BY ${ast.orderBy.map(({ col, direction }) => `${col} ${direction}`).join(', ')}`
227
+ ? `ORDER BY ${ast.orderBy.map(({ col, direction }) => `${quoteIdentifier(col)} ${direction}`).join(', ')}`
219
228
  : ''
220
229
 
221
230
  const limitStmt = ast.limit._tag === 'Some' ? `LIMIT ?` : ''