@livestore/common 0.3.0-dev.27 → 0.3.0-dev.28
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/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 +24 -24
- package/dist/leader-thread/LeaderSyncProcessor.d.ts +16 -3
- package/dist/leader-thread/LeaderSyncProcessor.d.ts.map +1 -1
- package/dist/leader-thread/LeaderSyncProcessor.js +65 -27
- package/dist/leader-thread/LeaderSyncProcessor.js.map +1 -1
- package/dist/leader-thread/make-leader-thread-layer.d.ts +15 -3
- package/dist/leader-thread/make-leader-thread-layer.d.ts.map +1 -1
- package/dist/leader-thread/make-leader-thread-layer.js +8 -1
- package/dist/leader-thread/make-leader-thread-layer.js.map +1 -1
- package/dist/schema/EventId.d.ts.map +1 -1
- package/dist/schema/EventId.js +5 -0
- package/dist/schema/EventId.js.map +1 -1
- package/dist/schema/MutationEvent.js +1 -1
- package/dist/schema/MutationEvent.js.map +1 -1
- package/dist/sync/syncstate.d.ts.map +1 -1
- package/dist/sync/syncstate.js +21 -15
- package/dist/sync/syncstate.js.map +1 -1
- package/dist/sync/syncstate.test.js +160 -170
- 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/leader-thread/LeaderSyncProcessor.ts +105 -34
- package/src/leader-thread/make-leader-thread-layer.ts +34 -12
- package/src/schema/EventId.ts +6 -0
- package/src/schema/MutationEvent.ts +1 -1
- package/src/sync/syncstate.test.ts +160 -171
- package/src/sync/syncstate.ts +29 -19
- package/src/version.ts +1 -1
- package/tmp/pack.tgz +0 -0
@@ -22,14 +22,13 @@ class TestEvent extends MutationEvent.EncodedWithMeta {
|
|
22
22
|
return this.rebase(parentId, this.isLocal);
|
23
23
|
};
|
24
24
|
}
|
25
|
-
const
|
26
|
-
const
|
27
|
-
const
|
28
|
-
const
|
29
|
-
const
|
30
|
-
const
|
31
|
-
const
|
32
|
-
const e_3_0 = new TestEvent({ global: 3, client: 0 }, e_2_0.id, 'a', false);
|
25
|
+
const e0_1 = new TestEvent({ global: 0, client: 1 }, EventId.ROOT, 'a', true);
|
26
|
+
const e1_0 = new TestEvent({ global: 1, client: 0 }, EventId.ROOT, 'a', false);
|
27
|
+
const e1_1 = new TestEvent({ global: 1, client: 1 }, e1_0.id, 'a', true);
|
28
|
+
const e1_2 = new TestEvent({ global: 1, client: 2 }, e1_1.id, 'a', true);
|
29
|
+
const e1_3 = new TestEvent({ global: 1, client: 3 }, e1_2.id, 'a', true);
|
30
|
+
const e2_0 = new TestEvent({ global: 2, client: 0 }, e1_0.id, 'a', false);
|
31
|
+
const e2_1 = new TestEvent({ global: 2, client: 1 }, e2_0.id, 'a', true);
|
33
32
|
const isEqualEvent = MutationEvent.isEqualEncoded;
|
34
33
|
const isClientEvent = (event) => event.isLocal;
|
35
34
|
describe('syncstate', () => {
|
@@ -38,370 +37,361 @@ describe('syncstate', () => {
|
|
38
37
|
describe('upstream-rebase', () => {
|
39
38
|
it('should rollback until start', () => {
|
40
39
|
const syncState = new SyncState.SyncState({
|
41
|
-
pending: [
|
40
|
+
pending: [e2_0],
|
42
41
|
upstreamHead: EventId.ROOT,
|
43
|
-
localHead:
|
42
|
+
localHead: e2_0.id,
|
44
43
|
});
|
45
|
-
const
|
46
|
-
const
|
44
|
+
const e1_0_e2_0 = e1_0.rebase_(e2_0.id);
|
45
|
+
const e1_1_e2_1 = e1_1.rebase_(e1_0_e2_0.id);
|
47
46
|
const result = merge({
|
48
47
|
syncState,
|
49
48
|
payload: SyncState.PayloadUpstreamRebase.make({
|
50
|
-
rollbackEvents: [
|
51
|
-
newEvents: [
|
49
|
+
rollbackEvents: [e1_0, e1_1],
|
50
|
+
newEvents: [e1_0_e2_0, e1_1_e2_1],
|
52
51
|
}),
|
53
52
|
});
|
54
|
-
const
|
53
|
+
const e2_0_e3_0 = e2_0.rebase_(e1_0_e2_0.id);
|
55
54
|
expectRebase(result);
|
56
|
-
expectEventArraysEqual(result.newSyncState.pending, [
|
57
|
-
expect(result.newSyncState.upstreamHead).toMatchObject(
|
58
|
-
expect(result.newSyncState.localHead).toMatchObject(
|
59
|
-
expectEventArraysEqual(result.newEvents, [
|
60
|
-
expectEventArraysEqual(result.rollbackEvents, [
|
55
|
+
expectEventArraysEqual(result.newSyncState.pending, [e2_0_e3_0]);
|
56
|
+
expect(result.newSyncState.upstreamHead).toMatchObject(e1_1_e2_1.id);
|
57
|
+
expect(result.newSyncState.localHead).toMatchObject(e2_0_e3_0.id);
|
58
|
+
expectEventArraysEqual(result.newEvents, [e1_0_e2_0, e1_1_e2_1, e2_0_e3_0]);
|
59
|
+
expectEventArraysEqual(result.rollbackEvents, [e1_0, e1_1, e2_0]);
|
61
60
|
});
|
62
61
|
it('should rollback only to specified point', () => {
|
63
62
|
const syncState = new SyncState.SyncState({
|
64
|
-
pending: [
|
63
|
+
pending: [e2_0],
|
65
64
|
upstreamHead: EventId.ROOT,
|
66
|
-
localHead:
|
65
|
+
localHead: e2_0.id,
|
67
66
|
});
|
68
|
-
const
|
67
|
+
const e1_1_e2_0 = e1_1.rebase_(e1_0.id);
|
69
68
|
const result = merge({
|
70
69
|
syncState,
|
71
70
|
payload: SyncState.PayloadUpstreamRebase.make({
|
72
|
-
newEvents: [
|
73
|
-
rollbackEvents: [
|
71
|
+
newEvents: [e1_1_e2_0],
|
72
|
+
rollbackEvents: [e1_1],
|
74
73
|
}),
|
75
74
|
});
|
76
|
-
const
|
75
|
+
const e2_0_e3_0 = e2_0.rebase_(e1_1_e2_0.id);
|
77
76
|
expectRebase(result);
|
78
|
-
expectEventArraysEqual(result.newSyncState.pending, [
|
79
|
-
expect(result.newSyncState.upstreamHead).toMatchObject(
|
80
|
-
expect(result.newSyncState.localHead).toMatchObject(
|
81
|
-
expectEventArraysEqual(result.newEvents, [
|
82
|
-
expectEventArraysEqual(result.rollbackEvents, [
|
77
|
+
expectEventArraysEqual(result.newSyncState.pending, [e2_0_e3_0]);
|
78
|
+
expect(result.newSyncState.upstreamHead).toMatchObject(e1_1_e2_0.id);
|
79
|
+
expect(result.newSyncState.localHead).toMatchObject(e2_0_e3_0.id);
|
80
|
+
expectEventArraysEqual(result.newEvents, [e1_1_e2_0, e2_0_e3_0]);
|
81
|
+
expectEventArraysEqual(result.rollbackEvents, [e1_1, e2_0]);
|
83
82
|
});
|
84
83
|
it('should work for empty pending', () => {
|
85
84
|
const syncState = new SyncState.SyncState({
|
86
85
|
pending: [],
|
87
86
|
upstreamHead: EventId.ROOT,
|
88
|
-
localHead:
|
87
|
+
localHead: e1_0.id,
|
89
88
|
});
|
90
89
|
const result = merge({
|
91
90
|
syncState,
|
92
|
-
payload: SyncState.PayloadUpstreamRebase.make({ rollbackEvents: [
|
91
|
+
payload: SyncState.PayloadUpstreamRebase.make({ rollbackEvents: [e1_0], newEvents: [e2_0] }),
|
93
92
|
});
|
94
93
|
expectRebase(result);
|
95
94
|
expectEventArraysEqual(result.newSyncState.pending, []);
|
96
|
-
expect(result.newSyncState.upstreamHead).toMatchObject(
|
97
|
-
expect(result.newSyncState.localHead).toMatchObject(
|
98
|
-
expect(result.newEvents).toStrictEqual([
|
95
|
+
expect(result.newSyncState.upstreamHead).toMatchObject(e2_0.id);
|
96
|
+
expect(result.newSyncState.localHead).toMatchObject(e2_0.id);
|
97
|
+
expect(result.newEvents).toStrictEqual([e2_0]);
|
99
98
|
});
|
100
99
|
});
|
101
100
|
describe('upstream-advance: advance', () => {
|
102
101
|
it('should throw error if newEvents are not sorted in ascending order by eventId (client)', () => {
|
103
102
|
const syncState = new SyncState.SyncState({
|
104
|
-
pending: [
|
103
|
+
pending: [e1_0],
|
105
104
|
upstreamHead: EventId.ROOT,
|
106
|
-
localHead:
|
105
|
+
localHead: e1_0.id,
|
107
106
|
});
|
108
|
-
const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [
|
107
|
+
const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e1_1, e1_0] } });
|
109
108
|
expect(result).toMatchObject({ _tag: 'unexpected-error' });
|
110
109
|
});
|
111
110
|
it('should throw error if newEvents are not sorted in ascending order by eventId (global)', () => {
|
112
111
|
const syncState = new SyncState.SyncState({
|
113
|
-
pending: [
|
112
|
+
pending: [e1_0],
|
114
113
|
upstreamHead: EventId.ROOT,
|
115
|
-
localHead:
|
114
|
+
localHead: e1_0.id,
|
116
115
|
});
|
117
|
-
const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [
|
116
|
+
const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e2_0, e1_0] } });
|
118
117
|
expect(result).toMatchObject({ _tag: 'unexpected-error' });
|
119
118
|
});
|
120
119
|
it('should throw error if incoming event is < expected upstream head', () => {
|
121
120
|
const syncState = new SyncState.SyncState({
|
122
121
|
pending: [],
|
123
|
-
upstreamHead:
|
124
|
-
localHead:
|
122
|
+
upstreamHead: e2_0.id,
|
123
|
+
localHead: e2_0.id,
|
125
124
|
});
|
126
|
-
const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [
|
125
|
+
const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e1_0] } });
|
127
126
|
expect(result).toMatchObject({ _tag: 'unexpected-error' });
|
128
127
|
});
|
129
128
|
it('should throw error if incoming event is = expected upstream head', () => {
|
130
129
|
const syncState = new SyncState.SyncState({
|
131
130
|
pending: [],
|
132
|
-
upstreamHead:
|
133
|
-
localHead:
|
131
|
+
upstreamHead: e2_0.id,
|
132
|
+
localHead: e2_0.id,
|
134
133
|
});
|
135
|
-
const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [
|
136
|
-
expect(result).toMatchObject({ _tag: 'unexpected-error' });
|
137
|
-
});
|
138
|
-
it('should throw if the parent id of the first incoming event is unknown', () => {
|
139
|
-
const syncState = new SyncState.SyncState({
|
140
|
-
pending: [],
|
141
|
-
upstreamHead: EventId.ROOT,
|
142
|
-
localHead: e_1_0.id,
|
143
|
-
});
|
144
|
-
const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_3_0] } });
|
134
|
+
const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e2_0] } });
|
145
135
|
expect(result).toMatchObject({ _tag: 'unexpected-error' });
|
146
136
|
});
|
147
137
|
it('should confirm pending event when receiving matching event', () => {
|
148
138
|
const syncState = new SyncState.SyncState({
|
149
|
-
pending: [
|
139
|
+
pending: [e1_0],
|
150
140
|
upstreamHead: EventId.ROOT,
|
151
|
-
localHead:
|
141
|
+
localHead: e1_0.id,
|
152
142
|
});
|
153
|
-
const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [
|
143
|
+
const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e1_0] } });
|
154
144
|
expectAdvance(result);
|
155
145
|
expectEventArraysEqual(result.newSyncState.pending, []);
|
156
|
-
expect(result.newSyncState.upstreamHead).toMatchObject(
|
157
|
-
expect(result.newSyncState.localHead).toMatchObject(
|
146
|
+
expect(result.newSyncState.upstreamHead).toMatchObject(e1_0.id);
|
147
|
+
expect(result.newSyncState.localHead).toMatchObject(e1_0.id);
|
158
148
|
expectEventArraysEqual(result.newEvents, []);
|
159
|
-
expectEventArraysEqual(result.confirmedEvents, [
|
149
|
+
expectEventArraysEqual(result.confirmedEvents, [e1_0]);
|
160
150
|
});
|
161
151
|
it('should confirm partial pending event when receiving matching event', () => {
|
162
152
|
const syncState = new SyncState.SyncState({
|
163
|
-
pending: [
|
153
|
+
pending: [e1_0, e2_0],
|
164
154
|
upstreamHead: EventId.ROOT,
|
165
|
-
localHead:
|
155
|
+
localHead: e2_0.id,
|
166
156
|
});
|
167
|
-
const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [
|
157
|
+
const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e1_0] } });
|
168
158
|
expectAdvance(result);
|
169
|
-
expectEventArraysEqual(result.newSyncState.pending, [
|
170
|
-
expect(result.newSyncState.upstreamHead).toMatchObject(
|
171
|
-
expect(result.newSyncState.localHead).toMatchObject(
|
159
|
+
expectEventArraysEqual(result.newSyncState.pending, [e2_0]);
|
160
|
+
expect(result.newSyncState.upstreamHead).toMatchObject(e1_0.id);
|
161
|
+
expect(result.newSyncState.localHead).toMatchObject(e2_0.id);
|
172
162
|
expectEventArraysEqual(result.newEvents, []);
|
173
|
-
expectEventArraysEqual(result.confirmedEvents, [
|
163
|
+
expectEventArraysEqual(result.confirmedEvents, [e1_0]);
|
174
164
|
});
|
175
165
|
it('should confirm pending event and add new event', () => {
|
176
166
|
const syncState = new SyncState.SyncState({
|
177
|
-
pending: [
|
167
|
+
pending: [e1_0],
|
178
168
|
upstreamHead: EventId.ROOT,
|
179
|
-
localHead:
|
169
|
+
localHead: e1_0.id,
|
180
170
|
});
|
181
|
-
const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [
|
171
|
+
const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e1_0, e1_1] } });
|
182
172
|
expectAdvance(result);
|
183
173
|
expectEventArraysEqual(result.newSyncState.pending, []);
|
184
|
-
expect(result.newSyncState.upstreamHead).toMatchObject(
|
185
|
-
expect(result.newSyncState.localHead).toMatchObject(
|
186
|
-
expect(result.newEvents).toStrictEqual([
|
187
|
-
expectEventArraysEqual(result.confirmedEvents, [
|
174
|
+
expect(result.newSyncState.upstreamHead).toMatchObject(e1_1.id);
|
175
|
+
expect(result.newSyncState.localHead).toMatchObject(e1_1.id);
|
176
|
+
expect(result.newEvents).toStrictEqual([e1_1]);
|
177
|
+
expectEventArraysEqual(result.confirmedEvents, [e1_0]);
|
188
178
|
});
|
189
179
|
it('should confirm pending event and add multiple new events', () => {
|
190
180
|
const syncState = new SyncState.SyncState({
|
191
|
-
pending: [
|
192
|
-
upstreamHead:
|
193
|
-
localHead:
|
181
|
+
pending: [e1_1],
|
182
|
+
upstreamHead: e1_0.id,
|
183
|
+
localHead: e1_1.id,
|
194
184
|
});
|
195
185
|
const result = merge({
|
196
186
|
syncState,
|
197
|
-
payload: { _tag: 'upstream-advance', newEvents: [
|
187
|
+
payload: { _tag: 'upstream-advance', newEvents: [e1_1, e1_2, e1_3, e2_0, e2_1] },
|
198
188
|
});
|
199
189
|
expectAdvance(result);
|
200
190
|
expectEventArraysEqual(result.newSyncState.pending, []);
|
201
|
-
expect(result.newSyncState.upstreamHead).toMatchObject(
|
202
|
-
expect(result.newSyncState.localHead).toMatchObject(
|
203
|
-
expect(result.newEvents).toStrictEqual([
|
204
|
-
expectEventArraysEqual(result.confirmedEvents, [
|
191
|
+
expect(result.newSyncState.upstreamHead).toMatchObject(e2_1.id);
|
192
|
+
expect(result.newSyncState.localHead).toMatchObject(e2_1.id);
|
193
|
+
expect(result.newEvents).toStrictEqual([e1_2, e1_3, e2_0, e2_1]);
|
194
|
+
expectEventArraysEqual(result.confirmedEvents, [e1_1]);
|
205
195
|
});
|
206
196
|
it('should confirm pending global event while keep pending client events', () => {
|
207
197
|
const syncState = new SyncState.SyncState({
|
208
|
-
pending: [
|
198
|
+
pending: [e1_0, e1_1],
|
209
199
|
upstreamHead: EventId.ROOT,
|
210
|
-
localHead:
|
200
|
+
localHead: e1_1.id,
|
211
201
|
});
|
212
202
|
const result = merge({
|
213
203
|
syncState,
|
214
|
-
payload: { _tag: 'upstream-advance', newEvents: [
|
204
|
+
payload: { _tag: 'upstream-advance', newEvents: [e1_0] },
|
215
205
|
});
|
216
206
|
expectAdvance(result);
|
217
|
-
expectEventArraysEqual(result.newSyncState.pending, [
|
218
|
-
expect(result.newSyncState.upstreamHead).toMatchObject(
|
219
|
-
expect(result.newSyncState.localHead).toMatchObject(
|
207
|
+
expectEventArraysEqual(result.newSyncState.pending, [e1_1]);
|
208
|
+
expect(result.newSyncState.upstreamHead).toMatchObject(e1_0.id);
|
209
|
+
expect(result.newSyncState.localHead).toMatchObject(e1_1.id);
|
220
210
|
expectEventArraysEqual(result.newEvents, []);
|
221
|
-
expectEventArraysEqual(result.confirmedEvents, [
|
211
|
+
expectEventArraysEqual(result.confirmedEvents, [e1_0]);
|
222
212
|
});
|
223
213
|
it('should ignore client events (incoming is subset of pending)', () => {
|
224
214
|
const syncState = new SyncState.SyncState({
|
225
|
-
pending: [
|
215
|
+
pending: [e0_1, e1_0],
|
226
216
|
upstreamHead: EventId.ROOT,
|
227
|
-
localHead:
|
217
|
+
localHead: e1_0.id,
|
228
218
|
});
|
229
219
|
const result = merge({
|
230
220
|
syncState,
|
231
|
-
payload: { _tag: 'upstream-advance', newEvents: [
|
221
|
+
payload: { _tag: 'upstream-advance', newEvents: [e1_0] },
|
232
222
|
ignoreClientEvents: true,
|
233
223
|
});
|
234
224
|
expectAdvance(result);
|
235
225
|
expectEventArraysEqual(result.newSyncState.pending, []);
|
236
|
-
expect(result.newSyncState.upstreamHead).toMatchObject(
|
237
|
-
expect(result.newSyncState.localHead).toMatchObject(
|
226
|
+
expect(result.newSyncState.upstreamHead).toMatchObject(e1_0.id);
|
227
|
+
expect(result.newSyncState.localHead).toMatchObject(e1_0.id);
|
238
228
|
expectEventArraysEqual(result.newEvents, []);
|
239
|
-
expectEventArraysEqual(result.confirmedEvents, [
|
229
|
+
expectEventArraysEqual(result.confirmedEvents, [e0_1, e1_0]);
|
240
230
|
});
|
241
231
|
it('should ignore client events (incoming is subset of pending case 2)', () => {
|
242
232
|
const syncState = new SyncState.SyncState({
|
243
|
-
pending: [
|
233
|
+
pending: [e0_1, e1_0, e2_0],
|
244
234
|
upstreamHead: EventId.ROOT,
|
245
|
-
localHead:
|
235
|
+
localHead: e1_0.id,
|
246
236
|
});
|
247
237
|
const result = merge({
|
248
238
|
syncState,
|
249
|
-
payload: { _tag: 'upstream-advance', newEvents: [
|
239
|
+
payload: { _tag: 'upstream-advance', newEvents: [e1_0] },
|
250
240
|
ignoreClientEvents: true,
|
251
241
|
});
|
252
242
|
expectAdvance(result);
|
253
|
-
expectEventArraysEqual(result.newSyncState.pending, [
|
254
|
-
expect(result.newSyncState.upstreamHead).toMatchObject(
|
255
|
-
expect(result.newSyncState.localHead).toMatchObject(
|
243
|
+
expectEventArraysEqual(result.newSyncState.pending, [e2_0]);
|
244
|
+
expect(result.newSyncState.upstreamHead).toMatchObject(e1_0.id);
|
245
|
+
expect(result.newSyncState.localHead).toMatchObject(e2_0.id);
|
256
246
|
expectEventArraysEqual(result.newEvents, []);
|
257
|
-
expectEventArraysEqual(result.confirmedEvents, [
|
247
|
+
expectEventArraysEqual(result.confirmedEvents, [e0_1, e1_0]);
|
258
248
|
});
|
259
249
|
it('should ignore client events (incoming goes beyond pending)', () => {
|
260
250
|
const syncState = new SyncState.SyncState({
|
261
|
-
pending: [
|
251
|
+
pending: [e0_1, e1_0, e1_1],
|
262
252
|
upstreamHead: EventId.ROOT,
|
263
|
-
localHead:
|
253
|
+
localHead: e1_1.id,
|
264
254
|
});
|
265
255
|
const result = merge({
|
266
256
|
syncState,
|
267
|
-
payload: { _tag: 'upstream-advance', newEvents: [
|
257
|
+
payload: { _tag: 'upstream-advance', newEvents: [e1_0, e2_0] },
|
268
258
|
ignoreClientEvents: true,
|
269
259
|
});
|
270
260
|
expectAdvance(result);
|
271
261
|
expectEventArraysEqual(result.newSyncState.pending, []);
|
272
|
-
expect(result.newSyncState.upstreamHead).toMatchObject(
|
273
|
-
expect(result.newSyncState.localHead).toMatchObject(
|
274
|
-
expect(result.newEvents).toStrictEqual([
|
275
|
-
expectEventArraysEqual(result.confirmedEvents, [
|
262
|
+
expect(result.newSyncState.upstreamHead).toMatchObject(e2_0.id);
|
263
|
+
expect(result.newSyncState.localHead).toMatchObject(e2_0.id);
|
264
|
+
expect(result.newEvents).toStrictEqual([e2_0]);
|
265
|
+
expectEventArraysEqual(result.confirmedEvents, [e0_1, e1_0, e1_1]);
|
276
266
|
});
|
277
267
|
it('should fail if incoming event is ≤ local head', () => {
|
278
268
|
const syncState = new SyncState.SyncState({
|
279
269
|
pending: [],
|
280
|
-
upstreamHead:
|
281
|
-
localHead:
|
270
|
+
upstreamHead: e2_0.id,
|
271
|
+
localHead: e2_0.id,
|
282
272
|
});
|
283
|
-
const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [
|
273
|
+
const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e1_0] } });
|
284
274
|
expect(result).toMatchObject({ _tag: 'unexpected-error' });
|
285
275
|
});
|
286
276
|
});
|
287
277
|
describe('upstream-advance: rebase', () => {
|
288
278
|
it('should rebase single client event to end', () => {
|
289
279
|
const syncState = new SyncState.SyncState({
|
290
|
-
pending: [
|
280
|
+
pending: [e1_0],
|
291
281
|
upstreamHead: EventId.ROOT,
|
292
|
-
localHead:
|
282
|
+
localHead: e1_0.id,
|
293
283
|
});
|
294
|
-
const result = merge({ syncState, payload: SyncState.PayloadUpstreamAdvance.make({ newEvents: [
|
295
|
-
const
|
284
|
+
const result = merge({ syncState, payload: SyncState.PayloadUpstreamAdvance.make({ newEvents: [e1_1] }) });
|
285
|
+
const e1_0_e1_2 = e1_0.rebase_(e1_1.id);
|
296
286
|
expectRebase(result);
|
297
|
-
expectEventArraysEqual(result.newSyncState.pending, [
|
298
|
-
expect(result.newSyncState.upstreamHead).toMatchObject(
|
299
|
-
expect(result.newSyncState.localHead).toMatchObject(
|
300
|
-
expectEventArraysEqual(result.rollbackEvents, [
|
301
|
-
expectEventArraysEqual(result.newEvents, [
|
287
|
+
expectEventArraysEqual(result.newSyncState.pending, [e1_0_e1_2]);
|
288
|
+
expect(result.newSyncState.upstreamHead).toMatchObject(e1_1.id);
|
289
|
+
expect(result.newSyncState.localHead).toMatchObject(e1_0_e1_2.id);
|
290
|
+
expectEventArraysEqual(result.rollbackEvents, [e1_0]);
|
291
|
+
expectEventArraysEqual(result.newEvents, [e1_1, e1_0_e1_2]);
|
302
292
|
});
|
303
293
|
it('should rebase different event with same id', () => {
|
304
|
-
const
|
294
|
+
const e2_0_b = new TestEvent({ global: 1, client: 0 }, e1_0.id, '1_0_b', false);
|
305
295
|
const syncState = new SyncState.SyncState({
|
306
|
-
pending: [
|
296
|
+
pending: [e2_0_b],
|
307
297
|
upstreamHead: EventId.ROOT,
|
308
|
-
localHead:
|
298
|
+
localHead: e2_0_b.id,
|
309
299
|
});
|
310
|
-
const result = merge({ syncState, payload: SyncState.PayloadUpstreamAdvance.make({ newEvents: [
|
311
|
-
const
|
300
|
+
const result = merge({ syncState, payload: SyncState.PayloadUpstreamAdvance.make({ newEvents: [e2_0] }) });
|
301
|
+
const e2_0_e3_0 = e2_0_b.rebase_(e2_0.id);
|
312
302
|
expectRebase(result);
|
313
|
-
expectEventArraysEqual(result.newSyncState.pending, [
|
314
|
-
expectEventArraysEqual(result.newEvents, [
|
315
|
-
expectEventArraysEqual(result.rollbackEvents, [
|
316
|
-
expect(result.newSyncState.upstreamHead).toMatchObject(
|
317
|
-
expect(result.newSyncState.localHead).toMatchObject(
|
303
|
+
expectEventArraysEqual(result.newSyncState.pending, [e2_0_e3_0]);
|
304
|
+
expectEventArraysEqual(result.newEvents, [e2_0, e2_0_e3_0]);
|
305
|
+
expectEventArraysEqual(result.rollbackEvents, [e2_0_b]);
|
306
|
+
expect(result.newSyncState.upstreamHead).toMatchObject(e2_0.id);
|
307
|
+
expect(result.newSyncState.localHead).toMatchObject(e2_0_e3_0.id);
|
318
308
|
});
|
319
309
|
it('should rebase single client event to end (more incoming events)', () => {
|
320
310
|
const syncState = new SyncState.SyncState({
|
321
|
-
pending: [
|
311
|
+
pending: [e1_0],
|
322
312
|
upstreamHead: EventId.ROOT,
|
323
|
-
localHead:
|
313
|
+
localHead: e1_0.id,
|
324
314
|
});
|
325
315
|
const result = merge({
|
326
316
|
syncState,
|
327
|
-
payload: SyncState.PayloadUpstreamAdvance.make({ newEvents: [
|
317
|
+
payload: SyncState.PayloadUpstreamAdvance.make({ newEvents: [e1_1, e1_2, e1_3, e2_0] }),
|
328
318
|
});
|
329
|
-
const
|
319
|
+
const e1_0_e3_0 = e1_0.rebase_(e2_0.id);
|
330
320
|
expectRebase(result);
|
331
|
-
expectEventArraysEqual(result.newSyncState.pending, [
|
332
|
-
expect(result.newSyncState.upstreamHead).toMatchObject(
|
333
|
-
expect(result.newSyncState.localHead).toMatchObject(
|
321
|
+
expectEventArraysEqual(result.newSyncState.pending, [e1_0_e3_0]);
|
322
|
+
expect(result.newSyncState.upstreamHead).toMatchObject(e2_0.id);
|
323
|
+
expect(result.newSyncState.localHead).toMatchObject(e1_0_e3_0.id);
|
334
324
|
});
|
335
325
|
it('should only rebase divergent events when first event matches', () => {
|
336
326
|
const syncState = new SyncState.SyncState({
|
337
|
-
pending: [
|
327
|
+
pending: [e1_0, e1_1],
|
338
328
|
upstreamHead: EventId.ROOT,
|
339
|
-
localHead:
|
329
|
+
localHead: e1_0.id,
|
340
330
|
});
|
341
331
|
const result = merge({
|
342
332
|
syncState,
|
343
|
-
payload: SyncState.PayloadUpstreamAdvance.make({ newEvents: [
|
333
|
+
payload: SyncState.PayloadUpstreamAdvance.make({ newEvents: [e1_0, e1_2, e1_3, e2_0] }),
|
344
334
|
});
|
345
|
-
const
|
335
|
+
const e1_1_e2_1 = e1_1.rebase_(e2_0.id);
|
346
336
|
expectRebase(result);
|
347
|
-
expectEventArraysEqual(result.newSyncState.pending, [
|
348
|
-
expectEventArraysEqual(result.rollbackEvents, [
|
349
|
-
expectEventArraysEqual(result.newEvents, [
|
350
|
-
expect(result.newSyncState.upstreamHead).toMatchObject(
|
351
|
-
expect(result.newSyncState.localHead).toMatchObject(
|
337
|
+
expectEventArraysEqual(result.newSyncState.pending, [e1_1_e2_1]);
|
338
|
+
expectEventArraysEqual(result.rollbackEvents, [e1_1]);
|
339
|
+
expectEventArraysEqual(result.newEvents, [e1_2, e1_3, e2_0, e1_1_e2_1]);
|
340
|
+
expect(result.newSyncState.upstreamHead).toMatchObject(e2_0.id);
|
341
|
+
expect(result.newSyncState.localHead).toMatchObject(e1_1_e2_1.id);
|
352
342
|
});
|
353
343
|
it('should rebase all client events when incoming chain starts differently', () => {
|
354
344
|
const syncState = new SyncState.SyncState({
|
355
|
-
pending: [
|
345
|
+
pending: [e1_0, e1_1],
|
356
346
|
upstreamHead: EventId.ROOT,
|
357
|
-
localHead:
|
347
|
+
localHead: e1_1.id,
|
358
348
|
});
|
359
349
|
const result = merge({
|
360
350
|
syncState,
|
361
|
-
payload: SyncState.PayloadUpstreamAdvance.make({ newEvents: [
|
351
|
+
payload: SyncState.PayloadUpstreamAdvance.make({ newEvents: [e1_1, e1_2, e1_3, e2_0] }),
|
362
352
|
});
|
363
|
-
const
|
364
|
-
const
|
353
|
+
const e1_0_e2_1 = e1_0.rebase_(e2_0.id);
|
354
|
+
const e1_1_e2_2 = e1_1.rebase_(e1_0_e2_1.id);
|
365
355
|
expectRebase(result);
|
366
|
-
expectEventArraysEqual(result.newSyncState.pending, [
|
367
|
-
expectEventArraysEqual(result.newEvents, [
|
368
|
-
expectEventArraysEqual(result.rollbackEvents, [
|
369
|
-
expect(result.newSyncState.upstreamHead).toMatchObject(
|
370
|
-
expect(result.newSyncState.localHead).toMatchObject(
|
356
|
+
expectEventArraysEqual(result.newSyncState.pending, [e1_0_e2_1, e1_1_e2_2]);
|
357
|
+
expectEventArraysEqual(result.newEvents, [e1_1, e1_2, e1_3, e2_0, e1_0_e2_1, e1_1_e2_2]);
|
358
|
+
expectEventArraysEqual(result.rollbackEvents, [e1_0, e1_1]);
|
359
|
+
expect(result.newSyncState.upstreamHead).toMatchObject(e2_0.id);
|
360
|
+
expect(result.newSyncState.localHead).toMatchObject(e1_1_e2_2.id);
|
371
361
|
});
|
372
362
|
describe('local-push', () => {
|
373
363
|
describe('advance', () => {
|
374
364
|
it('should advance with new events', () => {
|
375
365
|
const syncState = new SyncState.SyncState({
|
376
|
-
pending: [
|
366
|
+
pending: [e1_0],
|
377
367
|
upstreamHead: EventId.ROOT,
|
378
|
-
localHead:
|
368
|
+
localHead: e1_0.id,
|
379
369
|
});
|
380
370
|
const result = merge({
|
381
371
|
syncState,
|
382
|
-
payload: SyncState.PayloadLocalPush.make({ newEvents: [
|
372
|
+
payload: SyncState.PayloadLocalPush.make({ newEvents: [e1_1, e1_2, e1_3] }),
|
383
373
|
});
|
384
374
|
expectAdvance(result);
|
385
|
-
expectEventArraysEqual(result.newSyncState.pending, [
|
375
|
+
expectEventArraysEqual(result.newSyncState.pending, [e1_0, e1_1, e1_2, e1_3]);
|
386
376
|
expect(result.newSyncState.upstreamHead).toMatchObject(EventId.ROOT);
|
387
|
-
expect(result.newSyncState.localHead).toMatchObject(
|
388
|
-
expectEventArraysEqual(result.newEvents, [
|
377
|
+
expect(result.newSyncState.localHead).toMatchObject(e1_3.id);
|
378
|
+
expectEventArraysEqual(result.newEvents, [e1_1, e1_2, e1_3]);
|
389
379
|
expectEventArraysEqual(result.confirmedEvents, []);
|
390
380
|
});
|
391
381
|
});
|
392
382
|
describe('reject', () => {
|
393
383
|
it('should reject when new events are greater than pending events', () => {
|
394
384
|
const syncState = new SyncState.SyncState({
|
395
|
-
pending: [
|
385
|
+
pending: [e1_0, e1_1],
|
396
386
|
upstreamHead: EventId.ROOT,
|
397
|
-
localHead:
|
387
|
+
localHead: e1_1.id,
|
398
388
|
});
|
399
389
|
const result = merge({
|
400
390
|
syncState,
|
401
|
-
payload: SyncState.PayloadLocalPush.make({ newEvents: [
|
391
|
+
payload: SyncState.PayloadLocalPush.make({ newEvents: [e1_1, e1_2] }),
|
402
392
|
});
|
403
393
|
expectReject(result);
|
404
|
-
expect(result.expectedMinimumId).toMatchObject(
|
394
|
+
expect(result.expectedMinimumId).toMatchObject(e1_2.id);
|
405
395
|
});
|
406
396
|
});
|
407
397
|
});
|