@livestore/common 0.3.0-dev.27 → 0.3.0-dev.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.tsbuildinfo +1 -1
- package/dist/__tests__/fixture.d.ts +83 -221
- package/dist/__tests__/fixture.d.ts.map +1 -1
- package/dist/__tests__/fixture.js +33 -11
- package/dist/__tests__/fixture.js.map +1 -1
- package/dist/adapter-types.d.ts +22 -15
- package/dist/adapter-types.d.ts.map +1 -1
- package/dist/adapter-types.js +15 -2
- package/dist/adapter-types.js.map +1 -1
- package/dist/bounded-collections.d.ts +1 -1
- package/dist/bounded-collections.d.ts.map +1 -1
- package/dist/debug-info.d.ts.map +1 -1
- package/dist/debug-info.js +1 -0
- package/dist/debug-info.js.map +1 -1
- package/dist/devtools/devtools-messages-client-session.d.ts +21 -21
- package/dist/devtools/devtools-messages-common.d.ts +6 -6
- package/dist/devtools/devtools-messages-leader.d.ts +45 -45
- package/dist/devtools/devtools-messages-leader.d.ts.map +1 -1
- package/dist/devtools/devtools-messages-leader.js +11 -11
- package/dist/devtools/devtools-messages-leader.js.map +1 -1
- package/dist/index.d.ts +2 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -5
- package/dist/index.js.map +1 -1
- package/dist/leader-thread/LeaderSyncProcessor.d.ts +25 -12
- package/dist/leader-thread/LeaderSyncProcessor.d.ts.map +1 -1
- package/dist/leader-thread/LeaderSyncProcessor.js +125 -89
- package/dist/leader-thread/LeaderSyncProcessor.js.map +1 -1
- package/dist/leader-thread/{apply-mutation.d.ts → apply-event.d.ts} +7 -7
- package/dist/leader-thread/apply-event.d.ts.map +1 -0
- package/dist/leader-thread/apply-event.js +103 -0
- package/dist/leader-thread/apply-event.js.map +1 -0
- package/dist/leader-thread/eventlog.d.ts +27 -0
- package/dist/leader-thread/eventlog.d.ts.map +1 -0
- package/dist/leader-thread/eventlog.js +123 -0
- package/dist/leader-thread/eventlog.js.map +1 -0
- package/dist/leader-thread/leader-worker-devtools.js +18 -18
- package/dist/leader-thread/leader-worker-devtools.js.map +1 -1
- package/dist/leader-thread/make-leader-thread-layer.d.ts +16 -4
- package/dist/leader-thread/make-leader-thread-layer.d.ts.map +1 -1
- package/dist/leader-thread/make-leader-thread-layer.js +23 -16
- package/dist/leader-thread/make-leader-thread-layer.js.map +1 -1
- package/dist/leader-thread/mod.d.ts +1 -1
- package/dist/leader-thread/mod.d.ts.map +1 -1
- package/dist/leader-thread/mod.js +1 -1
- package/dist/leader-thread/mod.js.map +1 -1
- package/dist/leader-thread/recreate-db.d.ts.map +1 -1
- package/dist/leader-thread/recreate-db.js +6 -8
- package/dist/leader-thread/recreate-db.js.map +1 -1
- package/dist/leader-thread/types.d.ts +11 -11
- package/dist/leader-thread/types.d.ts.map +1 -1
- package/dist/materializer-helper.d.ts +23 -0
- package/dist/materializer-helper.d.ts.map +1 -0
- package/dist/materializer-helper.js +70 -0
- package/dist/materializer-helper.js.map +1 -0
- package/dist/query-builder/api.d.ts +58 -53
- package/dist/query-builder/api.d.ts.map +1 -1
- package/dist/query-builder/api.js +3 -5
- package/dist/query-builder/api.js.map +1 -1
- package/dist/query-builder/astToSql.d.ts.map +1 -1
- package/dist/query-builder/astToSql.js +59 -37
- package/dist/query-builder/astToSql.js.map +1 -1
- package/dist/query-builder/impl.d.ts +2 -3
- package/dist/query-builder/impl.d.ts.map +1 -1
- package/dist/query-builder/impl.js +48 -46
- package/dist/query-builder/impl.js.map +1 -1
- package/dist/query-builder/impl.test.d.ts +86 -1
- package/dist/query-builder/impl.test.d.ts.map +1 -1
- package/dist/query-builder/impl.test.js +244 -36
- package/dist/query-builder/impl.test.js.map +1 -1
- package/dist/rehydrate-from-eventlog.d.ts +14 -0
- package/dist/rehydrate-from-eventlog.d.ts.map +1 -0
- package/dist/{rehydrate-from-mutationlog.js → rehydrate-from-eventlog.js} +25 -26
- package/dist/rehydrate-from-eventlog.js.map +1 -0
- package/dist/schema/EventDef.d.ts +136 -0
- package/dist/schema/EventDef.d.ts.map +1 -0
- package/dist/schema/EventDef.js +58 -0
- package/dist/schema/EventDef.js.map +1 -0
- package/dist/schema/EventId.d.ts +2 -2
- package/dist/schema/EventId.d.ts.map +1 -1
- package/dist/schema/EventId.js +8 -2
- package/dist/schema/EventId.js.map +1 -1
- package/dist/schema/{MutationEvent.d.ts → LiveStoreEvent.d.ts} +56 -56
- package/dist/schema/LiveStoreEvent.d.ts.map +1 -0
- package/dist/schema/{MutationEvent.js → LiveStoreEvent.js} +25 -25
- package/dist/schema/LiveStoreEvent.js.map +1 -0
- package/dist/schema/client-document-def.d.ts +223 -0
- package/dist/schema/client-document-def.d.ts.map +1 -0
- package/dist/schema/client-document-def.js +170 -0
- package/dist/schema/client-document-def.js.map +1 -0
- package/dist/schema/client-document-def.test.d.ts +2 -0
- package/dist/schema/client-document-def.test.d.ts.map +1 -0
- package/dist/schema/client-document-def.test.js +201 -0
- package/dist/schema/client-document-def.test.js.map +1 -0
- package/dist/schema/db-schema/dsl/mod.d.ts.map +1 -1
- package/dist/schema/events.d.ts +2 -0
- package/dist/schema/events.d.ts.map +1 -0
- package/dist/schema/events.js +2 -0
- package/dist/schema/events.js.map +1 -0
- package/dist/schema/mod.d.ts +4 -3
- package/dist/schema/mod.d.ts.map +1 -1
- package/dist/schema/mod.js +4 -3
- package/dist/schema/mod.js.map +1 -1
- package/dist/schema/schema.d.ts +27 -23
- package/dist/schema/schema.d.ts.map +1 -1
- package/dist/schema/schema.js +45 -43
- package/dist/schema/schema.js.map +1 -1
- package/dist/schema/sqlite-state.d.ts +12 -0
- package/dist/schema/sqlite-state.d.ts.map +1 -0
- package/dist/schema/sqlite-state.js +36 -0
- package/dist/schema/sqlite-state.js.map +1 -0
- package/dist/schema/system-tables.d.ts +67 -98
- package/dist/schema/system-tables.d.ts.map +1 -1
- package/dist/schema/system-tables.js +62 -48
- package/dist/schema/system-tables.js.map +1 -1
- package/dist/schema/table-def.d.ts +26 -96
- package/dist/schema/table-def.d.ts.map +1 -1
- package/dist/schema/table-def.js +16 -64
- package/dist/schema/table-def.js.map +1 -1
- package/dist/schema/view.d.ts +3 -0
- package/dist/schema/view.d.ts.map +1 -0
- package/dist/schema/view.js +3 -0
- package/dist/schema/view.js.map +1 -0
- package/dist/schema-management/common.d.ts +4 -4
- package/dist/schema-management/common.d.ts.map +1 -1
- package/dist/schema-management/migrations.d.ts.map +1 -1
- package/dist/schema-management/migrations.js +6 -6
- package/dist/schema-management/migrations.js.map +1 -1
- package/dist/schema-management/validate-mutation-defs.d.ts +3 -3
- package/dist/schema-management/validate-mutation-defs.d.ts.map +1 -1
- package/dist/schema-management/validate-mutation-defs.js +17 -17
- package/dist/schema-management/validate-mutation-defs.js.map +1 -1
- package/dist/sync/ClientSessionSyncProcessor.d.ts +7 -7
- package/dist/sync/ClientSessionSyncProcessor.d.ts.map +1 -1
- package/dist/sync/ClientSessionSyncProcessor.js +31 -30
- package/dist/sync/ClientSessionSyncProcessor.js.map +1 -1
- package/dist/sync/next/facts.d.ts +19 -19
- package/dist/sync/next/facts.d.ts.map +1 -1
- package/dist/sync/next/facts.js +2 -2
- package/dist/sync/next/facts.js.map +1 -1
- package/dist/sync/next/history-dag-common.d.ts +3 -3
- 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/history-dag.js +1 -1
- package/dist/sync/next/history-dag.js.map +1 -1
- package/dist/sync/next/rebase-events.d.ts +7 -7
- package/dist/sync/next/rebase-events.d.ts.map +1 -1
- package/dist/sync/next/rebase-events.js +5 -5
- package/dist/sync/next/rebase-events.js.map +1 -1
- package/dist/sync/next/test/compact-events.calculator.test.js +38 -33
- package/dist/sync/next/test/compact-events.calculator.test.js.map +1 -1
- package/dist/sync/next/test/compact-events.test.js +71 -71
- package/dist/sync/next/test/compact-events.test.js.map +1 -1
- package/dist/sync/next/test/{mutation-fixtures.d.ts → event-fixtures.d.ts} +29 -29
- package/dist/sync/next/test/event-fixtures.d.ts.map +1 -0
- package/dist/sync/next/test/{mutation-fixtures.js → event-fixtures.js} +60 -25
- package/dist/sync/next/test/event-fixtures.js.map +1 -0
- package/dist/sync/next/test/mod.d.ts +1 -1
- package/dist/sync/next/test/mod.d.ts.map +1 -1
- package/dist/sync/next/test/mod.js +1 -1
- package/dist/sync/next/test/mod.js.map +1 -1
- package/dist/sync/sync.d.ts +3 -3
- package/dist/sync/sync.d.ts.map +1 -1
- package/dist/sync/syncstate.d.ts +32 -32
- package/dist/sync/syncstate.d.ts.map +1 -1
- package/dist/sync/syncstate.js +31 -25
- package/dist/sync/syncstate.js.map +1 -1
- package/dist/sync/syncstate.test.js +165 -175
- 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.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +3 -3
- package/src/__tests__/fixture.ts +36 -15
- package/src/adapter-types.ts +23 -16
- package/src/debug-info.ts +1 -0
- package/src/devtools/devtools-messages-leader.ts +13 -13
- package/src/index.ts +2 -5
- package/src/leader-thread/LeaderSyncProcessor.ts +183 -122
- package/src/leader-thread/{apply-mutation.ts → apply-event.ts} +50 -74
- package/src/leader-thread/eventlog.ts +199 -0
- package/src/leader-thread/leader-worker-devtools.ts +18 -18
- package/src/leader-thread/make-leader-thread-layer.ts +51 -29
- package/src/leader-thread/mod.ts +1 -1
- package/src/leader-thread/recreate-db.ts +6 -9
- package/src/leader-thread/types.ts +12 -12
- package/src/materializer-helper.ts +110 -0
- package/src/query-builder/api.ts +79 -105
- package/src/query-builder/astToSql.ts +68 -39
- package/src/query-builder/impl.test.ts +264 -42
- package/src/query-builder/impl.ts +72 -56
- package/src/{rehydrate-from-mutationlog.ts → rehydrate-from-eventlog.ts} +33 -40
- package/src/schema/EventDef.ts +216 -0
- package/src/schema/EventId.ts +11 -3
- package/src/schema/{MutationEvent.ts → LiveStoreEvent.ts} +68 -69
- package/src/schema/client-document-def.test.ts +239 -0
- package/src/schema/client-document-def.ts +444 -0
- package/src/schema/db-schema/dsl/mod.ts +0 -1
- package/src/schema/events.ts +1 -0
- package/src/schema/mod.ts +4 -3
- package/src/schema/schema.ts +79 -69
- package/src/schema/sqlite-state.ts +62 -0
- package/src/schema/system-tables.ts +42 -53
- package/src/schema/table-def.ts +53 -209
- package/src/schema/view.ts +2 -0
- package/src/schema-management/common.ts +4 -4
- package/src/schema-management/migrations.ts +8 -9
- package/src/schema-management/validate-mutation-defs.ts +22 -24
- package/src/sync/ClientSessionSyncProcessor.ts +37 -36
- package/src/sync/next/facts.ts +31 -32
- package/src/sync/next/history-dag-common.ts +4 -4
- package/src/sync/next/history-dag.ts +1 -1
- package/src/sync/next/rebase-events.ts +13 -13
- package/src/sync/next/test/compact-events.calculator.test.ts +45 -45
- package/src/sync/next/test/compact-events.test.ts +73 -73
- package/src/sync/next/test/event-fixtures.ts +219 -0
- package/src/sync/next/test/mod.ts +1 -1
- package/src/sync/sync.ts +3 -3
- package/src/sync/syncstate.test.ts +168 -179
- package/src/sync/syncstate.ts +48 -38
- package/src/sync/validate-push-payload.ts +2 -2
- package/src/version.ts +1 -1
- package/tmp/pack.tgz +0 -0
- package/tsconfig.json +1 -0
- package/dist/derived-mutations.d.ts +0 -109
- package/dist/derived-mutations.d.ts.map +0 -1
- package/dist/derived-mutations.js +0 -54
- package/dist/derived-mutations.js.map +0 -1
- package/dist/derived-mutations.test.d.ts +0 -2
- package/dist/derived-mutations.test.d.ts.map +0 -1
- package/dist/derived-mutations.test.js +0 -93
- package/dist/derived-mutations.test.js.map +0 -1
- package/dist/init-singleton-tables.d.ts +0 -4
- package/dist/init-singleton-tables.d.ts.map +0 -1
- package/dist/init-singleton-tables.js +0 -16
- package/dist/init-singleton-tables.js.map +0 -1
- package/dist/leader-thread/apply-mutation.d.ts.map +0 -1
- package/dist/leader-thread/apply-mutation.js +0 -122
- package/dist/leader-thread/apply-mutation.js.map +0 -1
- package/dist/leader-thread/mutationlog.d.ts +0 -27
- package/dist/leader-thread/mutationlog.d.ts.map +0 -1
- package/dist/leader-thread/mutationlog.js +0 -124
- package/dist/leader-thread/mutationlog.js.map +0 -1
- package/dist/leader-thread/pull-queue-set.d.ts +0 -7
- package/dist/leader-thread/pull-queue-set.d.ts.map +0 -1
- package/dist/leader-thread/pull-queue-set.js +0 -38
- package/dist/leader-thread/pull-queue-set.js.map +0 -1
- package/dist/mutation.d.ts +0 -20
- package/dist/mutation.d.ts.map +0 -1
- package/dist/mutation.js +0 -68
- package/dist/mutation.js.map +0 -1
- package/dist/query-info.d.ts +0 -41
- package/dist/query-info.d.ts.map +0 -1
- package/dist/query-info.js +0 -7
- package/dist/query-info.js.map +0 -1
- package/dist/rehydrate-from-mutationlog.d.ts +0 -15
- package/dist/rehydrate-from-mutationlog.d.ts.map +0 -1
- package/dist/rehydrate-from-mutationlog.js.map +0 -1
- package/dist/schema/MutationEvent.d.ts.map +0 -1
- package/dist/schema/MutationEvent.js.map +0 -1
- package/dist/schema/mutations.d.ts +0 -115
- package/dist/schema/mutations.d.ts.map +0 -1
- package/dist/schema/mutations.js +0 -42
- package/dist/schema/mutations.js.map +0 -1
- package/dist/sync/next/test/mutation-fixtures.d.ts.map +0 -1
- package/dist/sync/next/test/mutation-fixtures.js.map +0 -1
- package/src/derived-mutations.test.ts +0 -101
- package/src/derived-mutations.ts +0 -170
- package/src/init-singleton-tables.ts +0 -24
- package/src/leader-thread/mutationlog.ts +0 -202
- package/src/mutation.ts +0 -108
- package/src/query-info.ts +0 -83
- package/src/schema/mutations.ts +0 -193
- package/src/sync/next/test/mutation-fixtures.ts +0 -228
@@ -1,3 +1,4 @@
|
|
1
|
+
/// <reference lib="dom" />
|
1
2
|
import { LS_DEV, shouldNeverHappen, TRACE_VERBOSE } from '@livestore/utils'
|
2
3
|
import type { Runtime, Scope } from '@livestore/utils/effect'
|
3
4
|
import { BucketQueue, Effect, FiberHandle, Queue, Schema, Stream, Subscribable } from '@livestore/utils/effect'
|
@@ -5,17 +6,17 @@ import * as otel from '@opentelemetry/api'
|
|
5
6
|
|
6
7
|
import type { ClientSession, UnexpectedError } from '../adapter-types.js'
|
7
8
|
import * as EventId from '../schema/EventId.js'
|
8
|
-
import
|
9
|
-
import
|
9
|
+
import * as LiveStoreEvent from '../schema/LiveStoreEvent.js'
|
10
|
+
import { getEventDef, LEADER_MERGE_COUNTER_TABLE, type LiveStoreSchema } from '../schema/mod.js'
|
10
11
|
import { sql } from '../util.js'
|
11
12
|
import * as SyncState from './syncstate.js'
|
12
13
|
|
13
14
|
/**
|
14
15
|
* Rebase behaviour:
|
15
|
-
* - We continously pull
|
16
|
+
* - We continously pull events from the leader and apply them to the local store.
|
16
17
|
* - If there was a race condition (i.e. the leader and client session have both advacned),
|
17
|
-
* we'll need to rebase the local pending
|
18
|
-
* - The goal is to never block the UI, so we'll interrupt rebasing if a new
|
18
|
+
* we'll need to rebase the local pending events on top of the leader's head.
|
19
|
+
* - The goal is to never block the UI, so we'll interrupt rebasing if a new events is pushed by the client session.
|
19
20
|
* - We also want to avoid "backwards-jumping" in the UI, so we'll transactionally apply a read model changes during a rebase.
|
20
21
|
* - We might need to make the rebase behaviour configurable e.g. to let users manually trigger a rebase
|
21
22
|
*
|
@@ -25,7 +26,7 @@ export const makeClientSessionSyncProcessor = ({
|
|
25
26
|
schema,
|
26
27
|
clientSession,
|
27
28
|
runtime,
|
28
|
-
|
29
|
+
applyEvent,
|
29
30
|
rollback,
|
30
31
|
refreshTables,
|
31
32
|
span,
|
@@ -35,8 +36,8 @@ export const makeClientSessionSyncProcessor = ({
|
|
35
36
|
schema: LiveStoreSchema
|
36
37
|
clientSession: ClientSession
|
37
38
|
runtime: Runtime.Runtime<Scope.Scope>
|
38
|
-
|
39
|
-
|
39
|
+
applyEvent: (
|
40
|
+
eventDecoded: LiveStoreEvent.PartialAnyDecoded,
|
40
41
|
options: { otelContext: otel.Context; withChangeset: boolean },
|
41
42
|
) => {
|
42
43
|
writeTables: Set<string>
|
@@ -54,36 +55,36 @@ export const makeClientSessionSyncProcessor = ({
|
|
54
55
|
*/
|
55
56
|
confirmUnsavedChanges: boolean
|
56
57
|
}): ClientSessionSyncProcessor => {
|
57
|
-
const
|
58
|
+
const eventSchema = LiveStoreEvent.makeEventDefSchemaMemo(schema)
|
58
59
|
|
59
60
|
const syncStateRef = {
|
60
61
|
// The initial state is identical to the leader's initial state
|
61
62
|
current: new SyncState.SyncState({
|
62
63
|
localHead: clientSession.leaderThread.initialState.leaderHead,
|
63
64
|
upstreamHead: clientSession.leaderThread.initialState.leaderHead,
|
64
|
-
// Given we're starting with the leader's snapshot, we don't have any pending
|
65
|
+
// Given we're starting with the leader's snapshot, we don't have any pending events intially
|
65
66
|
pending: [],
|
66
67
|
}),
|
67
68
|
}
|
68
69
|
|
69
70
|
const syncStateUpdateQueue = Queue.unbounded<SyncState.SyncState>().pipe(Effect.runSync)
|
70
|
-
const isClientEvent = (
|
71
|
-
|
71
|
+
const isClientEvent = (eventEncoded: LiveStoreEvent.EncodedWithMeta) =>
|
72
|
+
getEventDef(schema, eventEncoded.name).eventDef.options.clientOnly
|
72
73
|
|
73
74
|
/** We're queuing push requests to reduce the number of messages sent to the leader by batching them */
|
74
|
-
const leaderPushQueue = BucketQueue.make<
|
75
|
+
const leaderPushQueue = BucketQueue.make<LiveStoreEvent.EncodedWithMeta>().pipe(Effect.runSync)
|
75
76
|
|
76
77
|
const push: ClientSessionSyncProcessor['push'] = (batch, { otelContext }) => {
|
77
78
|
// TODO validate batch
|
78
79
|
|
79
80
|
let baseEventId = syncStateRef.current.localHead
|
80
|
-
const
|
81
|
-
const
|
82
|
-
const nextIdPair = EventId.nextPair(baseEventId,
|
81
|
+
const encodedEventDefs = batch.map(({ name, args }) => {
|
82
|
+
const eventDef = getEventDef(schema, name)
|
83
|
+
const nextIdPair = EventId.nextPair(baseEventId, eventDef.eventDef.options.clientOnly)
|
83
84
|
baseEventId = nextIdPair.id
|
84
|
-
return new
|
85
|
-
Schema.encodeUnknownSync(
|
86
|
-
|
85
|
+
return new LiveStoreEvent.EncodedWithMeta(
|
86
|
+
Schema.encodeUnknownSync(eventSchema)({
|
87
|
+
name,
|
87
88
|
args,
|
88
89
|
...nextIdPair,
|
89
90
|
clientId: clientSession.clientId,
|
@@ -94,9 +95,9 @@ export const makeClientSessionSyncProcessor = ({
|
|
94
95
|
|
95
96
|
const mergeResult = SyncState.merge({
|
96
97
|
syncState: syncStateRef.current,
|
97
|
-
payload: { _tag: 'local-push', newEvents:
|
98
|
+
payload: { _tag: 'local-push', newEvents: encodedEventDefs },
|
98
99
|
isClientEvent,
|
99
|
-
isEqualEvent:
|
100
|
+
isEqualEvent: LiveStoreEvent.isEqualEncoded,
|
100
101
|
})
|
101
102
|
|
102
103
|
if (mergeResult._tag === 'unexpected-error') {
|
@@ -104,7 +105,7 @@ export const makeClientSessionSyncProcessor = ({
|
|
104
105
|
}
|
105
106
|
|
106
107
|
span.addEvent('local-push', {
|
107
|
-
batchSize:
|
108
|
+
batchSize: encodedEventDefs.length,
|
108
109
|
mergeResult: TRACE_VERBOSE ? JSON.stringify(mergeResult) : undefined,
|
109
110
|
})
|
110
111
|
|
@@ -116,18 +117,18 @@ export const makeClientSessionSyncProcessor = ({
|
|
116
117
|
syncStateUpdateQueue.offer(mergeResult.newSyncState).pipe(Effect.runSync)
|
117
118
|
|
118
119
|
const writeTables = new Set<string>()
|
119
|
-
for (const
|
120
|
+
for (const event of mergeResult.newEvents) {
|
120
121
|
// TODO avoid encoding and decoding here again
|
121
|
-
const
|
122
|
-
const res =
|
122
|
+
const decodedEventDef = Schema.decodeSync(eventSchema)(event)
|
123
|
+
const res = applyEvent(decodedEventDef, { otelContext, withChangeset: true })
|
123
124
|
for (const table of res.writeTables) {
|
124
125
|
writeTables.add(table)
|
125
126
|
}
|
126
|
-
|
127
|
+
event.meta.sessionChangeset = res.sessionChangeset
|
127
128
|
}
|
128
129
|
|
129
|
-
// console.debug('pushToLeader',
|
130
|
-
BucketQueue.offerAll(leaderPushQueue,
|
130
|
+
// console.debug('pushToLeader', encodedEventDefs.length, ...encodedEventDefs.map((_) => _.toJSON()))
|
131
|
+
BucketQueue.offerAll(leaderPushQueue, encodedEventDefs).pipe(Effect.runSync)
|
131
132
|
|
132
133
|
return { writeTables }
|
133
134
|
}
|
@@ -160,7 +161,7 @@ export const makeClientSessionSyncProcessor = ({
|
|
160
161
|
|
161
162
|
const backgroundLeaderPushing = Effect.gen(function* () {
|
162
163
|
const batch = yield* BucketQueue.takeBetween(leaderPushQueue, 1, params.leaderPushBatchSize)
|
163
|
-
yield* clientSession.leaderThread.
|
164
|
+
yield* clientSession.leaderThread.events.push(batch).pipe(
|
164
165
|
Effect.catchTag('LeaderAheadError', () => {
|
165
166
|
debugInfo.rejectCount++
|
166
167
|
return BucketQueue.clear(leaderPushQueue)
|
@@ -177,7 +178,7 @@ export const makeClientSessionSyncProcessor = ({
|
|
177
178
|
|
178
179
|
// NOTE We need to lazily call `.pull` as we want the cursor to be updated
|
179
180
|
yield* Stream.suspend(() =>
|
180
|
-
clientSession.leaderThread.
|
181
|
+
clientSession.leaderThread.events.pull({
|
181
182
|
cursor: { mergeCounter: getMergeCounter(), eventId: syncStateRef.current.localHead },
|
182
183
|
}),
|
183
184
|
).pipe(
|
@@ -193,7 +194,7 @@ export const makeClientSessionSyncProcessor = ({
|
|
193
194
|
syncState: syncStateRef.current,
|
194
195
|
payload,
|
195
196
|
isClientEvent,
|
196
|
-
isEqualEvent:
|
197
|
+
isEqualEvent: LiveStoreEvent.isEqualEncoded,
|
197
198
|
})
|
198
199
|
|
199
200
|
if (mergeResult._tag === 'unexpected-error') {
|
@@ -257,15 +258,15 @@ export const makeClientSessionSyncProcessor = ({
|
|
257
258
|
if (mergeResult.newEvents.length === 0) return
|
258
259
|
|
259
260
|
const writeTables = new Set<string>()
|
260
|
-
for (const
|
261
|
+
for (const event of mergeResult.newEvents) {
|
261
262
|
// TODO apply changeset if available (will require tracking of write tables as well)
|
262
|
-
const
|
263
|
-
const res =
|
263
|
+
const decodedEventDef = Schema.decodeSync(eventSchema)(event)
|
264
|
+
const res = applyEvent(decodedEventDef, { otelContext, withChangeset: true })
|
264
265
|
for (const table of res.writeTables) {
|
265
266
|
writeTables.add(table)
|
266
267
|
}
|
267
268
|
|
268
|
-
|
269
|
+
event.meta.sessionChangeset = res.sessionChangeset
|
269
270
|
}
|
270
271
|
|
271
272
|
refreshTables(writeTables)
|
@@ -314,7 +315,7 @@ export const makeClientSessionSyncProcessor = ({
|
|
314
315
|
|
315
316
|
export interface ClientSessionSyncProcessor {
|
316
317
|
push: (
|
317
|
-
batch: ReadonlyArray<
|
318
|
+
batch: ReadonlyArray<LiveStoreEvent.PartialAnyDecoded>,
|
318
319
|
options: { otelContext: otel.Context },
|
319
320
|
) => {
|
320
321
|
writeTables: Set<string>
|
package/src/sync/next/facts.ts
CHANGED
@@ -1,20 +1,20 @@
|
|
1
1
|
import { notYetImplemented } from '@livestore/utils'
|
2
2
|
|
3
|
-
import type * as EventId from '../../schema/EventId.js'
|
4
3
|
import type {
|
4
|
+
EventDefFactInput,
|
5
|
+
EventDefFacts,
|
6
|
+
EventDefFactsGroup,
|
7
|
+
EventDefFactsSnapshot,
|
5
8
|
FactsCallback,
|
6
|
-
|
7
|
-
|
8
|
-
MutationEventFactsGroup,
|
9
|
-
MutationEventFactsSnapshot,
|
10
|
-
} from '../../schema/mutations.js'
|
9
|
+
} from '../../schema/EventDef.js'
|
10
|
+
import type * as EventId from '../../schema/EventId.js'
|
11
11
|
import { graphologyDag } from './graphology_.js'
|
12
12
|
import { EMPTY_FACT_VALUE, type HistoryDag, type HistoryDagNode } from './history-dag-common.js'
|
13
13
|
|
14
14
|
export const factsSnapshotForEvents = (
|
15
15
|
events: HistoryDagNode[],
|
16
16
|
endEventId: EventId.EventId,
|
17
|
-
):
|
17
|
+
): EventDefFactsSnapshot => {
|
18
18
|
const facts = new Map<string, any>()
|
19
19
|
|
20
20
|
for (const event of events) {
|
@@ -31,7 +31,7 @@ export const factsSnapshotForEvents = (
|
|
31
31
|
export const factsSnapshotForDag = (
|
32
32
|
dag: HistoryDag,
|
33
33
|
endEventId: EventId.EventId | undefined,
|
34
|
-
):
|
34
|
+
): EventDefFactsSnapshot => {
|
35
35
|
const facts = new Map<string, any>()
|
36
36
|
|
37
37
|
const orderedEventIdStrs = graphologyDag.topologicalSort(dag)
|
@@ -56,20 +56,20 @@ export type FactValidationResult =
|
|
56
56
|
success: false
|
57
57
|
/** Index of the item that caused the validation to fail */
|
58
58
|
index: number
|
59
|
-
requiredFacts:
|
59
|
+
requiredFacts: EventDefFacts
|
60
60
|
mismatch: {
|
61
|
-
existing:
|
62
|
-
required:
|
61
|
+
existing: EventDefFacts
|
62
|
+
required: EventDefFacts
|
63
63
|
}
|
64
|
-
currentSnapshot:
|
64
|
+
currentSnapshot: EventDefFacts
|
65
65
|
}
|
66
66
|
|
67
67
|
export const validateFacts = ({
|
68
68
|
factGroups,
|
69
69
|
initialSnapshot,
|
70
70
|
}: {
|
71
|
-
factGroups:
|
72
|
-
initialSnapshot:
|
71
|
+
factGroups: EventDefFactsGroup[]
|
72
|
+
initialSnapshot: EventDefFactsSnapshot
|
73
73
|
}): FactValidationResult => {
|
74
74
|
const currentSnapshot = new Map(initialSnapshot)
|
75
75
|
|
@@ -102,13 +102,13 @@ export const validateFacts = ({
|
|
102
102
|
}
|
103
103
|
}
|
104
104
|
|
105
|
-
export const applyFactGroups = (factGroups:
|
105
|
+
export const applyFactGroups = (factGroups: EventDefFactsGroup[], snapshot: EventDefFactsSnapshot) => {
|
106
106
|
for (const factGroup of factGroups) {
|
107
107
|
applyFactGroup(factGroup, snapshot)
|
108
108
|
}
|
109
109
|
}
|
110
110
|
|
111
|
-
export const applyFactGroup = (factGroup:
|
111
|
+
export const applyFactGroup = (factGroup: EventDefFactsGroup, snapshot: EventDefFactsSnapshot) => {
|
112
112
|
for (const [key, value] of factGroup.modifySet) {
|
113
113
|
snapshot.set(key, value)
|
114
114
|
}
|
@@ -119,7 +119,7 @@ export const applyFactGroup = (factGroup: MutationEventFactsGroup, snapshot: Mut
|
|
119
119
|
}
|
120
120
|
|
121
121
|
/** Check if setA is a subset of setB */
|
122
|
-
const isSubSetMapByValue = (setA:
|
122
|
+
const isSubSetMapByValue = (setA: EventDefFacts, setB: EventDefFacts) => {
|
123
123
|
for (const [key, value] of setA) {
|
124
124
|
if (setB.get(key) !== value) {
|
125
125
|
return false
|
@@ -129,7 +129,7 @@ const isSubSetMapByValue = (setA: MutationEventFacts, setB: MutationEventFacts)
|
|
129
129
|
}
|
130
130
|
|
131
131
|
/** Check if setA is a subset of setB */
|
132
|
-
const isSubSetMapByKey = (setA:
|
132
|
+
const isSubSetMapByKey = (setA: EventDefFacts, setB: EventDefFacts) => {
|
133
133
|
for (const [key, _value] of setA) {
|
134
134
|
if (!setB.has(key)) {
|
135
135
|
return false
|
@@ -139,17 +139,16 @@ const isSubSetMapByKey = (setA: MutationEventFacts, setB: MutationEventFacts) =>
|
|
139
139
|
}
|
140
140
|
|
141
141
|
/** Check if groupA depends on groupB */
|
142
|
-
export const dependsOn = (groupA:
|
142
|
+
export const dependsOn = (groupA: EventDefFactsGroup, groupB: EventDefFactsGroup): boolean =>
|
143
143
|
factsIntersect(groupA.depRead, groupB.modifySet) ||
|
144
144
|
factsIntersect(groupA.depRead, groupB.modifyUnset) ||
|
145
145
|
factsIntersect(groupA.depRequire, groupB.modifySet) ||
|
146
146
|
factsIntersect(groupA.depRequire, groupB.modifyUnset)
|
147
147
|
|
148
|
-
export const replacesFacts = (groupA:
|
149
|
-
const replaces = (a:
|
148
|
+
export const replacesFacts = (groupA: EventDefFactsGroup, groupB: EventDefFactsGroup): boolean => {
|
149
|
+
const replaces = (a: EventDefFacts, b: EventDefFacts) => a.size > 0 && b.size > 0 && isSameMapByKey(a, b)
|
150
150
|
|
151
|
-
const noFactsOrSame = (a:
|
152
|
-
a.size === 0 || b.size === 0 || isSameMapByKey(a, b)
|
151
|
+
const noFactsOrSame = (a: EventDefFacts, b: EventDefFacts) => a.size === 0 || b.size === 0 || isSameMapByKey(a, b)
|
153
152
|
|
154
153
|
return (
|
155
154
|
(replaces(groupA.modifySet, groupB.modifySet) && noFactsOrSame(groupA.modifyUnset, groupB.modifyUnset)) ||
|
@@ -159,16 +158,16 @@ export const replacesFacts = (groupA: MutationEventFactsGroup, groupB: MutationE
|
|
159
158
|
)
|
160
159
|
}
|
161
160
|
|
162
|
-
export const isSameMapByKey = (set:
|
161
|
+
export const isSameMapByKey = (set: EventDefFacts, otherSet: EventDefFacts) =>
|
163
162
|
set.size === otherSet.size && isSubSetMapByKey(set, otherSet)
|
164
163
|
|
165
|
-
export const factsToString = (facts:
|
164
|
+
export const factsToString = (facts: EventDefFacts) => {
|
166
165
|
return Array.from(facts)
|
167
166
|
.map(([key, value]) => (value === EMPTY_FACT_VALUE ? key : `${key}=${value}`))
|
168
167
|
.join(', ')
|
169
168
|
}
|
170
169
|
|
171
|
-
export const factsIntersect = (setA:
|
170
|
+
export const factsIntersect = (setA: EventDefFacts, setB: EventDefFacts): boolean => {
|
172
171
|
for (const [key, _value] of setA) {
|
173
172
|
if (setB.has(key)) {
|
174
173
|
return true
|
@@ -177,16 +176,16 @@ export const factsIntersect = (setA: MutationEventFacts, setB: MutationEventFact
|
|
177
176
|
return false
|
178
177
|
}
|
179
178
|
|
180
|
-
export const
|
179
|
+
export const getFactsGroupForEventArgs = ({
|
181
180
|
factsCallback,
|
182
181
|
args,
|
183
182
|
currentFacts,
|
184
183
|
}: {
|
185
184
|
factsCallback: FactsCallback<any> | undefined
|
186
185
|
args: any
|
187
|
-
currentFacts:
|
188
|
-
}):
|
189
|
-
const depRead:
|
186
|
+
currentFacts: EventDefFactsSnapshot
|
187
|
+
}): EventDefFactsGroup => {
|
188
|
+
const depRead: EventDefFactsSnapshot = new Map<string, any>()
|
190
189
|
const factsSnapshotProxy = new Proxy(currentFacts, {
|
191
190
|
get: (target, prop) => {
|
192
191
|
if (prop === 'has') {
|
@@ -201,12 +200,12 @@ export const getFactsGroupForMutationArgs = ({
|
|
201
200
|
}
|
202
201
|
}
|
203
202
|
|
204
|
-
notYetImplemented(`
|
203
|
+
notYetImplemented(`getFactsGroupForEventArgs: ${prop.toString()} is not yet implemented`)
|
205
204
|
},
|
206
205
|
})
|
207
206
|
|
208
207
|
const factsRes = factsCallback?.(args, factsSnapshotProxy)
|
209
|
-
const iterableToMap = (iterable: Iterable<
|
208
|
+
const iterableToMap = (iterable: Iterable<EventDefFactInput>) => {
|
210
209
|
const map = new Map()
|
211
210
|
for (const item of iterable) {
|
212
211
|
if (typeof item === 'string') {
|
@@ -1,5 +1,5 @@
|
|
1
|
+
import type { EventDefFactsGroup } from '../../schema/EventDef.js'
|
1
2
|
import * as EventId from '../../schema/EventId.js'
|
2
|
-
import type { MutationEventFactsGroup } from '../../schema/mutations.js'
|
3
3
|
import { graphology } from './graphology_.js'
|
4
4
|
|
5
5
|
export const connectionTypeOptions = ['parent', 'facts'] as const
|
@@ -25,10 +25,10 @@ export const rootParentId = EventId.make({ global: EventId.ROOT.global - 1, clie
|
|
25
25
|
export type HistoryDagNode = {
|
26
26
|
id: EventId.EventId
|
27
27
|
parentId: EventId.EventId
|
28
|
-
|
28
|
+
name: string
|
29
29
|
args: any
|
30
30
|
/** Facts are being used for conflict detection and history compaction */
|
31
|
-
factsGroup:
|
31
|
+
factsGroup: EventDefFactsGroup
|
32
32
|
meta?: any
|
33
33
|
clientId: string
|
34
34
|
sessionId: string | undefined
|
@@ -38,7 +38,7 @@ export const rootEventNode: HistoryDagNode = {
|
|
38
38
|
id: EventId.ROOT,
|
39
39
|
parentId: rootParentId,
|
40
40
|
// unused below
|
41
|
-
|
41
|
+
name: '__Root__',
|
42
42
|
args: {},
|
43
43
|
factsGroup: { modifySet: new Map(), modifyUnset: new Map(), depRequire: new Map(), depRead: new Map() },
|
44
44
|
clientId: 'root',
|
@@ -14,7 +14,7 @@ export const historyDagFromNodes = (dagNodes: HistoryDagNode[], options?: { skip
|
|
14
14
|
|
15
15
|
if (validationResult.success === false) {
|
16
16
|
throw new Error(
|
17
|
-
`
|
17
|
+
`Event ${dagNodes[validationResult.index]!.name} requires facts that have not been set yet.\nRequires: ${factsToString(validationResult.requiredFacts)}\nFacts Snapshot: ${factsToString(validationResult.currentSnapshot)}`,
|
18
18
|
)
|
19
19
|
}
|
20
20
|
}
|
@@ -1,11 +1,11 @@
|
|
1
|
+
import type { EventDef, EventDefFactsSnapshot } from '../../schema/EventDef.js'
|
1
2
|
import * as EventId from '../../schema/EventId.js'
|
2
|
-
import type * as
|
3
|
-
import type { MutationDef, MutationEventFactsSnapshot } from '../../schema/mutations.js'
|
3
|
+
import type * as LiveStoreEvent from '../../schema/LiveStoreEvent.js'
|
4
4
|
import {
|
5
5
|
applyFactGroups,
|
6
6
|
factsIntersect,
|
7
7
|
type FactValidationResult,
|
8
|
-
|
8
|
+
getFactsGroupForEventArgs,
|
9
9
|
validateFacts,
|
10
10
|
} from './facts.js'
|
11
11
|
import type { HistoryDagNode } from './history-dag-common.js'
|
@@ -19,13 +19,13 @@ export type RebaseInput = {
|
|
19
19
|
newRemoteEvents: RebaseEventWithConflict[]
|
20
20
|
pendingLocalEvents: RebaseEventWithConflict[]
|
21
21
|
validate: (args: {
|
22
|
-
rebasedLocalEvents:
|
23
|
-
|
22
|
+
rebasedLocalEvents: LiveStoreEvent.PartialAnyDecoded[]
|
23
|
+
eventDefs: Record<string, EventDef.Any>
|
24
24
|
}) => FactValidationResult
|
25
25
|
}
|
26
26
|
|
27
27
|
export type RebaseOutput = {
|
28
|
-
rebasedLocalEvents:
|
28
|
+
rebasedLocalEvents: LiveStoreEvent.PartialAnyDecoded[]
|
29
29
|
}
|
30
30
|
|
31
31
|
export type RebaseFn = (input: RebaseInput) => RebaseOutput
|
@@ -49,10 +49,10 @@ export const rebaseEvents = ({
|
|
49
49
|
pendingLocalEvents: HistoryDagNode[]
|
50
50
|
newRemoteEvents: HistoryDagNode[]
|
51
51
|
rebaseFn: RebaseFn
|
52
|
-
currentFactsSnapshot:
|
52
|
+
currentFactsSnapshot: EventDefFactsSnapshot
|
53
53
|
clientId: string
|
54
54
|
sessionId: string
|
55
|
-
}): ReadonlyArray<
|
55
|
+
}): ReadonlyArray<LiveStoreEvent.AnyDecoded> => {
|
56
56
|
const initialSnapshot = new Map(currentFactsSnapshot)
|
57
57
|
applyFactGroups(
|
58
58
|
newRemoteEvents.map((event) => event.factsGroup),
|
@@ -76,11 +76,11 @@ export const rebaseEvents = ({
|
|
76
76
|
factsIntersect(pending.factsGroup.modifySet, remote.factsGroup.modifySet),
|
77
77
|
),
|
78
78
|
})),
|
79
|
-
validate: ({ rebasedLocalEvents,
|
79
|
+
validate: ({ rebasedLocalEvents, eventDefs }) =>
|
80
80
|
validateFacts({
|
81
81
|
factGroups: rebasedLocalEvents.map((event) =>
|
82
|
-
|
83
|
-
factsCallback:
|
82
|
+
getFactsGroupForEventArgs({
|
83
|
+
factsCallback: eventDefs[event.name]!.options.facts,
|
84
84
|
args: event.args,
|
85
85
|
currentFacts: new Map(),
|
86
86
|
}),
|
@@ -95,10 +95,10 @@ export const rebaseEvents = ({
|
|
95
95
|
({
|
96
96
|
id: EventId.make({ global: headGlobalId + index + 1, client: EventId.clientDefault }),
|
97
97
|
parentId: EventId.make({ global: headGlobalId + index, client: EventId.clientDefault }),
|
98
|
-
|
98
|
+
name: event.name,
|
99
99
|
args: event.args,
|
100
100
|
clientId,
|
101
101
|
sessionId,
|
102
|
-
}) satisfies
|
102
|
+
}) satisfies LiveStoreEvent.AnyDecoded,
|
103
103
|
)
|
104
104
|
}
|
@@ -1,16 +1,16 @@
|
|
1
|
-
import {
|
1
|
+
import { defineEvent } from '@livestore/common/schema'
|
2
2
|
import { Schema } from '@livestore/utils/effect'
|
3
3
|
import { describe, expect, it } from 'vitest'
|
4
4
|
|
5
5
|
import { compactEvents } from '../compact-events.js'
|
6
6
|
import { historyDagFromNodes } from '../history-dag.js'
|
7
7
|
import { customSerializer } from './compact-events.test.js'
|
8
|
-
import { toEventNodes } from './
|
8
|
+
import { toEventNodes } from './event-fixtures.js'
|
9
9
|
|
10
10
|
expect.addSnapshotSerializer(customSerializer)
|
11
11
|
|
12
12
|
const compact = (events: any[]) => {
|
13
|
-
const dag = historyDagFromNodes(toEventNodes(events,
|
13
|
+
const dag = historyDagFromNodes(toEventNodes(events, eventDefs, 'client-id', 'session-id'))
|
14
14
|
const compacted = compactEvents(dag)
|
15
15
|
|
16
16
|
return Array.from(compacted.dag.nodeEntries())
|
@@ -23,98 +23,98 @@ const facts = {
|
|
23
23
|
multiplyByZero: `multiplyByZero`,
|
24
24
|
}
|
25
25
|
|
26
|
-
const
|
27
|
-
add:
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
}
|
39
|
-
},
|
40
|
-
),
|
26
|
+
const eventDefs = {
|
27
|
+
add: defineEvent({
|
28
|
+
name: 'add',
|
29
|
+
schema: Schema.Struct({ value: Schema.Number }),
|
30
|
+
}),
|
31
|
+
multiply: defineEvent({
|
32
|
+
name: 'multiply',
|
33
|
+
schema: Schema.Struct({ value: Schema.Number }),
|
34
|
+
facts: ({ value }, currentFacts) => ({
|
35
|
+
modify: {
|
36
|
+
set: value === 0 || currentFacts.has(facts.multiplyByZero) ? [facts.multiplyByZero] : [],
|
37
|
+
unset: value === 0 ? [] : [facts.multiplyByZero],
|
38
|
+
},
|
39
|
+
}),
|
40
|
+
}),
|
41
41
|
// TODO divide by zero
|
42
42
|
}
|
43
43
|
|
44
44
|
describe('compactEvents calculator', () => {
|
45
45
|
it('1 + 1', () => {
|
46
46
|
const expected = compact([
|
47
|
-
|
48
|
-
|
47
|
+
eventDefs.add({ value: 1 }), // 0
|
48
|
+
eventDefs.add({ value: 1 }), // 1
|
49
49
|
])
|
50
50
|
|
51
51
|
expect(expected).toMatchInlineSnapshot(`
|
52
52
|
[
|
53
|
-
{ id:
|
54
|
-
{ id:
|
53
|
+
{ id: 1, parentId: 0, name: "add", args: { value: 1 }, clientId: "client-id", sessionId: "session-id", facts: "" }
|
54
|
+
{ id: 2, parentId: 1, name: "add", args: { value: 1 }, clientId: "client-id", sessionId: "session-id", facts: "" }
|
55
55
|
]
|
56
56
|
`)
|
57
57
|
})
|
58
58
|
|
59
59
|
it('2 * 2', () => {
|
60
60
|
const expected = compact([
|
61
|
-
|
62
|
-
|
61
|
+
eventDefs.multiply({ value: 2 }), // 0
|
62
|
+
eventDefs.multiply({ value: 2 }), // 1
|
63
63
|
])
|
64
64
|
|
65
65
|
expect(expected).toMatchInlineSnapshot(`
|
66
66
|
[
|
67
|
-
{ id:
|
68
|
-
{ id:
|
67
|
+
{ id: 1, parentId: 0, name: "multiply", args: { value: 2 }, clientId: "client-id", sessionId: "session-id", facts: "?multiplyByZero -multiplyByZero" }
|
68
|
+
{ id: 2, parentId: 1, name: "multiply", args: { value: 2 }, clientId: "client-id", sessionId: "session-id", facts: "?multiplyByZero -multiplyByZero" }
|
69
69
|
]
|
70
70
|
`)
|
71
71
|
})
|
72
72
|
|
73
73
|
it('2 * 2 * 0', () => {
|
74
74
|
const expected = compact([
|
75
|
-
|
76
|
-
|
77
|
-
|
75
|
+
eventDefs.multiply({ value: 2 }), // 0
|
76
|
+
eventDefs.multiply({ value: 2 }), // 1
|
77
|
+
eventDefs.multiply({ value: 0 }), // 2
|
78
78
|
])
|
79
79
|
|
80
80
|
expect(expected).toMatchInlineSnapshot(`
|
81
81
|
[
|
82
|
-
{ id:
|
82
|
+
{ id: 3, parentId: 0, name: "multiply", args: { value: 0 }, clientId: "client-id", sessionId: "session-id", facts: "+multiplyByZero" }
|
83
83
|
]
|
84
84
|
`)
|
85
85
|
})
|
86
86
|
|
87
87
|
it('2 * 2 * 0 + 1', () => {
|
88
88
|
const expected = compact([
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
89
|
+
eventDefs.multiply({ value: 2 }), // 0
|
90
|
+
eventDefs.multiply({ value: 2 }), // 1
|
91
|
+
eventDefs.multiply({ value: 0 }), // 2
|
92
|
+
eventDefs.add({ value: 1 }), // 3
|
93
93
|
])
|
94
94
|
|
95
95
|
expect(expected).toMatchInlineSnapshot(`
|
96
96
|
[
|
97
|
-
{ id:
|
98
|
-
{ id:
|
97
|
+
{ id: 3, parentId: 0, name: "multiply", args: { value: 0 }, clientId: "client-id", sessionId: "session-id", facts: "+multiplyByZero" }
|
98
|
+
{ id: 4, parentId: 3, name: "add", args: { value: 1 }, clientId: "client-id", sessionId: "session-id", facts: "" }
|
99
99
|
]
|
100
100
|
`)
|
101
101
|
})
|
102
102
|
|
103
103
|
it('1 + 2 * 0 * 2 + 1', () => {
|
104
104
|
const expected = compact([
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
105
|
+
eventDefs.add({ value: 1 }), // 0
|
106
|
+
eventDefs.multiply({ value: 2 }), // 1
|
107
|
+
eventDefs.multiply({ value: 0 }), // 2
|
108
|
+
eventDefs.multiply({ value: 2 }), // 3
|
109
|
+
eventDefs.add({ value: 1 }), // 4
|
110
110
|
])
|
111
111
|
|
112
112
|
expect(expected).toMatchInlineSnapshot(`
|
113
113
|
[
|
114
|
-
{ id:
|
115
|
-
{ id:
|
116
|
-
{ id:
|
117
|
-
{ id:
|
114
|
+
{ id: 1, parentId: 0, name: "add", args: { value: 1 }, clientId: "client-id", sessionId: "session-id", facts: "" }
|
115
|
+
{ id: 3, parentId: 1, name: "multiply", args: { value: 0 }, clientId: "client-id", sessionId: "session-id", facts: "+multiplyByZero" }
|
116
|
+
{ id: 4, parentId: 3, name: "multiply", args: { value: 2 }, clientId: "client-id", sessionId: "session-id", facts: "?multiplyByZero +multiplyByZero -multiplyByZero" }
|
117
|
+
{ id: 5, parentId: 4, name: "add", args: { value: 1 }, clientId: "client-id", sessionId: "session-id", facts: "" }
|
118
118
|
]
|
119
119
|
`)
|
120
120
|
})
|