@livestore/common 0.3.0-dev.11 → 0.3.0-dev.3

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 (181) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/adapter-types.d.ts +35 -47
  3. package/dist/adapter-types.d.ts.map +1 -1
  4. package/dist/adapter-types.js.map +1 -1
  5. package/dist/derived-mutations.d.ts +4 -4
  6. package/dist/derived-mutations.d.ts.map +1 -1
  7. package/dist/derived-mutations.test.js.map +1 -1
  8. package/dist/devtools/devtools-bridge.d.ts +1 -2
  9. package/dist/devtools/devtools-bridge.d.ts.map +1 -1
  10. package/dist/devtools/devtools-messages.d.ts +592 -3
  11. package/dist/devtools/devtools-messages.d.ts.map +1 -1
  12. package/dist/devtools/devtools-messages.js +171 -3
  13. package/dist/devtools/devtools-messages.js.map +1 -1
  14. package/dist/index.d.ts +4 -0
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/init-singleton-tables.d.ts +2 -2
  17. package/dist/init-singleton-tables.d.ts.map +1 -1
  18. package/dist/init-singleton-tables.js.map +1 -1
  19. package/dist/leader-thread/apply-mutation.d.ts +2 -5
  20. package/dist/leader-thread/apply-mutation.d.ts.map +1 -1
  21. package/dist/leader-thread/apply-mutation.js +29 -41
  22. package/dist/leader-thread/apply-mutation.js.map +1 -1
  23. package/dist/leader-thread/connection.d.ts +4 -4
  24. package/dist/leader-thread/connection.d.ts.map +1 -1
  25. package/dist/leader-thread/connection.js +5 -5
  26. package/dist/leader-thread/connection.js.map +1 -1
  27. package/dist/leader-thread/leader-sync-processor.d.ts +2 -2
  28. package/dist/leader-thread/leader-sync-processor.d.ts.map +1 -1
  29. package/dist/leader-thread/leader-sync-processor.js +12 -20
  30. package/dist/leader-thread/leader-sync-processor.js.map +1 -1
  31. package/dist/leader-thread/leader-worker-devtools.d.ts +1 -1
  32. package/dist/leader-thread/leader-worker-devtools.d.ts.map +1 -1
  33. package/dist/leader-thread/leader-worker-devtools.js +81 -37
  34. package/dist/leader-thread/leader-worker-devtools.js.map +1 -1
  35. package/dist/leader-thread/make-leader-thread-layer.d.ts +11 -12
  36. package/dist/leader-thread/make-leader-thread-layer.d.ts.map +1 -1
  37. package/dist/leader-thread/make-leader-thread-layer.js +14 -33
  38. package/dist/leader-thread/make-leader-thread-layer.js.map +1 -1
  39. package/dist/leader-thread/mutationlog.d.ts +19 -6
  40. package/dist/leader-thread/mutationlog.d.ts.map +1 -1
  41. package/dist/leader-thread/mutationlog.js +6 -7
  42. package/dist/leader-thread/mutationlog.js.map +1 -1
  43. package/dist/leader-thread/pull-queue-set.d.ts.map +1 -1
  44. package/dist/leader-thread/recreate-db.d.ts.map +1 -1
  45. package/dist/leader-thread/recreate-db.js +18 -24
  46. package/dist/leader-thread/recreate-db.js.map +1 -1
  47. package/dist/leader-thread/types.d.ts +16 -36
  48. package/dist/leader-thread/types.d.ts.map +1 -1
  49. package/dist/leader-thread/types.js.map +1 -1
  50. package/dist/mutation.d.ts +2 -9
  51. package/dist/mutation.d.ts.map +1 -1
  52. package/dist/mutation.js +5 -5
  53. package/dist/mutation.js.map +1 -1
  54. package/dist/query-builder/impl.d.ts +1 -1
  55. package/dist/rehydrate-from-mutationlog.d.ts +5 -5
  56. package/dist/rehydrate-from-mutationlog.d.ts.map +1 -1
  57. package/dist/rehydrate-from-mutationlog.js +19 -13
  58. package/dist/rehydrate-from-mutationlog.js.map +1 -1
  59. package/dist/schema/EventId.d.ts +14 -16
  60. package/dist/schema/EventId.d.ts.map +1 -1
  61. package/dist/schema/EventId.js +7 -15
  62. package/dist/schema/EventId.js.map +1 -1
  63. package/dist/schema/MutationEvent.d.ts +80 -49
  64. package/dist/schema/MutationEvent.d.ts.map +1 -1
  65. package/dist/schema/MutationEvent.js +15 -32
  66. package/dist/schema/MutationEvent.js.map +1 -1
  67. package/dist/schema/system-tables.d.ts +26 -26
  68. package/dist/schema/system-tables.d.ts.map +1 -1
  69. package/dist/schema/system-tables.js +11 -19
  70. package/dist/schema/system-tables.js.map +1 -1
  71. package/dist/schema-management/common.d.ts +3 -3
  72. package/dist/schema-management/common.d.ts.map +1 -1
  73. package/dist/schema-management/common.js.map +1 -1
  74. package/dist/schema-management/migrations.d.ts +4 -4
  75. package/dist/schema-management/migrations.d.ts.map +1 -1
  76. package/dist/schema-management/migrations.js +6 -6
  77. package/dist/schema-management/migrations.js.map +1 -1
  78. package/dist/sync/client-session-sync-processor.d.ts +4 -4
  79. package/dist/sync/client-session-sync-processor.d.ts.map +1 -1
  80. package/dist/sync/index.d.ts +1 -1
  81. package/dist/sync/index.d.ts.map +1 -1
  82. package/dist/sync/index.js +1 -1
  83. package/dist/sync/index.js.map +1 -1
  84. package/dist/sync/next/history-dag-common.d.ts +4 -1
  85. package/dist/sync/next/history-dag-common.d.ts.map +1 -1
  86. package/dist/sync/next/history-dag-common.js +1 -1
  87. package/dist/sync/next/history-dag-common.js.map +1 -1
  88. package/dist/sync/next/rebase-events.d.ts +3 -3
  89. package/dist/sync/next/rebase-events.d.ts.map +1 -1
  90. package/dist/sync/next/rebase-events.js +2 -3
  91. package/dist/sync/next/rebase-events.js.map +1 -1
  92. package/dist/sync/next/test/mutation-fixtures.d.ts +7 -7
  93. package/dist/sync/next/test/mutation-fixtures.d.ts.map +1 -1
  94. package/dist/sync/next/test/mutation-fixtures.js +9 -3
  95. package/dist/sync/next/test/mutation-fixtures.js.map +1 -1
  96. package/dist/sync/sync.d.ts +11 -21
  97. package/dist/sync/sync.d.ts.map +1 -1
  98. package/dist/sync/sync.js.map +1 -1
  99. package/dist/sync/syncstate.d.ts +23 -45
  100. package/dist/sync/syncstate.d.ts.map +1 -1
  101. package/dist/sync/syncstate.js +12 -56
  102. package/dist/sync/syncstate.js.map +1 -1
  103. package/dist/sync/syncstate.test.js +69 -125
  104. package/dist/sync/syncstate.test.js.map +1 -1
  105. package/dist/sync/validate-push-payload.d.ts +2 -2
  106. package/dist/sync/validate-push-payload.d.ts.map +1 -1
  107. package/dist/sync/validate-push-payload.js +2 -2
  108. package/dist/sync/validate-push-payload.js.map +1 -1
  109. package/dist/version.d.ts +1 -1
  110. package/dist/version.d.ts.map +1 -1
  111. package/dist/version.js +1 -1
  112. package/dist/version.js.map +1 -1
  113. package/package.json +5 -6
  114. package/src/adapter-types.ts +40 -39
  115. package/src/derived-mutations.test.ts +1 -1
  116. package/src/derived-mutations.ts +5 -9
  117. package/src/devtools/devtools-bridge.ts +1 -2
  118. package/src/devtools/devtools-messages.ts +243 -3
  119. package/src/index.ts +6 -0
  120. package/src/init-singleton-tables.ts +2 -2
  121. package/src/leader-thread/apply-mutation.ts +35 -53
  122. package/src/leader-thread/connection.ts +7 -7
  123. package/src/leader-thread/{LeaderSyncProcessor.ts → leader-sync-processor.ts} +268 -306
  124. package/src/leader-thread/leader-worker-devtools.ts +124 -52
  125. package/src/leader-thread/make-leader-thread-layer.ts +30 -62
  126. package/src/leader-thread/mutationlog.ts +10 -14
  127. package/src/leader-thread/recreate-db.ts +20 -24
  128. package/src/leader-thread/types.ts +20 -41
  129. package/src/mutation.ts +7 -17
  130. package/src/rehydrate-from-mutationlog.ts +26 -18
  131. package/src/schema/EventId.ts +9 -23
  132. package/src/schema/MutationEvent.ts +24 -46
  133. package/src/schema/system-tables.ts +11 -19
  134. package/src/schema-management/common.ts +3 -3
  135. package/src/schema-management/migrations.ts +10 -10
  136. package/src/sync/{ClientSessionSyncProcessor.ts → client-session-sync-processor.ts} +19 -26
  137. package/src/sync/index.ts +1 -1
  138. package/src/sync/next/history-dag-common.ts +1 -1
  139. package/src/sync/next/rebase-events.ts +7 -7
  140. package/src/sync/next/test/mutation-fixtures.ts +10 -3
  141. package/src/sync/sync.ts +6 -19
  142. package/src/sync/syncstate.test.ts +67 -127
  143. package/src/sync/syncstate.ts +19 -21
  144. package/src/sync/validate-push-payload.ts +4 -7
  145. package/src/version.ts +1 -1
  146. package/dist/devtools/devtool-message-leader.d.ts +0 -2
  147. package/dist/devtools/devtool-message-leader.d.ts.map +0 -1
  148. package/dist/devtools/devtool-message-leader.js +0 -2
  149. package/dist/devtools/devtool-message-leader.js.map +0 -1
  150. package/dist/devtools/devtools-messages-client-session.d.ts +0 -297
  151. package/dist/devtools/devtools-messages-client-session.d.ts.map +0 -1
  152. package/dist/devtools/devtools-messages-client-session.js +0 -61
  153. package/dist/devtools/devtools-messages-client-session.js.map +0 -1
  154. package/dist/devtools/devtools-messages-common.d.ts +0 -65
  155. package/dist/devtools/devtools-messages-common.d.ts.map +0 -1
  156. package/dist/devtools/devtools-messages-common.js +0 -35
  157. package/dist/devtools/devtools-messages-common.js.map +0 -1
  158. package/dist/devtools/devtools-messages-leader.d.ts +0 -261
  159. package/dist/devtools/devtools-messages-leader.d.ts.map +0 -1
  160. package/dist/devtools/devtools-messages-leader.js +0 -85
  161. package/dist/devtools/devtools-messages-leader.js.map +0 -1
  162. package/dist/leader-thread/LeaderSyncProcessor.d.ts +0 -37
  163. package/dist/leader-thread/LeaderSyncProcessor.d.ts.map +0 -1
  164. package/dist/leader-thread/LeaderSyncProcessor.js +0 -432
  165. package/dist/leader-thread/LeaderSyncProcessor.js.map +0 -1
  166. package/dist/schema/EventId.test.d.ts +0 -2
  167. package/dist/schema/EventId.test.d.ts.map +0 -1
  168. package/dist/schema/EventId.test.js +0 -11
  169. package/dist/schema/EventId.test.js.map +0 -1
  170. package/dist/schema/MutationEvent.test.d.ts +0 -2
  171. package/dist/schema/MutationEvent.test.d.ts.map +0 -1
  172. package/dist/schema/MutationEvent.test.js +0 -2
  173. package/dist/schema/MutationEvent.test.js.map +0 -1
  174. package/dist/sync/ClientSessionSyncProcessor.d.ts +0 -43
  175. package/dist/sync/ClientSessionSyncProcessor.d.ts.map +0 -1
  176. package/dist/sync/ClientSessionSyncProcessor.js +0 -141
  177. package/dist/sync/ClientSessionSyncProcessor.js.map +0 -1
  178. package/src/devtools/devtools-messages-client-session.ts +0 -109
  179. package/src/devtools/devtools-messages-common.ts +0 -52
  180. package/src/devtools/devtools-messages-leader.ts +0 -115
  181. package/src/schema/EventId.test.ts +0 -12
@@ -6,7 +6,6 @@ import type {
6
6
  Option,
7
7
  Queue,
8
8
  Scope,
9
- Subscribable,
10
9
  SubscriptionRef,
11
10
  WebChannel,
12
11
  } from '@livestore/utils/effect'
@@ -16,14 +15,14 @@ import type {
16
15
  BootStatus,
17
16
  Devtools,
18
17
  InvalidPushError,
19
- MakeSqliteDb,
18
+ MakeSynchronousDatabase,
20
19
  PersistenceInfo,
21
- SqliteDb,
22
20
  SyncBackend,
21
+ SynchronousDatabase,
23
22
  UnexpectedError,
24
23
  } from '../index.js'
25
24
  import type { EventId, LiveStoreSchema, MutationEvent } from '../schema/mod.js'
26
- import type * as SyncState from '../sync/syncstate.js'
25
+ import type { PayloadUpstream, SyncState } from '../sync/syncstate.js'
27
26
  import type { ShutdownChannel } from './shutdown-channel.js'
28
27
 
29
28
  export type ShutdownState = 'running' | 'shutting-down'
@@ -56,8 +55,8 @@ export type InitialSyncInfo = Option.Option<{
56
55
  // | { _tag: 'Recreate'; snapshotRef: Ref.Ref<Uint8Array | undefined>; syncInfo: InitialSyncInfo }
57
56
  // | { _tag: 'Reuse'; syncInfo: InitialSyncInfo }
58
57
 
59
- export type LeaderSqliteDb = SqliteDb<{ dbPointer: number; persistenceInfo: PersistenceInfo }>
60
- export type PersistenceInfoPair = { readModel: PersistenceInfo; mutationLog: PersistenceInfo }
58
+ export type LeaderDatabase = SynchronousDatabase<{ dbPointer: number; persistenceInfo: PersistenceInfo }>
59
+ export type PersistenceInfoPair = { db: PersistenceInfo; mutationLog: PersistenceInfo }
61
60
 
62
61
  export type DevtoolsOptions =
63
62
  | {
@@ -65,9 +64,10 @@ export type DevtoolsOptions =
65
64
  }
66
65
  | {
67
66
  enabled: true
68
- makeBootContext: Effect.Effect<
67
+ makeContext: Effect.Effect<
69
68
  {
70
69
  devtoolsWebChannel: WebChannel.WebChannel<Devtools.MessageToAppLeader, Devtools.MessageFromAppLeader>
70
+ shutdownChannel: ShutdownChannel
71
71
  persistenceInfo: PersistenceInfoPair
72
72
  },
73
73
  UnexpectedError,
@@ -75,40 +75,23 @@ export type DevtoolsOptions =
75
75
  >
76
76
  }
77
77
 
78
- export type DevtoolsContext =
79
- | {
80
- enabled: true
81
- syncBackendPullLatch: Effect.Latch
82
- syncBackendPushLatch: Effect.Latch
83
- }
84
- | {
85
- enabled: false
86
- }
87
-
88
78
  export class LeaderThreadCtx extends Context.Tag('LeaderThreadCtx')<
89
79
  LeaderThreadCtx,
90
80
  {
91
81
  schema: LiveStoreSchema
92
82
  storeId: string
93
- clientId: string
94
- makeSqliteDb: MakeSqliteDb
95
- dbReadModel: LeaderSqliteDb
96
- dbMutationLog: LeaderSqliteDb
83
+ originId: string
84
+ makeSyncDb: MakeSynchronousDatabase
85
+ db: LeaderDatabase
86
+ dbLog: LeaderDatabase
97
87
  bootStatusQueue: Queue.Queue<BootStatus>
98
88
  // TODO we should find a more elegant way to handle cases which need this ref for their implementation
99
89
  shutdownStateSubRef: SubscriptionRef.SubscriptionRef<ShutdownState>
100
- shutdownChannel: ShutdownChannel
101
90
  mutationEventSchema: MutationEvent.ForMutationDefRecord<any>
102
- devtools: DevtoolsContext
91
+ // devtools: DevtoolsContext
103
92
  syncBackend: SyncBackend | undefined
104
- syncProcessor: LeaderSyncProcessor
93
+ syncProcessor: SyncProcessor
105
94
  connectedClientSessionPullQueues: PullQueueSet
106
- /**
107
- * e.g. used for `store._dev` APIs
108
- *
109
- * This is currently separated from `.devtools` as it also needs to work when devtools are disabled
110
- */
111
- extraIncomingMessagesQueue: Queue.Queue<Devtools.MessageToAppLeader>
112
95
  }
113
96
  >() {}
114
97
 
@@ -118,28 +101,24 @@ export type InitialBlockingSyncContext = {
118
101
  }
119
102
 
120
103
  export type PullQueueItem = {
121
- payload: SyncState.PayloadUpstream
104
+ // mutationEvents: ReadonlyArray<MutationEvent.AnyEncoded>
105
+ // backendHead: number
106
+ payload: PayloadUpstream
107
+ // TODO move `remaining` into `PayloadUpstream`
122
108
  remaining: number
123
109
  }
124
110
 
125
- export interface LeaderSyncProcessor {
111
+ export interface SyncProcessor {
126
112
  push: (
127
113
  /** `batch` needs to follow the same rules as `batch` in `SyncBackend.push` */
128
114
  batch: ReadonlyArray<MutationEvent.EncodedWithMeta>,
129
- options?: {
130
- /**
131
- * If true, the effect will only finish when the local push has been processed (i.e. succeeded or was rejected).
132
- * @default false
133
- */
134
- waitForProcessing?: boolean
135
- },
136
- ) => Effect.Effect<void, InvalidPushError>
115
+ ) => Effect.Effect<void, UnexpectedError | InvalidPushError, HttpClient.HttpClient | LeaderThreadCtx>
137
116
 
138
117
  pushPartial: (mutationEvent: MutationEvent.PartialAnyEncoded) => Effect.Effect<void, UnexpectedError, LeaderThreadCtx>
139
118
  boot: (args: {
140
119
  dbReady: Deferred.Deferred<void>
141
120
  }) => Effect.Effect<void, UnexpectedError, LeaderThreadCtx | Scope.Scope | HttpClient.HttpClient>
142
- syncState: Subscribable.Subscribable<SyncState.SyncState>
121
+ syncState: Effect.Effect<SyncState, UnexpectedError>
143
122
  }
144
123
 
145
124
  export interface PullQueueSet {
package/src/mutation.ts CHANGED
@@ -8,19 +8,10 @@ import { prepareBindValues } from './util.js'
8
8
 
9
9
  export const getExecArgsFromMutation = ({
10
10
  mutationDef,
11
- mutationEvent,
11
+ mutationEventDecoded,
12
12
  }: {
13
13
  mutationDef: MutationDef.Any
14
- /** Both encoded and decoded mutation events are supported to reduce the number of times we need to decode/encode */
15
- mutationEvent:
16
- | {
17
- decoded: MutationEvent.AnyDecoded | MutationEvent.PartialAnyDecoded
18
- encoded: undefined
19
- }
20
- | {
21
- decoded: undefined
22
- encoded: MutationEvent.AnyEncoded | MutationEvent.PartialAnyEncoded
23
- }
14
+ mutationEventDecoded: MutationEvent.Any | MutationEvent.PartialAny
24
15
  }): ReadonlyArray<{
25
16
  statementSql: string
26
17
  bindValues: PreparedBindValues
@@ -32,9 +23,7 @@ export const getExecArgsFromMutation = ({
32
23
 
33
24
  switch (typeof mutationDef.sql) {
34
25
  case 'function': {
35
- const mutationArgsDecoded =
36
- mutationEvent.decoded?.args ?? Schema.decodeUnknownSync(mutationDef.schema)(mutationEvent.encoded!.args)
37
- const res = mutationDef.sql(mutationArgsDecoded)
26
+ const res = mutationDef.sql(mutationEventDecoded.args)
38
27
  statementRes = Array.isArray(res) ? res : [res]
39
28
  break
40
29
  }
@@ -51,9 +40,10 @@ export const getExecArgsFromMutation = ({
51
40
  return statementRes.map((statementRes) => {
52
41
  const statementSql = typeof statementRes === 'string' ? statementRes : statementRes.sql
53
42
 
54
- const mutationArgsEncoded =
55
- mutationEvent.encoded?.args ?? Schema.encodeUnknownSync(mutationDef.schema)(mutationEvent.decoded!.args)
56
- const bindValues = typeof statementRes === 'string' ? mutationArgsEncoded : statementRes.bindValues
43
+ const bindValues =
44
+ typeof statementRes === 'string'
45
+ ? Schema.encodeUnknownSync(mutationDef.schema)(mutationEventDecoded.args)
46
+ : statementRes.bindValues
57
47
 
58
48
  const writeTables = typeof statementRes === 'string' ? undefined : statementRes.writeTables
59
49
 
@@ -1,8 +1,8 @@
1
- import { memoizeByRef, shouldNeverHappen } from '@livestore/utils'
1
+ import { isDevEnv, memoizeByRef, shouldNeverHappen } from '@livestore/utils'
2
2
  import { Chunk, Effect, Option, Schema, Stream } from '@livestore/utils/effect'
3
3
 
4
- import { type MigrationOptionsFromMutationLog, type SqliteDb, UnexpectedError } from './adapter-types.js'
5
- import { makeApplyMutation } from './leader-thread/apply-mutation.js'
4
+ import { type MigrationOptionsFromMutationLog, type SynchronousDatabase, UnexpectedError } from './adapter-types.js'
5
+ import { getExecArgsFromMutation } from './mutation.js'
6
6
  import type { LiveStoreSchema, MutationDef, MutationEvent, MutationLogMetaRow } from './schema/mod.js'
7
7
  import { EventId, MUTATION_LOG_META_TABLE } from './schema/mod.js'
8
8
  import type { PreparedBindValues } from './util.js'
@@ -10,14 +10,13 @@ import { sql } from './util.js'
10
10
 
11
11
  export const rehydrateFromMutationLog = ({
12
12
  logDb,
13
- // TODO re-use this db when bringing back the boot in-memory db implementation
14
- // db,
13
+ db,
15
14
  schema,
16
15
  migrationOptions,
17
16
  onProgress,
18
17
  }: {
19
- logDb: SqliteDb
20
- db: SqliteDb
18
+ logDb: SynchronousDatabase
19
+ db: SynchronousDatabase
21
20
  schema: LiveStoreSchema
22
21
  migrationOptions: MigrationOptionsFromMutationLog
23
22
  onProgress: (_: { done: number; total: number }) => Effect.Effect<void>
@@ -29,8 +28,6 @@ export const rehydrateFromMutationLog = ({
29
28
 
30
29
  const hashMutation = memoizeByRef((mutation: MutationDef.Any) => Schema.hash(mutation.schema))
31
30
 
32
- const applyMutation = yield* makeApplyMutation
33
-
34
31
  const processMutation = (row: MutationLogMetaRow) =>
35
32
  Effect.gen(function* () {
36
33
  const mutationDef = schema.mutations.get(row.mutation) ?? shouldNeverHappen(`Unknown mutation ${row.mutation}`)
@@ -43,10 +40,7 @@ export const rehydrateFromMutationLog = ({
43
40
  )
44
41
  }
45
42
 
46
- const args = JSON.parse(row.argsJson)
47
-
48
- // Checking whether the schema has changed in an incompatible way
49
- yield* Schema.decodeUnknown(mutationDef.schema)(args).pipe(
43
+ const argsDecoded = yield* Schema.decodeUnknown(Schema.parseJson(mutationDef.schema))(row.argsJson).pipe(
50
44
  Effect.mapError((cause) =>
51
45
  UnexpectedError.make({
52
46
  cause,
@@ -59,14 +53,28 @@ This likely means the schema has changed in an incompatible way.
59
53
  ),
60
54
  )
61
55
 
62
- const mutationEventEncoded = {
56
+ const mutationEventDecoded = {
63
57
  id: { global: row.idGlobal, local: row.idLocal },
64
58
  parentId: { global: row.parentIdGlobal, local: row.parentIdLocal },
65
59
  mutation: row.mutation,
66
- args,
67
- } satisfies MutationEvent.AnyEncoded
68
-
69
- yield* applyMutation(mutationEventEncoded, { skipMutationLog: true })
60
+ args: argsDecoded,
61
+ } satisfies MutationEvent.Any
62
+
63
+ const execArgsArr = getExecArgsFromMutation({ mutationDef, mutationEventDecoded })
64
+
65
+ const makeExecuteOptions = (statementSql: string, bindValues: any) => ({
66
+ onRowsChanged: (rowsChanged: number) => {
67
+ if (rowsChanged === 0 && migrationOptions.logging?.excludeAffectedRows?.(statementSql) !== true) {
68
+ console.warn(`Mutation "${mutationDef.name}" did not affect any rows:`, statementSql, bindValues)
69
+ }
70
+ },
71
+ })
72
+
73
+ for (const { statementSql, bindValues } of execArgsArr) {
74
+ // TODO cache prepared statements for mutations
75
+ db.execute(statementSql, bindValues, isDevEnv() ? makeExecuteOptions(statementSql, bindValues) : undefined)
76
+ // console.log(`Re-executed mutation ${mutationSql}`, bindValues)
77
+ }
70
78
  }).pipe(Effect.withSpan(`@livestore/common:rehydrateFromMutationLog:processMutation`))
71
79
 
72
80
  const CHUNK_SIZE = 100
@@ -1,14 +1,4 @@
1
- import { Brand, Schema } from '@livestore/utils/effect'
2
-
3
- export type LocalEventId = Brand.Branded<number, 'LocalEventId'>
4
- export const localEventId = Brand.nominal<LocalEventId>()
5
- export const LocalEventId = Schema.fromBrand(localEventId)(Schema.Int)
6
-
7
- export type GlobalEventId = Brand.Branded<number, 'GlobalEventId'>
8
- export const globalEventId = Brand.nominal<GlobalEventId>()
9
- export const GlobalEventId = Schema.fromBrand(globalEventId)(Schema.Int)
10
-
11
- export const localDefault = 0 as any as LocalEventId
1
+ import { Schema } from '@livestore/utils/effect'
12
2
 
13
3
  /**
14
4
  * LiveStore event id value consisting of a globally unique event sequence number
@@ -16,11 +6,11 @@ export const localDefault = 0 as any as LocalEventId
16
6
  *
17
7
  * The local sequence number is only used for localOnly mutations and starts from 0 for each global sequence number.
18
8
  */
19
- export type EventId = { global: GlobalEventId; local: LocalEventId }
9
+ export type EventId = { global: number; local: number }
20
10
 
21
11
  export const EventId = Schema.Struct({
22
- global: GlobalEventId,
23
- local: LocalEventId,
12
+ global: Schema.Number,
13
+ local: Schema.Number,
24
14
  }).annotations({ title: 'LiveStore.EventId' })
25
15
 
26
16
  /**
@@ -37,24 +27,20 @@ export const isEqual = (a: EventId, b: EventId) => a.global === b.global && a.lo
37
27
 
38
28
  export type EventIdPair = { id: EventId; parentId: EventId }
39
29
 
40
- export const ROOT = { global: -1 as any as GlobalEventId, local: localDefault } satisfies EventId
30
+ export const ROOT = { global: -1, local: 0 } satisfies EventId
41
31
 
42
32
  export const isGreaterThan = (a: EventId, b: EventId) => {
43
33
  return a.global > b.global || (a.global === b.global && a.local > b.local)
44
34
  }
45
35
 
46
- export const make = (id: EventId | typeof EventId.Encoded): EventId => {
47
- return Schema.is(EventId)(id) ? id : Schema.decodeSync(EventId)(id)
48
- }
49
-
50
- export const nextPair = (id: EventId, isLocal: boolean): EventIdPair => {
36
+ export const nextPair = (id: EventId, isLocal: boolean) => {
51
37
  if (isLocal) {
52
- return { id: { global: id.global, local: (id.local + 1) as any as LocalEventId }, parentId: id }
38
+ return { id: { global: id.global, local: id.local + 1 }, parentId: id }
53
39
  }
54
40
 
55
41
  return {
56
- id: { global: (id.global + 1) as any as GlobalEventId, local: localDefault },
42
+ id: { global: id.global + 1, local: 0 },
57
43
  // NOTE we always point to `local: 0` for non-localOnly mutations
58
- parentId: { global: id.global, local: localDefault },
44
+ parentId: { global: id.global, local: 0 },
59
45
  }
60
46
  }
@@ -1,4 +1,5 @@
1
1
  import { memoizeByRef } from '@livestore/utils'
2
+ import type { Deferred } from '@livestore/utils/effect'
2
3
  import { Schema } from '@livestore/utils/effect'
3
4
 
4
5
  import * as EventId from './EventId.js'
@@ -29,31 +30,10 @@ export type MutationEventEncoded<TMutationsDef extends MutationDef.Any> = {
29
30
  parentId: EventId.EventId
30
31
  }
31
32
 
32
- export type AnyDecoded = MutationEvent<MutationDef.Any>
33
- export const AnyDecoded = Schema.Struct({
34
- mutation: Schema.String,
35
- args: Schema.Any,
36
- id: EventId.EventId,
37
- parentId: EventId.EventId,
38
- }).annotations({ title: 'MutationEvent.AnyDecoded' })
39
-
33
+ export type Any = MutationEvent<MutationDef.Any>
40
34
  export type AnyEncoded = MutationEventEncoded<MutationDef.Any>
41
- export const AnyEncoded = Schema.Struct({
42
- mutation: Schema.String,
43
- args: Schema.Any,
44
- id: EventId.EventId,
45
- parentId: EventId.EventId,
46
- }).annotations({ title: 'MutationEvent.AnyEncoded' })
47
-
48
- export const AnyEncodedGlobal = Schema.Struct({
49
- mutation: Schema.String,
50
- args: Schema.Any,
51
- id: EventId.GlobalEventId,
52
- parentId: EventId.GlobalEventId,
53
- }).annotations({ title: 'MutationEvent.AnyEncodedGlobal' })
54
- export type AnyEncodedGlobal = typeof AnyEncodedGlobal.Type
55
35
 
56
- export type PartialAnyDecoded = MutationEventPartial<MutationDef.Any>
36
+ export type PartialAny = MutationEventPartial<MutationDef.Any>
57
37
  export type PartialAnyEncoded = MutationEventPartialEncoded<MutationDef.Any>
58
38
 
59
39
  export type PartialForSchema<TSchema extends LiveStoreSchema> = {
@@ -64,9 +44,8 @@ export type ForSchema<TSchema extends LiveStoreSchema> = {
64
44
  [K in keyof TSchema['_MutationDefMapType']]: MutationEvent<TSchema['_MutationDefMapType'][K]>
65
45
  }[keyof TSchema['_MutationDefMapType']]
66
46
 
67
- export const isPartialMutationEvent = (
68
- mutationEvent: AnyDecoded | PartialAnyDecoded,
69
- ): mutationEvent is PartialAnyDecoded => 'id' in mutationEvent === false && 'parentId' in mutationEvent === false
47
+ export const isPartialMutationEvent = (mutationEvent: Any | PartialAny): mutationEvent is PartialAny =>
48
+ 'id' in mutationEvent === false && 'parentId' in mutationEvent === false
70
49
 
71
50
  export type ForMutationDefRecord<TMutationsDefRecord extends MutationDefRecord> = Schema.Schema<
72
51
  {
@@ -126,21 +105,33 @@ export const makeMutationEventPartialSchema = <TSchema extends LiveStoreSchema>(
126
105
  args: def.schema,
127
106
  }),
128
107
  ),
129
- ).annotations({ title: 'MutationEventPartial' }) as any
108
+ ).annotations({ title: 'MutationEventSchemaPartial' }) as any
130
109
 
131
110
  export const makeMutationEventSchemaMemo = memoizeByRef(makeMutationEventSchema)
132
111
 
133
- /** Equivalent to AnyEncoded but with a meta field and some convenience methods */
112
+ export const Any = Schema.Struct({
113
+ mutation: Schema.String,
114
+ args: Schema.Any,
115
+ id: EventId.EventId,
116
+ parentId: EventId.EventId,
117
+ }).annotations({ title: 'MutationEvent.Any' })
118
+
119
+ export const DecodedAny = Schema.typeSchema(Any).annotations({
120
+ title: 'MutationEvent.DecodedAny',
121
+ })
122
+
123
+ export const EncodedAny = Schema.encodedSchema(Any).annotations({
124
+ title: 'MutationEvent.EncodedAny',
125
+ })
126
+
127
+ /** Equivalent to EncodedAny but with a meta field and some convenience methods */
134
128
  export class EncodedWithMeta extends Schema.Class<EncodedWithMeta>('MutationEvent.EncodedWithMeta')({
135
129
  mutation: Schema.String,
136
130
  args: Schema.Any,
137
131
  id: EventId.EventId,
138
132
  parentId: EventId.EventId,
139
- // TODO get rid of `meta` again by cleaning up the usage implementations
140
133
  meta: Schema.optionalWith(
141
- Schema.Any as Schema.Schema<{
142
- sessionChangeset?: Uint8Array
143
- }>,
134
+ Schema.Any as Schema.Schema<{ deferred?: Deferred.Deferred<void>; sessionChangeset?: Uint8Array }>,
144
135
  { default: () => ({}) },
145
136
  ),
146
137
  }) {
@@ -158,21 +149,8 @@ export class EncodedWithMeta extends Schema.Class<EncodedWithMeta>('MutationEven
158
149
  rebase = (parentId: EventId.EventId, isLocal: boolean) =>
159
150
  new EncodedWithMeta({
160
151
  ...this,
161
- ...EventId.nextPair(parentId, isLocal),
152
+ ...EventId.nextPair(this.id, isLocal),
162
153
  })
163
-
164
- static fromGlobal = (mutationEvent: AnyEncodedGlobal) =>
165
- new EncodedWithMeta({
166
- ...mutationEvent,
167
- id: { global: mutationEvent.id, local: EventId.localDefault },
168
- parentId: { global: mutationEvent.parentId, local: EventId.localDefault },
169
- })
170
-
171
- toGlobal = (): AnyEncodedGlobal => ({
172
- ...this,
173
- id: this.id.global,
174
- parentId: this.parentId.global,
175
- })
176
154
  }
177
155
 
178
156
  export const isEqualEncoded = (a: AnyEncoded, b: AnyEncoded) =>
@@ -1,7 +1,6 @@
1
1
  import { type SqliteAst as __SqliteAst, SqliteDsl } from '@livestore/db-schema'
2
2
  import { Schema } from '@livestore/utils/effect'
3
3
 
4
- import * as EventId from './EventId.js'
5
4
  import type { FromTable } from './table-def.js'
6
5
  import { table } from './table-def.js'
7
6
 
@@ -47,15 +46,14 @@ export const sessionChangesetMetaTable = table(
47
46
  SESSION_CHANGESET_META_TABLE,
48
47
  {
49
48
  // TODO bring back primary key
50
- idGlobal: SqliteDsl.integer({ schema: EventId.GlobalEventId }),
51
- idLocal: SqliteDsl.integer({ schema: EventId.LocalEventId }),
52
- changeset: SqliteDsl.blob({ nullable: true }),
49
+ idGlobal: SqliteDsl.integer({}),
50
+ idLocal: SqliteDsl.integer({}),
51
+ // idGlobal: SqliteDsl.integer({ primaryKey: true }),
52
+ // idLocal: SqliteDsl.integer({ primaryKey: true }),
53
+ changeset: SqliteDsl.blob({}),
53
54
  debug: SqliteDsl.json({ nullable: true }),
54
55
  },
55
- {
56
- disableAutomaticIdColumn: true,
57
- indexes: [{ columns: ['idGlobal', 'idLocal'], name: 'idx_session_changeset_id' }],
58
- },
56
+ { disableAutomaticIdColumn: true },
59
57
  )
60
58
 
61
59
  export type SessionChangesetMetaRow = FromTable.RowDecoded<typeof sessionChangesetMetaTable>
@@ -72,22 +70,16 @@ export const MUTATION_LOG_META_TABLE = 'mutation_log'
72
70
  export const mutationLogMetaTable = table(
73
71
  MUTATION_LOG_META_TABLE,
74
72
  {
75
- idGlobal: SqliteDsl.integer({ primaryKey: true, schema: EventId.GlobalEventId }),
76
- idLocal: SqliteDsl.integer({ primaryKey: true, schema: EventId.LocalEventId }),
77
- parentIdGlobal: SqliteDsl.integer({ schema: EventId.GlobalEventId }),
78
- parentIdLocal: SqliteDsl.integer({ schema: EventId.LocalEventId }),
73
+ idGlobal: SqliteDsl.integer({ primaryKey: true }),
74
+ idLocal: SqliteDsl.integer({ primaryKey: true }),
75
+ parentIdGlobal: SqliteDsl.integer({}),
76
+ parentIdLocal: SqliteDsl.integer({}),
79
77
  mutation: SqliteDsl.text({}),
80
78
  argsJson: SqliteDsl.text({ schema: Schema.parseJson(Schema.Any) }),
81
79
  schemaHash: SqliteDsl.integer({}),
82
80
  syncMetadataJson: SqliteDsl.text({ schema: Schema.parseJson(Schema.Option(Schema.JsonValue)) }),
83
81
  },
84
- {
85
- disableAutomaticIdColumn: true,
86
- indexes: [
87
- { columns: ['idGlobal'], name: 'idx_idGlobal' },
88
- { columns: ['idGlobal', 'idLocal'], name: 'idx_mutationlog_id' },
89
- ],
90
- },
82
+ { disableAutomaticIdColumn: true, indexes: [] },
91
83
  )
92
84
 
93
85
  export type MutationLogMetaRow = FromTable.RowDecoded<typeof mutationLogMetaTable>
@@ -1,4 +1,4 @@
1
- import type { SqliteDb } from '../adapter-types.js'
1
+ import type { SynchronousDatabase } from '../adapter-types.js'
2
2
  import type { ParamsObject } from '../util.js'
3
3
  import { prepareBindValues } from '../util.js'
4
4
 
@@ -6,7 +6,7 @@ import { prepareBindValues } from '../util.js'
6
6
  // will require proper scope-aware cleanup etc (for testing and apps with multiple LiveStore instances)
7
7
  // const cachedStmts = new Map<string, PreparedStatement>()
8
8
 
9
- export const dbExecute = (db: SqliteDb, queryStr: string, bindValues?: ParamsObject) => {
9
+ export const dbExecute = (db: SynchronousDatabase, queryStr: string, bindValues?: ParamsObject) => {
10
10
  // let stmt = cachedStmts.get(queryStr)
11
11
  // if (!stmt) {
12
12
  const stmt = db.prepare(queryStr)
@@ -20,7 +20,7 @@ export const dbExecute = (db: SqliteDb, queryStr: string, bindValues?: ParamsObj
20
20
  stmt.finalize()
21
21
  }
22
22
 
23
- export const dbSelect = <T>(db: SqliteDb, queryStr: string, bindValues?: ParamsObject) => {
23
+ export const dbSelect = <T>(db: SynchronousDatabase, queryStr: string, bindValues?: ParamsObject) => {
24
24
  // let stmt = cachedStmts.get(queryStr)
25
25
  // if (!stmt) {
26
26
  const stmt = db.prepare(queryStr)
@@ -2,7 +2,7 @@ import { SqliteAst, SqliteDsl } from '@livestore/db-schema'
2
2
  import { memoizeByStringifyArgs } from '@livestore/utils'
3
3
  import { Effect, Schema as EffectSchema } from '@livestore/utils/effect'
4
4
 
5
- import type { SqliteDb } from '../adapter-types.js'
5
+ import type { SynchronousDatabase } from '../adapter-types.js'
6
6
  import type { LiveStoreSchema } from '../schema/mod.js'
7
7
  import type { SchemaMetaRow, SchemaMutationsMetaRow } from '../schema/system-tables.js'
8
8
  import {
@@ -19,7 +19,7 @@ import { validateSchema } from './validate-mutation-defs.js'
19
19
 
20
20
  const getMemoizedTimestamp = memoizeByStringifyArgs(() => new Date().toISOString())
21
21
 
22
- export const makeSchemaManager = (db: SqliteDb): Effect.Effect<SchemaManager> =>
22
+ export const makeSchemaManager = (db: SynchronousDatabase): Effect.Effect<SchemaManager> =>
23
23
  Effect.gen(function* () {
24
24
  yield* migrateTable({
25
25
  db,
@@ -51,7 +51,7 @@ export const migrateDb = ({
51
51
  schema,
52
52
  onProgress,
53
53
  }: {
54
- db: SqliteDb
54
+ db: SynchronousDatabase
55
55
  schema: LiveStoreSchema
56
56
  onProgress?: (opts: { done: number; total: number }) => Effect.Effect<void>
57
57
  }) =>
@@ -116,7 +116,7 @@ export const migrateTable = ({
116
116
  behaviour,
117
117
  skipMetaTable = false,
118
118
  }: {
119
- db: SqliteDb
119
+ db: SynchronousDatabase
120
120
  tableAst: SqliteAst.Table
121
121
  schemaHash?: number
122
122
  behaviour: 'drop-and-recreate' | 'create-if-not-exists'
@@ -129,10 +129,10 @@ export const migrateTable = ({
129
129
 
130
130
  if (behaviour === 'drop-and-recreate') {
131
131
  // TODO need to possibly handle cascading deletes due to foreign keys
132
- dbExecute(db, sql`drop table if exists '${tableName}'`)
133
- dbExecute(db, sql`create table if not exists '${tableName}' (${columnSpec}) strict`)
132
+ dbExecute(db, sql`drop table if exists ${tableName}`)
133
+ dbExecute(db, sql`create table if not exists ${tableName} (${columnSpec}) strict`)
134
134
  } else if (behaviour === 'create-if-not-exists') {
135
- dbExecute(db, sql`create table if not exists '${tableName}' (${columnSpec}) strict`)
135
+ dbExecute(db, sql`create table if not exists ${tableName} (${columnSpec}) strict`)
136
136
  }
137
137
 
138
138
  for (const index of tableAst.indexes) {
@@ -162,11 +162,11 @@ export const migrateTable = ({
162
162
 
163
163
  const createIndexFromDefinition = (tableName: string, index: SqliteAst.Index) => {
164
164
  const uniqueStr = index.unique ? 'UNIQUE' : ''
165
- return sql`create ${uniqueStr} index if not exists '${index.name}' on '${tableName}' (${index.columns.join(', ')})`
165
+ return sql`create ${uniqueStr} index if not exists ${index.name} on ${tableName} (${index.columns.join(', ')})`
166
166
  }
167
167
 
168
168
  export const makeColumnSpec = (tableAst: SqliteAst.Table) => {
169
- const primaryKeys = tableAst.columns.filter((_) => _.primaryKey).map((_) => `'${_.name}'`)
169
+ const primaryKeys = tableAst.columns.filter((_) => _.primaryKey).map((_) => _.name)
170
170
  const columnDefStrs = tableAst.columns.map(toSqliteColumnSpec)
171
171
  if (primaryKeys.length > 0) {
172
172
  columnDefStrs.push(`PRIMARY KEY (${primaryKeys.join(', ')})`)
@@ -191,5 +191,5 @@ const toSqliteColumnSpec = (column: SqliteAst.Column) => {
191
191
  return `default ${encodedDefaultValue}`
192
192
  })()
193
193
 
194
- return `'${column.name}' ${columnTypeStr} ${nullableStr} ${defaultValueStr}`
194
+ return `${column.name} ${columnTypeStr} ${nullableStr} ${defaultValueStr}`
195
195
  }