@livestore/common 0.3.0-dev.27 → 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 +25 -12
  26. package/dist/leader-thread/LeaderSyncProcessor.d.ts.map +1 -1
  27. package/dist/leader-thread/LeaderSyncProcessor.js +125 -89
  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 +16 -4
  40. package/dist/leader-thread/make-leader-thread-layer.d.ts.map +1 -1
  41. package/dist/leader-thread/make-leader-thread-layer.js +23 -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 +8 -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} +25 -25
  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 +31 -25
  168. package/dist/sync/syncstate.js.map +1 -1
  169. package/dist/sync/syncstate.test.js +165 -175
  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 +183 -122
  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 +51 -29
  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 +11 -3
  198. package/src/schema/{MutationEvent.ts → LiveStoreEvent.ts} +68 -69
  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 +168 -179
  223. package/src/sync/syncstate.ts +48 -38
  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,68 +1,66 @@
1
- import { LS_DEV, memoizeByRef, shouldNeverHappen } from '@livestore/utils'
1
+ import { LS_DEV, shouldNeverHappen } from '@livestore/utils'
2
2
  import { Effect, ReadonlyArray, Schema } from '@livestore/utils/effect'
3
3
 
4
4
  import type { SqliteDb } from '../adapter-types.js'
5
- import { getExecArgsFromMutation } from '../mutation.js'
6
- import type { LiveStoreSchema, MutationEvent, SessionChangesetMetaRow } from '../schema/mod.js'
5
+ import { getExecArgsFromEvent } from '../materializer-helper.js'
6
+ import type { LiveStoreSchema, SessionChangesetMetaRow } from '../schema/mod.js'
7
7
  import {
8
8
  EventId,
9
- getMutationDef,
10
- MUTATION_LOG_META_TABLE,
9
+ EVENTLOG_META_TABLE,
10
+ getEventDef,
11
11
  SESSION_CHANGESET_META_TABLE,
12
12
  sessionChangesetMetaTable,
13
13
  } from '../schema/mod.js'
14
14
  import { insertRow } from '../sql-queries/index.js'
15
15
  import { sql } from '../util.js'
16
16
  import { execSql, execSqlPrepared } from './connection.js'
17
- import * as Mutationlog from './mutationlog.js'
18
- import type { ApplyMutation } from './types.js'
17
+ import * as Eventlog from './eventlog.js'
18
+ import type { ApplyEvent } from './types.js'
19
19
 
20
- export const makeApplyMutation = ({
20
+ export const makeApplyEvent = ({
21
21
  schema,
22
22
  dbReadModel: db,
23
- dbMutationLog,
23
+ dbEventlog,
24
24
  }: {
25
25
  schema: LiveStoreSchema
26
26
  dbReadModel: SqliteDb
27
- dbMutationLog: SqliteDb
28
- }): Effect.Effect<ApplyMutation, never> =>
27
+ dbEventlog: SqliteDb
28
+ }): Effect.Effect<ApplyEvent, never> =>
29
29
  Effect.gen(function* () {
30
- const shouldExcludeMutationFromLog = makeShouldExcludeMutationFromLog(schema)
31
-
32
- const mutationDefSchemaHashMap = new Map(
30
+ const eventDefSchemaHashMap = new Map(
33
31
  // TODO Running `Schema.hash` can be a bottleneck for larger schemas. There is an opportunity to run this
34
32
  // at build time and lookup the pre-computed hash at runtime.
35
33
  // Also see https://github.com/Effect-TS/effect/issues/2719
36
- [...schema.mutations.map.entries()].map(([k, v]) => [k, Schema.hash(v.schema)] as const),
34
+ [...schema.eventsDefsMap.entries()].map(([k, v]) => [k, Schema.hash(v.schema)] as const),
37
35
  )
38
36
 
39
- return (mutationEventEncoded, options) =>
37
+ return (eventEncoded, options) =>
40
38
  Effect.gen(function* () {
41
- const skipMutationLog = options?.skipMutationLog ?? false
39
+ const skipEventlog = options?.skipEventlog ?? false
42
40
 
43
- const mutationName = mutationEventEncoded.mutation
44
- const mutationDef = getMutationDef(schema, mutationName)
41
+ const eventName = eventEncoded.name
42
+ const eventDef = getEventDef(schema, eventName)
45
43
 
46
- const execArgsArr = getExecArgsFromMutation({
47
- mutationDef,
48
- mutationEvent: { decoded: undefined, encoded: mutationEventEncoded },
44
+ const execArgsArr = getExecArgsFromEvent({
45
+ eventDef,
46
+ event: { decoded: undefined, encoded: eventEncoded },
49
47
  })
50
48
 
51
- // NOTE we might want to bring this back if we want to debug no-op mutations
49
+ // NOTE we might want to bring this back if we want to debug no-op events
52
50
  // const makeExecuteOptions = (statementSql: string, bindValues: any) => ({
53
51
  // onRowsChanged: (rowsChanged: number) => {
54
52
  // if (rowsChanged === 0) {
55
- // console.warn(`Mutation "${mutationDef.name}" did not affect any rows:`, statementSql, bindValues)
53
+ // console.warn(`Event "${eventDef.name}" did not affect any rows:`, statementSql, bindValues)
56
54
  // }
57
55
  // },
58
56
  // })
59
57
 
60
- // console.group('[@livestore/common:leader-thread:applyMutation]', { mutationName })
58
+ // console.group('[@livestore/common:leader-thread:applyEvent]', { eventName })
61
59
 
62
60
  const session = db.session()
63
61
 
64
62
  for (const { statementSql, bindValues } of execArgsArr) {
65
- // console.debug(mutationName, statementSql, bindValues)
63
+ // console.debug(eventName, statementSql, bindValues)
66
64
  // TODO use cached prepared statements instead of exec
67
65
  yield* execSqlPrepared(db, statementSql, bindValues)
68
66
  }
@@ -77,9 +75,9 @@ export const makeApplyMutation = ({
77
75
  tableName: SESSION_CHANGESET_META_TABLE,
78
76
  columns: sessionChangesetMetaTable.sqliteDef.columns,
79
77
  values: {
80
- idGlobal: mutationEventEncoded.id.global,
81
- idClient: mutationEventEncoded.id.client,
82
- // NOTE the changeset will be empty (i.e. null) for no-op mutations
78
+ idGlobal: eventEncoded.id.global,
79
+ idClient: eventEncoded.id.client,
80
+ // NOTE the changeset will be empty (i.e. null) for no-op events
83
81
  changeset: changeset ?? null,
84
82
  debug: LS_DEV ? execArgsArr : null,
85
83
  },
@@ -88,22 +86,21 @@ export const makeApplyMutation = ({
88
86
 
89
87
  // console.groupEnd()
90
88
 
91
- // write to mutation_log
92
- const excludeFromMutationLog = shouldExcludeMutationFromLog(mutationName, mutationEventEncoded)
93
- if (skipMutationLog === false && excludeFromMutationLog === false) {
94
- const mutationName = mutationEventEncoded.mutation
95
- const mutationDefSchemaHash =
96
- mutationDefSchemaHashMap.get(mutationName) ?? shouldNeverHappen(`Unknown mutation: ${mutationName}`)
97
-
98
- yield* Mutationlog.insertIntoMutationLog(
99
- mutationEventEncoded,
100
- dbMutationLog,
101
- mutationDefSchemaHash,
102
- mutationEventEncoded.clientId,
103
- mutationEventEncoded.sessionId,
89
+ // write to eventlog
90
+ if (skipEventlog === false) {
91
+ const eventName = eventEncoded.name
92
+ const eventDefSchemaHash =
93
+ eventDefSchemaHashMap.get(eventName) ?? shouldNeverHappen(`Unknown event definition: ${eventName}`)
94
+
95
+ yield* Eventlog.insertIntoEventlog(
96
+ eventEncoded,
97
+ dbEventlog,
98
+ eventDefSchemaHash,
99
+ eventEncoded.clientId,
100
+ eventEncoded.sessionId,
104
101
  )
105
102
  } else {
106
- // console.debug('[@livestore/common:leader-thread] skipping mutation log write', mutation, statementSql, bindValues)
103
+ // console.debug('[@livestore/common:leader-thread] skipping eventlog write', mutation, statementSql, bindValues)
107
104
  }
108
105
 
109
106
  return {
@@ -116,24 +113,24 @@ export const makeApplyMutation = ({
116
113
  : { _tag: 'no-op' as const },
117
114
  }
118
115
  }).pipe(
119
- Effect.withSpan(`@livestore/common:leader-thread:applyMutation`, {
116
+ Effect.withSpan(`@livestore/common:leader-thread:applyEvent`, {
120
117
  attributes: {
121
- mutationName: mutationEventEncoded.mutation,
122
- mutationId: mutationEventEncoded.id,
123
- 'span.label': `${EventId.toString(mutationEventEncoded.id)} ${mutationEventEncoded.mutation}`,
118
+ eventName: eventEncoded.name,
119
+ mutationId: eventEncoded.id,
120
+ 'span.label': `${EventId.toString(eventEncoded.id)} ${eventEncoded.name}`,
124
121
  },
125
122
  }),
126
- // Effect.logDuration('@livestore/common:leader-thread:applyMutation'),
123
+ // Effect.logDuration('@livestore/common:leader-thread:applyEvent'),
127
124
  )
128
125
  })
129
126
 
130
127
  export const rollback = ({
131
128
  db,
132
- dbMutationLog,
129
+ dbEventlog,
133
130
  eventIdsToRollback,
134
131
  }: {
135
132
  db: SqliteDb
136
- dbMutationLog: SqliteDb
133
+ dbEventlog: SqliteDb
137
134
  eventIdsToRollback: EventId.EventId[]
138
135
  }) =>
139
136
  Effect.gen(function* () {
@@ -163,10 +160,10 @@ export const rollback = ({
163
160
  )
164
161
  }
165
162
 
166
- // Delete the mutation log rows
163
+ // Delete the eventlog rows
167
164
  for (const eventIdPairChunk of eventIdPairChunks) {
168
- dbMutationLog.execute(
169
- sql`DELETE FROM ${MUTATION_LOG_META_TABLE} WHERE (idGlobal, idClient) IN (${eventIdPairChunk.join(', ')})`,
165
+ dbEventlog.execute(
166
+ sql`DELETE FROM ${EVENTLOG_META_TABLE} WHERE (idGlobal, idClient) IN (${eventIdPairChunk.join(', ')})`,
170
167
  )
171
168
  }
172
169
  }).pipe(
@@ -174,24 +171,3 @@ export const rollback = ({
174
171
  attributes: { count: eventIdsToRollback.length },
175
172
  }),
176
173
  )
177
-
178
- // TODO let's consider removing this "should exclude" mechanism in favour of log compaction etc
179
- const makeShouldExcludeMutationFromLog = memoizeByRef((schema: LiveStoreSchema) => {
180
- const migrationOptions = schema.migrationOptions
181
- const mutationLogExclude =
182
- migrationOptions.strategy === 'from-mutation-log'
183
- ? (migrationOptions.excludeMutations ?? new Set(['livestore.RawSql']))
184
- : new Set(['livestore.RawSql'])
185
-
186
- return (mutationName: string, mutationEventEncoded: MutationEvent.AnyEncoded): boolean => {
187
- if (mutationLogExclude.has(mutationName)) return true
188
-
189
- const mutationDef = getMutationDef(schema, mutationName)
190
- const execArgsArr = getExecArgsFromMutation({
191
- mutationDef,
192
- mutationEvent: { decoded: undefined, encoded: mutationEventEncoded },
193
- })
194
-
195
- return execArgsArr.some((_) => _.statementSql.includes('__livestore'))
196
- }
197
- })
@@ -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,