@api-client/core 0.11.6 → 0.11.8

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 (58) hide show
  1. package/build/src/amf/definitions/Shapes.d.ts +1 -1
  2. package/build/src/amf/definitions/Shapes.js.map +1 -1
  3. package/build/src/browser.d.ts +2 -0
  4. package/build/src/browser.d.ts.map +1 -1
  5. package/build/src/browser.js +2 -0
  6. package/build/src/browser.js.map +1 -1
  7. package/build/src/index.d.ts +2 -0
  8. package/build/src/index.d.ts.map +1 -1
  9. package/build/src/index.js +2 -0
  10. package/build/src/index.js.map +1 -1
  11. package/build/src/modeling/DataAssociation.d.ts +10 -2
  12. package/build/src/modeling/DataAssociation.d.ts.map +1 -1
  13. package/build/src/modeling/DataAssociation.js +32 -2
  14. package/build/src/modeling/DataAssociation.js.map +1 -1
  15. package/build/src/modeling/DataEntity.d.ts +26 -1
  16. package/build/src/modeling/DataEntity.d.ts.map +1 -1
  17. package/build/src/modeling/DataEntity.js +73 -8
  18. package/build/src/modeling/DataEntity.js.map +1 -1
  19. package/build/src/modeling/DataModel.d.ts +10 -1
  20. package/build/src/modeling/DataModel.d.ts.map +1 -1
  21. package/build/src/modeling/DataModel.js +22 -2
  22. package/build/src/modeling/DataModel.js.map +1 -1
  23. package/build/src/modeling/DataNamespace.d.ts +60 -55
  24. package/build/src/modeling/DataNamespace.d.ts.map +1 -1
  25. package/build/src/modeling/DataNamespace.js +133 -116
  26. package/build/src/modeling/DataNamespace.js.map +1 -1
  27. package/build/src/modeling/DataProperty.d.ts +16 -3
  28. package/build/src/modeling/DataProperty.d.ts.map +1 -1
  29. package/build/src/modeling/DataProperty.js +28 -2
  30. package/build/src/modeling/DataProperty.js.map +1 -1
  31. package/build/src/modeling/ImpactAnalysis.d.ts +290 -0
  32. package/build/src/modeling/ImpactAnalysis.d.ts.map +1 -0
  33. package/build/src/modeling/ImpactAnalysis.js +437 -0
  34. package/build/src/modeling/ImpactAnalysis.js.map +1 -0
  35. package/build/src/modeling/types.d.ts +14 -0
  36. package/build/src/modeling/types.d.ts.map +1 -0
  37. package/build/src/modeling/types.js +2 -0
  38. package/build/src/modeling/types.js.map +1 -0
  39. package/data/models/example-generator-api.json +9 -9
  40. package/package.json +9 -19
  41. package/src/amf/definitions/Shapes.ts +1 -1
  42. package/src/modeling/DataAssociation.ts +36 -2
  43. package/src/modeling/DataEntity.ts +88 -12
  44. package/src/modeling/DataModel.ts +24 -2
  45. package/src/modeling/DataNamespace.ts +150 -137
  46. package/src/modeling/DataProperty.ts +32 -3
  47. package/src/modeling/ImpactAnalysis.ts +519 -0
  48. package/src/modeling/types.ts +13 -0
  49. package/tests/servers/ExpressServer.ts +1 -0
  50. package/tests/servers/express-routes/BaseApi.ts +1 -1
  51. package/tests/servers/express-routes/TestsApi.ts +1 -1
  52. package/tests/unit/modeling/data_association.spec.ts +73 -0
  53. package/tests/unit/modeling/data_entity.spec.ts +111 -1
  54. package/tests/unit/modeling/data_model.spec.ts +54 -0
  55. package/tests/unit/modeling/data_namespace.spec.ts +46 -1
  56. package/tests/unit/modeling/data_property.spec.ts +73 -0
  57. package/tests/unit/modeling/impact_analysis.spec.ts +373 -0
  58. package/tsconfig.browser.json +2 -1
@@ -475,7 +475,6 @@ test.group('remove()', (group) => {
475
475
  })
476
476
 
477
477
  test('throws when removing an entity that is a target', ({ assert }) => {
478
- // const e3 = m1.addEntity('e3')
479
478
  e2.addTargetAssociation(e1.key)
480
479
  assert.throws(
481
480
  () => e1.remove(),
@@ -483,6 +482,47 @@ test.group('remove()', (group) => {
483
482
  `Cannot remove entity ${e1.info.name} because it is used as a target in associations in entities: e2.`
484
483
  )
485
484
  })
485
+
486
+ test('force removes an entity that is a target', ({ assert }) => {
487
+ e2.addTargetAssociation(e1.key)
488
+ e1.remove({ force: true })
489
+ assert.deepEqual(m1.entities, [e2])
490
+ assert.deepEqual(root.definitions.entities, [e2])
491
+ assert.deepEqual(e2.associations, [], 'removes the association from the target entity')
492
+ assert.deepEqual(e2.fields, [], 'removes the association from the entity fields')
493
+ assert.deepEqual(root.definitions.associations, [], 'removes the association from the root definitions')
494
+ })
495
+
496
+ test('throws when removing an entity that is a parent', ({ assert }) => {
497
+ const e3 = m1.addEntity('e3')
498
+ e3.addParent(e1.key)
499
+ assert.throws(
500
+ () => e1.remove(),
501
+ RemoveEntityException as unknown as ErrorConstructor,
502
+ `Cannot remove entity ${e1.info.name} because it is a parent for the following entities: e3.`
503
+ )
504
+ })
505
+
506
+ test('force removes an entity that is a parent', ({ assert }) => {
507
+ const e3 = m1.addEntity('e3')
508
+ e3.addParent(e1.key)
509
+ e1.remove({ force: true })
510
+ assert.deepEqual(m1.entities, [e2, e3])
511
+ assert.deepEqual(root.definitions.entities, [e2, e3])
512
+ assert.deepEqual(e3.parents, [], 'removes the parent from the child entity')
513
+ })
514
+
515
+ test('force removes an entity that is a parent and a target', ({ assert }) => {
516
+ const e3 = m1.addEntity('e3')
517
+ e3.addParent(e1.key)
518
+ e2.addTargetAssociation(e1.key)
519
+ e1.remove({ force: true })
520
+ assert.deepEqual(m1.entities, [e2, e3])
521
+ assert.deepEqual(root.definitions.entities, [e2, e3])
522
+ assert.deepEqual(e3.parents, [], 'removes the parent from the child entity')
523
+ assert.deepEqual(e2.associations, [], 'removes the association from the target entity')
524
+ assert.deepEqual(root.definitions.associations, [], 'removes the association from the root definitions')
525
+ })
486
526
  })
487
527
 
488
528
  test.group('addTypedProperty()', (group) => {
@@ -1947,3 +1987,73 @@ test.group('moveField()', (group) => {
1947
1987
  assert.throws(() => e1.moveField(p1.key, 4), ValidationError as unknown as ErrorConstructor, 'Validation failure')
1948
1988
  })
1949
1989
  })
1990
+
1991
+ test.group('DataEntity.isChildOf()', (group) => {
1992
+ let root: DataNamespace
1993
+ let n1: DataNamespace
1994
+ let n2: DataNamespace
1995
+ let m1: DataModel
1996
+ let m2: DataModel
1997
+ let e1: DataEntity
1998
+ let e2: DataEntity
1999
+ let e3: DataEntity
2000
+
2001
+ group.each.setup(() => {
2002
+ root = new DataNamespace()
2003
+ n1 = root.addNamespace('n1')
2004
+ n2 = n1.addNamespace('n2')
2005
+ m1 = root.addDataModel('m1')
2006
+ m2 = n1.addDataModel('m2')
2007
+ e1 = m1.addEntity('e1')
2008
+ e2 = m2.addEntity('e2')
2009
+ e3 = n2.addDataModel('m3').addEntity('e3')
2010
+ })
2011
+
2012
+ test('returns false when called on an entity not in a data model', ({ assert }) => {
2013
+ const e4 = new DataEntity(root)
2014
+ const result = e4.isChildOf('some-key')
2015
+ assert.isFalse(result)
2016
+ })
2017
+
2018
+ test('returns false when called on self', ({ assert }) => {
2019
+ const result = e2.isChildOf(e2.key)
2020
+ assert.isFalse(result)
2021
+ })
2022
+
2023
+ test('returns true when called on a direct parent', ({ assert }) => {
2024
+ const result = e2.isChildOf(m2.key)
2025
+ assert.isTrue(result)
2026
+ })
2027
+
2028
+ test('returns true when called on a grandparent', ({ assert }) => {
2029
+ const result = e3.isChildOf(root.key)
2030
+ assert.isTrue(result)
2031
+ })
2032
+
2033
+ test('returns false when called on a sibling', ({ assert }) => {
2034
+ const e4 = m1.addEntity('e4')
2035
+ const result = e1.isChildOf(e4.key)
2036
+ assert.isFalse(result)
2037
+ })
2038
+
2039
+ test('returns false when called on a child', ({ assert }) => {
2040
+ const p1 = e2.addNamedProperty('p1')
2041
+ const result = e2.isChildOf(p1.key)
2042
+ assert.isFalse(result)
2043
+ })
2044
+
2045
+ test('returns false when called on a non-existent namespace', ({ assert }) => {
2046
+ const result = e2.isChildOf('non-existent-key')
2047
+ assert.isFalse(result)
2048
+ })
2049
+
2050
+ test('returns true when called on a grandparent', ({ assert }) => {
2051
+ const result = e3.isChildOf(n1.key)
2052
+ assert.isTrue(result)
2053
+ })
2054
+
2055
+ test('returns true when called on a data model in the same namespace', ({ assert }) => {
2056
+ const result = e1.isChildOf(m1.key)
2057
+ assert.isTrue(result)
2058
+ })
2059
+ })
@@ -339,3 +339,57 @@ test.group('adaptEntity()', (group) => {
339
339
  assert.throws(() => dm2.adaptEntity(e1, { index: 1 }), `The index 1 is not valid.`)
340
340
  })
341
341
  })
342
+
343
+ test.group('isChildOf()', (group) => {
344
+ let root: DataNamespace
345
+ let n1: DataNamespace
346
+ let n2: DataNamespace
347
+ let m1: DataModel
348
+ let m2: DataModel
349
+ let m3: DataModel
350
+
351
+ group.each.setup(() => {
352
+ root = new DataNamespace()
353
+ n1 = root.addNamespace('n1')
354
+ n2 = n1.addNamespace('n2')
355
+ m1 = root.addDataModel('m1')
356
+ m2 = n1.addDataModel('m2')
357
+ m3 = n2.addDataModel('m3')
358
+ })
359
+
360
+ test('returns false when called on the root data model', ({ assert }) => {
361
+ const result = m1.isChildOf('some-key')
362
+ assert.isFalse(result)
363
+ })
364
+
365
+ test('returns true when called on a direct child', ({ assert }) => {
366
+ const result = m2.isChildOf(n1.key)
367
+ assert.isTrue(result)
368
+ })
369
+
370
+ test('returns true when called on a grandchild', ({ assert }) => {
371
+ const result = m3.isChildOf(root.key)
372
+ assert.isTrue(result)
373
+ })
374
+
375
+ test('returns false when called on a sibling', ({ assert }) => {
376
+ const m4 = root.addDataModel('m4')
377
+ const result = m1.isChildOf(m4.key)
378
+ assert.isFalse(result)
379
+ })
380
+
381
+ test('returns false when called on a parent', ({ assert }) => {
382
+ const result = n1.isChildOf(m2.key)
383
+ assert.isFalse(result)
384
+ })
385
+
386
+ test('returns false when called on a non-existent namespace', ({ assert }) => {
387
+ const result = m2.isChildOf('non-existent-key')
388
+ assert.isFalse(result)
389
+ })
390
+
391
+ test('returns false when called on self', ({ assert }) => {
392
+ const result = m2.isChildOf(m2.key)
393
+ assert.isFalse(result)
394
+ })
395
+ })
@@ -1263,7 +1263,7 @@ test.group('adaptDataModel()', (group) => {
1263
1263
  assert.throws(() => n2.adaptDataModel(m1, { index: 1 }), `The index 1 is not valid.`)
1264
1264
  })
1265
1265
 
1266
- test('throws when adapting a data model from another namepsace', ({ assert }) => {
1266
+ test('throws when adapting a data model from another namespace', ({ assert }) => {
1267
1267
  const otherRoot = new DataNamespace()
1268
1268
  const otherModel = new DataModel(otherRoot)
1269
1269
  assert.throws(
@@ -1272,3 +1272,48 @@ test.group('adaptDataModel()', (group) => {
1272
1272
  )
1273
1273
  })
1274
1274
  })
1275
+
1276
+ test.group('isChildOf()', (group) => {
1277
+ let root: DataNamespace
1278
+ let n1: DataNamespace
1279
+ let n2: DataNamespace
1280
+ let n3: DataNamespace
1281
+
1282
+ group.each.setup(() => {
1283
+ root = new DataNamespace()
1284
+ n1 = root.addNamespace('n1')
1285
+ n2 = n1.addNamespace('n2')
1286
+ n3 = n2.addNamespace('n3')
1287
+ })
1288
+
1289
+ test('returns false when called on the root namespace', ({ assert }) => {
1290
+ const result = root.isChildOf('some-key')
1291
+ assert.isFalse(result)
1292
+ })
1293
+
1294
+ test('returns true when called on a direct child', ({ assert }) => {
1295
+ const result = n1.isChildOf(root.key)
1296
+ assert.isTrue(result)
1297
+ })
1298
+
1299
+ test('returns true when called on a grandchild', ({ assert }) => {
1300
+ const result = n3.isChildOf(root.key)
1301
+ assert.isTrue(result)
1302
+ })
1303
+
1304
+ test('returns false when called on a sibling', ({ assert }) => {
1305
+ const n4 = root.addNamespace('n4')
1306
+ const result = n1.isChildOf(n4.key)
1307
+ assert.isFalse(result)
1308
+ })
1309
+
1310
+ test('returns false when called on a parent', ({ assert }) => {
1311
+ const result = root.isChildOf(n1.key)
1312
+ assert.isFalse(result)
1313
+ })
1314
+
1315
+ test('returns false when called on a non-existent namespace', ({ assert }) => {
1316
+ const result = n1.isChildOf('non-existent-key')
1317
+ assert.isFalse(result)
1318
+ })
1319
+ })
@@ -815,3 +815,76 @@ test.group('readBinding()', () => {
815
815
  assert.isUndefined(binding)
816
816
  })
817
817
  })
818
+
819
+ test.group('DataProperty.isChildOf()', (group) => {
820
+ let root: DataNamespace
821
+ let n1: DataNamespace
822
+ let n2: DataNamespace
823
+ let m1: DataModel
824
+ let m2: DataModel
825
+ let e1: DataEntity
826
+ let e2: DataEntity
827
+ let p1: DataProperty
828
+ let p2: DataProperty
829
+ let p3: DataProperty
830
+
831
+ group.each.setup(() => {
832
+ root = new DataNamespace()
833
+ n1 = root.addNamespace('n1')
834
+ n2 = n1.addNamespace('n2')
835
+ m1 = root.addDataModel('m1')
836
+ m2 = n1.addDataModel('m2')
837
+ e1 = m1.addEntity('e1')
838
+ e2 = m2.addEntity('e2')
839
+ p1 = e1.addNamedProperty('p1')
840
+ p2 = e2.addNamedProperty('p2')
841
+ p3 = n2.addDataModel('m3').addEntity('e3').addNamedProperty('p3')
842
+ })
843
+
844
+ test('returns false when called on a property not in an entity', ({ assert }) => {
845
+ const p4 = new DataProperty(root)
846
+ const result = p4.isChildOf('some-key')
847
+ assert.isFalse(result)
848
+ })
849
+
850
+ test('returns false when called on self', ({ assert }) => {
851
+ const result = p2.isChildOf(p2.key)
852
+ assert.isFalse(result)
853
+ })
854
+
855
+ test('returns true when called on a direct parent', ({ assert }) => {
856
+ const result = p2.isChildOf(e2.key)
857
+ assert.isTrue(result)
858
+ })
859
+
860
+ test('returns true when called on a grandparent', ({ assert }) => {
861
+ const result = p3.isChildOf(root.key)
862
+ assert.isTrue(result)
863
+ })
864
+
865
+ test('returns false when called on a sibling', ({ assert }) => {
866
+ const p4 = e1.addNamedProperty('p4')
867
+ const result = p1.isChildOf(p4.key)
868
+ assert.isFalse(result)
869
+ })
870
+
871
+ test('returns false when called on a child', ({ assert }) => {
872
+ const result = e2.isChildOf(p2.key)
873
+ assert.isFalse(result)
874
+ })
875
+
876
+ test('returns false when called on a non-existent namespace', ({ assert }) => {
877
+ const result = p2.isChildOf('non-existent-key')
878
+ assert.isFalse(result)
879
+ })
880
+
881
+ test('returns true when called on a grandparent', ({ assert }) => {
882
+ const result = p3.isChildOf(n1.key)
883
+ assert.isTrue(result)
884
+ })
885
+
886
+ test('returns true when called on a data model in the same namespace', ({ assert }) => {
887
+ const result = p1.isChildOf(m1.key)
888
+ assert.isTrue(result)
889
+ })
890
+ })
@@ -0,0 +1,373 @@
1
+ import { test } from '@japa/runner'
2
+ import { ImpactAnalysis } from '../../../src/modeling/ImpactAnalysis.js'
3
+ import {
4
+ DataNamespaceKind,
5
+ DataEntityKind,
6
+ DataModelKind,
7
+ DataPropertyKind,
8
+ DataAssociationKind,
9
+ } from '../../../src/models/kinds.js'
10
+ import { DataNamespace } from '../../../src/modeling/DataNamespace.js'
11
+ import { DataEntity } from '../../../src/modeling/DataEntity.js'
12
+ import { DataModel } from '../../../src/modeling/DataModel.js'
13
+ import { DataProperty } from '../../../src/modeling/DataProperty.js'
14
+ import { DataAssociation } from '../../../src/modeling/DataAssociation.js'
15
+
16
+ test.group('ImpactAnalysis', (group) => {
17
+ let root: DataNamespace
18
+ let analyzer: ImpactAnalysis
19
+ let n1: DataNamespace
20
+ let n2: DataNamespace
21
+ let m1: DataModel
22
+ let m2: DataModel
23
+ let m3: DataModel
24
+ let e1: DataEntity
25
+ let e2: DataEntity
26
+ let e3: DataEntity
27
+ let e4: DataEntity
28
+ let p1: DataProperty
29
+ let a1: DataAssociation
30
+
31
+ group.each.setup(() => {
32
+ root = new DataNamespace()
33
+ analyzer = new ImpactAnalysis(root)
34
+ n1 = root.addNamespace('n1')
35
+ m1 = root.addDataModel('m1')
36
+ n2 = n1.addNamespace('n2')
37
+ m2 = n1.addDataModel('m2')
38
+ e1 = m1.addEntity('e1')
39
+ e2 = m2.addEntity('e2')
40
+ m3 = n2.addDataModel('m3')
41
+ e3 = m3.addEntity('e3')
42
+ p1 = e1.addNamedProperty('p1')
43
+ a1 = e1.addNamedAssociation('a1')
44
+ a1.addTarget(e2)
45
+ e2.addParent(e3.key)
46
+ e3.addParent(e1.key)
47
+ e4 = root.addDataModel('m4').addEntity('e4')
48
+ e4.addParent(e3.key)
49
+ // DataNamespace (root)
50
+ // ├── DataNamespace (n1)
51
+ // │ ├── DataModel (m2)
52
+ // │ │ └── DataEntity (e2)
53
+ // │ │ └── parent: DataEntity (e3)
54
+ // │ └── DataNamespace (n2)
55
+ // │ └── DataModel (m3)
56
+ // │ └── DataEntity (e3)
57
+ // │ └── parent: DataEntity (e1)
58
+ // ├── DataModel (m1)
59
+ // │ └── DataEntity (e1)
60
+ // │ ├── DataProperty (p1)
61
+ // │ └── DataAssociation (a1)
62
+ // │ └── target: DataEntity (e2)
63
+ // └── DataModel (m4)
64
+ // └── DataEntity (e4)
65
+ // └── parent: DataEntity (e3)
66
+ })
67
+
68
+ test('returns a report for deleting a namespace', ({ assert }) => {
69
+ const report = analyzer.deleteAnalysis(n1.key, DataNamespaceKind)
70
+ assert.equal(report.key, n1.key)
71
+ assert.equal(report.kind, DataNamespaceKind)
72
+ assert.isFalse(report.canProceed, 'operation should not be able to proceed')
73
+ // Affected items:
74
+ // - n1 (self)
75
+ // - m2 (child)
76
+ // - e2 (child), note, e3 parent is not included because it is included in the deletion.
77
+ // - n2 (child)
78
+ // - m3 (child)
79
+ // - e3 (child)
80
+ // - a1 (target of e2)
81
+ // - e4 (parent of e3)
82
+ assert.lengthOf(report.impact, 8, 'has all items')
83
+ const [n1r, n2r, m3r, e3r, e4r, m2r, e2r, a1r] = report.impact
84
+
85
+ assert.ok(n1r)
86
+ assert.equal(n1r.key, n1.key)
87
+ assert.equal(n1r.kind, DataNamespaceKind)
88
+ assert.equal(n1r.type, 'delete')
89
+ assert.equal(n1r.impact, `The n1 namespace will be deleted.`)
90
+ assert.isFalse(n1r.blocking)
91
+
92
+ assert.ok(n2r)
93
+ assert.equal(n2r.key, n2.key)
94
+ assert.equal(n2r.kind, DataNamespaceKind)
95
+ assert.equal(n2r.type, 'delete')
96
+ assert.equal(n2r.impact, `The n2 namespace will be deleted.`)
97
+ assert.isFalse(n2r.blocking)
98
+
99
+ assert.ok(m3r)
100
+ assert.equal(m3r.key, m3.key)
101
+ assert.equal(m3r.kind, DataModelKind)
102
+ assert.equal(m3r.type, 'delete')
103
+ assert.equal(m3r.impact, `The m3 data model will be deleted.`)
104
+ assert.isFalse(m3r.blocking)
105
+
106
+ assert.ok(e3r)
107
+ assert.equal(e3r.key, e3.key)
108
+ assert.equal(e3r.kind, DataEntityKind)
109
+ assert.equal(e3r.type, 'delete')
110
+ assert.equal(e3r.impact, `The e3 entity will be deleted.`)
111
+ assert.isFalse(e3r.blocking)
112
+
113
+ assert.ok(e4r)
114
+ assert.equal(e4r.key, e4.key)
115
+ assert.equal(e4r.kind, DataEntityKind)
116
+ assert.equal(e4r.type, 'delete')
117
+ assert.equal(e4r.impact, `The e4 entity will become an orphan because it is a child of e3.`)
118
+ assert.equal(e4r.resolution, `The e3 will be removed as the parent parent of e4.`)
119
+ assert.isTrue(e4r.blocking)
120
+ assert.equal(e4r.relationship, 'child')
121
+
122
+ assert.ok(m2r)
123
+ assert.equal(m2r.key, m2.key)
124
+ assert.equal(m2r.kind, DataModelKind)
125
+ assert.equal(m2r.type, 'delete')
126
+ assert.equal(m2r.impact, `The m2 data model will be deleted.`)
127
+ assert.isFalse(m2r.blocking)
128
+
129
+ assert.ok(e2r)
130
+ assert.equal(e2r.key, e2.key)
131
+ assert.equal(e2r.kind, DataEntityKind)
132
+ assert.equal(e2r.type, 'delete')
133
+ assert.equal(e2r.impact, `The e2 entity will be deleted.`)
134
+ assert.isFalse(e2r.blocking)
135
+
136
+ assert.ok(a1r)
137
+ assert.equal(a1r.key, a1.key)
138
+ assert.equal(a1r.kind, DataAssociationKind)
139
+ assert.equal(a1r.type, 'delete')
140
+ assert.equal(a1r.impact, `The a1 association will be broken because it has a target to e2.`)
141
+ assert.equal(a1r.resolution, `The a1 association will be removed from e2.`)
142
+ assert.isTrue(a1r.blocking)
143
+ })
144
+
145
+ test('returns a report for deleting a data model', ({ assert }) => {
146
+ const report = analyzer.deleteAnalysis(m1.key, DataModelKind)
147
+ assert.equal(report.key, m1.key)
148
+ assert.equal(report.kind, DataModelKind)
149
+ assert.isFalse(report.canProceed, 'operation should not be able to proceed')
150
+
151
+ // Affected items:
152
+ // - m1 (self)
153
+ // - e1 (child)
154
+ // - p1 (child of e1)
155
+ // - a1 (child of e1)
156
+ // - e3 (parent of e4)
157
+ assert.lengthOf(report.impact, 5, 'has all items')
158
+ const [m1r, e1r, e3r, p1r, a1r] = report.impact
159
+
160
+ assert.ok(m1r)
161
+ assert.equal(m1r.key, m1.key)
162
+ assert.equal(m1r.kind, DataModelKind)
163
+ assert.equal(m1r.type, 'delete')
164
+ assert.equal(m1r.impact, `The m1 data model will be deleted.`)
165
+ assert.isFalse(m1r.blocking)
166
+
167
+ assert.ok(e1r)
168
+ assert.equal(e1r.key, e1.key)
169
+ assert.equal(e1r.kind, DataEntityKind)
170
+ assert.equal(e1r.type, 'delete')
171
+ assert.equal(e1r.impact, `The e1 entity will be deleted.`)
172
+ assert.isFalse(e1r.blocking)
173
+
174
+ assert.ok(p1r)
175
+ assert.equal(p1r.key, p1.key)
176
+ assert.equal(p1r.kind, DataPropertyKind)
177
+ assert.equal(p1r.type, 'delete')
178
+ assert.equal(p1r.impact, `The p1 property will be deleted.`)
179
+ assert.isFalse(p1r.blocking)
180
+
181
+ assert.ok(a1r)
182
+ assert.equal(a1r.key, a1.key)
183
+ assert.equal(a1r.kind, DataAssociationKind)
184
+ assert.equal(a1r.type, 'delete')
185
+ assert.equal(a1r.impact, `The a1 association will be deleted.`)
186
+ assert.isFalse(a1r.blocking)
187
+
188
+ assert.ok(e3r)
189
+ assert.equal(e3r.key, e3.key)
190
+ assert.equal(e3r.kind, DataEntityKind)
191
+ assert.equal(e3r.type, 'delete')
192
+ assert.equal(e3r.impact, `The e3 entity will become an orphan because it is a child of e1.`)
193
+ assert.equal(e3r.resolution, `The e1 will be removed as the parent parent of e3.`)
194
+ assert.isTrue(e3r.blocking)
195
+ assert.equal(e3r.relationship, 'child')
196
+ })
197
+
198
+ test('returns a report for deleting an entity', ({ assert }) => {
199
+ const report = analyzer.deleteAnalysis(e1.key, DataEntityKind)
200
+ assert.equal(report.key, e1.key)
201
+ assert.equal(report.kind, DataEntityKind)
202
+ assert.isFalse(report.canProceed, 'operation should not be able to proceed')
203
+
204
+ // Affected items:
205
+ // - e1 (self)
206
+ // - e3 (parent)
207
+ // - p1 (child)
208
+ // - a1 (child)
209
+ assert.lengthOf(report.impact, 4, 'has all items')
210
+ const [e1r, e3r, p1r, a1r] = report.impact
211
+
212
+ assert.ok(e1r)
213
+ assert.equal(e1r.key, e1.key)
214
+ assert.equal(e1r.kind, DataEntityKind)
215
+ assert.equal(e1r.type, 'delete')
216
+ assert.equal(e1r.impact, `The e1 entity will be deleted.`)
217
+ assert.isFalse(e1r.blocking)
218
+
219
+ assert.ok(p1r)
220
+ assert.equal(p1r.key, p1.key)
221
+ assert.equal(p1r.kind, DataPropertyKind)
222
+ assert.equal(p1r.type, 'delete')
223
+ assert.equal(p1r.impact, `The p1 property will be deleted.`)
224
+ assert.isFalse(p1r.blocking)
225
+
226
+ assert.ok(a1r)
227
+ assert.equal(a1r.key, a1.key)
228
+ assert.equal(a1r.kind, DataAssociationKind)
229
+ assert.equal(a1r.type, 'delete')
230
+ assert.equal(a1r.impact, `The a1 association will be deleted.`)
231
+ assert.isFalse(a1r.blocking)
232
+
233
+ assert.ok(e3r)
234
+ assert.equal(e3r.key, e3.key)
235
+ assert.equal(e3r.kind, DataEntityKind)
236
+ assert.equal(e3r.type, 'delete')
237
+ assert.equal(e3r.impact, `The e3 entity will become an orphan because it is a child of e1.`)
238
+ assert.equal(e3r.resolution, `The e1 will be removed as the parent parent of e3.`)
239
+ assert.isTrue(e3r.blocking)
240
+ assert.equal(e3r.relationship, 'child')
241
+ })
242
+
243
+ test('returns a report for deleting a property', ({ assert }) => {
244
+ p1.getWebBinding().hidden = true
245
+ const report = analyzer.deleteAnalysis(p1.key, DataPropertyKind)
246
+ assert.equal(report.key, p1.key)
247
+ assert.equal(report.kind, DataPropertyKind)
248
+ assert.isTrue(report.canProceed, 'operation should be able to proceed')
249
+
250
+ // Affected items:
251
+ // - p1 (self)
252
+ assert.lengthOf(report.impact, 1, 'has all items')
253
+ const [p1r] = report.impact
254
+
255
+ assert.ok(p1r)
256
+ assert.equal(p1r.key, p1.key)
257
+ assert.equal(p1r.kind, DataPropertyKind)
258
+ assert.equal(p1r.type, 'delete')
259
+ assert.equal(p1r.impact, `The p1 property will be deleted.`)
260
+ assert.isFalse(p1r.blocking)
261
+ })
262
+
263
+ test('returns a report for deleting an association', ({ assert }) => {
264
+ a1.getWebBinding().hidden = true
265
+ const report = analyzer.deleteAnalysis(a1.key, DataAssociationKind)
266
+ assert.equal(report.key, a1.key)
267
+ assert.equal(report.kind, DataAssociationKind)
268
+ assert.isTrue(report.canProceed, 'operation should be able to proceed')
269
+
270
+ // Affected items:
271
+ // - a1 (self)
272
+ assert.lengthOf(report.impact, 1, 'has all items')
273
+ const [a1r] = report.impact
274
+
275
+ assert.ok(a1r)
276
+ assert.equal(a1r.key, a1.key)
277
+ assert.equal(a1r.kind, DataAssociationKind)
278
+ assert.equal(a1r.type, 'delete')
279
+ assert.equal(a1r.impact, `The a1 association will be deleted.`)
280
+ assert.isFalse(a1r.blocking)
281
+ })
282
+
283
+ test('handles circular dependencies', ({ assert }) => {
284
+ const report = analyzer.deleteAnalysis(e3.key, DataEntityKind)
285
+ assert.equal(report.key, e3.key)
286
+ assert.equal(report.kind, DataEntityKind)
287
+ assert.isFalse(report.canProceed, 'operation should not be able to proceed')
288
+
289
+ // Affected items:
290
+ // - e3 (self)
291
+ // - e2 (target of a1)
292
+ // - e4 (child)
293
+ assert.lengthOf(report.impact, 3, 'has all items')
294
+ const [e3r, e2r, e4r] = report.impact
295
+
296
+ assert.ok(e3r)
297
+ assert.equal(e3r.key, e3.key)
298
+ assert.equal(e3r.kind, DataEntityKind)
299
+ assert.equal(e3r.type, 'delete')
300
+ assert.equal(e3r.impact, `The e3 entity will be deleted.`)
301
+ assert.isFalse(e3r.blocking)
302
+
303
+ assert.ok(e2r)
304
+ assert.equal(e2r.key, e2.key)
305
+ assert.equal(e2r.kind, DataEntityKind)
306
+ assert.equal(e2r.type, 'delete')
307
+ assert.equal(e2r.impact, `The e2 entity will become an orphan because it is a child of e3.`)
308
+ assert.equal(e2r.resolution, `The e3 will be removed as the parent parent of e2.`)
309
+ assert.isTrue(e2r.blocking)
310
+ assert.equal(e2r.relationship, 'child')
311
+
312
+ assert.ok(e4r)
313
+ assert.equal(e4r.key, e4.key)
314
+ assert.equal(e4r.kind, DataEntityKind)
315
+ assert.equal(e4r.type, 'delete')
316
+ assert.equal(e4r.impact, `The e4 entity will become an orphan because it is a child of e3.`)
317
+ assert.equal(e4r.resolution, `The e3 will be removed as the parent parent of e4.`)
318
+ assert.isTrue(e4r.blocking)
319
+ assert.equal(e4r.relationship, 'child')
320
+ })
321
+
322
+ test('deleteAnalysis() handles foreign namespaces', ({ assert }) => {
323
+ const f1 = new DataNamespace()
324
+ const fm1 = f1.addDataModel('fm1')
325
+ const fe1 = fm1.addEntity('fe1')
326
+ root.addForeign(f1)
327
+ a1.addTarget(fe1)
328
+
329
+ const report = analyzer.deleteAnalysis(e1.key, DataEntityKind)
330
+ // console.log(JSON.stringify(report.impact, null, 2))
331
+ assert.equal(report.key, e1.key)
332
+ assert.equal(report.kind, DataEntityKind)
333
+ assert.isFalse(report.canProceed, 'operation should not be able to proceed')
334
+
335
+ // Affected items:
336
+ // - e1 (self)
337
+ // - e3 (parent)
338
+ // - p1 (child)
339
+ // - a1 (child)
340
+ assert.lengthOf(report.impact, 4, 'has all items')
341
+ const [e1r, e3r, p1r, a1r] = report.impact
342
+
343
+ assert.ok(e1r)
344
+ assert.equal(e1r.key, e1.key)
345
+ assert.equal(e1r.kind, DataEntityKind)
346
+ assert.equal(e1r.type, 'delete')
347
+ assert.equal(e1r.impact, `The e1 entity will be deleted.`)
348
+ assert.isFalse(e1r.blocking)
349
+
350
+ assert.ok(p1r)
351
+ assert.equal(p1r.key, p1.key)
352
+ assert.equal(p1r.kind, DataPropertyKind)
353
+ assert.equal(p1r.type, 'delete')
354
+ assert.equal(p1r.impact, `The p1 property will be deleted.`)
355
+ assert.isFalse(p1r.blocking)
356
+
357
+ assert.ok(a1r)
358
+ assert.equal(a1r.key, a1.key)
359
+ assert.equal(a1r.kind, DataAssociationKind)
360
+ assert.equal(a1r.type, 'delete')
361
+ assert.equal(a1r.impact, `The a1 association will be deleted.`)
362
+ assert.isFalse(a1r.blocking)
363
+
364
+ assert.ok(e3r)
365
+ assert.equal(e3r.key, e3.key)
366
+ assert.equal(e3r.kind, DataEntityKind)
367
+ assert.equal(e3r.type, 'delete')
368
+ assert.equal(e3r.impact, `The e3 entity will become an orphan because it is a child of e1.`)
369
+ assert.equal(e3r.resolution, `The e1 will be removed as the parent parent of e3.`)
370
+ assert.isTrue(e3r.blocking)
371
+ assert.equal(e3r.relationship, 'child')
372
+ })
373
+ })