@livestore/common 0.0.0-snapshot-909cdd1ac2fd591945c2be2b0f53e14d87f3c9d4
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 -0
- package/dist/__tests__/fixture.d.ts +72 -0
- package/dist/__tests__/fixture.d.ts.map +1 -0
- package/dist/__tests__/fixture.js +16 -0
- package/dist/__tests__/fixture.js.map +1 -0
- package/dist/adapter-types.d.ts +202 -0
- package/dist/adapter-types.d.ts.map +1 -0
- package/dist/adapter-types.js +49 -0
- package/dist/adapter-types.js.map +1 -0
- package/dist/bounded-collections.d.ts +36 -0
- package/dist/bounded-collections.d.ts.map +1 -0
- package/dist/bounded-collections.js +98 -0
- package/dist/bounded-collections.js.map +1 -0
- package/dist/debug-info.d.ts +122 -0
- package/dist/debug-info.d.ts.map +1 -0
- package/dist/debug-info.js +47 -0
- package/dist/debug-info.js.map +1 -0
- package/dist/derived-mutations.d.ts +109 -0
- package/dist/derived-mutations.d.ts.map +1 -0
- package/dist/derived-mutations.js +54 -0
- package/dist/derived-mutations.js.map +1 -0
- package/dist/derived-mutations.test.d.ts +2 -0
- package/dist/derived-mutations.test.d.ts.map +1 -0
- package/dist/derived-mutations.test.js +93 -0
- package/dist/derived-mutations.test.js.map +1 -0
- package/dist/devtools/devtools-bridge.d.ts +12 -0
- package/dist/devtools/devtools-bridge.d.ts.map +1 -0
- package/dist/devtools/devtools-bridge.js +2 -0
- package/dist/devtools/devtools-bridge.js.map +1 -0
- package/dist/devtools/devtools-messages.d.ts +705 -0
- package/dist/devtools/devtools-messages.d.ts.map +1 -0
- package/dist/devtools/devtools-messages.js +178 -0
- package/dist/devtools/devtools-messages.js.map +1 -0
- package/dist/devtools/devtools-window-message.d.ts +29 -0
- package/dist/devtools/devtools-window-message.d.ts.map +1 -0
- package/dist/devtools/devtools-window-message.js +33 -0
- package/dist/devtools/devtools-window-message.js.map +1 -0
- package/dist/devtools/index.d.ts +42 -0
- package/dist/devtools/index.d.ts.map +1 -0
- package/dist/devtools/index.js +49 -0
- package/dist/devtools/index.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/init-singleton-tables.d.ts +4 -0
- package/dist/init-singleton-tables.d.ts.map +1 -0
- package/dist/init-singleton-tables.js +16 -0
- package/dist/init-singleton-tables.js.map +1 -0
- package/dist/mutation.d.ts +13 -0
- package/dist/mutation.d.ts.map +1 -0
- package/dist/mutation.js +43 -0
- package/dist/mutation.js.map +1 -0
- package/dist/query-info.d.ts +47 -0
- package/dist/query-info.d.ts.map +1 -0
- package/dist/query-info.js +38 -0
- package/dist/query-info.js.map +1 -0
- package/dist/rehydrate-from-mutationlog.d.ts +14 -0
- package/dist/rehydrate-from-mutationlog.d.ts.map +1 -0
- package/dist/rehydrate-from-mutationlog.js +72 -0
- package/dist/rehydrate-from-mutationlog.js.map +1 -0
- package/dist/schema/index.d.ts +60 -0
- package/dist/schema/index.d.ts.map +1 -0
- package/dist/schema/index.js +66 -0
- package/dist/schema/index.js.map +1 -0
- package/dist/schema/mutations.d.ts +227 -0
- package/dist/schema/mutations.d.ts.map +1 -0
- package/dist/schema/mutations.js +68 -0
- package/dist/schema/mutations.js.map +1 -0
- package/dist/schema/schema-helpers.d.ts +4 -0
- package/dist/schema/schema-helpers.d.ts.map +1 -0
- package/dist/schema/schema-helpers.js +30 -0
- package/dist/schema/schema-helpers.js.map +1 -0
- package/dist/schema/system-tables.d.ts +331 -0
- package/dist/schema/system-tables.d.ts.map +1 -0
- package/dist/schema/system-tables.js +46 -0
- package/dist/schema/system-tables.js.map +1 -0
- package/dist/schema/table-def.d.ts +135 -0
- package/dist/schema/table-def.d.ts.map +1 -0
- package/dist/schema/table-def.js +70 -0
- package/dist/schema/table-def.js.map +1 -0
- package/dist/schema-management/common.d.ts +13 -0
- package/dist/schema-management/common.d.ts.map +1 -0
- package/dist/schema-management/common.js +25 -0
- package/dist/schema-management/common.js.map +1 -0
- package/dist/schema-management/migrations.d.ts +23 -0
- package/dist/schema-management/migrations.d.ts.map +1 -0
- package/dist/schema-management/migrations.js +116 -0
- package/dist/schema-management/migrations.js.map +1 -0
- package/dist/schema-management/validate-mutation-defs.d.ts +8 -0
- package/dist/schema-management/validate-mutation-defs.d.ts.map +1 -0
- package/dist/schema-management/validate-mutation-defs.js +39 -0
- package/dist/schema-management/validate-mutation-defs.js.map +1 -0
- package/dist/sql-queries/index.d.ts +4 -0
- package/dist/sql-queries/index.d.ts.map +1 -0
- package/dist/sql-queries/index.js +4 -0
- package/dist/sql-queries/index.js.map +1 -0
- package/dist/sql-queries/misc.d.ts +2 -0
- package/dist/sql-queries/misc.d.ts.map +1 -0
- package/dist/sql-queries/misc.js +2 -0
- package/dist/sql-queries/misc.js.map +1 -0
- package/dist/sql-queries/sql-queries.d.ts +72 -0
- package/dist/sql-queries/sql-queries.d.ts.map +1 -0
- package/dist/sql-queries/sql-queries.js +191 -0
- package/dist/sql-queries/sql-queries.js.map +1 -0
- package/dist/sql-queries/sql-query-builder.d.ts +47 -0
- package/dist/sql-queries/sql-query-builder.d.ts.map +1 -0
- package/dist/sql-queries/sql-query-builder.js +60 -0
- package/dist/sql-queries/sql-query-builder.js.map +1 -0
- package/dist/sql-queries/types.d.ts +50 -0
- package/dist/sql-queries/types.d.ts.map +1 -0
- package/dist/sql-queries/types.js +5 -0
- package/dist/sql-queries/types.js.map +1 -0
- package/dist/sync/index.d.ts +2 -0
- package/dist/sync/index.d.ts.map +1 -0
- package/dist/sync/index.js +2 -0
- package/dist/sync/index.js.map +1 -0
- package/dist/sync/next/compact-events.d.ts +15 -0
- package/dist/sync/next/compact-events.d.ts.map +1 -0
- package/dist/sync/next/compact-events.js +176 -0
- package/dist/sync/next/compact-events.js.map +1 -0
- package/dist/sync/next/facts.d.ts +37 -0
- package/dist/sync/next/facts.d.ts.map +1 -0
- package/dist/sync/next/facts.js +156 -0
- package/dist/sync/next/facts.js.map +1 -0
- package/dist/sync/next/graphology.d.ts +8 -0
- package/dist/sync/next/graphology.d.ts.map +1 -0
- package/dist/sync/next/graphology.js +36 -0
- package/dist/sync/next/graphology.js.map +1 -0
- package/dist/sync/next/graphology_.d.ts +3 -0
- package/dist/sync/next/graphology_.d.ts.map +1 -0
- package/dist/sync/next/graphology_.js +3 -0
- package/dist/sync/next/graphology_.js.map +1 -0
- package/dist/sync/next/history-dag.d.ts +30 -0
- package/dist/sync/next/history-dag.d.ts.map +1 -0
- package/dist/sync/next/history-dag.js +69 -0
- package/dist/sync/next/history-dag.js.map +1 -0
- package/dist/sync/next/mod.d.ts +5 -0
- package/dist/sync/next/mod.d.ts.map +1 -0
- package/dist/sync/next/mod.js +5 -0
- package/dist/sync/next/mod.js.map +1 -0
- package/dist/sync/next/rebase-events.d.ts +27 -0
- package/dist/sync/next/rebase-events.d.ts.map +1 -0
- package/dist/sync/next/rebase-events.js +41 -0
- package/dist/sync/next/rebase-events.js.map +1 -0
- package/dist/sync/next/test/compact-events.calculator.test.d.ts +2 -0
- package/dist/sync/next/test/compact-events.calculator.test.d.ts.map +1 -0
- package/dist/sync/next/test/compact-events.calculator.test.js +101 -0
- package/dist/sync/next/test/compact-events.calculator.test.js.map +1 -0
- package/dist/sync/next/test/compact-events.test.d.ts +2 -0
- package/dist/sync/next/test/compact-events.test.d.ts.map +1 -0
- package/dist/sync/next/test/compact-events.test.js +201 -0
- package/dist/sync/next/test/compact-events.test.js.map +1 -0
- package/dist/sync/next/test/mod.d.ts +2 -0
- package/dist/sync/next/test/mod.d.ts.map +1 -0
- package/dist/sync/next/test/mod.js +2 -0
- package/dist/sync/next/test/mod.js.map +1 -0
- package/dist/sync/next/test/mutation-fixtures.d.ts +73 -0
- package/dist/sync/next/test/mutation-fixtures.d.ts.map +1 -0
- package/dist/sync/next/test/mutation-fixtures.js +161 -0
- package/dist/sync/next/test/mutation-fixtures.js.map +1 -0
- package/dist/sync/sync.d.ts +45 -0
- package/dist/sync/sync.d.ts.map +1 -0
- package/dist/sync/sync.js +12 -0
- package/dist/sync/sync.js.map +1 -0
- package/dist/util.d.ts +25 -0
- package/dist/util.d.ts.map +1 -0
- package/dist/util.js +38 -0
- package/dist/util.js.map +1 -0
- package/dist/version.d.ts +10 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +12 -0
- package/dist/version.js.map +1 -0
- package/package.json +61 -0
- package/src/__tests__/fixture.ts +23 -0
- package/src/adapter-types.ts +216 -0
- package/src/ambient.d.ts +3 -0
- package/src/bounded-collections.ts +121 -0
- package/src/debug-info.ts +76 -0
- package/src/derived-mutations.test.ts +101 -0
- package/src/derived-mutations.ts +170 -0
- package/src/devtools/devtools-bridge.ts +13 -0
- package/src/devtools/devtools-messages.ts +247 -0
- package/src/devtools/devtools-window-message.ts +27 -0
- package/src/devtools/index.ts +49 -0
- package/src/index.ts +20 -0
- package/src/init-singleton-tables.ts +24 -0
- package/src/mutation.ts +69 -0
- package/src/query-info.ts +104 -0
- package/src/rehydrate-from-mutationlog.ts +131 -0
- package/src/schema/index.ts +144 -0
- package/src/schema/mutations.ts +313 -0
- package/src/schema/schema-helpers.ts +49 -0
- package/src/schema/system-tables.ts +84 -0
- package/src/schema/table-def.ts +312 -0
- package/src/schema-management/common.ts +44 -0
- package/src/schema-management/migrations.ts +188 -0
- package/src/schema-management/validate-mutation-defs.ts +63 -0
- package/src/sql-queries/index.ts +3 -0
- package/src/sql-queries/misc.ts +2 -0
- package/src/sql-queries/sql-queries.ts +359 -0
- package/src/sql-queries/sql-query-builder.ts +135 -0
- package/src/sql-queries/types.ts +97 -0
- package/src/sync/index.ts +1 -0
- package/src/sync/next/ambient.d.ts +3 -0
- package/src/sync/next/compact-events.ts +218 -0
- package/src/sync/next/facts.ts +229 -0
- package/src/sync/next/graphology.ts +49 -0
- package/src/sync/next/graphology_.ts +2 -0
- package/src/sync/next/history-dag.ts +109 -0
- package/src/sync/next/mod.ts +4 -0
- package/src/sync/next/rebase-events.ts +97 -0
- package/src/sync/next/test/compact-events.calculator.test.ts +121 -0
- package/src/sync/next/test/compact-events.test.ts +232 -0
- package/src/sync/next/test/mod.ts +1 -0
- package/src/sync/next/test/mutation-fixtures.ts +230 -0
- package/src/sync/sync.ts +46 -0
- package/src/util.ts +56 -0
- package/src/version.ts +13 -0
- package/tsconfig.json +11 -0
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import { Schema, Transferable } from '@livestore/utils/effect'
|
|
2
|
+
|
|
3
|
+
import { NetworkStatus } from '../adapter-types.js'
|
|
4
|
+
import { DebugInfo } from '../debug-info.js'
|
|
5
|
+
import { mutationEventSchemaEncodedAny } from '../schema/mutations.js'
|
|
6
|
+
import { PreparedBindValues } from '../util.js'
|
|
7
|
+
import { liveStoreVersion as pkgVersion } from '../version.js'
|
|
8
|
+
|
|
9
|
+
const requestId = Schema.String
|
|
10
|
+
const appHostId = Schema.String
|
|
11
|
+
const liveStoreVersion = Schema.Literal(pkgVersion)
|
|
12
|
+
|
|
13
|
+
const LSDMessage = <Tag extends string, Fields extends Schema.Struct.Fields>(tag: Tag, fields: Fields) =>
|
|
14
|
+
Schema.TaggedStruct(tag, {
|
|
15
|
+
liveStoreVersion,
|
|
16
|
+
...fields,
|
|
17
|
+
}).annotations({ identifier: tag })
|
|
18
|
+
|
|
19
|
+
const LSDChannelMessage = <Tag extends string, Fields extends Schema.Struct.Fields>(tag: Tag, fields: Fields) =>
|
|
20
|
+
LSDMessage(tag, {
|
|
21
|
+
appHostId,
|
|
22
|
+
...fields,
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
const LSDReqResMessage = <Tag extends string, Fields extends Schema.Struct.Fields>(tag: Tag, fields: Fields) =>
|
|
26
|
+
LSDChannelMessage(tag, {
|
|
27
|
+
requestId,
|
|
28
|
+
...fields,
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
export class SnapshotReq extends LSDReqResMessage('LSD.SnapshotReq', {}) {}
|
|
32
|
+
|
|
33
|
+
export class SnapshotRes extends LSDReqResMessage('LSD.SnapshotRes', {
|
|
34
|
+
snapshot: Transferable.Uint8Array,
|
|
35
|
+
}) {}
|
|
36
|
+
|
|
37
|
+
export class LoadDatabaseFileReq extends LSDReqResMessage('LSD.LoadDatabaseFileReq', {
|
|
38
|
+
data: Transferable.Uint8Array,
|
|
39
|
+
}) {}
|
|
40
|
+
|
|
41
|
+
export class LoadDatabaseFileRes extends LSDReqResMessage('LSD.LoadDatabaseFileRes', {
|
|
42
|
+
status: Schema.Literal('ok', 'unsupported-file', 'unsupported-database'),
|
|
43
|
+
}) {}
|
|
44
|
+
|
|
45
|
+
export class DebugInfoReq extends LSDReqResMessage('LSD.DebugInfoReq', {}) {}
|
|
46
|
+
|
|
47
|
+
export class DebugInfoRes extends LSDReqResMessage('LSD.DebugInfoRes', {
|
|
48
|
+
debugInfo: DebugInfo,
|
|
49
|
+
}) {}
|
|
50
|
+
|
|
51
|
+
export class DebugInfoHistorySubscribe extends LSDReqResMessage('LSD.DebugInfoHistorySubscribe', {}) {}
|
|
52
|
+
|
|
53
|
+
export class DebugInfoHistoryRes extends LSDReqResMessage('LSD.DebugInfoHistoryRes', {
|
|
54
|
+
debugInfoHistory: Schema.Array(DebugInfo),
|
|
55
|
+
}) {}
|
|
56
|
+
|
|
57
|
+
export class DebugInfoHistoryUnsubscribe extends LSDReqResMessage('LSD.DebugInfoHistoryUnsubscribe', {}) {}
|
|
58
|
+
|
|
59
|
+
export class DebugInfoResetReq extends LSDReqResMessage('LSD.DebugInfoResetReq', {}) {}
|
|
60
|
+
|
|
61
|
+
export class DebugInfoResetRes extends LSDReqResMessage('LSD.DebugInfoResetRes', {}) {}
|
|
62
|
+
|
|
63
|
+
export class DebugInfoRerunQueryReq extends LSDReqResMessage('LSD.DebugInfoRerunQueryReq', {
|
|
64
|
+
queryStr: Schema.String,
|
|
65
|
+
bindValues: Schema.UndefinedOr(PreparedBindValues),
|
|
66
|
+
queriedTables: Schema.ReadonlySet(Schema.String),
|
|
67
|
+
}) {}
|
|
68
|
+
|
|
69
|
+
export class DebugInfoRerunQueryRes extends LSDReqResMessage('LSD.DebugInfoRerunQueryRes', {}) {}
|
|
70
|
+
|
|
71
|
+
export class MutationBroadcast extends LSDMessage('LSD.MutationBroadcast', {
|
|
72
|
+
mutationEventEncoded: mutationEventSchemaEncodedAny,
|
|
73
|
+
persisted: Schema.Boolean,
|
|
74
|
+
}) {}
|
|
75
|
+
|
|
76
|
+
export class RunMutationReq extends LSDReqResMessage('LSD.RunMutationReq', {
|
|
77
|
+
mutationEventEncoded: mutationEventSchemaEncodedAny.pipe(Schema.omit('id', 'parentId')),
|
|
78
|
+
persisted: Schema.Boolean,
|
|
79
|
+
}) {}
|
|
80
|
+
|
|
81
|
+
export class RunMutationRes extends LSDReqResMessage('LSD.RunMutationRes', {}) {}
|
|
82
|
+
|
|
83
|
+
export class MutationLogReq extends LSDReqResMessage('LSD.MutationLogReq', {}) {}
|
|
84
|
+
|
|
85
|
+
export class MutationLogRes extends LSDReqResMessage('LSD.MutationLogRes', {
|
|
86
|
+
mutationLog: Transferable.Uint8Array,
|
|
87
|
+
}) {}
|
|
88
|
+
|
|
89
|
+
export class ReactivityGraphSubscribe extends LSDReqResMessage('LSD.ReactivityGraphSubscribe', {
|
|
90
|
+
includeResults: Schema.Boolean,
|
|
91
|
+
}) {}
|
|
92
|
+
|
|
93
|
+
export class ReactivityGraphUnsubscribe extends LSDReqResMessage('LSD.ReactivityGraphUnsubscribe', {}) {}
|
|
94
|
+
|
|
95
|
+
export class ReactivityGraphRes extends LSDReqResMessage('LSD.ReactivityGraphRes', {
|
|
96
|
+
reactivityGraph: Schema.Any,
|
|
97
|
+
}) {}
|
|
98
|
+
|
|
99
|
+
export class LiveQueriesSubscribe extends LSDReqResMessage('LSD.LiveQueriesSubscribe', {}) {}
|
|
100
|
+
|
|
101
|
+
export class LiveQueriesUnsubscribe extends LSDReqResMessage('LSD.LiveQueriesUnsubscribe', {}) {}
|
|
102
|
+
|
|
103
|
+
export class SerializedLiveQuery extends Schema.Struct({
|
|
104
|
+
_tag: Schema.Literal('js', 'sql', 'graphql'),
|
|
105
|
+
id: Schema.Number,
|
|
106
|
+
label: Schema.String,
|
|
107
|
+
runs: Schema.Number,
|
|
108
|
+
executionTimes: Schema.Array(Schema.Number),
|
|
109
|
+
lastestResult: Schema.Any,
|
|
110
|
+
activeSubscriptions: Schema.Array(
|
|
111
|
+
Schema.Struct({ frames: Schema.Array(Schema.Struct({ name: Schema.String, filePath: Schema.String })) }),
|
|
112
|
+
),
|
|
113
|
+
}) {}
|
|
114
|
+
|
|
115
|
+
export class LiveQueriesRes extends LSDReqResMessage('LSD.LiveQueriesRes', {
|
|
116
|
+
liveQueries: Schema.Array(SerializedLiveQuery),
|
|
117
|
+
}) {}
|
|
118
|
+
|
|
119
|
+
export class ResetAllDataReq extends LSDReqResMessage('LSD.ResetAllDataReq', {
|
|
120
|
+
mode: Schema.Literal('all-data', 'only-app-db'),
|
|
121
|
+
}) {}
|
|
122
|
+
|
|
123
|
+
export class ResetAllDataRes extends LSDReqResMessage('LSD.ResetAllDataRes', {}) {}
|
|
124
|
+
|
|
125
|
+
export class DatabaseFileInfoReq extends LSDReqResMessage('LSD.DatabaseFileInfoReq', {}) {}
|
|
126
|
+
|
|
127
|
+
export class DatabaseFileInfo extends Schema.Struct({
|
|
128
|
+
fileSize: Schema.Number,
|
|
129
|
+
persistenceInfo: Schema.Struct({ fileName: Schema.String }, { key: Schema.String, value: Schema.Any }),
|
|
130
|
+
}) {}
|
|
131
|
+
|
|
132
|
+
export class DatabaseFileInfoRes extends LSDReqResMessage('LSD.DatabaseFileInfoRes', {
|
|
133
|
+
db: DatabaseFileInfo,
|
|
134
|
+
mutationLog: DatabaseFileInfo,
|
|
135
|
+
}) {}
|
|
136
|
+
|
|
137
|
+
export class MessagePortForStoreReq extends LSDReqResMessage('LSD.MessagePortForStoreReq', {}) {}
|
|
138
|
+
|
|
139
|
+
export class MessagePortForStoreRes extends LSDReqResMessage('LSD.MessagePortForStoreRes', {
|
|
140
|
+
port: Transferable.MessagePort,
|
|
141
|
+
}) {}
|
|
142
|
+
|
|
143
|
+
export class NetworkStatusSubscribe extends LSDReqResMessage('LSD.NetworkStatusSubscribe', {}) {}
|
|
144
|
+
export class NetworkStatusUnsubscribe extends LSDReqResMessage('LSD.NetworkStatusUnsubscribe', {}) {}
|
|
145
|
+
|
|
146
|
+
export class NetworkStatusRes extends LSDReqResMessage('LSD.NetworkStatusRes', {
|
|
147
|
+
networkStatus: NetworkStatus,
|
|
148
|
+
}) {}
|
|
149
|
+
|
|
150
|
+
export class SyncingInfoReq extends LSDReqResMessage('LSD.SyncingInfoReq', {}) {}
|
|
151
|
+
|
|
152
|
+
export class SyncingInfo extends Schema.Struct({
|
|
153
|
+
enabled: Schema.Boolean,
|
|
154
|
+
metadata: Schema.Record({ key: Schema.String, value: Schema.Any }),
|
|
155
|
+
}) {}
|
|
156
|
+
|
|
157
|
+
export class SyncingInfoRes extends LSDReqResMessage('LSD.SyncingInfoRes', {
|
|
158
|
+
syncingInfo: SyncingInfo,
|
|
159
|
+
}) {}
|
|
160
|
+
|
|
161
|
+
export class SyncHistorySubscribe extends LSDReqResMessage('LSD.SyncHistorySubscribe', {}) {}
|
|
162
|
+
export class SyncHistoryUnsubscribe extends LSDReqResMessage('LSD.SyncHistoryUnsubscribe', {}) {}
|
|
163
|
+
export class SyncHistoryRes extends LSDReqResMessage('LSD.SyncHistoryRes', {
|
|
164
|
+
mutationEventEncoded: mutationEventSchemaEncodedAny,
|
|
165
|
+
metadata: Schema.Option(Schema.JsonValue),
|
|
166
|
+
}) {}
|
|
167
|
+
|
|
168
|
+
export class DevtoolsReady extends LSDMessage('LSD.DevtoolsReady', {}) {}
|
|
169
|
+
|
|
170
|
+
export class DevtoolsConnected extends LSDChannelMessage('LSD.DevtoolsConnected', {}) {}
|
|
171
|
+
|
|
172
|
+
export class AppHostReady extends LSDChannelMessage('LSD.AppHostReady', {
|
|
173
|
+
isLeader: Schema.Boolean,
|
|
174
|
+
}) {}
|
|
175
|
+
|
|
176
|
+
export class Disconnect extends LSDChannelMessage('LSD.Disconnect', {}) {}
|
|
177
|
+
|
|
178
|
+
export class Ping extends LSDReqResMessage('LSD.Ping', {}) {}
|
|
179
|
+
|
|
180
|
+
export class Pong extends LSDReqResMessage('LSD.Pong', {}) {}
|
|
181
|
+
|
|
182
|
+
export const MessageToAppHostCoordinator = Schema.Union(
|
|
183
|
+
SnapshotReq,
|
|
184
|
+
LoadDatabaseFileReq,
|
|
185
|
+
MutationLogReq,
|
|
186
|
+
ResetAllDataReq,
|
|
187
|
+
MessagePortForStoreRes,
|
|
188
|
+
NetworkStatusSubscribe,
|
|
189
|
+
NetworkStatusUnsubscribe,
|
|
190
|
+
DevtoolsReady,
|
|
191
|
+
Disconnect,
|
|
192
|
+
DevtoolsConnected,
|
|
193
|
+
RunMutationReq,
|
|
194
|
+
Ping,
|
|
195
|
+
DatabaseFileInfoReq,
|
|
196
|
+
SyncHistorySubscribe,
|
|
197
|
+
SyncHistoryUnsubscribe,
|
|
198
|
+
SyncingInfoReq,
|
|
199
|
+
).annotations({ identifier: 'LSD.MessageToAppHostCoordinator' })
|
|
200
|
+
|
|
201
|
+
export type MessageToAppHostCoordinator = typeof MessageToAppHostCoordinator.Type
|
|
202
|
+
|
|
203
|
+
export const MessageToAppHostStore = Schema.Union(
|
|
204
|
+
DebugInfoReq,
|
|
205
|
+
DebugInfoHistorySubscribe,
|
|
206
|
+
DebugInfoHistoryUnsubscribe,
|
|
207
|
+
DebugInfoResetReq,
|
|
208
|
+
DebugInfoRerunQueryReq,
|
|
209
|
+
ReactivityGraphSubscribe,
|
|
210
|
+
ReactivityGraphUnsubscribe,
|
|
211
|
+
LiveQueriesSubscribe,
|
|
212
|
+
LiveQueriesUnsubscribe,
|
|
213
|
+
// Ping,
|
|
214
|
+
).annotations({ identifier: 'LSD.MessageToAppHostStore' })
|
|
215
|
+
|
|
216
|
+
export type MessageToAppHostStore = typeof MessageToAppHostStore.Type
|
|
217
|
+
|
|
218
|
+
export const MessageFromAppHostCoordinator = Schema.Union(
|
|
219
|
+
SnapshotRes,
|
|
220
|
+
LoadDatabaseFileRes,
|
|
221
|
+
MutationLogRes,
|
|
222
|
+
ResetAllDataRes,
|
|
223
|
+
MessagePortForStoreReq,
|
|
224
|
+
Disconnect,
|
|
225
|
+
MutationBroadcast,
|
|
226
|
+
AppHostReady,
|
|
227
|
+
NetworkStatusRes,
|
|
228
|
+
RunMutationRes,
|
|
229
|
+
Pong,
|
|
230
|
+
DatabaseFileInfoRes,
|
|
231
|
+
SyncHistoryRes,
|
|
232
|
+
SyncingInfoRes,
|
|
233
|
+
).annotations({ identifier: 'LSD.MessageFromAppHostCoordinator' })
|
|
234
|
+
|
|
235
|
+
export type MessageFromAppHostCoordinator = typeof MessageFromAppHostCoordinator.Type
|
|
236
|
+
|
|
237
|
+
export const MessageFromAppHostStore = Schema.Union(
|
|
238
|
+
DebugInfoRes,
|
|
239
|
+
DebugInfoHistoryRes,
|
|
240
|
+
DebugInfoResetRes,
|
|
241
|
+
DebugInfoRerunQueryRes,
|
|
242
|
+
ReactivityGraphRes,
|
|
243
|
+
LiveQueriesRes,
|
|
244
|
+
// Pong,
|
|
245
|
+
).annotations({ identifier: 'LSD.MessageFromAppHostStore' })
|
|
246
|
+
|
|
247
|
+
export type MessageFromAppHostStore = typeof MessageFromAppHostStore.Type
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Schema, Transferable } from '@livestore/utils/effect'
|
|
2
|
+
|
|
3
|
+
const appHostId = 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.MessagePortReady', {
|
|
8
|
+
port: Transferable.MessagePort,
|
|
9
|
+
appHostId,
|
|
10
|
+
}) {}
|
|
11
|
+
|
|
12
|
+
export class ContentscriptListening extends Schema.TaggedStruct('LSD.WindowMessage.ContentscriptListening', {}) {}
|
|
13
|
+
|
|
14
|
+
// export class ContentscriptReady extends Schema.TaggedStruct('LSD.WindowMessage.ContentscriptReady', {
|
|
15
|
+
// appHostId,
|
|
16
|
+
// }) {}
|
|
17
|
+
|
|
18
|
+
export class LoadIframe extends Schema.TaggedStruct('LSD.WindowMessage.LoadIframe', {}) {}
|
|
19
|
+
|
|
20
|
+
export class StoreReady extends Schema.TaggedStruct('LSD.WindowMessage.StoreReady', {
|
|
21
|
+
appHostId,
|
|
22
|
+
}) {}
|
|
23
|
+
|
|
24
|
+
export class MessageForStore extends Schema.Union(MessagePortReady, ContentscriptListening) {}
|
|
25
|
+
|
|
26
|
+
export class MessageForContentscript extends Schema.Union(StoreReady, LoadIframe) {}
|
|
27
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { Effect, Scope } from '@livestore/utils/effect'
|
|
2
|
+
import { Schema, WebChannel } from '@livestore/utils/effect'
|
|
3
|
+
|
|
4
|
+
export * from './devtools-messages.js'
|
|
5
|
+
export * from './devtools-window-message.js'
|
|
6
|
+
export * from './devtools-bridge.js'
|
|
7
|
+
|
|
8
|
+
export namespace WebBridge {
|
|
9
|
+
export class AppHostReady extends Schema.TaggedStruct('LSD.WebBridge.AppHostReady', {
|
|
10
|
+
appHostId: Schema.String,
|
|
11
|
+
// storeId: Schema.String,
|
|
12
|
+
isLeader: Schema.Boolean,
|
|
13
|
+
}) {}
|
|
14
|
+
|
|
15
|
+
export class DevtoolsReady extends Schema.TaggedStruct('LSD.WebBridge.DevtoolsReady', {
|
|
16
|
+
devtoolsId: Schema.String,
|
|
17
|
+
}) {}
|
|
18
|
+
|
|
19
|
+
export class ConnectToDevtools extends Schema.TaggedStruct('LSD.WebBridge.ConnectToDevtools', {
|
|
20
|
+
devtoolsId: Schema.String,
|
|
21
|
+
appHostId: Schema.String,
|
|
22
|
+
/**
|
|
23
|
+
* Given the m:n relationship between devtools and app hosts and the fact that appHostIds are usually
|
|
24
|
+
* sticky, we generate a new unique id for the lifetime of the web bridge.
|
|
25
|
+
*/
|
|
26
|
+
webBridgeId: Schema.String,
|
|
27
|
+
isLeader: Schema.Boolean,
|
|
28
|
+
storeId: Schema.String,
|
|
29
|
+
}) {}
|
|
30
|
+
|
|
31
|
+
export class AppHostWillDisconnect extends Schema.TaggedStruct('LSD.WebBridge.AppHostWillDisconnect', {
|
|
32
|
+
appHostId: Schema.String,
|
|
33
|
+
}) {}
|
|
34
|
+
|
|
35
|
+
// export class DevtoolsWillDisconnect extends Schema.TaggedStruct('LSD.WebBridge.DevtoolsWillDisconnect', {
|
|
36
|
+
// appHostId: Schema.String,
|
|
37
|
+
// }) {}
|
|
38
|
+
|
|
39
|
+
export class All extends Schema.Union(AppHostReady, DevtoolsReady, ConnectToDevtools, AppHostWillDisconnect) {}
|
|
40
|
+
|
|
41
|
+
export const makeBroadcastChannel = (
|
|
42
|
+
key?: string,
|
|
43
|
+
): Effect.Effect<WebChannel.WebChannel<typeof All.Type, typeof All.Type>, never, Scope.Scope> =>
|
|
44
|
+
WebChannel.broadcastChannel({
|
|
45
|
+
channelName: `livestore-web-bridge-devtools${key ? `-${key}` : ''}`,
|
|
46
|
+
listenSchema: All,
|
|
47
|
+
sendSchema: All,
|
|
48
|
+
})
|
|
49
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export * from './schema/system-tables.js'
|
|
2
|
+
export * from './util.js'
|
|
3
|
+
export * from './adapter-types.js'
|
|
4
|
+
export * from './schema-management/migrations.js'
|
|
5
|
+
export * from './mutation.js'
|
|
6
|
+
export * from './init-singleton-tables.js'
|
|
7
|
+
export * from './rehydrate-from-mutationlog.js'
|
|
8
|
+
export * from './query-info.js'
|
|
9
|
+
export * from './derived-mutations.js'
|
|
10
|
+
export * from './sync/index.js'
|
|
11
|
+
export * as Devtools from './devtools/index.js'
|
|
12
|
+
export * from './debug-info.js'
|
|
13
|
+
export * from './bounded-collections.js'
|
|
14
|
+
export * from './version.js'
|
|
15
|
+
|
|
16
|
+
declare global {
|
|
17
|
+
interface LiveStoreGlobal {
|
|
18
|
+
// syncBackend: never
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { SynchronousDatabase } from './adapter-types.js'
|
|
2
|
+
import type { LiveStoreSchema } from './schema/index.js'
|
|
3
|
+
import { getDefaultValuesEncoded } from './schema/schema-helpers.js'
|
|
4
|
+
import { prepareBindValues, sql } from './util.js'
|
|
5
|
+
|
|
6
|
+
export const initializeSingletonTables = (schema: LiveStoreSchema, db: SynchronousDatabase) => {
|
|
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
|
+
}
|
package/src/mutation.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { memoizeByRef, shouldNeverHappen } from '@livestore/utils'
|
|
2
|
+
import { Schema } from '@livestore/utils/effect'
|
|
3
|
+
|
|
4
|
+
import type { LiveStoreSchema } from './schema/index.js'
|
|
5
|
+
import type { MutationDef, MutationEvent } from './schema/mutations.js'
|
|
6
|
+
import type { PreparedBindValues } from './util.js'
|
|
7
|
+
import { prepareBindValues } from './util.js'
|
|
8
|
+
|
|
9
|
+
export const getExecArgsFromMutation = ({
|
|
10
|
+
mutationDef,
|
|
11
|
+
mutationEventDecoded,
|
|
12
|
+
}: {
|
|
13
|
+
mutationDef: MutationDef.Any
|
|
14
|
+
mutationEventDecoded: MutationEvent.Any
|
|
15
|
+
}): ReadonlyArray<{
|
|
16
|
+
statementSql: string
|
|
17
|
+
bindValues: PreparedBindValues
|
|
18
|
+
writeTables: ReadonlySet<string> | undefined
|
|
19
|
+
}> => {
|
|
20
|
+
let statementRes: ReadonlyArray<
|
|
21
|
+
string | { sql: string; bindValues: Record<string, unknown>; writeTables?: ReadonlySet<string> }
|
|
22
|
+
>
|
|
23
|
+
|
|
24
|
+
switch (typeof mutationDef.sql) {
|
|
25
|
+
case 'function': {
|
|
26
|
+
const res = mutationDef.sql(mutationEventDecoded.args)
|
|
27
|
+
statementRes = Array.isArray(res) ? res : [res]
|
|
28
|
+
break
|
|
29
|
+
}
|
|
30
|
+
case 'string': {
|
|
31
|
+
statementRes = [mutationDef.sql]
|
|
32
|
+
break
|
|
33
|
+
}
|
|
34
|
+
default: {
|
|
35
|
+
statementRes = mutationDef.sql
|
|
36
|
+
break
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return statementRes.map((statementRes) => {
|
|
41
|
+
const statementSql = typeof statementRes === 'string' ? statementRes : statementRes.sql
|
|
42
|
+
|
|
43
|
+
const bindValues =
|
|
44
|
+
typeof statementRes === 'string'
|
|
45
|
+
? Schema.encodeUnknownSync(mutationDef.schema)(mutationEventDecoded.args)
|
|
46
|
+
: statementRes.bindValues
|
|
47
|
+
|
|
48
|
+
const writeTables = typeof statementRes === 'string' ? undefined : statementRes.writeTables
|
|
49
|
+
|
|
50
|
+
return { statementSql, bindValues: prepareBindValues(bindValues ?? {}, statementSql), writeTables }
|
|
51
|
+
})
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export const makeShouldExcludeMutationFromLog = memoizeByRef((schema: LiveStoreSchema) => {
|
|
55
|
+
const migrationOptions = schema.migrationOptions
|
|
56
|
+
const mutationLogExclude =
|
|
57
|
+
migrationOptions.strategy === 'from-mutation-log'
|
|
58
|
+
? (migrationOptions.excludeMutations ?? new Set(['livestore.RawSql']))
|
|
59
|
+
: new Set(['livestore.RawSql'])
|
|
60
|
+
|
|
61
|
+
return (mutationName: string, mutationEventDecoded: MutationEvent.Any): boolean => {
|
|
62
|
+
if (mutationLogExclude.has(mutationName)) return true
|
|
63
|
+
|
|
64
|
+
const mutationDef = schema.mutations.get(mutationName) ?? shouldNeverHappen(`Unknown mutation: ${mutationName}`)
|
|
65
|
+
const execArgsArr = getExecArgsFromMutation({ mutationDef, mutationEventDecoded })
|
|
66
|
+
|
|
67
|
+
return execArgsArr.some((_) => _.statementSql.includes('__livestore'))
|
|
68
|
+
}
|
|
69
|
+
})
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import type { Schema } from '@livestore/utils/effect'
|
|
2
|
+
|
|
3
|
+
import type { DbSchema } from './schema/index.js'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Semantic information about a query with supported cases being:
|
|
7
|
+
* - a whole row
|
|
8
|
+
* - a single column value
|
|
9
|
+
* - a sub value in a JSON column
|
|
10
|
+
*/
|
|
11
|
+
export type QueryInfo<TTableDef extends DbSchema.TableDef = DbSchema.TableDef> =
|
|
12
|
+
| QueryInfoNone
|
|
13
|
+
| QueryInfoRow<TTableDef>
|
|
14
|
+
| QueryInfoColJsonValue<TTableDef, GetJsonColumn<TTableDef>>
|
|
15
|
+
| QueryInfoCol<TTableDef, keyof TTableDef['sqliteDef']['columns']>
|
|
16
|
+
|
|
17
|
+
export type QueryInfoNone = {
|
|
18
|
+
_tag: 'None'
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export type QueryInfoRow<TTableDef extends DbSchema.TableDef> = {
|
|
22
|
+
_tag: 'Row'
|
|
23
|
+
table: TTableDef
|
|
24
|
+
id: string
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export type QueryInfoCol<
|
|
28
|
+
TTableDef extends DbSchema.TableDef,
|
|
29
|
+
TColName extends keyof TTableDef['sqliteDef']['columns'],
|
|
30
|
+
> = {
|
|
31
|
+
_tag: 'Col'
|
|
32
|
+
table: TTableDef
|
|
33
|
+
id: string
|
|
34
|
+
column: TColName
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export type QueryInfoColJsonValue<TTableDef extends DbSchema.TableDef, TColName extends GetJsonColumn<TTableDef>> = {
|
|
38
|
+
_tag: 'ColJsonValue'
|
|
39
|
+
table: TTableDef
|
|
40
|
+
id: string
|
|
41
|
+
column: TColName
|
|
42
|
+
/**
|
|
43
|
+
* example: `$.tabs[3].items[2]` (`$` referring to the column value)
|
|
44
|
+
*/
|
|
45
|
+
jsonPath: string
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
type GetJsonColumn<TTableDef extends DbSchema.TableDef> = keyof {
|
|
49
|
+
[ColName in keyof TTableDef['sqliteDef']['columns'] as TTableDef['sqliteDef']['columns'][ColName]['columnType'] extends 'text'
|
|
50
|
+
? ColName
|
|
51
|
+
: never]: {}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export type UpdateValueForPath<TQueryInfo extends QueryInfo> = TQueryInfo extends { _tag: 'Row' }
|
|
55
|
+
? Partial<DbSchema.FromTable.RowDecodedAll<TQueryInfo['table']>>
|
|
56
|
+
: TQueryInfo extends { _tag: 'Col' }
|
|
57
|
+
? Schema.Schema.Type<TQueryInfo['table']['sqliteDef']['columns'][TQueryInfo['column']]['schema']>
|
|
58
|
+
: TQueryInfo extends { _tag: 'ColJsonValue' }
|
|
59
|
+
? { TODO: true }
|
|
60
|
+
: never
|
|
61
|
+
|
|
62
|
+
// export const mutationForQueryInfo = <const TQueryInfo extends QueryInfo>(
|
|
63
|
+
// queryInfo: TQueryInfo,
|
|
64
|
+
// value: UpdateValueForPath<TQueryInfo>,
|
|
65
|
+
// ): RawSqlMutationEvent => {
|
|
66
|
+
// if (queryInfo._tag === 'ColJsonValue' || queryInfo._tag === 'None') {
|
|
67
|
+
// return notYetImplemented('TODO')
|
|
68
|
+
// }
|
|
69
|
+
|
|
70
|
+
// const sqliteTableDef = queryInfo.table.sqliteDef
|
|
71
|
+
// const id = queryInfo.id
|
|
72
|
+
|
|
73
|
+
// const { columnNames, bindValues } = (() => {
|
|
74
|
+
// if (queryInfo._tag === 'Row') {
|
|
75
|
+
// const columnNames = Object.keys(value)
|
|
76
|
+
|
|
77
|
+
// const partialStructSchema = queryInfo.table.schema.pipe(Schema.pick(...columnNames))
|
|
78
|
+
|
|
79
|
+
// // const columnNames = Object.keys(value)
|
|
80
|
+
// const encodedBindValues = Schema.encodeEither(partialStructSchema)(value)
|
|
81
|
+
// if (encodedBindValues._tag === 'Left') {
|
|
82
|
+
// return shouldNeverHappen(encodedBindValues.left.toString())
|
|
83
|
+
// } else {
|
|
84
|
+
// return { columnNames, bindValues: encodedBindValues.right }
|
|
85
|
+
// }
|
|
86
|
+
// } else if (queryInfo._tag === 'Col') {
|
|
87
|
+
// const columnName = queryInfo.column
|
|
88
|
+
// const columnSchema =
|
|
89
|
+
// sqliteTableDef.columns[columnName]?.schema ?? shouldNeverHappen(`Column ${columnName} not found`)
|
|
90
|
+
// const bindValues = { [columnName]: Schema.encodeSync(columnSchema)(value) }
|
|
91
|
+
// return { columnNames: [columnName], bindValues }
|
|
92
|
+
// } else {
|
|
93
|
+
// return shouldNeverHappen()
|
|
94
|
+
// }
|
|
95
|
+
// })()
|
|
96
|
+
|
|
97
|
+
// const updateClause = columnNames.map((columnName) => `${columnName} = $${columnName}`).join(', ')
|
|
98
|
+
|
|
99
|
+
// const whereClause = `where id = '${id}'`
|
|
100
|
+
// const sql = `UPDATE ${sqliteTableDef.name} SET ${updateClause} ${whereClause}`
|
|
101
|
+
// const writeTables = new Set<string>([queryInfo.table.sqliteDef.name])
|
|
102
|
+
|
|
103
|
+
// return rawSqlMutation({ sql, bindValues, writeTables })
|
|
104
|
+
// }
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { memoizeByRef, shouldNeverHappen } from '@livestore/utils'
|
|
2
|
+
import { Chunk, Effect, Option, Schema, Stream } from '@livestore/utils/effect'
|
|
3
|
+
|
|
4
|
+
import { type MigrationOptionsFromMutationLog, type SynchronousDatabase, UnexpectedError } from './adapter-types.js'
|
|
5
|
+
import { getExecArgsFromMutation } from './mutation.js'
|
|
6
|
+
import type { LiveStoreSchema, MutationDef, MutationEvent, MutationLogMetaRow } from './schema/index.js'
|
|
7
|
+
import { MUTATION_LOG_META_TABLE } from './schema/index.js'
|
|
8
|
+
import type { PreparedBindValues } from './util.js'
|
|
9
|
+
import { sql } from './util.js'
|
|
10
|
+
|
|
11
|
+
export const rehydrateFromMutationLog = ({
|
|
12
|
+
logDb,
|
|
13
|
+
db,
|
|
14
|
+
schema,
|
|
15
|
+
migrationOptions,
|
|
16
|
+
onProgress,
|
|
17
|
+
}: {
|
|
18
|
+
logDb: SynchronousDatabase
|
|
19
|
+
db: SynchronousDatabase
|
|
20
|
+
schema: LiveStoreSchema
|
|
21
|
+
migrationOptions: MigrationOptionsFromMutationLog
|
|
22
|
+
onProgress: (_: { done: number; total: number }) => Effect.Effect<void>
|
|
23
|
+
}) =>
|
|
24
|
+
Effect.gen(function* () {
|
|
25
|
+
const mutationsCount = logDb.select<{ count: number }>(
|
|
26
|
+
`SELECT COUNT(*) AS count FROM ${MUTATION_LOG_META_TABLE}`,
|
|
27
|
+
)[0]!.count
|
|
28
|
+
|
|
29
|
+
const hashMutation = memoizeByRef((mutation: MutationDef.Any) => Schema.hash(mutation.schema))
|
|
30
|
+
|
|
31
|
+
const processMutation = (row: MutationLogMetaRow) =>
|
|
32
|
+
Effect.gen(function* () {
|
|
33
|
+
const mutationDef = schema.mutations.get(row.mutation) ?? shouldNeverHappen(`Unknown mutation ${row.mutation}`)
|
|
34
|
+
|
|
35
|
+
if (migrationOptions.excludeMutations?.has(row.mutation) === true) return
|
|
36
|
+
|
|
37
|
+
if (hashMutation(mutationDef) !== row.schemaHash) {
|
|
38
|
+
yield* Effect.logWarning(
|
|
39
|
+
`Schema hash mismatch for mutation ${row.mutation}. Trying to apply mutation anyway.`,
|
|
40
|
+
)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const argsDecoded = yield* Schema.decodeUnknown(Schema.parseJson(mutationDef.schema))(row.argsJson).pipe(
|
|
44
|
+
Effect.mapError((cause) =>
|
|
45
|
+
UnexpectedError.make({
|
|
46
|
+
cause,
|
|
47
|
+
note: `\
|
|
48
|
+
There was an error during rehydrating from the mutation log while decoding
|
|
49
|
+
the persisted mutation event args for mutation "${row.mutation}".
|
|
50
|
+
This likely means the schema has changed in an incompatible way.
|
|
51
|
+
`,
|
|
52
|
+
}),
|
|
53
|
+
),
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
const mutationEventDecoded = {
|
|
57
|
+
id: { global: row.idGlobal, local: row.idLocal },
|
|
58
|
+
parentId: { global: row.parentIdGlobal, local: row.parentIdLocal },
|
|
59
|
+
mutation: row.mutation,
|
|
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(
|
|
76
|
+
statementSql,
|
|
77
|
+
bindValues,
|
|
78
|
+
import.meta.env.DEV ? makeExecuteOptions(statementSql, bindValues) : undefined,
|
|
79
|
+
)
|
|
80
|
+
// console.log(`Re-executed mutation ${mutationSql}`, bindValues)
|
|
81
|
+
}
|
|
82
|
+
}).pipe(Effect.withSpan(`@livestore/common:rehydrateFromMutationLog:processMutation`))
|
|
83
|
+
|
|
84
|
+
const CHUNK_SIZE = 100
|
|
85
|
+
|
|
86
|
+
const stmt = logDb.prepare(sql`\
|
|
87
|
+
SELECT * FROM ${MUTATION_LOG_META_TABLE}
|
|
88
|
+
WHERE idGlobal > COALESCE($idGlobal, '') AND idLocal > COALESCE($idLocal, '')
|
|
89
|
+
ORDER BY idGlobal ASC, idLocal ASC
|
|
90
|
+
LIMIT ${CHUNK_SIZE}
|
|
91
|
+
`)
|
|
92
|
+
|
|
93
|
+
let processedMutations = 0
|
|
94
|
+
|
|
95
|
+
yield* Stream.unfoldChunk<Chunk.Chunk<MutationLogMetaRow> | { _tag: 'Initial ' }, MutationLogMetaRow>(
|
|
96
|
+
{ _tag: 'Initial ' },
|
|
97
|
+
(item) => {
|
|
98
|
+
// End stream if no more rows
|
|
99
|
+
if (Chunk.isChunk(item) && item.length === 0) return Option.none()
|
|
100
|
+
|
|
101
|
+
const lastId = Chunk.isChunk(item)
|
|
102
|
+
? Chunk.last(item).pipe(
|
|
103
|
+
Option.map((_) => ({ global: _.idGlobal, local: _.idLocal })),
|
|
104
|
+
Option.getOrUndefined,
|
|
105
|
+
)
|
|
106
|
+
: undefined
|
|
107
|
+
const nextItem = Chunk.fromIterable(
|
|
108
|
+
stmt.select<MutationLogMetaRow>({
|
|
109
|
+
$idGlobal: lastId?.global,
|
|
110
|
+
$idLocal: lastId?.local,
|
|
111
|
+
} as any as PreparedBindValues),
|
|
112
|
+
)
|
|
113
|
+
const prevItem = Chunk.isChunk(item) ? item : Chunk.empty()
|
|
114
|
+
return Option.some([prevItem, nextItem])
|
|
115
|
+
},
|
|
116
|
+
).pipe(
|
|
117
|
+
Stream.bufferChunks({ capacity: 2 }),
|
|
118
|
+
Stream.tap((row) =>
|
|
119
|
+
Effect.gen(function* () {
|
|
120
|
+
yield* processMutation(row)
|
|
121
|
+
|
|
122
|
+
processedMutations++
|
|
123
|
+
yield* onProgress({ done: processedMutations, total: mutationsCount })
|
|
124
|
+
}),
|
|
125
|
+
),
|
|
126
|
+
Stream.runDrain,
|
|
127
|
+
)
|
|
128
|
+
}).pipe(
|
|
129
|
+
Effect.withPerformanceMeasure('@livestore/common:rehydrateFromMutationLog'),
|
|
130
|
+
Effect.withSpan('@livestore/common:rehydrateFromMutationLog'),
|
|
131
|
+
)
|