@api-client/core 0.18.16 → 0.18.18
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/build/src/{modeling → decorators}/observed.d.ts +3 -3
- package/build/src/decorators/observed.d.ts.map +1 -0
- package/build/src/{modeling → decorators}/observed.js +4 -4
- package/build/src/decorators/observed.js.map +1 -0
- package/build/src/modeling/ApiModel.js +1 -1
- package/build/src/modeling/ApiModel.js.map +1 -1
- package/build/src/modeling/DataDomain.d.ts +7 -2
- package/build/src/modeling/DataDomain.d.ts.map +1 -1
- package/build/src/modeling/DataDomain.js +15 -2
- package/build/src/modeling/DataDomain.js.map +1 -1
- package/build/src/modeling/DomainAssociation.d.ts +7 -0
- package/build/src/modeling/DomainAssociation.d.ts.map +1 -1
- package/build/src/modeling/DomainAssociation.js +44 -1
- package/build/src/modeling/DomainAssociation.js.map +1 -1
- package/build/src/modeling/DomainEntity.d.ts +6 -0
- package/build/src/modeling/DomainEntity.d.ts.map +1 -1
- package/build/src/modeling/DomainEntity.js +21 -1
- package/build/src/modeling/DomainEntity.js.map +1 -1
- package/build/src/modeling/DomainModel.js +1 -1
- package/build/src/modeling/DomainModel.js.map +1 -1
- package/build/src/modeling/DomainNamespace.js +1 -1
- package/build/src/modeling/DomainNamespace.js.map +1 -1
- package/build/src/modeling/DomainProperty.d.ts +5 -0
- package/build/src/modeling/DomainProperty.d.ts.map +1 -1
- package/build/src/modeling/DomainProperty.js +38 -1
- package/build/src/modeling/DomainProperty.js.map +1 -1
- package/build/src/modeling/DomainSerialization.d.ts +6 -3
- package/build/src/modeling/DomainSerialization.d.ts.map +1 -1
- package/build/src/modeling/DomainSerialization.js +374 -52
- package/build/src/modeling/DomainSerialization.js.map +1 -1
- package/build/src/modeling/types.d.ts +69 -2
- package/build/src/modeling/types.d.ts.map +1 -1
- package/build/src/modeling/types.js.map +1 -1
- package/build/src/models/Thing.js +1 -1
- package/build/src/models/Thing.js.map +1 -1
- package/build/tsconfig.tsbuildinfo +1 -1
- package/data/models/example-generator-api.json +10 -10
- package/package.json +2 -1
- package/src/{modeling → decorators}/observed.ts +5 -5
- package/src/modeling/ApiModel.ts +1 -1
- package/src/modeling/DataDomain.ts +24 -3
- package/src/modeling/DomainAssociation.ts +51 -1
- package/src/modeling/DomainEntity.ts +24 -1
- package/src/modeling/DomainModel.ts +1 -1
- package/src/modeling/DomainNamespace.ts +1 -1
- package/src/modeling/DomainProperty.ts +43 -1
- package/src/modeling/DomainSerialization.ts +440 -56
- package/src/modeling/types.ts +73 -2
- package/src/models/Thing.ts +1 -1
- package/tests/unit/decorators/observed.spec.ts +527 -0
- package/tests/unit/modeling/data_domain_serialization.spec.ts +508 -0
- package/tests/unit/modeling/domain_asociation.spec.ts +376 -0
- package/tests/unit/modeling/domain_entity.spec.ts +147 -0
- package/tests/unit/modeling/domain_property.spec.ts +273 -0
- package/build/src/modeling/observed.d.ts.map +0 -1
- package/build/src/modeling/observed.js.map +0 -1
|
@@ -908,3 +908,379 @@ test.group('DomainAssociation.hasSemantic()', () => {
|
|
|
908
908
|
assert.isFalse(association.hasSemantic(SemanticType.ResourceOwnerIdentifier))
|
|
909
909
|
})
|
|
910
910
|
})
|
|
911
|
+
|
|
912
|
+
test.group('DomainAssociation.duplicate()', () => {
|
|
913
|
+
test('duplicates an association successfully', ({ assert }) => {
|
|
914
|
+
const dataDomain = new DataDomain()
|
|
915
|
+
const model = dataDomain.addModel()
|
|
916
|
+
const entity = model.addEntity()
|
|
917
|
+
const targetEntity = model.addEntity()
|
|
918
|
+
|
|
919
|
+
const association = entity.addAssociation({ key: targetEntity.key })
|
|
920
|
+
association.info.name = 'originalAssociation'
|
|
921
|
+
association.required = true
|
|
922
|
+
association.multiple = false
|
|
923
|
+
|
|
924
|
+
const duplicate = association.duplicate()
|
|
925
|
+
|
|
926
|
+
assert.isDefined(duplicate)
|
|
927
|
+
assert.notEqual(duplicate.key, association.key)
|
|
928
|
+
assert.equal(duplicate.info.name, 'originalAssociation_copy')
|
|
929
|
+
assert.equal(duplicate.required, true)
|
|
930
|
+
assert.equal(duplicate.multiple, false)
|
|
931
|
+
})
|
|
932
|
+
|
|
933
|
+
test('places duplicate right after original association in fields list', ({ assert }) => {
|
|
934
|
+
const dataDomain = new DataDomain()
|
|
935
|
+
const model = dataDomain.addModel()
|
|
936
|
+
const entity = model.addEntity()
|
|
937
|
+
const targetEntity = model.addEntity()
|
|
938
|
+
|
|
939
|
+
// Add multiple fields to test ordering
|
|
940
|
+
const property1 = entity.addProperty({ info: { name: 'first' } })
|
|
941
|
+
const association1 = entity.addAssociation({ key: targetEntity.key })
|
|
942
|
+
association1.info.name = 'originalAssoc'
|
|
943
|
+
const property2 = entity.addProperty({ info: { name: 'second' } })
|
|
944
|
+
|
|
945
|
+
const duplicate = association1.duplicate()
|
|
946
|
+
|
|
947
|
+
// Check that duplicate is placed right after association1
|
|
948
|
+
const fieldKeys = entity.fields.map((f) => f.key)
|
|
949
|
+
const association1Index = fieldKeys.indexOf(association1.key)
|
|
950
|
+
const duplicateIndex = fieldKeys.indexOf(duplicate.key)
|
|
951
|
+
|
|
952
|
+
assert.equal(duplicateIndex, association1Index + 1)
|
|
953
|
+
assert.deepEqual(fieldKeys, [property1.key, association1.key, duplicate.key, property2.key])
|
|
954
|
+
})
|
|
955
|
+
|
|
956
|
+
test('generates unique name when base name conflicts', ({ assert }) => {
|
|
957
|
+
const dataDomain = new DataDomain()
|
|
958
|
+
const model = dataDomain.addModel()
|
|
959
|
+
const entity = model.addEntity()
|
|
960
|
+
const targetEntity = model.addEntity()
|
|
961
|
+
|
|
962
|
+
const association = entity.addAssociation({ key: targetEntity.key })
|
|
963
|
+
association.info.name = 'test'
|
|
964
|
+
// Add another association that conflicts with the first generated name
|
|
965
|
+
const conflictAssoc = entity.addAssociation({ key: targetEntity.key })
|
|
966
|
+
conflictAssoc.info.name = 'test_copy'
|
|
967
|
+
|
|
968
|
+
const duplicate = association.duplicate()
|
|
969
|
+
|
|
970
|
+
assert.equal(duplicate.info.name, 'test_copy_2')
|
|
971
|
+
})
|
|
972
|
+
|
|
973
|
+
test('uses fallback name when original association has no name', ({ assert }) => {
|
|
974
|
+
const dataDomain = new DataDomain()
|
|
975
|
+
const model = dataDomain.addModel()
|
|
976
|
+
const entity = model.addEntity()
|
|
977
|
+
const targetEntity = model.addEntity()
|
|
978
|
+
|
|
979
|
+
const association = entity.addAssociation({ key: targetEntity.key })
|
|
980
|
+
// The association gets the default name "new_association" from schema creation
|
|
981
|
+
assert.equal(association.info.name, 'new_association')
|
|
982
|
+
|
|
983
|
+
const duplicate = association.duplicate()
|
|
984
|
+
|
|
985
|
+
assert.equal(duplicate.info.name, 'new_association_copy')
|
|
986
|
+
})
|
|
987
|
+
|
|
988
|
+
test('uses field fallback when association name is explicitly undefined', ({ assert }) => {
|
|
989
|
+
const dataDomain = new DataDomain()
|
|
990
|
+
const model = dataDomain.addModel()
|
|
991
|
+
const entity = model.addEntity()
|
|
992
|
+
const targetEntity = model.addEntity()
|
|
993
|
+
|
|
994
|
+
const association = entity.addAssociation({ key: targetEntity.key })
|
|
995
|
+
association.info.name = 'test'
|
|
996
|
+
// Manually set name to undefined to test the fallback logic
|
|
997
|
+
association.info.name = undefined
|
|
998
|
+
|
|
999
|
+
const duplicate = association.duplicate()
|
|
1000
|
+
|
|
1001
|
+
assert.equal(duplicate.info.name, 'field_copy')
|
|
1002
|
+
})
|
|
1003
|
+
|
|
1004
|
+
test('does not copy key property', ({ assert }) => {
|
|
1005
|
+
const dataDomain = new DataDomain()
|
|
1006
|
+
const model = dataDomain.addModel()
|
|
1007
|
+
const entity = model.addEntity()
|
|
1008
|
+
const targetEntity = model.addEntity()
|
|
1009
|
+
|
|
1010
|
+
const association = entity.addAssociation({ key: targetEntity.key })
|
|
1011
|
+
const originalKey = association.key
|
|
1012
|
+
|
|
1013
|
+
const duplicate = association.duplicate()
|
|
1014
|
+
|
|
1015
|
+
assert.notEqual(duplicate.key, originalKey)
|
|
1016
|
+
})
|
|
1017
|
+
|
|
1018
|
+
test('does not copy targets initially but recreates them', ({ assert }) => {
|
|
1019
|
+
const dataDomain = new DataDomain()
|
|
1020
|
+
const model = dataDomain.addModel()
|
|
1021
|
+
const entity = model.addEntity()
|
|
1022
|
+
const targetEntity1 = model.addEntity()
|
|
1023
|
+
const targetEntity2 = model.addEntity()
|
|
1024
|
+
|
|
1025
|
+
const association = entity.addAssociation({ key: targetEntity1.key })
|
|
1026
|
+
association.addTarget(targetEntity2.key)
|
|
1027
|
+
association.info.name = 'multiTarget'
|
|
1028
|
+
|
|
1029
|
+
const duplicate = association.duplicate()
|
|
1030
|
+
|
|
1031
|
+
// Should have the same targets but different association instance
|
|
1032
|
+
const originalTargets = [...association.listTargets()]
|
|
1033
|
+
const duplicateTargets = [...duplicate.listTargets()]
|
|
1034
|
+
|
|
1035
|
+
assert.equal(originalTargets.length, duplicateTargets.length)
|
|
1036
|
+
assert.equal(originalTargets.length, 2)
|
|
1037
|
+
|
|
1038
|
+
// Check that target keys match
|
|
1039
|
+
const originalKeys = originalTargets.map((t) => t.key).sort()
|
|
1040
|
+
const duplicateKeys = duplicateTargets.map((t) => t.key).sort()
|
|
1041
|
+
assert.deepEqual(originalKeys, duplicateKeys)
|
|
1042
|
+
})
|
|
1043
|
+
|
|
1044
|
+
test('copies all other association attributes', ({ assert }) => {
|
|
1045
|
+
const dataDomain = new DataDomain()
|
|
1046
|
+
const model = dataDomain.addModel()
|
|
1047
|
+
const entity = model.addEntity()
|
|
1048
|
+
const targetEntity = model.addEntity()
|
|
1049
|
+
|
|
1050
|
+
const association = entity.addAssociation({ key: targetEntity.key })
|
|
1051
|
+
association.info.name = 'complexAssociation'
|
|
1052
|
+
association.info.description = 'A complex association'
|
|
1053
|
+
association.required = true
|
|
1054
|
+
association.multiple = true
|
|
1055
|
+
association.readOnly = true
|
|
1056
|
+
association.onDelete = 'cascade'
|
|
1057
|
+
association.semantics = [{ id: SemanticType.ResourceOwnerIdentifier }]
|
|
1058
|
+
association.schema = { linked: true, unionType: 'allOf' }
|
|
1059
|
+
association.bindings = [{ type: 'web', schema: { hidden: true } }]
|
|
1060
|
+
|
|
1061
|
+
const duplicate = association.duplicate()
|
|
1062
|
+
|
|
1063
|
+
assert.equal(duplicate.info.name, 'complexAssociation_copy')
|
|
1064
|
+
assert.equal(duplicate.info.description, 'A complex association')
|
|
1065
|
+
assert.equal(duplicate.required, true)
|
|
1066
|
+
assert.equal(duplicate.multiple, true)
|
|
1067
|
+
assert.equal(duplicate.readOnly, true)
|
|
1068
|
+
assert.equal(duplicate.onDelete, 'cascade')
|
|
1069
|
+
assert.deepEqual(duplicate.semantics, [{ id: SemanticType.ResourceOwnerIdentifier }])
|
|
1070
|
+
assert.deepEqual(duplicate.schema, { linked: true, unionType: 'allOf' })
|
|
1071
|
+
assert.deepEqual(duplicate.bindings, [{ type: 'web', schema: { hidden: true } }])
|
|
1072
|
+
})
|
|
1073
|
+
|
|
1074
|
+
test('creates independent copy of schema and bindings', ({ assert }) => {
|
|
1075
|
+
const dataDomain = new DataDomain()
|
|
1076
|
+
const model = dataDomain.addModel()
|
|
1077
|
+
const entity = model.addEntity()
|
|
1078
|
+
const targetEntity = model.addEntity()
|
|
1079
|
+
|
|
1080
|
+
const association = entity.addAssociation({ key: targetEntity.key })
|
|
1081
|
+
association.info.name = 'original'
|
|
1082
|
+
association.schema = { linked: false, unionType: 'anyOf' }
|
|
1083
|
+
association.bindings = [{ type: 'web', schema: { hidden: false } }]
|
|
1084
|
+
|
|
1085
|
+
const duplicate = association.duplicate()
|
|
1086
|
+
|
|
1087
|
+
// Modify original schema and bindings
|
|
1088
|
+
association.schema!.linked = true
|
|
1089
|
+
association.bindings[0].schema = { hidden: true }
|
|
1090
|
+
|
|
1091
|
+
// Duplicate should be unaffected
|
|
1092
|
+
assert.equal(duplicate.schema!.linked, false)
|
|
1093
|
+
assert.deepEqual(duplicate.bindings[0].schema, { hidden: false })
|
|
1094
|
+
})
|
|
1095
|
+
|
|
1096
|
+
test('copies targets correctly', ({ assert }) => {
|
|
1097
|
+
const dataDomain = new DataDomain()
|
|
1098
|
+
const model = dataDomain.addModel()
|
|
1099
|
+
const entity = model.addEntity()
|
|
1100
|
+
|
|
1101
|
+
const targetEntity1 = model.addEntity()
|
|
1102
|
+
const targetEntity2 = model.addEntity()
|
|
1103
|
+
|
|
1104
|
+
const association = entity.addAssociation()
|
|
1105
|
+
association.addTarget(targetEntity1.key)
|
|
1106
|
+
association.addTarget(targetEntity2.key)
|
|
1107
|
+
association.info.name = 'multiTargetAssoc'
|
|
1108
|
+
|
|
1109
|
+
// Check that original association has targets
|
|
1110
|
+
const originalTargets = [...association.listTargets()]
|
|
1111
|
+
assert.equal(originalTargets.length, 2)
|
|
1112
|
+
|
|
1113
|
+
const duplicate = association.duplicate()
|
|
1114
|
+
|
|
1115
|
+
// Check targets on duplicate
|
|
1116
|
+
const duplicateTargets = [...duplicate.listTargets()]
|
|
1117
|
+
const duplicateTargetObjects = duplicate.targets
|
|
1118
|
+
|
|
1119
|
+
// Check targets array structure
|
|
1120
|
+
assert.equal(duplicateTargetObjects.length, 2)
|
|
1121
|
+
assert.equal(duplicateTargetObjects[0].key, targetEntity1.key)
|
|
1122
|
+
assert.equal(duplicateTargetObjects[1].key, targetEntity2.key)
|
|
1123
|
+
|
|
1124
|
+
// Check resolved targets
|
|
1125
|
+
assert.equal(duplicateTargets.length, 2)
|
|
1126
|
+
const duplicateKeys = duplicateTargets.map((t) => t.key).sort()
|
|
1127
|
+
const expectedKeys = [targetEntity1.key, targetEntity2.key].sort()
|
|
1128
|
+
assert.deepEqual(duplicateKeys, expectedKeys)
|
|
1129
|
+
})
|
|
1130
|
+
|
|
1131
|
+
test('notifies domain of changes', ({ assert }) => {
|
|
1132
|
+
const dataDomain = new DataDomain()
|
|
1133
|
+
const model = dataDomain.addModel()
|
|
1134
|
+
const entity = model.addEntity()
|
|
1135
|
+
const targetEntity = model.addEntity()
|
|
1136
|
+
|
|
1137
|
+
const association = entity.addAssociation({ key: targetEntity.key })
|
|
1138
|
+
association.info.name = 'test'
|
|
1139
|
+
|
|
1140
|
+
let notificationCalled = false
|
|
1141
|
+
const originalNotify = dataDomain.notifyChange
|
|
1142
|
+
dataDomain.notifyChange = () => {
|
|
1143
|
+
notificationCalled = true
|
|
1144
|
+
originalNotify.call(dataDomain)
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
association.duplicate()
|
|
1148
|
+
|
|
1149
|
+
assert.isTrue(notificationCalled)
|
|
1150
|
+
|
|
1151
|
+
// Restore original method
|
|
1152
|
+
dataDomain.notifyChange = originalNotify
|
|
1153
|
+
})
|
|
1154
|
+
|
|
1155
|
+
test('throws error when association has no parent entity', ({ assert }) => {
|
|
1156
|
+
const dataDomain = new DataDomain()
|
|
1157
|
+
const association = new DomainAssociation(dataDomain, 'non-existent-parent', {
|
|
1158
|
+
info: { name: 'orphan' },
|
|
1159
|
+
})
|
|
1160
|
+
|
|
1161
|
+
assert.throws(() => {
|
|
1162
|
+
association.duplicate()
|
|
1163
|
+
}, 'Cannot duplicate association')
|
|
1164
|
+
})
|
|
1165
|
+
|
|
1166
|
+
test('throws error when association is not in parent entity fields list', ({ assert }) => {
|
|
1167
|
+
const dataDomain = new DataDomain()
|
|
1168
|
+
const model = dataDomain.addModel()
|
|
1169
|
+
const entity = model.addEntity()
|
|
1170
|
+
const association = new DomainAssociation(dataDomain, entity.key, {
|
|
1171
|
+
info: { name: 'detached' },
|
|
1172
|
+
})
|
|
1173
|
+
|
|
1174
|
+
// Add association to graph but not to entity fields
|
|
1175
|
+
dataDomain.graph.setNode(association.key, association)
|
|
1176
|
+
|
|
1177
|
+
assert.throws(() => {
|
|
1178
|
+
association.duplicate()
|
|
1179
|
+
}, 'does not exist on the parent entity fields list')
|
|
1180
|
+
})
|
|
1181
|
+
|
|
1182
|
+
test('works with empty entity fields list', ({ assert }) => {
|
|
1183
|
+
const dataDomain = new DataDomain()
|
|
1184
|
+
const model = dataDomain.addModel()
|
|
1185
|
+
const entity = model.addEntity()
|
|
1186
|
+
const targetEntity = model.addEntity()
|
|
1187
|
+
const association = entity.addAssociation({ key: targetEntity.key })
|
|
1188
|
+
association.info.name = 'only'
|
|
1189
|
+
|
|
1190
|
+
const duplicate = association.duplicate()
|
|
1191
|
+
|
|
1192
|
+
assert.equal(entity.fields.length, 2)
|
|
1193
|
+
assert.equal(entity.fields[0].key, association.key)
|
|
1194
|
+
assert.equal(entity.fields[1].key, duplicate.key)
|
|
1195
|
+
})
|
|
1196
|
+
|
|
1197
|
+
test('handles duplication with mixed field types', ({ assert }) => {
|
|
1198
|
+
const dataDomain = new DataDomain()
|
|
1199
|
+
const model = dataDomain.addModel()
|
|
1200
|
+
const entity = model.addEntity()
|
|
1201
|
+
const targetEntity = model.addEntity()
|
|
1202
|
+
|
|
1203
|
+
const property1 = entity.addProperty({ info: { name: 'prop1' } })
|
|
1204
|
+
const association1 = entity.addAssociation({ key: targetEntity.key })
|
|
1205
|
+
association1.info.name = 'assoc1'
|
|
1206
|
+
const property2 = entity.addProperty({ info: { name: 'prop2' } })
|
|
1207
|
+
|
|
1208
|
+
const duplicate = association1.duplicate()
|
|
1209
|
+
|
|
1210
|
+
// Should maintain correct order
|
|
1211
|
+
const fieldKeys = entity.fields.map((f) => f.key)
|
|
1212
|
+
assert.deepEqual(fieldKeys, [property1.key, association1.key, duplicate.key, property2.key])
|
|
1213
|
+
})
|
|
1214
|
+
|
|
1215
|
+
test('preserves field types correctly', ({ assert }) => {
|
|
1216
|
+
const dataDomain = new DataDomain()
|
|
1217
|
+
const model = dataDomain.addModel()
|
|
1218
|
+
const entity = model.addEntity()
|
|
1219
|
+
const targetEntity = model.addEntity()
|
|
1220
|
+
const association = entity.addAssociation({ key: targetEntity.key })
|
|
1221
|
+
|
|
1222
|
+
const duplicate = association.duplicate()
|
|
1223
|
+
|
|
1224
|
+
// Check that both original and duplicate have correct field type
|
|
1225
|
+
const originalField = entity.fields.find((f) => f.key === association.key)
|
|
1226
|
+
const duplicateField = entity.fields.find((f) => f.key === duplicate.key)
|
|
1227
|
+
|
|
1228
|
+
assert.equal(originalField?.type, 'association')
|
|
1229
|
+
assert.equal(duplicateField?.type, 'association')
|
|
1230
|
+
})
|
|
1231
|
+
|
|
1232
|
+
test('handles multiple target entities correctly', ({ assert }) => {
|
|
1233
|
+
const dataDomain = new DataDomain()
|
|
1234
|
+
const model = dataDomain.addModel()
|
|
1235
|
+
const entity = model.addEntity()
|
|
1236
|
+
const targetEntity1 = model.addEntity()
|
|
1237
|
+
const targetEntity2 = model.addEntity()
|
|
1238
|
+
const targetEntity3 = model.addEntity()
|
|
1239
|
+
|
|
1240
|
+
const association = entity.addAssociation()
|
|
1241
|
+
association.addTarget(targetEntity1.key)
|
|
1242
|
+
association.addTarget(targetEntity2.key)
|
|
1243
|
+
association.addTarget(targetEntity3.key)
|
|
1244
|
+
association.info.name = 'multiTarget'
|
|
1245
|
+
|
|
1246
|
+
const duplicate = association.duplicate()
|
|
1247
|
+
|
|
1248
|
+
const originalTargets = [...association.listTargets()]
|
|
1249
|
+
const duplicateTargets = [...duplicate.listTargets()]
|
|
1250
|
+
|
|
1251
|
+
assert.equal(originalTargets.length, 3)
|
|
1252
|
+
assert.equal(duplicateTargets.length, 3)
|
|
1253
|
+
|
|
1254
|
+
// Verify all targets are copied correctly
|
|
1255
|
+
const originalKeys = originalTargets.map((t) => t.key).sort()
|
|
1256
|
+
const duplicateKeys = duplicateTargets.map((t) => t.key).sort()
|
|
1257
|
+
assert.deepEqual(originalKeys, duplicateKeys)
|
|
1258
|
+
})
|
|
1259
|
+
|
|
1260
|
+
test('handles foreign domains correctly', ({ assert }) => {
|
|
1261
|
+
const fd = new DataDomain()
|
|
1262
|
+
const fd1 = fd.addModel()
|
|
1263
|
+
const fe1 = fd1.addEntity()
|
|
1264
|
+
fd.info.version = '1.0.0'
|
|
1265
|
+
|
|
1266
|
+
const dataDomain = new DataDomain()
|
|
1267
|
+
const model = dataDomain.addModel()
|
|
1268
|
+
const entity = model.addEntity()
|
|
1269
|
+
dataDomain.registerForeignDomain(fd)
|
|
1270
|
+
|
|
1271
|
+
const association = entity.addAssociation({ key: fe1.key, domain: fd.key })
|
|
1272
|
+
|
|
1273
|
+
const duplicate = association.duplicate()
|
|
1274
|
+
|
|
1275
|
+
const originalTargets = [...association.listTargets()]
|
|
1276
|
+
const duplicateTargets = [...duplicate.listTargets()]
|
|
1277
|
+
|
|
1278
|
+
assert.equal(originalTargets.length, 1)
|
|
1279
|
+
assert.equal(duplicateTargets.length, 1)
|
|
1280
|
+
|
|
1281
|
+
// Verify all targets are copied correctly
|
|
1282
|
+
const originalKeys = originalTargets.map((t) => t.key).sort()
|
|
1283
|
+
const duplicateKeys = duplicateTargets.map((t) => t.key).sort()
|
|
1284
|
+
assert.deepEqual(originalKeys, duplicateKeys)
|
|
1285
|
+
})
|
|
1286
|
+
})
|
|
@@ -729,3 +729,150 @@ test.group('DomainEntity.isChildOf()', () => {
|
|
|
729
729
|
assert.isTrue(entity.isChildOf(dataDomain.key))
|
|
730
730
|
})
|
|
731
731
|
})
|
|
732
|
+
|
|
733
|
+
test.group('DomainEntity.generateUniqueName()', () => {
|
|
734
|
+
test('generates unique name when no fields exist', ({ assert }) => {
|
|
735
|
+
const dataDomain = new DataDomain()
|
|
736
|
+
const model = dataDomain.addModel()
|
|
737
|
+
const entity = model.addEntity()
|
|
738
|
+
|
|
739
|
+
const uniqueName = entity.generateUniqueName('test')
|
|
740
|
+
assert.equal(uniqueName, 'test_copy')
|
|
741
|
+
})
|
|
742
|
+
|
|
743
|
+
test('generates unique name when base name does not conflict', ({ assert }) => {
|
|
744
|
+
const dataDomain = new DataDomain()
|
|
745
|
+
const model = dataDomain.addModel()
|
|
746
|
+
const entity = model.addEntity()
|
|
747
|
+
|
|
748
|
+
// Add a property with a different name
|
|
749
|
+
entity.addProperty({ info: { name: 'existing_field' } })
|
|
750
|
+
|
|
751
|
+
const uniqueName = entity.generateUniqueName('test')
|
|
752
|
+
assert.equal(uniqueName, 'test_copy')
|
|
753
|
+
})
|
|
754
|
+
|
|
755
|
+
test('generates unique name when base_copy conflicts with existing property', ({ assert }) => {
|
|
756
|
+
const dataDomain = new DataDomain()
|
|
757
|
+
const model = dataDomain.addModel()
|
|
758
|
+
const entity = model.addEntity()
|
|
759
|
+
|
|
760
|
+
// Add a property that conflicts with the first generated name
|
|
761
|
+
entity.addProperty({ info: { name: 'test_copy' } })
|
|
762
|
+
|
|
763
|
+
const uniqueName = entity.generateUniqueName('test')
|
|
764
|
+
assert.equal(uniqueName, 'test_copy_2')
|
|
765
|
+
})
|
|
766
|
+
|
|
767
|
+
test('generates unique name when multiple conflicts exist with properties', ({ assert }) => {
|
|
768
|
+
const dataDomain = new DataDomain()
|
|
769
|
+
const model = dataDomain.addModel()
|
|
770
|
+
const entity = model.addEntity()
|
|
771
|
+
|
|
772
|
+
// Add properties that conflict with multiple generated names
|
|
773
|
+
entity.addProperty({ info: { name: 'test_copy' } })
|
|
774
|
+
entity.addProperty({ info: { name: 'test_copy_2' } })
|
|
775
|
+
entity.addProperty({ info: { name: 'test_copy_3' } })
|
|
776
|
+
|
|
777
|
+
const uniqueName = entity.generateUniqueName('test')
|
|
778
|
+
assert.equal(uniqueName, 'test_copy_4')
|
|
779
|
+
})
|
|
780
|
+
|
|
781
|
+
test('generates unique name when conflicts exist with associations', ({ assert }) => {
|
|
782
|
+
const dataDomain = new DataDomain()
|
|
783
|
+
const model = dataDomain.addModel()
|
|
784
|
+
const entity = model.addEntity()
|
|
785
|
+
const targetEntity = model.addEntity()
|
|
786
|
+
|
|
787
|
+
// Add an association that conflicts with the first generated name
|
|
788
|
+
const association = entity.addAssociation({ key: targetEntity.key })
|
|
789
|
+
association.info.name = 'test_copy'
|
|
790
|
+
|
|
791
|
+
const uniqueName = entity.generateUniqueName('test')
|
|
792
|
+
assert.equal(uniqueName, 'test_copy_2')
|
|
793
|
+
})
|
|
794
|
+
|
|
795
|
+
test('generates unique name when conflicts exist with both properties and associations', ({ assert }) => {
|
|
796
|
+
const dataDomain = new DataDomain()
|
|
797
|
+
const model = dataDomain.addModel()
|
|
798
|
+
const entity = model.addEntity()
|
|
799
|
+
const targetEntity = model.addEntity()
|
|
800
|
+
|
|
801
|
+
// Add property and association with conflicting names
|
|
802
|
+
entity.addProperty({ info: { name: 'test_copy' } })
|
|
803
|
+
const association = entity.addAssociation({ key: targetEntity.key })
|
|
804
|
+
association.info.name = 'test_copy_2'
|
|
805
|
+
|
|
806
|
+
const uniqueName = entity.generateUniqueName('test')
|
|
807
|
+
assert.equal(uniqueName, 'test_copy_3')
|
|
808
|
+
})
|
|
809
|
+
|
|
810
|
+
test('handles fields with undefined names', ({ assert }) => {
|
|
811
|
+
const dataDomain = new DataDomain()
|
|
812
|
+
const model = dataDomain.addModel()
|
|
813
|
+
const entity = model.addEntity()
|
|
814
|
+
const targetEntity = model.addEntity()
|
|
815
|
+
|
|
816
|
+
// Add property without a name (undefined name)
|
|
817
|
+
entity.addProperty({ info: {} })
|
|
818
|
+
// Add association without a name
|
|
819
|
+
entity.addAssociation({ key: targetEntity.key })
|
|
820
|
+
|
|
821
|
+
const uniqueName = entity.generateUniqueName('test')
|
|
822
|
+
assert.equal(uniqueName, 'test_copy')
|
|
823
|
+
})
|
|
824
|
+
|
|
825
|
+
test('generates incrementing counter correctly', ({ assert }) => {
|
|
826
|
+
const dataDomain = new DataDomain()
|
|
827
|
+
const model = dataDomain.addModel()
|
|
828
|
+
const entity = model.addEntity()
|
|
829
|
+
|
|
830
|
+
// Add many conflicting properties to test counter increment
|
|
831
|
+
for (let i = 0; i < 10; i++) {
|
|
832
|
+
const name = i === 0 ? 'test_copy' : `test_copy_${i + 1}`
|
|
833
|
+
entity.addProperty({ info: { name } })
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
const uniqueName = entity.generateUniqueName('test')
|
|
837
|
+
assert.equal(uniqueName, 'test_copy_11')
|
|
838
|
+
})
|
|
839
|
+
|
|
840
|
+
test('works with different base names', ({ assert }) => {
|
|
841
|
+
const dataDomain = new DataDomain()
|
|
842
|
+
const model = dataDomain.addModel()
|
|
843
|
+
const entity = model.addEntity()
|
|
844
|
+
|
|
845
|
+
entity.addProperty({ info: { name: 'user_copy' } })
|
|
846
|
+
entity.addProperty({ info: { name: 'product_copy' } })
|
|
847
|
+
|
|
848
|
+
const userUnique = entity.generateUniqueName('user')
|
|
849
|
+
const productUnique = entity.generateUniqueName('product')
|
|
850
|
+
const orderUnique = entity.generateUniqueName('order')
|
|
851
|
+
|
|
852
|
+
assert.equal(userUnique, 'user_copy_2')
|
|
853
|
+
assert.equal(productUnique, 'product_copy_2')
|
|
854
|
+
assert.equal(orderUnique, 'order_copy')
|
|
855
|
+
})
|
|
856
|
+
|
|
857
|
+
test('handles empty base name', ({ assert }) => {
|
|
858
|
+
const dataDomain = new DataDomain()
|
|
859
|
+
const model = dataDomain.addModel()
|
|
860
|
+
const entity = model.addEntity()
|
|
861
|
+
|
|
862
|
+
const uniqueName = entity.generateUniqueName('')
|
|
863
|
+
assert.equal(uniqueName, '_copy')
|
|
864
|
+
})
|
|
865
|
+
|
|
866
|
+
test('case sensitive name comparison', ({ assert }) => {
|
|
867
|
+
const dataDomain = new DataDomain()
|
|
868
|
+
const model = dataDomain.addModel()
|
|
869
|
+
const entity = model.addEntity()
|
|
870
|
+
|
|
871
|
+
// Add property with uppercase name
|
|
872
|
+
entity.addProperty({ info: { name: 'TEST_COPY' } })
|
|
873
|
+
|
|
874
|
+
// Should not conflict because comparison is case-sensitive
|
|
875
|
+
const uniqueName = entity.generateUniqueName('test')
|
|
876
|
+
assert.equal(uniqueName, 'test_copy')
|
|
877
|
+
})
|
|
878
|
+
})
|