@quadnix/octo 0.0.2 → 0.0.4
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/package.json +6 -1
- package/.eslintrc.cjs +0 -26
- package/dist/tsconfig.build.tsbuildinfo +0 -1
- package/src/app.type.ts +0 -56
- package/src/decorators/action.decorator.spec.ts +0 -43
- package/src/decorators/action.decorator.ts +0 -24
- package/src/decorators/anchor.decorator.ts +0 -10
- package/src/decorators/container.spec.ts +0 -104
- package/src/decorators/container.ts +0 -133
- package/src/decorators/factory.decorator.ts +0 -13
- package/src/decorators/model.decorator.ts +0 -10
- package/src/decorators/module.decorator.ts +0 -13
- package/src/decorators/overlay.decorator.ts +0 -10
- package/src/decorators/resource.decorator.ts +0 -10
- package/src/decorators/test-container.spec.ts +0 -50
- package/src/decorators/test-container.ts +0 -56
- package/src/functions/dependency/dependency.model.spec.ts +0 -43
- package/src/functions/dependency/dependency.model.ts +0 -178
- package/src/functions/diff/diff-metadata.model.ts +0 -51
- package/src/functions/diff/diff.model.ts +0 -33
- package/src/functions/diff/diff.utility.ts +0 -163
- package/src/functions/module/module.abstract.ts +0 -59
- package/src/functions/module/module.interface.ts +0 -5
- package/src/index.ts +0 -62
- package/src/models/action.interface.ts +0 -35
- package/src/models/app/app.interface.ts +0 -5
- package/src/models/app/app.model.ts +0 -111
- package/src/models/deployment/deployment.interface.ts +0 -5
- package/src/models/deployment/deployment.model.ts +0 -35
- package/src/models/environment/environment.interface.ts +0 -6
- package/src/models/environment/environment.model.spec.ts +0 -125
- package/src/models/environment/environment.model.ts +0 -55
- package/src/models/execution/execution.interface.ts +0 -8
- package/src/models/execution/execution.model.spec.ts +0 -62
- package/src/models/execution/execution.model.ts +0 -89
- package/src/models/image/image.interface.ts +0 -8
- package/src/models/image/image.model.ts +0 -62
- package/src/models/model.abstract.ts +0 -324
- package/src/models/model.interface.ts +0 -42
- package/src/models/pipeline/pipeline.interface.ts +0 -6
- package/src/models/pipeline/pipeline.model.ts +0 -47
- package/src/models/region/region.interface.ts +0 -5
- package/src/models/region/region.model.spec.ts +0 -162
- package/src/models/region/region.model.ts +0 -48
- package/src/models/server/server.interface.ts +0 -7
- package/src/models/server/server.model.ts +0 -56
- package/src/models/service/service.interface.ts +0 -5
- package/src/models/service/service.model.ts +0 -25
- package/src/models/support/support.interface.ts +0 -6
- package/src/models/support/support.model.spec.ts +0 -78
- package/src/models/support/support.model.ts +0 -52
- package/src/overlays/anchor.abstract.ts +0 -41
- package/src/overlays/anchor.interface.ts +0 -7
- package/src/overlays/anchor.spec.ts +0 -41
- package/src/overlays/overlay-data.repository.ts +0 -76
- package/src/overlays/overlay.abstract.ts +0 -64
- package/src/overlays/overlay.interface.ts +0 -9
- package/src/overlays/overlay.service.ts +0 -38
- package/src/overlays/overlay.spec.ts +0 -86
- package/src/resources/resource-action.interface.ts +0 -9
- package/src/resources/resource-data.repository.spec.ts +0 -133
- package/src/resources/resource-data.repository.ts +0 -92
- package/src/resources/resource.abstract.ts +0 -108
- package/src/resources/resource.interface.ts +0 -7
- package/src/resources/resource.spec.ts +0 -60
- package/src/resources/shared-resource.abstract.ts +0 -53
- package/src/resources/shared-resource.spec.ts +0 -133
- package/src/services/serialization/model/__snapshots__/model-serialization.service.spec.ts.snap +0 -656
- package/src/services/serialization/model/model-serialization.service.spec.ts +0 -195
- package/src/services/serialization/model/model-serialization.service.ts +0 -172
- package/src/services/serialization/resource/__snapshots__/resource-serialization.service.spec.ts.snap +0 -284
- package/src/services/serialization/resource/resource-serialization.service.spec.ts +0 -311
- package/src/services/serialization/resource/resource-serialization.service.ts +0 -166
- package/src/services/state-management/local.state-provider.spec.ts +0 -42
- package/src/services/state-management/local.state-provider.ts +0 -23
- package/src/services/state-management/state-management.service.ts +0 -43
- package/src/services/state-management/state-provider.interface.ts +0 -5
- package/src/services/transaction/__snapshots__/transaction.service.spec.ts.snap +0 -284
- package/src/services/transaction/transaction.service.spec.ts +0 -823
- package/src/services/transaction/transaction.service.ts +0 -386
- package/test/app.e2e-spec.ts +0 -104
- package/test/helpers/test-classes.ts +0 -31
- package/test/models/__snapshots__/model.e2e-spec.ts.snap +0 -451
- package/test/models/model.e2e-spec.ts +0 -366
- package/tsconfig.build.json +0 -4
- package/tsconfig.json +0 -9
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
import { jest } from '@jest/globals';
|
|
2
|
-
import { Diff } from '../functions/diff/diff.model.js';
|
|
3
|
-
import { ResourceDataRepository } from './resource-data.repository.js';
|
|
4
|
-
import { AResource } from './resource.abstract.js';
|
|
5
|
-
import { ASharedResource } from './shared-resource.abstract.js';
|
|
6
|
-
|
|
7
|
-
class TestResource extends AResource<TestResource> {
|
|
8
|
-
readonly MODEL_NAME: string = 'test-resource';
|
|
9
|
-
|
|
10
|
-
constructor(resourceId: string) {
|
|
11
|
-
super(resourceId, {}, []);
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
class TestResourceWithDiffOverride extends AResource<TestResource> {
|
|
16
|
-
readonly MODEL_NAME: string = 'test-resource';
|
|
17
|
-
|
|
18
|
-
constructor(resourceId: string) {
|
|
19
|
-
super(resourceId, {}, []);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
override async diff(): Promise<Diff[]> {
|
|
23
|
-
return [];
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
class SharedTestResource extends ASharedResource<TestResource> {
|
|
28
|
-
readonly MODEL_NAME: string = 'test-resource';
|
|
29
|
-
|
|
30
|
-
constructor(resourceId: string, properties: { [key: string]: unknown }, parents: [TestResource?]) {
|
|
31
|
-
super(resourceId, properties, parents as AResource<TestResource>[]);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
describe('ResourceDataRepository UT', () => {
|
|
36
|
-
describe('diff()', () => {
|
|
37
|
-
it('should compare resources using resource diff()', async () => {
|
|
38
|
-
const oldResource = new TestResourceWithDiffOverride('resource-1');
|
|
39
|
-
const newResource = new TestResourceWithDiffOverride('resource-1');
|
|
40
|
-
|
|
41
|
-
const resourceDataRepository = new ResourceDataRepository([], [oldResource]);
|
|
42
|
-
resourceDataRepository.add(newResource);
|
|
43
|
-
|
|
44
|
-
const diffOverrideSpy = jest.spyOn(newResource, 'diff');
|
|
45
|
-
|
|
46
|
-
const diffs = await resourceDataRepository.diff();
|
|
47
|
-
|
|
48
|
-
expect(diffOverrideSpy).toHaveBeenCalledTimes(1);
|
|
49
|
-
expect(diffs).toMatchInlineSnapshot(`[]`);
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
it('should compare distinct resources', async () => {
|
|
53
|
-
const oldResource = new TestResource('resource-1');
|
|
54
|
-
const newResource = new TestResourceWithDiffOverride('resource-1');
|
|
55
|
-
|
|
56
|
-
const resourceDataRepository = new ResourceDataRepository([], [oldResource]);
|
|
57
|
-
resourceDataRepository.add(newResource);
|
|
58
|
-
|
|
59
|
-
const diffs = await resourceDataRepository.diff();
|
|
60
|
-
|
|
61
|
-
expect(diffs).toMatchInlineSnapshot(`[]`);
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
it('should compare same resources', async () => {
|
|
65
|
-
const oldResource = new TestResource('resource-1');
|
|
66
|
-
const newResource = new TestResource('resource-1');
|
|
67
|
-
|
|
68
|
-
const resourceDataRepository = new ResourceDataRepository([], [oldResource]);
|
|
69
|
-
resourceDataRepository.add(newResource);
|
|
70
|
-
|
|
71
|
-
const diffs = await resourceDataRepository.diff();
|
|
72
|
-
|
|
73
|
-
expect(diffs).toMatchInlineSnapshot(`[]`);
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
it('should compare same resources with delete marker on latest', async () => {
|
|
77
|
-
const oldResource = new TestResource('resource-1');
|
|
78
|
-
const newResource = new TestResource('resource-1');
|
|
79
|
-
|
|
80
|
-
const resourceDataRepository = new ResourceDataRepository([], [oldResource]);
|
|
81
|
-
resourceDataRepository.add(newResource);
|
|
82
|
-
newResource.markDeleted();
|
|
83
|
-
|
|
84
|
-
const diffs = await resourceDataRepository.diff();
|
|
85
|
-
|
|
86
|
-
expect(diffs).toMatchInlineSnapshot(`
|
|
87
|
-
[
|
|
88
|
-
{
|
|
89
|
-
"action": "delete",
|
|
90
|
-
"field": "resourceId",
|
|
91
|
-
"value": "resource-1",
|
|
92
|
-
},
|
|
93
|
-
]
|
|
94
|
-
`);
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
it('should add resource if not found in old', async () => {
|
|
98
|
-
const newResource = new TestResource('resource-1');
|
|
99
|
-
|
|
100
|
-
const resourceDataRepository = new ResourceDataRepository([], []);
|
|
101
|
-
resourceDataRepository.add(newResource);
|
|
102
|
-
|
|
103
|
-
const diffs = await resourceDataRepository.diff();
|
|
104
|
-
|
|
105
|
-
expect(diffs).toMatchInlineSnapshot(`
|
|
106
|
-
[
|
|
107
|
-
{
|
|
108
|
-
"action": "add",
|
|
109
|
-
"field": "resourceId",
|
|
110
|
-
"value": "resource-1",
|
|
111
|
-
},
|
|
112
|
-
]
|
|
113
|
-
`);
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
it('should skip adding shared-resource if it already exists', async () => {
|
|
117
|
-
const resource1 = new TestResource('resource-1');
|
|
118
|
-
const resource2 = new TestResource('resource-2');
|
|
119
|
-
const sharedResource1 = new SharedTestResource('shared-test-resource', {}, [resource1]);
|
|
120
|
-
const sharedResource2 = new SharedTestResource('shared-test-resource', {}, [resource2]);
|
|
121
|
-
|
|
122
|
-
const resourceDataRepository = new ResourceDataRepository(
|
|
123
|
-
[resource1, resource2, sharedResource1],
|
|
124
|
-
[resource1, resource2, sharedResource1],
|
|
125
|
-
);
|
|
126
|
-
resourceDataRepository.add(sharedResource2);
|
|
127
|
-
|
|
128
|
-
const diffs = await resourceDataRepository.diff();
|
|
129
|
-
|
|
130
|
-
expect(diffs).toMatchInlineSnapshot(`[]`);
|
|
131
|
-
});
|
|
132
|
-
});
|
|
133
|
-
});
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import { ActionOutputs, ModelType, UnknownResource } from '../app.type.js';
|
|
2
|
-
import { Factory } from '../decorators/factory.decorator.js';
|
|
3
|
-
import { Diff, DiffAction } from '../functions/diff/diff.model.js';
|
|
4
|
-
import { IResource } from './resource.interface.js';
|
|
5
|
-
|
|
6
|
-
export class ResourceDataRepository {
|
|
7
|
-
constructor(
|
|
8
|
-
private readonly newResources: UnknownResource[] = [],
|
|
9
|
-
private readonly oldResources: UnknownResource[] = [],
|
|
10
|
-
) {
|
|
11
|
-
Object.freeze(this.oldResources);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
private async _diffResources(newResources: ActionOutputs, oldResources: ActionOutputs): Promise<Diff[]> {
|
|
15
|
-
const diffs: Diff[] = [];
|
|
16
|
-
|
|
17
|
-
for (const oldResourceId in oldResources) {
|
|
18
|
-
if (!newResources[oldResourceId]) {
|
|
19
|
-
diffs.push(new Diff(oldResources[oldResourceId], DiffAction.DELETE, 'resourceId', oldResourceId));
|
|
20
|
-
} else {
|
|
21
|
-
const rDiff = await newResources[oldResourceId].diff(oldResources[oldResourceId]);
|
|
22
|
-
diffs.push(...rDiff);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
for (const newResourceId in newResources) {
|
|
27
|
-
if (!oldResources[newResourceId]) {
|
|
28
|
-
const newResource = newResources[newResourceId];
|
|
29
|
-
|
|
30
|
-
if (newResource.MODEL_TYPE === 'shared-resource' || newResource.getSharedResource() !== undefined) {
|
|
31
|
-
const rDiff = await newResource.diff();
|
|
32
|
-
diffs.push(...rDiff);
|
|
33
|
-
} else {
|
|
34
|
-
diffs.push(new Diff(newResource, DiffAction.ADD, 'resourceId', newResource.resourceId));
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
return diffs;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
add(resource: UnknownResource): void {
|
|
43
|
-
if (resource.MODEL_TYPE !== ModelType.RESOURCE && resource.MODEL_TYPE !== ModelType.SHARED_RESOURCE) {
|
|
44
|
-
throw new Error('Adding non-resource model!');
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// Insert or replace resources.
|
|
48
|
-
const rIndex = this.newResources.findIndex((r) => r.resourceId === resource.resourceId);
|
|
49
|
-
if (rIndex === -1) {
|
|
50
|
-
this.newResources.push(resource);
|
|
51
|
-
} else {
|
|
52
|
-
this.newResources[rIndex] = resource;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
async diff(): Promise<Diff[]> {
|
|
57
|
-
const newResources: ActionOutputs = this.newResources.reduce(
|
|
58
|
-
(accumulator, current) => ({ ...accumulator, [current.resourceId]: current }),
|
|
59
|
-
{},
|
|
60
|
-
);
|
|
61
|
-
const oldResources: ActionOutputs = this.oldResources.reduce(
|
|
62
|
-
(accumulator, current) => ({ ...accumulator, [current.resourceId]: current }),
|
|
63
|
-
{},
|
|
64
|
-
);
|
|
65
|
-
|
|
66
|
-
return this._diffResources(newResources, oldResources);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
getById(resourceId: IResource['resourceId']): UnknownResource | undefined {
|
|
70
|
-
return this.newResources.find((r) => r.resourceId === resourceId);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
getByProperties(filters: { key: string; value: any }[] = []): UnknownResource[] {
|
|
74
|
-
return this.newResources.filter((r) => filters.every((c) => r.properties[c.key] === c.value));
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
@Factory<ResourceDataRepository>(ResourceDataRepository)
|
|
79
|
-
export class ResourceDataRepositoryFactory {
|
|
80
|
-
private static instance: ResourceDataRepository;
|
|
81
|
-
|
|
82
|
-
static async create(
|
|
83
|
-
forceNew: boolean,
|
|
84
|
-
newResources: UnknownResource[],
|
|
85
|
-
oldResources: UnknownResource[],
|
|
86
|
-
): Promise<ResourceDataRepository> {
|
|
87
|
-
if (forceNew || !this.instance) {
|
|
88
|
-
this.instance = new ResourceDataRepository(newResources, oldResources);
|
|
89
|
-
}
|
|
90
|
-
return this.instance;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
import { ModelType, UnknownResource } from '../app.type.js';
|
|
2
|
-
import { Diff, DiffAction } from '../functions/diff/diff.model.js';
|
|
3
|
-
import { DiffUtility } from '../functions/diff/diff.utility.js';
|
|
4
|
-
import { AModel } from '../models/model.abstract.js';
|
|
5
|
-
import { IResource } from './resource.interface.js';
|
|
6
|
-
import { ASharedResource } from './shared-resource.abstract.js';
|
|
7
|
-
|
|
8
|
-
export abstract class AResource<T> extends AModel<IResource, T> {
|
|
9
|
-
abstract override readonly MODEL_NAME: string;
|
|
10
|
-
override readonly MODEL_TYPE: ModelType = ModelType.RESOURCE;
|
|
11
|
-
|
|
12
|
-
/*
|
|
13
|
-
* While model graph are well connected, resource graph can contain nodes that are completely disassociated.
|
|
14
|
-
* For this reason, we traverse the resource graph using an array. Thus, even after calling remove()
|
|
15
|
-
* on a resource node, it will be traversed, and there needs to be a marker to identify that it has been deleted.
|
|
16
|
-
* */
|
|
17
|
-
private _deleteMarker = false;
|
|
18
|
-
|
|
19
|
-
readonly properties: IResource['properties'] = {};
|
|
20
|
-
|
|
21
|
-
readonly resourceId: IResource['resourceId'];
|
|
22
|
-
|
|
23
|
-
readonly response: IResource['response'] = {};
|
|
24
|
-
|
|
25
|
-
protected constructor(
|
|
26
|
-
resourceId: IResource['resourceId'],
|
|
27
|
-
properties: IResource['properties'],
|
|
28
|
-
parents: UnknownResource[],
|
|
29
|
-
) {
|
|
30
|
-
super();
|
|
31
|
-
|
|
32
|
-
this.resourceId = resourceId;
|
|
33
|
-
|
|
34
|
-
for (const key in properties) {
|
|
35
|
-
this.properties[key] = properties[key];
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
for (const parent of parents) {
|
|
39
|
-
parent.addChild('resourceId', this, 'resourceId');
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
async diff(previous?: T): Promise<Diff[]> {
|
|
44
|
-
const diffs: Diff[] = [];
|
|
45
|
-
|
|
46
|
-
if (this.isMarkedDeleted()) {
|
|
47
|
-
diffs.push(
|
|
48
|
-
new Diff((previous || this) as AModel<IResource, T>, DiffAction.DELETE, 'resourceId', this.resourceId),
|
|
49
|
-
);
|
|
50
|
-
return diffs;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
if (previous) {
|
|
54
|
-
if (!DiffUtility.isObjectDeepEquals(this.properties, (previous as unknown as AResource<T>).properties)) {
|
|
55
|
-
diffs.push(new Diff(this, DiffAction.UPDATE, 'resourceId', this.resourceId));
|
|
56
|
-
}
|
|
57
|
-
} else {
|
|
58
|
-
diffs.push(new Diff(this, DiffAction.ADD, 'resourceId', this.resourceId));
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
return diffs;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
getContext(): string {
|
|
65
|
-
return `${this.MODEL_NAME}=${this.resourceId}`;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
getSharedResource(): ASharedResource<T> | undefined {
|
|
69
|
-
const sameModelDependencies = this.getChildren(this.MODEL_NAME)[this.MODEL_NAME];
|
|
70
|
-
const sharedResourceDependency = sameModelDependencies?.find((d) => d.to.MODEL_TYPE === ModelType.SHARED_RESOURCE);
|
|
71
|
-
return sharedResourceDependency?.to as ASharedResource<T>;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
isMarkedDeleted(): boolean {
|
|
75
|
-
return this._deleteMarker;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
markDeleted(): void {
|
|
79
|
-
super.remove();
|
|
80
|
-
this._deleteMarker = true;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
override remove(): void {
|
|
84
|
-
throw new Error('Cannot use remove() on resources! Use a delete marker instead.');
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
synth(): IResource {
|
|
88
|
-
return {
|
|
89
|
-
properties: { ...this.properties },
|
|
90
|
-
resourceId: this.resourceId,
|
|
91
|
-
response: { ...this.response },
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
static override async unSynth(
|
|
96
|
-
deserializationClass: any,
|
|
97
|
-
resource: IResource,
|
|
98
|
-
parentResourceIds: string[],
|
|
99
|
-
deReferenceResource: (resourceId: string) => Promise<UnknownResource>,
|
|
100
|
-
): Promise<UnknownResource> {
|
|
101
|
-
const parents = await Promise.all(parentResourceIds.map((p) => deReferenceResource(p)));
|
|
102
|
-
const deReferencedResource = new deserializationClass(resource.resourceId, resource.properties, parents);
|
|
103
|
-
for (const key in resource.response) {
|
|
104
|
-
deReferencedResource.response[key] = resource.response[key];
|
|
105
|
-
}
|
|
106
|
-
return deReferencedResource;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import { AResource } from './resource.abstract.js';
|
|
2
|
-
|
|
3
|
-
class TestResource extends AResource<TestResource> {
|
|
4
|
-
readonly MODEL_NAME: string = 'test-resource';
|
|
5
|
-
|
|
6
|
-
constructor(resourceId: string) {
|
|
7
|
-
super(resourceId, {}, []);
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
describe('Resource UT', () => {
|
|
12
|
-
it('should be able to associate with another resource as its child', () => {
|
|
13
|
-
const resource1 = new TestResource('resource-1');
|
|
14
|
-
const resource2 = new TestResource('resource-2');
|
|
15
|
-
|
|
16
|
-
resource2.addChild('resourceId', resource1, 'resourceId');
|
|
17
|
-
|
|
18
|
-
expect((resource2.getChildren()['test-resource'][0].to as AResource<TestResource>).resourceId).toBe('resource-1');
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
it('should be able to associate with another resource multiple times', () => {
|
|
22
|
-
const resource1 = new TestResource('resource-1');
|
|
23
|
-
const resource2 = new TestResource('resource-2');
|
|
24
|
-
|
|
25
|
-
resource2.addChild('resourceId', resource1, 'resourceId');
|
|
26
|
-
resource2.addChild('resourceId', resource1, 'resourceId');
|
|
27
|
-
expect(resource2.getChildren()['test-resource'].length).toBe(1);
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
describe('markDeleted()', () => {
|
|
31
|
-
it('should not be able to mark a resource deleted with dependencies', () => {
|
|
32
|
-
const resource1 = new TestResource('resource-1');
|
|
33
|
-
resource1.properties['key1'] = 'value1';
|
|
34
|
-
resource1.response['response1'] = 'value1';
|
|
35
|
-
const resource2 = new TestResource('resource-2');
|
|
36
|
-
resource2.properties['key2'] = 'value2';
|
|
37
|
-
resource2.response['response2'] = 'value2';
|
|
38
|
-
resource1.addChild('resourceId', resource2, 'resourceId');
|
|
39
|
-
|
|
40
|
-
expect(() => {
|
|
41
|
-
resource1.markDeleted();
|
|
42
|
-
}).toThrowErrorMatchingInlineSnapshot(`"Cannot remove model until dependent models exist!"`);
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it('should be able to mark leaf resources deleted', () => {
|
|
46
|
-
const resource1 = new TestResource('resource-1');
|
|
47
|
-
resource1.properties['key1'] = 'value1';
|
|
48
|
-
resource1.response['response1'] = 'value1';
|
|
49
|
-
const resource2 = new TestResource('resource-2');
|
|
50
|
-
resource2.properties['key2'] = 'value2';
|
|
51
|
-
resource2.response['response2'] = 'value2';
|
|
52
|
-
resource1.addChild('resourceId', resource2, 'resourceId');
|
|
53
|
-
|
|
54
|
-
resource2.markDeleted();
|
|
55
|
-
|
|
56
|
-
expect(resource1.getChildren()).toMatchInlineSnapshot(`{}`);
|
|
57
|
-
expect(resource2.isMarkedDeleted()).toBe(true);
|
|
58
|
-
});
|
|
59
|
-
});
|
|
60
|
-
});
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import { ModelType } from '../app.type.js';
|
|
2
|
-
import { Diff } from '../functions/diff/diff.model.js';
|
|
3
|
-
import { AResource } from './resource.abstract.js';
|
|
4
|
-
|
|
5
|
-
export abstract class ASharedResource<T> extends AResource<T> {
|
|
6
|
-
override readonly MODEL_TYPE: ModelType = ModelType.SHARED_RESOURCE;
|
|
7
|
-
|
|
8
|
-
async diff(): Promise<Diff[]> {
|
|
9
|
-
return [];
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
findParentsByProperty(filters: { key: keyof AResource<T>['properties']; value: any }[]): AResource<T>[] {
|
|
13
|
-
const parents: AResource<T>[] = [];
|
|
14
|
-
const dependencies = Object.values(this.getParents()).flat();
|
|
15
|
-
for (const d of dependencies) {
|
|
16
|
-
const resource = d.to as AResource<T>;
|
|
17
|
-
if (filters.every((c) => resource.properties[c.key] === c.value)) {
|
|
18
|
-
parents.push(resource);
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
return parents;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
override getSharedResource(): ASharedResource<T> | undefined {
|
|
25
|
-
return undefined;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
merge(previousSharedResource: ASharedResource<T>): ASharedResource<T> {
|
|
29
|
-
const currentDependencies = Object.values(this.getParents()).flat();
|
|
30
|
-
const previousDependencies = Object.values(previousSharedResource.getParents()).flat();
|
|
31
|
-
|
|
32
|
-
for (const key in previousSharedResource.properties) {
|
|
33
|
-
if (previousSharedResource.properties.hasOwnProperty(key) && !(key in this.properties)) {
|
|
34
|
-
this.properties[key] = previousSharedResource.properties[key];
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
for (const key in previousSharedResource.response) {
|
|
39
|
-
if (previousSharedResource.response.hasOwnProperty(key) && !(key in this.response)) {
|
|
40
|
-
this.response[key] = previousSharedResource.response[key];
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const previousParentsNotInCurrentSharedResource = previousDependencies
|
|
45
|
-
.filter((pd) => !currentDependencies.find((cd) => cd.isEqual(pd)))
|
|
46
|
-
.map((pd) => pd.to);
|
|
47
|
-
for (const parent of previousParentsNotInCurrentSharedResource) {
|
|
48
|
-
parent.addChild('resourceId', this, 'resourceId');
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
return this;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
import { Container } from '../decorators/container.js';
|
|
2
|
-
import { ResourceSerializationService } from '../services/serialization/resource/resource-serialization.service.js';
|
|
3
|
-
import { ResourceDataRepository } from './resource-data.repository.js';
|
|
4
|
-
import { AResource } from './resource.abstract.js';
|
|
5
|
-
import { ASharedResource } from './shared-resource.abstract.js';
|
|
6
|
-
|
|
7
|
-
class ParentResource extends AResource<ParentResource> {
|
|
8
|
-
readonly MODEL_NAME: string = 'parent-resource';
|
|
9
|
-
|
|
10
|
-
constructor(resourceId: string) {
|
|
11
|
-
super(resourceId, {}, []);
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
class TestResource extends AResource<TestResource> {
|
|
16
|
-
readonly MODEL_NAME: string = 'test-resource';
|
|
17
|
-
|
|
18
|
-
constructor(resourceId: string, properties: { [key: string]: string }, parents: [ParentResource]) {
|
|
19
|
-
super(resourceId, properties, parents);
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
class SharedTestResource extends ASharedResource<TestResource> {
|
|
24
|
-
readonly MODEL_NAME: string = 'shared-test-resource';
|
|
25
|
-
|
|
26
|
-
constructor(resourceId: string, properties: object, parents: [TestResource?, TestResource?]) {
|
|
27
|
-
super(resourceId, {}, parents as AResource<TestResource>[]);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
describe('SharedResource UT', () => {
|
|
32
|
-
let resourceSerializationService: ResourceSerializationService;
|
|
33
|
-
|
|
34
|
-
beforeAll(async () => {
|
|
35
|
-
resourceSerializationService = await Container.get(ResourceSerializationService);
|
|
36
|
-
resourceSerializationService.registerClass(ParentResource.name, ParentResource);
|
|
37
|
-
resourceSerializationService.registerClass(TestResource.name, TestResource);
|
|
38
|
-
resourceSerializationService.registerClass(SharedTestResource.name, SharedTestResource);
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
afterAll(() => {
|
|
42
|
-
Container.reset();
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it('should serialize and deserialize empty shared-resources', async () => {
|
|
46
|
-
await Container.get(ResourceDataRepository, { args: [true, [], []] });
|
|
47
|
-
|
|
48
|
-
const serializedOutput = await resourceSerializationService.serialize();
|
|
49
|
-
expect(serializedOutput).toMatchInlineSnapshot(`
|
|
50
|
-
{
|
|
51
|
-
"dependencies": [],
|
|
52
|
-
"resources": {},
|
|
53
|
-
"sharedResources": {},
|
|
54
|
-
}
|
|
55
|
-
`);
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
it('should serialize and deserialize shared-resources with parent', async () => {
|
|
59
|
-
const parentResource = new ParentResource('parent-1');
|
|
60
|
-
const testResource = new TestResource('resource-1', { property1: 'property-value-1' }, [parentResource]);
|
|
61
|
-
testResource.response['response1'] = 'response-value-1';
|
|
62
|
-
const sharedTestResource = new SharedTestResource('shared-test-resource', {}, [testResource]);
|
|
63
|
-
|
|
64
|
-
const resources = [parentResource, testResource, sharedTestResource];
|
|
65
|
-
await Container.get(ResourceDataRepository, { args: [true, [...resources], [...resources]] });
|
|
66
|
-
|
|
67
|
-
const serializedOutput = await resourceSerializationService.serialize();
|
|
68
|
-
await resourceSerializationService.deserialize(serializedOutput);
|
|
69
|
-
|
|
70
|
-
const resourceDataRepository = await Container.get(ResourceDataRepository);
|
|
71
|
-
const deserializedResources = resourceDataRepository.getByProperties();
|
|
72
|
-
|
|
73
|
-
// Validate shared resources are same pre/post serialization.
|
|
74
|
-
expect(deserializedResources.sort((a, b) => a.resourceId.localeCompare(b.resourceId))).toEqual(
|
|
75
|
-
resources.sort((a, b) => a.resourceId.localeCompare(b.resourceId)),
|
|
76
|
-
);
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
it('should serialize and deserialize shared-resources with different parents', async () => {
|
|
80
|
-
// "resource-1" is a shared-resource(S1) parented by "parent-1".
|
|
81
|
-
const parentResource1 = new ParentResource('parent-1');
|
|
82
|
-
const testResource1 = new TestResource('resource-1', { property1: 'property-value-1' }, [parentResource1]);
|
|
83
|
-
// "resource-2" is also a shared-resource(S1), but parented by "parent-2".
|
|
84
|
-
const parentResource2 = new ParentResource('parent-2');
|
|
85
|
-
const testResource2 = new TestResource('resource-2', { property2: 'property-value-2' }, [parentResource2]);
|
|
86
|
-
const sharedTestResource = new SharedTestResource('shared-test-resource', {}, [testResource1, testResource2]);
|
|
87
|
-
|
|
88
|
-
const resources = [parentResource1, testResource1, parentResource2, testResource2, sharedTestResource];
|
|
89
|
-
await Container.get(ResourceDataRepository, { args: [true, [...resources], [...resources]] });
|
|
90
|
-
|
|
91
|
-
const serializedOutput = await resourceSerializationService.serialize();
|
|
92
|
-
await resourceSerializationService.deserialize(serializedOutput);
|
|
93
|
-
|
|
94
|
-
const resourceDataRepository = await Container.get(ResourceDataRepository);
|
|
95
|
-
const deserializedResources = resourceDataRepository.getByProperties();
|
|
96
|
-
|
|
97
|
-
// Validate shared resources are same pre/post serialization.
|
|
98
|
-
expect(deserializedResources.sort((a, b) => a.resourceId.localeCompare(b.resourceId))).toEqual(
|
|
99
|
-
resources.sort((a, b) => a.resourceId.localeCompare(b.resourceId)),
|
|
100
|
-
);
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
describe('merge()', () => {
|
|
104
|
-
it('should merge old shared resource with self and return new shared resource', () => {
|
|
105
|
-
const resource1 = new ParentResource('resource-1');
|
|
106
|
-
const resource2 = new ParentResource('resource-2');
|
|
107
|
-
|
|
108
|
-
const sharedResource1 = new SharedTestResource('shared-resource', {}, [resource1]);
|
|
109
|
-
sharedResource1.properties['property-1'] = 'property-value-1';
|
|
110
|
-
sharedResource1.response['response-1'] = 'response-value-1';
|
|
111
|
-
|
|
112
|
-
const sharedResource2 = new SharedTestResource('shared-resource', {}, [resource2]);
|
|
113
|
-
sharedResource2.properties['property-2'] = 'property-value-2';
|
|
114
|
-
sharedResource2.response['response-2'] = 'response-value-2';
|
|
115
|
-
|
|
116
|
-
const mergedSharedResource = sharedResource2.merge(sharedResource1);
|
|
117
|
-
|
|
118
|
-
expect(mergedSharedResource['dependencies'].length).toBe(2);
|
|
119
|
-
expect(mergedSharedResource.properties).toMatchInlineSnapshot(`
|
|
120
|
-
{
|
|
121
|
-
"property-1": "property-value-1",
|
|
122
|
-
"property-2": "property-value-2",
|
|
123
|
-
}
|
|
124
|
-
`);
|
|
125
|
-
expect(mergedSharedResource.response).toMatchInlineSnapshot(`
|
|
126
|
-
{
|
|
127
|
-
"response-1": "response-value-1",
|
|
128
|
-
"response-2": "response-value-2",
|
|
129
|
-
}
|
|
130
|
-
`);
|
|
131
|
-
});
|
|
132
|
-
});
|
|
133
|
-
});
|