@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
@@ -0,0 +1,199 @@
1
+ import { LS_DEV, shouldNeverHappen } from '@livestore/utils'
2
+ import { Effect, Option, Schema } from '@livestore/utils/effect'
3
+
4
+ import type { SqliteDb } from '../adapter-types.js'
5
+ import * as EventId from '../schema/EventId.js'
6
+ import * as LiveStoreEvent from '../schema/LiveStoreEvent.js'
7
+ import {
8
+ EVENTLOG_META_TABLE,
9
+ eventlogMetaTable,
10
+ sessionChangesetMetaTable,
11
+ SYNC_STATUS_TABLE,
12
+ syncStatusTable,
13
+ } from '../schema/system-tables.js'
14
+ import { migrateTable } from '../schema-management/migrations.js'
15
+ import { insertRow, updateRows } from '../sql-queries/sql-queries.js'
16
+ import type { PreparedBindValues } from '../util.js'
17
+ import { prepareBindValues, sql } from '../util.js'
18
+ import { execSql } from './connection.js'
19
+ import type { InitialSyncInfo } from './types.js'
20
+ import { LeaderThreadCtx } from './types.js'
21
+
22
+ export const initEventlogDb = (dbEventlog: SqliteDb) =>
23
+ Effect.gen(function* () {
24
+ yield* migrateTable({
25
+ db: dbEventlog,
26
+ behaviour: 'create-if-not-exists',
27
+ tableAst: eventlogMetaTable.sqliteDef.ast,
28
+ skipMetaTable: true,
29
+ })
30
+
31
+ yield* migrateTable({
32
+ db: dbEventlog,
33
+ behaviour: 'create-if-not-exists',
34
+ tableAst: syncStatusTable.sqliteDef.ast,
35
+ skipMetaTable: true,
36
+ })
37
+
38
+ // Create sync status row if it doesn't exist
39
+ yield* execSql(
40
+ dbEventlog,
41
+ sql`INSERT INTO ${SYNC_STATUS_TABLE} (head)
42
+ SELECT ${EventId.ROOT.global}
43
+ WHERE NOT EXISTS (SELECT 1 FROM ${SYNC_STATUS_TABLE})`,
44
+ {},
45
+ )
46
+ })
47
+
48
+ /** Exclusive of the "since event" */
49
+ export const getEventsSince = (
50
+ since: EventId.EventId,
51
+ ): Effect.Effect<ReadonlyArray<LiveStoreEvent.EncodedWithMeta>, never, LeaderThreadCtx> =>
52
+ Effect.gen(function* () {
53
+ const { dbEventlog, dbReadModel } = yield* LeaderThreadCtx
54
+
55
+ const query = eventlogMetaTable.where('idGlobal', '>=', since.global).asSql()
56
+ const pendingEventsRaw = dbEventlog.select(query.query, prepareBindValues(query.bindValues, query.query))
57
+ const pendingEvents = Schema.decodeUnknownSync(eventlogMetaTable.rowSchema.pipe(Schema.Array))(pendingEventsRaw)
58
+
59
+ const sessionChangesetRows = sessionChangesetMetaTable.where('idGlobal', '>=', since.global).asSql()
60
+ const sessionChangesetRowsRaw = dbReadModel.select(
61
+ sessionChangesetRows.query,
62
+ prepareBindValues(sessionChangesetRows.bindValues, sessionChangesetRows.query),
63
+ )
64
+ const sessionChangesetRowsDecoded = Schema.decodeUnknownSync(
65
+ sessionChangesetMetaTable.rowSchema.pipe(Schema.Array),
66
+ )(sessionChangesetRowsRaw)
67
+
68
+ return pendingEvents
69
+ .map((eventlogEvent) => {
70
+ const sessionChangeset = sessionChangesetRowsDecoded.find(
71
+ (readModelEvent) =>
72
+ readModelEvent.idGlobal === eventlogEvent.idGlobal && readModelEvent.idClient === eventlogEvent.idClient,
73
+ )
74
+ return LiveStoreEvent.EncodedWithMeta.make({
75
+ name: eventlogEvent.name,
76
+ args: eventlogEvent.argsJson,
77
+ id: { global: eventlogEvent.idGlobal, client: eventlogEvent.idClient },
78
+ parentId: { global: eventlogEvent.parentIdGlobal, client: eventlogEvent.parentIdClient },
79
+ clientId: eventlogEvent.clientId,
80
+ sessionId: eventlogEvent.sessionId,
81
+ meta: {
82
+ sessionChangeset:
83
+ sessionChangeset && sessionChangeset.changeset !== null
84
+ ? {
85
+ _tag: 'sessionChangeset' as const,
86
+ data: sessionChangeset.changeset,
87
+ debug: sessionChangeset.debug,
88
+ }
89
+ : { _tag: 'unset' as const },
90
+ syncMetadata: eventlogEvent.syncMetadataJson,
91
+ },
92
+ })
93
+ })
94
+ .filter((_) => EventId.compare(_.id, since) > 0)
95
+ .sort((a, b) => EventId.compare(a.id, b.id))
96
+ })
97
+
98
+ export const getClientHeadFromDb = (dbEventlog: SqliteDb): EventId.EventId => {
99
+ const res = dbEventlog.select<{ idGlobal: EventId.GlobalEventId; idClient: EventId.ClientEventId }>(
100
+ sql`select idGlobal, idClient from ${EVENTLOG_META_TABLE} order by idGlobal DESC, idClient DESC limit 1`,
101
+ )[0]
102
+
103
+ return res ? { global: res.idGlobal, client: res.idClient } : EventId.ROOT
104
+ }
105
+
106
+ export const getBackendHeadFromDb = (dbEventlog: SqliteDb): EventId.GlobalEventId =>
107
+ dbEventlog.select<{ head: EventId.GlobalEventId }>(sql`select head from ${SYNC_STATUS_TABLE}`)[0]?.head ??
108
+ EventId.ROOT.global
109
+
110
+ // TODO use prepared statements
111
+ export const updateBackendHead = (dbEventlog: SqliteDb, head: EventId.EventId) =>
112
+ dbEventlog.execute(sql`UPDATE ${SYNC_STATUS_TABLE} SET head = ${head.global}`)
113
+
114
+ export const insertIntoEventlog = (
115
+ eventEncoded: LiveStoreEvent.EncodedWithMeta,
116
+ dbEventlog: SqliteDb,
117
+ eventDefSchemaHash: number,
118
+ clientId: string,
119
+ sessionId: string,
120
+ ) =>
121
+ Effect.gen(function* () {
122
+ // Check history consistency during LS_DEV
123
+ if (LS_DEV && eventEncoded.parentId.global !== EventId.ROOT.global) {
124
+ const parentEventExists =
125
+ dbEventlog.select<{ count: number }>(
126
+ `SELECT COUNT(*) as count FROM ${EVENTLOG_META_TABLE} WHERE idGlobal = ? AND idClient = ?`,
127
+ [eventEncoded.parentId.global, eventEncoded.parentId.client] as any as PreparedBindValues,
128
+ )[0]!.count === 1
129
+
130
+ if (parentEventExists === false) {
131
+ shouldNeverHappen(
132
+ `Parent mutation ${eventEncoded.parentId.global},${eventEncoded.parentId.client} does not exist`,
133
+ )
134
+ }
135
+ }
136
+
137
+ // TODO use prepared statements
138
+ yield* execSql(
139
+ dbEventlog,
140
+ ...insertRow({
141
+ tableName: EVENTLOG_META_TABLE,
142
+ columns: eventlogMetaTable.sqliteDef.columns,
143
+ values: {
144
+ idGlobal: eventEncoded.id.global,
145
+ idClient: eventEncoded.id.client,
146
+ parentIdGlobal: eventEncoded.parentId.global,
147
+ parentIdClient: eventEncoded.parentId.client,
148
+ name: eventEncoded.name,
149
+ argsJson: eventEncoded.args ?? {},
150
+ clientId,
151
+ sessionId,
152
+ schemaHash: eventDefSchemaHash,
153
+ syncMetadataJson: eventEncoded.meta.syncMetadata,
154
+ },
155
+ }),
156
+ )
157
+ })
158
+
159
+ export const updateSyncMetadata = (items: ReadonlyArray<LiveStoreEvent.EncodedWithMeta>) =>
160
+ Effect.gen(function* () {
161
+ const { dbEventlog } = yield* LeaderThreadCtx
162
+
163
+ // TODO try to do this in a single query
164
+ for (let i = 0; i < items.length; i++) {
165
+ const event = items[i]!
166
+
167
+ yield* execSql(
168
+ dbEventlog,
169
+ ...updateRows({
170
+ tableName: EVENTLOG_META_TABLE,
171
+ columns: eventlogMetaTable.sqliteDef.columns,
172
+ where: { idGlobal: event.id.global, idClient: event.id.client },
173
+ updateValues: { syncMetadataJson: event.meta.syncMetadata },
174
+ }),
175
+ )
176
+ }
177
+ })
178
+
179
+ export const getSyncBackendCursorInfo = (remoteHead: EventId.GlobalEventId) =>
180
+ Effect.gen(function* () {
181
+ const { dbEventlog } = yield* LeaderThreadCtx
182
+
183
+ if (remoteHead === EventId.ROOT.global) return Option.none()
184
+
185
+ const EventlogQuerySchema = Schema.Struct({
186
+ syncMetadataJson: Schema.parseJson(Schema.Option(Schema.JsonValue)),
187
+ }).pipe(Schema.pluck('syncMetadataJson'), Schema.Array, Schema.head)
188
+
189
+ const syncMetadataOption = yield* Effect.sync(() =>
190
+ dbEventlog.select<{ syncMetadataJson: string }>(
191
+ sql`SELECT syncMetadataJson FROM ${EVENTLOG_META_TABLE} WHERE idGlobal = ${remoteHead} ORDER BY idClient ASC LIMIT 1`,
192
+ ),
193
+ ).pipe(Effect.andThen(Schema.decode(EventlogQuerySchema)), Effect.map(Option.flatten), Effect.orDie)
194
+
195
+ return Option.some({
196
+ cursor: { global: remoteHead, client: EventId.clientDefault },
197
+ metadata: syncMetadataOption,
198
+ }) satisfies InitialSyncInfo
199
+ }).pipe(Effect.withSpan('@livestore/common:eventlog:getSyncBackendCursorInfo', { attributes: { remoteHead } }))
@@ -2,7 +2,7 @@ import { Effect, FiberMap, Option, Stream, SubscriptionRef } from '@livestore/ut
2
2
  import { nanoid } from '@livestore/utils/nanoid'
3
3
 
4
4
  import { Devtools, IntentionalShutdownCause, liveStoreVersion, UnexpectedError } from '../index.js'
5
- import { MUTATION_LOG_META_TABLE, SCHEMA_META_TABLE, SCHEMA_MUTATIONS_META_TABLE } from '../schema/mod.js'
5
+ import { EVENTLOG_META_TABLE, SCHEMA_EVENT_DEFS_META_TABLE, SCHEMA_META_TABLE } from '../schema/mod.js'
6
6
  import type { DevtoolsOptions, PersistenceInfoPair } from './types.js'
7
7
  import { LeaderThreadCtx } from './types.js'
8
8
 
@@ -63,7 +63,7 @@ const listenToDevtools = ({
63
63
  syncBackend,
64
64
  makeSqliteDb,
65
65
  dbReadModel,
66
- dbMutationLog,
66
+ dbEventlog,
67
67
  shutdownStateSubRef,
68
68
  shutdownChannel,
69
69
  syncProcessor,
@@ -143,20 +143,20 @@ const listenToDevtools = ({
143
143
  }
144
144
 
145
145
  try {
146
- if (tableNames.has(MUTATION_LOG_META_TABLE)) {
147
- // Is mutation log
146
+ if (tableNames.has(EVENTLOG_META_TABLE)) {
147
+ // Is eventlog
148
148
  yield* SubscriptionRef.set(shutdownStateSubRef, 'shutting-down')
149
149
 
150
- dbMutationLog.import(data)
150
+ dbEventlog.import(data)
151
151
 
152
152
  dbReadModel.destroy()
153
- } else if (tableNames.has(SCHEMA_META_TABLE) && tableNames.has(SCHEMA_MUTATIONS_META_TABLE)) {
153
+ } else if (tableNames.has(SCHEMA_META_TABLE) && tableNames.has(SCHEMA_EVENT_DEFS_META_TABLE)) {
154
154
  // Is read model
155
155
  yield* SubscriptionRef.set(shutdownStateSubRef, 'shutting-down')
156
156
 
157
157
  dbReadModel.import(data)
158
158
 
159
- dbMutationLog.destroy()
159
+ dbEventlog.destroy()
160
160
  } else {
161
161
  yield* sendMessage(
162
162
  Devtools.Leader.LoadDatabaseFile.Error.make({
@@ -190,7 +190,7 @@ const listenToDevtools = ({
190
190
  dbReadModel.destroy()
191
191
 
192
192
  if (mode === 'all-data') {
193
- dbMutationLog.destroy()
193
+ dbEventlog.destroy()
194
194
  }
195
195
 
196
196
  yield* sendMessage(Devtools.Leader.ResetAllData.Success.make({ ...reqPayload }))
@@ -207,33 +207,33 @@ const listenToDevtools = ({
207
207
 
208
208
  const dbSizeQuery = `SELECT page_count * page_size as size FROM pragma_page_count(), pragma_page_size();`
209
209
  const dbFileSize = dbReadModel.select<{ size: number }>(dbSizeQuery, undefined)[0]!.size
210
- const mutationLogFileSize = dbMutationLog.select<{ size: number }>(dbSizeQuery, undefined)[0]!.size
210
+ const eventlogFileSize = dbEventlog.select<{ size: number }>(dbSizeQuery, undefined)[0]!.size
211
211
 
212
212
  yield* sendMessage(
213
213
  Devtools.Leader.DatabaseFileInfoRes.make({
214
214
  readModel: { fileSize: dbFileSize, persistenceInfo: persistenceInfo.readModel },
215
- mutationLog: { fileSize: mutationLogFileSize, persistenceInfo: persistenceInfo.mutationLog },
215
+ eventlog: { fileSize: eventlogFileSize, persistenceInfo: persistenceInfo.eventlog },
216
216
  ...reqPayload,
217
217
  }),
218
218
  )
219
219
 
220
220
  return
221
221
  }
222
- case 'LSD.Leader.MutationLogReq': {
223
- const mutationLog = dbMutationLog.export()
222
+ case 'LSD.Leader.EventlogReq': {
223
+ const eventlog = dbEventlog.export()
224
224
 
225
- yield* sendMessage(Devtools.Leader.MutationLogRes.make({ mutationLog, ...reqPayload }))
225
+ yield* sendMessage(Devtools.Leader.EventlogRes.make({ eventlog, ...reqPayload }))
226
226
 
227
227
  return
228
228
  }
229
- case 'LSD.Leader.RunMutationReq': {
229
+ case 'LSD.Leader.CommitEventReq': {
230
230
  yield* syncProcessor.pushPartial({
231
- mutationEvent: decodedEvent.mutationEventEncoded,
231
+ event: decodedEvent.eventEncoded,
232
232
  clientId: `devtools-${clientId}`,
233
233
  sessionId: `devtools-${clientId}`,
234
234
  })
235
235
 
236
- yield* sendMessage(Devtools.Leader.RunMutationRes.make({ ...reqPayload }))
236
+ yield* sendMessage(Devtools.Leader.CommitEventRes.make({ ...reqPayload }))
237
237
 
238
238
  return
239
239
  }
@@ -245,10 +245,10 @@ const listenToDevtools = ({
245
245
  yield* syncBackend.pull(Option.none()).pipe(
246
246
  Stream.map((_) => _.batch),
247
247
  Stream.flattenIterables,
248
- Stream.tap(({ mutationEventEncoded, metadata }) =>
248
+ Stream.tap(({ eventEncoded, metadata }) =>
249
249
  sendMessage(
250
250
  Devtools.Leader.SyncHistoryRes.make({
251
- mutationEventEncoded,
251
+ eventEncoded,
252
252
  metadata,
253
253
  subscriptionId,
254
254
  ...reqPayload,
@@ -5,13 +5,13 @@ import type { BootStatus, MakeSqliteDb, MigrationsReport, SqliteError } from '..
5
5
  import { UnexpectedError } from '../adapter-types.js'
6
6
  import type * as Devtools from '../devtools/mod.js'
7
7
  import type { LiveStoreSchema } from '../schema/mod.js'
8
- import { MutationEvent } from '../schema/mod.js'
8
+ import { LiveStoreEvent } from '../schema/mod.js'
9
9
  import type { InvalidPullError, IsOfflineError, SyncOptions } from '../sync/sync.js'
10
10
  import { sql } from '../util.js'
11
- import { makeApplyMutation } from './apply-mutation.js'
11
+ import { makeApplyEvent } from './apply-event.js'
12
+ import * as Eventlog from './eventlog.js'
12
13
  import { bootDevtools } from './leader-worker-devtools.js'
13
14
  import { makeLeaderSyncProcessor } from './LeaderSyncProcessor.js'
14
- import * as Mutationlog from './mutationlog.js'
15
15
  import { recreateDb } from './recreate-db.js'
16
16
  import type { ShutdownChannel } from './shutdown-channel.js'
17
17
  import type {
@@ -31,7 +31,7 @@ export interface MakeLeaderThreadLayerParams {
31
31
  makeSqliteDb: MakeSqliteDb
32
32
  syncOptions: SyncOptions | undefined
33
33
  dbReadModel: LeaderSqliteDb
34
- dbMutationLog: LeaderSqliteDb
34
+ dbEventlog: LeaderSqliteDb
35
35
  devtoolsOptions: DevtoolsOptions
36
36
  shutdownChannel: ShutdownChannel
37
37
  params?: {
@@ -55,7 +55,7 @@ export const makeLeaderThreadLayer = ({
55
55
  makeSqliteDb,
56
56
  syncOptions,
57
57
  dbReadModel,
58
- dbMutationLog,
58
+ dbEventlog,
59
59
  devtoolsOptions,
60
60
  shutdownChannel,
61
61
  params,
@@ -66,8 +66,8 @@ export const makeLeaderThreadLayer = ({
66
66
 
67
67
  // TODO do more validation here than just checking the count of tables
68
68
  // Either happens on initial boot or if schema changes
69
- const dbMutationLogMissing =
70
- dbMutationLog.select<{ count: number }>(sql`select count(*) as count from sqlite_master`)[0]!.count === 0
69
+ const dbEventlogMissing =
70
+ dbEventlog.select<{ count: number }>(sql`select count(*) as count from sqlite_master`)[0]!.count === 0
71
71
 
72
72
  const dbReadModelMissing =
73
73
  dbReadModel.select<{ count: number }>(sql`select count(*) as count from sqlite_master`)[0]!.count === 0
@@ -89,8 +89,8 @@ export const makeLeaderThreadLayer = ({
89
89
 
90
90
  const syncProcessor = yield* makeLeaderSyncProcessor({
91
91
  schema,
92
- dbMutationLogMissing,
93
- dbMutationLog,
92
+ dbEventlogMissing,
93
+ dbEventlog,
94
94
  dbReadModel,
95
95
  dbReadModelMissing,
96
96
  initialBlockingSyncContext,
@@ -116,7 +116,7 @@ export const makeLeaderThreadLayer = ({
116
116
  }
117
117
  : { enabled: false as const }
118
118
 
119
- const applyMutation = yield* makeApplyMutation({ schema, dbReadModel, dbMutationLog })
119
+ const applyEvent = yield* makeApplyEvent({ schema, dbReadModel, dbEventlog })
120
120
 
121
121
  const ctx = {
122
122
  schema,
@@ -124,14 +124,14 @@ export const makeLeaderThreadLayer = ({
124
124
  storeId,
125
125
  clientId,
126
126
  dbReadModel,
127
- dbMutationLog,
127
+ dbEventlog,
128
128
  makeSqliteDb,
129
- mutationEventSchema: MutationEvent.makeMutationEventSchema(schema),
129
+ eventSchema: LiveStoreEvent.makeEventDefSchema(schema),
130
130
  shutdownStateSubRef: yield* SubscriptionRef.make<ShutdownState>('running'),
131
131
  shutdownChannel,
132
132
  syncBackend,
133
133
  syncProcessor,
134
- applyMutation,
134
+ applyEvent,
135
135
  extraIncomingMessagesQueue,
136
136
  devtools: devtoolsContext,
137
137
  // State will be set during `bootLeaderThread`
@@ -168,7 +168,7 @@ const makeInitialBlockingSyncContext = ({
168
168
  Effect.gen(function* () {
169
169
  const ctx = {
170
170
  isDone: false,
171
- processedMutations: 0,
171
+ processedEvents: 0,
172
172
  total: -1,
173
173
  }
174
174
 
@@ -191,10 +191,10 @@ const makeInitialBlockingSyncContext = ({
191
191
  ctx.total = remaining + processed
192
192
  }
193
193
 
194
- ctx.processedMutations += processed
194
+ ctx.processedEvents += processed
195
195
  yield* Queue.offer(bootStatusQueue, {
196
196
  stage: 'syncing',
197
- progress: { done: ctx.processedMutations, total: ctx.total },
197
+ progress: { done: ctx.processedEvents, total: ctx.total },
198
198
  })
199
199
 
200
200
  if (remaining === 0 && blockingDeferred !== undefined) {
@@ -223,9 +223,9 @@ const bootLeaderThread = ({
223
223
  LeaderThreadCtx | Scope.Scope | HttpClient.HttpClient
224
224
  > =>
225
225
  Effect.gen(function* () {
226
- const { dbMutationLog, bootStatusQueue, syncProcessor } = yield* LeaderThreadCtx
226
+ const { dbEventlog, bootStatusQueue, syncProcessor } = yield* LeaderThreadCtx
227
227
 
228
- yield* Mutationlog.initMutationLogDb(dbMutationLog)
228
+ yield* Eventlog.initEventlogDb(dbEventlog)
229
229
 
230
230
  let migrationsReport: MigrationsReport
231
231
  if (dbReadModelMissing) {
@@ -3,4 +3,4 @@ export * from './types.js'
3
3
  export * as ShutdownChannel from './shutdown-channel.js'
4
4
  export * from './leader-worker-devtools.js'
5
5
  export * from './make-leader-thread-layer.js'
6
- export * as Mutationlog from './mutationlog.js'
6
+ export * as Eventlog from './eventlog.js'
@@ -3,7 +3,7 @@ import type { HttpClient } from '@livestore/utils/effect'
3
3
  import { Effect, Queue } from '@livestore/utils/effect'
4
4
 
5
5
  import type { InvalidPullError, IsOfflineError, MigrationHooks, MigrationsReport, SqliteError } from '../index.js'
6
- import { initializeSingletonTables, migrateDb, rehydrateFromMutationLog, UnexpectedError } from '../index.js'
6
+ import { migrateDb, rehydrateFromEventlog, UnexpectedError } from '../index.js'
7
7
  import { configureConnection } from './connection.js'
8
8
  import { LeaderThreadCtx } from './types.js'
9
9
 
@@ -12,7 +12,7 @@ export const recreateDb: Effect.Effect<
12
12
  UnexpectedError | SqliteError | IsOfflineError | InvalidPullError,
13
13
  LeaderThreadCtx | HttpClient.HttpClient
14
14
  > = Effect.gen(function* () {
15
- const { dbReadModel, dbMutationLog, schema, bootStatusQueue, applyMutation } = yield* LeaderThreadCtx
15
+ const { dbReadModel, dbEventlog, schema, bootStatusQueue, applyEvent } = yield* LeaderThreadCtx
16
16
 
17
17
  const migrationOptions = schema.migrationOptions
18
18
  let migrationsReport: MigrationsReport
@@ -41,26 +41,23 @@ export const recreateDb: Effect.Effect<
41
41
  Queue.offer(bootStatusQueue, { stage: 'migrating', progress: { done, total } }),
42
42
  })
43
43
 
44
- initializeSingletonTables(schema, tmpDb)
45
-
46
44
  yield* Effect.tryAll(() => hooks?.pre?.(tmpDb)).pipe(UnexpectedError.mapToUnexpectedError)
47
45
 
48
46
  return { migrationsReport, tmpDb }
49
47
  })
50
48
 
51
49
  switch (migrationOptions.strategy) {
52
- case 'from-mutation-log': {
50
+ case 'from-eventlog': {
53
51
  const hooks = migrationOptions.hooks
54
52
  const initResult = yield* initDb(hooks)
55
53
 
56
54
  migrationsReport = initResult.migrationsReport
57
55
 
58
- yield* rehydrateFromMutationLog({
56
+ yield* rehydrateFromEventlog({
59
57
  // db: initResult.tmpDb,
60
- dbMutationLog,
58
+ dbEventlog,
61
59
  schema,
62
- migrationOptions,
63
- applyMutation,
60
+ applyEvent,
64
61
  onProgress: ({ done, total }) =>
65
62
  Queue.offer(bootStatusQueue, { stage: 'rehydrating', progress: { done, total } }),
66
63
  })
@@ -24,7 +24,7 @@ import type {
24
24
  SyncBackend,
25
25
  UnexpectedError,
26
26
  } from '../index.js'
27
- import type { EventId, LiveStoreSchema, MutationEvent } from '../schema/mod.js'
27
+ import type { EventId, LiveStoreEvent, LiveStoreSchema } from '../schema/mod.js'
28
28
  import type * as SyncState from '../sync/syncstate.js'
29
29
  import type { ShutdownChannel } from './shutdown-channel.js'
30
30
 
@@ -52,7 +52,7 @@ export type InitialSyncInfo = Option.Option<{
52
52
  // | { _tag: 'Reuse'; syncInfo: InitialSyncInfo }
53
53
 
54
54
  export type LeaderSqliteDb = SqliteDb<{ dbPointer: number; persistenceInfo: PersistenceInfo }>
55
- export type PersistenceInfoPair = { readModel: PersistenceInfo; mutationLog: PersistenceInfo }
55
+ export type PersistenceInfoPair = { readModel: PersistenceInfo; eventlog: PersistenceInfo }
56
56
 
57
57
  export type DevtoolsOptions =
58
58
  | {
@@ -90,16 +90,16 @@ export class LeaderThreadCtx extends Context.Tag('LeaderThreadCtx')<
90
90
  clientId: string
91
91
  makeSqliteDb: MakeSqliteDb
92
92
  dbReadModel: LeaderSqliteDb
93
- dbMutationLog: LeaderSqliteDb
93
+ dbEventlog: LeaderSqliteDb
94
94
  bootStatusQueue: Queue.Queue<BootStatus>
95
95
  // TODO we should find a more elegant way to handle cases which need this ref for their implementation
96
96
  shutdownStateSubRef: SubscriptionRef.SubscriptionRef<ShutdownState>
97
97
  shutdownChannel: ShutdownChannel
98
- mutationEventSchema: MutationEvent.ForMutationDefRecord<any>
98
+ eventSchema: LiveStoreEvent.ForEventDefRecord<any>
99
99
  devtools: DevtoolsContext
100
100
  syncBackend: SyncBackend | undefined
101
101
  syncProcessor: LeaderSyncProcessor
102
- applyMutation: ApplyMutation
102
+ applyEvent: ApplyEvent
103
103
  initialState: {
104
104
  leaderHead: EventId.EventId
105
105
  migrationsReport: MigrationsReport
@@ -113,11 +113,11 @@ export class LeaderThreadCtx extends Context.Tag('LeaderThreadCtx')<
113
113
  }
114
114
  >() {}
115
115
 
116
- export type ApplyMutation = (
117
- mutationEventEncoded: MutationEvent.EncodedWithMeta,
116
+ export type ApplyEvent = (
117
+ eventEncoded: LiveStoreEvent.EncodedWithMeta,
118
118
  options?: {
119
- /** Needed for rehydrateFromMutationLog */
120
- skipMutationLog?: boolean
119
+ /** Needed for rehydrateFromEventlog */
120
+ skipEventlog?: boolean
121
121
  },
122
122
  ) => Effect.Effect<
123
123
  { sessionChangeset: { _tag: 'sessionChangeset'; data: Uint8Array; debug: any } | { _tag: 'no-op' } },
@@ -143,10 +143,10 @@ export interface LeaderSyncProcessor {
143
143
  Scope.Scope
144
144
  >
145
145
 
146
- /** Used by client sessions to push mutations to the leader thread */
146
+ /** Used by client sessions to push events to the leader thread */
147
147
  push: (
148
148
  /** `batch` needs to follow the same rules as `batch` in `SyncBackend.push` */
149
- batch: ReadonlyArray<MutationEvent.EncodedWithMeta>,
149
+ batch: ReadonlyArray<LiveStoreEvent.EncodedWithMeta>,
150
150
  options?: {
151
151
  /**
152
152
  * If true, the effect will only finish when the local push has been processed (i.e. succeeded or was rejected).
@@ -158,7 +158,7 @@ export interface LeaderSyncProcessor {
158
158
 
159
159
  /** Currently only used by devtools which don't provide their own event numbers */
160
160
  pushPartial: (args: {
161
- mutationEvent: MutationEvent.PartialAnyEncoded
161
+ event: LiveStoreEvent.PartialAnyEncoded
162
162
  clientId: string
163
163
  sessionId: string
164
164
  }) => Effect.Effect<void, UnexpectedError>
@@ -0,0 +1,110 @@
1
+ import { isReadonlyArray } from '@livestore/utils'
2
+ import { Schema } from '@livestore/utils/effect'
3
+
4
+ import { SessionIdSymbol } from './adapter-types.js'
5
+ import { isQueryBuilder } from './query-builder/api.js'
6
+ import type { EventDef, Materializer, MaterializerResult } from './schema/EventDef.js'
7
+ import type * as LiveStoreEvent from './schema/LiveStoreEvent.js'
8
+ import type { BindValues } from './sql-queries/sql-queries.js'
9
+ import type { PreparedBindValues } from './util.js'
10
+ import { prepareBindValues } from './util.js'
11
+
12
+ export const getExecArgsFromEvent = ({
13
+ eventDef: { eventDef, materializer },
14
+ event,
15
+ }: {
16
+ eventDef: {
17
+ eventDef: EventDef.AnyWithoutFn
18
+ materializer: Materializer
19
+ }
20
+ /** Both encoded and decoded events are supported to reduce the number of times we need to decode/encode */
21
+ event:
22
+ | {
23
+ decoded: LiveStoreEvent.AnyDecoded | LiveStoreEvent.PartialAnyDecoded
24
+ encoded: undefined
25
+ }
26
+ | {
27
+ decoded: undefined
28
+ encoded: LiveStoreEvent.AnyEncoded | LiveStoreEvent.PartialAnyEncoded
29
+ }
30
+ }): ReadonlyArray<{
31
+ statementSql: string
32
+ bindValues: PreparedBindValues
33
+ writeTables: ReadonlySet<string> | undefined
34
+ }> => {
35
+ const eventArgsDecoded = event.decoded?.args ?? Schema.decodeUnknownSync(eventDef.schema)(event.encoded!.args)
36
+
37
+ const res = materializer(eventArgsDecoded, {
38
+ clientOnly: eventDef.options.clientOnly,
39
+ // TODO properly implement this
40
+ currentFacts: new Map(),
41
+ })
42
+
43
+ const statementRes = mapMaterializerResult(res)
44
+
45
+ return statementRes.map((statementRes) => {
46
+ const statementSql = statementRes.sql
47
+
48
+ const eventArgsEncoded = event.encoded?.args ?? Schema.encodeUnknownSync(eventDef.schema)(event.decoded!.args)
49
+ const bindValues = typeof statementRes === 'string' ? eventArgsEncoded : statementRes.bindValues
50
+
51
+ const writeTables = typeof statementRes === 'string' ? undefined : statementRes.writeTables
52
+
53
+ return { statementSql, bindValues: prepareBindValues(bindValues ?? {}, statementSql), writeTables }
54
+ })
55
+ }
56
+
57
+ const mapMaterializerResult = (
58
+ materializerResult: MaterializerResult | ReadonlyArray<MaterializerResult>,
59
+ ): ReadonlyArray<{
60
+ sql: string
61
+ bindValues: BindValues
62
+ writeTables: ReadonlySet<string> | undefined
63
+ }> => {
64
+ if (isReadonlyArray(materializerResult)) {
65
+ return materializerResult.flatMap(mapMaterializerResult)
66
+ }
67
+ if (isQueryBuilder(materializerResult)) {
68
+ const { query, bindValues } = materializerResult.asSql()
69
+ return [{ sql: query, bindValues: bindValues as BindValues, writeTables: undefined }]
70
+ } else if (typeof materializerResult === 'string') {
71
+ return [{ sql: materializerResult, bindValues: {} as BindValues, writeTables: undefined }]
72
+ } else {
73
+ return [
74
+ {
75
+ sql: materializerResult.sql,
76
+ bindValues: materializerResult.bindValues,
77
+ writeTables: materializerResult.writeTables,
78
+ },
79
+ ]
80
+ }
81
+ }
82
+
83
+ // NOTE we should explore whether there is a more elegant solution
84
+ // e.g. by leveraging the schema to replace the sessionIdSymbol
85
+ export const replaceSessionIdSymbol = (
86
+ bindValues: Record<string, unknown> | ReadonlyArray<unknown>,
87
+ sessionId: string,
88
+ ) => {
89
+ deepReplaceValue(bindValues, SessionIdSymbol, sessionId)
90
+ }
91
+
92
+ const deepReplaceValue = <S, R>(input: any, searchValue: S, replaceValue: R): void => {
93
+ if (Array.isArray(input)) {
94
+ for (const i in input) {
95
+ if (input[i] === searchValue) {
96
+ input[i] = replaceValue
97
+ } else {
98
+ deepReplaceValue(input[i], searchValue, replaceValue)
99
+ }
100
+ }
101
+ } else if (typeof input === 'object' && input !== null) {
102
+ for (const key in input) {
103
+ if (input[key] === searchValue) {
104
+ input[key] = replaceValue
105
+ } else {
106
+ deepReplaceValue(input[key], searchValue, replaceValue)
107
+ }
108
+ }
109
+ }
110
+ }