@livestore/common 0.3.0-dev.25 → 0.3.0-dev.27
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 +13 -12
- package/dist/adapter-types.d.ts.map +1 -1
- package/dist/adapter-types.js +5 -6
- package/dist/adapter-types.js.map +1 -1
- package/dist/devtools/devtools-messages-client-session.d.ts +21 -21
- package/dist/devtools/devtools-messages-common.d.ts +13 -6
- package/dist/devtools/devtools-messages-common.d.ts.map +1 -1
- package/dist/devtools/devtools-messages-common.js +6 -0
- package/dist/devtools/devtools-messages-common.js.map +1 -1
- package/dist/devtools/devtools-messages-leader.d.ts +25 -25
- package/dist/devtools/devtools-messages-leader.d.ts.map +1 -1
- package/dist/devtools/devtools-messages-leader.js +1 -2
- package/dist/devtools/devtools-messages-leader.js.map +1 -1
- package/dist/leader-thread/LeaderSyncProcessor.d.ts +15 -6
- package/dist/leader-thread/LeaderSyncProcessor.d.ts.map +1 -1
- package/dist/leader-thread/LeaderSyncProcessor.js +229 -207
- package/dist/leader-thread/LeaderSyncProcessor.js.map +1 -1
- package/dist/leader-thread/apply-mutation.d.ts +14 -9
- package/dist/leader-thread/apply-mutation.d.ts.map +1 -1
- package/dist/leader-thread/apply-mutation.js +43 -36
- package/dist/leader-thread/apply-mutation.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 +4 -5
- package/dist/leader-thread/leader-worker-devtools.js.map +1 -1
- package/dist/leader-thread/make-leader-thread-layer.d.ts.map +1 -1
- package/dist/leader-thread/make-leader-thread-layer.js +21 -33
- 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/mutationlog.d.ts +19 -3
- package/dist/leader-thread/mutationlog.d.ts.map +1 -1
- package/dist/leader-thread/mutationlog.js +105 -12
- package/dist/leader-thread/mutationlog.js.map +1 -1
- package/dist/leader-thread/pull-queue-set.d.ts +1 -1
- package/dist/leader-thread/pull-queue-set.d.ts.map +1 -1
- package/dist/leader-thread/pull-queue-set.js +6 -16
- package/dist/leader-thread/pull-queue-set.js.map +1 -1
- package/dist/leader-thread/recreate-db.d.ts.map +1 -1
- package/dist/leader-thread/recreate-db.js +4 -3
- package/dist/leader-thread/recreate-db.js.map +1 -1
- package/dist/leader-thread/types.d.ts +34 -19
- package/dist/leader-thread/types.d.ts.map +1 -1
- package/dist/leader-thread/types.js.map +1 -1
- package/dist/rehydrate-from-mutationlog.d.ts +5 -4
- package/dist/rehydrate-from-mutationlog.d.ts.map +1 -1
- package/dist/rehydrate-from-mutationlog.js +7 -9
- package/dist/rehydrate-from-mutationlog.js.map +1 -1
- package/dist/schema/EventId.d.ts +9 -0
- package/dist/schema/EventId.d.ts.map +1 -1
- package/dist/schema/EventId.js +17 -2
- package/dist/schema/EventId.js.map +1 -1
- package/dist/schema/MutationEvent.d.ts +78 -25
- package/dist/schema/MutationEvent.d.ts.map +1 -1
- package/dist/schema/MutationEvent.js +25 -12
- package/dist/schema/MutationEvent.js.map +1 -1
- package/dist/schema/schema.js +1 -1
- package/dist/schema/schema.js.map +1 -1
- package/dist/schema/system-tables.d.ts +67 -0
- package/dist/schema/system-tables.d.ts.map +1 -1
- package/dist/schema/system-tables.js +12 -1
- package/dist/schema/system-tables.js.map +1 -1
- package/dist/sync/ClientSessionSyncProcessor.d.ts +9 -1
- package/dist/sync/ClientSessionSyncProcessor.d.ts.map +1 -1
- package/dist/sync/ClientSessionSyncProcessor.js +49 -43
- package/dist/sync/ClientSessionSyncProcessor.js.map +1 -1
- package/dist/sync/sync.d.ts +6 -5
- package/dist/sync/sync.d.ts.map +1 -1
- package/dist/sync/sync.js.map +1 -1
- package/dist/sync/syncstate.d.ts +60 -84
- package/dist/sync/syncstate.d.ts.map +1 -1
- package/dist/sync/syncstate.js +127 -136
- package/dist/sync/syncstate.js.map +1 -1
- package/dist/sync/syncstate.test.js +205 -276
- package/dist/sync/syncstate.test.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +2 -2
- package/src/adapter-types.ts +11 -13
- package/src/devtools/devtools-messages-common.ts +9 -0
- package/src/devtools/devtools-messages-leader.ts +1 -2
- package/src/leader-thread/LeaderSyncProcessor.ts +399 -364
- package/src/leader-thread/apply-mutation.ts +81 -71
- package/src/leader-thread/leader-worker-devtools.ts +5 -7
- package/src/leader-thread/make-leader-thread-layer.ts +26 -41
- package/src/leader-thread/mod.ts +1 -1
- package/src/leader-thread/mutationlog.ts +166 -13
- package/src/leader-thread/recreate-db.ts +4 -3
- package/src/leader-thread/types.ts +33 -23
- package/src/rehydrate-from-mutationlog.ts +12 -12
- package/src/schema/EventId.ts +20 -2
- package/src/schema/MutationEvent.ts +32 -16
- package/src/schema/schema.ts +1 -1
- package/src/schema/system-tables.ts +20 -1
- package/src/sync/ClientSessionSyncProcessor.ts +59 -47
- package/src/sync/sync.ts +6 -9
- package/src/sync/syncstate.test.ts +239 -315
- package/src/sync/syncstate.ts +191 -188
- package/src/version.ts +1 -1
- package/tmp/pack.tgz +0 -0
- package/src/leader-thread/pull-queue-set.ts +0 -67
@@ -22,457 +22,386 @@ class TestEvent extends MutationEvent.EncodedWithMeta {
|
|
22
22
|
return this.rebase(parentId, this.isLocal);
|
23
23
|
};
|
24
24
|
}
|
25
|
-
const
|
26
|
-
const
|
27
|
-
const e_0_1 = new TestEvent({ global: 0, client: 1 }, e_0_0.id, 'a', true);
|
28
|
-
const e_0_2 = new TestEvent({ global: 0, client: 2 }, e_0_1.id, 'a', true);
|
29
|
-
const e_0_3 = new TestEvent({ global: 0, client: 3 }, e_0_2.id, 'a', true);
|
30
|
-
const e_1_0 = new TestEvent({ global: 1, client: 0 }, e_0_0.id, 'a', false);
|
25
|
+
const e_0_1 = new TestEvent({ global: 0, client: 1 }, EventId.ROOT, 'a', true);
|
26
|
+
const e_1_0 = new TestEvent({ global: 1, client: 0 }, EventId.ROOT, 'a', false);
|
31
27
|
const e_1_1 = new TestEvent({ global: 1, client: 1 }, e_1_0.id, 'a', true);
|
28
|
+
const e_1_2 = new TestEvent({ global: 1, client: 2 }, e_1_1.id, 'a', true);
|
29
|
+
const e_1_3 = new TestEvent({ global: 1, client: 3 }, e_1_2.id, 'a', true);
|
32
30
|
const e_2_0 = new TestEvent({ global: 2, client: 0 }, e_1_0.id, 'a', false);
|
31
|
+
const e_2_1 = new TestEvent({ global: 2, client: 1 }, e_2_0.id, 'a', true);
|
32
|
+
const e_3_0 = new TestEvent({ global: 3, client: 0 }, e_2_0.id, 'a', false);
|
33
33
|
const isEqualEvent = MutationEvent.isEqualEncoded;
|
34
34
|
const isClientEvent = (event) => event.isLocal;
|
35
35
|
describe('syncstate', () => {
|
36
|
-
describe('
|
37
|
-
const
|
38
|
-
describe
|
36
|
+
describe('merge', () => {
|
37
|
+
const merge = ({ syncState, payload, ignoreClientEvents = false, }) => SyncState.merge({ syncState, payload, isClientEvent, isEqualEvent, ignoreClientEvents });
|
38
|
+
describe('upstream-rebase', () => {
|
39
39
|
it('should rollback until start', () => {
|
40
40
|
const syncState = new SyncState.SyncState({
|
41
|
-
pending: [
|
42
|
-
rollbackTail: [e_0_0, e_0_1],
|
41
|
+
pending: [e_2_0],
|
43
42
|
upstreamHead: EventId.ROOT,
|
44
|
-
localHead:
|
43
|
+
localHead: e_2_0.id,
|
45
44
|
});
|
46
|
-
const
|
47
|
-
const
|
48
|
-
const result =
|
45
|
+
const e_1_0_e_2_0 = e_1_0.rebase_(e_2_0.id);
|
46
|
+
const e_1_1_e_2_1 = e_1_1.rebase_(e_1_0_e_2_0.id);
|
47
|
+
const result = merge({
|
49
48
|
syncState,
|
50
|
-
payload: {
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
trimRollbackUntil: trimRollbackUntil ? e_0_1_e_1_1.id : undefined,
|
55
|
-
},
|
56
|
-
});
|
57
|
-
const e_1_0_e_2_0 = e_1_0.rebase_(e_0_0_e_1_0.id);
|
58
|
-
expectRebase(result);
|
59
|
-
expectEventArraysEqual(result.newSyncState.pending, [e_1_0_e_2_0]);
|
60
|
-
if (trimRollbackUntil) {
|
61
|
-
expectEventArraysEqual(result.newSyncState.rollbackTail, []);
|
62
|
-
}
|
63
|
-
else {
|
64
|
-
expectEventArraysEqual(result.newSyncState.rollbackTail, [e_0_0_e_1_0, e_0_1_e_1_1]);
|
65
|
-
}
|
66
|
-
expect(result.newSyncState.upstreamHead).toMatchObject(e_0_1_e_1_1.id);
|
67
|
-
expect(result.newSyncState.localHead).toMatchObject(e_1_0_e_2_0.id);
|
68
|
-
expectEventArraysEqual(result.newEvents, [e_0_0_e_1_0, e_0_1_e_1_1, e_1_0_e_2_0]);
|
69
|
-
expectEventArraysEqual(result.eventsToRollback, [e_0_0, e_0_1, e_1_0]);
|
70
|
-
});
|
71
|
-
it('should rollback only to specified point', () => {
|
72
|
-
const syncState = new SyncState.SyncState({
|
73
|
-
pending: [e_1_0],
|
74
|
-
rollbackTail: [e_0_0, e_0_1],
|
75
|
-
upstreamHead: EventId.ROOT,
|
76
|
-
localHead: e_1_0.id,
|
49
|
+
payload: SyncState.PayloadUpstreamRebase.make({
|
50
|
+
rollbackEvents: [e_1_0, e_1_1],
|
51
|
+
newEvents: [e_1_0_e_2_0, e_1_1_e_2_1],
|
52
|
+
}),
|
77
53
|
});
|
78
|
-
const
|
79
|
-
const result = update({
|
80
|
-
syncState,
|
81
|
-
payload: {
|
82
|
-
_tag: 'upstream-rebase',
|
83
|
-
rollbackUntil: e_0_1.id,
|
84
|
-
newEvents: [e_0_1_e_1_0],
|
85
|
-
trimRollbackUntil: trimRollbackUntil ? e_0_0.id : undefined,
|
86
|
-
},
|
87
|
-
});
|
88
|
-
const e_1_0_e_2_0 = e_1_0.rebase_(e_0_1_e_1_0.id);
|
54
|
+
const e_2_0_e_3_0 = e_2_0.rebase_(e_1_0_e_2_0.id);
|
89
55
|
expectRebase(result);
|
90
|
-
expectEventArraysEqual(result.newSyncState.pending, [
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
expectEventArraysEqual(result.newSyncState.rollbackTail, [e_0_0, e_0_1_e_1_0]);
|
96
|
-
}
|
97
|
-
expect(result.newSyncState.upstreamHead).toMatchObject(e_0_1_e_1_0.id);
|
98
|
-
expect(result.newSyncState.localHead).toMatchObject(e_1_0_e_2_0.id);
|
99
|
-
expectEventArraysEqual(result.newEvents, [e_0_1_e_1_0, e_1_0_e_2_0]);
|
100
|
-
expectEventArraysEqual(result.eventsToRollback, [e_0_1, e_1_0]);
|
56
|
+
expectEventArraysEqual(result.newSyncState.pending, [e_2_0_e_3_0]);
|
57
|
+
expect(result.newSyncState.upstreamHead).toMatchObject(e_1_1_e_2_1.id);
|
58
|
+
expect(result.newSyncState.localHead).toMatchObject(e_2_0_e_3_0.id);
|
59
|
+
expectEventArraysEqual(result.newEvents, [e_1_0_e_2_0, e_1_1_e_2_1, e_2_0_e_3_0]);
|
60
|
+
expectEventArraysEqual(result.rollbackEvents, [e_1_0, e_1_1, e_2_0]);
|
101
61
|
});
|
102
|
-
it('should
|
62
|
+
it('should rollback only to specified point', () => {
|
103
63
|
const syncState = new SyncState.SyncState({
|
104
|
-
pending: [],
|
105
|
-
rollbackTail: [e_0_0],
|
64
|
+
pending: [e_2_0],
|
106
65
|
upstreamHead: EventId.ROOT,
|
107
|
-
localHead:
|
66
|
+
localHead: e_2_0.id,
|
108
67
|
});
|
109
|
-
const
|
68
|
+
const e_1_1_e_2_0 = e_1_1.rebase_(e_1_0.id);
|
69
|
+
const result = merge({
|
110
70
|
syncState,
|
111
|
-
payload: {
|
71
|
+
payload: SyncState.PayloadUpstreamRebase.make({
|
72
|
+
newEvents: [e_1_1_e_2_0],
|
73
|
+
rollbackEvents: [e_1_1],
|
74
|
+
}),
|
112
75
|
});
|
76
|
+
const e_2_0_e_3_0 = e_2_0.rebase_(e_1_1_e_2_0.id);
|
113
77
|
expectRebase(result);
|
114
|
-
expectEventArraysEqual(result.newSyncState.pending, []);
|
115
|
-
|
116
|
-
expect(result.newSyncState.
|
117
|
-
|
118
|
-
|
119
|
-
});
|
120
|
-
it('should fail for empty rollback tail', () => {
|
121
|
-
const syncState = new SyncState.SyncState({
|
122
|
-
pending: [],
|
123
|
-
rollbackTail: [],
|
124
|
-
upstreamHead: EventId.ROOT,
|
125
|
-
localHead: e_0_0.id,
|
126
|
-
});
|
127
|
-
const result = update({
|
128
|
-
syncState,
|
129
|
-
payload: { _tag: 'upstream-rebase', rollbackUntil: e_0_0.id, newEvents: [e_1_0] },
|
130
|
-
});
|
131
|
-
expect(result).toMatchObject({ _tag: 'unexpected-error' });
|
78
|
+
expectEventArraysEqual(result.newSyncState.pending, [e_2_0_e_3_0]);
|
79
|
+
expect(result.newSyncState.upstreamHead).toMatchObject(e_1_1_e_2_0.id);
|
80
|
+
expect(result.newSyncState.localHead).toMatchObject(e_2_0_e_3_0.id);
|
81
|
+
expectEventArraysEqual(result.newEvents, [e_1_1_e_2_0, e_2_0_e_3_0]);
|
82
|
+
expectEventArraysEqual(result.rollbackEvents, [e_1_1, e_2_0]);
|
132
83
|
});
|
133
|
-
it('should work for empty
|
84
|
+
it('should work for empty pending', () => {
|
134
85
|
const syncState = new SyncState.SyncState({
|
135
86
|
pending: [],
|
136
|
-
rollbackTail: [e_0_0],
|
137
87
|
upstreamHead: EventId.ROOT,
|
138
|
-
localHead:
|
88
|
+
localHead: e_1_0.id,
|
139
89
|
});
|
140
|
-
const result =
|
90
|
+
const result = merge({
|
141
91
|
syncState,
|
142
|
-
payload: {
|
92
|
+
payload: SyncState.PayloadUpstreamRebase.make({ rollbackEvents: [e_1_0], newEvents: [e_2_0] }),
|
143
93
|
});
|
144
94
|
expectRebase(result);
|
145
95
|
expectEventArraysEqual(result.newSyncState.pending, []);
|
146
|
-
|
147
|
-
expect(result.newSyncState.
|
148
|
-
expect(result.
|
149
|
-
expect(result.newEvents).toStrictEqual([]);
|
96
|
+
expect(result.newSyncState.upstreamHead).toMatchObject(e_2_0.id);
|
97
|
+
expect(result.newSyncState.localHead).toMatchObject(e_2_0.id);
|
98
|
+
expect(result.newEvents).toStrictEqual([e_2_0]);
|
150
99
|
});
|
151
100
|
});
|
152
101
|
describe('upstream-advance: advance', () => {
|
153
102
|
it('should throw error if newEvents are not sorted in ascending order by eventId (client)', () => {
|
154
103
|
const syncState = new SyncState.SyncState({
|
155
|
-
pending: [
|
156
|
-
rollbackTail: [],
|
104
|
+
pending: [e_1_0],
|
157
105
|
upstreamHead: EventId.ROOT,
|
158
|
-
localHead:
|
106
|
+
localHead: e_1_0.id,
|
159
107
|
});
|
160
|
-
const result =
|
108
|
+
const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_1_1, e_1_0] } });
|
161
109
|
expect(result).toMatchObject({ _tag: 'unexpected-error' });
|
162
110
|
});
|
163
111
|
it('should throw error if newEvents are not sorted in ascending order by eventId (global)', () => {
|
164
112
|
const syncState = new SyncState.SyncState({
|
165
|
-
pending: [
|
166
|
-
rollbackTail: [],
|
113
|
+
pending: [e_1_0],
|
167
114
|
upstreamHead: EventId.ROOT,
|
168
|
-
localHead:
|
115
|
+
localHead: e_1_0.id,
|
169
116
|
});
|
170
|
-
const result =
|
117
|
+
const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_2_0, e_1_0] } });
|
171
118
|
expect(result).toMatchObject({ _tag: 'unexpected-error' });
|
172
119
|
});
|
173
120
|
it('should throw error if incoming event is < expected upstream head', () => {
|
174
121
|
const syncState = new SyncState.SyncState({
|
175
122
|
pending: [],
|
176
|
-
|
177
|
-
|
178
|
-
localHead: e_1_0.id,
|
123
|
+
upstreamHead: e_2_0.id,
|
124
|
+
localHead: e_2_0.id,
|
179
125
|
});
|
180
|
-
const result =
|
126
|
+
const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_1_0] } });
|
181
127
|
expect(result).toMatchObject({ _tag: 'unexpected-error' });
|
182
128
|
});
|
183
129
|
it('should throw error if incoming event is = expected upstream head', () => {
|
184
130
|
const syncState = new SyncState.SyncState({
|
185
131
|
pending: [],
|
186
|
-
|
187
|
-
|
188
|
-
localHead: e_1_0.id,
|
132
|
+
upstreamHead: e_2_0.id,
|
133
|
+
localHead: e_2_0.id,
|
189
134
|
});
|
190
|
-
const result =
|
135
|
+
const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_2_0] } });
|
191
136
|
expect(result).toMatchObject({ _tag: 'unexpected-error' });
|
192
137
|
});
|
193
138
|
it('should throw if the parent id of the first incoming event is unknown', () => {
|
194
139
|
const syncState = new SyncState.SyncState({
|
195
140
|
pending: [],
|
196
|
-
rollbackTail: [e_0_0],
|
197
141
|
upstreamHead: EventId.ROOT,
|
198
|
-
localHead:
|
142
|
+
localHead: e_1_0.id,
|
199
143
|
});
|
200
|
-
const result =
|
144
|
+
const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_3_0] } });
|
201
145
|
expect(result).toMatchObject({ _tag: 'unexpected-error' });
|
202
146
|
});
|
203
|
-
it('should
|
147
|
+
it('should confirm pending event when receiving matching event', () => {
|
204
148
|
const syncState = new SyncState.SyncState({
|
205
|
-
pending: [
|
206
|
-
rollbackTail: [],
|
149
|
+
pending: [e_1_0],
|
207
150
|
upstreamHead: EventId.ROOT,
|
208
|
-
localHead:
|
151
|
+
localHead: e_1_0.id,
|
209
152
|
});
|
210
|
-
const result =
|
153
|
+
const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_1_0] } });
|
211
154
|
expectAdvance(result);
|
212
155
|
expectEventArraysEqual(result.newSyncState.pending, []);
|
213
|
-
|
214
|
-
expect(result.newSyncState.
|
215
|
-
|
216
|
-
|
156
|
+
expect(result.newSyncState.upstreamHead).toMatchObject(e_1_0.id);
|
157
|
+
expect(result.newSyncState.localHead).toMatchObject(e_1_0.id);
|
158
|
+
expectEventArraysEqual(result.newEvents, []);
|
159
|
+
expectEventArraysEqual(result.confirmedEvents, [e_1_0]);
|
217
160
|
});
|
218
|
-
it('should
|
161
|
+
it('should confirm partial pending event when receiving matching event', () => {
|
219
162
|
const syncState = new SyncState.SyncState({
|
220
|
-
pending: [
|
221
|
-
rollbackTail: [],
|
163
|
+
pending: [e_1_0, e_2_0],
|
222
164
|
upstreamHead: EventId.ROOT,
|
223
|
-
localHead:
|
165
|
+
localHead: e_2_0.id,
|
224
166
|
});
|
225
|
-
const result =
|
167
|
+
const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_1_0] } });
|
226
168
|
expectAdvance(result);
|
227
|
-
expectEventArraysEqual(result.newSyncState.pending, [
|
228
|
-
|
229
|
-
expect(result.newSyncState.
|
230
|
-
|
231
|
-
|
169
|
+
expectEventArraysEqual(result.newSyncState.pending, [e_2_0]);
|
170
|
+
expect(result.newSyncState.upstreamHead).toMatchObject(e_1_0.id);
|
171
|
+
expect(result.newSyncState.localHead).toMatchObject(e_2_0.id);
|
172
|
+
expectEventArraysEqual(result.newEvents, []);
|
173
|
+
expectEventArraysEqual(result.confirmedEvents, [e_1_0]);
|
232
174
|
});
|
233
|
-
it('should
|
175
|
+
it('should confirm pending event and add new event', () => {
|
234
176
|
const syncState = new SyncState.SyncState({
|
235
|
-
pending: [
|
236
|
-
rollbackTail: [],
|
177
|
+
pending: [e_1_0],
|
237
178
|
upstreamHead: EventId.ROOT,
|
238
|
-
localHead:
|
179
|
+
localHead: e_1_0.id,
|
239
180
|
});
|
240
|
-
const result =
|
181
|
+
const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_1_0, e_1_1] } });
|
241
182
|
expectAdvance(result);
|
242
183
|
expectEventArraysEqual(result.newSyncState.pending, []);
|
243
|
-
|
244
|
-
expect(result.newSyncState.
|
245
|
-
expect(result.
|
246
|
-
|
184
|
+
expect(result.newSyncState.upstreamHead).toMatchObject(e_1_1.id);
|
185
|
+
expect(result.newSyncState.localHead).toMatchObject(e_1_1.id);
|
186
|
+
expect(result.newEvents).toStrictEqual([e_1_1]);
|
187
|
+
expectEventArraysEqual(result.confirmedEvents, [e_1_0]);
|
247
188
|
});
|
248
|
-
it('should
|
189
|
+
it('should confirm pending event and add multiple new events', () => {
|
249
190
|
const syncState = new SyncState.SyncState({
|
250
|
-
pending: [
|
251
|
-
|
252
|
-
|
253
|
-
localHead: e_0_1.id,
|
191
|
+
pending: [e_1_1],
|
192
|
+
upstreamHead: e_1_0.id,
|
193
|
+
localHead: e_1_1.id,
|
254
194
|
});
|
255
|
-
const result =
|
195
|
+
const result = merge({
|
256
196
|
syncState,
|
257
|
-
payload: { _tag: 'upstream-advance', newEvents: [
|
197
|
+
payload: { _tag: 'upstream-advance', newEvents: [e_1_1, e_1_2, e_1_3, e_2_0, e_2_1] },
|
258
198
|
});
|
259
199
|
expectAdvance(result);
|
260
200
|
expectEventArraysEqual(result.newSyncState.pending, []);
|
261
|
-
|
262
|
-
expect(result.newSyncState.
|
201
|
+
expect(result.newSyncState.upstreamHead).toMatchObject(e_2_1.id);
|
202
|
+
expect(result.newSyncState.localHead).toMatchObject(e_2_1.id);
|
203
|
+
expect(result.newEvents).toStrictEqual([e_1_2, e_1_3, e_2_0, e_2_1]);
|
204
|
+
expectEventArraysEqual(result.confirmedEvents, [e_1_1]);
|
205
|
+
});
|
206
|
+
it('should confirm pending global event while keep pending client events', () => {
|
207
|
+
const syncState = new SyncState.SyncState({
|
208
|
+
pending: [e_1_0, e_1_1],
|
209
|
+
upstreamHead: EventId.ROOT,
|
210
|
+
localHead: e_1_1.id,
|
211
|
+
});
|
212
|
+
const result = merge({
|
213
|
+
syncState,
|
214
|
+
payload: { _tag: 'upstream-advance', newEvents: [e_1_0] },
|
215
|
+
});
|
216
|
+
expectAdvance(result);
|
217
|
+
expectEventArraysEqual(result.newSyncState.pending, [e_1_1]);
|
218
|
+
expect(result.newSyncState.upstreamHead).toMatchObject(e_1_0.id);
|
263
219
|
expect(result.newSyncState.localHead).toMatchObject(e_1_1.id);
|
264
|
-
|
220
|
+
expectEventArraysEqual(result.newEvents, []);
|
221
|
+
expectEventArraysEqual(result.confirmedEvents, [e_1_0]);
|
265
222
|
});
|
266
223
|
it('should ignore client events (incoming is subset of pending)', () => {
|
267
224
|
const syncState = new SyncState.SyncState({
|
268
|
-
pending: [
|
269
|
-
rollbackTail: [],
|
225
|
+
pending: [e_0_1, e_1_0],
|
270
226
|
upstreamHead: EventId.ROOT,
|
271
|
-
localHead:
|
227
|
+
localHead: e_1_0.id,
|
272
228
|
});
|
273
|
-
const result =
|
229
|
+
const result = merge({
|
274
230
|
syncState,
|
275
|
-
payload: { _tag: 'upstream-advance', newEvents: [
|
231
|
+
payload: { _tag: 'upstream-advance', newEvents: [e_1_0] },
|
276
232
|
ignoreClientEvents: true,
|
277
233
|
});
|
278
234
|
expectAdvance(result);
|
279
235
|
expectEventArraysEqual(result.newSyncState.pending, []);
|
280
|
-
|
281
|
-
expect(result.newSyncState.
|
282
|
-
|
283
|
-
|
236
|
+
expect(result.newSyncState.upstreamHead).toMatchObject(e_1_0.id);
|
237
|
+
expect(result.newSyncState.localHead).toMatchObject(e_1_0.id);
|
238
|
+
expectEventArraysEqual(result.newEvents, []);
|
239
|
+
expectEventArraysEqual(result.confirmedEvents, [e_0_1, e_1_0]);
|
284
240
|
});
|
285
241
|
it('should ignore client events (incoming is subset of pending case 2)', () => {
|
286
242
|
const syncState = new SyncState.SyncState({
|
287
|
-
pending: [
|
288
|
-
rollbackTail: [],
|
243
|
+
pending: [e_0_1, e_1_0, e_2_0],
|
289
244
|
upstreamHead: EventId.ROOT,
|
290
|
-
localHead:
|
245
|
+
localHead: e_1_0.id,
|
291
246
|
});
|
292
|
-
const result =
|
247
|
+
const result = merge({
|
293
248
|
syncState,
|
294
|
-
payload: { _tag: 'upstream-advance', newEvents: [
|
249
|
+
payload: { _tag: 'upstream-advance', newEvents: [e_1_0] },
|
295
250
|
ignoreClientEvents: true,
|
296
251
|
});
|
297
252
|
expectAdvance(result);
|
298
|
-
expectEventArraysEqual(result.newSyncState.pending, [
|
299
|
-
|
300
|
-
expect(result.newSyncState.
|
301
|
-
|
302
|
-
|
253
|
+
expectEventArraysEqual(result.newSyncState.pending, [e_2_0]);
|
254
|
+
expect(result.newSyncState.upstreamHead).toMatchObject(e_1_0.id);
|
255
|
+
expect(result.newSyncState.localHead).toMatchObject(e_2_0.id);
|
256
|
+
expectEventArraysEqual(result.newEvents, []);
|
257
|
+
expectEventArraysEqual(result.confirmedEvents, [e_0_1, e_1_0]);
|
303
258
|
});
|
304
259
|
it('should ignore client events (incoming goes beyond pending)', () => {
|
305
260
|
const syncState = new SyncState.SyncState({
|
306
|
-
pending: [
|
307
|
-
rollbackTail: [],
|
261
|
+
pending: [e_0_1, e_1_0, e_1_1],
|
308
262
|
upstreamHead: EventId.ROOT,
|
309
|
-
localHead:
|
263
|
+
localHead: e_1_1.id,
|
310
264
|
});
|
311
|
-
const result =
|
265
|
+
const result = merge({
|
312
266
|
syncState,
|
313
|
-
payload: { _tag: 'upstream-advance', newEvents: [
|
267
|
+
payload: { _tag: 'upstream-advance', newEvents: [e_1_0, e_2_0] },
|
314
268
|
ignoreClientEvents: true,
|
315
269
|
});
|
316
270
|
expectAdvance(result);
|
317
271
|
expectEventArraysEqual(result.newSyncState.pending, []);
|
318
|
-
|
319
|
-
expect(result.newSyncState.
|
320
|
-
expect(result.
|
321
|
-
|
272
|
+
expect(result.newSyncState.upstreamHead).toMatchObject(e_2_0.id);
|
273
|
+
expect(result.newSyncState.localHead).toMatchObject(e_2_0.id);
|
274
|
+
expect(result.newEvents).toStrictEqual([e_2_0]);
|
275
|
+
expectEventArraysEqual(result.confirmedEvents, [e_0_1, e_1_0, e_1_1]);
|
322
276
|
});
|
323
277
|
it('should fail if incoming event is ≤ local head', () => {
|
324
278
|
const syncState = new SyncState.SyncState({
|
325
279
|
pending: [],
|
326
|
-
|
327
|
-
|
328
|
-
localHead: e_1_0.id,
|
280
|
+
upstreamHead: e_2_0.id,
|
281
|
+
localHead: e_2_0.id,
|
329
282
|
});
|
330
|
-
const result =
|
283
|
+
const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_1_0] } });
|
331
284
|
expect(result).toMatchObject({ _tag: 'unexpected-error' });
|
332
285
|
});
|
333
286
|
});
|
334
287
|
describe('upstream-advance: rebase', () => {
|
335
288
|
it('should rebase single client event to end', () => {
|
336
289
|
const syncState = new SyncState.SyncState({
|
337
|
-
pending: [
|
338
|
-
rollbackTail: [],
|
339
|
-
upstreamHead: EventId.ROOT,
|
340
|
-
localHead: e_0_0.id,
|
341
|
-
});
|
342
|
-
const result = update({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_0_1] } });
|
343
|
-
const e_0_0_e_0_2 = e_0_0.rebase_(e_0_1.id);
|
344
|
-
expectRebase(result);
|
345
|
-
expectEventArraysEqual(result.newSyncState.pending, [e_0_0_e_0_2]);
|
346
|
-
expectEventArraysEqual(result.newSyncState.rollbackTail, [e_0_1]);
|
347
|
-
expect(result.newSyncState.upstreamHead).toMatchObject(e_0_1.id);
|
348
|
-
expect(result.newSyncState.localHead).toMatchObject(e_0_0_e_0_2.id);
|
349
|
-
expectEventArraysEqual(result.eventsToRollback, [e_0_0]);
|
350
|
-
expectEventArraysEqual(result.newEvents, [e_0_1, e_0_0_e_0_2]);
|
351
|
-
});
|
352
|
-
it('should rebase different event with same id (no rollback tail)', () => {
|
353
|
-
const e_0_0_b = new TestEvent({ global: 0, client: 0 }, EventId.ROOT, '0_0_b', true);
|
354
|
-
const syncState = new SyncState.SyncState({
|
355
|
-
pending: [e_0_0_b],
|
356
|
-
rollbackTail: [],
|
290
|
+
pending: [e_1_0],
|
357
291
|
upstreamHead: EventId.ROOT,
|
358
|
-
localHead:
|
292
|
+
localHead: e_1_0.id,
|
359
293
|
});
|
360
|
-
const result =
|
361
|
-
const
|
294
|
+
const result = merge({ syncState, payload: SyncState.PayloadUpstreamAdvance.make({ newEvents: [e_1_1] }) });
|
295
|
+
const e_1_0_e_1_2 = e_1_0.rebase_(e_1_1.id);
|
362
296
|
expectRebase(result);
|
363
|
-
expectEventArraysEqual(result.newSyncState.pending, [
|
364
|
-
|
365
|
-
|
366
|
-
expectEventArraysEqual(result.
|
367
|
-
|
368
|
-
expect(result.newSyncState.localHead).toMatchObject(e_0_0_e_1_0.id);
|
297
|
+
expectEventArraysEqual(result.newSyncState.pending, [e_1_0_e_1_2]);
|
298
|
+
expect(result.newSyncState.upstreamHead).toMatchObject(e_1_1.id);
|
299
|
+
expect(result.newSyncState.localHead).toMatchObject(e_1_0_e_1_2.id);
|
300
|
+
expectEventArraysEqual(result.rollbackEvents, [e_1_0]);
|
301
|
+
expectEventArraysEqual(result.newEvents, [e_1_1, e_1_0_e_1_2]);
|
369
302
|
});
|
370
303
|
it('should rebase different event with same id', () => {
|
371
|
-
const
|
304
|
+
const e_2_0_b = new TestEvent({ global: 1, client: 0 }, e_1_0.id, '1_0_b', false);
|
372
305
|
const syncState = new SyncState.SyncState({
|
373
|
-
pending: [
|
374
|
-
rollbackTail: [e_0_0, e_0_1],
|
306
|
+
pending: [e_2_0_b],
|
375
307
|
upstreamHead: EventId.ROOT,
|
376
|
-
localHead:
|
308
|
+
localHead: e_2_0_b.id,
|
377
309
|
});
|
378
|
-
const result =
|
379
|
-
const
|
310
|
+
const result = merge({ syncState, payload: SyncState.PayloadUpstreamAdvance.make({ newEvents: [e_2_0] }) });
|
311
|
+
const e_2_0_e_3_0 = e_2_0_b.rebase_(e_2_0.id);
|
380
312
|
expectRebase(result);
|
381
|
-
expectEventArraysEqual(result.newSyncState.pending, [
|
382
|
-
expectEventArraysEqual(result.
|
383
|
-
expectEventArraysEqual(result.
|
384
|
-
|
385
|
-
expect(result.newSyncState.
|
386
|
-
expect(result.newSyncState.localHead).toMatchObject(e_1_0_e_2_0.id);
|
313
|
+
expectEventArraysEqual(result.newSyncState.pending, [e_2_0_e_3_0]);
|
314
|
+
expectEventArraysEqual(result.newEvents, [e_2_0, e_2_0_e_3_0]);
|
315
|
+
expectEventArraysEqual(result.rollbackEvents, [e_2_0_b]);
|
316
|
+
expect(result.newSyncState.upstreamHead).toMatchObject(e_2_0.id);
|
317
|
+
expect(result.newSyncState.localHead).toMatchObject(e_2_0_e_3_0.id);
|
387
318
|
});
|
388
319
|
it('should rebase single client event to end (more incoming events)', () => {
|
389
320
|
const syncState = new SyncState.SyncState({
|
390
|
-
pending: [
|
391
|
-
rollbackTail: [],
|
321
|
+
pending: [e_1_0],
|
392
322
|
upstreamHead: EventId.ROOT,
|
393
|
-
localHead:
|
323
|
+
localHead: e_1_0.id,
|
394
324
|
});
|
395
|
-
const result =
|
325
|
+
const result = merge({
|
396
326
|
syncState,
|
397
|
-
payload: {
|
327
|
+
payload: SyncState.PayloadUpstreamAdvance.make({ newEvents: [e_1_1, e_1_2, e_1_3, e_2_0] }),
|
398
328
|
});
|
399
|
-
const
|
329
|
+
const e_1_0_e_3_0 = e_1_0.rebase_(e_2_0.id);
|
400
330
|
expectRebase(result);
|
401
|
-
expectEventArraysEqual(result.newSyncState.pending, [
|
402
|
-
|
403
|
-
expect(result.newSyncState.
|
404
|
-
expect(result.newSyncState.localHead).toMatchObject(e_0_0_e_2_0.id);
|
331
|
+
expectEventArraysEqual(result.newSyncState.pending, [e_1_0_e_3_0]);
|
332
|
+
expect(result.newSyncState.upstreamHead).toMatchObject(e_2_0.id);
|
333
|
+
expect(result.newSyncState.localHead).toMatchObject(e_1_0_e_3_0.id);
|
405
334
|
});
|
406
335
|
it('should only rebase divergent events when first event matches', () => {
|
407
336
|
const syncState = new SyncState.SyncState({
|
408
|
-
pending: [
|
409
|
-
rollbackTail: [],
|
337
|
+
pending: [e_1_0, e_1_1],
|
410
338
|
upstreamHead: EventId.ROOT,
|
411
|
-
localHead:
|
339
|
+
localHead: e_1_0.id,
|
412
340
|
});
|
413
|
-
const result =
|
341
|
+
const result = merge({
|
414
342
|
syncState,
|
415
|
-
payload: {
|
343
|
+
payload: SyncState.PayloadUpstreamAdvance.make({ newEvents: [e_1_0, e_1_2, e_1_3, e_2_0] }),
|
416
344
|
});
|
417
|
-
const
|
345
|
+
const e_1_1_e_2_1 = e_1_1.rebase_(e_2_0.id);
|
418
346
|
expectRebase(result);
|
419
|
-
expectEventArraysEqual(result.newSyncState.pending, [
|
420
|
-
expectEventArraysEqual(result.
|
421
|
-
expectEventArraysEqual(result.
|
422
|
-
|
423
|
-
expect(result.newSyncState.
|
424
|
-
expect(result.newSyncState.localHead).toMatchObject(e_0_1_e_1_1.id);
|
347
|
+
expectEventArraysEqual(result.newSyncState.pending, [e_1_1_e_2_1]);
|
348
|
+
expectEventArraysEqual(result.rollbackEvents, [e_1_1]);
|
349
|
+
expectEventArraysEqual(result.newEvents, [e_1_2, e_1_3, e_2_0, e_1_1_e_2_1]);
|
350
|
+
expect(result.newSyncState.upstreamHead).toMatchObject(e_2_0.id);
|
351
|
+
expect(result.newSyncState.localHead).toMatchObject(e_1_1_e_2_1.id);
|
425
352
|
});
|
426
353
|
it('should rebase all client events when incoming chain starts differently', () => {
|
427
354
|
const syncState = new SyncState.SyncState({
|
428
|
-
pending: [
|
429
|
-
rollbackTail: [],
|
355
|
+
pending: [e_1_0, e_1_1],
|
430
356
|
upstreamHead: EventId.ROOT,
|
431
|
-
localHead:
|
357
|
+
localHead: e_1_1.id,
|
432
358
|
});
|
433
|
-
const result =
|
359
|
+
const result = merge({
|
434
360
|
syncState,
|
435
|
-
payload: {
|
361
|
+
payload: SyncState.PayloadUpstreamAdvance.make({ newEvents: [e_1_1, e_1_2, e_1_3, e_2_0] }),
|
436
362
|
});
|
437
|
-
const
|
438
|
-
const
|
363
|
+
const e_1_0_e_2_1 = e_1_0.rebase_(e_2_0.id);
|
364
|
+
const e_1_1_e_2_2 = e_1_1.rebase_(e_1_0_e_2_1.id);
|
439
365
|
expectRebase(result);
|
440
|
-
expectEventArraysEqual(result.newSyncState.pending, [
|
441
|
-
expectEventArraysEqual(result.
|
442
|
-
expectEventArraysEqual(result.
|
443
|
-
|
444
|
-
expect(result.newSyncState.
|
445
|
-
expect(result.newSyncState.localHead).toMatchObject(e_0_1_e_1_2.id);
|
366
|
+
expectEventArraysEqual(result.newSyncState.pending, [e_1_0_e_2_1, e_1_1_e_2_2]);
|
367
|
+
expectEventArraysEqual(result.newEvents, [e_1_1, e_1_2, e_1_3, e_2_0, e_1_0_e_2_1, e_1_1_e_2_2]);
|
368
|
+
expectEventArraysEqual(result.rollbackEvents, [e_1_0, e_1_1]);
|
369
|
+
expect(result.newSyncState.upstreamHead).toMatchObject(e_2_0.id);
|
370
|
+
expect(result.newSyncState.localHead).toMatchObject(e_1_1_e_2_2.id);
|
446
371
|
});
|
447
372
|
describe('local-push', () => {
|
448
373
|
describe('advance', () => {
|
449
374
|
it('should advance with new events', () => {
|
450
375
|
const syncState = new SyncState.SyncState({
|
451
|
-
pending: [
|
452
|
-
rollbackTail: [],
|
376
|
+
pending: [e_1_0],
|
453
377
|
upstreamHead: EventId.ROOT,
|
454
|
-
localHead:
|
378
|
+
localHead: e_1_0.id,
|
379
|
+
});
|
380
|
+
const result = merge({
|
381
|
+
syncState,
|
382
|
+
payload: SyncState.PayloadLocalPush.make({ newEvents: [e_1_1, e_1_2, e_1_3] }),
|
455
383
|
});
|
456
|
-
const result = update({ syncState, payload: { _tag: 'local-push', newEvents: [e_0_1, e_0_2, e_0_3] } });
|
457
384
|
expectAdvance(result);
|
458
|
-
expectEventArraysEqual(result.newSyncState.pending, [
|
459
|
-
expectEventArraysEqual(result.newSyncState.rollbackTail, []);
|
385
|
+
expectEventArraysEqual(result.newSyncState.pending, [e_1_0, e_1_1, e_1_2, e_1_3]);
|
460
386
|
expect(result.newSyncState.upstreamHead).toMatchObject(EventId.ROOT);
|
461
|
-
expect(result.newSyncState.localHead).toMatchObject(
|
462
|
-
expectEventArraysEqual(result.newEvents, [
|
387
|
+
expect(result.newSyncState.localHead).toMatchObject(e_1_3.id);
|
388
|
+
expectEventArraysEqual(result.newEvents, [e_1_1, e_1_2, e_1_3]);
|
389
|
+
expectEventArraysEqual(result.confirmedEvents, []);
|
463
390
|
});
|
464
391
|
});
|
465
392
|
describe('reject', () => {
|
466
393
|
it('should reject when new events are greater than pending events', () => {
|
467
394
|
const syncState = new SyncState.SyncState({
|
468
|
-
pending: [
|
469
|
-
rollbackTail: [],
|
395
|
+
pending: [e_1_0, e_1_1],
|
470
396
|
upstreamHead: EventId.ROOT,
|
471
|
-
localHead:
|
397
|
+
localHead: e_1_1.id,
|
398
|
+
});
|
399
|
+
const result = merge({
|
400
|
+
syncState,
|
401
|
+
payload: SyncState.PayloadLocalPush.make({ newEvents: [e_1_1, e_1_2] }),
|
472
402
|
});
|
473
|
-
const result = update({ syncState, payload: { _tag: 'local-push', newEvents: [e_0_1, e_0_2] } });
|
474
403
|
expectReject(result);
|
475
|
-
expect(result.expectedMinimumId).toMatchObject(
|
404
|
+
expect(result.expectedMinimumId).toMatchObject(e_1_2.id);
|
476
405
|
});
|
477
406
|
});
|
478
407
|
});
|
@@ -492,7 +421,7 @@ function expectAdvance(result) {
|
|
492
421
|
expect(result._tag).toBe('advance');
|
493
422
|
}
|
494
423
|
function expectRebase(result) {
|
495
|
-
expect(result._tag).toBe('rebase');
|
424
|
+
expect(result._tag, `Expected rebase, got ${result}`).toBe('rebase');
|
496
425
|
}
|
497
426
|
function expectReject(result) {
|
498
427
|
expect(result._tag).toBe('reject');
|