@livestore/common 0.3.0-dev.1 → 0.3.0-dev.10
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/adapter-types.d.ts +26 -23
- package/dist/adapter-types.d.ts.map +1 -1
- package/dist/adapter-types.js.map +1 -1
- package/dist/derived-mutations.d.ts +4 -4
- package/dist/derived-mutations.d.ts.map +1 -1
- package/dist/derived-mutations.test.js.map +1 -1
- package/dist/devtools/devtools-bridge.d.ts +2 -1
- package/dist/devtools/devtools-bridge.d.ts.map +1 -1
- package/dist/devtools/devtools-messages.d.ts +98 -110
- package/dist/devtools/devtools-messages.d.ts.map +1 -1
- package/dist/devtools/devtools-messages.js +9 -6
- package/dist/devtools/devtools-messages.js.map +1 -1
- package/dist/index.d.ts +0 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/leader-thread/LeaderSyncProcessor.d.ts +37 -0
- package/dist/leader-thread/LeaderSyncProcessor.d.ts.map +1 -0
- package/dist/leader-thread/LeaderSyncProcessor.js +417 -0
- package/dist/leader-thread/LeaderSyncProcessor.js.map +1 -0
- package/dist/leader-thread/apply-mutation.d.ts +5 -2
- package/dist/leader-thread/apply-mutation.d.ts.map +1 -1
- package/dist/leader-thread/apply-mutation.js +38 -26
- package/dist/leader-thread/apply-mutation.js.map +1 -1
- package/dist/leader-thread/leader-sync-processor.d.ts +2 -2
- package/dist/leader-thread/leader-sync-processor.d.ts.map +1 -1
- package/dist/leader-thread/leader-sync-processor.js +20 -12
- package/dist/leader-thread/leader-sync-processor.js.map +1 -1
- package/dist/leader-thread/leader-worker-devtools.d.ts +1 -1
- package/dist/leader-thread/leader-worker-devtools.d.ts.map +1 -1
- package/dist/leader-thread/leader-worker-devtools.js +22 -66
- package/dist/leader-thread/leader-worker-devtools.js.map +1 -1
- package/dist/leader-thread/make-leader-thread-layer.d.ts +8 -7
- package/dist/leader-thread/make-leader-thread-layer.d.ts.map +1 -1
- package/dist/leader-thread/make-leader-thread-layer.js +11 -5
- package/dist/leader-thread/make-leader-thread-layer.js.map +1 -1
- package/dist/leader-thread/mutationlog.d.ts +4 -17
- package/dist/leader-thread/mutationlog.d.ts.map +1 -1
- package/dist/leader-thread/mutationlog.js +2 -1
- package/dist/leader-thread/mutationlog.js.map +1 -1
- package/dist/leader-thread/pull-queue-set.d.ts.map +1 -1
- package/dist/leader-thread/recreate-db.d.ts.map +1 -1
- package/dist/leader-thread/recreate-db.js +9 -3
- package/dist/leader-thread/recreate-db.js.map +1 -1
- package/dist/leader-thread/types.d.ts +17 -9
- package/dist/leader-thread/types.d.ts.map +1 -1
- package/dist/leader-thread/types.js.map +1 -1
- package/dist/mutation.d.ts +9 -2
- package/dist/mutation.d.ts.map +1 -1
- package/dist/mutation.js +5 -5
- package/dist/mutation.js.map +1 -1
- package/dist/query-builder/impl.d.ts +1 -1
- package/dist/rehydrate-from-mutationlog.d.ts +2 -2
- package/dist/rehydrate-from-mutationlog.d.ts.map +1 -1
- package/dist/rehydrate-from-mutationlog.js +13 -19
- package/dist/rehydrate-from-mutationlog.js.map +1 -1
- package/dist/schema/EventId.d.ts +16 -14
- package/dist/schema/EventId.d.ts.map +1 -1
- package/dist/schema/EventId.js +15 -7
- package/dist/schema/EventId.js.map +1 -1
- package/dist/schema/EventId.test.d.ts +2 -0
- package/dist/schema/EventId.test.d.ts.map +1 -0
- package/dist/schema/EventId.test.js +11 -0
- package/dist/schema/EventId.test.js.map +1 -0
- package/dist/schema/MutationEvent.d.ts +49 -80
- package/dist/schema/MutationEvent.d.ts.map +1 -1
- package/dist/schema/MutationEvent.js +32 -15
- package/dist/schema/MutationEvent.js.map +1 -1
- package/dist/schema/MutationEvent.test.d.ts +2 -0
- package/dist/schema/MutationEvent.test.d.ts.map +1 -0
- package/dist/schema/MutationEvent.test.js +2 -0
- package/dist/schema/MutationEvent.test.js.map +1 -0
- package/dist/schema/system-tables.d.ts +26 -26
- package/dist/schema/system-tables.d.ts.map +1 -1
- package/dist/schema/system-tables.js +19 -11
- package/dist/schema/system-tables.js.map +1 -1
- package/dist/schema-management/migrations.js +6 -6
- package/dist/schema-management/migrations.js.map +1 -1
- package/dist/sync/ClientSessionSyncProcessor.d.ts +45 -0
- package/dist/sync/ClientSessionSyncProcessor.d.ts.map +1 -0
- package/dist/sync/ClientSessionSyncProcessor.js +134 -0
- package/dist/sync/ClientSessionSyncProcessor.js.map +1 -0
- package/dist/sync/client-session-sync-processor.d.ts +4 -4
- package/dist/sync/client-session-sync-processor.d.ts.map +1 -1
- package/dist/sync/index.d.ts +1 -1
- package/dist/sync/index.d.ts.map +1 -1
- package/dist/sync/index.js +1 -1
- package/dist/sync/index.js.map +1 -1
- package/dist/sync/next/history-dag-common.d.ts +1 -4
- package/dist/sync/next/history-dag-common.d.ts.map +1 -1
- package/dist/sync/next/history-dag-common.js +1 -1
- package/dist/sync/next/history-dag-common.js.map +1 -1
- package/dist/sync/next/rebase-events.d.ts +3 -3
- package/dist/sync/next/rebase-events.d.ts.map +1 -1
- package/dist/sync/next/rebase-events.js +3 -2
- package/dist/sync/next/rebase-events.js.map +1 -1
- package/dist/sync/next/test/mutation-fixtures.d.ts.map +1 -1
- package/dist/sync/next/test/mutation-fixtures.js +3 -9
- package/dist/sync/next/test/mutation-fixtures.js.map +1 -1
- package/dist/sync/sync.d.ts +21 -11
- package/dist/sync/sync.d.ts.map +1 -1
- package/dist/sync/sync.js.map +1 -1
- package/dist/sync/syncstate.d.ts +45 -23
- package/dist/sync/syncstate.d.ts.map +1 -1
- package/dist/sync/syncstate.js +56 -12
- package/dist/sync/syncstate.js.map +1 -1
- package/dist/sync/syncstate.test.js +125 -69
- package/dist/sync/syncstate.test.js.map +1 -1
- package/dist/sync/validate-push-payload.d.ts +2 -2
- package/dist/sync/validate-push-payload.d.ts.map +1 -1
- package/dist/sync/validate-push-payload.js +2 -2
- package/dist/sync/validate-push-payload.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/package.json +6 -5
- package/src/adapter-types.ts +22 -24
- package/src/derived-mutations.test.ts +1 -1
- package/src/derived-mutations.ts +9 -5
- package/src/devtools/devtools-bridge.ts +2 -1
- package/src/devtools/devtools-messages.ts +9 -6
- package/src/index.ts +0 -6
- package/src/leader-thread/{leader-sync-processor.ts → LeaderSyncProcessor.ts} +235 -230
- package/src/leader-thread/apply-mutation.ts +49 -31
- package/src/leader-thread/leader-worker-devtools.ts +30 -109
- package/src/leader-thread/make-leader-thread-layer.ts +24 -13
- package/src/leader-thread/mutationlog.ts +9 -5
- package/src/leader-thread/recreate-db.ts +9 -5
- package/src/leader-thread/types.ts +18 -11
- package/src/mutation.ts +17 -7
- package/src/rehydrate-from-mutationlog.ts +15 -23
- package/src/schema/EventId.test.ts +12 -0
- package/src/schema/EventId.ts +23 -9
- package/src/schema/MutationEvent.ts +46 -24
- package/src/schema/system-tables.ts +19 -11
- package/src/schema-management/migrations.ts +6 -6
- package/src/sync/{client-session-sync-processor.ts → ClientSessionSyncProcessor.ts} +11 -9
- package/src/sync/index.ts +1 -1
- package/src/sync/next/history-dag-common.ts +1 -1
- package/src/sync/next/rebase-events.ts +7 -7
- package/src/sync/next/test/mutation-fixtures.ts +3 -10
- package/src/sync/sync.ts +19 -6
- package/src/sync/syncstate.test.ts +127 -67
- package/src/sync/syncstate.ts +21 -19
- package/src/sync/validate-push-payload.ts +7 -4
- package/src/version.ts +1 -1
package/dist/index.d.ts.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,2BAA2B,CAAA;AACzC,cAAc,WAAW,CAAA;AACzB,cAAc,oBAAoB,CAAA;AAClC,cAAc,mCAAmC,CAAA;AACjD,cAAc,eAAe,CAAA;AAC7B,cAAc,4BAA4B,CAAA;AAC1C,cAAc,iCAAiC,CAAA;AAC/C,cAAc,iBAAiB,CAAA;AAC/B,cAAc,wBAAwB,CAAA;AACtC,cAAc,iBAAiB,CAAA;AAC/B,OAAO,KAAK,QAAQ,MAAM,qBAAqB,CAAA;AAC/C,cAAc,iBAAiB,CAAA;AAC/B,cAAc,0BAA0B,CAAA;AACxC,cAAc,cAAc,CAAA;AAC5B,cAAc,wBAAwB,CAAA;AACtC,cAAc,qBAAqB,CAAA;AACnC,cAAc,WAAW,CAAA
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,2BAA2B,CAAA;AACzC,cAAc,WAAW,CAAA;AACzB,cAAc,oBAAoB,CAAA;AAClC,cAAc,mCAAmC,CAAA;AACjD,cAAc,eAAe,CAAA;AAC7B,cAAc,4BAA4B,CAAA;AAC1C,cAAc,iCAAiC,CAAA;AAC/C,cAAc,iBAAiB,CAAA;AAC/B,cAAc,wBAAwB,CAAA;AACtC,cAAc,iBAAiB,CAAA;AAC/B,OAAO,KAAK,QAAQ,MAAM,qBAAqB,CAAA;AAC/C,cAAc,iBAAiB,CAAA;AAC/B,cAAc,0BAA0B,CAAA;AACxC,cAAc,cAAc,CAAA;AAC5B,cAAc,wBAAwB,CAAA;AACtC,cAAc,qBAAqB,CAAA;AACnC,cAAc,WAAW,CAAA"}
|
@@ -0,0 +1,37 @@
|
|
1
|
+
import type { Scope } from '@livestore/utils/effect';
|
2
|
+
import { Effect } from '@livestore/utils/effect';
|
3
|
+
import type { SynchronousDatabase } from '../adapter-types.js';
|
4
|
+
import { UnexpectedError } from '../adapter-types.js';
|
5
|
+
import type { LiveStoreSchema } from '../schema/mod.js';
|
6
|
+
import type { InitialBlockingSyncContext, LeaderSyncProcessor } from './types.js';
|
7
|
+
/**
|
8
|
+
* The LeaderSyncProcessor manages synchronization of mutations between
|
9
|
+
* the local state and the sync backend, ensuring efficient and orderly processing.
|
10
|
+
*
|
11
|
+
* In the LeaderSyncProcessor, pulling always has precedence over pushing.
|
12
|
+
*
|
13
|
+
* Responsibilities:
|
14
|
+
* - Queueing incoming local mutations in a localPushMailbox.
|
15
|
+
* - Broadcasting mutations to client sessions via pull queues.
|
16
|
+
* - Pushing mutations to the sync backend.
|
17
|
+
*
|
18
|
+
* Notes:
|
19
|
+
*
|
20
|
+
* local push processing:
|
21
|
+
* - localPushMailbox:
|
22
|
+
* - Maintains events in ascending order.
|
23
|
+
* - Uses `Deferred` objects to resolve/reject events based on application success.
|
24
|
+
* - Processes events from the mailbox, applying mutations in batches.
|
25
|
+
* - Controlled by a `Latch` to manage execution flow.
|
26
|
+
* - The latch closes on pull receipt and re-opens post-pull completion.
|
27
|
+
* - Processes up to `maxBatchSize` events per cycle.
|
28
|
+
*
|
29
|
+
*/
|
30
|
+
export declare const makeLeaderSyncProcessor: ({ schema, dbMissing, dbLog, initialBlockingSyncContext, }: {
|
31
|
+
schema: LiveStoreSchema;
|
32
|
+
/** Only used to know whether we can safely query dbLog during setup execution */
|
33
|
+
dbMissing: boolean;
|
34
|
+
dbLog: SynchronousDatabase;
|
35
|
+
initialBlockingSyncContext: InitialBlockingSyncContext;
|
36
|
+
}) => Effect.Effect<LeaderSyncProcessor, UnexpectedError, Scope.Scope>;
|
37
|
+
//# sourceMappingURL=LeaderSyncProcessor.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"LeaderSyncProcessor.d.ts","sourceRoot":"","sources":["../../src/leader-thread/LeaderSyncProcessor.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAc,KAAK,EAAE,MAAM,yBAAyB,CAAA;AAChE,OAAO,EAGL,MAAM,EAUP,MAAM,yBAAyB,CAAA;AAGhC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAA;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AACrD,OAAO,KAAK,EAAE,eAAe,EAA2B,MAAM,kBAAkB,CAAA;AAehF,OAAO,KAAK,EAAE,0BAA0B,EAAmB,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAQlG;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,uBAAuB,8DAKjC;IACD,MAAM,EAAE,eAAe,CAAA;IACvB,iFAAiF;IACjF,SAAS,EAAE,OAAO,CAAA;IAClB,KAAK,EAAE,mBAAmB,CAAA;IAC1B,0BAA0B,EAAE,0BAA0B,CAAA;CACvD,KAAG,MAAM,CAAC,MAAM,CAAC,mBAAmB,EAAE,eAAe,EAAE,KAAK,CAAC,KAAK,CAwK/D,CAAA"}
|
@@ -0,0 +1,417 @@
|
|
1
|
+
import { isNotUndefined, shouldNeverHappen, TRACE_VERBOSE } from '@livestore/utils';
|
2
|
+
import { BucketQueue, Deferred, Effect, Exit, FiberHandle, Option, OtelTracer, ReadonlyArray, Schema, Stream, Subscribable, SubscriptionRef, } from '@livestore/utils/effect';
|
3
|
+
import { UnexpectedError } from '../adapter-types.js';
|
4
|
+
import { EventId, MUTATION_LOG_META_TABLE, MutationEvent, mutationLogMetaTable, SESSION_CHANGESET_META_TABLE, } from '../schema/mod.js';
|
5
|
+
import { updateRows } from '../sql-queries/index.js';
|
6
|
+
import { InvalidPushError } from '../sync/sync.js';
|
7
|
+
import * as SyncState from '../sync/syncstate.js';
|
8
|
+
import { sql } from '../util.js';
|
9
|
+
import { makeApplyMutation } from './apply-mutation.js';
|
10
|
+
import { execSql } from './connection.js';
|
11
|
+
import { getBackendHeadFromDb, getLocalHeadFromDb, getMutationEventsSince, updateBackendHead } from './mutationlog.js';
|
12
|
+
import { LeaderThreadCtx } from './types.js';
|
13
|
+
/**
|
14
|
+
* The LeaderSyncProcessor manages synchronization of mutations between
|
15
|
+
* the local state and the sync backend, ensuring efficient and orderly processing.
|
16
|
+
*
|
17
|
+
* In the LeaderSyncProcessor, pulling always has precedence over pushing.
|
18
|
+
*
|
19
|
+
* Responsibilities:
|
20
|
+
* - Queueing incoming local mutations in a localPushMailbox.
|
21
|
+
* - Broadcasting mutations to client sessions via pull queues.
|
22
|
+
* - Pushing mutations to the sync backend.
|
23
|
+
*
|
24
|
+
* Notes:
|
25
|
+
*
|
26
|
+
* local push processing:
|
27
|
+
* - localPushMailbox:
|
28
|
+
* - Maintains events in ascending order.
|
29
|
+
* - Uses `Deferred` objects to resolve/reject events based on application success.
|
30
|
+
* - Processes events from the mailbox, applying mutations in batches.
|
31
|
+
* - Controlled by a `Latch` to manage execution flow.
|
32
|
+
* - The latch closes on pull receipt and re-opens post-pull completion.
|
33
|
+
* - Processes up to `maxBatchSize` events per cycle.
|
34
|
+
*
|
35
|
+
*/
|
36
|
+
export const makeLeaderSyncProcessor = ({ schema, dbMissing, dbLog, initialBlockingSyncContext, }) => Effect.gen(function* () {
|
37
|
+
const syncBackendQueue = yield* BucketQueue.make();
|
38
|
+
const syncStateSref = yield* SubscriptionRef.make(undefined);
|
39
|
+
const isLocalEvent = (mutationEventEncoded) => {
|
40
|
+
const mutationDef = schema.mutations.get(mutationEventEncoded.mutation);
|
41
|
+
return mutationDef.options.localOnly;
|
42
|
+
};
|
43
|
+
const spanRef = { current: undefined };
|
44
|
+
const localPushesQueue = yield* BucketQueue.make();
|
45
|
+
const localPushesLatch = yield* Effect.makeLatch(true);
|
46
|
+
const pullLatch = yield* Effect.makeLatch(true);
|
47
|
+
const push = (newEvents, options) => Effect.gen(function* () {
|
48
|
+
// TODO validate batch
|
49
|
+
if (newEvents.length === 0)
|
50
|
+
return;
|
51
|
+
const waitForProcessing = options?.waitForProcessing ?? false;
|
52
|
+
if (waitForProcessing) {
|
53
|
+
const deferreds = yield* Effect.forEach(newEvents, () => Deferred.make());
|
54
|
+
const items = newEvents.map((mutationEventEncoded, i) => [mutationEventEncoded, deferreds[i]]);
|
55
|
+
yield* BucketQueue.offerAll(localPushesQueue, items);
|
56
|
+
yield* Effect.all(deferreds);
|
57
|
+
}
|
58
|
+
else {
|
59
|
+
const items = newEvents.map((mutationEventEncoded) => [mutationEventEncoded, undefined]);
|
60
|
+
yield* BucketQueue.offerAll(localPushesQueue, items);
|
61
|
+
}
|
62
|
+
}).pipe(Effect.withSpan('@livestore/common:leader-thread:syncing:local-push', {
|
63
|
+
attributes: {
|
64
|
+
batchSize: newEvents.length,
|
65
|
+
batch: TRACE_VERBOSE ? newEvents : undefined,
|
66
|
+
},
|
67
|
+
links: spanRef.current
|
68
|
+
? [{ _tag: 'SpanLink', span: OtelTracer.makeExternalSpan(spanRef.current.spanContext()), attributes: {} }]
|
69
|
+
: undefined,
|
70
|
+
}));
|
71
|
+
const pushPartial = (mutationEventEncoded_) => Effect.gen(function* () {
|
72
|
+
const syncState = yield* syncStateSref;
|
73
|
+
if (syncState === undefined)
|
74
|
+
return shouldNeverHappen('Not initialized');
|
75
|
+
const mutationDef = schema.mutations.get(mutationEventEncoded_.mutation) ??
|
76
|
+
shouldNeverHappen(`Unknown mutation: ${mutationEventEncoded_.mutation}`);
|
77
|
+
const mutationEventEncoded = new MutationEvent.EncodedWithMeta({
|
78
|
+
...mutationEventEncoded_,
|
79
|
+
...EventId.nextPair(syncState.localHead, mutationDef.options.localOnly),
|
80
|
+
});
|
81
|
+
yield* push([mutationEventEncoded]);
|
82
|
+
}).pipe(Effect.catchTag('InvalidPushError', Effect.orDie));
|
83
|
+
// Starts various background loops
|
84
|
+
const boot = ({ dbReady }) => Effect.gen(function* () {
|
85
|
+
const span = yield* OtelTracer.currentOtelSpan.pipe(Effect.catchAll(() => Effect.succeed(undefined)));
|
86
|
+
spanRef.current = span;
|
87
|
+
const initialBackendHead = dbMissing ? EventId.ROOT.global : getBackendHeadFromDb(dbLog);
|
88
|
+
const initialLocalHead = dbMissing ? EventId.ROOT : getLocalHeadFromDb(dbLog);
|
89
|
+
if (initialBackendHead > initialLocalHead.global) {
|
90
|
+
return shouldNeverHappen(`During boot the backend head (${initialBackendHead}) should never be greater than the local head (${initialLocalHead.global})`);
|
91
|
+
}
|
92
|
+
const pendingMutationEvents = yield* getMutationEventsSince({
|
93
|
+
global: initialBackendHead,
|
94
|
+
local: EventId.localDefault,
|
95
|
+
}).pipe(Effect.map(ReadonlyArray.map((_) => new MutationEvent.EncodedWithMeta(_))));
|
96
|
+
const initialSyncState = new SyncState.SyncState({
|
97
|
+
pending: pendingMutationEvents,
|
98
|
+
// On the leader we don't need a rollback tail beyond `pending` items
|
99
|
+
rollbackTail: [],
|
100
|
+
upstreamHead: { global: initialBackendHead, local: EventId.localDefault },
|
101
|
+
localHead: initialLocalHead,
|
102
|
+
});
|
103
|
+
/** State transitions need to happen atomically, so we use a Ref to track the state */
|
104
|
+
yield* SubscriptionRef.set(syncStateSref, initialSyncState);
|
105
|
+
// Rehydrate sync queue
|
106
|
+
if (pendingMutationEvents.length > 0) {
|
107
|
+
const filteredBatch = pendingMutationEvents
|
108
|
+
// Don't sync localOnly mutations
|
109
|
+
.filter((mutationEventEncoded) => {
|
110
|
+
const mutationDef = schema.mutations.get(mutationEventEncoded.mutation);
|
111
|
+
return mutationDef.options.localOnly === false;
|
112
|
+
});
|
113
|
+
yield* BucketQueue.offerAll(syncBackendQueue, filteredBatch);
|
114
|
+
}
|
115
|
+
yield* backgroundApplyLocalPushes({
|
116
|
+
localPushesLatch,
|
117
|
+
localPushesQueue,
|
118
|
+
pullLatch,
|
119
|
+
syncStateSref,
|
120
|
+
syncBackendQueue,
|
121
|
+
schema,
|
122
|
+
isLocalEvent,
|
123
|
+
span,
|
124
|
+
}).pipe(Effect.tapCauseLogPretty, Effect.forkScoped);
|
125
|
+
const backendPushingFiberHandle = yield* FiberHandle.make();
|
126
|
+
yield* FiberHandle.run(backendPushingFiberHandle, backgroundBackendPushing({ dbReady, syncBackendQueue, span }).pipe(Effect.tapCauseLogPretty));
|
127
|
+
yield* backgroundBackendPulling({
|
128
|
+
dbReady,
|
129
|
+
initialBackendHead,
|
130
|
+
isLocalEvent,
|
131
|
+
restartBackendPushing: (filteredRebasedPending) => Effect.gen(function* () {
|
132
|
+
// Stop current pushing fiber
|
133
|
+
yield* FiberHandle.clear(backendPushingFiberHandle);
|
134
|
+
// Reset the sync queue
|
135
|
+
yield* BucketQueue.clear(syncBackendQueue);
|
136
|
+
yield* BucketQueue.offerAll(syncBackendQueue, filteredRebasedPending);
|
137
|
+
// Restart pushing fiber
|
138
|
+
yield* FiberHandle.run(backendPushingFiberHandle, backgroundBackendPushing({ dbReady, syncBackendQueue, span }).pipe(Effect.tapCauseLogPretty));
|
139
|
+
}),
|
140
|
+
syncStateSref,
|
141
|
+
localPushesLatch,
|
142
|
+
pullLatch,
|
143
|
+
span,
|
144
|
+
initialBlockingSyncContext,
|
145
|
+
}).pipe(Effect.tapCauseLogPretty, Effect.forkScoped);
|
146
|
+
}).pipe(Effect.withSpanScoped('@livestore/common:leader-thread:syncing'));
|
147
|
+
return {
|
148
|
+
push,
|
149
|
+
pushPartial,
|
150
|
+
boot,
|
151
|
+
syncState: Subscribable.make({
|
152
|
+
get: Effect.gen(function* () {
|
153
|
+
const syncState = yield* syncStateSref;
|
154
|
+
if (syncState === undefined)
|
155
|
+
return shouldNeverHappen('Not initialized');
|
156
|
+
return syncState;
|
157
|
+
}),
|
158
|
+
changes: syncStateSref.changes.pipe(Stream.filter(isNotUndefined)),
|
159
|
+
}),
|
160
|
+
};
|
161
|
+
});
|
162
|
+
const backgroundApplyLocalPushes = ({ localPushesLatch, localPushesQueue, pullLatch, syncStateSref, syncBackendQueue, schema, isLocalEvent, span, }) => Effect.gen(function* () {
|
163
|
+
const { connectedClientSessionPullQueues } = yield* LeaderThreadCtx;
|
164
|
+
const applyMutationItems = yield* makeApplyMutationItems;
|
165
|
+
while (true) {
|
166
|
+
// TODO make batch size configurable
|
167
|
+
const batchItems = yield* BucketQueue.takeBetween(localPushesQueue, 1, 10);
|
168
|
+
const [newEvents, deferreds] = ReadonlyArray.unzip(batchItems);
|
169
|
+
// Wait for the backend pulling to finish
|
170
|
+
yield* localPushesLatch.await;
|
171
|
+
// Prevent the backend pulling from starting until this local push is finished
|
172
|
+
yield* pullLatch.close;
|
173
|
+
const syncState = yield* syncStateSref;
|
174
|
+
if (syncState === undefined)
|
175
|
+
return shouldNeverHappen('Not initialized');
|
176
|
+
const updateResult = SyncState.updateSyncState({
|
177
|
+
syncState,
|
178
|
+
payload: { _tag: 'local-push', newEvents },
|
179
|
+
isLocalEvent,
|
180
|
+
isEqualEvent: MutationEvent.isEqualEncoded,
|
181
|
+
});
|
182
|
+
if (updateResult._tag === 'rebase') {
|
183
|
+
return shouldNeverHappen('The leader thread should never have to rebase due to a local push');
|
184
|
+
}
|
185
|
+
else if (updateResult._tag === 'reject') {
|
186
|
+
span?.addEvent('local-push:reject', {
|
187
|
+
batchSize: newEvents.length,
|
188
|
+
updateResult: TRACE_VERBOSE ? JSON.stringify(updateResult) : undefined,
|
189
|
+
});
|
190
|
+
const providedId = newEvents.at(0).id;
|
191
|
+
const remainingEvents = yield* BucketQueue.takeAll(localPushesQueue);
|
192
|
+
const allDeferreds = [...deferreds, ...remainingEvents.map(([_, deferred]) => deferred)].filter(isNotUndefined);
|
193
|
+
yield* Effect.forEach(allDeferreds, (deferred) => Deferred.fail(deferred, InvalidPushError.make({
|
194
|
+
// TODO improve error handling so it differentiates between a push being rejected
|
195
|
+
// because of itself or because of another push
|
196
|
+
reason: {
|
197
|
+
_tag: 'LeaderAhead',
|
198
|
+
minimumExpectedId: updateResult.expectedMinimumId,
|
199
|
+
providedId,
|
200
|
+
},
|
201
|
+
})));
|
202
|
+
// Allow the backend pulling to start
|
203
|
+
yield* pullLatch.open;
|
204
|
+
// In this case we're skipping state update and down/upstream processing
|
205
|
+
// We've cleared the local push queue and are now waiting for new local pushes / backend pulls
|
206
|
+
continue;
|
207
|
+
}
|
208
|
+
yield* SubscriptionRef.set(syncStateSref, updateResult.newSyncState);
|
209
|
+
yield* connectedClientSessionPullQueues.offer({
|
210
|
+
payload: { _tag: 'upstream-advance', newEvents: updateResult.newEvents },
|
211
|
+
remaining: 0,
|
212
|
+
});
|
213
|
+
span?.addEvent('local-push', {
|
214
|
+
batchSize: newEvents.length,
|
215
|
+
updateResult: TRACE_VERBOSE ? JSON.stringify(updateResult) : undefined,
|
216
|
+
});
|
217
|
+
// Don't sync localOnly mutations
|
218
|
+
const filteredBatch = updateResult.newEvents.filter((mutationEventEncoded) => {
|
219
|
+
const mutationDef = schema.mutations.get(mutationEventEncoded.mutation);
|
220
|
+
return mutationDef.options.localOnly === false;
|
221
|
+
});
|
222
|
+
yield* BucketQueue.offerAll(syncBackendQueue, filteredBatch);
|
223
|
+
yield* applyMutationItems({ batchItems: newEvents, deferreds });
|
224
|
+
// Allow the backend pulling to start
|
225
|
+
yield* pullLatch.open;
|
226
|
+
}
|
227
|
+
});
|
228
|
+
// TODO how to handle errors gracefully
|
229
|
+
const makeApplyMutationItems = Effect.gen(function* () {
|
230
|
+
const leaderThreadCtx = yield* LeaderThreadCtx;
|
231
|
+
const { db, dbLog } = leaderThreadCtx;
|
232
|
+
const applyMutation = yield* makeApplyMutation;
|
233
|
+
return ({ batchItems, deferreds }) => Effect.gen(function* () {
|
234
|
+
db.execute('BEGIN TRANSACTION', undefined); // Start the transaction
|
235
|
+
dbLog.execute('BEGIN TRANSACTION', undefined); // Start the transaction
|
236
|
+
yield* Effect.addFinalizer((exit) => Effect.gen(function* () {
|
237
|
+
if (Exit.isSuccess(exit))
|
238
|
+
return;
|
239
|
+
// Rollback in case of an error
|
240
|
+
db.execute('ROLLBACK', undefined);
|
241
|
+
dbLog.execute('ROLLBACK', undefined);
|
242
|
+
}));
|
243
|
+
for (let i = 0; i < batchItems.length; i++) {
|
244
|
+
yield* applyMutation(batchItems[i]);
|
245
|
+
if (deferreds?.[i] !== undefined) {
|
246
|
+
yield* Deferred.succeed(deferreds[i], void 0);
|
247
|
+
}
|
248
|
+
}
|
249
|
+
db.execute('COMMIT', undefined); // Commit the transaction
|
250
|
+
dbLog.execute('COMMIT', undefined); // Commit the transaction
|
251
|
+
}).pipe(Effect.uninterruptible, Effect.scoped, Effect.withSpan('@livestore/common:leader-thread:syncing:applyMutationItems', {
|
252
|
+
attributes: { count: batchItems.length },
|
253
|
+
}), Effect.tapCauseLogPretty, UnexpectedError.mapToUnexpectedError);
|
254
|
+
});
|
255
|
+
const backgroundBackendPulling = ({ dbReady, initialBackendHead, isLocalEvent, restartBackendPushing, span, syncStateSref, localPushesLatch, pullLatch, initialBlockingSyncContext, }) => Effect.gen(function* () {
|
256
|
+
const { syncBackend, db, dbLog, connectedClientSessionPullQueues, schema } = yield* LeaderThreadCtx;
|
257
|
+
if (syncBackend === undefined)
|
258
|
+
return;
|
259
|
+
const cursorInfo = yield* getCursorInfo(initialBackendHead);
|
260
|
+
const applyMutationItems = yield* makeApplyMutationItems;
|
261
|
+
const onNewPullChunk = (newEvents, remaining) => Effect.gen(function* () {
|
262
|
+
if (newEvents.length === 0)
|
263
|
+
return;
|
264
|
+
// Prevent more local pushes from being processed until this pull is finished
|
265
|
+
yield* localPushesLatch.close;
|
266
|
+
// Wait for pending local pushes to finish
|
267
|
+
yield* pullLatch.await;
|
268
|
+
const syncState = yield* syncStateSref;
|
269
|
+
if (syncState === undefined)
|
270
|
+
return shouldNeverHappen('Not initialized');
|
271
|
+
const trimRollbackUntil = newEvents.at(-1).id;
|
272
|
+
const updateResult = SyncState.updateSyncState({
|
273
|
+
syncState,
|
274
|
+
payload: { _tag: 'upstream-advance', newEvents, trimRollbackUntil },
|
275
|
+
isLocalEvent,
|
276
|
+
isEqualEvent: MutationEvent.isEqualEncoded,
|
277
|
+
ignoreLocalEvents: true,
|
278
|
+
});
|
279
|
+
if (updateResult._tag === 'reject') {
|
280
|
+
return shouldNeverHappen('The leader thread should never reject upstream advances');
|
281
|
+
}
|
282
|
+
const newBackendHead = newEvents.at(-1).id;
|
283
|
+
updateBackendHead(dbLog, newBackendHead);
|
284
|
+
if (updateResult._tag === 'rebase') {
|
285
|
+
span?.addEvent('backend-pull:rebase', {
|
286
|
+
newEventsCount: newEvents.length,
|
287
|
+
newEvents: TRACE_VERBOSE ? JSON.stringify(newEvents) : undefined,
|
288
|
+
rollbackCount: updateResult.eventsToRollback.length,
|
289
|
+
updateResult: TRACE_VERBOSE ? JSON.stringify(updateResult) : undefined,
|
290
|
+
});
|
291
|
+
const filteredRebasedPending = updateResult.newSyncState.pending.filter((mutationEvent) => {
|
292
|
+
const mutationDef = schema.mutations.get(mutationEvent.mutation);
|
293
|
+
return mutationDef.options.localOnly === false;
|
294
|
+
});
|
295
|
+
yield* restartBackendPushing(filteredRebasedPending);
|
296
|
+
if (updateResult.eventsToRollback.length > 0) {
|
297
|
+
yield* rollback({ db, dbLog, eventIdsToRollback: updateResult.eventsToRollback.map((_) => _.id) });
|
298
|
+
}
|
299
|
+
yield* connectedClientSessionPullQueues.offer({
|
300
|
+
payload: {
|
301
|
+
_tag: 'upstream-rebase',
|
302
|
+
newEvents: updateResult.newEvents,
|
303
|
+
rollbackUntil: updateResult.eventsToRollback.at(0).id,
|
304
|
+
trimRollbackUntil,
|
305
|
+
},
|
306
|
+
remaining,
|
307
|
+
});
|
308
|
+
}
|
309
|
+
else {
|
310
|
+
span?.addEvent('backend-pull:advance', {
|
311
|
+
newEventsCount: newEvents.length,
|
312
|
+
updateResult: TRACE_VERBOSE ? JSON.stringify(updateResult) : undefined,
|
313
|
+
});
|
314
|
+
yield* connectedClientSessionPullQueues.offer({
|
315
|
+
payload: { _tag: 'upstream-advance', newEvents: updateResult.newEvents, trimRollbackUntil },
|
316
|
+
remaining,
|
317
|
+
});
|
318
|
+
}
|
319
|
+
trimChangesetRows(db, newBackendHead);
|
320
|
+
yield* applyMutationItems({ batchItems: updateResult.newEvents, deferreds: undefined });
|
321
|
+
yield* SubscriptionRef.set(syncStateSref, updateResult.newSyncState);
|
322
|
+
if (remaining === 0) {
|
323
|
+
// Allow local pushes to be processed again
|
324
|
+
yield* localPushesLatch.open;
|
325
|
+
}
|
326
|
+
});
|
327
|
+
yield* syncBackend.pull(cursorInfo).pipe(
|
328
|
+
// TODO only take from queue while connected
|
329
|
+
Stream.tap(({ batch, remaining }) => Effect.gen(function* () {
|
330
|
+
// yield* Effect.spanEvent('batch', {
|
331
|
+
// attributes: {
|
332
|
+
// batchSize: batch.length,
|
333
|
+
// batch: TRACE_VERBOSE ? batch : undefined,
|
334
|
+
// },
|
335
|
+
// })
|
336
|
+
// Wait for the db to be initially created
|
337
|
+
yield* dbReady;
|
338
|
+
// NOTE we only want to take process mutations when the sync backend is connected
|
339
|
+
// (e.g. needed for simulating being offline)
|
340
|
+
// TODO remove when there's a better way to handle this in stream above
|
341
|
+
yield* SubscriptionRef.waitUntil(syncBackend.isConnected, (isConnected) => isConnected === true);
|
342
|
+
yield* onNewPullChunk(batch.map((_) => MutationEvent.EncodedWithMeta.fromGlobal(_.mutationEventEncoded)), remaining);
|
343
|
+
yield* initialBlockingSyncContext.update({ processed: batch.length, remaining });
|
344
|
+
})), Stream.runDrain, Effect.interruptible);
|
345
|
+
}).pipe(Effect.withSpan('@livestore/common:leader-thread:syncing:backend-pulling'));
|
346
|
+
const rollback = ({ db, dbLog, eventIdsToRollback, }) => Effect.gen(function* () {
|
347
|
+
const rollbackEvents = db
|
348
|
+
.select(sql `SELECT * FROM ${SESSION_CHANGESET_META_TABLE} WHERE (idGlobal, idLocal) IN (${eventIdsToRollback.map((id) => `(${id.global}, ${id.local})`).join(', ')})`)
|
349
|
+
.map((_) => ({ id: { global: _.idGlobal, local: _.idLocal }, changeset: _.changeset, debug: _.debug }))
|
350
|
+
.toSorted((a, b) => EventId.compare(a.id, b.id));
|
351
|
+
// Apply changesets in reverse order
|
352
|
+
for (let i = rollbackEvents.length - 1; i >= 0; i--) {
|
353
|
+
const { changeset } = rollbackEvents[i];
|
354
|
+
if (changeset !== null) {
|
355
|
+
db.makeChangeset(changeset).invert().apply();
|
356
|
+
}
|
357
|
+
}
|
358
|
+
// Delete the changeset rows
|
359
|
+
db.execute(sql `DELETE FROM ${SESSION_CHANGESET_META_TABLE} WHERE (idGlobal, idLocal) IN (${eventIdsToRollback.map((id) => `(${id.global}, ${id.local})`).join(', ')})`);
|
360
|
+
// Delete the mutation log rows
|
361
|
+
dbLog.execute(sql `DELETE FROM ${MUTATION_LOG_META_TABLE} WHERE (idGlobal, idLocal) IN (${eventIdsToRollback.map((id) => `(${id.global}, ${id.local})`).join(', ')})`);
|
362
|
+
}).pipe(Effect.withSpan('@livestore/common:leader-thread:syncing:rollback', {
|
363
|
+
attributes: { count: eventIdsToRollback.length },
|
364
|
+
}));
|
365
|
+
const getCursorInfo = (remoteHead) => Effect.gen(function* () {
|
366
|
+
const { dbLog } = yield* LeaderThreadCtx;
|
367
|
+
if (remoteHead === EventId.ROOT.global)
|
368
|
+
return Option.none();
|
369
|
+
const MutationlogQuerySchema = Schema.Struct({
|
370
|
+
syncMetadataJson: Schema.parseJson(Schema.Option(Schema.JsonValue)),
|
371
|
+
}).pipe(Schema.pluck('syncMetadataJson'), Schema.Array, Schema.head);
|
372
|
+
const syncMetadataOption = yield* Effect.sync(() => dbLog.select(sql `SELECT syncMetadataJson FROM ${MUTATION_LOG_META_TABLE} WHERE idGlobal = ${remoteHead} ORDER BY idLocal ASC LIMIT 1`)).pipe(Effect.andThen(Schema.decode(MutationlogQuerySchema)), Effect.map(Option.flatten), Effect.orDie);
|
373
|
+
return Option.some({
|
374
|
+
cursor: { global: remoteHead, local: EventId.localDefault },
|
375
|
+
metadata: syncMetadataOption,
|
376
|
+
});
|
377
|
+
}).pipe(Effect.withSpan('@livestore/common:leader-thread:syncing:getCursorInfo', { attributes: { remoteHead } }));
|
378
|
+
const backgroundBackendPushing = ({ dbReady, syncBackendQueue, span, }) => Effect.gen(function* () {
|
379
|
+
const { syncBackend, dbLog } = yield* LeaderThreadCtx;
|
380
|
+
if (syncBackend === undefined)
|
381
|
+
return;
|
382
|
+
yield* dbReady;
|
383
|
+
while (true) {
|
384
|
+
yield* SubscriptionRef.waitUntil(syncBackend.isConnected, (isConnected) => isConnected === true);
|
385
|
+
// TODO make batch size configurable
|
386
|
+
const queueItems = yield* BucketQueue.takeBetween(syncBackendQueue, 1, 50);
|
387
|
+
yield* SubscriptionRef.waitUntil(syncBackend.isConnected, (isConnected) => isConnected === true);
|
388
|
+
span?.addEvent('backend-push', {
|
389
|
+
batchSize: queueItems.length,
|
390
|
+
batch: TRACE_VERBOSE ? JSON.stringify(queueItems) : undefined,
|
391
|
+
});
|
392
|
+
// TODO handle push errors (should only happen during concurrent pull+push)
|
393
|
+
const pushResult = yield* syncBackend.push(queueItems.map((_) => _.toGlobal())).pipe(Effect.either);
|
394
|
+
if (pushResult._tag === 'Left') {
|
395
|
+
span?.addEvent('backend-push-error', { error: pushResult.left.toString() });
|
396
|
+
// wait for interrupt caused by background pulling which will then restart pushing
|
397
|
+
return yield* Effect.never;
|
398
|
+
}
|
399
|
+
const { metadata } = pushResult.right;
|
400
|
+
// TODO try to do this in a single query
|
401
|
+
for (let i = 0; i < queueItems.length; i++) {
|
402
|
+
const mutationEventEncoded = queueItems[i];
|
403
|
+
yield* execSql(dbLog, ...updateRows({
|
404
|
+
tableName: MUTATION_LOG_META_TABLE,
|
405
|
+
columns: mutationLogMetaTable.sqliteDef.columns,
|
406
|
+
where: { idGlobal: mutationEventEncoded.id.global, idLocal: mutationEventEncoded.id.local },
|
407
|
+
updateValues: { syncMetadataJson: metadata[i] },
|
408
|
+
}));
|
409
|
+
}
|
410
|
+
}
|
411
|
+
}).pipe(Effect.interruptible, Effect.withSpan('@livestore/common:leader-thread:syncing:backend-pushing'));
|
412
|
+
const trimChangesetRows = (db, newHead) => {
|
413
|
+
// Since we're using the session changeset rows to query for the current head,
|
414
|
+
// we're keeping at least one row for the current head, and thus are using `<` instead of `<=`
|
415
|
+
db.execute(sql `DELETE FROM ${SESSION_CHANGESET_META_TABLE} WHERE idGlobal < ${newHead.global}`);
|
416
|
+
};
|
417
|
+
//# sourceMappingURL=LeaderSyncProcessor.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"LeaderSyncProcessor.js","sourceRoot":"","sources":["../../src/leader-thread/LeaderSyncProcessor.ts"],"names":[],"mappings":"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"}
|
@@ -1,8 +1,11 @@
|
|
1
1
|
import type { Scope } from '@livestore/utils/effect';
|
2
2
|
import { Effect } from '@livestore/utils/effect';
|
3
3
|
import type { SqliteError, UnexpectedError } from '../index.js';
|
4
|
-
import type
|
4
|
+
import { type MutationEvent } from '../schema/mod.js';
|
5
5
|
import { LeaderThreadCtx } from './types.js';
|
6
|
-
export type ApplyMutation = (mutationEventEncoded: MutationEvent.AnyEncoded
|
6
|
+
export type ApplyMutation = (mutationEventEncoded: MutationEvent.AnyEncoded, options?: {
|
7
|
+
/** Needed for rehydrateFromMutationLog */
|
8
|
+
skipMutationLog?: boolean;
|
9
|
+
}) => Effect.Effect<void, SqliteError | UnexpectedError>;
|
7
10
|
export declare const makeApplyMutation: Effect.Effect<ApplyMutation, never, Scope.Scope | LeaderThreadCtx>;
|
8
11
|
//# sourceMappingURL=apply-mutation.d.ts.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"apply-mutation.d.ts","sourceRoot":"","sources":["../../src/leader-thread/apply-mutation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAA;AACpD,OAAO,EAAE,MAAM,EAAkB,MAAM,yBAAyB,CAAA;AAEhE,OAAO,KAAK,EAAE,WAAW,EAAuB,eAAe,EAAE,MAAM,aAAa,CAAA;
|
1
|
+
{"version":3,"file":"apply-mutation.d.ts","sourceRoot":"","sources":["../../src/leader-thread/apply-mutation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAA;AACpD,OAAO,EAAE,MAAM,EAAkB,MAAM,yBAAyB,CAAA;AAEhE,OAAO,KAAK,EAAE,WAAW,EAAuB,eAAe,EAAE,MAAM,aAAa,CAAA;AAEpF,OAAO,EAGL,KAAK,aAAa,EAInB,MAAM,kBAAkB,CAAA;AAGzB,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAE5C,MAAM,MAAM,aAAa,GAAG,CAC1B,oBAAoB,EAAE,aAAa,CAAC,UAAU,EAC9C,OAAO,CAAC,EAAE;IACR,0CAA0C;IAC1C,eAAe,CAAC,EAAE,OAAO,CAAA;CAC1B,KACE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,WAAW,GAAG,eAAe,CAAC,CAAA;AAEvD,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,MAAM,CAAC,aAAa,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,GAAG,eAAe,CAmFhG,CAAA"}
|
@@ -1,6 +1,7 @@
|
|
1
1
|
import { memoizeByRef, shouldNeverHappen } from '@livestore/utils';
|
2
2
|
import { Effect, Option, Schema } from '@livestore/utils/effect';
|
3
|
-
import { getExecArgsFromMutation
|
3
|
+
import { getExecArgsFromMutation } from '../mutation.js';
|
4
|
+
import { MUTATION_LOG_META_TABLE, mutationLogMetaTable, SESSION_CHANGESET_META_TABLE, sessionChangesetMetaTable, } from '../schema/mod.js';
|
4
5
|
import { insertRow } from '../sql-queries/index.js';
|
5
6
|
import { execSql, execSqlPrepared } from './connection.js';
|
6
7
|
import { LeaderThreadCtx } from './types.js';
|
@@ -12,12 +13,23 @@ export const makeApplyMutation = Effect.gen(function* () {
|
|
12
13
|
// at build time and lookup the pre-computed hash at runtime.
|
13
14
|
// Also see https://github.com/Effect-TS/effect/issues/2719
|
14
15
|
[...leaderThreadCtx.schema.mutations.entries()].map(([k, v]) => [k, Schema.hash(v.schema)]));
|
15
|
-
return (mutationEventEncoded) => Effect.gen(function* () {
|
16
|
-
const {
|
17
|
-
const
|
18
|
-
const mutationName =
|
16
|
+
return (mutationEventEncoded, options) => Effect.gen(function* () {
|
17
|
+
const { schema, db, dbLog } = leaderThreadCtx;
|
18
|
+
const skipMutationLog = options?.skipMutationLog ?? false;
|
19
|
+
const mutationName = mutationEventEncoded.mutation;
|
19
20
|
const mutationDef = schema.mutations.get(mutationName) ?? shouldNeverHappen(`Unknown mutation: ${mutationName}`);
|
20
|
-
const execArgsArr = getExecArgsFromMutation({
|
21
|
+
const execArgsArr = getExecArgsFromMutation({
|
22
|
+
mutationDef,
|
23
|
+
mutationEvent: { decoded: undefined, encoded: mutationEventEncoded },
|
24
|
+
});
|
25
|
+
// NOTE we might want to bring this back if we want to debug no-op mutations
|
26
|
+
// const makeExecuteOptions = (statementSql: string, bindValues: any) => ({
|
27
|
+
// onRowsChanged: (rowsChanged: number) => {
|
28
|
+
// if (rowsChanged === 0) {
|
29
|
+
// console.warn(`Mutation "${mutationDef.name}" did not affect any rows:`, statementSql, bindValues)
|
30
|
+
// }
|
31
|
+
// },
|
32
|
+
// })
|
21
33
|
// console.group('[@livestore/common:leader-thread:applyMutation]', { mutationName })
|
22
34
|
const session = db.session();
|
23
35
|
for (const { statementSql, bindValues } of execArgsArr) {
|
@@ -27,25 +39,22 @@ export const makeApplyMutation = Effect.gen(function* () {
|
|
27
39
|
}
|
28
40
|
const changeset = session.changeset();
|
29
41
|
session.finish();
|
30
|
-
//
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
},
|
43
|
-
}));
|
44
|
-
}
|
42
|
+
// TODO use prepared statements
|
43
|
+
yield* execSql(db, ...insertRow({
|
44
|
+
tableName: SESSION_CHANGESET_META_TABLE,
|
45
|
+
columns: sessionChangesetMetaTable.sqliteDef.columns,
|
46
|
+
values: {
|
47
|
+
idGlobal: mutationEventEncoded.id.global,
|
48
|
+
idLocal: mutationEventEncoded.id.local,
|
49
|
+
// NOTE the changeset will be empty (i.e. null) for no-op mutations
|
50
|
+
changeset: changeset ?? null,
|
51
|
+
debug: execArgsArr,
|
52
|
+
},
|
53
|
+
}));
|
45
54
|
// console.groupEnd()
|
46
55
|
// write to mutation_log
|
47
|
-
const excludeFromMutationLog = shouldExcludeMutationFromLog(mutationName,
|
48
|
-
if (excludeFromMutationLog === false) {
|
56
|
+
const excludeFromMutationLog = shouldExcludeMutationFromLog(mutationName, mutationEventEncoded);
|
57
|
+
if (skipMutationLog === false && excludeFromMutationLog === false) {
|
49
58
|
yield* insertIntoMutationLog(mutationEventEncoded, dbLog, mutationDefSchemaHashMap);
|
50
59
|
}
|
51
60
|
else {
|
@@ -55,7 +64,7 @@ export const makeApplyMutation = Effect.gen(function* () {
|
|
55
64
|
attributes: {
|
56
65
|
mutationName: mutationEventEncoded.mutation,
|
57
66
|
mutationId: mutationEventEncoded.id,
|
58
|
-
'span.label': mutationEventEncoded.mutation
|
67
|
+
'span.label': `(${mutationEventEncoded.id.global},${mutationEventEncoded.id.local}) ${mutationEventEncoded.mutation}`,
|
59
68
|
},
|
60
69
|
}));
|
61
70
|
});
|
@@ -84,11 +93,14 @@ const makeShouldExcludeMutationFromLog = memoizeByRef((schema) => {
|
|
84
93
|
const mutationLogExclude = migrationOptions.strategy === 'from-mutation-log'
|
85
94
|
? (migrationOptions.excludeMutations ?? new Set(['livestore.RawSql']))
|
86
95
|
: new Set(['livestore.RawSql']);
|
87
|
-
return (mutationName,
|
96
|
+
return (mutationName, mutationEventEncoded) => {
|
88
97
|
if (mutationLogExclude.has(mutationName))
|
89
98
|
return true;
|
90
99
|
const mutationDef = schema.mutations.get(mutationName) ?? shouldNeverHappen(`Unknown mutation: ${mutationName}`);
|
91
|
-
const execArgsArr = getExecArgsFromMutation({
|
100
|
+
const execArgsArr = getExecArgsFromMutation({
|
101
|
+
mutationDef,
|
102
|
+
mutationEvent: { decoded: undefined, encoded: mutationEventEncoded },
|
103
|
+
});
|
92
104
|
return execArgsArr.some((_) => _.statementSql.includes('__livestore'));
|
93
105
|
};
|
94
106
|
});
|