diff --git a/mdm-plugin-datamodel/grails-app/services/uk/ac/ox/softeng/maurodatamapper/datamodel/item/DataClassService.groovy b/mdm-plugin-datamodel/grails-app/services/uk/ac/ox/softeng/maurodatamapper/datamodel/item/DataClassService.groovy index b94f0f7e0d..12f6cc0f1c 100644 --- a/mdm-plugin-datamodel/grails-app/services/uk/ac/ox/softeng/maurodatamapper/datamodel/item/DataClassService.groovy +++ b/mdm-plugin-datamodel/grails-app/services/uk/ac/ox/softeng/maurodatamapper/datamodel/item/DataClassService.groovy @@ -97,21 +97,21 @@ class DataClassService extends ModelItemService implements SummaryMet saveDataTypesUsedInDataClass(domain) } } - if(args.deepSave){ + if (args.deepSave) { this.updateDataClassHierarchyAfterInsert(args, domain) } super.save(args, domain) } - void updateDataClassHierarchyAfterInsert(Map args, DataClass dataClass){ - if(dataClass.dataElements){ - dataClass.dataElements.each{de -> + void updateDataClassHierarchyAfterInsert(Map args, DataClass dataClass) { + if (dataClass.dataElements) { + dataClass.dataElements.each {de -> dataElementService.save(de) } } - if(dataClass.dataClasses){ - dataClass.dataClasses.each{dc -> + if (dataClass.dataClasses) { + dataClass.dataClasses.each {dc -> updateDataClassHierarchyAfterInsert(args, dc) } } @@ -122,13 +122,13 @@ class DataClassService extends ModelItemService implements SummaryMet Set dataTypes = extractAllUsedNewOrDirtyDataTypes(dataClass) log.debug('{} new or dirty used datatypes inside dataclass', dataTypes.size()) // Validation should have already been done - dataTypes.each { it.skipValidation(true) } + dataTypes.each {it.skipValidation(true)} dataTypeService.saveAll(dataTypes, false) } Set extractAllUsedNewOrDirtyDataTypes(DataClass dataClass) { - Set dataTypes = dataClass.dataElements.collect { it.dataType }.findAll { it.isDirty() || !it.ident() }.toSet() - dataTypes.addAll(dataClass.dataClasses.collect { extractAllUsedNewOrDirtyDataTypes(it) }.flatten().toSet() as Collection) + Set dataTypes = dataClass.dataElements.collect {it.dataType}.findAll {it.isDirty() || !it.ident()}.toSet() + dataTypes.addAll(dataClass.dataClasses.collect {extractAllUsedNewOrDirtyDataTypes(it)}.flatten().toSet() as Collection) dataTypes } @@ -152,7 +152,7 @@ class DataClassService extends ModelItemService implements SummaryMet dataClass.save(flush: false, validate: false) // Recurse through the hierarchy - dataClasses?.each { dc -> + dataClasses?.each {dc -> saveDataClassHierarchy(dc) } @@ -229,10 +229,10 @@ class DataClassService extends ModelItemService implements SummaryMet DataClass checkFacetsAfterImportingCatalogueItem(DataClass catalogueItem) { super.checkFacetsAfterImportingCatalogueItem(catalogueItem) if (catalogueItem.summaryMetadata) { - catalogueItem.summaryMetadata.each { sm -> + catalogueItem.summaryMetadata.each {sm -> sm.multiFacetAwareItemId = catalogueItem.id sm.createdBy = sm.createdBy ?: catalogueItem.createdBy - sm.summaryMetadataReports.each { smr -> + sm.summaryMetadataReports.each {smr -> smr.createdBy = catalogueItem.createdBy } } @@ -249,16 +249,16 @@ class DataClassService extends ModelItemService implements SummaryMet } Collection saveAllAndGetDataElements(Collection dataClasses) { - if(!dataClasses) return [] + if (!dataClasses) return [] - List classifiers = dataClasses.collectMany { it.classifiers ?: [] } as List + List classifiers = dataClasses.collectMany {it.classifiers ?: []} as List if (classifiers) { log.trace('Saving {} classifiers') classifierService.saveAll(classifiers) } - Collection alreadySaved = dataClasses.findAll { it.ident() && it.isDirty() } - Collection notSaved = dataClasses.findAll { !it.ident() } + Collection alreadySaved = dataClasses.findAll {it.ident() && it.isDirty()} + Collection notSaved = dataClasses.findAll {!it.ident()} Collection dataElements = [] @@ -273,10 +273,10 @@ class DataClassService extends ModelItemService implements SummaryMet int count = 0 // Find all DCs which are either top level or have their parent DC already saved - Collection parentIsSaved = notSaved.findAll { !it.parentDataClass || it.parentDataClass.id } + Collection parentIsSaved = notSaved.findAll {!it.parentDataClass || it.parentDataClass.id} log.trace('Ready to save on first run {}', parentIsSaved.size()) while (parentIsSaved) { - parentIsSaved.each { dc -> + parentIsSaved.each {dc -> dataElements.addAll dc.dataElements ?: [] dc.dataClasses?.clear() @@ -296,7 +296,7 @@ class DataClassService extends ModelItemService implements SummaryMet batch.clear() // Find all DCs which have a saved parent DC notSaved.removeAll(parentIsSaved) - parentIsSaved = notSaved.findAll { it.parentDataClass && it.parentDataClass.id } + parentIsSaved = notSaved.findAll {it.parentDataClass && it.parentDataClass.id} log.trace('Ready to save on subsequent run {}', parentIsSaved.size()) } } @@ -308,29 +308,29 @@ class DataClassService extends ModelItemService implements SummaryMet removeReferenceTypes(dataClass) dataClass.breadcrumbTree.removeFromParent() dataClass.dataModel.removeFromDataClasses(dataClass) - dataClass.dataClasses?.each { removeAssociations(it) } + dataClass.dataClasses?.each {removeAssociations(it)} } private void removeSemanticLinks(DataClass dataClass) { List semanticLinks = semanticLinkService.findAllByMultiFacetAwareItemId(dataClass.id) - semanticLinks.each { semanticLinkService.delete(it) } + semanticLinks.each {semanticLinkService.delete(it)} } private void removeReferenceTypes(DataClass dataClass) { List referenceTypes = new ArrayList<>(dataClass.referenceTypes.findAll()) - referenceTypes.each { dataTypeService.delete(it) } + referenceTypes.each {dataTypeService.delete(it)} } private void removeAllDataElementsWithNoLabel(DataClass dataClass) { - List dataElements = new ArrayList<>(dataClass.dataElements.findAll { !it.label }) - dataElements.each { dataElementService.delete(it) } + List dataElements = new ArrayList<>(dataClass.dataElements.findAll {!it.label}) + dataElements.each {dataElementService.delete(it)} } private void removeAllDataElementsWithSameLabel(DataClass dataClass) { if (dataClass.dataElements) { - Map> identicalDataElements = dataClass.dataElements.groupBy { it.label }.findAll { it.value.size() > 1 } - identicalDataElements.each { label, dataElements -> + Map> identicalDataElements = dataClass.dataElements.groupBy {it.label}.findAll {it.value.size() > 1} + identicalDataElements.each {label, dataElements -> for (int i = 1; i < dataElements.size(); i++) { dataElementService.delete(dataElements[i]) } @@ -340,8 +340,8 @@ class DataClassService extends ModelItemService implements SummaryMet private void ensureChildDataClassesHaveUniqueNames(DataClass dataClass) { if (dataClass.dataClasses) { - dataClass.dataClasses.groupBy { it.label }.findAll { it.value.size() > 1 }.each { label, dataClasses -> - dataClasses.eachWithIndex { DataClass child, int i -> + dataClass.dataClasses.groupBy {it.label}.findAll {it.value.size() > 1}.each {label, dataClasses -> + dataClasses.eachWithIndex {DataClass child, int i -> child.label = "${child.label}-$i" } } @@ -351,10 +351,10 @@ class DataClassService extends ModelItemService implements SummaryMet private void collapseReferenceTypes(DataClass dataClass) { if (!dataClass.referenceTypes || dataClass.referenceTypes.size() == 1) return DataModel dataModel = dataClass.dataModel - Map> labelGroupedReferenceTypes = dataClass.referenceTypes.groupBy { it.label } + Map> labelGroupedReferenceTypes = dataClass.referenceTypes.groupBy {it.label} - labelGroupedReferenceTypes.findAll { it.value.size() > 1 }.each { label, labelReferenceTypes -> - Map> dmGrouped = labelReferenceTypes.groupBy { it.dataModel ? 'dataModel' : 'noDataModel' } + labelGroupedReferenceTypes.findAll {it.value.size() > 1}.each {label, labelReferenceTypes -> + Map> dmGrouped = labelReferenceTypes.groupBy {it.dataModel ? 'dataModel' : 'noDataModel'} // There will be only 1 datamodel owned type as we've already merged datamodel owned datatypes if (dmGrouped.dataModel) { @@ -371,11 +371,11 @@ class DataClassService extends ModelItemService implements SummaryMet private void setCreatedBy(User creator, DataClass dataClass) { dataClass.createdBy = creator.emailAddress - dataClass.dataClasses?.each { dc -> + dataClass.dataClasses?.each {dc -> setCreatedBy(creator, dc) } - dataClass.dataElements?.each { de -> + dataClass.dataElements?.each {de -> de.createdBy = creator.emailAddress } } @@ -387,13 +387,13 @@ class DataClassService extends ModelItemService implements SummaryMet checkFacetsAfterImportingCatalogueItem(dataClass) if (dataClass.dataClasses) { dataClass.fullSortOfChildren(dataClass.dataClasses) - dataClass.dataClasses.each { dc -> + dataClass.dataClasses.each {dc -> checkImportedDataClassAssociations(importingUser, dataModel, dc, matchDataTypes) } } if (dataClass.dataElements) { dataClass.fullSortOfChildren(dataClass.dataElements) - dataClass.dataElements.each { de -> + dataClass.dataElements.each {de -> de.createdBy = importingUser.emailAddress de.checkPath() dataElementService.checkFacetsAfterImportingCatalogueItem(de) @@ -403,7 +403,7 @@ class DataClassService extends ModelItemService implements SummaryMet } DataClass findSameLabelTree(DataModel dataModel, DataClass searchFor) { - dataModel.dataClasses.find { hasSameLabelTree(it, searchFor) } + dataModel.dataClasses.find {hasSameLabelTree(it, searchFor)} } private boolean hasSameLabelTree(DataClass left, DataClass right) { @@ -638,11 +638,11 @@ WHERE } DataClass findDataClass(DataModel dataModel, String label) { - dataModel.dataClasses.find { !it.parentDataClass && it.label == label.trim() } + dataModel.dataClasses.find {!it.parentDataClass && it.label == label.trim()} } DataClass findDataClass(DataClass parentDataClass, String label) { - parentDataClass.dataClasses.find { it.label == label.trim() } + parentDataClass.dataClasses.find {it.label == label.trim()} } DataClass findDataClassByPath(DataModel dataModel, List pathLabels) { @@ -704,7 +704,7 @@ WHERE DataClass copy = new DataClass( minMultiplicity: original.minMultiplicity, - maxMultiplicity: original.maxMultiplicity, + maxMultiplicity: original.maxMultiplicity ) copy = copyModelItemInformation(original, copy, copier, userSecurityPolicyManager, copySummaryMetadata, copyInformation) @@ -721,8 +721,8 @@ WHERE List referenceTypes = ReferenceType.by().eq('referenceClass.id', original.id).list() - referenceTypes.sort().each { refType -> - ReferenceType referenceType = copiedDataModel.referenceTypes.find { it.label == refType.label } + referenceTypes.sort().each {refType -> + ReferenceType referenceType = copiedDataModel.referenceTypes.find {it.label == refType.label} if (!referenceType) { referenceType = new ReferenceType(createdBy: copier.emailAddress, label: refType.label) copiedDataModel.addToDataTypes(referenceType) @@ -733,15 +733,15 @@ WHERE copy.dataClasses = [] List dataClasses = DataClass.byParentDataClassId(original.id).join('classifiers').list() - CopyInformation dataClassCache = cacheFacetInformationForCopy(dataClasses.collect { it.id }, new CopyInformation(copyIndex: true)) - dataClasses.sort().each { child -> + CopyInformation dataClassCache = cacheFacetInformationForCopy(dataClasses.collect {it.id}, new CopyInformation(copyIndex: true)) + dataClasses.sort().each {child -> copyDataClass(copiedDataModel, child, copier, userSecurityPolicyManager, copy, copySummaryMetadata, dataClassCache) } copy.dataElements = [] List dataElements = DataElement.byDataClassId(original.id).join('classifiers').list() - CopyInformation dataElementCache = cacheFacetInformationForCopy(dataElements.collect { it.id }, new CopyInformation(copyIndex: true)) - dataElements.sort().each { element -> + CopyInformation dataElementCache = cacheFacetInformationForCopy(dataElements.collect {it.id}, new CopyInformation(copyIndex: true)) + dataElements.sort().each {element -> copy.addToDataElements( dataElementService .copyDataElement(copiedDataModel, element, copier, userSecurityPolicyManager, copySummaryMetadata, dataElementCache)) @@ -751,10 +751,10 @@ WHERE } DataClass copyModelItemInformation(DataClass original, - DataClass copy, - User copier, - UserSecurityPolicyManager userSecurityPolicyManager, - boolean copySummaryMetadata, CopyInformation copyInformation) { + DataClass copy, + User copier, + UserSecurityPolicyManager userSecurityPolicyManager, + boolean copySummaryMetadata, CopyInformation copyInformation) { copy = super.copyModelItemInformation(original, copy, copier, userSecurityPolicyManager, copyInformation) if (copySummaryMetadata) { @@ -765,9 +765,9 @@ WHERE @Override DataClass copyModelItemInformation(DataClass original, - DataClass copy, - User copier, - UserSecurityPolicyManager userSecurityPolicyManager, CopyInformation copyInformation = null) { + DataClass copy, + User copier, + UserSecurityPolicyManager userSecurityPolicyManager, CopyInformation copyInformation = null) { copyModelItemInformation(original, copy, copier, userSecurityPolicyManager, false, copyInformation) } @@ -777,7 +777,7 @@ WHERE if (!emptyReferenceTypes) return log.debug('Found {} empty reference types', emptyReferenceTypes.size()) // Copy all the missing reference classes - emptyReferenceTypes.each { rt -> + emptyReferenceTypes.each {rt -> ReferenceType ort = originalDataModel.findDataTypeByLabel(rt.label) as ReferenceType String originalDataClassPath = buildPath(ort.referenceClass) DataClass copiedDataClass = findDataClassByPath(copiedDataModel, originalDataClassPath.split(/\|/).toList()) @@ -792,7 +792,7 @@ WHERE } private Set findAllEmptyReferenceTypes(DataModel dataModel) { - dataModel.referenceTypes.findAll { !(it as ReferenceType).referenceClass } as Set + dataModel.referenceTypes.findAll {!(it as ReferenceType).referenceClass} as Set } String buildPath(DataClass dataClass) { @@ -837,7 +837,7 @@ WHERE @Override List findAllReadableByClassifier(UserSecurityPolicyManager userSecurityPolicyManager, Classifier classifier) { - findAllByClassifier(classifier).findAll { userSecurityPolicyManager.userCanReadSecuredResourceId(DataModel, it.model.id) } + findAllByClassifier(classifier).findAll {userSecurityPolicyManager.userCanReadSecuredResourceId(DataModel, it.model.id)} } @Override @@ -877,10 +877,10 @@ WHERE List alreadyExistingLinks = semanticLinkService.findAllBySourceMultiFacetAwareItemIdInListAndTargetMultiFacetAwareItemIdInListAndLinkType( dataClasses*.id, fromDataClasses*.id, SemanticLinkType.IS_FROM) - dataClasses.each { de -> - fromDataClasses.each { fde -> + dataClasses.each {de -> + fromDataClasses.each {fde -> // If no link already exists then add a new one - if (!alreadyExistingLinks.any { it.multiFacetAwareItemId == de.id && it.targetMultiFacetAwareItemId == fde.id }) { + if (!alreadyExistingLinks.any {it.multiFacetAwareItemId == de.id && it.targetMultiFacetAwareItemId == fde.id}) { setDataClassIsFromDataClass(de, fde, user) } } @@ -954,27 +954,27 @@ WHERE @Override void propagateContentsInformation(DataClass catalogueItem, DataClass previousVersionCatalogueItem) { - previousVersionCatalogueItem.dataClasses.each { previousChildDataClass -> - DataClass childDataClass = catalogueItem.dataClasses.find { it.label == previousChildDataClass.label } + previousVersionCatalogueItem.dataClasses.each {previousChildDataClass -> + DataClass childDataClass = catalogueItem.dataClasses.find {it.label == previousChildDataClass.label} if (childDataClass) { propagateDataFromPreviousVersion(childDataClass, previousChildDataClass) } } - previousVersionCatalogueItem.dataElements.each { previousDataElement -> - DataElement dataElement = catalogueItem.dataElements.find { it.label == previousDataElement.label } + previousVersionCatalogueItem.dataElements.each {previousDataElement -> + DataElement dataElement = catalogueItem.dataElements.find {it.label == previousDataElement.label} if (dataElement) { dataElementService.propagateDataFromPreviousVersion(dataElement, previousDataElement) } } - previousVersionCatalogueItem.summaryMetadata.each { previousSummaryMetadata -> - if (catalogueItem.summaryMetadata.any { it.label == previousSummaryMetadata.label }) return + previousVersionCatalogueItem.summaryMetadata.each {previousSummaryMetadata -> + if (catalogueItem.summaryMetadata.any {it.label == previousSummaryMetadata.label}) return SummaryMetadata summaryMetadata = new SummaryMetadata(label: previousSummaryMetadata.label, description: previousSummaryMetadata.description, summaryMetadataType: previousSummaryMetadata.summaryMetadataType) - previousSummaryMetadata.summaryMetadataReports.each { previousSummaryMetadataReport -> + previousSummaryMetadata.summaryMetadataReports.each {previousSummaryMetadataReport -> summaryMetadata.addToSummaryMetadataReports(reportDate: previousSummaryMetadataReport.reportDate, reportValue: previousSummaryMetadataReport.reportValue, createdBy: previousSummaryMetadataReport.createdBy @@ -1019,8 +1019,8 @@ WHERE throw new ApiInternalException("DCS04", "Source Data Class does not exist") DataClass targetDataClass = parentDataClassInTarget ? - parentDataClassInTarget.getDataClasses().find { it.label == dataClassNode.identifier } : - targetDataModel.getChildDataClasses().find { it.label == dataClassNode.identifier } + parentDataClassInTarget.getDataClasses().find {it.label == dataClassNode.identifier} : + targetDataModel.getChildDataClasses().find {it.label == dataClassNode.identifier} if (!targetDataClass) { //Create it @@ -1029,8 +1029,7 @@ WHERE maxMultiplicity: sourceDataClass.maxMultiplicity ) - targetDataClass = copyCatalogueItemInformation(sourceDataClass, targetDataClass, userSecurityPolicyManager.user, - userSecurityPolicyManager, false, null) + targetDataClass = copyModelItemInformation(sourceDataClass, targetDataClass, userSecurityPolicyManager.user, userSecurityPolicyManager) targetDataModel.addToDataClasses(targetDataClass) if (parentDataClassInTarget) { diff --git a/mdm-plugin-datamodel/src/integration-test/groovy/uk/ac/ox/softeng/maurodatamapper/datamodel/DataModelServiceIntegrationSpec.groovy b/mdm-plugin-datamodel/src/integration-test/groovy/uk/ac/ox/softeng/maurodatamapper/datamodel/DataModelServiceIntegrationSpec.groovy index 1e23167e87..f8a20af6a6 100644 --- a/mdm-plugin-datamodel/src/integration-test/groovy/uk/ac/ox/softeng/maurodatamapper/datamodel/DataModelServiceIntegrationSpec.groovy +++ b/mdm-plugin-datamodel/src/integration-test/groovy/uk/ac/ox/softeng/maurodatamapper/datamodel/DataModelServiceIntegrationSpec.groovy @@ -956,6 +956,7 @@ class DataModelServiceIntegrationSpec extends BaseDataModelIntegrationSpec { EnumerationType copiedEnumerationType = copiedDataElement.dataType then: + copiedEnumerationType.domainType == 'EnumerationType' copiedEnumerationType.enumerationValues.every {ev -> ev.key.startsWith('Key') && ev.key.endsWith((ev.idx + 1).toString()) && ev.value.startsWith('Value') && ev.value.endsWith((ev.idx + 1).toString()) diff --git a/mdm-plugin-datamodel/src/integration-test/groovy/uk/ac/ox/softeng/maurodatamapper/datamodel/item/DataClassFunctionalSpec.groovy b/mdm-plugin-datamodel/src/integration-test/groovy/uk/ac/ox/softeng/maurodatamapper/datamodel/item/DataClassFunctionalSpec.groovy index 42f28a26c8..e8cda9c70e 100644 --- a/mdm-plugin-datamodel/src/integration-test/groovy/uk/ac/ox/softeng/maurodatamapper/datamodel/item/DataClassFunctionalSpec.groovy +++ b/mdm-plugin-datamodel/src/integration-test/groovy/uk/ac/ox/softeng/maurodatamapper/datamodel/item/DataClassFunctionalSpec.groovy @@ -494,7 +494,7 @@ class DataClassFunctionalSpec extends OrderedResourceFunctionalSpec { responseBody().items.any { it.label == 'string' } } - void 'CC06: test copying a dataclass with ordered dataclasses, dataelements and enumerationvalues'() { + void 'CC06 : test copying a dataclass with ordered dataclasses, dataelements and enumerationvalues'() { given: POST('', validJson) verifyResponse CREATED, response @@ -527,7 +527,7 @@ class DataClassFunctionalSpec extends OrderedResourceFunctionalSpec { } when: - GET("$id/dataClasses") + GET("$id/dataClasses?sort=idx") then: verifyResponse OK, response @@ -566,7 +566,7 @@ class DataClassFunctionalSpec extends OrderedResourceFunctionalSpec { String copyId = responseBody().id when: - GET("${getResourcePath(otherDataModelId)}/$copyId/dataClasses", MAP_ARG, true) + GET("${getResourcePath(otherDataModelId)}/$copyId/dataClasses?sort=idx", MAP_ARG, true) then: verifyResponse OK, response @@ -606,6 +606,55 @@ class DataClassFunctionalSpec extends OrderedResourceFunctionalSpec { verifyResponse NO_CONTENT, response } + void 'CC07 : test copying a dataclass without index order'() { + given: + POST('', validJson) + verifyResponse CREATED, response + String id = responseBody().id + + for (int i in 1..5) { + POST("$id/dataClasses", [label: 'Child Data Class ' + i, idx: i]) + verifyResponse CREATED, response + } + + when: + GET("$id/dataClasses?sort=idx") + + then: + verifyResponse OK, response + responseBody().items.size() == 5 + responseBody().items.eachWithIndex {dc, i -> + assert dc.domainType == 'DataClass' + assert dc.label.startsWith('Child Data Class') && dc.label.endsWith((i + 1).toString()) + } + + when: + String originalId = responseBody().items[0].id + POST("$id/dataClasses/$dataModelId/$originalId", [copyLabel: 'Child Copied Class']) + + then: + verifyResponse CREATED, response + responseBody().label == 'Child Copied Class' + + when: + GET("$id/dataClasses?sort=idx") + + then: + verifyResponse OK, response + responseBody().items.size() == 6 + responseBody().items.take(5).eachWithIndex {dc, i -> + assert dc.domainType == 'DataClass' + assert dc.label.startsWith('Child Data Class') && dc.label.endsWith((i + 1).toString()) + } + + and: + responseBody().items[5].domainType == 'DataClass' + responseBody().items[5].label == 'Child Copied Class' + + cleanup: + cleanUpData() + } + @Rollback void 'test searching for metadata "mdk1" in content dataclass'() { given: diff --git a/mdm-plugin-datamodel/src/integration-test/groovy/uk/ac/ox/softeng/maurodatamapper/datamodel/item/DataClassServiceIntegrationSpec.groovy b/mdm-plugin-datamodel/src/integration-test/groovy/uk/ac/ox/softeng/maurodatamapper/datamodel/item/DataClassServiceIntegrationSpec.groovy index f664e53015..afedcba41b 100644 --- a/mdm-plugin-datamodel/src/integration-test/groovy/uk/ac/ox/softeng/maurodatamapper/datamodel/item/DataClassServiceIntegrationSpec.groovy +++ b/mdm-plugin-datamodel/src/integration-test/groovy/uk/ac/ox/softeng/maurodatamapper/datamodel/item/DataClassServiceIntegrationSpec.groovy @@ -21,6 +21,7 @@ import uk.ac.ox.softeng.maurodatamapper.core.bootstrap.StandardEmailAddress import uk.ac.ox.softeng.maurodatamapper.core.facet.Metadata import uk.ac.ox.softeng.maurodatamapper.core.facet.SemanticLink import uk.ac.ox.softeng.maurodatamapper.core.facet.SemanticLinkType +import uk.ac.ox.softeng.maurodatamapper.core.rest.transport.model.CopyInformation import uk.ac.ox.softeng.maurodatamapper.datamodel.DataModel import uk.ac.ox.softeng.maurodatamapper.datamodel.DataModelService import uk.ac.ox.softeng.maurodatamapper.datamodel.DataModelType @@ -575,12 +576,50 @@ class DataClassServiceIntegrationSpec extends BaseDataModelIntegrationSpec { EnumerationType copiedEnumerationType = copiedDataElement.dataType then: + copiedEnumerationType.domainType == 'EnumerationType' copiedEnumerationType.enumerationValues.every {ev -> ev.key.startsWith('Key') && ev.key.endsWith((ev.idx + 1).toString()) && ev.value.startsWith('Value') && ev.value.endsWith((ev.idx + 1).toString()) } } + void 'test copying dataclass without index order'() { + given: + setupData() + setupDataModelWithMultipleDataClassesAndDataElementsAndEnumerationValues() + + when: + DataClass parentClass = dataModel.childDataClasses.find {it.label == 'Root Data Class'} + + then: + parentClass.dataClasses.size() == 5 + parentClass.dataClasses.every {dc -> + dc.label.startsWith('Child Data Class') && dc.label.endsWith((dc.idx + 1).toString()) + } + + when: + DataClass original = parentClass.dataClasses.sort().first() + dataClassService.copyDataClass(dataModel, original, editor, userSecurityPolicyManager, parentClass, false, new CopyInformation(copyLabel: 'Child Copied Class')) + + then: + original.idx == 0 + checkAndSave(dataModel) + + when: + DataClass copied = parentClass.dataClasses.find {it.label == 'Child Copied Class'} + List dataClasses = parentClass.dataClasses.sort() + + then: + copied.label == 'Child Copied Class' + copied.idx != original.idx + copied.idx == 5 + dataClasses.size() == 6 + dataClasses.take(5).every {dc -> + dc.label.startsWith('Child Data Class') && dc.label.endsWith((dc.idx + 1).toString()) + } + dataClasses.last() == copied + } + void 'LIST01 : test getting all DataClasses inside a DataClass with importing involved'() { // This addresses the issue gh-226 where we were getting the correct data for DC with no imported DEs and a DC with only imported DEs but incorrect // when a DCs DEs were imported into other DEs. The join was causing non-distinct results. diff --git a/mdm-plugin-terminology/grails-app/services/uk/ac/ox/softeng/maurodatamapper/terminology/CodeSetService.groovy b/mdm-plugin-terminology/grails-app/services/uk/ac/ox/softeng/maurodatamapper/terminology/CodeSetService.groovy index eced8b9f48..44c34b6364 100644 --- a/mdm-plugin-terminology/grails-app/services/uk/ac/ox/softeng/maurodatamapper/terminology/CodeSetService.groovy +++ b/mdm-plugin-terminology/grails-app/services/uk/ac/ox/softeng/maurodatamapper/terminology/CodeSetService.groovy @@ -35,7 +35,6 @@ import uk.ac.ox.softeng.maurodatamapper.core.model.ModelService import uk.ac.ox.softeng.maurodatamapper.core.provider.dataloader.DataLoaderProviderService import uk.ac.ox.softeng.maurodatamapper.core.provider.importer.ModelImporterProviderService import uk.ac.ox.softeng.maurodatamapper.core.provider.importer.parameter.ModelImporterProviderServiceParameters -import uk.ac.ox.softeng.maurodatamapper.core.rest.transport.model.CopyInformation import uk.ac.ox.softeng.maurodatamapper.path.Path import uk.ac.ox.softeng.maurodatamapper.path.PathNode import uk.ac.ox.softeng.maurodatamapper.security.User @@ -247,10 +246,9 @@ class CodeSetService extends ModelService { copy.trackChanges() - CopyInformation copyTermsInformation = new CopyInformation(copyIndex: true) List terms = termService.findAllByCodeSetId(original.id) - terms.sort().each {term -> - termService.copyTerm(copy, term, copier, userSecurityPolicyManager, copyTermsInformation) + terms.each {term -> + copy.addToTerms(term) } log.debug('Copy of codeset took {}', Utils.timeTaken(start)) copy diff --git a/mdm-plugin-terminology/grails-app/services/uk/ac/ox/softeng/maurodatamapper/terminology/TerminologyService.groovy b/mdm-plugin-terminology/grails-app/services/uk/ac/ox/softeng/maurodatamapper/terminology/TerminologyService.groovy index 721788be5e..792c8dad4a 100644 --- a/mdm-plugin-terminology/grails-app/services/uk/ac/ox/softeng/maurodatamapper/terminology/TerminologyService.groovy +++ b/mdm-plugin-terminology/grails-app/services/uk/ac/ox/softeng/maurodatamapper/terminology/TerminologyService.groovy @@ -360,7 +360,7 @@ class TerminologyService extends ModelService { List termRelationshipTypes = TermRelationshipType.byTerminologyId(original.id).join('classifiers').list() List originalTerms = Term.byTerminologyId(original.id).join('classifiers').list() List termRelationships = [] - CopyInformation termsCachedInformation = new CopyInformation(copyIndex: true) + CopyInformation termsCachedInformation = new CopyInformation() if (originalTerms) { List originalTermIds = originalTerms.collect { it.id } @@ -369,19 +369,19 @@ class TerminologyService extends ModelService { } // Copy all the TermRelationshipType - termRelationshipTypes.sort().each { trt -> + termRelationshipTypes.each { trt -> termRelationshipTypeService.copyTermRelationshipType(copy, trt, copier) } // Copy all the terms - originalTerms.sort().each { term -> + originalTerms.each { term -> termService.copyTerm(copy, term, copier, userSecurityPolicyManager, termsCachedInformation) } // Copy all the term relationships // We need all the terms to exist so we can create the links // Only copy source relationships as this will propagate the target relationships - termRelationships.sort().each { relationship -> + termRelationships.each { relationship -> termRelationshipService.copyTermRelationship(copy, relationship, new TreeMap(copy.terms.collectEntries {[it.code, it]}), copier) } log.debug('Copy of terminology took {}', Utils.timeTaken(start)) diff --git a/mdm-plugin-terminology/grails-app/services/uk/ac/ox/softeng/maurodatamapper/terminology/item/TermService.groovy b/mdm-plugin-terminology/grails-app/services/uk/ac/ox/softeng/maurodatamapper/terminology/item/TermService.groovy index 4381115b79..68c42af2a6 100644 --- a/mdm-plugin-terminology/grails-app/services/uk/ac/ox/softeng/maurodatamapper/terminology/item/TermService.groovy +++ b/mdm-plugin-terminology/grails-app/services/uk/ac/ox/softeng/maurodatamapper/terminology/item/TermService.groovy @@ -236,12 +236,19 @@ class TermService extends ModelItemService { copy } + Term copyTerm(CodeSet copiedCodeSet, Term original, User copier, UserSecurityPolicyManager userSecurityPolicyManager, + CopyInformation copyInformation = null) { + Term copy = copyTerm(original, copier, userSecurityPolicyManager, copyInformation) + copiedCodeSet.addToTerms(copy) + copy + } + Term copyTerm(Term original, User copier, UserSecurityPolicyManager userSecurityPolicyManager, CopyInformation copyInformation = null) { if (!original) throw new ApiInternalException('DCSXX', 'Cannot copy non-existent Term') Term copy = new Term(createdBy: copier.emailAddress, code: original.code, definition: original.definition, url: original.url, isParent: original.isParent, depth: original.depth) - copy = copyModelItemInformation(original, copy, copier, userSecurityPolicyManager, copyInformation) + copy = copyCatalogueItemInformation(original, copy, copier, userSecurityPolicyManager, copyInformation) setCatalogueItemRefinesCatalogueItem(copy, original, copier) copy }