@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,202 +0,0 @@
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 MutationEvent from '../schema/MutationEvent.js'
7
- import {
8
- MUTATION_LOG_META_TABLE,
9
- mutationLogMetaTable,
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 initMutationLogDb = (dbMutationLog: SqliteDb) =>
23
- Effect.gen(function* () {
24
- yield* migrateTable({
25
- db: dbMutationLog,
26
- behaviour: 'create-if-not-exists',
27
- tableAst: mutationLogMetaTable.sqliteDef.ast,
28
- skipMetaTable: true,
29
- })
30
-
31
- yield* migrateTable({
32
- db: dbMutationLog,
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
- dbMutationLog,
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 getMutationEventsSince = (
50
- since: EventId.EventId,
51
- ): Effect.Effect<ReadonlyArray<MutationEvent.EncodedWithMeta>, never, LeaderThreadCtx> =>
52
- Effect.gen(function* () {
53
- const { dbMutationLog, dbReadModel } = yield* LeaderThreadCtx
54
-
55
- const query = mutationLogMetaTable.query.where('idGlobal', '>=', since.global).asSql()
56
- const pendingMutationEventsRaw = dbMutationLog.select(query.query, prepareBindValues(query.bindValues, query.query))
57
- const pendingMutationEvents = Schema.decodeUnknownSync(mutationLogMetaTable.schema.pipe(Schema.Array))(
58
- pendingMutationEventsRaw,
59
- )
60
-
61
- const sessionChangesetRows = sessionChangesetMetaTable.query.where('idGlobal', '>=', since.global).asSql()
62
- const sessionChangesetRowsRaw = dbReadModel.select(
63
- sessionChangesetRows.query,
64
- prepareBindValues(sessionChangesetRows.bindValues, sessionChangesetRows.query),
65
- )
66
- const sessionChangesetRowsDecoded = Schema.decodeUnknownSync(sessionChangesetMetaTable.schema.pipe(Schema.Array))(
67
- sessionChangesetRowsRaw,
68
- )
69
-
70
- return pendingMutationEvents
71
- .map((mutationLogEvent) => {
72
- const sessionChangeset = sessionChangesetRowsDecoded.find(
73
- (readModelEvent) =>
74
- readModelEvent.idGlobal === mutationLogEvent.idGlobal &&
75
- readModelEvent.idClient === mutationLogEvent.idClient,
76
- )
77
- return MutationEvent.EncodedWithMeta.make({
78
- mutation: mutationLogEvent.mutation,
79
- args: mutationLogEvent.argsJson,
80
- id: { global: mutationLogEvent.idGlobal, client: mutationLogEvent.idClient },
81
- parentId: { global: mutationLogEvent.parentIdGlobal, client: mutationLogEvent.parentIdClient },
82
- clientId: mutationLogEvent.clientId,
83
- sessionId: mutationLogEvent.sessionId,
84
- meta: {
85
- sessionChangeset:
86
- sessionChangeset && sessionChangeset.changeset !== null
87
- ? {
88
- _tag: 'sessionChangeset' as const,
89
- data: sessionChangeset.changeset,
90
- debug: sessionChangeset.debug,
91
- }
92
- : { _tag: 'unset' as const },
93
- syncMetadata: mutationLogEvent.syncMetadataJson,
94
- },
95
- })
96
- })
97
- .filter((_) => EventId.compare(_.id, since) > 0)
98
- .sort((a, b) => EventId.compare(a.id, b.id))
99
- })
100
-
101
- export const getClientHeadFromDb = (dbMutationLog: SqliteDb): EventId.EventId => {
102
- const res = dbMutationLog.select<{ idGlobal: EventId.GlobalEventId; idClient: EventId.ClientEventId }>(
103
- sql`select idGlobal, idClient from ${MUTATION_LOG_META_TABLE} order by idGlobal DESC, idClient DESC limit 1`,
104
- )[0]
105
-
106
- return res ? { global: res.idGlobal, client: res.idClient } : EventId.ROOT
107
- }
108
-
109
- export const getBackendHeadFromDb = (dbMutationLog: SqliteDb): EventId.GlobalEventId =>
110
- dbMutationLog.select<{ head: EventId.GlobalEventId }>(sql`select head from ${SYNC_STATUS_TABLE}`)[0]?.head ??
111
- EventId.ROOT.global
112
-
113
- // TODO use prepared statements
114
- export const updateBackendHead = (dbMutationLog: SqliteDb, head: EventId.EventId) =>
115
- dbMutationLog.execute(sql`UPDATE ${SYNC_STATUS_TABLE} SET head = ${head.global}`)
116
-
117
- export const insertIntoMutationLog = (
118
- mutationEventEncoded: MutationEvent.EncodedWithMeta,
119
- dbMutationLog: SqliteDb,
120
- mutationDefSchemaHash: number,
121
- clientId: string,
122
- sessionId: string,
123
- ) =>
124
- Effect.gen(function* () {
125
- // Check history consistency during LS_DEV
126
- if (LS_DEV && mutationEventEncoded.parentId.global !== EventId.ROOT.global) {
127
- const parentMutationExists =
128
- dbMutationLog.select<{ count: number }>(
129
- `SELECT COUNT(*) as count FROM ${MUTATION_LOG_META_TABLE} WHERE idGlobal = ? AND idClient = ?`,
130
- [mutationEventEncoded.parentId.global, mutationEventEncoded.parentId.client] as any as PreparedBindValues,
131
- )[0]!.count === 1
132
-
133
- if (parentMutationExists === false) {
134
- shouldNeverHappen(
135
- `Parent mutation ${mutationEventEncoded.parentId.global},${mutationEventEncoded.parentId.client} does not exist`,
136
- )
137
- }
138
- }
139
-
140
- // TODO use prepared statements
141
- yield* execSql(
142
- dbMutationLog,
143
- ...insertRow({
144
- tableName: MUTATION_LOG_META_TABLE,
145
- columns: mutationLogMetaTable.sqliteDef.columns,
146
- values: {
147
- idGlobal: mutationEventEncoded.id.global,
148
- idClient: mutationEventEncoded.id.client,
149
- parentIdGlobal: mutationEventEncoded.parentId.global,
150
- parentIdClient: mutationEventEncoded.parentId.client,
151
- mutation: mutationEventEncoded.mutation,
152
- argsJson: mutationEventEncoded.args ?? {},
153
- clientId,
154
- sessionId,
155
- schemaHash: mutationDefSchemaHash,
156
- syncMetadataJson: mutationEventEncoded.meta.syncMetadata,
157
- },
158
- }),
159
- )
160
- })
161
-
162
- export const updateSyncMetadata = (items: ReadonlyArray<MutationEvent.EncodedWithMeta>) =>
163
- Effect.gen(function* () {
164
- const { dbMutationLog } = yield* LeaderThreadCtx
165
-
166
- // TODO try to do this in a single query
167
- for (let i = 0; i < items.length; i++) {
168
- const mutationEvent = items[i]!
169
-
170
- yield* execSql(
171
- dbMutationLog,
172
- ...updateRows({
173
- tableName: MUTATION_LOG_META_TABLE,
174
- columns: mutationLogMetaTable.sqliteDef.columns,
175
- where: { idGlobal: mutationEvent.id.global, idClient: mutationEvent.id.client },
176
- updateValues: { syncMetadataJson: mutationEvent.meta.syncMetadata },
177
- }),
178
- )
179
- }
180
- })
181
-
182
- export const getSyncBackendCursorInfo = (remoteHead: EventId.GlobalEventId) =>
183
- Effect.gen(function* () {
184
- const { dbMutationLog } = yield* LeaderThreadCtx
185
-
186
- if (remoteHead === EventId.ROOT.global) return Option.none()
187
-
188
- const MutationlogQuerySchema = Schema.Struct({
189
- syncMetadataJson: Schema.parseJson(Schema.Option(Schema.JsonValue)),
190
- }).pipe(Schema.pluck('syncMetadataJson'), Schema.Array, Schema.head)
191
-
192
- const syncMetadataOption = yield* Effect.sync(() =>
193
- dbMutationLog.select<{ syncMetadataJson: string }>(
194
- sql`SELECT syncMetadataJson FROM ${MUTATION_LOG_META_TABLE} WHERE idGlobal = ${remoteHead} ORDER BY idClient ASC LIMIT 1`,
195
- ),
196
- ).pipe(Effect.andThen(Schema.decode(MutationlogQuerySchema)), Effect.map(Option.flatten), Effect.orDie)
197
-
198
- return Option.some({
199
- cursor: { global: remoteHead, client: EventId.clientDefault },
200
- metadata: syncMetadataOption,
201
- }) satisfies InitialSyncInfo
202
- }).pipe(Effect.withSpan('@livestore/common:mutationlog:getSyncBackendCursorInfo', { attributes: { remoteHead } }))
package/src/mutation.ts DELETED
@@ -1,108 +0,0 @@
1
- import { Schema } from '@livestore/utils/effect'
2
-
3
- import { SessionIdSymbol } from './adapter-types.js'
4
- import type { QueryBuilder } from './query-builder/api.js'
5
- import { isQueryBuilder } from './query-builder/api.js'
6
- import type * as MutationEvent from './schema/MutationEvent.js'
7
- import type { MutationDef, MutationHandlerResult } from './schema/mutations.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 getExecArgsFromMutation = ({
13
- mutationDef,
14
- mutationEvent,
15
- }: {
16
- mutationDef: MutationDef.Any
17
- /** Both encoded and decoded mutation events are supported to reduce the number of times we need to decode/encode */
18
- mutationEvent:
19
- | {
20
- decoded: MutationEvent.AnyDecoded | MutationEvent.PartialAnyDecoded
21
- encoded: undefined
22
- }
23
- | {
24
- decoded: undefined
25
- encoded: MutationEvent.AnyEncoded | MutationEvent.PartialAnyEncoded
26
- }
27
- }): ReadonlyArray<{
28
- statementSql: string
29
- bindValues: PreparedBindValues
30
- writeTables: ReadonlySet<string> | undefined
31
- }> => {
32
- let statementRes: ReadonlyArray<
33
- string | { sql: string; bindValues: Record<string, unknown>; writeTables?: ReadonlySet<string> }
34
- >
35
-
36
- switch (typeof mutationDef.sql) {
37
- case 'function': {
38
- const mutationArgsDecoded =
39
- mutationEvent.decoded?.args ?? Schema.decodeUnknownSync(mutationDef.schema)(mutationEvent.encoded!.args)
40
-
41
- const res = mutationDef.sql(mutationArgsDecoded, {
42
- clientOnly: mutationDef.options.clientOnly,
43
- // TODO properly implement this
44
- currentFacts: new Map(),
45
- })
46
-
47
- statementRes = (Array.isArray(res) ? res : [res]).map((_: QueryBuilder.Any | MutationHandlerResult) => {
48
- if (isQueryBuilder(_)) {
49
- const { query, bindValues } = _.asSql()
50
- return { sql: query, bindValues: bindValues as BindValues }
51
- }
52
-
53
- return _
54
- })
55
-
56
- break
57
- }
58
- case 'string': {
59
- statementRes = [mutationDef.sql]
60
- break
61
- }
62
- default: {
63
- statementRes = mutationDef.sql
64
- break
65
- }
66
- }
67
-
68
- return statementRes.map((statementRes) => {
69
- const statementSql = typeof statementRes === 'string' ? statementRes : statementRes.sql
70
-
71
- const mutationArgsEncoded =
72
- mutationEvent.encoded?.args ?? Schema.encodeUnknownSync(mutationDef.schema)(mutationEvent.decoded!.args)
73
- const bindValues = typeof statementRes === 'string' ? mutationArgsEncoded : statementRes.bindValues
74
-
75
- const writeTables = typeof statementRes === 'string' ? undefined : statementRes.writeTables
76
-
77
- return { statementSql, bindValues: prepareBindValues(bindValues ?? {}, statementSql), writeTables }
78
- })
79
- }
80
-
81
- // NOTE we should explore whether there is a more elegant solution
82
- // e.g. by leveraging the schema to replace the sessionIdSymbol
83
- export const replaceSessionIdSymbol = (
84
- bindValues: Record<string, unknown> | ReadonlyArray<unknown>,
85
- sessionId: string,
86
- ) => {
87
- deepReplaceValue(bindValues, SessionIdSymbol, sessionId)
88
- }
89
-
90
- const deepReplaceValue = <S, R>(input: any, searchValue: S, replaceValue: R): void => {
91
- if (Array.isArray(input)) {
92
- for (const i in input) {
93
- if (input[i] === searchValue) {
94
- input[i] = replaceValue
95
- } else {
96
- deepReplaceValue(input[i], searchValue, replaceValue)
97
- }
98
- }
99
- } else if (typeof input === 'object' && input !== null) {
100
- for (const key in input) {
101
- if (input[key] === searchValue) {
102
- input[key] = replaceValue
103
- } else {
104
- deepReplaceValue(input[key], searchValue, replaceValue)
105
- }
106
- }
107
- }
108
- }
package/src/query-info.ts DELETED
@@ -1,83 +0,0 @@
1
- import type { SessionIdSymbol } from './adapter-types.js'
2
- import type { DbSchema } from './schema/mod.js'
3
-
4
- /**
5
- * Semantic information about a query with supported cases being:
6
- * - a whole row
7
- * - a single column value
8
- * - a sub value in a JSON column
9
- *
10
- * This information is currently only used for derived mutations.
11
- */
12
- export type QueryInfo = QueryInfo.None | QueryInfo.Row | QueryInfo.Col | QueryInfo.ColJsonValue | QueryInfo.Write
13
- // export type QueryInfo<TTableDef extends DbSchema.TableDefBase = DbSchema.TableDefBase> =
14
- // | QueryInfo.None
15
- // | QueryInfo.Row<TTableDef>
16
- // | QueryInfo.ColJsonValue<TTableDef, GetJsonColumn<TTableDef>>
17
- // | QueryInfo.Col<TTableDef, keyof TTableDef['sqliteDef']['columns']>
18
-
19
- export namespace QueryInfo {
20
- export type None = {
21
- _tag: 'None'
22
- }
23
-
24
- export type Row = {
25
- _tag: 'Row'
26
- table: DbSchema.TableDefBase
27
- id: string | SessionIdSymbol | number
28
- }
29
-
30
- export type Col = {
31
- _tag: 'Col'
32
- table: DbSchema.TableDefBase
33
- id: string | SessionIdSymbol | number
34
- column: string
35
- }
36
-
37
- export type ColJsonValue = {
38
- _tag: 'ColJsonValue'
39
- table: DbSchema.TableDefBase
40
- id: string | SessionIdSymbol | number
41
- column: string
42
- /**
43
- * example: `$.tabs[3].items[2]` (`$` referring to the column value)
44
- */
45
- jsonPath: string
46
- }
47
-
48
- // NOTE Not yet used but we might want to use this in order to avoid write queries in read-only situations
49
- export type Write = {
50
- _tag: 'Write'
51
- }
52
-
53
- // NOTE maybe we want to bring back type-params back like below
54
- // export type Row<TTableDef extends DbSchema.TableDefBase> = {
55
- // _tag: 'Row'
56
- // table: TTableDef
57
- // id: string | SessionIdSymbol
58
- // }
59
-
60
- // export type Col<TTableDef extends DbSchema.TableDefBase, TColName extends keyof TTableDef['sqliteDef']['columns']> = {
61
- // _tag: 'Col'
62
- // table: TTableDef
63
- // id: string | SessionIdSymbol
64
- // column: TColName
65
- // }
66
-
67
- // export type ColJsonValue<TTableDef extends DbSchema.TableDefBase, TColName extends GetJsonColumn<TTableDef>> = {
68
- // _tag: 'ColJsonValue'
69
- // table: TTableDef
70
- // id: string | SessionIdSymbol
71
- // column: TColName
72
- // /**
73
- // * example: `$.tabs[3].items[2]` (`$` referring to the column value)
74
- // */
75
- // jsonPath: string
76
- // }
77
- }
78
-
79
- // type GetJsonColumn<TTableDef extends DbSchema.TableDefBase> = keyof {
80
- // [ColName in keyof TTableDef['sqliteDef']['columns'] as TTableDef['sqliteDef']['columns'][ColName]['columnType'] extends 'text'
81
- // ? ColName
82
- // : never]: {}
83
- // }
@@ -1,193 +0,0 @@
1
- import { Schema } from '@livestore/utils/effect'
2
-
3
- import type { QueryBuilder } from '../query-builder/mod.js'
4
- import type { BindValues } from '../sql-queries/sql-queries.js'
5
-
6
- export type MutationDefMap = {
7
- map: Map<string | 'livestore.RawSql', MutationDef.Any>
8
- wasProvided: boolean
9
- }
10
- export type MutationDefRecord = {
11
- 'livestore.RawSql': RawSqlMutation
12
- [name: string]: MutationDef.Any
13
- }
14
-
15
- export type InternalMutationSchema<TRecord extends MutationDefRecord = MutationDefRecord> = {
16
- _DefRecord: TRecord
17
-
18
- map: Map<keyof TRecord, TRecord[keyof TRecord]>
19
- schemaHashMap: Map<keyof TRecord, number>
20
- }
21
-
22
- export type MutationDefSqlResult<TTo> =
23
- | SingleOrReadonlyArray<string>
24
- | ((
25
- args: TTo,
26
- context: { currentFacts: MutationEventFacts; clientOnly: boolean },
27
- ) => SingleOrReadonlyArray<
28
- | string
29
- | {
30
- sql: string
31
- /** Note args need to be manually encoded to `BindValues` when returning this argument */
32
- bindValues: BindValues
33
- writeTables?: ReadonlySet<string>
34
- }
35
- | QueryBuilder.Any
36
- >)
37
-
38
- export type MutationHandlerResult = {
39
- sql: string
40
- bindValues: BindValues
41
- writeTables?: ReadonlySet<string>
42
- }
43
-
44
- export type SingleOrReadonlyArray<T> = T | ReadonlyArray<T>
45
-
46
- export type MutationDef<TName extends string, TFrom, TTo> = {
47
- name: TName
48
- schema: Schema.Schema<TTo, TFrom>
49
- sql: MutationDefSqlResult<NoInfer<TTo>>
50
- options: {
51
- /** Warning: This feature is not fully implemented yet */
52
- historyId: string
53
- /**
54
- * When set to true, the mutation won't be synced across clients but
55
- */
56
- clientOnly: boolean
57
- /** Warning: This feature is not fully implemented yet */
58
- facts: FactsCallback<TTo> | undefined
59
- }
60
-
61
- /** Helper function to construct a partial mutation event */
62
- (args: TTo): {
63
- mutation: TName
64
- args: TTo
65
- }
66
- }
67
-
68
- export type FactsCallback<TTo> = (
69
- args: TTo,
70
- currentFacts: MutationEventFacts,
71
- ) => {
72
- modify: {
73
- set: Iterable<MutationEventFactInput>
74
- unset: Iterable<MutationEventFactInput>
75
- }
76
- require: Iterable<MutationEventFactInput>
77
- }
78
-
79
- export namespace MutationDef {
80
- export type Any = MutationDef<string, any, any>
81
- }
82
-
83
- export type MutationEventKey = string
84
- export type MutationEventFact = string
85
- export type MutationEventFacts = ReadonlyMap<string, any>
86
-
87
- export type MutationEventFactsGroup = {
88
- modifySet: MutationEventFacts
89
- modifyUnset: MutationEventFacts
90
-
91
- /**
92
- * Events on independent "dependency" branches are commutative which can facilitate more prioritized syncing
93
- */
94
- depRequire: MutationEventFacts
95
- depRead: MutationEventFacts
96
- }
97
-
98
- export type MutationEventFactsSnapshot = Map<string, any>
99
-
100
- export type MutationEventFactInput = string | readonly [string, any]
101
-
102
- export const defineFacts = <
103
- TRecord extends Record<string, MutationEventFactInput | ((...args: any[]) => MutationEventFactInput)>,
104
- >(
105
- record: TRecord,
106
- ): TRecord => record
107
-
108
- export type DefineMutationOptions<TTo> = {
109
- // TODO actually implement this
110
- onError?: (error: any) => void
111
- historyId?: string
112
- /** Warning: This feature is not fully implemented yet */
113
- facts?: (
114
- args: TTo,
115
- currentFacts: MutationEventFacts,
116
- ) => {
117
- modify?: {
118
- set?: Iterable<MutationEventFactInput>
119
- unset?: Iterable<MutationEventFactInput>
120
- }
121
- /**
122
- * Two purposes: constrain history and constrain compaction
123
- */
124
- require?: Iterable<MutationEventFactInput>
125
- }
126
- /**
127
- * When set to true, the mutation won't be synced over the network
128
- */
129
- clientOnly?: boolean
130
- }
131
-
132
- // TODO possibly also allow for mutation event subsumption behaviour
133
- export const defineMutation = <TName extends string, TFrom, TTo>(
134
- name: TName,
135
- schema: Schema.Schema<TTo, TFrom>,
136
- sql: MutationDefSqlResult<NoInfer<TTo>>,
137
- options?: DefineMutationOptions<TTo>,
138
- ): MutationDef<TName, TFrom, TTo> => {
139
- const makePartialEvent = (args: TTo) => ({ mutation: name, args })
140
-
141
- Object.defineProperty(makePartialEvent, 'name', { value: name })
142
- Object.defineProperty(makePartialEvent, 'schema', { value: schema })
143
- Object.defineProperty(makePartialEvent, 'sql', { value: sql })
144
- Object.defineProperty(makePartialEvent, 'options', {
145
- value: {
146
- historyId: options?.historyId ?? 'main',
147
- clientOnly: options?.clientOnly ?? false,
148
- facts: options?.facts
149
- ? (args, currentFacts) => {
150
- const res = options.facts!(args, currentFacts)
151
- return {
152
- modify: {
153
- set: res.modify?.set ? new Set(res.modify.set) : new Set(),
154
- unset: res.modify?.unset ? new Set(res.modify.unset) : new Set(),
155
- },
156
- require: res.require ? new Set(res.require) : new Set(),
157
- }
158
- }
159
- : undefined,
160
- } satisfies MutationDef.Any['options'],
161
- })
162
-
163
- return makePartialEvent as MutationDef<TName, TFrom, TTo>
164
- }
165
-
166
- export const makeMutationDefRecord = <TInputRecord extends Record<string, MutationDef.Any>>(
167
- inputRecord: TInputRecord,
168
- ): {
169
- [K in TInputRecord[keyof TInputRecord]['name']]: Extract<TInputRecord[keyof TInputRecord], { name: K }>
170
- } => {
171
- const result: any = {}
172
-
173
- for (const [name, def] of Object.entries(inputRecord)) {
174
- result[name] = def
175
- }
176
-
177
- result['livestore.RawSql'] = rawSqlMutation
178
-
179
- return result
180
- }
181
-
182
- export const rawSqlMutation = defineMutation(
183
- 'livestore.RawSql',
184
- Schema.Struct({
185
- sql: Schema.String,
186
- bindValues: Schema.optional(Schema.Record({ key: Schema.String, value: Schema.Any })),
187
- writeTables: Schema.optional(Schema.ReadonlySet(Schema.String)),
188
- }),
189
- ({ sql, bindValues, writeTables }) => ({ sql, bindValues: bindValues ?? {}, writeTables }),
190
- )
191
-
192
- export type RawSqlMutation = typeof rawSqlMutation
193
- export type RawSqlMutationEvent = ReturnType<typeof rawSqlMutation>