Skip to content

Commit c021d5e

Browse files
committed
patch(fix): octo fixed overlay bugs.
- Factory initializing overlay-data.repository incorrectly. - overlay-data.repository diff() to be async. - overlay-data.repository diff() to handle update. - overlay model diff() to not have previous optional.
1 parent 3850e01 commit c021d5e

File tree

4 files changed

+197
-71
lines changed

4 files changed

+197
-71
lines changed

packages/octo/src/overlays/overlay-data.repository.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,15 @@ export class OverlayDataRepository {
2121
}
2222
}
2323

24-
diff(): Diff[] {
24+
async diff(): Promise<Diff[]> {
2525
const diffs: Diff[] = [];
2626

2727
for (const overlay of this.oldOverlays) {
28-
if (!this.newOverlays.find((o) => o.overlayId === overlay.overlayId)) {
28+
const newOverlay = this.newOverlays.find((o) => o.overlayId === overlay.overlayId);
29+
if (!newOverlay) {
2930
diffs.push(new Diff(overlay, DiffAction.DELETE, 'overlayId', overlay.overlayId));
31+
} else {
32+
diffs.push(...(await newOverlay.diff(overlay)));
3033
}
3134
}
3235

@@ -49,7 +52,7 @@ export class OverlayDataRepository {
4952

5053
remove(overlay: UnknownOverlay): void {
5154
if (overlay.MODEL_TYPE !== ModelType.OVERLAY) {
52-
throw new Error('Adding non-overlay model!');
55+
throw new Error('Removing non-overlay model!');
5356
}
5457

5558
const overlayIndex = this.newOverlays.findIndex((o) => o.overlayId === overlay.overlayId);
@@ -69,10 +72,10 @@ export class OverlayDataRepositoryFactory {
6972
oldOverlays: UnknownOverlay[],
7073
): Promise<OverlayDataRepository> {
7174
if (!this.instance) {
72-
this.instance = new OverlayDataRepository(newOverlays, oldOverlays);
75+
this.instance = new OverlayDataRepository(oldOverlays, newOverlays);
7376
}
7477
if (forceNew) {
75-
const newInstance = new OverlayDataRepository(newOverlays, oldOverlays);
78+
const newInstance = new OverlayDataRepository(oldOverlays, newOverlays);
7679
Object.keys(this.instance).forEach((key) => (this.instance[key] = newInstance[key]));
7780
}
7881
return this.instance;

packages/octo/src/overlays/overlay.abstract.ts

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -36,19 +36,11 @@ export abstract class AOverlay<T> extends AModel<IOverlay, T> {
3636
this.anchors.push(anchor);
3737
}
3838

39-
async diff(previous?: T): Promise<Diff[]> {
39+
async diff(previous: T): Promise<Diff[]> {
4040
const diffs: Diff[] = [];
4141

42-
if (previous) {
43-
const propertyDiffs = DiffUtility.diffObject(
44-
(previous || { properties: {} }) as unknown as UnknownOverlay,
45-
this,
46-
'properties',
47-
);
48-
diffs.push(...propertyDiffs);
49-
} else {
50-
diffs.push(new Diff(this, DiffAction.ADD, 'overlayId', this.overlayId));
51-
}
42+
const propertyDiffs = DiffUtility.diffObject(previous as unknown as UnknownOverlay, this, 'properties');
43+
diffs.push(...propertyDiffs);
5244

5345
return diffs;
5446
}

packages/octo/src/overlays/overlay.spec.ts

Lines changed: 185 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,73 @@
11
import { TestAnchor, TestOverlay } from '../../test/helpers/test-classes.js';
2+
import { Container } from '../decorators/container.js';
3+
import { DiffAction } from '../functions/diff/diff.js';
24
import { App } from '../models/app/app.model.js';
5+
import { OverlayDataRepository, OverlayDataRepositoryFactory } from './overlay-data.repository.js';
36
import { AOverlay } from './overlay.abstract.js';
7+
import { OverlayService, OverlayServiceFactory } from './overlay.service.js';
48

59
describe('Overlay UT', () => {
10+
beforeEach(() => {
11+
Container.registerFactory(OverlayDataRepository, OverlayDataRepositoryFactory);
12+
Container.get(OverlayDataRepository, { args: [true, [], []] });
13+
14+
Container.registerFactory(OverlayService, OverlayServiceFactory);
15+
});
16+
17+
afterEach(() => {
18+
Container.reset();
19+
});
20+
21+
describe('addAnchor()', () => {
22+
it('should create dependency between overlay and anchor parents', () => {
23+
const app = new App('test');
24+
const anchor1 = new TestAnchor('anchor-1', app);
25+
app['anchors'].push(anchor1);
26+
27+
const overlay1 = new TestOverlay('overlay-1', {}, [anchor1]);
28+
29+
// App to Overlay dependency.
30+
expect(app['dependencies']).toMatchInlineSnapshot(`
31+
[
32+
{
33+
"from": "app=test",
34+
"relationship": undefined,
35+
"to": "test-overlay=overlay-1",
36+
},
37+
]
38+
`);
39+
expect(
40+
app['dependencies'][0].hasMatchingBehavior('MODEL_NAME', DiffAction.DELETE, 'overlayId', DiffAction.DELETE),
41+
).toBe(true);
42+
43+
// Overlay to App dependency.
44+
expect(overlay1['dependencies']).toMatchInlineSnapshot(`
45+
[
46+
{
47+
"from": "test-overlay=overlay-1",
48+
"relationship": undefined,
49+
"to": "app=test",
50+
},
51+
]
52+
`);
53+
expect(
54+
overlay1['dependencies'][0].hasMatchingBehavior('overlayId', DiffAction.ADD, 'MODEL_NAME', DiffAction.ADD),
55+
).toBe(true);
56+
expect(
57+
overlay1['dependencies'][0].hasMatchingBehavior('overlayId', DiffAction.ADD, 'MODEL_NAME', DiffAction.UPDATE),
58+
).toBe(true);
59+
});
60+
});
61+
662
describe('diff()', () => {
7-
it('should produce an add diff without previous', async () => {
8-
const overlay = new TestOverlay('overlay-1', {}, []);
63+
it('should produce an add diff', async () => {
64+
const overlayDataRepository = await Container.get(OverlayDataRepository);
65+
const overlayService = await Container.get(OverlayService);
966

10-
const diffs = await overlay.diff();
67+
const overlay1 = new TestOverlay('overlay-1', {}, []);
68+
overlayService.addOverlay(overlay1);
69+
70+
const diffs = await overlayDataRepository.diff();
1171
expect(diffs).toMatchInlineSnapshot(`
1272
[
1373
{
@@ -19,11 +79,36 @@ describe('Overlay UT', () => {
1979
`);
2080
});
2181

22-
it('should produce an update diff with previous', async () => {
23-
const overlay1 = new TestOverlay('overlay-1', { key1: 'value1', key2: 'value2' }, []);
24-
const overlay2 = new TestOverlay('overlay-1', { key1: 'value1', key2: 'value2.1', key3: 'value3' }, []);
82+
it('should produce a delete diff', async () => {
83+
const overlay1 = new TestOverlay('overlay-1', {}, []);
84+
85+
const overlayDataRepository = await Container.get(OverlayDataRepository, { args: [true, [], [overlay1]] });
86+
const overlayService = await Container.get(OverlayService);
87+
88+
overlayService.removeOverlay(overlay1);
89+
90+
const diffs = await overlayDataRepository.diff();
91+
expect(diffs).toMatchInlineSnapshot(`
92+
[
93+
{
94+
"action": "delete",
95+
"field": "overlayId",
96+
"value": "overlay-1",
97+
},
98+
]
99+
`);
100+
});
101+
102+
it('should produce an update diff of flat properties', async () => {
103+
const overlay1_0 = new TestOverlay('overlay-1', { key1: 'value1', key2: 'value2' }, []);
104+
105+
const overlayDataRepository = await Container.get(OverlayDataRepository, { args: [true, [], [overlay1_0]] });
106+
const overlayService = await Container.get(OverlayService);
107+
108+
const overlay1_1 = new TestOverlay('overlay-1', { key1: 'value1', key2: 'value2.1', key3: 'value3' }, []);
109+
overlayService.addOverlay(overlay1_1);
25110

26-
const diffs = await overlay2.diff(overlay1);
111+
const diffs = await overlayDataRepository.diff();
27112
expect(diffs).toMatchInlineSnapshot(`
28113
[
29114
{
@@ -45,63 +130,109 @@ describe('Overlay UT', () => {
45130
]
46131
`);
47132
});
133+
134+
it('should produce an update diff of nested properties', async () => {
135+
const overlay1_0 = new TestOverlay(
136+
'overlay-1',
137+
{ key1: { 'key1.1': 'value1.1' }, key2: { 'key2.1': 'value2.1' } },
138+
[],
139+
);
140+
141+
const overlayDataRepository = await Container.get(OverlayDataRepository, { args: [true, [], [overlay1_0]] });
142+
const overlayService = await Container.get(OverlayService);
143+
144+
const overlay1_1 = new TestOverlay(
145+
'overlay-1',
146+
{ key1: { 'key1.1': 'value1.3', 'key1.2': 'value1.2' }, key2: { 'key2.1': 'value2.1' } },
147+
[],
148+
);
149+
overlayService.addOverlay(overlay1_1);
150+
151+
const diffs = await overlayDataRepository.diff();
152+
expect(diffs).toMatchInlineSnapshot(`
153+
[
154+
{
155+
"action": "update",
156+
"field": "properties",
157+
"value": {
158+
"key": "key1",
159+
"value": {
160+
"key1.1": "value1.3",
161+
"key1.2": "value1.2",
162+
},
163+
},
164+
},
165+
]
166+
`);
167+
});
168+
169+
it('should produce an update diff of array properties', async () => {
170+
const overlay1_0 = new TestOverlay('overlay-1', { key1: ['value1.1', 'value1.2'] }, []);
171+
172+
const overlayDataRepository = await Container.get(OverlayDataRepository, { args: [true, [], [overlay1_0]] });
173+
const overlayService = await Container.get(OverlayService);
174+
175+
const overlay1_1 = new TestOverlay('overlay-1', { key1: ['value1.3', 'value1.4'] }, []);
176+
overlayService.addOverlay(overlay1_1);
177+
178+
const diffs = await overlayDataRepository.diff();
179+
expect(diffs).toMatchInlineSnapshot(`
180+
[
181+
{
182+
"action": "update",
183+
"field": "properties",
184+
"value": {
185+
"key": "key1",
186+
"value": [
187+
"value1.3",
188+
"value1.4",
189+
],
190+
},
191+
},
192+
]
193+
`);
194+
});
48195
});
49196

50197
describe('removeAnchor()', () => {
51-
it('should remove one anchor parent when multiple anchors have same parent', () => {
198+
it('should remove dependency between overlay and anchor parents', () => {
199+
const app1 = new App('test1');
200+
const anchor1 = new TestAnchor('anchor-1', app1);
201+
app1['anchors'].push(anchor1);
202+
203+
const app2 = new App('test2');
204+
const anchor2 = new TestAnchor('anchor-2', app2);
205+
app2['anchors'].push(anchor2);
206+
207+
const overlay1 = new TestOverlay('overlay-1', {}, [anchor1, anchor2]);
208+
209+
expect(overlay1['dependencies'].find((d) => d.to.getContext() === app1.getContext())).toBeTruthy();
210+
expect(overlay1['dependencies'].find((d) => d.to.getContext() === app2.getContext())).toBeTruthy();
211+
212+
overlay1.removeAnchor(anchor1);
213+
214+
expect(overlay1['dependencies'].find((d) => d.to.getContext() === app1.getContext())).toBeFalsy();
215+
expect(overlay1['dependencies'].find((d) => d.to.getContext() === app2.getContext())).toBeTruthy();
216+
});
217+
218+
it('should only remove one dependency with parent when multiple anchors have same parent', () => {
52219
const app = new App('test');
53220
const anchor1 = new TestAnchor('anchor-1', app);
221+
app['anchors'].push(anchor1);
54222
const anchor2 = new TestAnchor('anchor-2', app);
223+
app['anchors'].push(anchor2);
55224

56225
const overlay1 = new TestOverlay('overlay-1', {}, [anchor1, anchor2]);
57-
expect(app['dependencies']).toMatchInlineSnapshot(`
58-
[
59-
{
60-
"from": "app=test",
61-
"relationship": undefined,
62-
"to": "test-overlay=overlay-1",
63-
},
64-
{
65-
"from": "app=test",
66-
"relationship": undefined,
67-
"to": "test-overlay=overlay-1",
68-
},
69-
]
70-
`);
71-
expect(overlay1['dependencies']).toMatchInlineSnapshot(`
72-
[
73-
{
74-
"from": "test-overlay=overlay-1",
75-
"relationship": undefined,
76-
"to": "app=test",
77-
},
78-
{
79-
"from": "test-overlay=overlay-1",
80-
"relationship": undefined,
81-
"to": "app=test",
82-
},
83-
]
84-
`);
226+
expect(overlay1.getAnchors().length).toBe(2);
227+
228+
expect(app['dependencies'].filter((d) => d.to.getContext() === overlay1.getContext()).length).toBe(2);
229+
expect(overlay1['dependencies'].filter((d) => d.to.getContext() === app.getContext()).length).toBe(2);
85230

86231
overlay1.removeAnchor(anchor1);
87-
expect(app['dependencies']).toMatchInlineSnapshot(`
88-
[
89-
{
90-
"from": "app=test",
91-
"relationship": undefined,
92-
"to": "test-overlay=overlay-1",
93-
},
94-
]
95-
`);
96-
expect(overlay1['dependencies']).toMatchInlineSnapshot(`
97-
[
98-
{
99-
"from": "test-overlay=overlay-1",
100-
"relationship": undefined,
101-
"to": "app=test",
102-
},
103-
]
104-
`);
232+
expect(overlay1.getAnchors().length).toBe(1);
233+
234+
expect(app['dependencies'].filter((d) => d.to.getContext() === overlay1.getContext()).length).toBe(1);
235+
expect(overlay1['dependencies'].filter((d) => d.to.getContext() === app.getContext()).length).toBe(1);
105236
});
106237
});
107238

packages/octo/src/services/transaction/transaction.service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ export class TransactionService {
228228
},
229229
): AsyncGenerator<DiffMetadata[][] | UnknownResource[], DiffMetadata[][]> {
230230
// Diff overlays and add to existing diffs.
231-
diffs.push(...this.overlayDataRepository.diff());
231+
diffs.push(...(await this.overlayDataRepository.diff()));
232232

233233
// Set apply order on model diffs.
234234
const modelDiffs = diffs.map((d) => {

0 commit comments

Comments
 (0)