@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.
Files changed (86) hide show
  1. package/package.json +6 -1
  2. package/.eslintrc.cjs +0 -26
  3. package/dist/tsconfig.build.tsbuildinfo +0 -1
  4. package/src/app.type.ts +0 -56
  5. package/src/decorators/action.decorator.spec.ts +0 -43
  6. package/src/decorators/action.decorator.ts +0 -24
  7. package/src/decorators/anchor.decorator.ts +0 -10
  8. package/src/decorators/container.spec.ts +0 -104
  9. package/src/decorators/container.ts +0 -133
  10. package/src/decorators/factory.decorator.ts +0 -13
  11. package/src/decorators/model.decorator.ts +0 -10
  12. package/src/decorators/module.decorator.ts +0 -13
  13. package/src/decorators/overlay.decorator.ts +0 -10
  14. package/src/decorators/resource.decorator.ts +0 -10
  15. package/src/decorators/test-container.spec.ts +0 -50
  16. package/src/decorators/test-container.ts +0 -56
  17. package/src/functions/dependency/dependency.model.spec.ts +0 -43
  18. package/src/functions/dependency/dependency.model.ts +0 -178
  19. package/src/functions/diff/diff-metadata.model.ts +0 -51
  20. package/src/functions/diff/diff.model.ts +0 -33
  21. package/src/functions/diff/diff.utility.ts +0 -163
  22. package/src/functions/module/module.abstract.ts +0 -59
  23. package/src/functions/module/module.interface.ts +0 -5
  24. package/src/index.ts +0 -62
  25. package/src/models/action.interface.ts +0 -35
  26. package/src/models/app/app.interface.ts +0 -5
  27. package/src/models/app/app.model.ts +0 -111
  28. package/src/models/deployment/deployment.interface.ts +0 -5
  29. package/src/models/deployment/deployment.model.ts +0 -35
  30. package/src/models/environment/environment.interface.ts +0 -6
  31. package/src/models/environment/environment.model.spec.ts +0 -125
  32. package/src/models/environment/environment.model.ts +0 -55
  33. package/src/models/execution/execution.interface.ts +0 -8
  34. package/src/models/execution/execution.model.spec.ts +0 -62
  35. package/src/models/execution/execution.model.ts +0 -89
  36. package/src/models/image/image.interface.ts +0 -8
  37. package/src/models/image/image.model.ts +0 -62
  38. package/src/models/model.abstract.ts +0 -324
  39. package/src/models/model.interface.ts +0 -42
  40. package/src/models/pipeline/pipeline.interface.ts +0 -6
  41. package/src/models/pipeline/pipeline.model.ts +0 -47
  42. package/src/models/region/region.interface.ts +0 -5
  43. package/src/models/region/region.model.spec.ts +0 -162
  44. package/src/models/region/region.model.ts +0 -48
  45. package/src/models/server/server.interface.ts +0 -7
  46. package/src/models/server/server.model.ts +0 -56
  47. package/src/models/service/service.interface.ts +0 -5
  48. package/src/models/service/service.model.ts +0 -25
  49. package/src/models/support/support.interface.ts +0 -6
  50. package/src/models/support/support.model.spec.ts +0 -78
  51. package/src/models/support/support.model.ts +0 -52
  52. package/src/overlays/anchor.abstract.ts +0 -41
  53. package/src/overlays/anchor.interface.ts +0 -7
  54. package/src/overlays/anchor.spec.ts +0 -41
  55. package/src/overlays/overlay-data.repository.ts +0 -76
  56. package/src/overlays/overlay.abstract.ts +0 -64
  57. package/src/overlays/overlay.interface.ts +0 -9
  58. package/src/overlays/overlay.service.ts +0 -38
  59. package/src/overlays/overlay.spec.ts +0 -86
  60. package/src/resources/resource-action.interface.ts +0 -9
  61. package/src/resources/resource-data.repository.spec.ts +0 -133
  62. package/src/resources/resource-data.repository.ts +0 -92
  63. package/src/resources/resource.abstract.ts +0 -108
  64. package/src/resources/resource.interface.ts +0 -7
  65. package/src/resources/resource.spec.ts +0 -60
  66. package/src/resources/shared-resource.abstract.ts +0 -53
  67. package/src/resources/shared-resource.spec.ts +0 -133
  68. package/src/services/serialization/model/__snapshots__/model-serialization.service.spec.ts.snap +0 -656
  69. package/src/services/serialization/model/model-serialization.service.spec.ts +0 -195
  70. package/src/services/serialization/model/model-serialization.service.ts +0 -172
  71. package/src/services/serialization/resource/__snapshots__/resource-serialization.service.spec.ts.snap +0 -284
  72. package/src/services/serialization/resource/resource-serialization.service.spec.ts +0 -311
  73. package/src/services/serialization/resource/resource-serialization.service.ts +0 -166
  74. package/src/services/state-management/local.state-provider.spec.ts +0 -42
  75. package/src/services/state-management/local.state-provider.ts +0 -23
  76. package/src/services/state-management/state-management.service.ts +0 -43
  77. package/src/services/state-management/state-provider.interface.ts +0 -5
  78. package/src/services/transaction/__snapshots__/transaction.service.spec.ts.snap +0 -284
  79. package/src/services/transaction/transaction.service.spec.ts +0 -823
  80. package/src/services/transaction/transaction.service.ts +0 -386
  81. package/test/app.e2e-spec.ts +0 -104
  82. package/test/helpers/test-classes.ts +0 -31
  83. package/test/models/__snapshots__/model.e2e-spec.ts.snap +0 -451
  84. package/test/models/model.e2e-spec.ts +0 -366
  85. package/tsconfig.build.json +0 -4
  86. package/tsconfig.json +0 -9
@@ -1,10 +0,0 @@
1
- import { ModelSerializationService } from '../services/serialization/model/model-serialization.service.js';
2
- import { Container } from './container.js';
3
-
4
- export function Overlay(): (constructor: any) => void {
5
- return function (constructor: any) {
6
- Container.get(ModelSerializationService).then((modelSerializationService) => {
7
- modelSerializationService.registerClass(constructor.name, constructor);
8
- });
9
- };
10
- }
@@ -1,10 +0,0 @@
1
- import { ResourceSerializationService } from '../services/serialization/resource/resource-serialization.service.js';
2
- import { Container } from './container.js';
3
-
4
- export function Resource(): (constructor: any) => void {
5
- return function (constructor: any) {
6
- Container.get(ResourceSerializationService).then((resourceSerializationService) => {
7
- resourceSerializationService.registerClass(constructor.name, constructor);
8
- });
9
- };
10
- }
@@ -1,50 +0,0 @@
1
- import { jest } from '@jest/globals';
2
- import {
3
- ModelSerializationService,
4
- ModelSerializationServiceFactory,
5
- } from '../services/serialization/model/model-serialization.service.js';
6
- import { ResourceSerializationService } from '../services/serialization/resource/resource-serialization.service.js';
7
- import { Container } from './container.js';
8
- import { TestContainer } from './test-container.js';
9
-
10
- describe('TestContainer UT', () => {
11
- beforeAll(() => {
12
- // Register a new factory with metadata for testing purposes.
13
- Container.registerFactory(ModelSerializationService, ModelSerializationServiceFactory, {
14
- metadata: { test: 'true' },
15
- });
16
-
17
- TestContainer.create(
18
- [
19
- {
20
- type: ModelSerializationService,
21
- value: jest.fn(),
22
- },
23
- {
24
- metadata: { test: 'true' },
25
- type: ModelSerializationService,
26
- value: 'My Mock',
27
- },
28
- ],
29
- { factoryTimeoutInMs: 500 },
30
- );
31
- });
32
-
33
- it('should replace old factory with new mock', async () => {
34
- const modelSerializationService = await Container.get<jest.Mock>(ModelSerializationService as any);
35
- expect(modelSerializationService.getMockName()).toBe('jest.fn()');
36
- });
37
-
38
- it('should replace old factory with metadata with new mock', async () => {
39
- const modelSerializationService = await Container.get<string>(ModelSerializationService as any, {
40
- metadata: { test: 'true' },
41
- });
42
- expect(modelSerializationService).toBe('My Mock');
43
- });
44
-
45
- it('should not replace old factory when no mock given', async () => {
46
- const resourceSerializationService = await Container.get(ResourceSerializationService);
47
- expect(typeof resourceSerializationService['getMockName']).toBe('undefined');
48
- expect(typeof resourceSerializationService.serialize).toBe('function');
49
- });
50
- });
@@ -1,56 +0,0 @@
1
- import { Constructable } from '../app.type.js';
2
- import { DiffUtility } from '../functions/diff/diff.utility.js';
3
- import { Container } from './container.js';
4
-
5
- type Factory<T> = { create: () => Promise<T> };
6
-
7
- type FactoryMock<T> = {
8
- metadata?: { [key: string]: string };
9
- type: Constructable<T> | string;
10
- value: T;
11
- };
12
-
13
- type TestContainerOptions = { factoryTimeoutInMs?: number };
14
-
15
- export class TestContainer {
16
- private static createTestFactory<T>(mock: FactoryMock<T>): Factory<T> {
17
- return class {
18
- static mock: FactoryMock<T> = mock;
19
-
20
- static async create(): Promise<T> {
21
- return this.mock.value;
22
- }
23
- };
24
- }
25
-
26
- static create(mocks: FactoryMock<unknown>[], options: TestContainerOptions): void {
27
- const oldFactories = { ...Container['factories'] };
28
- Container.reset();
29
-
30
- if (options.factoryTimeoutInMs) {
31
- Container.setFactoryTimeout(options.factoryTimeoutInMs);
32
- }
33
-
34
- for (const mock of mocks) {
35
- const mockClassName = typeof mock.type === 'string' ? mock.type : mock.type.name;
36
- const mockMetadata = mock.metadata || {};
37
- const registeredFactories = oldFactories[mockClassName] || [];
38
- const matchingFactoryIndex = registeredFactories.findIndex((f) =>
39
- DiffUtility.isObjectDeepEquals(f.metadata, mockMetadata),
40
- );
41
-
42
- if (matchingFactoryIndex > -1) {
43
- oldFactories[mockClassName][matchingFactoryIndex].factory = this.createTestFactory(mock);
44
- }
45
- }
46
-
47
- for (const name in oldFactories) {
48
- for (const oldFactory of oldFactories[name]) {
49
- Container.registerFactory(name, oldFactory.factory as Factory<unknown>, { metadata: oldFactory.metadata });
50
- if (oldFactory.default) {
51
- Container.setDefault(name, oldFactory.factory as Factory<unknown>);
52
- }
53
- }
54
- }
55
- }
56
- }
@@ -1,43 +0,0 @@
1
- import { App } from '../../models/app/app.model.js';
2
- import { Environment } from '../../models/environment/environment.model.js';
3
- import { Region } from '../../models/region/region.model.js';
4
- import { DiffAction } from '../diff/diff.model.js';
5
- import { Dependency } from './dependency.model.js';
6
-
7
- describe('Dependency UT', () => {
8
- describe('addBehavior()', () => {
9
- it('should throw error when adding behavior on the wrong field (onField)', () => {
10
- expect(() => {
11
- const dependency = new Dependency(new Region('region-1'), new Environment('qa'));
12
- dependency.addBehavior('doesNotExist', DiffAction.ADD, 'environmentName', DiffAction.ADD);
13
- }).toThrowErrorMatchingInlineSnapshot(`"Invalid field name is not a property of given model!"`);
14
- });
15
-
16
- it('should throw error when adding behavior on the wrong field (toField)', () => {
17
- expect(() => {
18
- const dependency = new Dependency(new Region('region-1'), new Environment('qa'));
19
- dependency.addBehavior('regionId', DiffAction.ADD, 'doesNotExist', DiffAction.ADD);
20
- }).toThrowErrorMatchingInlineSnapshot(`"Invalid field name is not a property of given model!"`);
21
- });
22
- });
23
-
24
- describe('toJSON()', () => {
25
- it('should be able to JSON summarize a dependency', () => {
26
- const app = new App('app');
27
- const region = new Region('region-1');
28
- app.addRegion(region);
29
- const environment = new Environment('qa');
30
- region.addEnvironment(environment);
31
-
32
- const dependency = new Dependency(region, environment);
33
-
34
- expect(dependency.toJSON()).toMatchInlineSnapshot(`
35
- {
36
- "from": "region=region-1,app=app",
37
- "relationship": undefined,
38
- "to": "environment=qa,region=region-1,app=app",
39
- }
40
- `);
41
- });
42
- });
43
- });
@@ -1,178 +0,0 @@
1
- import { UnknownModel } from '../../app.type.js';
2
- import { DiffAction } from '../diff/diff.model.js';
3
-
4
- class DependencyBehavior {
5
- forAction: DiffAction;
6
-
7
- onAction: DiffAction;
8
-
9
- onField: string;
10
-
11
- toField: string;
12
-
13
- constructor(onField: string, onAction: DiffAction, toField: string, forAction: DiffAction) {
14
- this.onField = onField;
15
- this.onAction = onAction;
16
- this.toField = toField;
17
- this.forAction = forAction;
18
- }
19
- }
20
-
21
- export enum DependencyRelationship {
22
- CHILD = 'child',
23
- PARENT = 'parent',
24
- }
25
-
26
- export interface IDependency {
27
- behaviors: {
28
- forAction: DependencyBehavior['forAction'];
29
- onAction: DependencyBehavior['onAction'];
30
- onField: DependencyBehavior['onField'];
31
- toField: DependencyBehavior['toField'];
32
- }[];
33
-
34
- from: string;
35
-
36
- relationship?: {
37
- onField: DependencyBehavior['onField'];
38
- toField: DependencyBehavior['toField'];
39
- type: DependencyRelationship;
40
- };
41
-
42
- to: string;
43
- }
44
-
45
- export class Dependency {
46
- private readonly behaviors: DependencyBehavior[] = [];
47
-
48
- readonly from: UnknownModel;
49
-
50
- private relationship: { onField: string; toField: string; type: DependencyRelationship };
51
-
52
- readonly to: UnknownModel;
53
-
54
- constructor(from: UnknownModel, to: UnknownModel) {
55
- this.from = from;
56
- this.to = to;
57
- }
58
-
59
- private getBehaviorIndex(onField: string, onAction: DiffAction, toField: string, forAction: DiffAction): number {
60
- return this.behaviors.findIndex(
61
- (b) => b.onField === onField && b.onAction === onAction && b.toField === toField && b.forAction === forAction,
62
- );
63
- }
64
-
65
- addBehavior(onField: string, onAction: DiffAction, toField: string, forAction: DiffAction): void {
66
- if (!this.from.hasOwnProperty(onField) || !this.to.hasOwnProperty(toField)) {
67
- throw new Error('Invalid field name is not a property of given model!');
68
- }
69
-
70
- if (this.getBehaviorIndex(onField, onAction, toField, forAction) === -1) {
71
- this.behaviors.push(new DependencyBehavior(onField, onAction, toField, forAction));
72
- }
73
- }
74
-
75
- addChildRelationship(onField: string, toField: string): void {
76
- if (this.relationship) {
77
- throw new Error('Dependency relationship already exists!');
78
- }
79
- this.relationship = { onField, toField, type: DependencyRelationship.CHILD };
80
- }
81
-
82
- addParentRelationship(onField: string, toField: string): void {
83
- if (this.relationship) {
84
- throw new Error('Dependency relationship already exists!');
85
- }
86
- this.relationship = { onField, toField, type: DependencyRelationship.PARENT };
87
- }
88
-
89
- hasMatchingBehavior(onField?: string, onAction?: DiffAction, toField?: string, forAction?: DiffAction): boolean {
90
- return this.behaviors.some((b) => {
91
- const onFieldCondition = onField ? b.onField === onField : true;
92
- const onActionCondition = onAction ? b.onAction === onAction : true;
93
- const toFieldCondition = toField ? b.toField === toField : true;
94
- const forActionCondition = forAction ? b.forAction === forAction : true;
95
- return onFieldCondition && onActionCondition && toFieldCondition && forActionCondition;
96
- });
97
- }
98
-
99
- isChildRelationship(): boolean {
100
- return this.relationship && this.relationship.type === DependencyRelationship.CHILD;
101
- }
102
-
103
- isEqual(dependency: Dependency): boolean {
104
- return (
105
- this.from.getContext() === dependency.from.getContext() && this.to.getContext() === dependency.to.getContext()
106
- );
107
- }
108
-
109
- isParentRelationship(): boolean {
110
- return this.relationship && this.relationship.type === DependencyRelationship.PARENT;
111
- }
112
-
113
- getRelationship(): { onField: string; toField: string; type: DependencyRelationship } | undefined {
114
- return this.relationship;
115
- }
116
-
117
- removeBehavior(onField: string, onAction: DiffAction, toField: string, forAction: DiffAction): void {
118
- const index = this.getBehaviorIndex(onField, onAction, toField, forAction);
119
- if (index === -1) {
120
- throw new Error('Dependency behavior not found!');
121
- }
122
-
123
- this.behaviors.splice(index, 1);
124
- }
125
-
126
- synth(): IDependency {
127
- const behaviors: IDependency['behaviors'] = [];
128
- this.behaviors.forEach((b) => {
129
- behaviors.push({
130
- forAction: b.forAction,
131
- onAction: b.onAction,
132
- onField: b.onField,
133
- toField: b.toField,
134
- });
135
- });
136
-
137
- return {
138
- behaviors,
139
- from: this.from.getContext(),
140
- relationship: this.relationship
141
- ? {
142
- onField: this.relationship.onField,
143
- toField: this.relationship.toField,
144
- type: this.relationship.type,
145
- }
146
- : undefined,
147
- to: this.to.getContext(),
148
- };
149
- }
150
-
151
- toJSON(): object {
152
- return {
153
- from: this.from.getContext(),
154
- relationship: this.relationship
155
- ? {
156
- onField: this.relationship.onField,
157
- toField: this.relationship.toField,
158
- type: this.relationship.type,
159
- }
160
- : undefined,
161
- to: this.to.getContext(),
162
- };
163
- }
164
-
165
- static unSynth(from: UnknownModel, to: UnknownModel, dependency: IDependency): Dependency {
166
- const newDependency = new Dependency(from, to);
167
-
168
- dependency.behaviors.forEach((b) => {
169
- newDependency.addBehavior(b.onField, b.onAction, b.toField, b.forAction);
170
- });
171
-
172
- if (dependency.relationship) {
173
- newDependency.relationship = { ...dependency.relationship };
174
- }
175
-
176
- return newDependency;
177
- }
178
- }
@@ -1,51 +0,0 @@
1
- import { ActionInputs, ActionOutputs, UnknownModel, UnknownResource } from '../../app.type.js';
2
- import { IAction } from '../../models/action.interface.js';
3
- import { IResourceAction } from '../../resources/resource-action.interface.js';
4
- import { Diff, DiffAction } from './diff.model.js';
5
-
6
- export class DiffMetadata {
7
- readonly actions: IAction<ActionInputs, ActionOutputs>[] | IResourceAction[];
8
- applied: boolean;
9
- applyOrder: number;
10
-
11
- readonly diff: Diff;
12
- readonly action: DiffAction;
13
- readonly field: string;
14
- readonly model: UnknownModel | UnknownResource;
15
- readonly value: unknown;
16
-
17
- readonly inputs: ActionInputs = {};
18
- readonly outputs: ActionOutputs = {};
19
-
20
- constructor(diff: Diff, actions: IAction<ActionInputs, ActionOutputs>[] | IResourceAction[]) {
21
- if (!actions?.length) {
22
- throw new Error('No matching action given for diff!');
23
- }
24
-
25
- this.actions = actions;
26
- this.applied = false;
27
- this.applyOrder = -1;
28
-
29
- this.diff = diff;
30
- this.action = diff.action;
31
- this.field = diff.field;
32
- this.model = diff.model;
33
- this.value = diff.value;
34
- }
35
-
36
- toJSON(): ReturnType<Diff['toJSON']> {
37
- return {
38
- action: this.action,
39
- field: this.field,
40
- value: this.value,
41
- };
42
- }
43
-
44
- updateInputs(inputs: ActionInputs): void {
45
- Object.assign(this.inputs, inputs);
46
- }
47
-
48
- updateOutputs(outputs: ActionOutputs): void {
49
- Object.assign(this.outputs, outputs);
50
- }
51
- }
@@ -1,33 +0,0 @@
1
- import { UnknownModel } from '../../app.type.js';
2
-
3
- export enum DiffAction {
4
- ADD = 'add',
5
- DELETE = 'delete',
6
- REPLACE = 'replace',
7
- UPDATE = 'update',
8
- }
9
-
10
- export class Diff {
11
- readonly action: DiffAction;
12
-
13
- readonly field: string;
14
-
15
- readonly model: UnknownModel;
16
-
17
- readonly value: unknown;
18
-
19
- constructor(model: Diff['model'], action: Diff['action'], field: Diff['field'], value: Diff['value']) {
20
- this.model = model;
21
- this.action = action;
22
- this.field = field;
23
- this.value = value;
24
- }
25
-
26
- toJSON(): Omit<Diff, 'model' | 'toJSON'> {
27
- return {
28
- action: this.action,
29
- field: this.field,
30
- value: this.value,
31
- };
32
- }
33
- }
@@ -1,163 +0,0 @@
1
- import { UnknownModel } from '../../app.type.js';
2
- import { Diff, DiffAction } from './diff.model.js';
3
-
4
- export class DiffUtility {
5
- private static generateDeleteDiff(model: UnknownModel, field: string): Diff[] {
6
- const diff: Diff[] = [];
7
-
8
- const children = model.getChildren();
9
- for (const modelName of Object.keys(children)) {
10
- for (const dependency of children[modelName]) {
11
- const child = dependency.to;
12
- const childField = dependency.getRelationship()!.toField;
13
- diff.push(...DiffUtility.generateDeleteDiff(child, childField));
14
- }
15
- }
16
-
17
- diff.push(new Diff(model, DiffAction.DELETE, field, model[field]));
18
- return diff;
19
- }
20
-
21
- // Source: https://stackoverflow.com/a/32922084/1834562
22
- static isObjectDeepEquals(x: object, y: object): boolean {
23
- const ok = Object.keys,
24
- tx = typeof x,
25
- ty = typeof y;
26
- return x && y && tx === 'object' && tx === ty
27
- ? ok(x).length === ok(y).length && ok(x).every((key) => this.isObjectDeepEquals(x[key], y[key]))
28
- : x === y;
29
- }
30
-
31
- /**
32
- * Generate a deep diff of an array of basic types from the previous model vs the latest model.
33
- * @param a previous model.
34
- * @param b latest model.
35
- * @param field string representing the field parent uses to reference the array.
36
- */
37
- static diffArray(a: UnknownModel, b: UnknownModel, field: string): Diff[] {
38
- const diff: Diff[] = [];
39
- const aSet = new Set(a[field]);
40
- const bSet = new Set(b[field]);
41
-
42
- // Iterate elements of previous (a). If found in latest (b), consider it an UPDATE.
43
- // If not found in latest (b), consider it a DELETE.
44
- for (const element of aSet) {
45
- if (bSet.has(element)) {
46
- diff.push(new Diff(b, DiffAction.UPDATE, field, element));
47
- } else {
48
- diff.push(new Diff(a, DiffAction.DELETE, field, element));
49
- }
50
- }
51
-
52
- // Iterate elements of latest (b). If not found in previous (a), consider it an ADD.
53
- for (const element of bSet) {
54
- if (!aSet.has(element)) {
55
- diff.push(new Diff(b, DiffAction.ADD, field, element));
56
- }
57
- }
58
-
59
- return diff;
60
- }
61
-
62
- /**
63
- * Generate a deep diff of an array of objects from the previous model vs the latest model.
64
- * @param a previous model.
65
- * @param b latest model.
66
- * @param field string representing the field parent uses to reference the array.
67
- * @param compare function to check if two objects are equal.
68
- */
69
- static diffArrayOfObjects(
70
- a: UnknownModel,
71
- b: UnknownModel,
72
- field: string,
73
- compare: (object1, object2) => boolean,
74
- ): Diff[] {
75
- const diff: Diff[] = [];
76
-
77
- // Iterate elements of previous (a). If found in latest (b), consider it an UPDATE.
78
- // If not found in latest (b), consider it a DELETE.
79
- for (const aObject of a[field]) {
80
- if (b[field].some((bObject) => compare(aObject, bObject))) {
81
- diff.push(new Diff(b, DiffAction.UPDATE, field, aObject));
82
- } else {
83
- diff.push(...DiffUtility.generateDeleteDiff(a, field));
84
- }
85
- }
86
-
87
- // Iterate elements of latest (b). If not found in previous (a), consider it an ADD.
88
- for (const bObject of b[field]) {
89
- if (!a[field].some((aObject) => compare(aObject, bObject))) {
90
- diff.push(new Diff(b, DiffAction.ADD, field, bObject));
91
- }
92
- }
93
-
94
- return diff;
95
- }
96
-
97
- /**
98
- * Generate a deep diff of a map of basic types from the previous model vs the latest model.
99
- * @param a previous model.
100
- * @param b latest model.
101
- * @param field string representing the field parent uses to reference the map.
102
- */
103
- static diffMap(a: UnknownModel, b: UnknownModel, field: string): Diff[] {
104
- const diff: Diff[] = [];
105
-
106
- // Iterate fields of previous (a). If found in latest (b), consider it an UPDATE.
107
- // If not found in latest (b), consider it a DELETE.
108
- for (const [key, value] of a[field]) {
109
- if (b[field].has(key)) {
110
- if (b[field].get(key) !== value) {
111
- diff.push(new Diff(b, DiffAction.UPDATE, field, { key, value: b[field].get(key) }));
112
- }
113
- } else {
114
- diff.push(new Diff(a, DiffAction.DELETE, field, { key, value }));
115
- }
116
- }
117
-
118
- // Iterate fields of latest (b). If not found in previous (a), consider it an ADD.
119
- for (const [key, value] of b[field]) {
120
- if (!a[field].has(key)) {
121
- diff.push(new Diff(b, DiffAction.ADD, field, { key, value }));
122
- }
123
- }
124
-
125
- return diff;
126
- }
127
-
128
- /**
129
- * Generate a deep diff of an array of previous models vs latest models.
130
- * The diff is generated recursively, i.e. all children of the model are included in the diff.
131
- * @param a array of previous models.
132
- * @param b array of latest models.
133
- * @param field string representing the unique identifier of the model.
134
- */
135
- static async diffModels(a: UnknownModel[], b: UnknownModel[], field: string): Promise<Diff[]> {
136
- const diff: Diff[] = [];
137
-
138
- // Iterate fields of previous (a). If found in latest (b), get recursive diff of children of b vs a.
139
- // If not found in latest (b), consider it a DELETE.
140
- for (const x of a) {
141
- const y = b.find((i) => i[field] === x[field]);
142
- if (y) {
143
- const pDiff = await y.diff(x);
144
- diff.push(...pDiff);
145
- } else {
146
- diff.push(...DiffUtility.generateDeleteDiff(x, field));
147
- }
148
- }
149
-
150
- // Iterate fields of latest (b). If not found in previous (a), consider it an ADD.
151
- // Recursively add all children of b.
152
- for (const y of b) {
153
- if (!a.find((i) => i[field] === y[field])) {
154
- diff.push(new Diff(y, DiffAction.ADD, field, y[field]));
155
-
156
- const pDiff = await y.diff();
157
- diff.push(...pDiff);
158
- }
159
- }
160
-
161
- return diff;
162
- }
163
- }
@@ -1,59 +0,0 @@
1
- import { UnknownModel } from '../../app.type.js';
2
- import { IModule } from './module.interface.js';
3
-
4
- export abstract class AModule {
5
- private readonly members: UnknownModel[] = [];
6
-
7
- protected addMember(member: UnknownModel): void {
8
- const index = this.members.findIndex((m) => m.getContext() === member.getContext());
9
-
10
- if (index === -1) {
11
- this.members.push(member);
12
- }
13
- }
14
-
15
- abstract apply(...args: UnknownModel[]): void;
16
-
17
- abstract remove(...args: UnknownModel[]): void;
18
-
19
- removeAll(): void {
20
- for (const member of this.members) {
21
- member.remove(false, true);
22
- }
23
-
24
- for (const member of this.members) {
25
- member.remove(false, false);
26
- }
27
- }
28
-
29
- protected removeMember(member: UnknownModel): void {
30
- const index = this.members.findIndex((m) => m.getContext() === member.getContext());
31
-
32
- if (index !== -1) {
33
- this.members.splice(index, 1);
34
- }
35
- }
36
-
37
- synth(): IModule {
38
- return {
39
- members: this.members.map((m) => ({
40
- context: m.getContext(),
41
- })),
42
- };
43
- }
44
-
45
- static async unSynth(
46
- deserializationClass: any,
47
- module: IModule,
48
- deReferenceContext: (context: string) => Promise<UnknownModel>,
49
- ): Promise<AModule> {
50
- const newModule = new deserializationClass();
51
-
52
- for (const member of module.members) {
53
- const model = await deReferenceContext(member.context);
54
- newModule.addMember(model);
55
- }
56
-
57
- return newModule;
58
- }
59
- }
@@ -1,5 +0,0 @@
1
- import { IModelReference } from '../../models/model.interface.js';
2
-
3
- export interface IModule {
4
- members: IModelReference[];
5
- }