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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (277) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/__tests__/fixture.d.ts +83 -221
  3. package/dist/__tests__/fixture.d.ts.map +1 -1
  4. package/dist/__tests__/fixture.js +33 -11
  5. package/dist/__tests__/fixture.js.map +1 -1
  6. package/dist/adapter-types.d.ts +22 -15
  7. package/dist/adapter-types.d.ts.map +1 -1
  8. package/dist/adapter-types.js +15 -2
  9. package/dist/adapter-types.js.map +1 -1
  10. package/dist/bounded-collections.d.ts +1 -1
  11. package/dist/bounded-collections.d.ts.map +1 -1
  12. package/dist/debug-info.d.ts.map +1 -1
  13. package/dist/debug-info.js +1 -0
  14. package/dist/debug-info.js.map +1 -1
  15. package/dist/devtools/devtools-messages-client-session.d.ts +21 -21
  16. package/dist/devtools/devtools-messages-common.d.ts +6 -6
  17. package/dist/devtools/devtools-messages-leader.d.ts +45 -45
  18. package/dist/devtools/devtools-messages-leader.d.ts.map +1 -1
  19. package/dist/devtools/devtools-messages-leader.js +11 -11
  20. package/dist/devtools/devtools-messages-leader.js.map +1 -1
  21. package/dist/index.d.ts +2 -5
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +2 -5
  24. package/dist/index.js.map +1 -1
  25. package/dist/leader-thread/LeaderSyncProcessor.d.ts +10 -10
  26. package/dist/leader-thread/LeaderSyncProcessor.d.ts.map +1 -1
  27. package/dist/leader-thread/LeaderSyncProcessor.js +63 -65
  28. package/dist/leader-thread/LeaderSyncProcessor.js.map +1 -1
  29. package/dist/leader-thread/{apply-mutation.d.ts → apply-event.d.ts} +7 -7
  30. package/dist/leader-thread/apply-event.d.ts.map +1 -0
  31. package/dist/leader-thread/apply-event.js +103 -0
  32. package/dist/leader-thread/apply-event.js.map +1 -0
  33. package/dist/leader-thread/eventlog.d.ts +27 -0
  34. package/dist/leader-thread/eventlog.d.ts.map +1 -0
  35. package/dist/leader-thread/eventlog.js +123 -0
  36. package/dist/leader-thread/eventlog.js.map +1 -0
  37. package/dist/leader-thread/leader-worker-devtools.js +18 -18
  38. package/dist/leader-thread/leader-worker-devtools.js.map +1 -1
  39. package/dist/leader-thread/make-leader-thread-layer.d.ts +2 -2
  40. package/dist/leader-thread/make-leader-thread-layer.d.ts.map +1 -1
  41. package/dist/leader-thread/make-leader-thread-layer.js +16 -16
  42. package/dist/leader-thread/make-leader-thread-layer.js.map +1 -1
  43. package/dist/leader-thread/mod.d.ts +1 -1
  44. package/dist/leader-thread/mod.d.ts.map +1 -1
  45. package/dist/leader-thread/mod.js +1 -1
  46. package/dist/leader-thread/mod.js.map +1 -1
  47. package/dist/leader-thread/recreate-db.d.ts.map +1 -1
  48. package/dist/leader-thread/recreate-db.js +6 -8
  49. package/dist/leader-thread/recreate-db.js.map +1 -1
  50. package/dist/leader-thread/types.d.ts +11 -11
  51. package/dist/leader-thread/types.d.ts.map +1 -1
  52. package/dist/materializer-helper.d.ts +23 -0
  53. package/dist/materializer-helper.d.ts.map +1 -0
  54. package/dist/materializer-helper.js +70 -0
  55. package/dist/materializer-helper.js.map +1 -0
  56. package/dist/query-builder/api.d.ts +58 -53
  57. package/dist/query-builder/api.d.ts.map +1 -1
  58. package/dist/query-builder/api.js +3 -5
  59. package/dist/query-builder/api.js.map +1 -1
  60. package/dist/query-builder/astToSql.d.ts.map +1 -1
  61. package/dist/query-builder/astToSql.js +59 -37
  62. package/dist/query-builder/astToSql.js.map +1 -1
  63. package/dist/query-builder/impl.d.ts +2 -3
  64. package/dist/query-builder/impl.d.ts.map +1 -1
  65. package/dist/query-builder/impl.js +48 -46
  66. package/dist/query-builder/impl.js.map +1 -1
  67. package/dist/query-builder/impl.test.d.ts +86 -1
  68. package/dist/query-builder/impl.test.d.ts.map +1 -1
  69. package/dist/query-builder/impl.test.js +244 -36
  70. package/dist/query-builder/impl.test.js.map +1 -1
  71. package/dist/rehydrate-from-eventlog.d.ts +14 -0
  72. package/dist/rehydrate-from-eventlog.d.ts.map +1 -0
  73. package/dist/{rehydrate-from-mutationlog.js → rehydrate-from-eventlog.js} +25 -26
  74. package/dist/rehydrate-from-eventlog.js.map +1 -0
  75. package/dist/schema/EventDef.d.ts +136 -0
  76. package/dist/schema/EventDef.d.ts.map +1 -0
  77. package/dist/schema/EventDef.js +58 -0
  78. package/dist/schema/EventDef.js.map +1 -0
  79. package/dist/schema/EventId.d.ts +2 -2
  80. package/dist/schema/EventId.d.ts.map +1 -1
  81. package/dist/schema/EventId.js +3 -2
  82. package/dist/schema/EventId.js.map +1 -1
  83. package/dist/schema/{MutationEvent.d.ts → LiveStoreEvent.d.ts} +56 -56
  84. package/dist/schema/LiveStoreEvent.d.ts.map +1 -0
  85. package/dist/schema/{MutationEvent.js → LiveStoreEvent.js} +24 -24
  86. package/dist/schema/LiveStoreEvent.js.map +1 -0
  87. package/dist/schema/client-document-def.d.ts +223 -0
  88. package/dist/schema/client-document-def.d.ts.map +1 -0
  89. package/dist/schema/client-document-def.js +170 -0
  90. package/dist/schema/client-document-def.js.map +1 -0
  91. package/dist/schema/client-document-def.test.d.ts +2 -0
  92. package/dist/schema/client-document-def.test.d.ts.map +1 -0
  93. package/dist/schema/client-document-def.test.js +201 -0
  94. package/dist/schema/client-document-def.test.js.map +1 -0
  95. package/dist/schema/db-schema/dsl/mod.d.ts.map +1 -1
  96. package/dist/schema/events.d.ts +2 -0
  97. package/dist/schema/events.d.ts.map +1 -0
  98. package/dist/schema/events.js +2 -0
  99. package/dist/schema/events.js.map +1 -0
  100. package/dist/schema/mod.d.ts +4 -3
  101. package/dist/schema/mod.d.ts.map +1 -1
  102. package/dist/schema/mod.js +4 -3
  103. package/dist/schema/mod.js.map +1 -1
  104. package/dist/schema/schema.d.ts +27 -23
  105. package/dist/schema/schema.d.ts.map +1 -1
  106. package/dist/schema/schema.js +45 -43
  107. package/dist/schema/schema.js.map +1 -1
  108. package/dist/schema/sqlite-state.d.ts +12 -0
  109. package/dist/schema/sqlite-state.d.ts.map +1 -0
  110. package/dist/schema/sqlite-state.js +36 -0
  111. package/dist/schema/sqlite-state.js.map +1 -0
  112. package/dist/schema/system-tables.d.ts +67 -98
  113. package/dist/schema/system-tables.d.ts.map +1 -1
  114. package/dist/schema/system-tables.js +62 -48
  115. package/dist/schema/system-tables.js.map +1 -1
  116. package/dist/schema/table-def.d.ts +26 -96
  117. package/dist/schema/table-def.d.ts.map +1 -1
  118. package/dist/schema/table-def.js +16 -64
  119. package/dist/schema/table-def.js.map +1 -1
  120. package/dist/schema/view.d.ts +3 -0
  121. package/dist/schema/view.d.ts.map +1 -0
  122. package/dist/schema/view.js +3 -0
  123. package/dist/schema/view.js.map +1 -0
  124. package/dist/schema-management/common.d.ts +4 -4
  125. package/dist/schema-management/common.d.ts.map +1 -1
  126. package/dist/schema-management/migrations.d.ts.map +1 -1
  127. package/dist/schema-management/migrations.js +6 -6
  128. package/dist/schema-management/migrations.js.map +1 -1
  129. package/dist/schema-management/validate-mutation-defs.d.ts +3 -3
  130. package/dist/schema-management/validate-mutation-defs.d.ts.map +1 -1
  131. package/dist/schema-management/validate-mutation-defs.js +17 -17
  132. package/dist/schema-management/validate-mutation-defs.js.map +1 -1
  133. package/dist/sync/ClientSessionSyncProcessor.d.ts +7 -7
  134. package/dist/sync/ClientSessionSyncProcessor.d.ts.map +1 -1
  135. package/dist/sync/ClientSessionSyncProcessor.js +31 -30
  136. package/dist/sync/ClientSessionSyncProcessor.js.map +1 -1
  137. package/dist/sync/next/facts.d.ts +19 -19
  138. package/dist/sync/next/facts.d.ts.map +1 -1
  139. package/dist/sync/next/facts.js +2 -2
  140. package/dist/sync/next/facts.js.map +1 -1
  141. package/dist/sync/next/history-dag-common.d.ts +3 -3
  142. package/dist/sync/next/history-dag-common.d.ts.map +1 -1
  143. package/dist/sync/next/history-dag-common.js +1 -1
  144. package/dist/sync/next/history-dag-common.js.map +1 -1
  145. package/dist/sync/next/history-dag.js +1 -1
  146. package/dist/sync/next/history-dag.js.map +1 -1
  147. package/dist/sync/next/rebase-events.d.ts +7 -7
  148. package/dist/sync/next/rebase-events.d.ts.map +1 -1
  149. package/dist/sync/next/rebase-events.js +5 -5
  150. package/dist/sync/next/rebase-events.js.map +1 -1
  151. package/dist/sync/next/test/compact-events.calculator.test.js +38 -33
  152. package/dist/sync/next/test/compact-events.calculator.test.js.map +1 -1
  153. package/dist/sync/next/test/compact-events.test.js +71 -71
  154. package/dist/sync/next/test/compact-events.test.js.map +1 -1
  155. package/dist/sync/next/test/{mutation-fixtures.d.ts → event-fixtures.d.ts} +29 -29
  156. package/dist/sync/next/test/event-fixtures.d.ts.map +1 -0
  157. package/dist/sync/next/test/{mutation-fixtures.js → event-fixtures.js} +60 -25
  158. package/dist/sync/next/test/event-fixtures.js.map +1 -0
  159. package/dist/sync/next/test/mod.d.ts +1 -1
  160. package/dist/sync/next/test/mod.d.ts.map +1 -1
  161. package/dist/sync/next/test/mod.js +1 -1
  162. package/dist/sync/next/test/mod.js.map +1 -1
  163. package/dist/sync/sync.d.ts +3 -3
  164. package/dist/sync/sync.d.ts.map +1 -1
  165. package/dist/sync/syncstate.d.ts +32 -32
  166. package/dist/sync/syncstate.d.ts.map +1 -1
  167. package/dist/sync/syncstate.js +10 -10
  168. package/dist/sync/syncstate.js.map +1 -1
  169. package/dist/sync/syncstate.test.js +5 -5
  170. package/dist/sync/syncstate.test.js.map +1 -1
  171. package/dist/sync/validate-push-payload.d.ts +2 -2
  172. package/dist/sync/validate-push-payload.d.ts.map +1 -1
  173. package/dist/sync/validate-push-payload.js.map +1 -1
  174. package/dist/version.d.ts +1 -1
  175. package/dist/version.js +1 -1
  176. package/package.json +3 -3
  177. package/src/__tests__/fixture.ts +36 -15
  178. package/src/adapter-types.ts +23 -16
  179. package/src/debug-info.ts +1 -0
  180. package/src/devtools/devtools-messages-leader.ts +13 -13
  181. package/src/index.ts +2 -5
  182. package/src/leader-thread/LeaderSyncProcessor.ts +81 -91
  183. package/src/leader-thread/{apply-mutation.ts → apply-event.ts} +50 -74
  184. package/src/leader-thread/eventlog.ts +199 -0
  185. package/src/leader-thread/leader-worker-devtools.ts +18 -18
  186. package/src/leader-thread/make-leader-thread-layer.ts +18 -18
  187. package/src/leader-thread/mod.ts +1 -1
  188. package/src/leader-thread/recreate-db.ts +6 -9
  189. package/src/leader-thread/types.ts +12 -12
  190. package/src/materializer-helper.ts +110 -0
  191. package/src/query-builder/api.ts +79 -105
  192. package/src/query-builder/astToSql.ts +68 -39
  193. package/src/query-builder/impl.test.ts +264 -42
  194. package/src/query-builder/impl.ts +72 -56
  195. package/src/{rehydrate-from-mutationlog.ts → rehydrate-from-eventlog.ts} +33 -40
  196. package/src/schema/EventDef.ts +216 -0
  197. package/src/schema/EventId.ts +5 -3
  198. package/src/schema/{MutationEvent.ts → LiveStoreEvent.ts} +67 -68
  199. package/src/schema/client-document-def.test.ts +239 -0
  200. package/src/schema/client-document-def.ts +444 -0
  201. package/src/schema/db-schema/dsl/mod.ts +0 -1
  202. package/src/schema/events.ts +1 -0
  203. package/src/schema/mod.ts +4 -3
  204. package/src/schema/schema.ts +79 -69
  205. package/src/schema/sqlite-state.ts +62 -0
  206. package/src/schema/system-tables.ts +42 -53
  207. package/src/schema/table-def.ts +53 -209
  208. package/src/schema/view.ts +2 -0
  209. package/src/schema-management/common.ts +4 -4
  210. package/src/schema-management/migrations.ts +8 -9
  211. package/src/schema-management/validate-mutation-defs.ts +22 -24
  212. package/src/sync/ClientSessionSyncProcessor.ts +37 -36
  213. package/src/sync/next/facts.ts +31 -32
  214. package/src/sync/next/history-dag-common.ts +4 -4
  215. package/src/sync/next/history-dag.ts +1 -1
  216. package/src/sync/next/rebase-events.ts +13 -13
  217. package/src/sync/next/test/compact-events.calculator.test.ts +45 -45
  218. package/src/sync/next/test/compact-events.test.ts +73 -73
  219. package/src/sync/next/test/event-fixtures.ts +219 -0
  220. package/src/sync/next/test/mod.ts +1 -1
  221. package/src/sync/sync.ts +3 -3
  222. package/src/sync/syncstate.test.ts +8 -8
  223. package/src/sync/syncstate.ts +19 -19
  224. package/src/sync/validate-push-payload.ts +2 -2
  225. package/src/version.ts +1 -1
  226. package/tmp/pack.tgz +0 -0
  227. package/tsconfig.json +1 -0
  228. package/dist/derived-mutations.d.ts +0 -109
  229. package/dist/derived-mutations.d.ts.map +0 -1
  230. package/dist/derived-mutations.js +0 -54
  231. package/dist/derived-mutations.js.map +0 -1
  232. package/dist/derived-mutations.test.d.ts +0 -2
  233. package/dist/derived-mutations.test.d.ts.map +0 -1
  234. package/dist/derived-mutations.test.js +0 -93
  235. package/dist/derived-mutations.test.js.map +0 -1
  236. package/dist/init-singleton-tables.d.ts +0 -4
  237. package/dist/init-singleton-tables.d.ts.map +0 -1
  238. package/dist/init-singleton-tables.js +0 -16
  239. package/dist/init-singleton-tables.js.map +0 -1
  240. package/dist/leader-thread/apply-mutation.d.ts.map +0 -1
  241. package/dist/leader-thread/apply-mutation.js +0 -122
  242. package/dist/leader-thread/apply-mutation.js.map +0 -1
  243. package/dist/leader-thread/mutationlog.d.ts +0 -27
  244. package/dist/leader-thread/mutationlog.d.ts.map +0 -1
  245. package/dist/leader-thread/mutationlog.js +0 -124
  246. package/dist/leader-thread/mutationlog.js.map +0 -1
  247. package/dist/leader-thread/pull-queue-set.d.ts +0 -7
  248. package/dist/leader-thread/pull-queue-set.d.ts.map +0 -1
  249. package/dist/leader-thread/pull-queue-set.js +0 -38
  250. package/dist/leader-thread/pull-queue-set.js.map +0 -1
  251. package/dist/mutation.d.ts +0 -20
  252. package/dist/mutation.d.ts.map +0 -1
  253. package/dist/mutation.js +0 -68
  254. package/dist/mutation.js.map +0 -1
  255. package/dist/query-info.d.ts +0 -41
  256. package/dist/query-info.d.ts.map +0 -1
  257. package/dist/query-info.js +0 -7
  258. package/dist/query-info.js.map +0 -1
  259. package/dist/rehydrate-from-mutationlog.d.ts +0 -15
  260. package/dist/rehydrate-from-mutationlog.d.ts.map +0 -1
  261. package/dist/rehydrate-from-mutationlog.js.map +0 -1
  262. package/dist/schema/MutationEvent.d.ts.map +0 -1
  263. package/dist/schema/MutationEvent.js.map +0 -1
  264. package/dist/schema/mutations.d.ts +0 -115
  265. package/dist/schema/mutations.d.ts.map +0 -1
  266. package/dist/schema/mutations.js +0 -42
  267. package/dist/schema/mutations.js.map +0 -1
  268. package/dist/sync/next/test/mutation-fixtures.d.ts.map +0 -1
  269. package/dist/sync/next/test/mutation-fixtures.js.map +0 -1
  270. package/src/derived-mutations.test.ts +0 -101
  271. package/src/derived-mutations.ts +0 -170
  272. package/src/init-singleton-tables.ts +0 -24
  273. package/src/leader-thread/mutationlog.ts +0 -202
  274. package/src/mutation.ts +0 -108
  275. package/src/query-info.ts +0 -83
  276. package/src/schema/mutations.ts +0 -193
  277. package/src/sync/next/test/mutation-fixtures.ts +0 -228
@@ -1,101 +0,0 @@
1
- import { describe, expect, test } from 'vitest'
2
-
3
- import { appConfig, todos } from './__tests__/fixture.js'
4
- import type * as MutationEvent from './schema/MutationEvent.js'
5
-
6
- describe('derived mutations', () => {
7
- test('todos', () => {
8
- expect(patchId(todos.insert({ id: 't1', completed: true, text: 'Task 1' }))).toMatchInlineSnapshot(`
9
- {
10
- "args": {
11
- "completed": true,
12
- "id": "t1",
13
- "text": "Task 1",
14
- },
15
- "id": "00000000-0000-0000-0000-000000000000",
16
- "mutation": "_Derived_Create_todos",
17
- }
18
- `)
19
-
20
- expect(patchId(todos.update({ where: { id: 't1' }, values: { text: 'Task 1 - fixed' } }))).toMatchInlineSnapshot(`
21
- {
22
- "args": {
23
- "values": {
24
- "text": "Task 1 - fixed",
25
- },
26
- "where": {
27
- "id": "t1",
28
- },
29
- },
30
- "id": "00000000-0000-0000-0000-000000000000",
31
- "mutation": "_Derived_Update_todos",
32
- }
33
- `)
34
-
35
- expect(patchId(todos.delete({ where: { id: 't1' } }))).toMatchInlineSnapshot(`
36
- {
37
- "args": {
38
- "where": {
39
- "id": "t1",
40
- },
41
- },
42
- "id": "00000000-0000-0000-0000-000000000000",
43
- "mutation": "_Derived_Delete_todos",
44
- }
45
- `)
46
- })
47
-
48
- test('app_config', () => {
49
- expect(patchId(appConfig.insert())).toMatchInlineSnapshot(`
50
- {
51
- "args": {
52
- "id": "singleton",
53
- "value": {
54
- "value": undefined,
55
- },
56
- },
57
- "id": "00000000-0000-0000-0000-000000000000",
58
- "mutation": "_Derived_Create_app_config",
59
- }
60
- `)
61
-
62
- expect(patchId(appConfig.insert({ fontSize: 12, theme: 'dark' }))).toMatchInlineSnapshot(`
63
- {
64
- "args": {
65
- "id": "singleton",
66
- "value": {
67
- "value": {
68
- "fontSize": 12,
69
- "theme": "dark",
70
- },
71
- },
72
- },
73
- "id": "00000000-0000-0000-0000-000000000000",
74
- "mutation": "_Derived_Create_app_config",
75
- }
76
- `)
77
-
78
- expect(patchId(appConfig.update({ fontSize: 13 }))).toMatchInlineSnapshot(`
79
- {
80
- "args": {
81
- "values": {
82
- "value": {
83
- "fontSize": 13,
84
- },
85
- },
86
- "where": {
87
- "id": "singleton",
88
- },
89
- },
90
- "id": "00000000-0000-0000-0000-000000000000",
91
- "mutation": "_Derived_Update_app_config",
92
- }
93
- `)
94
- })
95
- })
96
-
97
- const patchId = (muationEvent: MutationEvent.PartialAnyDecoded) => {
98
- // TODO use new id paradigm
99
- const id = `00000000-0000-0000-0000-000000000000`
100
- return { ...muationEvent, id }
101
- }
@@ -1,170 +0,0 @@
1
- import type { GetValForKey } from '@livestore/utils'
2
- import { ReadonlyRecord, Schema } from '@livestore/utils/effect'
3
-
4
- import type { SqliteDsl } from './schema/db-schema/mod.js'
5
- import type * as MutationEvent from './schema/MutationEvent.js'
6
- import { defineMutation } from './schema/mutations.js'
7
- import { getDefaultValuesDecoded } from './schema/schema-helpers.js'
8
- import type * as DbSchema from './schema/table-def.js'
9
- import { deleteRows, insertRow, updateRows } from './sql-queries/sql-queries.js'
10
-
11
- export const makeDerivedMutationDefsForTable = <
12
- TTableDef extends DbSchema.TableDefBase<
13
- DbSchema.DefaultSqliteTableDefConstrained,
14
- DbSchema.TableOptions & { deriveMutations: { enabled: true } }
15
- >,
16
- >(
17
- table: TTableDef,
18
- ) => ({
19
- insert: deriveCreateMutationDef(table),
20
- update: deriveUpdateMutationDef(table),
21
- delete: deriveDeleteMutationDef(table),
22
- })
23
-
24
- export const deriveCreateMutationDef = <
25
- TTableDef extends DbSchema.TableDefBase<
26
- DbSchema.DefaultSqliteTableDefConstrained,
27
- DbSchema.TableOptions & { deriveMutations: { enabled: true } }
28
- >,
29
- >(
30
- table: TTableDef,
31
- ) => {
32
- const tableName = table.sqliteDef.name
33
-
34
- const [optionalFields, requiredColumns] = ReadonlyRecord.partition(
35
- (table.sqliteDef as DbSchema.DefaultSqliteTableDef).columns,
36
- (col) => col.nullable === false && col.default._tag === 'None',
37
- )
38
-
39
- const insertSchema = Schema.Struct(ReadonlyRecord.map(requiredColumns, (col) => col.schema))
40
- .pipe(Schema.extend(Schema.partial(Schema.Struct(ReadonlyRecord.map(optionalFields, (col) => col.schema)))))
41
- .annotations({ title: `${tableName}:Insert` })
42
-
43
- return defineMutation(
44
- `_Derived_Create_${tableName}`,
45
- insertSchema,
46
- ({ id, ...explicitDefaultValues }) => {
47
- const defaultValues = getDefaultValuesDecoded(table, explicitDefaultValues)
48
-
49
- const [sql, bindValues] = insertRow({
50
- tableName: table.sqliteDef.name,
51
- columns: table.sqliteDef.columns,
52
- values: { ...defaultValues, id },
53
- })
54
-
55
- return { sql, bindValues, writeTables: new Set([tableName]) }
56
- },
57
- { clientOnly: table.options.deriveMutations.clientOnly },
58
- )
59
- }
60
-
61
- export const deriveUpdateMutationDef = <
62
- TTableDef extends DbSchema.TableDefBase<
63
- DbSchema.DefaultSqliteTableDefConstrained,
64
- DbSchema.TableOptions & { deriveMutations: { enabled: true } }
65
- >,
66
- >(
67
- table: TTableDef,
68
- ) => {
69
- const tableName = table.sqliteDef.name
70
-
71
- return defineMutation(
72
- `_Derived_Update_${tableName}`,
73
- Schema.Struct({
74
- where: Schema.partial(table.schema),
75
- values: Schema.partial(table.schema),
76
- }).annotations({ title: `${tableName}:Update` }),
77
- ({ where, values }) => {
78
- const [sql, bindValues] = updateRows({
79
- tableName: table.sqliteDef.name,
80
- columns: table.sqliteDef.columns,
81
- where,
82
- updateValues: values,
83
- })
84
-
85
- return { sql, bindValues, writeTables: new Set([tableName]) }
86
- },
87
- { clientOnly: table.options.deriveMutations.clientOnly },
88
- )
89
- }
90
-
91
- export const deriveDeleteMutationDef = <
92
- TTableDef extends DbSchema.TableDefBase<
93
- DbSchema.DefaultSqliteTableDefConstrained,
94
- DbSchema.TableOptions & { deriveMutations: { enabled: true } }
95
- >,
96
- >(
97
- table: TTableDef,
98
- ) => {
99
- const tableName = table.sqliteDef.name
100
-
101
- return defineMutation(
102
- `_Derived_Delete_${tableName}`,
103
- Schema.Struct({
104
- where: Schema.partial(table.schema),
105
- }),
106
- ({ where }) => {
107
- const [sql, bindValues] = deleteRows({
108
- tableName: table.sqliteDef.name,
109
- columns: table.sqliteDef.columns,
110
- where,
111
- })
112
-
113
- return { sql, bindValues, writeTables: new Set([tableName]) }
114
- },
115
- { clientOnly: table.options.deriveMutations.clientOnly },
116
- )
117
- }
118
-
119
- /**
120
- * Convenience helper functions on top of the derived mutation definitions.
121
- */
122
- export type DerivedMutationHelperFns<
123
- TColumns extends SqliteDsl.ConstraintColumns,
124
- TOptions extends DbSchema.TableOptions,
125
- > = {
126
- insert: DerivedMutationHelperFns.InsertMutationFn<TColumns, TOptions>
127
- update: DerivedMutationHelperFns.UpdateMutationFn<TColumns, TOptions>
128
- delete: DerivedMutationHelperFns.DeleteMutationFn<TColumns, TOptions>
129
- // TODO also consider adding upsert and deep json mutations (like lenses)
130
- }
131
-
132
- export namespace DerivedMutationHelperFns {
133
- export type InsertMutationFn<
134
- TColumns extends SqliteDsl.ConstraintColumns,
135
- TOptions extends DbSchema.TableOptions,
136
- > = SqliteDsl.AnyIfConstained<
137
- TColumns,
138
- UseShortcut<TOptions> extends true
139
- ? (
140
- values?: GetValForKey<SqliteDsl.FromColumns.InsertRowDecoded<TColumns>, 'value'>,
141
- ) => MutationEvent.PartialAnyDecoded
142
- : (values: SqliteDsl.FromColumns.InsertRowDecoded<TColumns>) => MutationEvent.PartialAnyDecoded
143
- >
144
-
145
- export type UpdateMutationFn<
146
- TColumns extends SqliteDsl.ConstraintColumns,
147
- TOptions extends DbSchema.TableOptions,
148
- > = SqliteDsl.AnyIfConstained<
149
- TColumns,
150
- UseShortcut<TOptions> extends true
151
- ? (
152
- values: Partial<GetValForKey<SqliteDsl.FromColumns.RowDecoded<TColumns>, 'value'>>,
153
- ) => MutationEvent.PartialAnyDecoded
154
- : (args: {
155
- where: Partial<SqliteDsl.FromColumns.RowDecoded<TColumns>>
156
- values: Partial<SqliteDsl.FromColumns.RowDecoded<TColumns>>
157
- }) => MutationEvent.PartialAnyDecoded
158
- >
159
-
160
- export type DeleteMutationFn<
161
- TColumns extends SqliteDsl.ConstraintColumns,
162
- _TOptions extends DbSchema.TableOptions,
163
- > = (args: { where: Partial<SqliteDsl.FromColumns.RowDecoded<TColumns>> }) => MutationEvent.PartialAnyDecoded
164
-
165
- type UseShortcut<TOptions extends DbSchema.TableOptions> = TOptions['isSingleColumn'] extends true
166
- ? TOptions['isSingleton'] extends true
167
- ? true
168
- : false
169
- : false
170
- }
@@ -1,24 +0,0 @@
1
- import type { SqliteDb } from './adapter-types.js'
2
- import type { LiveStoreSchema } from './schema/mod.js'
3
- import { getDefaultValuesEncoded } from './schema/schema-helpers.js'
4
- import { prepareBindValues, sql } from './util.js'
5
-
6
- export const initializeSingletonTables = (schema: LiveStoreSchema, db: SqliteDb) => {
7
- for (const [, tableDef] of schema.tables) {
8
- if (tableDef.options.isSingleton) {
9
- const defaultValues = getDefaultValuesEncoded(tableDef, undefined)
10
-
11
- const defaultColumnNames = [...Object.keys(defaultValues), 'id']
12
- const columnValues = defaultColumnNames.map((name) => `$${name}`).join(', ')
13
-
14
- const tableName = tableDef.sqliteDef.name
15
- const insertQuery = sql`insert into ${tableName} (${defaultColumnNames.join(
16
- ', ',
17
- )}) select ${columnValues} where not exists(select 1 from ${tableName} where id = 'singleton')`
18
-
19
- const bindValues = prepareBindValues({ ...defaultValues, id: 'singleton' }, insertQuery)
20
-
21
- db.execute(insertQuery, bindValues)
22
- }
23
- }
24
- }
@@ -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
- // }