@livestore/common 0.0.54-dev.21 → 0.0.54-dev.23
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.
- package/dist/.tsbuildinfo +1 -1
- package/dist/__tests__/fixture.d.ts +0 -2
- package/dist/__tests__/fixture.d.ts.map +1 -1
- package/dist/adapter-types.d.ts +75 -16
- package/dist/adapter-types.d.ts.map +1 -1
- package/dist/adapter-types.js +18 -0
- package/dist/adapter-types.js.map +1 -1
- package/dist/debug-info.d.ts +8 -8
- package/dist/devtools/devtools-messages.d.ts +54 -35
- package/dist/devtools/devtools-messages.d.ts.map +1 -1
- package/dist/devtools/devtools-messages.js +38 -28
- package/dist/devtools/devtools-messages.js.map +1 -1
- package/dist/devtools/devtools-window-message.d.ts +26 -0
- package/dist/devtools/devtools-window-message.d.ts.map +1 -0
- package/dist/devtools/devtools-window-message.js +30 -0
- package/dist/devtools/devtools-window-message.js.map +1 -0
- package/dist/devtools/index.d.ts +1 -0
- package/dist/devtools/index.d.ts.map +1 -1
- package/dist/devtools/index.js +1 -0
- package/dist/devtools/index.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/rehydrate-from-mutationlog.d.ts +8 -3
- package/dist/rehydrate-from-mutationlog.d.ts.map +1 -1
- package/dist/rehydrate-from-mutationlog.js +71 -56
- package/dist/rehydrate-from-mutationlog.js.map +1 -1
- package/dist/schema/system-tables.d.ts +0 -5
- package/dist/schema/system-tables.d.ts.map +1 -1
- package/dist/schema/table-def.d.ts +0 -2
- package/dist/schema/table-def.d.ts.map +1 -1
- package/dist/schema/table-def.js +0 -1
- package/dist/schema/table-def.js.map +1 -1
- package/dist/schema-management/migrations.d.ts +9 -4
- package/dist/schema-management/migrations.d.ts.map +1 -1
- package/dist/schema-management/migrations.js +24 -13
- package/dist/schema-management/migrations.js.map +1 -1
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +3 -0
- package/dist/version.js.map +1 -0
- package/package.json +3 -3
- package/src/adapter-types.ts +53 -15
- package/src/devtools/devtools-messages.ts +67 -47
- package/src/devtools/devtools-window-message.ts +25 -0
- package/src/devtools/index.ts +1 -0
- package/src/index.ts +1 -0
- package/src/rehydrate-from-mutationlog.ts +100 -64
- package/src/schema/table-def.ts +0 -4
- package/src/schema-management/migrations.ts +104 -84
- package/src/version.ts +3 -0
package/src/adapter-types.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import type { Stream, SubscriptionRef
|
|
1
|
+
import type { Effect, Queue, Stream, SubscriptionRef } from '@livestore/utils/effect'
|
|
2
2
|
import { Schema } from '@livestore/utils/effect'
|
|
3
|
-
import type * as otel from '@opentelemetry/api'
|
|
4
3
|
|
|
5
4
|
import type { LiveStoreSchema, MutationEvent } from './schema/index.js'
|
|
6
5
|
import type { PreparedBindValues } from './util.js'
|
|
@@ -22,7 +21,6 @@ export type InMemoryDatabase = {
|
|
|
22
21
|
_tag: 'InMemoryDatabase'
|
|
23
22
|
prepare(queryStr: string): PreparedStatement
|
|
24
23
|
execute(queryStr: string, bindValues: PreparedBindValues | undefined): GetRowsChangedCount
|
|
25
|
-
dangerouslyReset(): Promise<void>
|
|
26
24
|
export(): Uint8Array
|
|
27
25
|
}
|
|
28
26
|
|
|
@@ -38,27 +36,54 @@ export type NetworkStatus = {
|
|
|
38
36
|
timestampMs: number
|
|
39
37
|
}
|
|
40
38
|
|
|
39
|
+
export const BootStateProgress = Schema.Struct({
|
|
40
|
+
done: Schema.Number,
|
|
41
|
+
total: Schema.Number,
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
export const BootStatus = Schema.Union(
|
|
45
|
+
Schema.Struct({ stage: Schema.Literal('loading') }),
|
|
46
|
+
Schema.Struct({ stage: Schema.Literal('migrating'), progress: BootStateProgress }),
|
|
47
|
+
Schema.Struct({ stage: Schema.Literal('rehydrating'), progress: BootStateProgress }),
|
|
48
|
+
Schema.Struct({ stage: Schema.Literal('syncing'), progress: BootStateProgress }),
|
|
49
|
+
Schema.Struct({ stage: Schema.Literal('done') }),
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
export type BootStatus = typeof BootStatus.Type
|
|
53
|
+
|
|
41
54
|
export type Coordinator = {
|
|
55
|
+
isShutdownRef: { current: boolean }
|
|
42
56
|
devtools: {
|
|
57
|
+
enabled: boolean
|
|
43
58
|
channelId: string
|
|
59
|
+
/**
|
|
60
|
+
* Returns a dedicated message port for the store which is established over the message port passed in
|
|
61
|
+
*/
|
|
62
|
+
connect: (options: {
|
|
63
|
+
port: MessagePort
|
|
64
|
+
connectionId: string
|
|
65
|
+
}) => Effect.Effect<{ storeMessagePort: MessagePort }, UnexpectedError>
|
|
44
66
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
67
|
+
// TODO is exposing the lock status really needed (or only relevant for web adapter?)
|
|
68
|
+
lockStatus: SubscriptionRef.SubscriptionRef<LockStatus>
|
|
69
|
+
syncMutations: Stream.Stream<MutationEvent.AnyEncoded, UnexpectedError>
|
|
70
|
+
execute(queryStr: string, bindValues: PreparedBindValues | undefined): Effect.Effect<void, UnexpectedError>
|
|
71
|
+
mutate(mutationEventEncoded: MutationEvent.Any, options: { persisted: boolean }): Effect.Effect<void, UnexpectedError>
|
|
72
|
+
dangerouslyReset(mode: ResetMode): Effect.Effect<void, UnexpectedError>
|
|
73
|
+
export: Effect.Effect<Uint8Array | undefined, UnexpectedError>
|
|
51
74
|
/**
|
|
52
75
|
* This is different from `export` since in `getInitialSnapshot` is usually the place for migrations etc to happen
|
|
53
76
|
*/
|
|
54
|
-
getInitialSnapshot
|
|
55
|
-
getMutationLogData
|
|
56
|
-
shutdown
|
|
77
|
+
getInitialSnapshot: Effect.Effect<Uint8Array, UnexpectedError>
|
|
78
|
+
getMutationLogData: Effect.Effect<Uint8Array, UnexpectedError>
|
|
79
|
+
shutdown: Effect.Effect<void, UnexpectedError>
|
|
57
80
|
networkStatus: SubscriptionRef.SubscriptionRef<NetworkStatus>
|
|
58
81
|
}
|
|
59
82
|
|
|
60
83
|
export type GetRowsChangedCount = () => number
|
|
61
84
|
|
|
85
|
+
export type LockStatus = 'has-lock' | 'no-lock'
|
|
86
|
+
|
|
62
87
|
export type BootDb = {
|
|
63
88
|
_tag: 'BootDb'
|
|
64
89
|
execute(queryStr: string, bindValues?: PreparedBindValues): void
|
|
@@ -67,6 +92,19 @@ export type BootDb = {
|
|
|
67
92
|
txn(callback: () => void): void
|
|
68
93
|
}
|
|
69
94
|
|
|
95
|
+
export class UnexpectedError extends Schema.TaggedError<UnexpectedError>()('LiveStore.UnexpectedError', {
|
|
96
|
+
cause: Schema.AnyError,
|
|
97
|
+
}) {}
|
|
98
|
+
|
|
99
|
+
export class SqliteError extends Schema.TaggedError<SqliteError>()('LiveStore.SqliteError', {
|
|
100
|
+
sql: Schema.String,
|
|
101
|
+
bindValues: Schema.Record(Schema.String, Schema.Any),
|
|
102
|
+
/** The SQLite result code */
|
|
103
|
+
code: Schema.Number,
|
|
104
|
+
/** The original SQLite3 error */
|
|
105
|
+
cause: Schema.AnyError,
|
|
106
|
+
}) {}
|
|
107
|
+
|
|
70
108
|
// TODO possibly allow a combination of these options
|
|
71
109
|
// TODO allow a way to stream the migration progress back to the app
|
|
72
110
|
export type MigrationOptions<TSchema extends LiveStoreSchema = LiveStoreSchema> =
|
|
@@ -107,7 +145,7 @@ export type MigrationOptionsFromMutationLog<TSchema extends LiveStoreSchema = Li
|
|
|
107
145
|
}
|
|
108
146
|
|
|
109
147
|
export type StoreAdapterFactory = (opts: {
|
|
110
|
-
otelTracer: otel.Tracer
|
|
111
|
-
otelContext: otel.Context
|
|
112
148
|
schema: LiveStoreSchema
|
|
113
|
-
|
|
149
|
+
devtoolsEnabled: boolean
|
|
150
|
+
bootStatusQueue: Queue.Queue<BootStatus>
|
|
151
|
+
}) => Effect.Effect<StoreAdapter, UnexpectedError>
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Schema } from '@livestore/utils/effect'
|
|
3
|
-
import { type SqliteDsl as __SqliteDsl } from 'effect-db-schema'
|
|
1
|
+
import { Schema, Transferable } from '@livestore/utils/effect'
|
|
4
2
|
|
|
5
3
|
import { NetworkStatus } from '../adapter-types.js'
|
|
6
4
|
import { DebugInfo } from '../debug-info.js'
|
|
7
5
|
import { mutationEventSchemaEncodedAny } from '../schema/mutations.js'
|
|
8
6
|
import { PreparedBindValues } from '../util.js'
|
|
7
|
+
import { liveStoreVersion as pkgVersion } from '../version.js'
|
|
9
8
|
|
|
10
9
|
const requestId = Schema.String
|
|
11
10
|
const channelId = Schema.String
|
|
@@ -20,20 +19,21 @@ export class SnapshotReq extends Schema.TaggedStruct('LSD.SnapshotReq', {
|
|
|
20
19
|
export class SnapshotRes extends Schema.TaggedStruct('LSD.SnapshotRes', {
|
|
21
20
|
liveStoreVersion,
|
|
22
21
|
requestId,
|
|
23
|
-
snapshot:
|
|
22
|
+
snapshot: Transferable.Uint8Array,
|
|
24
23
|
}).annotations({ identifier: 'LSD.SnapshotRes' }) {}
|
|
25
24
|
|
|
26
|
-
export class
|
|
25
|
+
export class LoadDatabaseFileReq extends Schema.TaggedStruct('LSD.LoadDatabaseFileReq', {
|
|
27
26
|
liveStoreVersion,
|
|
28
27
|
requestId,
|
|
29
28
|
channelId,
|
|
30
|
-
|
|
31
|
-
}).annotations({ identifier: 'LSD.
|
|
29
|
+
data: Transferable.Uint8Array,
|
|
30
|
+
}).annotations({ identifier: 'LSD.LoadDatabaseFileReq' }) {}
|
|
32
31
|
|
|
33
|
-
export class
|
|
32
|
+
export class LoadDatabaseFileRes extends Schema.TaggedStruct('LSD.LoadDatabaseFileRes', {
|
|
34
33
|
liveStoreVersion,
|
|
35
34
|
requestId,
|
|
36
|
-
|
|
35
|
+
status: Schema.Literal('ok', 'unsupported-file', 'unsupported-database'),
|
|
36
|
+
}).annotations({ identifier: 'LSD.LoadDatabaseFileRes' }) {}
|
|
37
37
|
|
|
38
38
|
export class DebugInfoReq extends Schema.TaggedStruct('LSD.DebugInfoReq', {
|
|
39
39
|
liveStoreVersion,
|
|
@@ -102,21 +102,9 @@ export class MutationLogRes extends Schema.TaggedStruct('LSD.MutationLogRes', {
|
|
|
102
102
|
liveStoreVersion,
|
|
103
103
|
requestId,
|
|
104
104
|
channelId,
|
|
105
|
-
mutationLog:
|
|
105
|
+
mutationLog: Transferable.Uint8Array,
|
|
106
106
|
}).annotations({ identifier: 'LSD.MutationLogRes' }) {}
|
|
107
107
|
|
|
108
|
-
export class LoadMutationLogReq extends Schema.TaggedStruct('LSD.LoadMutationLogReq', {
|
|
109
|
-
liveStoreVersion,
|
|
110
|
-
requestId,
|
|
111
|
-
channelId,
|
|
112
|
-
mutationLog: Schema.Uint8Array,
|
|
113
|
-
}).annotations({ identifier: 'LSD.LoadMutationLogReq' }) {}
|
|
114
|
-
|
|
115
|
-
export class LoadMutationLogRes extends Schema.TaggedStruct('LSD.LoadMutationLogRes', {
|
|
116
|
-
liveStoreVersion,
|
|
117
|
-
requestId,
|
|
118
|
-
}).annotations({ identifier: 'LSD.LoadMutationLogRes' }) {}
|
|
119
|
-
|
|
120
108
|
export class ReactivityGraphSubscribe extends Schema.TaggedStruct('LSD.ReactivityGraphSubscribe', {
|
|
121
109
|
liveStoreVersion,
|
|
122
110
|
requestId,
|
|
@@ -178,6 +166,19 @@ export class ResetAllDataRes extends Schema.TaggedStruct('LSD.ResetAllDataRes',
|
|
|
178
166
|
requestId,
|
|
179
167
|
}).annotations({ identifier: 'LSD.ResetAllDataRes' }) {}
|
|
180
168
|
|
|
169
|
+
export class MessagePortForStoreReq extends Schema.TaggedStruct('LSD.MessagePortForStoreReq', {
|
|
170
|
+
liveStoreVersion,
|
|
171
|
+
requestId,
|
|
172
|
+
channelId,
|
|
173
|
+
}).annotations({ identifier: 'LSD.MessagePortForStoreReq' }) {}
|
|
174
|
+
|
|
175
|
+
export class MessagePortForStoreRes extends Schema.TaggedStruct('LSD.MessagePortForStoreRes', {
|
|
176
|
+
liveStoreVersion,
|
|
177
|
+
requestId,
|
|
178
|
+
channelId,
|
|
179
|
+
port: Transferable.MessagePort,
|
|
180
|
+
}).annotations({ identifier: 'LSD.MessagePortForStoreRes' }) {}
|
|
181
|
+
|
|
181
182
|
export class NetworkStatusChanged extends Schema.TaggedStruct('LSD.NetworkStatusChanged', {
|
|
182
183
|
liveStoreVersion,
|
|
183
184
|
channelId,
|
|
@@ -204,11 +205,33 @@ export class Disconnect extends Schema.TaggedStruct('LSD.Disconnect', {
|
|
|
204
205
|
channelId,
|
|
205
206
|
}).annotations({ identifier: 'LSD.Disconnect' }) {}
|
|
206
207
|
|
|
207
|
-
export
|
|
208
|
+
export class Ping extends Schema.TaggedStruct('LSD.Ping', {
|
|
209
|
+
liveStoreVersion,
|
|
210
|
+
requestId,
|
|
211
|
+
channelId,
|
|
212
|
+
}).annotations({ identifier: 'LSD.Ping' }) {}
|
|
213
|
+
|
|
214
|
+
export class Pong extends Schema.TaggedStruct('LSD.Pong', {
|
|
215
|
+
liveStoreVersion,
|
|
216
|
+
requestId,
|
|
217
|
+
}).annotations({ identifier: 'LSD.Pong' }) {}
|
|
218
|
+
|
|
219
|
+
export const MessageToAppHostCoordinator = Schema.Union(
|
|
208
220
|
SnapshotReq,
|
|
209
|
-
|
|
221
|
+
LoadDatabaseFileReq,
|
|
210
222
|
MutationLogReq,
|
|
211
|
-
|
|
223
|
+
ResetAllDataReq,
|
|
224
|
+
MessagePortForStoreRes,
|
|
225
|
+
DevtoolsReady,
|
|
226
|
+
Disconnect,
|
|
227
|
+
DevtoolsConnected,
|
|
228
|
+
RunMutationReq,
|
|
229
|
+
Ping,
|
|
230
|
+
).annotations({ identifier: 'LSD.MessageToAppHostCoordinator' })
|
|
231
|
+
|
|
232
|
+
export type MessageToAppHostCoordinator = typeof MessageToAppHostCoordinator.Type
|
|
233
|
+
|
|
234
|
+
export const MessageToAppHostStore = Schema.Union(
|
|
212
235
|
DebugInfoReq,
|
|
213
236
|
DebugInfoResetReq,
|
|
214
237
|
DebugInfoRerunQueryReq,
|
|
@@ -216,37 +239,34 @@ export const MessageToAppHost = Schema.Union(
|
|
|
216
239
|
ReactivityGraphUnsubscribe,
|
|
217
240
|
LiveQueriesSubscribe,
|
|
218
241
|
LiveQueriesUnsubscribe,
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
Disconnect,
|
|
222
|
-
DevtoolsConnected,
|
|
223
|
-
RunMutationReq,
|
|
224
|
-
).annotations({ identifier: 'LSD.MessageToAppHost' })
|
|
242
|
+
// Ping,
|
|
243
|
+
).annotations({ identifier: 'LSD.MessageToAppHostStore' })
|
|
225
244
|
|
|
226
|
-
export type
|
|
245
|
+
export type MessageToAppHostStore = typeof MessageToAppHostStore.Type
|
|
227
246
|
|
|
228
|
-
export const
|
|
247
|
+
export const MessageFromAppHostCoordinator = Schema.Union(
|
|
229
248
|
SnapshotRes,
|
|
230
|
-
|
|
249
|
+
LoadDatabaseFileRes,
|
|
231
250
|
MutationLogRes,
|
|
232
|
-
LoadMutationLogRes,
|
|
233
|
-
DebugInfoRes,
|
|
234
|
-
DebugInfoResetRes,
|
|
235
|
-
DebugInfoRerunQueryRes,
|
|
236
|
-
ReactivityGraphRes,
|
|
237
|
-
LiveQueriesRes,
|
|
238
251
|
ResetAllDataRes,
|
|
252
|
+
MessagePortForStoreReq,
|
|
239
253
|
Disconnect,
|
|
240
254
|
MutationBroadcast,
|
|
241
255
|
AppHostReady,
|
|
242
256
|
NetworkStatusChanged,
|
|
243
257
|
RunMutationRes,
|
|
244
|
-
|
|
258
|
+
Pong,
|
|
259
|
+
).annotations({ identifier: 'LSD.MessageFromAppHostCoordinator' })
|
|
260
|
+
|
|
261
|
+
export type MessageFromAppHostCoordinator = typeof MessageFromAppHostCoordinator.Type
|
|
245
262
|
|
|
246
|
-
export
|
|
263
|
+
export const MessageFromAppHostStore = Schema.Union(
|
|
264
|
+
DebugInfoRes,
|
|
265
|
+
DebugInfoResetRes,
|
|
266
|
+
DebugInfoRerunQueryRes,
|
|
267
|
+
ReactivityGraphRes,
|
|
268
|
+
LiveQueriesRes,
|
|
269
|
+
// Pong,
|
|
270
|
+
).annotations({ identifier: 'LSD.MessageFromAppHostStore' })
|
|
247
271
|
|
|
248
|
-
|
|
249
|
-
export const makeBroadcastChannels = () => ({
|
|
250
|
-
fromAppHost: new BroadcastChannel(`livestore-devtools-from-app-host`),
|
|
251
|
-
toAppHost: new BroadcastChannel(`livestore-devtools-to-app-host`),
|
|
252
|
-
})
|
|
272
|
+
export type MessageFromAppHostStore = typeof MessageFromAppHostStore.Type
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Schema, Transferable } from '@livestore/utils/effect'
|
|
2
|
+
|
|
3
|
+
const channelId = Schema.String
|
|
4
|
+
|
|
5
|
+
export namespace DevtoolsWindowMessage {
|
|
6
|
+
/** Message is being created in contentscript-iframe, sent to contentscript and then sent to Store */
|
|
7
|
+
export class MessagePortReady extends Schema.TaggedStruct('LSD.WindowMessage.MessagePortForStore', {
|
|
8
|
+
port: Transferable.MessagePort,
|
|
9
|
+
channelId,
|
|
10
|
+
}) {}
|
|
11
|
+
|
|
12
|
+
export class ContentscriptListening extends Schema.TaggedStruct('LSD.WindowMessage.ContentscriptListening', {}) {}
|
|
13
|
+
|
|
14
|
+
// export class ContentscriptReady extends Schema.TaggedStruct('LSD.WindowMessage.ContentscriptReady', {
|
|
15
|
+
// channelId,
|
|
16
|
+
// }) {}
|
|
17
|
+
|
|
18
|
+
export class StoreReady extends Schema.TaggedStruct('LSD.WindowMessage.StoreReady', {
|
|
19
|
+
channelId,
|
|
20
|
+
}) {}
|
|
21
|
+
|
|
22
|
+
export class MessageForStore extends Schema.Union(MessagePortReady, ContentscriptListening) {}
|
|
23
|
+
|
|
24
|
+
export class MessageForContentscript extends Schema.Union(StoreReady) {}
|
|
25
|
+
}
|
package/src/devtools/index.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -1,91 +1,127 @@
|
|
|
1
1
|
import { shouldNeverHappen } from '@livestore/utils'
|
|
2
|
-
import { Schema } from '@livestore/utils/effect'
|
|
2
|
+
import { Chunk, Effect, Option, Schema, Stream } from '@livestore/utils/effect'
|
|
3
3
|
|
|
4
|
-
import type
|
|
4
|
+
import { type InMemoryDatabase, type MigrationOptionsFromMutationLog, SqliteError } from './adapter-types.js'
|
|
5
5
|
import { getExecArgsFromMutation } from './mutation.js'
|
|
6
6
|
import type { LiveStoreSchema, MutationLogMetaRow } from './schema/index.js'
|
|
7
7
|
import { MUTATION_LOG_META_TABLE } from './schema/index.js'
|
|
8
|
+
import type { PreparedBindValues } from './util.js'
|
|
9
|
+
import { sql } from './util.js'
|
|
8
10
|
|
|
9
|
-
export const rehydrateFromMutationLog =
|
|
11
|
+
export const rehydrateFromMutationLog = ({
|
|
10
12
|
logDb,
|
|
11
13
|
db,
|
|
12
14
|
schema,
|
|
13
15
|
migrationOptions,
|
|
16
|
+
onProgress,
|
|
14
17
|
}: {
|
|
15
18
|
logDb: InMemoryDatabase
|
|
16
19
|
db: InMemoryDatabase
|
|
17
20
|
schema: LiveStoreSchema
|
|
18
21
|
migrationOptions: MigrationOptionsFromMutationLog
|
|
19
|
-
}) =>
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const
|
|
23
|
-
|
|
22
|
+
onProgress: (_: { done: number; total: number }) => Effect.Effect<void>
|
|
23
|
+
}) =>
|
|
24
|
+
Effect.gen(function* () {
|
|
25
|
+
const mutationsCount = logDb
|
|
26
|
+
.prepare(`SELECT COUNT(*) AS count FROM ${MUTATION_LOG_META_TABLE}`)
|
|
27
|
+
.select<{ count: number }>(undefined)[0]!.count
|
|
24
28
|
|
|
25
|
-
|
|
29
|
+
const processMutation = (row: MutationLogMetaRow) =>
|
|
30
|
+
Effect.gen(function* () {
|
|
31
|
+
const mutationDef = schema.mutations.get(row.mutation) ?? shouldNeverHappen(`Unknown mutation ${row.mutation}`)
|
|
26
32
|
|
|
27
|
-
|
|
28
|
-
const mutationDef = schema.mutations.get(row.mutation) ?? shouldNeverHappen(`Unknown mutation ${row.mutation}`)
|
|
33
|
+
if (migrationOptions.excludeMutations?.has(row.mutation) === true) return
|
|
29
34
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
console.warn(`Schema hash mismatch for mutation ${row.mutation}. Trying to apply mutation anyway.`)
|
|
34
|
-
}
|
|
35
|
+
if (Schema.hash(mutationDef.schema) !== row.schemaHash) {
|
|
36
|
+
console.warn(`Schema hash mismatch for mutation ${row.mutation}. Trying to apply mutation anyway.`)
|
|
37
|
+
}
|
|
35
38
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
+
const argsDecodedEither = Schema.decodeUnknownEither(Schema.parseJson(mutationDef.schema))(row.argsJson)
|
|
40
|
+
if (argsDecodedEither._tag === 'Left') {
|
|
41
|
+
return shouldNeverHappen(`\
|
|
39
42
|
There was an error decoding the persisted mutation event args for mutation "${row.mutation}".
|
|
40
43
|
This likely means the schema has changed in an incompatible way.
|
|
41
44
|
|
|
42
45
|
Error: ${argsDecodedEither.left}
|
|
43
46
|
`)
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const mutationEventDecoded = {
|
|
50
|
+
id: row.id,
|
|
51
|
+
mutation: row.mutation,
|
|
52
|
+
args: argsDecodedEither.right,
|
|
53
|
+
}
|
|
54
|
+
// const argsEncoded = JSON.parse(row.args_json)
|
|
55
|
+
// const mutationSqlRes =
|
|
56
|
+
// typeof mutation.sql === 'string'
|
|
57
|
+
// ? mutation.sql
|
|
58
|
+
// : mutation.sql(Schema.decodeUnknownSync(mutation.schema)(argsEncoded))
|
|
59
|
+
// const mutationSql = typeof mutationSqlRes === 'string' ? mutationSqlRes : mutationSqlRes.sql
|
|
60
|
+
// const bindValues = typeof mutationSqlRes === 'string' ? argsEncoded : mutationSqlRes.bindValues
|
|
61
|
+
|
|
62
|
+
const execArgsArr = getExecArgsFromMutation({ mutationDef, mutationEventDecoded })
|
|
63
|
+
|
|
64
|
+
for (const { statementSql, bindValues } of execArgsArr) {
|
|
65
|
+
try {
|
|
66
|
+
// TODO cache prepared statements for mutations
|
|
67
|
+
const getRowsChanged = db.execute(statementSql, bindValues)
|
|
68
|
+
if (
|
|
69
|
+
import.meta.env.DEV &&
|
|
70
|
+
getRowsChanged() === 0 &&
|
|
71
|
+
migrationOptions.logging?.excludeAffectedRows?.(statementSql) !== true
|
|
72
|
+
) {
|
|
73
|
+
console.warn(`Mutation "${mutationDef.name}" did not affect any rows:`, statementSql, bindValues)
|
|
74
|
+
}
|
|
75
|
+
// console.log(`Re-executed mutation ${mutationSql}`, bindValues)
|
|
76
|
+
} catch (e) {
|
|
77
|
+
yield* new SqliteError({
|
|
78
|
+
sql: statementSql,
|
|
79
|
+
bindValues,
|
|
80
|
+
code: (e as any).resultCode,
|
|
81
|
+
cause: e,
|
|
82
|
+
})
|
|
70
83
|
}
|
|
71
|
-
// console.log(`Re-executed mutation ${mutationSql}`, bindValues)
|
|
72
|
-
} catch (e) {
|
|
73
|
-
console.error(`Error executing migration for mutation ${statementSql}`, bindValues, e)
|
|
74
|
-
debugger
|
|
75
|
-
throw e
|
|
76
84
|
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
85
|
+
}).pipe(Effect.withSpan(`@livestore/common:rehydrateFromMutationLog:processMutation`))
|
|
86
|
+
|
|
87
|
+
const CHUNK_SIZE = 100
|
|
88
|
+
|
|
89
|
+
const stmt = logDb.prepare(sql`\
|
|
90
|
+
SELECT * FROM ${MUTATION_LOG_META_TABLE}
|
|
91
|
+
WHERE id > COALESCE($id, '')
|
|
92
|
+
ORDER BY id ASC
|
|
93
|
+
LIMIT ${CHUNK_SIZE}
|
|
94
|
+
`)
|
|
95
|
+
|
|
96
|
+
let processedMutations = 0
|
|
97
|
+
|
|
98
|
+
yield* Stream.unfoldChunk<Chunk.Chunk<MutationLogMetaRow> | { _tag: 'Initial ' }, MutationLogMetaRow>(
|
|
99
|
+
{ _tag: 'Initial ' },
|
|
100
|
+
(item) => {
|
|
101
|
+
// End stream if no more rows
|
|
102
|
+
if (Chunk.isChunk(item) && item.length === 0) return Option.none()
|
|
103
|
+
|
|
104
|
+
const lastId = Chunk.isChunk(item) ? Chunk.last(item).pipe(Option.getOrUndefined)?.id : undefined
|
|
105
|
+
const nextItem = Chunk.fromIterable(
|
|
106
|
+
stmt.select<MutationLogMetaRow>({ $id: lastId } as any as PreparedBindValues),
|
|
107
|
+
)
|
|
108
|
+
const prevItem = Chunk.isChunk(item) ? item : Chunk.empty()
|
|
109
|
+
return Option.some([prevItem, nextItem])
|
|
110
|
+
},
|
|
111
|
+
).pipe(
|
|
112
|
+
(_) => _,
|
|
113
|
+
Stream.bufferChunks({ capacity: 2 }),
|
|
114
|
+
Stream.tap((row) =>
|
|
115
|
+
Effect.gen(function* () {
|
|
116
|
+
yield* processMutation(row)
|
|
117
|
+
|
|
118
|
+
processedMutations++
|
|
119
|
+
yield* onProgress({ done: processedMutations, total: mutationsCount })
|
|
120
|
+
}),
|
|
121
|
+
),
|
|
122
|
+
Stream.runDrain,
|
|
89
123
|
)
|
|
90
|
-
}
|
|
91
|
-
|
|
124
|
+
}).pipe(
|
|
125
|
+
Effect.withPerformanceMeasure('@livestore/common:rehydrateFromMutationLog'),
|
|
126
|
+
Effect.withSpan('@livestore/common:rehydrateFromMutationLog'),
|
|
127
|
+
)
|
package/src/schema/table-def.ts
CHANGED
|
@@ -86,8 +86,6 @@ export type TableOptions = {
|
|
|
86
86
|
* @default false
|
|
87
87
|
*/
|
|
88
88
|
isSingleton: boolean
|
|
89
|
-
// TODO remove
|
|
90
|
-
dynamicRegistration: boolean
|
|
91
89
|
disableAutomaticIdColumn: boolean
|
|
92
90
|
/**
|
|
93
91
|
* Setting this to true will automatically derive insert, update and delete mutations for this table. Example:
|
|
@@ -139,7 +137,6 @@ export const table = <
|
|
|
139
137
|
|
|
140
138
|
const options_: TableOptions = {
|
|
141
139
|
isSingleton: options?.isSingleton ?? false,
|
|
142
|
-
dynamicRegistration: options?.dynamicRegistration ?? false,
|
|
143
140
|
disableAutomaticIdColumn: options?.disableAutomaticIdColumn ?? false,
|
|
144
141
|
deriveMutations:
|
|
145
142
|
options?.deriveMutations === true
|
|
@@ -239,7 +236,6 @@ type WithId<TColumns extends SqliteDsl.Columns, TOptions extends TableOptions> =
|
|
|
239
236
|
|
|
240
237
|
type WithDefaults<TOptionsInput extends TableOptionsInput, TIsSingleColumn extends boolean> = {
|
|
241
238
|
isSingleton: TOptionsInput['isSingleton'] extends true ? true : false
|
|
242
|
-
dynamicRegistration: TOptionsInput['dynamicRegistration'] extends true ? true : false
|
|
243
239
|
disableAutomaticIdColumn: TOptionsInput['disableAutomaticIdColumn'] extends true ? true : false
|
|
244
240
|
deriveMutations: TOptionsInput['deriveMutations'] extends true
|
|
245
241
|
? { enabled: true; localOnly: boolean }
|