From 06476849989264ce836fbea01d8d619bcb3d6267 Mon Sep 17 00:00:00 2001 From: "d.svitak" Date: Thu, 5 Feb 2026 15:28:56 +0100 Subject: [PATCH 1/9] first batch of changes on a way to remove model layer from migration-library --- .../com/quadient/migration/api/Migration.kt | 20 +- .../api/dto/migrationmodel/DisplayRule.kt | 26 +- .../api/dto/migrationmodel/DocumentObject.kt | 32 +- .../migration/api/dto/migrationmodel/File.kt | 33 +- .../api/dto/migrationmodel/Hyperlink.kt | 15 +- .../migration/api/dto/migrationmodel/Image.kt | 39 +- .../api/dto/migrationmodel/MigrationObject.kt | 4 + .../api/dto/migrationmodel/ParagraphStyle.kt | 108 +- .../migration/api/dto/migrationmodel/Ref.kt | 126 +- .../api/dto/migrationmodel/RefValidatable.kt | 5 + .../api/dto/migrationmodel/TextStyle.kt | 81 +- .../api/dto/migrationmodel/Variable.kt | 26 +- .../dto/migrationmodel/VariableStructure.kt | 31 +- .../builder/DisplayRuleBuilder.kt | 2 + .../builder/DocumentObjectBuilder.kt | 2 + .../migrationmodel/builder/DtoBuilderBase.kt | 24 + .../dto/migrationmodel/builder/FileBuilder.kt | 2 + .../migrationmodel/builder/ImageBuilder.kt | 2 + .../builder/ParagraphStyleBuilder.kt | 2 + .../builder/TextStyleBuilder.kt | 2 + .../migrationmodel/builder/VariableBuilder.kt | 2 + .../builder/VariableStructureBuilder.kt | 2 + .../migrationmodel/documentcontent/Area.kt | 17 +- .../documentcontent/DocumentContent.kt | 35 +- .../documentcontent/FirstMatch.kt | 37 +- .../documentcontent/Paragraph.kt | 58 +- .../documentcontent/SelectByLanguage.kt | 26 +- .../migrationmodel/documentcontent/Table.kt | 38 +- .../api/repository/DisplayRuleRepository.kt | 18 +- .../repository/DocumentObjectRepository.kt | 7 +- .../api/repository/FileRepository.kt | 19 +- .../api/repository/ImageRepository.kt | 22 +- .../api/repository/MappingRepository.kt | 2 + .../repository/ParagraphStyleRepository.kt | 17 +- .../migration/api/repository/Repository.kt | 11 +- .../api/repository/TextStyleRepository.kt | 18 +- .../api/repository/VariableRepository.kt | 18 +- .../repository/VariableStructureRepository.kt | 18 +- .../migration/data/DisplayRuleModel.kt | 20 - .../migration/data/DocumentObjectModel.kt | 43 - .../com/quadient/migration/data/FileModel.kt | 23 - .../quadient/migration/data/HyperlinkModel.kt | 17 - .../com/quadient/migration/data/ImageModel.kt | 28 - .../migration/data/MigrationObjectModel.kt | 20 - .../migration/data/ParagraphStyleModel.kt | 74 - .../com/quadient/migration/data/RefModel.kt | 123 - .../quadient/migration/data/TextStyleModel.kt | 51 - .../quadient/migration/data/VariableModel.kt | 20 - .../migration/data/VariableStructureModel.kt | 20 - .../data/documentcontent/AreaModel.kt | 16 - .../documentcontent/DocumentContentModel.kt | 28 - .../data/documentcontent/FirstMatchModel.kt | 30 - .../data/documentcontent/ParagraphModel.kt | 72 - .../documentcontent/SelectByLanguageModel.kt | 24 - .../data/documentcontent/TableModel.kt | 52 - .../migrationmodel/MappingEntity.kt | 22 +- .../DisplayRuleInternalRepository.kt | 23 +- .../DocumentObjectInternalRepository.kt | 39 +- .../repository/FileInternalRepository.kt | 21 +- .../repository/ImageInternalRepository.kt | 24 +- .../repository/InternalRepository.kt | 3 +- .../ParagraphStyleInternalRepository.kt | 31 +- .../repository/TextStyleInternalRepository.kt | 31 +- .../repository/VariableInternalRepository.kt | 26 +- .../VariableStructureInternalRepository.kt | 18 +- .../persistence/table/DocumentObjectTable.kt | 24 +- .../migration/service/DeployPhaseUtils.kt | 4 +- .../migration/service/ReferenceValidator.kt | 53 +- .../migration/service/StylesValidator.kt | 92 +- .../migration/service/deploy/DeployClient.kt | 128 +- .../service/deploy/DesignerDeployClient.kt | 24 +- .../service/deploy/InteractiveDeployClient.kt | 24 +- .../service/deploy/ProgressReport.kt | 15 +- .../DesignerDocumentObjectBuilder.kt | 79 +- .../InspireDocumentObjectBuilder.kt | 2489 +++++++++-------- .../InteractiveDocumentObjectBuilder.kt | 62 +- .../migration/shared/DisplayRuleDefinition.kt | 18 +- .../DocumentObjectRepositoryTest.kt | 12 +- .../persistence/MappingRepositoryTest.kt | 42 +- .../migrationmodel/MappingEntityTest.kt | 80 +- .../service/ReferenceValidatorTest.kt | 36 +- .../migration/service/StylesValidatorTest.kt | 21 +- .../migration/tools/TestObjectBuilders.kt | 49 +- .../tools/model/TestModelObjectBuilders.kt | 220 +- 84 files changed, 2313 insertions(+), 3005 deletions(-) create mode 100644 migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/RefValidatable.kt delete mode 100644 migration-library/src/main/kotlin/com/quadient/migration/data/DisplayRuleModel.kt delete mode 100644 migration-library/src/main/kotlin/com/quadient/migration/data/DocumentObjectModel.kt delete mode 100644 migration-library/src/main/kotlin/com/quadient/migration/data/FileModel.kt delete mode 100644 migration-library/src/main/kotlin/com/quadient/migration/data/HyperlinkModel.kt delete mode 100644 migration-library/src/main/kotlin/com/quadient/migration/data/ImageModel.kt delete mode 100644 migration-library/src/main/kotlin/com/quadient/migration/data/MigrationObjectModel.kt delete mode 100644 migration-library/src/main/kotlin/com/quadient/migration/data/ParagraphStyleModel.kt delete mode 100644 migration-library/src/main/kotlin/com/quadient/migration/data/RefModel.kt delete mode 100644 migration-library/src/main/kotlin/com/quadient/migration/data/TextStyleModel.kt delete mode 100644 migration-library/src/main/kotlin/com/quadient/migration/data/VariableModel.kt delete mode 100644 migration-library/src/main/kotlin/com/quadient/migration/data/VariableStructureModel.kt delete mode 100644 migration-library/src/main/kotlin/com/quadient/migration/data/documentcontent/AreaModel.kt delete mode 100644 migration-library/src/main/kotlin/com/quadient/migration/data/documentcontent/DocumentContentModel.kt delete mode 100644 migration-library/src/main/kotlin/com/quadient/migration/data/documentcontent/FirstMatchModel.kt delete mode 100644 migration-library/src/main/kotlin/com/quadient/migration/data/documentcontent/ParagraphModel.kt delete mode 100644 migration-library/src/main/kotlin/com/quadient/migration/data/documentcontent/SelectByLanguageModel.kt delete mode 100644 migration-library/src/main/kotlin/com/quadient/migration/data/documentcontent/TableModel.kt diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/Migration.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/Migration.kt index 79b6943a..beccdfcd 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/Migration.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/Migration.kt @@ -28,16 +28,16 @@ class Migration(public val config: MigConfig, public val projectConfig: ProjectC private val projectName = projectConfig.name private val ipsConfig = config.inspireConfig.ipsConfig private val ipsService = IpsService(ipsConfig) - val repositories = mutableListOf>() - - val variableRepository: Repository - val documentObjectRepository: Repository - val textStyleRepository: Repository - val paragraphStyleRepository: Repository - val variableStructureRepository: Repository - val displayRuleRepository: Repository - val imageRepository: Repository - val fileRepository: Repository + val repositories = mutableListOf>() + + val variableRepository: Repository + val documentObjectRepository: Repository + val textStyleRepository: Repository + val paragraphStyleRepository: Repository + val variableStructureRepository: Repository + val displayRuleRepository: Repository + val imageRepository: Repository + val fileRepository: Repository val statusTrackingRepository = StatusTrackingRepository(projectName) val mappingRepository: MappingRepository diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/DisplayRule.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/DisplayRule.kt index 1c38ec7b..a31d8347 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/DisplayRule.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/DisplayRule.kt @@ -1,11 +1,35 @@ package com.quadient.migration.api.dto.migrationmodel +import com.quadient.migration.persistence.table.DisplayRuleTable import com.quadient.migration.shared.DisplayRuleDefinition +import kotlinx.datetime.Instant +import org.jetbrains.exposed.v1.core.ResultRow data class DisplayRule( override val id: String, override var name: String?, override var originLocations: List = emptyList(), override var customFields: CustomFieldMap, + override val created: Instant, + override val lastUpdated: Instant, var definition: DisplayRuleDefinition? -) : MigrationObject \ No newline at end of file +) : MigrationObject, RefValidatable { + override fun collectRefs(): List { + // DisplayRuleDefinition.collectRefs() returns List which are already DTOs + return definition?.collectRefs() ?: emptyList() + } + + companion object { + fun fromDb(row: ResultRow): DisplayRule { + return DisplayRule( + id = row[DisplayRuleTable.id].value, + name = row[DisplayRuleTable.name], + originLocations = row[DisplayRuleTable.originLocations], + customFields = CustomFieldMap(row[DisplayRuleTable.customFields].toMutableMap()), + lastUpdated = row[DisplayRuleTable.lastUpdated], + created = row[DisplayRuleTable.created], + definition = row[DisplayRuleTable.definition] + ) + } + } +} \ No newline at end of file diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/DocumentObject.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/DocumentObject.kt index 7193f7cd..37d60bd0 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/DocumentObject.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/DocumentObject.kt @@ -1,6 +1,5 @@ package com.quadient.migration.api.dto.migrationmodel -import com.quadient.migration.data.DocumentObjectModel import com.quadient.migration.shared.DocumentObjectOptions import com.quadient.migration.shared.DocumentObjectType import com.quadient.migration.shared.MetadataPrimitive @@ -12,6 +11,8 @@ data class DocumentObject( override var name: String? = null, override var originLocations: List = emptyList(), override var customFields: CustomFieldMap, + override val created: Instant, + override val lastUpdated: Instant, var type: DocumentObjectType, var content: List = mutableListOf(), var internal: Boolean? = false, @@ -20,33 +21,12 @@ data class DocumentObject( var variableStructureRef: VariableStructureRef? = null, var baseTemplate: String? = null, var options: DocumentObjectOptions? = null, - var created: Instant? = null, - var lastUpdated: Instant? = null, val metadata: Map>, val skip: SkipOptions, val subject: String?, -) : MigrationObject { - companion object { - fun fromModel(model: DocumentObjectModel): DocumentObject { - return DocumentObject( - id = model.id, - name = model.name, - originLocations = model.originLocations, - customFields = CustomFieldMap(model.customFields.toMutableMap()), - type = model.type, - content = model.content.map { DocumentContent.fromModelContent(it) }, - internal = model.internal, - targetFolder = model.targetFolder?.toString(), - displayRuleRef = model.displayRuleRef?.let(DisplayRuleRef::fromModel), - variableStructureRef = model.variableStructureRef?.let(VariableStructureRef::fromModel), - baseTemplate = model.baseTemplate, - options = model.options, - created = model.created, - lastUpdated = model.lastUpdated, - metadata = model.metadata, - skip = model.skip, - subject = model.subject, - ) - } +) : MigrationObject, RefValidatable { + override fun collectRefs(): List { + // Refs are collected from content via proper traversal + return listOfNotNull(displayRuleRef, variableStructureRef) } } \ No newline at end of file diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/File.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/File.kt index 2e7165ef..4181ab68 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/File.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/File.kt @@ -1,30 +1,41 @@ package com.quadient.migration.api.dto.migrationmodel -import com.quadient.migration.data.FileModel +import com.quadient.migration.persistence.table.FileTable import com.quadient.migration.shared.FileType +import com.quadient.migration.shared.IcmPath import com.quadient.migration.shared.SkipOptions +import kotlinx.datetime.Instant +import org.jetbrains.exposed.v1.core.ResultRow data class File( override val id: String, override var name: String?, override var originLocations: List, override var customFields: CustomFieldMap, + override val created: Instant, + override val lastUpdated: Instant, var sourcePath: String?, var targetFolder: String?, var fileType: FileType, val skip: SkipOptions, -) : MigrationObject { +) : MigrationObject, RefValidatable { + override fun collectRefs(): List { + return emptyList() + } + companion object { - fun fromModel(model: FileModel): File { + fun fromDb(row: ResultRow): File { return File( - id = model.id, - name = model.name, - originLocations = model.originLocations, - customFields = CustomFieldMap(model.customFields.toMutableMap()), - sourcePath = model.sourcePath, - targetFolder = model.targetFolder?.toString(), - fileType = model.fileType, - skip = model.skip, + id = row[FileTable.id].value, + name = row[FileTable.name], + originLocations = row[FileTable.originLocations], + customFields = CustomFieldMap(row[FileTable.customFields].toMutableMap()), + created = row[FileTable.created], + lastUpdated = row[FileTable.created], + sourcePath = row[FileTable.sourcePath], + targetFolder = row[FileTable.targetFolder]?.let(IcmPath::from)?.toString(), + fileType = FileType.valueOf(row[FileTable.fileType]), + skip = row[FileTable.skip], ) } } diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/Hyperlink.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/Hyperlink.kt index 7fa33f34..a6650707 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/Hyperlink.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/Hyperlink.kt @@ -1,6 +1,5 @@ package com.quadient.migration.api.dto.migrationmodel -import com.quadient.migration.data.HyperlinkModel import com.quadient.migration.persistence.migrationmodel.HyperlinkEntity data class Hyperlink( @@ -9,19 +8,13 @@ data class Hyperlink( val alternateText: String? = null ) : TextContent { companion object { - fun fromModel(model: HyperlinkModel) = Hyperlink( - url = model.url, - displayText = model.displayText, - alternateText = model.alternateText + fun fromDb(entity: HyperlinkEntity) = Hyperlink( + url = entity.url, + displayText = entity.displayText, + alternateText = entity.alternateText ) } - fun toModel() = HyperlinkModel( - url = url, - displayText = displayText, - alternateText = alternateText - ) - fun toDb() = HyperlinkEntity( url = url, displayText = displayText, diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/Image.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/Image.kt index da9191f4..cabe06c7 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/Image.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/Image.kt @@ -1,16 +1,21 @@ package com.quadient.migration.api.dto.migrationmodel -import com.quadient.migration.data.ImageModel +import com.quadient.migration.persistence.table.ImageTable +import com.quadient.migration.shared.IcmPath import com.quadient.migration.shared.ImageOptions import com.quadient.migration.shared.ImageType import com.quadient.migration.shared.MetadataPrimitive import com.quadient.migration.shared.SkipOptions +import kotlinx.datetime.Instant +import org.jetbrains.exposed.v1.core.ResultRow data class Image( override val id: String, override var name: String?, override var originLocations: List, override var customFields: CustomFieldMap, + override val created: Instant, + override val lastUpdated: Instant, var sourcePath: String?, var options: ImageOptions?, var imageType: ImageType?, @@ -18,21 +23,27 @@ data class Image( val metadata: Map>, val skip: SkipOptions, var alternateText: String? = null, -) : MigrationObject { +) : MigrationObject, RefValidatable { + override fun collectRefs(): List { + return emptyList() + } + companion object { - fun fromModel(model: ImageModel): Image { + fun fromDb(row: ResultRow): Image { return Image( - id = model.id, - name = model.name, - originLocations = model.originLocations, - customFields = CustomFieldMap(model.customFields.toMutableMap()), - sourcePath = model.sourcePath, - options = model.options, - imageType = model.imageType, - targetFolder = model.targetFolder?.toString(), - metadata = model.metadata, - skip = model.skip, - alternateText = model.alternateText, + id = row[ImageTable.id].value, + name = row[ImageTable.name], + originLocations = row[ImageTable.originLocations], + customFields = CustomFieldMap(row[ImageTable.customFields].toMutableMap()), + created = row[ImageTable.created], + lastUpdated = row[ImageTable.created], + sourcePath = row[ImageTable.sourcePath], + imageType = ImageType.valueOf(row[ImageTable.imageType]), + options = row[ImageTable.options], + targetFolder = row[ImageTable.targetFolder]?.let(IcmPath::from)?.toString(), + metadata = row[ImageTable.metadata], + skip = row[ImageTable.skip], + alternateText = row[ImageTable.alternateText], ) } } diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/MigrationObject.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/MigrationObject.kt index 32422dc6..9d83175d 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/MigrationObject.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/MigrationObject.kt @@ -1,10 +1,14 @@ package com.quadient.migration.api.dto.migrationmodel +import kotlinx.datetime.Instant + interface MigrationObject { val id: String var name: String? var originLocations: List var customFields: CustomFieldMap + val created: Instant + val lastUpdated: Instant fun nameOrId(): String { val name = name diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/ParagraphStyle.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/ParagraphStyle.kt index 6c75c33c..241fb55f 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/ParagraphStyle.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/ParagraphStyle.kt @@ -1,33 +1,73 @@ package com.quadient.migration.api.dto.migrationmodel -import com.quadient.migration.data.ParagraphStyleDefinitionModel -import com.quadient.migration.data.ParagraphStyleModel -import com.quadient.migration.data.TabModel -import com.quadient.migration.data.TabsModel import com.quadient.migration.persistence.migrationmodel.ParagraphStyleDefinitionEntity import com.quadient.migration.persistence.migrationmodel.TabEntity import com.quadient.migration.persistence.migrationmodel.TabsEntity +import com.quadient.migration.persistence.table.ParagraphStyleTable import com.quadient.migration.shared.Alignment import com.quadient.migration.shared.LineSpacing import com.quadient.migration.shared.ParagraphPdfTaggingRule import com.quadient.migration.shared.Size import com.quadient.migration.shared.TabType +import kotlinx.datetime.Instant +import org.jetbrains.exposed.v1.core.ResultRow data class ParagraphStyle( override val id: String, override var name: String? = null, override var originLocations: List = emptyList(), override var customFields: CustomFieldMap, + override val created: Instant, + override val lastUpdated: Instant, var definition: ParagraphStyleDefOrRef, -) : MigrationObject { +) : MigrationObject, RefValidatable { + override fun collectRefs(): List { + return when (definition) { + is ParagraphStyleDefinition -> emptyList() + is ParagraphStyleRef -> listOf(definition as Ref) + } + } + companion object { - fun fromModel(model: ParagraphStyleModel) = ParagraphStyle( - id = model.id, - name = model.name, - originLocations = model.originLocations, - customFields = CustomFieldMap(model.customFields.toMutableMap()), - definition = ParagraphStyleDefOrRef.fromModel(model.definition), - ) + fun fromDb(row: ResultRow): ParagraphStyle { + // Need to convert from Entity to DTO + val definitionEntity = row[ParagraphStyleTable.definition] + val definition = when (definitionEntity) { + is com.quadient.migration.persistence.migrationmodel.ParagraphStyleDefinitionEntity -> { + ParagraphStyleDefinition( + leftIndent = definitionEntity.leftIndent, + rightIndent = definitionEntity.rightIndent, + defaultTabSize = definitionEntity.defaultTabSize, + spaceBefore = definitionEntity.spaceBefore, + spaceAfter = definitionEntity.spaceAfter, + alignment = definitionEntity.alignment, + firstLineIndent = definitionEntity.firstLineIndent, + lineSpacing = definitionEntity.lineSpacing, + keepWithNextParagraph = definitionEntity.keepWithNextParagraph, + tabs = definitionEntity.tabs?.let { tabsEntity -> + Tabs( + tabs = tabsEntity.tabs.map { Tab(it.position, it.type) }, + useOutsideTabs = tabsEntity.useOutsideTabs + ) + }, + pdfTaggingRule = definitionEntity.pdfTaggingRule, + ) + } + is com.quadient.migration.persistence.migrationmodel.ParagraphStyleEntityRef -> { + ParagraphStyleRef.fromDb(definitionEntity) + } + } + + return ParagraphStyle( + id = row[ParagraphStyleTable.id].value, + name = row[ParagraphStyleTable.name], + originLocations = row[ParagraphStyleTable.originLocations], + customFields = CustomFieldMap(row[ParagraphStyleTable.customFields].toMutableMap()), + lastUpdated = row[ParagraphStyleTable.lastUpdated], + created = row[ParagraphStyleTable.created], + definition = definition, + ) + } } } @@ -44,22 +84,6 @@ data class ParagraphStyleDefinition( var tabs: Tabs?, var pdfTaggingRule: ParagraphPdfTaggingRule?, ) : ParagraphStyleDefOrRef { - companion object { - fun fromModel(model: ParagraphStyleDefinitionModel) = ParagraphStyleDefinition( - leftIndent = model.leftIndent, - rightIndent = model.rightIndent, - defaultTabSize = model.defaultTabSize, - spaceBefore = model.spaceBefore, - spaceAfter = model.spaceAfter, - alignment = model.alignment, - firstLineIndent = model.firstLineIndent, - lineSpacing = model.lineSpacing, - keepWithNextParagraph = model.keepWithNextParagraph, - tabs = model.tabs?.let(Tabs::fromModel), - pdfTaggingRule = model.pdfTaggingRule, - ) - } - override fun toDb() = ParagraphStyleDefinitionEntity( leftIndent = leftIndent, rightIndent = rightIndent, @@ -73,43 +97,15 @@ data class ParagraphStyleDefinition( tabs = tabs?.toDb(), pdfTaggingRule = pdfTaggingRule, ) - - override fun toModel() = ParagraphStyleDefinitionModel( - leftIndent = leftIndent, - rightIndent = rightIndent, - defaultTabSize = defaultTabSize, - spaceBefore = spaceBefore, - spaceAfter = spaceAfter, - alignment = alignment, - firstLineIndent = firstLineIndent, - lineSpacing = lineSpacing, - keepWithNextParagraph = keepWithNextParagraph, - tabs = tabs?.toModel(), - pdfTaggingRule = pdfTaggingRule, - ) } data class Tabs(val tabs: List, val useOutsideTabs: Boolean) { - companion object { - fun fromModel(db: TabsModel) = Tabs( - tabs = db.tabs.map { Tab(it.position, it.type) }, - useOutsideTabs = db.useOutsideTabs, - ) - } - fun toDb() = TabsEntity( tabs = tabs.map { TabEntity(position = it.position, type = it.type) }, useOutsideTabs = useOutsideTabs, ) - - fun toModel() = TabsModel( - tabs = tabs.map { - TabModel(position = it.position, type = it.type) - }, - useOutsideTabs = useOutsideTabs, - ) } data class Tab(val position: Size, val type: TabType) \ No newline at end of file diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/Ref.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/Ref.kt index 093410a8..0126941c 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/Ref.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/Ref.kt @@ -1,185 +1,133 @@ package com.quadient.migration.api.dto.migrationmodel -import com.quadient.migration.data.DisplayRuleModelRef -import com.quadient.migration.data.DocumentObjectModelRef -import com.quadient.migration.data.FirstMatchModel -import com.quadient.migration.data.HyperlinkModel -import com.quadient.migration.data.ImageModelRef -import com.quadient.migration.data.FileModelRef -import com.quadient.migration.data.ParagraphStyleDefOrRefModel -import com.quadient.migration.data.ParagraphStyleDefinitionModel -import com.quadient.migration.data.ParagraphStyleModelRef -import com.quadient.migration.data.RefModel -import com.quadient.migration.data.StringModel -import com.quadient.migration.data.TableModel -import com.quadient.migration.data.TextContentModel -import com.quadient.migration.data.TextStyleDefOrRefModel -import com.quadient.migration.data.TextStyleDefinitionModel -import com.quadient.migration.data.TextStyleModelRef -import com.quadient.migration.data.VariableModelRef -import com.quadient.migration.data.VariableStructureModelRef import com.quadient.migration.persistence.migrationmodel.DisplayRuleEntityRef import com.quadient.migration.persistence.migrationmodel.DocumentObjectEntityRef +import com.quadient.migration.persistence.migrationmodel.FirstMatchEntity +import com.quadient.migration.persistence.migrationmodel.HyperlinkEntity import com.quadient.migration.persistence.migrationmodel.ImageEntityRef import com.quadient.migration.persistence.migrationmodel.FileEntityRef import com.quadient.migration.persistence.migrationmodel.ParagraphStyleEntityRef import com.quadient.migration.persistence.migrationmodel.StringEntity +import com.quadient.migration.persistence.migrationmodel.TableEntity +import com.quadient.migration.persistence.migrationmodel.TextContentEntity import com.quadient.migration.persistence.migrationmodel.TextStyleEntityRef import com.quadient.migration.persistence.migrationmodel.VariableEntityRef import com.quadient.migration.persistence.migrationmodel.VariableStructureEntityRef sealed interface Ref { val id: String - - companion object { - fun fromModel(model: RefModel) = when (model) { - is DocumentObjectModelRef -> DocumentObjectRef.fromModel(model) - is VariableModelRef -> VariableRef.fromModel(model) - is TextStyleModelRef -> TextStyleRef.fromModel(model) - is ParagraphStyleModelRef -> ParagraphStyleRef.fromModel(model) - is DisplayRuleModelRef -> DisplayRuleRef.fromModel(model) - is ImageModelRef -> ImageRef.fromModel(model) - is FileModelRef -> FileRef.fromModel(model) - is VariableStructureModelRef -> VariableStructureRef.fromModel(model) - } - } } sealed interface TextContent { companion object { - fun fromModel(model: TextContentModel) = when (model) { - is DocumentObjectModelRef -> DocumentObjectRef.fromModel(model) - is ImageModelRef -> ImageRef.fromModel(model) - is FileModelRef -> FileRef.fromModel(model) - is StringModel -> StringValue.fromModel(model) - is TableModel -> Table.fromModel(model) - is VariableModelRef -> VariableRef.fromModel(model) - is FirstMatchModel -> FirstMatch.fromModel(model) - is HyperlinkModel -> Hyperlink.fromModel(model) + fun fromDb(entity: TextContentEntity): TextContent = when (entity) { + is StringEntity -> StringValue.fromDb(entity) + is VariableEntityRef -> VariableRef.fromDb(entity) + is TableEntity -> Table.fromDb(entity) + is DocumentObjectEntityRef -> DocumentObjectRef.fromDb(entity) + is ImageEntityRef -> ImageRef.fromDb(entity) + is FileEntityRef -> FileRef.fromDb(entity) + is FirstMatchEntity -> FirstMatch.fromDb(entity) + is HyperlinkEntity -> Hyperlink.fromDb(entity) } } } sealed interface TextStyleDefOrRef { - companion object { - fun fromModel(model: TextStyleDefOrRefModel) = when (model) { - is TextStyleDefinitionModel -> TextStyleDefinition.fromModel(model) - is TextStyleModelRef -> TextStyleRef.fromModel(model) - } - } - fun toDb() = when (this) { is TextStyleDefinition -> this.toDb() is TextStyleRef -> this.toDb() } - - fun toModel() = when (this) { - is TextStyleDefinition -> this.toModel() - is TextStyleRef -> this.toModel() - } } sealed interface ParagraphStyleDefOrRef { - companion object { - fun fromModel(model: ParagraphStyleDefOrRefModel) = when (model) { - is ParagraphStyleDefinitionModel -> ParagraphStyleDefinition.fromModel(model) - is ParagraphStyleModelRef -> ParagraphStyleRef.fromModel(model) - } - } - fun toDb() = when (this) { is ParagraphStyleDefinition -> this.toDb() is ParagraphStyleRef -> this.toDb() } - - fun toModel() = when (this) { - is ParagraphStyleDefinition -> this.toModel() - is ParagraphStyleRef -> this.toModel() - } } data class DocumentObjectRef(override val id: String, val displayRuleRef: DisplayRuleRef? = null) : Ref, - DocumentContent, TextContent { + DocumentContent, TextContent, RefValidatable { constructor(id: String) : this(id, null) + override fun collectRefs(): List { + return listOfNotNull(this, displayRuleRef) + } + companion object { - fun fromModel(model: DocumentObjectModelRef) = - DocumentObjectRef(model.id, model.displayRuleRef?.let { DisplayRuleRef.fromModel(it) }) + fun fromDb(entity: DocumentObjectEntityRef) = + DocumentObjectRef(entity.id, entity.displayRuleRef?.let { DisplayRuleRef.fromDb(it) }) } fun toDb() = DocumentObjectEntityRef(id, displayRuleRef?.toDb()) - fun toModel() = DocumentObjectModelRef(id, displayRuleRef?.toModel()) } data class VariableRef(override val id: String) : Ref, TextContent { companion object { - fun fromModel(model: VariableModelRef) = VariableRef(model.id) + fun fromDb(entity: VariableEntityRef) = VariableRef(entity.id) } - fun toModel() = VariableModelRef(id) fun toDb() = VariableEntityRef(id) } data class TextStyleRef(override val id: String) : Ref, TextStyleDefOrRef { companion object { - fun fromModel(model: TextStyleModelRef) = TextStyleRef(model.id) + fun fromDb(entity: TextStyleEntityRef) = TextStyleRef(entity.id) } - override fun toModel() = TextStyleModelRef(id) override fun toDb() = TextStyleEntityRef(id) } data class ParagraphStyleRef(override val id: String) : Ref, ParagraphStyleDefOrRef { companion object { - fun fromModel(model: ParagraphStyleModelRef) = ParagraphStyleRef(model.id) + fun fromDb(entity: ParagraphStyleEntityRef) = ParagraphStyleRef(entity.id) } - override fun toModel() = ParagraphStyleModelRef(id) override fun toDb() = ParagraphStyleEntityRef(id) } data class DisplayRuleRef(override val id: String) : Ref { companion object { - fun fromModel(model: DisplayRuleModelRef) = DisplayRuleRef(model.id) + fun fromDb(entity: DisplayRuleEntityRef) = DisplayRuleRef(entity.id) } - fun toModel() = DisplayRuleModelRef(id) fun toDb() = DisplayRuleEntityRef(id) } -data class ImageRef(override val id: String) : Ref, DocumentContent, TextContent { +data class ImageRef(override val id: String) : Ref, DocumentContent, TextContent, RefValidatable { + override fun collectRefs(): List { + return listOf(this) + } + companion object { - fun fromModel(model: ImageModelRef) = ImageRef(model.id) + fun fromDb(entity: ImageEntityRef) = ImageRef(entity.id) } - fun toModel() = ImageModelRef(id) fun toDb() = ImageEntityRef(id) } -data class FileRef(override val id: String) : Ref, DocumentContent, TextContent { +data class FileRef(override val id: String) : Ref, DocumentContent, TextContent, RefValidatable { + override fun collectRefs(): List { + return listOf(this) + } + companion object { - fun fromModel(model: FileModelRef) = FileRef(model.id) + fun fromDb(entity: FileEntityRef) = FileRef(entity.id) } - fun toModel() = FileModelRef(id) fun toDb() = FileEntityRef(id) } data class VariableStructureRef(override val id: String) : Ref { - companion object { - fun fromModel(model: VariableStructureModelRef) = VariableStructureRef(model.id) - } - - fun toModel() = VariableStructureModelRef(id) fun toDb() = VariableStructureEntityRef(id) } data class StringValue(val value: String) : TextContent { companion object { - fun fromModel(model: StringModel) = StringValue(model.value) + fun fromDb(entity: StringEntity) = StringValue(entity.value) } - fun toModel() = StringModel(value) fun toDb() = StringEntity(value) } diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/RefValidatable.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/RefValidatable.kt new file mode 100644 index 00000000..bde83498 --- /dev/null +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/RefValidatable.kt @@ -0,0 +1,5 @@ +package com.quadient.migration.api.dto.migrationmodel + +interface RefValidatable { + fun collectRefs(): List +} diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/TextStyle.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/TextStyle.kt index 6a17a360..03e4530d 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/TextStyle.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/TextStyle.kt @@ -1,27 +1,62 @@ package com.quadient.migration.api.dto.migrationmodel -import com.quadient.migration.data.TextStyleDefinitionModel -import com.quadient.migration.data.TextStyleModel import com.quadient.migration.persistence.migrationmodel.TextStyleDefinitionEntity +import com.quadient.migration.persistence.table.TextStyleTable import com.quadient.migration.shared.Color import com.quadient.migration.shared.Size import com.quadient.migration.shared.SuperOrSubscript +import kotlinx.datetime.Instant +import org.jetbrains.exposed.v1.core.ResultRow data class TextStyle( override val id: String, override var name: String? = null, override var originLocations: List = emptyList(), override var customFields: CustomFieldMap, + override val created: Instant, + override val lastUpdated: Instant, var definition: TextStyleDefOrRef, -) : MigrationObject { +) : MigrationObject, RefValidatable { + override fun collectRefs(): List { + return when (definition) { + is TextStyleDefinition -> emptyList() + is TextStyleRef -> listOf(definition as Ref) + } + } + companion object { - fun fromModel(model: TextStyleModel) = TextStyle( - id = model.id, - name = model.name, - originLocations = model.originLocations, - customFields = CustomFieldMap(model.customFields.toMutableMap()), - definition = TextStyleDefOrRef.fromModel(model.definition), - ) + fun fromDb(row: ResultRow): TextStyle { + // Need to convert from Entity to DTO + val definitionEntity = row[TextStyleTable.definition] + val definition = when (definitionEntity) { + is com.quadient.migration.persistence.migrationmodel.TextStyleDefinitionEntity -> { + TextStyleDefinition( + fontFamily = definitionEntity.fontFamily, + foregroundColor = definitionEntity.foregroundColor, + size = definitionEntity.size, + bold = definitionEntity.bold, + italic = definitionEntity.italic, + underline = definitionEntity.underline, + strikethrough = definitionEntity.strikethrough, + superOrSubscript = definitionEntity.superOrSubscript, + interspacing = definitionEntity.interspacing, + ) + } + is com.quadient.migration.persistence.migrationmodel.TextStyleEntityRef -> { + TextStyleRef.fromDb(definitionEntity) + } + } + + return TextStyle( + id = row[TextStyleTable.id].value, + name = row[TextStyleTable.name], + originLocations = row[TextStyleTable.originLocations], + customFields = CustomFieldMap(row[TextStyleTable.customFields].toMutableMap()), + lastUpdated = row[TextStyleTable.lastUpdated], + created = row[TextStyleTable.created], + definition = definition, + ) + } } } @@ -36,20 +71,6 @@ data class TextStyleDefinition( var superOrSubscript: SuperOrSubscript = SuperOrSubscript.None, var interspacing: Size?, ) : TextStyleDefOrRef { - companion object { - fun fromModel(model: TextStyleDefinitionModel) = TextStyleDefinition( - fontFamily = model.fontFamily, - foregroundColor = model.foregroundColor, - size = model.size, - bold = model.bold, - italic = model.italic, - underline = model.underline, - strikethrough = model.strikethrough, - interspacing = model.interspacing, - superOrSubscript = model.superOrSubscript, - ) - } - override fun toDb() = TextStyleDefinitionEntity( fontFamily = fontFamily, foregroundColor = foregroundColor, @@ -61,16 +82,4 @@ data class TextStyleDefinition( superOrSubscript = superOrSubscript, interspacing = interspacing, ) - - override fun toModel() = TextStyleDefinitionModel( - fontFamily = fontFamily, - foregroundColor = foregroundColor, - size = size, - bold = bold, - italic = italic, - underline = underline, - strikethrough = strikethrough, - superOrSubscript = superOrSubscript, - interspacing = interspacing, - ) } \ No newline at end of file diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/Variable.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/Variable.kt index 3e79bd87..34c1ace4 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/Variable.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/Variable.kt @@ -1,12 +1,36 @@ package com.quadient.migration.api.dto.migrationmodel +import com.quadient.migration.persistence.table.VariableTable import com.quadient.migration.shared.DataType +import kotlinx.datetime.Instant +import org.jetbrains.exposed.v1.core.ResultRow data class Variable( override val id: String, override var name: String? = null, override var originLocations: List = emptyList(), override var customFields: CustomFieldMap, + override val created: Instant, + override val lastUpdated: Instant, var dataType: DataType, var defaultValue: String? -) : MigrationObject \ No newline at end of file +) : MigrationObject, RefValidatable { + override fun collectRefs(): List { + return emptyList() + } + + companion object { + fun fromDb(row: ResultRow): Variable { + return Variable( + id = row[VariableTable.id].value, + name = row[VariableTable.name], + originLocations = row[VariableTable.originLocations], + customFields = CustomFieldMap(row[VariableTable.customFields].toMutableMap()), + lastUpdated = row[VariableTable.lastUpdated], + created = row[VariableTable.created], + dataType = DataType.valueOf(row[VariableTable.dataType]), + defaultValue = row[VariableTable.defaultValue] + ) + } + } +} \ No newline at end of file diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/VariableStructure.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/VariableStructure.kt index 06d8252c..491f6813 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/VariableStructure.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/VariableStructure.kt @@ -1,25 +1,36 @@ package com.quadient.migration.api.dto.migrationmodel -import com.quadient.migration.data.VariableStructureModel +import com.quadient.migration.persistence.table.VariableStructureTable import com.quadient.migration.shared.VariablePathData +import kotlinx.datetime.Instant +import org.jetbrains.exposed.v1.core.ResultRow data class VariableStructure( override val id: String, override var name: String? = null, override var originLocations: List = emptyList(), override var customFields: CustomFieldMap, + override val created: Instant, + override val lastUpdated: Instant, val structure: Map, val languageVariable: VariableRef?, -) : MigrationObject { +) : MigrationObject, RefValidatable { + override fun collectRefs(): List { + return structure.keys.map { VariableRef(it) } + } companion object { - fun fromModel(model: VariableStructureModel) = VariableStructure( - id = model.id, - name = model.name, - originLocations = model.originLocations, - customFields = CustomFieldMap(model.customFields.toMutableMap()), - structure = model.structure.map { (key, value) -> key.id to value }.toMap(), - languageVariable = model.languageVariable?.let { VariableRef.fromModel(it) } - ) + fun fromDb(row: ResultRow): VariableStructure { + return VariableStructure( + id = row[VariableStructureTable.id].value, + name = row[VariableStructureTable.name], + customFields = CustomFieldMap(row[VariableStructureTable.customFields].toMutableMap()), + lastUpdated = row[VariableStructureTable.lastUpdated], + created = row[VariableStructureTable.created], + structure = row[VariableStructureTable.structure], + originLocations = row[VariableStructureTable.originLocations], + languageVariable = row[VariableStructureTable.languageVariable]?.let { VariableRef(it) } + ) + } } } \ No newline at end of file diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/DisplayRuleBuilder.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/DisplayRuleBuilder.kt index a6e565ca..ad871416 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/DisplayRuleBuilder.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/DisplayRuleBuilder.kt @@ -60,6 +60,8 @@ class DisplayRuleBuilder(id: String) : DtoBuilderBase>( @@ -17,6 +19,8 @@ abstract class DtoBuilderBase>( protected var name: String? = null protected var originLocations: List = emptyList() protected var customFields = CustomFieldMap() + protected var created: Instant = Clock.System.now() + protected var lastUpdated: Instant = Clock.System.now() /** * Sets the name of the object. If not provided the name will default to the id. @@ -74,5 +78,25 @@ abstract class DtoBuilderBase>( return this as K } + /** + * Sets the created timestamp for the object. + * @param created The created timestamp. + * @return The builder instance for method chaining. + */ + fun created(created: Instant): K { + this.created = created + return this as K + } + + /** + * Sets the lastUpdated timestamp for the object. + * @param lastUpdated The lastUpdated timestamp. + * @return The builder instance for method chaining. + */ + fun lastUpdated(lastUpdated: Instant): K { + this.lastUpdated = lastUpdated + return this as K + } + abstract fun build(): T } \ No newline at end of file diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/FileBuilder.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/FileBuilder.kt index b6c02da2..2807e34e 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/FileBuilder.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/FileBuilder.kt @@ -56,6 +56,8 @@ class FileBuilder(id: String) : DtoBuilderBase(id) { name = name, originLocations = originLocations, customFields = customFields, + created = created, + lastUpdated = lastUpdated, sourcePath = sourcePath, targetFolder = targetFolder, fileType = fileType, diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/ImageBuilder.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/ImageBuilder.kt index 45b00c17..a4ef7d43 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/ImageBuilder.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/ImageBuilder.kt @@ -94,6 +94,8 @@ class ImageBuilder(id: String) : DtoBuilderBase(id) { name = name, originLocations = originLocations, customFields = customFields, + created = created, + lastUpdated = lastUpdated, sourcePath = sourcePath, imageType = imageType, options = options, diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/ParagraphStyleBuilder.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/ParagraphStyleBuilder.kt index 2f2f5922..94d0bf6a 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/ParagraphStyleBuilder.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/ParagraphStyleBuilder.kt @@ -28,6 +28,8 @@ class ParagraphStyleBuilder(id: String) : DtoBuilderBase name = name, originLocations = originLocations, customFields = customFields, + created = created, + lastUpdated = lastUpdated, definition = definition ?: throw IllegalArgumentException("TextStyleDefinition must be provided"), ) } diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/VariableBuilder.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/VariableBuilder.kt index 0c50389a..70a32a1e 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/VariableBuilder.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/VariableBuilder.kt @@ -32,6 +32,8 @@ class VariableBuilder(id: String) : DtoBuilderBase(id name = name, originLocations = originLocations, customFields = customFields, + created = created, + lastUpdated = lastUpdated, dataType = dataType ?: throw IllegalArgumentException("dataType is required"), defaultValue = defaultValue ) diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/VariableStructureBuilder.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/VariableStructureBuilder.kt index 2801e982..49e6af2a 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/VariableStructureBuilder.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/VariableStructureBuilder.kt @@ -89,6 +89,8 @@ class VariableStructureBuilder(id: String) : DtoBuilderBase, var position: Position?, var interactiveFlowName: String?) : - DocumentContent { + DocumentContent, RefValidatable { + override fun collectRefs(): List { + return content.flatMap { + when (it) { + is RefValidatable -> it.collectRefs() + else -> emptyList() + } + } + } + companion object { - fun fromModel(model: AreaModel): Area = - Area(model.content.map { DocumentContent.fromModelContent(it) }, model.position, model.interactiveFlowName) + fun fromDb(entity: AreaEntity): Area = Area( + entity.content.map { DocumentContent.fromDbContent(it) }, entity.position, entity.interactiveFlowName + ) } fun toDb() = AreaEntity(content.toDb(), position, interactiveFlowName) diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/documentcontent/DocumentContent.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/documentcontent/DocumentContent.kt index 9a20b4e2..51491f44 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/documentcontent/DocumentContent.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/documentcontent/DocumentContent.kt @@ -1,27 +1,26 @@ package com.quadient.migration.api.dto.migrationmodel -import com.quadient.migration.data.DocumentContentModel -import com.quadient.migration.data.DocumentObjectModelRef -import com.quadient.migration.data.FirstMatchModel -import com.quadient.migration.data.AreaModel -import com.quadient.migration.data.ImageModelRef -import com.quadient.migration.data.FileModelRef -import com.quadient.migration.data.ParagraphModel -import com.quadient.migration.data.SelectByLanguageModel -import com.quadient.migration.data.TableModel import com.quadient.migration.persistence.migrationmodel.DocumentContentEntity +import com.quadient.migration.persistence.migrationmodel.AreaEntity +import com.quadient.migration.persistence.migrationmodel.FirstMatchEntity +import com.quadient.migration.persistence.migrationmodel.ParagraphEntity +import com.quadient.migration.persistence.migrationmodel.SelectByLanguageEntity +import com.quadient.migration.persistence.migrationmodel.TableEntity +import com.quadient.migration.persistence.migrationmodel.DocumentObjectEntityRef +import com.quadient.migration.persistence.migrationmodel.ImageEntityRef +import com.quadient.migration.persistence.migrationmodel.FileEntityRef sealed interface DocumentContent { companion object { - fun fromModelContent(model: DocumentContentModel) = when (model) { - is TableModel -> Table.fromModel(model) - is ParagraphModel -> Paragraph.fromModel(model) - is DocumentObjectModelRef -> DocumentObjectRef.fromModel(model) - is ImageModelRef -> ImageRef.fromModel(model) - is FileModelRef -> FileRef.fromModel(model) - is AreaModel -> Area.fromModel(model) - is FirstMatchModel -> FirstMatch.fromModel(model) - is SelectByLanguageModel -> SelectByLanguage.fromModel(model) + fun fromDbContent(entity: DocumentContentEntity): DocumentContent = when (entity) { + is TableEntity -> Table.fromDb(entity) + is ParagraphEntity -> Paragraph.fromDb(entity) + is DocumentObjectEntityRef -> DocumentObjectRef.fromDb(entity) + is ImageEntityRef -> ImageRef.fromDb(entity) + is FileEntityRef -> FileRef.fromDb(entity) + is AreaEntity -> Area.fromDb(entity) + is FirstMatchEntity -> FirstMatch.fromDb(entity) + is SelectByLanguageEntity -> SelectByLanguage.fromDb(entity) } } } diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/documentcontent/FirstMatch.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/documentcontent/FirstMatch.kt index 89fc88c0..d466f948 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/documentcontent/FirstMatch.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/documentcontent/FirstMatch.kt @@ -1,25 +1,42 @@ package com.quadient.migration.api.dto.migrationmodel -import com.quadient.migration.data.FirstMatchModel import com.quadient.migration.persistence.migrationmodel.FirstMatchEntity -data class FirstMatch(val cases: List, val default: List) : DocumentContent, TextContent { +data class FirstMatch(val cases: List, val default: List) : DocumentContent, TextContent, RefValidatable { + override fun collectRefs(): List { + return cases.flatMap { it.collectRefs() } + default.flatMap { + when (it) { + is RefValidatable -> it.collectRefs() + else -> emptyList() + } + } + } + companion object { - fun fromModel(model: FirstMatchModel): FirstMatch = FirstMatch( - cases = model.cases.map { Case.fromModel(it) }, - default = model.default.map { DocumentContent.fromModelContent(it) }) + fun fromDb(entity: FirstMatchEntity): FirstMatch = FirstMatch( + cases = entity.cases.map { Case.fromDb(it) }, + default = entity.default.map { DocumentContent.fromDbContent(it) }) } fun toDb() = FirstMatchEntity( cases = cases.map { it.toDb() }, default = default.toDb() ) - data class Case(val displayRuleRef: DisplayRuleRef, val content: List, val name: String?) { + data class Case(val displayRuleRef: DisplayRuleRef, val content: List, val name: String?) : RefValidatable { + override fun collectRefs(): List { + return listOf(displayRuleRef) + content.flatMap { + when (it) { + is RefValidatable -> it.collectRefs() + else -> emptyList() + } + } + } + companion object { - fun fromModel(model: FirstMatchModel.CaseModel) = Case( - displayRuleRef = DisplayRuleRef.fromModel(model.displayRuleRef), - content = model.content.map { DocumentContent.fromModelContent(it) }, - name = model.name + fun fromDb(entity: FirstMatchEntity.CaseEntity) = Case( + displayRuleRef = DisplayRuleRef.fromDb(entity.displayRuleRef), + content = entity.content.map { DocumentContent.fromDbContent(it) }, + name = entity.name ) } diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/documentcontent/Paragraph.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/documentcontent/Paragraph.kt index 71ac61c5..385431b9 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/documentcontent/Paragraph.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/documentcontent/Paragraph.kt @@ -1,14 +1,5 @@ package com.quadient.migration.api.dto.migrationmodel -import com.quadient.migration.data.DocumentObjectModelRef -import com.quadient.migration.data.FileModelRef -import com.quadient.migration.data.FirstMatchModel -import com.quadient.migration.data.HyperlinkModel -import com.quadient.migration.data.ImageModelRef -import com.quadient.migration.data.ParagraphModel -import com.quadient.migration.data.StringModel -import com.quadient.migration.data.TableModel -import com.quadient.migration.data.VariableModelRef import com.quadient.migration.persistence.migrationmodel.ParagraphEntity import com.quadient.migration.persistence.migrationmodel.ParagraphEntity.TextEntity @@ -16,29 +7,16 @@ data class Paragraph( val content: List, val styleRef: ParagraphStyleRef?, val displayRuleRef: DisplayRuleRef? -) : DocumentContent { +) : DocumentContent, RefValidatable { + override fun collectRefs(): List { + return content.flatMap { it.collectRefs() } + listOfNotNull(styleRef, displayRuleRef) + } + companion object { - fun fromModel(model: ParagraphModel) = Paragraph( - styleRef = model.styleRef?.let { ParagraphStyleRef.fromModel(it) }, - displayRuleRef = model.displayRuleRef?.let { DisplayRuleRef.fromModel(it) }, - content = model.content.map { - Text( - styleRef = it.styleRef?.let { TextStyleRef.fromModel(it) }, - displayRuleRef = it.displayRuleRef?.let { DisplayRuleRef.fromModel(it) }, - content = it.content.map { textContent -> - when (textContent) { - is StringModel -> StringValue.fromModel(textContent) - is VariableModelRef -> VariableRef.fromModel(textContent) - is DocumentObjectModelRef -> DocumentObjectRef.fromModel(textContent) - is TableModel -> Table.fromModel(textContent) - is ImageModelRef -> ImageRef.fromModel(textContent) - is FileModelRef -> FileRef.fromModel(textContent) - is FirstMatchModel -> FirstMatch.fromModel(textContent) - is HyperlinkModel -> Hyperlink.fromModel(textContent) - } - }) - }, - ) + fun fromDb(entity: ParagraphEntity): Paragraph = Paragraph( + styleRef = entity.styleRef?.let { ParagraphStyleRef.fromDb(it) }, + displayRuleRef = entity.displayRuleRef?.let { DisplayRuleRef.fromDb(it) }, + content = entity.content.map { Text.fromDb(it) }) } constructor(ref: VariableRef) : this( @@ -86,5 +64,21 @@ data class Paragraph( }.toMutableList(), ) - data class Text(val content: List, val styleRef: TextStyleRef?, val displayRuleRef: DisplayRuleRef?) + data class Text(val content: List, val styleRef: TextStyleRef?, val displayRuleRef: DisplayRuleRef?) : RefValidatable { + override fun collectRefs(): List { + return content.flatMap { + when (it) { + is RefValidatable -> it.collectRefs() + else -> emptyList() + } + } + listOfNotNull(styleRef, displayRuleRef) + } + + companion object { + fun fromDb(entity: TextEntity) = Text( + styleRef = entity.styleRef?.let { TextStyleRef.fromDb(it) }, + displayRuleRef = entity.displayRuleRef?.let { DisplayRuleRef.fromDb(it) }, + content = entity.content.map { TextContent.fromDb(it) }) + } + } } diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/documentcontent/SelectByLanguage.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/documentcontent/SelectByLanguage.kt index a490cc18..a2d46624 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/documentcontent/SelectByLanguage.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/documentcontent/SelectByLanguage.kt @@ -1,22 +1,34 @@ package com.quadient.migration.api.dto.migrationmodel -import com.quadient.migration.data.SelectByLanguageModel import com.quadient.migration.persistence.migrationmodel.SelectByLanguageEntity -data class SelectByLanguage(val cases: List) : DocumentContent { +data class SelectByLanguage(val cases: List) : DocumentContent, RefValidatable { + override fun collectRefs(): List { + return cases.flatMap { it.collectRefs() } + } + companion object { - fun fromModel(model: SelectByLanguageModel): SelectByLanguage = SelectByLanguage( - cases = model.cases.map { Case.fromModel(it) }, + fun fromDb(entity: SelectByLanguageEntity): SelectByLanguage = SelectByLanguage( + cases = entity.cases.map { Case.fromDb(it) }, ) } fun toDb() = SelectByLanguageEntity( cases = cases.map { it.toDb() }) - data class Case(val content: List, val language: String) { + data class Case(val content: List, val language: String) : RefValidatable { + override fun collectRefs(): List { + return content.flatMap { + when (it) { + is RefValidatable -> it.collectRefs() + else -> emptyList() + } + } + } + companion object { - fun fromModel(model: SelectByLanguageModel.CaseModel) = Case( - content = model.content.map { DocumentContent.fromModelContent(it) }, language = model.language + fun fromDb(entity: SelectByLanguageEntity.CaseEntity) = Case( + content = entity.content.map { DocumentContent.fromDbContent(it) }, language = entity.language ) } diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/documentcontent/Table.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/documentcontent/Table.kt index d2e5a2f4..a64ae18f 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/documentcontent/Table.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/documentcontent/Table.kt @@ -1,6 +1,5 @@ package com.quadient.migration.api.dto.migrationmodel -import com.quadient.migration.data.TableModel import com.quadient.migration.persistence.migrationmodel.TableEntity import com.quadient.migration.persistence.migrationmodel.TableEntity.ColumnWidthEntity import com.quadient.migration.shared.Size @@ -11,21 +10,25 @@ data class Table( val columnWidths: List, val pdfTaggingRule: TablePdfTaggingRule = TablePdfTaggingRule.Default, val pdfAlternateText: String? = null, -) : DocumentContent, TextContent { +) : DocumentContent, TextContent, RefValidatable { + override fun collectRefs(): List { + return rows.flatMap { it.collectRefs() } + } + companion object { - fun fromModel(model: TableModel): Table = Table( - rows = model.rows.map { row -> + fun fromDb(table: TableEntity): Table = Table( + rows = table.rows.map { row -> Row(row.cells.map { cell -> Cell( - cell.content.map { DocumentContent.fromModelContent(it) }, + cell.content.map { DocumentContent.fromDbContent(it) }, cell.mergeLeft, cell.mergeUp, ) - }, displayRuleRef = row.displayRuleRef?.let { DisplayRuleRef.fromModel(it) }) + }, displayRuleRef = row.displayRuleRef?.let { DisplayRuleRef.fromDb(it) }) }, - columnWidths = model.columnWidths.map { ColumnWidth(it.minWidth, it.percentWidth) }, - pdfTaggingRule = model.pdfTaggingRule, - pdfAlternateText = model.pdfAlternateText + columnWidths = table.columnWidths.map { ColumnWidth(it.minWidth, it.percentWidth) }, + pdfTaggingRule = table.pdfTaggingRule, + pdfAlternateText = table.pdfAlternateText ) } @@ -46,13 +49,26 @@ data class Table( ) } - data class Row(val cells: List, val displayRuleRef: DisplayRuleRef? = null) + data class Row(val cells: List, val displayRuleRef: DisplayRuleRef? = null) : RefValidatable { + override fun collectRefs(): List { + return cells.flatMap { it.collectRefs() } + listOfNotNull(displayRuleRef) + } + } data class Cell( val content: List, val mergeLeft: Boolean, val mergeUp: Boolean, - ) + ) : RefValidatable { + override fun collectRefs(): List { + return content.flatMap { + when (it) { + is RefValidatable -> it.collectRefs() + else -> emptyList() + } + } + } + } data class ColumnWidth(val minWidth: Size, val percentWidth: Double) } diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/DisplayRuleRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/DisplayRuleRepository.kt index 48f423f4..a678c269 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/DisplayRuleRepository.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/DisplayRuleRepository.kt @@ -1,10 +1,8 @@ package com.quadient.migration.api.repository -import com.quadient.migration.api.dto.migrationmodel.CustomFieldMap import com.quadient.migration.api.dto.migrationmodel.DisplayRule import com.quadient.migration.api.dto.migrationmodel.DocumentObject import com.quadient.migration.api.dto.migrationmodel.MigrationObject -import com.quadient.migration.data.DisplayRuleModel import com.quadient.migration.persistence.repository.InternalRepository import com.quadient.migration.persistence.table.DisplayRuleTable import com.quadient.migration.persistence.table.DocumentObjectTable @@ -14,23 +12,17 @@ import org.jetbrains.exposed.v1.jdbc.selectAll import org.jetbrains.exposed.v1.jdbc.transactions.transaction import org.jetbrains.exposed.v1.jdbc.upsertReturning -class DisplayRuleRepository(internalRepository: InternalRepository) : - Repository(internalRepository) { - override fun toDto(model: DisplayRuleModel): DisplayRule { - return DisplayRule( - id = model.id, - name = model.name, - originLocations = model.originLocations, - customFields = CustomFieldMap(model.customFields.toMutableMap()), - definition = model.definition, - ) +class DisplayRuleRepository(internalRepository: InternalRepository) : + Repository(internalRepository) { + override fun toDto(model: DisplayRule): DisplayRule { + return model } override fun findUsages(id: String): List { return transaction { DocumentObjectTable.selectAll().where { DocumentObjectTable.projectName eq internalRepository.projectName } .map { DocumentObjectTable.fromResultRow(it) } - .filter { it.collectRefs().any { it.id == id } }.map { DocumentObject.fromModel(it) } + .filter { it.collectRefs().any { it.id == id } } .distinct() } } diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/DocumentObjectRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/DocumentObjectRepository.kt index 6e70bb41..252f2598 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/DocumentObjectRepository.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/DocumentObjectRepository.kt @@ -4,7 +4,6 @@ import com.quadient.migration.api.dto.migrationmodel.DocumentObject import com.quadient.migration.api.dto.migrationmodel.DocumentObjectFilter import com.quadient.migration.api.dto.migrationmodel.MigrationObject import com.quadient.migration.api.dto.migrationmodel.toDb -import com.quadient.migration.data.DocumentObjectModel import com.quadient.migration.persistence.repository.DocumentObjectInternalRepository import com.quadient.migration.persistence.table.DocumentObjectTable import com.quadient.migration.service.deploy.ResourceType @@ -22,20 +21,20 @@ import org.jetbrains.exposed.v1.jdbc.transactions.transaction import org.jetbrains.exposed.v1.jdbc.upsertReturning class DocumentObjectRepository(internalRepository: DocumentObjectInternalRepository) : - Repository(internalRepository) { + Repository(internalRepository) { val statusTrackingRepository = StatusTrackingRepository(internalRepository.projectName) fun list(documentObjectFilter: DocumentObjectFilter): List { return internalRepository.list(filter(documentObjectFilter)).map(::toDto) } - override fun toDto(model: DocumentObjectModel): DocumentObject = DocumentObject.fromModel(model) + override fun toDto(model: DocumentObject): DocumentObject = model override fun findUsages(id: String): List { return transaction { DocumentObjectTable.selectAll().where { DocumentObjectTable.projectName eq internalRepository.projectName } .map { DocumentObjectTable.fromResultRow(it) }.filter { it.collectRefs().any { it.id == id } } - .map { DocumentObject.fromModel(it) }.distinct() + .distinct() } } diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/FileRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/FileRepository.kt index f39b2c31..14ee6399 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/FileRepository.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/FileRepository.kt @@ -1,10 +1,8 @@ package com.quadient.migration.api.repository -import com.quadient.migration.api.dto.migrationmodel.CustomFieldMap import com.quadient.migration.api.dto.migrationmodel.DocumentObject import com.quadient.migration.api.dto.migrationmodel.File import com.quadient.migration.api.dto.migrationmodel.MigrationObject -import com.quadient.migration.data.FileModel import com.quadient.migration.persistence.repository.FileInternalRepository import com.quadient.migration.persistence.table.DocumentObjectTable import com.quadient.migration.persistence.table.FileTable @@ -15,27 +13,18 @@ import org.jetbrains.exposed.v1.jdbc.selectAll import org.jetbrains.exposed.v1.jdbc.transactions.transaction import org.jetbrains.exposed.v1.jdbc.upsertReturning -class FileRepository(internalRepository: FileInternalRepository) : Repository(internalRepository) { +class FileRepository(internalRepository: FileInternalRepository) : Repository(internalRepository) { val statusTrackingRepository = StatusTrackingRepository(internalRepository.projectName) - override fun toDto(model: FileModel): File { - return File( - id = model.id, - name = model.name, - originLocations = model.originLocations, - customFields = CustomFieldMap(model.customFields.toMutableMap()), - sourcePath = model.sourcePath, - targetFolder = model.targetFolder?.toString(), - fileType = model.fileType, - skip = model.skip, - ) + override fun toDto(model: File): File { + return model } override fun findUsages(id: String): List { return transaction { DocumentObjectTable.selectAll().where { DocumentObjectTable.projectName eq internalRepository.projectName } .map { DocumentObjectTable.fromResultRow(it) }.filter { it.collectRefs().any { it.id == id } } - .map { DocumentObject.fromModel(it) }.distinct() + .distinct() } } diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/ImageRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/ImageRepository.kt index 8549dbc2..958cd389 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/ImageRepository.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/ImageRepository.kt @@ -1,10 +1,8 @@ package com.quadient.migration.api.repository -import com.quadient.migration.api.dto.migrationmodel.CustomFieldMap import com.quadient.migration.api.dto.migrationmodel.DocumentObject import com.quadient.migration.api.dto.migrationmodel.Image import com.quadient.migration.api.dto.migrationmodel.MigrationObject -import com.quadient.migration.data.ImageModel import com.quadient.migration.persistence.repository.ImageInternalRepository import com.quadient.migration.persistence.table.DocumentObjectTable import com.quadient.migration.persistence.table.ImageTable @@ -16,30 +14,18 @@ import org.jetbrains.exposed.v1.jdbc.selectAll import org.jetbrains.exposed.v1.jdbc.transactions.transaction import org.jetbrains.exposed.v1.jdbc.upsertReturning -class ImageRepository(internalRepository: ImageInternalRepository) : Repository(internalRepository) { +class ImageRepository(internalRepository: ImageInternalRepository) : Repository(internalRepository) { val statusTrackingRepository = StatusTrackingRepository(internalRepository.projectName) - override fun toDto(model: ImageModel): Image { - return Image( - id = model.id, - name = model.name, - originLocations = model.originLocations, - customFields = CustomFieldMap(model.customFields.toMutableMap()), - sourcePath = model.sourcePath, - options = model.options, - imageType = model.imageType, - targetFolder = model.targetFolder?.toString(), - metadata = model.metadata, - skip = model.skip, - alternateText = model.alternateText, - ) + override fun toDto(model: Image): Image { + return model } override fun findUsages(id: String): List { return transaction { DocumentObjectTable.selectAll().where { DocumentObjectTable.projectName eq internalRepository.projectName } .map { DocumentObjectTable.fromResultRow(it) }.filter { it.collectRefs().any { it.id == id } } - .map { DocumentObject.fromModel(it) }.distinct() + .distinct() } } diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/MappingRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/MappingRepository.kt index 6387abf0..0cdc8a39 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/MappingRepository.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/MappingRepository.kt @@ -191,6 +191,8 @@ class MappingRepository( name = null, originLocations = emptyList(), customFields = CustomFieldMap(), + created = kotlinx.datetime.Clock.System.now(), + lastUpdated = kotlinx.datetime.Clock.System.now(), structure = mutableMapOf(), languageVariable = null, ) diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/ParagraphStyleRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/ParagraphStyleRepository.kt index 06189122..14acc06e 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/ParagraphStyleRepository.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/ParagraphStyleRepository.kt @@ -1,11 +1,8 @@ package com.quadient.migration.api.repository -import com.quadient.migration.api.dto.migrationmodel.CustomFieldMap import com.quadient.migration.api.dto.migrationmodel.DocumentObject import com.quadient.migration.api.dto.migrationmodel.MigrationObject import com.quadient.migration.api.dto.migrationmodel.ParagraphStyle -import com.quadient.migration.api.dto.migrationmodel.ParagraphStyleDefOrRef -import com.quadient.migration.data.ParagraphStyleModel import com.quadient.migration.persistence.repository.ParagraphStyleInternalRepository import com.quadient.migration.persistence.table.DocumentObjectTable import com.quadient.migration.persistence.table.ParagraphStyleTable @@ -18,24 +15,18 @@ import org.jetbrains.exposed.v1.jdbc.upsertReturning import kotlin.collections.map class ParagraphStyleRepository(internalRepository: ParagraphStyleInternalRepository) : - Repository(internalRepository) { + Repository(internalRepository) { val statusTrackingRepository = StatusTrackingRepository(internalRepository.projectName) - override fun toDto(model: ParagraphStyleModel): ParagraphStyle { - return ParagraphStyle( - id = model.id, - name = model.name, - originLocations = model.originLocations, - customFields = CustomFieldMap(model.customFields.toMutableMap()), - definition = ParagraphStyleDefOrRef.fromModel(model.definition), - ) + override fun toDto(model: ParagraphStyle): ParagraphStyle { + return model } override fun findUsages(id: String): List { return transaction { DocumentObjectTable.selectAll().where { DocumentObjectTable.projectName eq internalRepository.projectName } .map { DocumentObjectTable.fromResultRow(it) }.filter { it.collectRefs().any { it.id == id } } - .map { DocumentObject.fromModel(it) }.distinct() + .distinct() } } diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/Repository.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/Repository.kt index 6da13e40..8f1c40a5 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/Repository.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/Repository.kt @@ -2,15 +2,14 @@ package com.quadient.migration.api.repository import com.quadient.migration.api.dto.migrationmodel.MigrationObject import com.quadient.migration.api.dto.migrationmodel.Ref -import com.quadient.migration.data.MigrationObjectModel +import com.quadient.migration.api.dto.migrationmodel.RefValidatable import com.quadient.migration.persistence.repository.InternalRepository -import com.quadient.migration.service.RefValidatable import org.jetbrains.exposed.v1.jdbc.transactions.transaction -abstract class Repository( - protected val internalRepository: InternalRepository +abstract class Repository( + protected val internalRepository: InternalRepository ) { - abstract fun toDto(model: K): T + abstract fun toDto(model: T): T fun listAll(): List = internalRepository.listAllModel().map(::toDto) fun find(id: String): T? = internalRepository.findModel(id)?.let(::toDto) @@ -28,7 +27,7 @@ abstract class Repository( fun findRefs(id: String): List { val model = internalRepository.findModel(id) if (model != null && model is RefValidatable) { - return model.collectRefs().map { Ref.fromModel(it) } + return model.collectRefs() } return emptyList() } diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/TextStyleRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/TextStyleRepository.kt index 20a29c8e..4a5279ab 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/TextStyleRepository.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/TextStyleRepository.kt @@ -1,11 +1,7 @@ package com.quadient.migration.api.repository -import com.quadient.migration.api.dto.migrationmodel.CustomFieldMap -import com.quadient.migration.api.dto.migrationmodel.DocumentObject import com.quadient.migration.api.dto.migrationmodel.MigrationObject import com.quadient.migration.api.dto.migrationmodel.TextStyle -import com.quadient.migration.api.dto.migrationmodel.TextStyleDefOrRef -import com.quadient.migration.data.TextStyleModel import com.quadient.migration.persistence.repository.TextStyleInternalRepository import com.quadient.migration.persistence.table.DocumentObjectTable import com.quadient.migration.persistence.table.TextStyleTable @@ -18,24 +14,18 @@ import org.jetbrains.exposed.v1.jdbc.upsertReturning import kotlin.collections.map class TextStyleRepository(internalRepository: TextStyleInternalRepository) : - Repository(internalRepository) { + Repository(internalRepository) { val statusTrackingRepository = StatusTrackingRepository(internalRepository.projectName) - override fun toDto(model: TextStyleModel): TextStyle { - return TextStyle( - id = model.id, - name = model.name, - originLocations = model.originLocations, - customFields = CustomFieldMap(model.customFields.toMutableMap()), - definition = TextStyleDefOrRef.fromModel(model.definition), - ) + override fun toDto(model: TextStyle): TextStyle { + return model } override fun findUsages(id: String): List { return transaction { DocumentObjectTable.selectAll().where { DocumentObjectTable.projectName eq internalRepository.projectName } .map { DocumentObjectTable.fromResultRow(it) } - .filter { it.collectRefs().any { it.id == id } }.map { DocumentObject.fromModel(it) } + .filter { it.collectRefs().any { it.id == id } } .distinct() } } diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/VariableRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/VariableRepository.kt index 78402a7c..6ea4deed 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/VariableRepository.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/VariableRepository.kt @@ -1,10 +1,7 @@ package com.quadient.migration.api.repository -import com.quadient.migration.api.dto.migrationmodel.CustomFieldMap -import com.quadient.migration.api.dto.migrationmodel.DocumentObject import com.quadient.migration.api.dto.migrationmodel.MigrationObject import com.quadient.migration.api.dto.migrationmodel.Variable -import com.quadient.migration.data.VariableModel import com.quadient.migration.persistence.repository.VariableInternalRepository import com.quadient.migration.persistence.table.DocumentObjectTable import com.quadient.migration.persistence.table.VariableTable @@ -16,23 +13,16 @@ import org.jetbrains.exposed.v1.jdbc.upsertReturning import kotlin.collections.map class VariableRepository(internalRepository: VariableInternalRepository) : - Repository(internalRepository) { - override fun toDto(model: VariableModel): Variable { - return Variable( - id = model.id, - name = model.name, - originLocations = model.originLocations, - customFields = CustomFieldMap(model.customFields.toMutableMap()), - dataType = model.dataType, - defaultValue = model.defaultValue - ) + Repository(internalRepository) { + override fun toDto(model: Variable): Variable { + return model } override fun findUsages(id: String): List { return transaction { DocumentObjectTable.selectAll().where { DocumentObjectTable.projectName eq internalRepository.projectName } .map { DocumentObjectTable.fromResultRow(it) }.filter { it.collectRefs().any { it.id == id } } - .map { DocumentObject.fromModel(it) }.distinct() + .distinct() } } diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/VariableStructureRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/VariableStructureRepository.kt index 298f8ada..a0940046 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/VariableStructureRepository.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/VariableStructureRepository.kt @@ -1,11 +1,8 @@ package com.quadient.migration.api.repository -import com.quadient.migration.api.dto.migrationmodel.CustomFieldMap import com.quadient.migration.api.dto.migrationmodel.DocumentObject import com.quadient.migration.api.dto.migrationmodel.MigrationObject -import com.quadient.migration.api.dto.migrationmodel.VariableRef import com.quadient.migration.api.dto.migrationmodel.VariableStructure -import com.quadient.migration.data.VariableStructureModel import com.quadient.migration.persistence.repository.VariableStructureInternalRepository import com.quadient.migration.persistence.table.DocumentObjectTable import com.quadient.migration.persistence.table.VariableStructureTable @@ -17,23 +14,16 @@ import org.jetbrains.exposed.v1.jdbc.upsertReturning import kotlin.collections.map class VariableStructureRepository(internalRepository: VariableStructureInternalRepository) : - Repository(internalRepository) { - override fun toDto(model: VariableStructureModel): VariableStructure { - return VariableStructure( - id = model.id, - name = model.name, - originLocations = model.originLocations, - customFields = CustomFieldMap(model.customFields.toMutableMap()), - structure = model.structure.map { (key, value) -> key.id to value }.toMap(), - languageVariable = model.languageVariable?.let { VariableRef.fromModel(it) } - ) + Repository(internalRepository) { + override fun toDto(model: VariableStructure): VariableStructure { + return model } override fun findUsages(id: String): List { return transaction { DocumentObjectTable.selectAll().where { DocumentObjectTable.projectName eq internalRepository.projectName } .map { DocumentObjectTable.fromResultRow(it) }.filter { it.collectRefs().any { it.id == id } } - .map { DocumentObject.fromModel(it) }.distinct() + .distinct() } } diff --git a/migration-library/src/main/kotlin/com/quadient/migration/data/DisplayRuleModel.kt b/migration-library/src/main/kotlin/com/quadient/migration/data/DisplayRuleModel.kt deleted file mode 100644 index 55c7fb4b..00000000 --- a/migration-library/src/main/kotlin/com/quadient/migration/data/DisplayRuleModel.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.quadient.migration.data - -import com.quadient.migration.service.RefValidatable -import com.quadient.migration.shared.DisplayRuleDefinition -import kotlinx.datetime.Instant - -data class DisplayRuleModel( - override val id: String, - override val name: String? = null, - override val originLocations: List = emptyList(), - override val customFields: Map, - override val created: Instant, - val customFieldsMap: Map = emptyMap(), - val lastUpdated: Instant, - val definition: DisplayRuleDefinition? -) : RefValidatable, MigrationObjectModel { - override fun collectRefs(): List { - return definition?.collectRefs() ?: emptyList() - } -} diff --git a/migration-library/src/main/kotlin/com/quadient/migration/data/DocumentObjectModel.kt b/migration-library/src/main/kotlin/com/quadient/migration/data/DocumentObjectModel.kt deleted file mode 100644 index 88ad305f..00000000 --- a/migration-library/src/main/kotlin/com/quadient/migration/data/DocumentObjectModel.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.quadient.migration.data - -import com.quadient.migration.service.RefValidatable -import com.quadient.migration.shared.DocumentObjectOptions -import com.quadient.migration.shared.DocumentObjectType -import com.quadient.migration.shared.IcmPath -import com.quadient.migration.shared.MetadataPrimitive -import com.quadient.migration.shared.SkipOptions -import kotlinx.datetime.Instant - -data class DocumentObjectModel( - override val id: String, - override val name: String?, - val type: DocumentObjectType, - val content: List, - val internal: Boolean, - val targetFolder: IcmPath? = null, - override val originLocations: List, - override val customFields: Map, - override val created: Instant, - val lastUpdated: Instant, - val displayRuleRef: DisplayRuleModelRef? = null, - val variableStructureRef: VariableStructureModelRef? = null, - val baseTemplate: String?, - val options: DocumentObjectOptions?, - val metadata: Map>, - val skip: SkipOptions, - val subject: String?, -) : RefValidatable, MigrationObjectModel { - override fun collectRefs(): List { - return this.content.map { - when (it) { - is RefModel -> it.collectRefs() - is TableModel -> it.collectRefs() - is ParagraphModel -> it.collectRefs() - is AreaModel -> it.collectRefs() - is FirstMatchModel -> it.collectRefs() - is SelectByLanguageModel -> it.collectRefs() - } - }.flatten() + (displayRuleRef?.let { listOf(it) } ?: emptyList()) - } - -} \ No newline at end of file diff --git a/migration-library/src/main/kotlin/com/quadient/migration/data/FileModel.kt b/migration-library/src/main/kotlin/com/quadient/migration/data/FileModel.kt deleted file mode 100644 index 15c7846c..00000000 --- a/migration-library/src/main/kotlin/com/quadient/migration/data/FileModel.kt +++ /dev/null @@ -1,23 +0,0 @@ -package com.quadient.migration.data - -import com.quadient.migration.service.RefValidatable -import com.quadient.migration.shared.FileType -import com.quadient.migration.shared.IcmPath -import com.quadient.migration.shared.SkipOptions -import kotlinx.datetime.Instant - -data class FileModel( - override val id: String, - override val name: String?, - override val originLocations: List, - override val customFields: Map, - override val created: Instant, - val sourcePath: String?, - val targetFolder: IcmPath?, - val fileType: FileType, - val skip: SkipOptions, -) : RefValidatable, MigrationObjectModel { - override fun collectRefs(): List { - return emptyList() - } -} diff --git a/migration-library/src/main/kotlin/com/quadient/migration/data/HyperlinkModel.kt b/migration-library/src/main/kotlin/com/quadient/migration/data/HyperlinkModel.kt deleted file mode 100644 index 12df79bf..00000000 --- a/migration-library/src/main/kotlin/com/quadient/migration/data/HyperlinkModel.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.quadient.migration.data - -import com.quadient.migration.persistence.migrationmodel.HyperlinkEntity - -data class HyperlinkModel( - val url: String, - val displayText: String? = null, - val alternateText: String? = null -) : TextContentModel { - companion object { - fun fromDb(entity: HyperlinkEntity) = HyperlinkModel( - url = entity.url, - displayText = entity.displayText, - alternateText = entity.alternateText - ) - } -} diff --git a/migration-library/src/main/kotlin/com/quadient/migration/data/ImageModel.kt b/migration-library/src/main/kotlin/com/quadient/migration/data/ImageModel.kt deleted file mode 100644 index 3c85e8f1..00000000 --- a/migration-library/src/main/kotlin/com/quadient/migration/data/ImageModel.kt +++ /dev/null @@ -1,28 +0,0 @@ -package com.quadient.migration.data - -import com.quadient.migration.service.RefValidatable -import com.quadient.migration.shared.IcmPath -import com.quadient.migration.shared.ImageOptions -import com.quadient.migration.shared.ImageType -import com.quadient.migration.shared.MetadataPrimitive -import com.quadient.migration.shared.SkipOptions -import kotlinx.datetime.Instant - -data class ImageModel( - override val id: String, - override val name: String?, - override val originLocations: List, - override val customFields: Map, - override val created: Instant, - val sourcePath: String?, - val imageType: ImageType, - val options: ImageOptions?, - val targetFolder: IcmPath?, - val metadata: Map>, - val skip: SkipOptions, - val alternateText: String? = null, -) : RefValidatable, MigrationObjectModel { - override fun collectRefs(): List { - return emptyList() - } -} \ No newline at end of file diff --git a/migration-library/src/main/kotlin/com/quadient/migration/data/MigrationObjectModel.kt b/migration-library/src/main/kotlin/com/quadient/migration/data/MigrationObjectModel.kt deleted file mode 100644 index 8bd8701d..00000000 --- a/migration-library/src/main/kotlin/com/quadient/migration/data/MigrationObjectModel.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.quadient.migration.data - -import kotlinx.datetime.Instant - -interface MigrationObjectModel { - val id: String - val name: String? - val originLocations: List - val customFields: Map - val created: Instant - - fun nameOrId(): String { - val name = name - return if (name.isNullOrBlank()) { - id - } else { - name - } - } -} \ No newline at end of file diff --git a/migration-library/src/main/kotlin/com/quadient/migration/data/ParagraphStyleModel.kt b/migration-library/src/main/kotlin/com/quadient/migration/data/ParagraphStyleModel.kt deleted file mode 100644 index 583cb85a..00000000 --- a/migration-library/src/main/kotlin/com/quadient/migration/data/ParagraphStyleModel.kt +++ /dev/null @@ -1,74 +0,0 @@ -package com.quadient.migration.data - -import com.quadient.migration.persistence.migrationmodel.ParagraphStyleDefinitionEntity -import com.quadient.migration.persistence.migrationmodel.TabEntity -import com.quadient.migration.persistence.migrationmodel.TabsEntity -import com.quadient.migration.service.RefValidatable -import com.quadient.migration.shared.Alignment -import com.quadient.migration.shared.LineSpacing -import com.quadient.migration.shared.Size -import com.quadient.migration.shared.TabType -import kotlinx.datetime.Instant - -data class ParagraphStyleModel( - override val id: String, - override var name: String? = null, - override var originLocations: List = emptyList(), - override val customFields: Map, - override val created: Instant, - val lastUpdated: Instant, - val definition: ParagraphStyleDefOrRefModel, -) : RefValidatable, MigrationObjectModel { - override fun collectRefs(): List { - return when (definition) { - is ParagraphStyleDefinitionModel -> emptyList() - is ParagraphStyleModelRef -> listOf(definition) - } - } -} - -data class ParagraphStyleDefinitionModel( - val leftIndent: Size?, - val rightIndent: Size?, - val defaultTabSize: Size?, - val spaceBefore: Size?, - val spaceAfter: Size?, - val alignment: Alignment, - val firstLineIndent: Size?, - val lineSpacing: LineSpacing, - val keepWithNextParagraph: Boolean?, - val tabs: TabsModel?, - val pdfTaggingRule: com.quadient.migration.shared.ParagraphPdfTaggingRule?, -) : ParagraphStyleDefOrRefModel { - companion object { - fun fromDb(entity: ParagraphStyleDefinitionEntity) = ParagraphStyleDefinitionModel( - leftIndent = entity.leftIndent, - rightIndent = entity.rightIndent, - defaultTabSize = entity.defaultTabSize, - spaceBefore = entity.spaceBefore, - spaceAfter = entity.spaceAfter, - alignment = entity.alignment, - firstLineIndent = entity.firstLineIndent, - lineSpacing = entity.lineSpacing, - keepWithNextParagraph = entity.keepWithNextParagraph, - tabs = entity.tabs?.let { TabsModel.fromDb(it) }, - pdfTaggingRule = entity.pdfTaggingRule - ) - } -} - -data class TabsModel(val tabs: List, val useOutsideTabs: Boolean) { - companion object { - fun fromDb(entity: TabsEntity) = TabsModel( - tabs = entity.tabs.map { TabModel.fromDb(it) }, - useOutsideTabs = entity.useOutsideTabs - ) - } -} - -data class TabModel(val position: Size, val type: TabType) { - companion object { - fun fromDb(entity: TabEntity) = TabModel(position = entity.position, type = entity.type) - } -} - diff --git a/migration-library/src/main/kotlin/com/quadient/migration/data/RefModel.kt b/migration-library/src/main/kotlin/com/quadient/migration/data/RefModel.kt deleted file mode 100644 index 7f5cd0d6..00000000 --- a/migration-library/src/main/kotlin/com/quadient/migration/data/RefModel.kt +++ /dev/null @@ -1,123 +0,0 @@ -package com.quadient.migration.data - -import com.quadient.migration.persistence.migrationmodel.DisplayRuleEntityRef -import com.quadient.migration.persistence.migrationmodel.DocumentObjectEntityRef -import com.quadient.migration.persistence.migrationmodel.FirstMatchEntity -import com.quadient.migration.persistence.migrationmodel.HyperlinkEntity -import com.quadient.migration.persistence.migrationmodel.ImageEntityRef -import com.quadient.migration.persistence.migrationmodel.FileEntityRef -import com.quadient.migration.persistence.migrationmodel.ParagraphStyleDefOrRefEntity -import com.quadient.migration.persistence.migrationmodel.ParagraphStyleDefinitionEntity -import com.quadient.migration.persistence.migrationmodel.ParagraphStyleEntityRef -import com.quadient.migration.persistence.migrationmodel.StringEntity -import com.quadient.migration.persistence.migrationmodel.TableEntity -import com.quadient.migration.persistence.migrationmodel.TextContentEntity -import com.quadient.migration.persistence.migrationmodel.TextStyleDefOrRefEntity -import com.quadient.migration.persistence.migrationmodel.TextStyleDefinitionEntity -import com.quadient.migration.persistence.migrationmodel.TextStyleEntityRef -import com.quadient.migration.persistence.migrationmodel.VariableEntityRef -import com.quadient.migration.persistence.migrationmodel.VariableStructureEntityRef - -sealed interface RefModel { - val id: String -} - -sealed interface TextContentModel { - companion object { - fun fromDb(entity: TextContentEntity): TextContentModel = when (entity) { - is StringEntity -> StringModel.fromDb(entity) - is VariableEntityRef -> VariableModelRef.fromDb(entity) - is TableEntity -> TableModel.fromDb(entity) - is DocumentObjectEntityRef -> DocumentObjectModelRef.fromDb(entity) - is ImageEntityRef -> ImageModelRef.fromDb(entity) - is FileEntityRef -> FileModelRef.fromDb(entity) - is FirstMatchEntity -> FirstMatchModel.fromDb(entity) - is HyperlinkEntity -> HyperlinkModel.fromDb(entity) - } - } -} - -sealed interface TextStyleDefOrRefModel { - companion object { - fun fromDb(entity: TextStyleDefOrRefEntity) = when (entity) { - is TextStyleDefinitionEntity -> TextStyleDefinitionModel.fromDb(entity) - is TextStyleEntityRef -> TextStyleModelRef.fromDb(entity) - } - } -} -sealed interface ParagraphStyleDefOrRefModel { - companion object { - fun fromDb(entity: ParagraphStyleDefOrRefEntity) = when (entity) { - is ParagraphStyleDefinitionEntity -> ParagraphStyleDefinitionModel.fromDb(entity) - is ParagraphStyleEntityRef -> ParagraphStyleModelRef.fromDb(entity) - } - } -} - -data class DocumentObjectModelRef(override val id: String, val displayRuleRef: DisplayRuleModelRef?) : RefModel, - DocumentContentModel, TextContentModel { - override fun collectRefs(): List { - return listOfNotNull(this, this.displayRuleRef) - } - - companion object { - fun fromDb(entity: DocumentObjectEntityRef) = - DocumentObjectModelRef(entity.id, entity.displayRuleRef?.let { DisplayRuleModelRef.fromDb(it) }) - } -} - -data class VariableModelRef(override val id: String) : RefModel, TextContentModel { - companion object { - fun fromDb(entity: VariableEntityRef) = VariableModelRef(entity.id) - } -} - -data class TextStyleModelRef(override val id: String) : RefModel, TextStyleDefOrRefModel { - companion object { - fun fromDb(entity: TextStyleEntityRef) = TextStyleModelRef(entity.id) - } -} - -data class ParagraphStyleModelRef(override val id: String) : RefModel, ParagraphStyleDefOrRefModel { - companion object { - fun fromDb(entity: ParagraphStyleEntityRef) = ParagraphStyleModelRef(entity.id) - } -} - -data class DisplayRuleModelRef(override val id: String) : RefModel { - companion object { - fun fromDb(entity: DisplayRuleEntityRef) = DisplayRuleModelRef(entity.id) - } -} - -data class ImageModelRef(override val id: String) : RefModel, DocumentContentModel, TextContentModel { - override fun collectRefs(): List { - return listOf(this) - } - - companion object { - fun fromDb(entity: ImageEntityRef) = ImageModelRef(entity.id) - } -} - -data class FileModelRef(override val id: String) : RefModel, DocumentContentModel, TextContentModel { - override fun collectRefs(): List { - return listOf(this) - } - - companion object { - fun fromDb(entity: FileEntityRef) = FileModelRef(entity.id) - } -} - -data class VariableStructureModelRef(override val id: String) : RefModel { - companion object { - fun fromDb(entity: VariableStructureEntityRef) = VariableStructureModelRef(entity.id) - } -} - -data class StringModel(val value: String) : TextContentModel { - companion object { - fun fromDb(entity: StringEntity) = StringModel(entity.value) - } -} diff --git a/migration-library/src/main/kotlin/com/quadient/migration/data/TextStyleModel.kt b/migration-library/src/main/kotlin/com/quadient/migration/data/TextStyleModel.kt deleted file mode 100644 index 35cead66..00000000 --- a/migration-library/src/main/kotlin/com/quadient/migration/data/TextStyleModel.kt +++ /dev/null @@ -1,51 +0,0 @@ -package com.quadient.migration.data - -import com.quadient.migration.persistence.migrationmodel.TextStyleDefinitionEntity -import com.quadient.migration.service.RefValidatable -import com.quadient.migration.shared.Color -import com.quadient.migration.shared.Size -import com.quadient.migration.shared.SuperOrSubscript -import kotlinx.datetime.Instant - -data class TextStyleModel ( - override val id: String, - override val name: String? = null, - override val originLocations: List = emptyList(), - override val customFields: Map, - override val created: Instant, - val lastUpdated: Instant, - val definition: TextStyleDefOrRefModel, -) : RefValidatable, MigrationObjectModel { - override fun collectRefs(): List { - return when (definition) { - is TextStyleDefinitionModel -> emptyList() - is TextStyleModelRef -> listOf(definition) - } - } -} - -data class TextStyleDefinitionModel( - val fontFamily: String? = null, - val foregroundColor: Color? = null, - val size: Size? = null, - val bold: Boolean = false, - val italic: Boolean = false, - val underline: Boolean = false, - val strikethrough: Boolean = false, - val superOrSubscript: SuperOrSubscript, - val interspacing: Size?, -): TextStyleDefOrRefModel { - companion object { - fun fromDb(entity: TextStyleDefinitionEntity) = TextStyleDefinitionModel( - fontFamily = entity.fontFamily, - foregroundColor = entity.foregroundColor, - size = entity.size, - bold = entity.bold, - italic = entity.italic, - underline = entity.underline, - strikethrough = entity.strikethrough, - superOrSubscript = entity.superOrSubscript, - interspacing = entity.interspacing, - ) - } -} \ No newline at end of file diff --git a/migration-library/src/main/kotlin/com/quadient/migration/data/VariableModel.kt b/migration-library/src/main/kotlin/com/quadient/migration/data/VariableModel.kt deleted file mode 100644 index 67f8e41e..00000000 --- a/migration-library/src/main/kotlin/com/quadient/migration/data/VariableModel.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.quadient.migration.data - -import com.quadient.migration.service.RefValidatable -import com.quadient.migration.shared.DataType -import kotlinx.datetime.Instant - -data class VariableModel( - override val id: String, - override val name: String? = null, - override val originLocations: List = emptyList(), - override val customFields: Map, - override val created: Instant, - val lastUpdated: Instant, - val dataType: DataType, - val defaultValue: String? -) : RefValidatable, MigrationObjectModel { - override fun collectRefs(): List { - return emptyList() - } -} diff --git a/migration-library/src/main/kotlin/com/quadient/migration/data/VariableStructureModel.kt b/migration-library/src/main/kotlin/com/quadient/migration/data/VariableStructureModel.kt deleted file mode 100644 index 37f004ea..00000000 --- a/migration-library/src/main/kotlin/com/quadient/migration/data/VariableStructureModel.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.quadient.migration.data - -import com.quadient.migration.service.RefValidatable -import com.quadient.migration.shared.VariablePathData -import kotlinx.datetime.Instant - -data class VariableStructureModel( - override val id: String, - override val name: String? = null, - override val originLocations: List = emptyList(), - override val customFields: Map, - override val created: Instant, - val lastUpdated: Instant, - val languageVariable: VariableModelRef?, - val structure: Map -) : RefValidatable, MigrationObjectModel { - override fun collectRefs(): List { - return structure.keys.map { it } - } -} \ No newline at end of file diff --git a/migration-library/src/main/kotlin/com/quadient/migration/data/documentcontent/AreaModel.kt b/migration-library/src/main/kotlin/com/quadient/migration/data/documentcontent/AreaModel.kt deleted file mode 100644 index b9d4d35c..00000000 --- a/migration-library/src/main/kotlin/com/quadient/migration/data/documentcontent/AreaModel.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.quadient.migration.data - -import com.quadient.migration.persistence.migrationmodel.AreaEntity -import com.quadient.migration.shared.Position - -data class AreaModel(val content: List, val position: Position?, val interactiveFlowName: String?) : DocumentContentModel { - override fun collectRefs(): List { - return content.flatMap { it.collectRefs() } - } - - companion object { - fun fromDb(entity: AreaEntity): AreaModel = AreaModel( - entity.content.map { DocumentContentModel.fromDbContent(it) }, entity.position, entity.interactiveFlowName - ) - } -} \ No newline at end of file diff --git a/migration-library/src/main/kotlin/com/quadient/migration/data/documentcontent/DocumentContentModel.kt b/migration-library/src/main/kotlin/com/quadient/migration/data/documentcontent/DocumentContentModel.kt deleted file mode 100644 index 540da3d7..00000000 --- a/migration-library/src/main/kotlin/com/quadient/migration/data/documentcontent/DocumentContentModel.kt +++ /dev/null @@ -1,28 +0,0 @@ -package com.quadient.migration.data - -import com.quadient.migration.persistence.migrationmodel.DocumentContentEntity -import com.quadient.migration.persistence.migrationmodel.DocumentObjectEntityRef -import com.quadient.migration.persistence.migrationmodel.FileEntityRef -import com.quadient.migration.persistence.migrationmodel.FirstMatchEntity -import com.quadient.migration.persistence.migrationmodel.AreaEntity -import com.quadient.migration.persistence.migrationmodel.ImageEntityRef -import com.quadient.migration.persistence.migrationmodel.ParagraphEntity -import com.quadient.migration.persistence.migrationmodel.SelectByLanguageEntity -import com.quadient.migration.persistence.migrationmodel.TableEntity -import com.quadient.migration.service.RefValidatable - -sealed interface DocumentContentModel : RefValidatable { - companion object { - fun fromDbContent(entity: DocumentContentEntity) = when (entity) { - is TableEntity -> TableModel.fromDb(entity) - is ParagraphEntity -> ParagraphModel.fromDb(entity) - is DocumentObjectEntityRef -> DocumentObjectModelRef.fromDb(entity) - is ImageEntityRef -> ImageModelRef.fromDb(entity) - is FileEntityRef -> FileModelRef.fromDb(entity) - is AreaEntity -> AreaModel.fromDb(entity) - is FirstMatchEntity -> FirstMatchModel.fromDb(entity) - is SelectByLanguageEntity -> SelectByLanguageModel.fromDb(entity) - } - } -} - diff --git a/migration-library/src/main/kotlin/com/quadient/migration/data/documentcontent/FirstMatchModel.kt b/migration-library/src/main/kotlin/com/quadient/migration/data/documentcontent/FirstMatchModel.kt deleted file mode 100644 index a2fbfa97..00000000 --- a/migration-library/src/main/kotlin/com/quadient/migration/data/documentcontent/FirstMatchModel.kt +++ /dev/null @@ -1,30 +0,0 @@ -package com.quadient.migration.data - -import com.quadient.migration.persistence.migrationmodel.FirstMatchEntity -import com.quadient.migration.persistence.migrationmodel.FirstMatchEntity.CaseEntity -import com.quadient.migration.service.RefValidatable - -data class FirstMatchModel(val cases: List, val default: List) : DocumentContentModel, - TextContentModel, RefValidatable { - companion object { - fun fromDb(entity: FirstMatchEntity): FirstMatchModel = FirstMatchModel( - cases = entity.cases.map { CaseModel.fromDb(it) }, - default = entity.default.map { DocumentContentModel.fromDbContent(it) }) - } - - override fun collectRefs(): List { - return cases.flatMap { listOf(it.displayRuleRef) + it.content.flatMap { it.collectRefs() } + default.flatMap { it.collectRefs() } } - } - - data class CaseModel( - val displayRuleRef: DisplayRuleModelRef, val content: List, val name: String? - ) { - companion object { - fun fromDb(entity: CaseEntity) = CaseModel( - displayRuleRef = DisplayRuleModelRef.fromDb(entity.displayRuleRef), - content = entity.content.map { DocumentContentModel.fromDbContent(it) }, - name = entity.name - ) - } - } -} diff --git a/migration-library/src/main/kotlin/com/quadient/migration/data/documentcontent/ParagraphModel.kt b/migration-library/src/main/kotlin/com/quadient/migration/data/documentcontent/ParagraphModel.kt deleted file mode 100644 index d6232ca0..00000000 --- a/migration-library/src/main/kotlin/com/quadient/migration/data/documentcontent/ParagraphModel.kt +++ /dev/null @@ -1,72 +0,0 @@ -package com.quadient.migration.data - -import com.quadient.migration.persistence.migrationmodel.ParagraphEntity -import com.quadient.migration.persistence.migrationmodel.ParagraphEntity.TextEntity -import com.quadient.migration.service.RefValidatable - -data class ParagraphModel( - val content: List, - val styleRef: ParagraphStyleModelRef?, - val displayRuleRef: DisplayRuleModelRef? -) : DocumentContentModel, RefValidatable { - companion object { - fun fromDb(entity: ParagraphEntity): ParagraphModel = ParagraphModel( - styleRef = entity.styleRef?.let { ParagraphStyleModelRef.fromDb(it) }, - displayRuleRef = entity.displayRuleRef?.let { DisplayRuleModelRef.fromDb(it) }, - content = entity.content.map { TextModel.fromDb(it) }) - } - - override fun collectRefs(): List { - val result = content.flatMap { - it.collectRefs() - }.toMutableList() - - if (styleRef != null) { - result.add(styleRef) - } - - if (displayRuleRef != null) { - result.add(displayRuleRef) - } - - return result - } - - data class TextModel( - val content: List, - val styleRef: TextStyleModelRef?, - val displayRuleRef: DisplayRuleModelRef? - ) : RefValidatable { - override fun collectRefs(): List { - val result: MutableList = content.mapNotNull { - when (it) { - is VariableModelRef -> listOf(it) - is StringModel -> null - is HyperlinkModel -> null - is TableModel -> it.collectRefs() - is DocumentObjectModelRef -> listOf(it) - is ImageModelRef -> listOf(it) - is FileModelRef -> listOf(it) - is FirstMatchModel -> it.collectRefs() - } - }.flatten().toMutableList() - - if (styleRef != null) { - result.add(styleRef) - } - - if (displayRuleRef != null) { - result.add(displayRuleRef) - } - - return result - } - - companion object { - fun fromDb(entity: TextEntity) = TextModel( - styleRef = entity.styleRef?.let { TextStyleModelRef.fromDb(it) }, - displayRuleRef = entity.displayRuleRef?.let { DisplayRuleModelRef.fromDb(it) }, - content = entity.content.map { TextContentModel.fromDb(it) }) - } - } -} diff --git a/migration-library/src/main/kotlin/com/quadient/migration/data/documentcontent/SelectByLanguageModel.kt b/migration-library/src/main/kotlin/com/quadient/migration/data/documentcontent/SelectByLanguageModel.kt deleted file mode 100644 index 8ed33576..00000000 --- a/migration-library/src/main/kotlin/com/quadient/migration/data/documentcontent/SelectByLanguageModel.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.quadient.migration.data - -import com.quadient.migration.persistence.migrationmodel.SelectByLanguageEntity -import com.quadient.migration.service.RefValidatable - -data class SelectByLanguageModel(val cases: List) : DocumentContentModel, RefValidatable { - companion object { - fun fromDb(entity: SelectByLanguageEntity): SelectByLanguageModel = SelectByLanguageModel( - cases = entity.cases.map { CaseModel.fromDb(it) }, - ) - } - - override fun collectRefs(): List { - return cases.flatMap { it.content.flatMap { it.collectRefs() } } - } - - data class CaseModel(val language: String, val content: List) { - companion object { - fun fromDb(entity: SelectByLanguageEntity.CaseEntity) = CaseModel( - content = entity.content.map { DocumentContentModel.fromDbContent(it) }, language = entity.language - ) - } - } -} diff --git a/migration-library/src/main/kotlin/com/quadient/migration/data/documentcontent/TableModel.kt b/migration-library/src/main/kotlin/com/quadient/migration/data/documentcontent/TableModel.kt deleted file mode 100644 index b12ba615..00000000 --- a/migration-library/src/main/kotlin/com/quadient/migration/data/documentcontent/TableModel.kt +++ /dev/null @@ -1,52 +0,0 @@ -package com.quadient.migration.data - -import com.quadient.migration.persistence.migrationmodel.TableEntity -import com.quadient.migration.shared.TablePdfTaggingRule -import com.quadient.migration.service.RefValidatable -import com.quadient.migration.shared.Size - -data class TableModel( - val rows: List, - val columnWidths: List, - val pdfTaggingRule: TablePdfTaggingRule = TablePdfTaggingRule.Default, - val pdfAlternateText: String? = null, -) : DocumentContentModel, TextContentModel, RefValidatable { - - companion object { - fun fromDb(table: TableEntity): TableModel = TableModel( - rows = table.rows.map { row -> - RowModel(row.cells.map { cell -> - CellModel( - cell.content.map { DocumentContentModel.fromDbContent(it) }, - cell.mergeLeft, - cell.mergeUp, - ) - }, displayRuleRef = row.displayRuleRef?.let { DisplayRuleModelRef.fromDb(it) }) - }, - columnWidths = table.columnWidths.map { ColumnWidthModel(it.minWidth, it.percentWidth) }, - pdfTaggingRule = table.pdfTaggingRule, - pdfAlternateText = table.pdfAlternateText - ) - } - - override fun collectRefs(): List { - return rows.flatMap { row -> - row.cells.flatMap { cell -> - cell - .content - .map { it.collectRefs() } - .flatten() + (row.displayRuleRef?.let { listOf(it) } ?: emptyList()) - } - } - } - - data class RowModel(val cells: List, val displayRuleRef: DisplayRuleModelRef?) - - data class CellModel( - val content: List, - var mergeLeft: Boolean = false, - var mergeUp: Boolean = false, - ) - - data class ColumnWidthModel(val minWidth: Size, val percentWidth: Double) -} diff --git a/migration-library/src/main/kotlin/com/quadient/migration/persistence/migrationmodel/MappingEntity.kt b/migration-library/src/main/kotlin/com/quadient/migration/persistence/migrationmodel/MappingEntity.kt index 1daf4ad1..bc122cde 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/persistence/migrationmodel/MappingEntity.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/persistence/migrationmodel/MappingEntity.kt @@ -1,7 +1,6 @@ package com.quadient.migration.persistence.migrationmodel import com.quadient.migration.api.dto.migrationmodel.* -import com.quadient.migration.data.TabsModel import com.quadient.migration.persistence.table.MappingTable import com.quadient.migration.shared.* import com.quadient.migration.shared.LineSpacing.Additional @@ -171,7 +170,12 @@ sealed class MappingItemEntity { firstLineIndent = definition.firstLineIndent, lineSpacing = definition.lineSpacing ?: Additional(null), keepWithNextParagraph = definition.keepWithNextParagraph, - tabs = definition.tabs?.let(TabsModel::fromDb)?.let(Tabs::fromModel), + tabs = definition.tabs?.let { tabsEntity -> + Tabs( + tabs = tabsEntity.tabs.map { Tab(it.position, it.type) }, + useOutsideTabs = tabsEntity.useOutsideTabs + ) + }, pdfTaggingRule = definition.pdfTaggingRule ) ) @@ -189,7 +193,12 @@ sealed class MappingItemEntity { firstLineIndent = definition.firstLineIndent, lineSpacing = definition.lineSpacing ?: Additional(null), keepWithNextParagraph = definition.keepWithNextParagraph ?: false, - tabs = definition.tabs?.let(TabsModel::fromDb)?.let(Tabs::fromModel), + tabs = definition.tabs?.let { tabsEntity -> + Tabs( + tabs = tabsEntity.tabs.map { Tab(it.position, it.type) }, + useOutsideTabs = tabsEntity.useOutsideTabs + ) + }, pdfTaggingRule = definition.pdfTaggingRule ) ) @@ -352,7 +361,12 @@ sealed class MappingItemEntity { firstLineIndent = definition.firstLineIndent, lineSpacing = definition.lineSpacing, keepWithNextParagraph = definition.keepWithNextParagraph, - tabs = definition.tabs?.let(TabsModel::fromDb)?.let(Tabs::fromModel), + tabs = definition.tabs?.let { tabsEntity -> + Tabs( + tabs = tabsEntity.tabs.map { Tab(it.position, it.type) }, + useOutsideTabs = tabsEntity.useOutsideTabs + ) + }, pdfTaggingRule = definition.pdfTaggingRule ) } diff --git a/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/DisplayRuleInternalRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/DisplayRuleInternalRepository.kt index 353de229..d3db4792 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/DisplayRuleInternalRepository.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/DisplayRuleInternalRepository.kt @@ -1,28 +1,13 @@ package com.quadient.migration.persistence.repository -import com.quadient.migration.data.DisplayRuleModel -import com.quadient.migration.persistence.table.DisplayRuleTable.created -import com.quadient.migration.persistence.table.DisplayRuleTable.customFields -import com.quadient.migration.persistence.table.DisplayRuleTable.definition -import com.quadient.migration.persistence.table.DisplayRuleTable.id -import com.quadient.migration.persistence.table.DisplayRuleTable.lastUpdated -import com.quadient.migration.persistence.table.DisplayRuleTable.name -import com.quadient.migration.persistence.table.DisplayRuleTable.originLocations +import com.quadient.migration.api.dto.migrationmodel.DisplayRule import com.quadient.migration.persistence.table.MigrationObjectTable import org.jetbrains.exposed.v1.core.ResultRow class DisplayRuleInternalRepository( table: MigrationObjectTable, projectName: String -) : InternalRepository(table, projectName) { - override fun toModel(row: ResultRow): DisplayRuleModel { - return DisplayRuleModel( - id = row[id].value, - name = row[name], - originLocations = row[originLocations], - customFields = row[customFields], - lastUpdated = row[lastUpdated], - created = row[created], - definition = row[definition] - ) +) : InternalRepository(table, projectName) { + override fun toModel(row: ResultRow): DisplayRule { + return DisplayRule.fromDb(row) } } diff --git a/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/DocumentObjectInternalRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/DocumentObjectInternalRepository.kt index ae092c0f..79603efc 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/DocumentObjectInternalRepository.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/DocumentObjectInternalRepository.kt @@ -1,43 +1,12 @@ package com.quadient.migration.persistence.repository -import com.quadient.migration.data.DisplayRuleModelRef -import com.quadient.migration.data.DocumentContentModel -import com.quadient.migration.data.DocumentObjectModel -import com.quadient.migration.data.VariableStructureModelRef +import com.quadient.migration.api.dto.migrationmodel.DocumentObject import com.quadient.migration.persistence.table.DocumentObjectTable -import com.quadient.migration.persistence.table.DocumentObjectTable.baseTemplate -import com.quadient.migration.persistence.table.DocumentObjectTable.content -import com.quadient.migration.persistence.table.DocumentObjectTable.displayRuleRef -import com.quadient.migration.persistence.table.DocumentObjectTable.internal -import com.quadient.migration.persistence.table.DocumentObjectTable.metadata -import com.quadient.migration.persistence.table.DocumentObjectTable.options -import com.quadient.migration.persistence.table.DocumentObjectTable.targetFolder -import com.quadient.migration.persistence.table.DocumentObjectTable.type -import com.quadient.migration.shared.DocumentObjectType -import com.quadient.migration.shared.IcmPath import org.jetbrains.exposed.v1.core.ResultRow class DocumentObjectInternalRepository(table: DocumentObjectTable, projectName: String) : - InternalRepository(table, projectName) { - override fun toModel(row: ResultRow): DocumentObjectModel { - return DocumentObjectModel( - id = row[table.id].value, - name = row[table.name], - type = DocumentObjectType.valueOf(row[type]), - content = row[content]?.map(DocumentContentModel::fromDbContent) ?: emptyList(), - internal = row[internal], - targetFolder = row[targetFolder]?.let(IcmPath::from), - originLocations = row[table.originLocations], - customFields = row[table.customFields], - created = row[table.created], - lastUpdated = row[table.lastUpdated], - baseTemplate = row[baseTemplate], - displayRuleRef = row[displayRuleRef]?.let { DisplayRuleModelRef(it) }, - variableStructureRef = row[DocumentObjectTable.variableStructureRef]?.let { VariableStructureModelRef(it) }, - options = row[options], - metadata = row[metadata], - skip = row[DocumentObjectTable.skip], - subject = row[DocumentObjectTable.subject] - ) + InternalRepository(table, projectName) { + override fun toModel(row: ResultRow): DocumentObject { + return DocumentObjectTable.fromResultRow(row) } } \ No newline at end of file diff --git a/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/FileInternalRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/FileInternalRepository.kt index 01e8bf4e..42213396 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/FileInternalRepository.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/FileInternalRepository.kt @@ -1,26 +1,13 @@ package com.quadient.migration.persistence.repository -import com.quadient.migration.data.FileModel -import com.quadient.migration.persistence.table.FileTable +import com.quadient.migration.api.dto.migrationmodel.File import com.quadient.migration.persistence.table.MigrationObjectTable -import com.quadient.migration.shared.FileType -import com.quadient.migration.shared.IcmPath import org.jetbrains.exposed.v1.core.ResultRow class FileInternalRepository( table: MigrationObjectTable, projectName: String -) : InternalRepository(table, projectName) { - override fun toModel(row: ResultRow): FileModel { - return FileModel( - id = row[table.id].value, - name = row[table.name], - originLocations = row[table.originLocations], - customFields = row[table.customFields], - created = row[table.created], - sourcePath = row[FileTable.sourcePath], - targetFolder = row[FileTable.targetFolder]?.let(IcmPath::from), - fileType = FileType.valueOf(row[FileTable.fileType]), - skip = row[FileTable.skip], - ) +) : InternalRepository(table, projectName) { + override fun toModel(row: ResultRow): File { + return File.fromDb(row) } } diff --git a/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/ImageInternalRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/ImageInternalRepository.kt index 9e733cf6..595629a7 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/ImageInternalRepository.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/ImageInternalRepository.kt @@ -1,29 +1,13 @@ package com.quadient.migration.persistence.repository -import com.quadient.migration.data.ImageModel -import com.quadient.migration.persistence.table.ImageTable +import com.quadient.migration.api.dto.migrationmodel.Image import com.quadient.migration.persistence.table.MigrationObjectTable -import com.quadient.migration.shared.IcmPath -import com.quadient.migration.shared.ImageType import org.jetbrains.exposed.v1.core.ResultRow class ImageInternalRepository( table: MigrationObjectTable, projectName: String -) : InternalRepository(table, projectName) { - override fun toModel(row: ResultRow): ImageModel { - return ImageModel( - id = row[table.id].value, - name = row[table.name], - originLocations = row[table.originLocations], - customFields = row[table.customFields], - created = row[table.created], - sourcePath = row[ImageTable.sourcePath], - imageType = ImageType.valueOf(row[ImageTable.imageType]), - options = row[ImageTable.options], - targetFolder = row[ImageTable.targetFolder]?.let(IcmPath::from), - metadata = row[ImageTable.metadata], - skip = row[ImageTable.skip], - alternateText = row[ImageTable.alternateText], - ) +) : InternalRepository(table, projectName) { + override fun toModel(row: ResultRow): Image { + return Image.fromDb(row) } } \ No newline at end of file diff --git a/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/InternalRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/InternalRepository.kt index 7f9fbb4a..b7c31e81 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/InternalRepository.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/InternalRepository.kt @@ -1,7 +1,6 @@ package com.quadient.migration.persistence.repository import com.quadient.migration.api.dto.migrationmodel.MigrationObject -import com.quadient.migration.data.MigrationObjectModel import com.quadient.migration.persistence.table.MigrationObjectTable import com.quadient.migration.tools.getOrPutOrNull import org.jetbrains.exposed.v1.core.Op @@ -17,7 +16,7 @@ import org.jetbrains.exposed.v1.jdbc.selectAll import org.jetbrains.exposed.v1.jdbc.transactions.transaction import org.slf4j.LoggerFactory -abstract class InternalRepository( +abstract class InternalRepository( val table: MigrationObjectTable, val projectName: String ) { private val logger = LoggerFactory.getLogger(this::class.java)!! diff --git a/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/ParagraphStyleInternalRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/ParagraphStyleInternalRepository.kt index ef522e4e..1757407e 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/ParagraphStyleInternalRepository.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/ParagraphStyleInternalRepository.kt @@ -1,33 +1,24 @@ package com.quadient.migration.persistence.repository -import com.quadient.migration.data.ParagraphStyleDefOrRefModel -import com.quadient.migration.data.ParagraphStyleDefinitionModel -import com.quadient.migration.data.ParagraphStyleModel -import com.quadient.migration.data.ParagraphStyleModelRef +import com.quadient.migration.api.dto.migrationmodel.ParagraphStyle +import com.quadient.migration.api.dto.migrationmodel.ParagraphStyleDefinition +import com.quadient.migration.api.dto.migrationmodel.ParagraphStyleRef import com.quadient.migration.persistence.table.ParagraphStyleTable -import com.quadient.migration.persistence.table.ParagraphStyleTable.definition import org.jetbrains.exposed.v1.core.ResultRow class ParagraphStyleInternalRepository(table: ParagraphStyleTable, projectName: String) : - InternalRepository(table, projectName) { + InternalRepository(table, projectName) { - override fun toModel(row: ResultRow): ParagraphStyleModel { - return ParagraphStyleModel( - id = row[table.id].value, - name = row[table.name], - originLocations = row[table.originLocations], - customFields = row[table.customFields], - lastUpdated = row[table.lastUpdated], - created = row[table.created], - definition = ParagraphStyleDefOrRefModel.fromDb(row[definition]), - ) + override fun toModel(row: ResultRow): ParagraphStyle { + return ParagraphStyle.fromDb(row) } - internal fun firstWithDefinitionModel(id: String): ParagraphStyleModel? { + internal fun firstWithDefinition(id: String): ParagraphStyle? { val model = findModel(id) - return when (model?.definition) { - is ParagraphStyleDefinitionModel -> model - is ParagraphStyleModelRef -> firstWithDefinitionModel(model.definition.id) + val def = model?.definition + return when (def) { + is ParagraphStyleDefinition -> model + is ParagraphStyleRef -> firstWithDefinition(def.id) null -> null } } diff --git a/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/TextStyleInternalRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/TextStyleInternalRepository.kt index 02aeb198..3065ad01 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/TextStyleInternalRepository.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/TextStyleInternalRepository.kt @@ -1,33 +1,24 @@ package com.quadient.migration.persistence.repository -import com.quadient.migration.data.TextStyleDefOrRefModel -import com.quadient.migration.data.TextStyleDefinitionModel -import com.quadient.migration.data.TextStyleModel -import com.quadient.migration.data.TextStyleModelRef +import com.quadient.migration.api.dto.migrationmodel.TextStyle +import com.quadient.migration.api.dto.migrationmodel.TextStyleDefinition +import com.quadient.migration.api.dto.migrationmodel.TextStyleRef import com.quadient.migration.persistence.table.TextStyleTable -import com.quadient.migration.persistence.table.TextStyleTable.definition import org.jetbrains.exposed.v1.core.ResultRow class TextStyleInternalRepository(table: TextStyleTable, projectName: String) : - InternalRepository(table, projectName) { + InternalRepository(table, projectName) { - override fun toModel(row: ResultRow): TextStyleModel { - return TextStyleModel( - id = row[table.id].value, - name = row[table.name], - originLocations = row[table.originLocations], - customFields = row[table.customFields], - lastUpdated = row[table.lastUpdated], - created = row[table.created], - definition = TextStyleDefOrRefModel.fromDb(row[definition]), - ) + override fun toModel(row: ResultRow): TextStyle { + return TextStyle.fromDb(row) } - internal fun firstWithDefinitionModel(id: String): TextStyleModel? { + internal fun firstWithDefinition(id: String): TextStyle? { val model = findModel(id) - return when (model?.definition) { - is TextStyleDefinitionModel -> model - is TextStyleModelRef -> firstWithDefinitionModel(model.definition.id) + val def = model?.definition + return when (def) { + is TextStyleDefinition -> model + is TextStyleRef -> firstWithDefinition(def.id) null -> null } } diff --git a/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/VariableInternalRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/VariableInternalRepository.kt index ba3707bb..3aa5e899 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/VariableInternalRepository.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/VariableInternalRepository.kt @@ -1,31 +1,13 @@ package com.quadient.migration.persistence.repository -import com.quadient.migration.data.VariableModel +import com.quadient.migration.api.dto.migrationmodel.Variable import com.quadient.migration.persistence.table.MigrationObjectTable -import com.quadient.migration.persistence.table.VariableTable.created -import com.quadient.migration.persistence.table.VariableTable.customFields -import com.quadient.migration.persistence.table.VariableTable.id -import com.quadient.migration.persistence.table.VariableTable.dataType -import com.quadient.migration.persistence.table.VariableTable.defaultValue -import com.quadient.migration.persistence.table.VariableTable.lastUpdated -import com.quadient.migration.persistence.table.VariableTable.name -import com.quadient.migration.persistence.table.VariableTable.originLocations -import com.quadient.migration.shared.DataType import org.jetbrains.exposed.v1.core.ResultRow class VariableInternalRepository(table: MigrationObjectTable, projectName: String) : - InternalRepository(table, projectName) { + InternalRepository(table, projectName) { - override fun toModel(row: ResultRow): VariableModel { - return VariableModel( - id = row[id].value, - name = row[name], - originLocations = row[originLocations], - customFields = row[customFields], - lastUpdated = row[lastUpdated], - created = row[created], - dataType = DataType.valueOf(row[dataType]), - defaultValue = row[defaultValue] - ) + override fun toModel(row: ResultRow): Variable { + return Variable.fromDb(row) } } \ No newline at end of file diff --git a/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/VariableStructureInternalRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/VariableStructureInternalRepository.kt index f07fe5d6..0a63663d 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/VariableStructureInternalRepository.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/VariableStructureInternalRepository.kt @@ -1,22 +1,12 @@ package com.quadient.migration.persistence.repository -import com.quadient.migration.data.VariableModelRef -import com.quadient.migration.data.VariableStructureModel +import com.quadient.migration.api.dto.migrationmodel.VariableStructure import com.quadient.migration.persistence.table.VariableStructureTable import org.jetbrains.exposed.v1.core.ResultRow class VariableStructureInternalRepository(table: VariableStructureTable, projectName: String) : - InternalRepository(table, projectName) { - override fun toModel(row: ResultRow): VariableStructureModel { - return VariableStructureModel( - id = row[table.id].value, - name = row[table.name], - customFields = row[table.customFields], - lastUpdated = row[table.lastUpdated], - created = row[table.created], - structure = row[VariableStructureTable.structure].map { (key, value) -> VariableModelRef(key) to value }.toMap(), - originLocations = row[table.originLocations], - languageVariable = row[VariableStructureTable.languageVariable]?.let { VariableModelRef(it) } - ) + InternalRepository(table, projectName) { + override fun toModel(row: ResultRow): VariableStructure { + return VariableStructure.fromDb(row) } } \ No newline at end of file diff --git a/migration-library/src/main/kotlin/com/quadient/migration/persistence/table/DocumentObjectTable.kt b/migration-library/src/main/kotlin/com/quadient/migration/persistence/table/DocumentObjectTable.kt index 71d7e1d5..940ca007 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/persistence/table/DocumentObjectTable.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/persistence/table/DocumentObjectTable.kt @@ -1,13 +1,13 @@ package com.quadient.migration.persistence.table -import com.quadient.migration.data.DisplayRuleModelRef -import com.quadient.migration.data.DocumentContentModel -import com.quadient.migration.data.DocumentObjectModel -import com.quadient.migration.data.VariableStructureModelRef +import com.quadient.migration.api.dto.migrationmodel.CustomFieldMap +import com.quadient.migration.api.dto.migrationmodel.DisplayRuleRef +import com.quadient.migration.api.dto.migrationmodel.DocumentContent +import com.quadient.migration.api.dto.migrationmodel.DocumentObject +import com.quadient.migration.api.dto.migrationmodel.VariableStructureRef import com.quadient.migration.persistence.migrationmodel.DocumentContentEntity import com.quadient.migration.shared.DocumentObjectOptions import com.quadient.migration.shared.DocumentObjectType -import com.quadient.migration.shared.IcmPath import com.quadient.migration.shared.MetadataPrimitive import com.quadient.migration.shared.SkipOptions import kotlinx.serialization.json.Json @@ -27,20 +27,20 @@ object DocumentObjectTable : MigrationObjectTable("document_object") { val skip = jsonb("skip", Json) val subject = varchar("subject", 255).nullable() - fun fromResultRow(result: ResultRow): DocumentObjectModel { - return DocumentObjectModel( + fun fromResultRow(result: ResultRow): DocumentObject { + return DocumentObject( id = result[id].value, name = result[name], type = DocumentObjectType.valueOf(result[type]), - content = result[content]?.map(DocumentContentModel::fromDbContent) ?: emptyList(), + content = result[content]?.map(DocumentContent::fromDbContent) ?: emptyList(), internal = result[internal], - targetFolder = result[targetFolder]?.let(IcmPath::from), + targetFolder = result[targetFolder], originLocations = result[originLocations], - customFields = result[customFields], + customFields = CustomFieldMap(result[customFields].toMutableMap()), created = result[created], lastUpdated = result[lastUpdated], - displayRuleRef = result[displayRuleRef]?.let { DisplayRuleModelRef(it) }, - variableStructureRef = result[variableStructureRef]?.let { VariableStructureModelRef(it) }, + displayRuleRef = result[displayRuleRef]?.let { DisplayRuleRef(it) }, + variableStructureRef = result[variableStructureRef]?.let { VariableStructureRef(it) }, baseTemplate = result[baseTemplate], options = result[options], metadata = result[metadata], diff --git a/migration-library/src/main/kotlin/com/quadient/migration/service/DeployPhaseUtils.kt b/migration-library/src/main/kotlin/com/quadient/migration/service/DeployPhaseUtils.kt index 57b3f708..173b5e77 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/service/DeployPhaseUtils.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/service/DeployPhaseUtils.kt @@ -1,7 +1,7 @@ package com.quadient.migration.service import com.quadient.migration.api.ProjectConfig -import com.quadient.migration.data.ImageModel +import com.quadient.migration.api.dto.migrationmodel.Image import com.quadient.migration.shared.IcmPath import com.quadient.migration.shared.ImageType import com.quadient.migration.shared.isNullOrBlank @@ -27,7 +27,7 @@ fun getBaseTemplateFullPath(config: ProjectConfig, documentObjectBaseTemplatePat .join(path) } -fun imageExtension(image: ImageModel) = imageExtension(image.imageType, image.name, image.sourcePath) +fun imageExtension(image: Image) = imageExtension(image.imageType!!, image.name, image.sourcePath) fun imageExtension(imageType: ImageType, name: String?, sourcePath: String?): String { return imageType.extension() ?: sourcePath?.split('.')?.last() ?: name?.split('.')?.last() ?: "" diff --git a/migration-library/src/main/kotlin/com/quadient/migration/service/ReferenceValidator.kt b/migration-library/src/main/kotlin/com/quadient/migration/service/ReferenceValidator.kt index fdd3fe9b..c6d446c8 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/service/ReferenceValidator.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/service/ReferenceValidator.kt @@ -1,14 +1,15 @@ package com.quadient.migration.service -import com.quadient.migration.data.DisplayRuleModelRef -import com.quadient.migration.data.DocumentObjectModelRef -import com.quadient.migration.data.ImageModelRef -import com.quadient.migration.data.FileModelRef -import com.quadient.migration.data.ParagraphStyleModelRef -import com.quadient.migration.data.RefModel -import com.quadient.migration.data.TextStyleModelRef -import com.quadient.migration.data.VariableModelRef -import com.quadient.migration.data.VariableStructureModelRef +import com.quadient.migration.api.dto.migrationmodel.DisplayRuleRef +import com.quadient.migration.api.dto.migrationmodel.DocumentObjectRef +import com.quadient.migration.api.dto.migrationmodel.ImageRef +import com.quadient.migration.api.dto.migrationmodel.FileRef +import com.quadient.migration.api.dto.migrationmodel.ParagraphStyleRef +import com.quadient.migration.api.dto.migrationmodel.Ref +import com.quadient.migration.api.dto.migrationmodel.TextStyleRef +import com.quadient.migration.api.dto.migrationmodel.VariableRef +import com.quadient.migration.api.dto.migrationmodel.VariableStructureRef +import com.quadient.migration.api.dto.migrationmodel.RefValidatable import com.quadient.migration.persistence.repository.DisplayRuleInternalRepository import com.quadient.migration.persistence.repository.DocumentObjectInternalRepository import com.quadient.migration.persistence.repository.ImageInternalRepository @@ -18,10 +19,6 @@ import com.quadient.migration.persistence.repository.TextStyleInternalRepository import com.quadient.migration.persistence.repository.VariableInternalRepository import com.quadient.migration.persistence.repository.VariableStructureInternalRepository -interface RefValidatable { - fun collectRefs(): List -} - class ReferenceValidator( private val documentObjectRepository: DocumentObjectInternalRepository, private val variableRepository: VariableInternalRepository, @@ -47,7 +44,7 @@ class ReferenceValidator( val displayRules = displayRuleRepository.listAllModel() val images = imageRepository.listAllModel() val files = fileRepository.listAllModel() - val alreadyValidatedRefs = mutableSetOf() + val alreadyValidatedRefs = mutableSetOf() val missingRefs = (documentObjects + variables + paragraphStyles + textStyles + dataStructures + displayRules + images + files).mapNotNull { @@ -61,11 +58,11 @@ class ReferenceValidator( * Validates the references of a single object. * @return ValidationResult containing validated references and missing references */ - fun validate(input: RefValidatable, alreadyValidRefs: MutableSet): ValidationResult { - val queue: MutableList = input.collectRefs().toMutableList() + fun validate(input: RefValidatable, alreadyValidRefs: MutableSet): ValidationResult { + val queue: MutableList = input.collectRefs().toMutableList() - val missingRefs = mutableListOf() - val validatedRefs = mutableListOf() + val missingRefs = mutableListOf() + val validatedRefs = mutableListOf() while (queue.isNotEmpty()) { val current = queue.removeFirst() @@ -74,7 +71,7 @@ class ReferenceValidator( } when (current) { - is DocumentObjectModelRef -> { + is DocumentObjectRef -> { val documentObject = documentObjectRepository.findModel(current.id) if (documentObject == null) { @@ -86,7 +83,7 @@ class ReferenceValidator( } } - is VariableModelRef -> { + is VariableRef -> { val variable = variableRepository.findModel(current.id) if (variable != null) { @@ -97,7 +94,7 @@ class ReferenceValidator( } } - is ParagraphStyleModelRef -> { + is ParagraphStyleRef -> { val style = paragraphStyleRepository.findModel(current.id) if (style != null) { @@ -109,7 +106,7 @@ class ReferenceValidator( } } - is TextStyleModelRef -> { + is TextStyleRef -> { val style = textStyleRepository.findModel(current.id) if (style != null) { @@ -121,7 +118,7 @@ class ReferenceValidator( } } - is DisplayRuleModelRef -> { + is DisplayRuleRef -> { val rule = displayRuleRepository.findModel(current.id) if (rule != null) { @@ -133,7 +130,7 @@ class ReferenceValidator( } } - is ImageModelRef -> { + is ImageRef -> { val image = imageRepository.findModel(current.id) if (image != null) { @@ -145,7 +142,7 @@ class ReferenceValidator( } } - is FileModelRef -> { + is FileRef -> { val file = fileRepository.findModel(current.id) if (file != null) { @@ -157,7 +154,7 @@ class ReferenceValidator( } } - is VariableStructureModelRef -> { + is VariableStructureRef -> { val variableStructure = variableStructureRepository.findModel(current.id) if (variableStructure != null) { @@ -174,7 +171,7 @@ class ReferenceValidator( return ValidationResult(validatedRefs, missingRefs) } - data class ValidationResult(val validatedRefs: List, val missingRefs: List) - data class MissingRefs(val missingRefs: List) + data class ValidationResult(val validatedRefs: List, val missingRefs: List) + data class MissingRefs(val missingRefs: List) } diff --git a/migration-library/src/main/kotlin/com/quadient/migration/service/StylesValidator.kt b/migration-library/src/main/kotlin/com/quadient/migration/service/StylesValidator.kt index 74f5693a..df11eb54 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/service/StylesValidator.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/service/StylesValidator.kt @@ -2,19 +2,19 @@ package com.quadient.migration.service import com.fasterxml.jackson.databind.node.ArrayNode import com.fasterxml.jackson.dataformat.xml.XmlMapper -import com.quadient.migration.data.DisplayRuleModelRef -import com.quadient.migration.data.DocumentObjectModel -import com.quadient.migration.data.DocumentObjectModelRef -import com.quadient.migration.data.FileModelRef -import com.quadient.migration.data.ImageModelRef -import com.quadient.migration.data.ParagraphStyleDefinitionModel -import com.quadient.migration.data.ParagraphStyleModel -import com.quadient.migration.data.ParagraphStyleModelRef -import com.quadient.migration.data.TextStyleDefinitionModel -import com.quadient.migration.data.TextStyleModel -import com.quadient.migration.data.TextStyleModelRef -import com.quadient.migration.data.VariableModelRef -import com.quadient.migration.data.VariableStructureModelRef +import com.quadient.migration.api.dto.migrationmodel.DisplayRuleRef +import com.quadient.migration.api.dto.migrationmodel.DocumentObject +import com.quadient.migration.api.dto.migrationmodel.DocumentObjectRef +import com.quadient.migration.api.dto.migrationmodel.FileRef +import com.quadient.migration.api.dto.migrationmodel.ImageRef +import com.quadient.migration.api.dto.migrationmodel.ParagraphStyleDefinition +import com.quadient.migration.api.dto.migrationmodel.ParagraphStyle +import com.quadient.migration.api.dto.migrationmodel.ParagraphStyleRef +import com.quadient.migration.api.dto.migrationmodel.TextStyleDefinition +import com.quadient.migration.api.dto.migrationmodel.TextStyle +import com.quadient.migration.api.dto.migrationmodel.TextStyleRef +import com.quadient.migration.api.dto.migrationmodel.VariableRef +import com.quadient.migration.api.dto.migrationmodel.VariableStructureRef import com.quadient.migration.persistence.repository.DocumentObjectInternalRepository import com.quadient.migration.persistence.repository.ParagraphStyleInternalRepository import com.quadient.migration.persistence.repository.TextStyleInternalRepository @@ -40,10 +40,10 @@ class StylesValidator( return validateInternal(documentObjects) } - private fun validateInternal(objects: List): ValidationResult { + private fun validateInternal(objects: List): ValidationResult { val refs = resolveDocumentObjects(objects).flatMap { it.collectRefs() }.toSet() - val textStyles = mutableSetOf() - val paragraphStyles = mutableSetOf() + val textStyles = mutableSetOf() + val paragraphStyles = mutableSetOf() val neededTextStyleIds = mutableSetOf() val neededParagraphStyleIds = mutableSetOf() @@ -53,7 +53,7 @@ class StylesValidator( for (style in refs) { when (style) { - is ParagraphStyleModelRef -> { + is ParagraphStyleRef -> { val model = paragraphStyleRepository.findModel(style.id) if (model == null) { missingParagraphStyleIds.add(style.id) @@ -62,7 +62,7 @@ class StylesValidator( } } - is TextStyleModelRef -> { + is TextStyleRef -> { val model = textStyleRepository.findModel(style.id) if (model == null) { missingTextStyleIds.add(style.id) @@ -71,12 +71,12 @@ class StylesValidator( } } - is DisplayRuleModelRef -> {} - is DocumentObjectModelRef -> {} - is ImageModelRef -> {} - is FileModelRef -> {} - is VariableModelRef -> {} - is VariableStructureModelRef -> {} + is DisplayRuleRef -> {} + is DocumentObjectRef -> {} + is ImageRef -> {} + is FileRef -> {} + is VariableRef -> {} + is VariableStructureRef -> {} } } @@ -133,8 +133,8 @@ class StylesValidator( ) } - private fun resolveDocumentObjects(objects: List): List { - val result = mutableListOf() + private fun resolveDocumentObjects(objects: List): List { + val result = mutableListOf() val visited = mutableSetOf() val queue = objects.toMutableList() @@ -146,7 +146,7 @@ class StylesValidator( result.add(current) visited.add(current.id) - val refs = current.collectRefs().filterIsInstance() + val refs = current.collectRefs().filterIsInstance() for (ref in refs) { val model = documentObjectRepository.findModelOrFail(ref.id) if (!visited.contains(model.id)) { @@ -158,39 +158,45 @@ class StylesValidator( return result } - private fun TextStyleModel.resolveTextStyle( + private fun TextStyle.resolveTextStyle( textStyleIds: MutableSet, missingTextStyles: MutableSet ) { when (this.definition) { - is TextStyleDefinitionModel -> { + is TextStyleDefinition -> { textStyleIds.add(this.nameOrId()) } - is TextStyleModelRef -> { - val model = textStyleRepository.findModel(this.definition.id) - if (model != null) { - model.resolveTextStyle(textStyleIds, missingTextStyles) - } else { - missingTextStyles.add(this.id) + is TextStyleRef -> { + val def = this.definition + if (def is TextStyleRef) { + val model = textStyleRepository.findModel(def.id) + if (model != null) { + model.resolveTextStyle(textStyleIds, missingTextStyles) + } else { + missingTextStyles.add(this.id) + } } } } } - private fun ParagraphStyleModel.resolveParagraphStyle( + private fun ParagraphStyle.resolveParagraphStyle( paragraphStyleIds: MutableSet, missingParagraphStyles: MutableSet ) { when (this.definition) { - is ParagraphStyleDefinitionModel -> { + is ParagraphStyleDefinition -> { paragraphStyleIds.add(this.nameOrId()) } - is ParagraphStyleModelRef -> { - val model = paragraphStyleRepository.findModel(this.definition.id) - if (model != null) { - model.resolveParagraphStyle(paragraphStyleIds, missingParagraphStyles) - } else { - missingParagraphStyles.add(this.id) + is ParagraphStyleRef -> { + val def = this.definition + if (def is ParagraphStyleRef) { + val model = paragraphStyleRepository.findModel(def.id) + if (model != null) { + model.resolveParagraphStyle(paragraphStyleIds, missingParagraphStyles) + } else { + missingParagraphStyles.add(this.id) + } } } } diff --git a/migration-library/src/main/kotlin/com/quadient/migration/service/deploy/DeployClient.kt b/migration-library/src/main/kotlin/com/quadient/migration/service/deploy/DeployClient.kt index 45f00d8e..6be6ba07 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/service/deploy/DeployClient.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/service/deploy/DeployClient.kt @@ -6,18 +6,18 @@ import com.quadient.migration.api.InspireOutput import com.quadient.migration.api.repository.StatusTrackingRepository import com.quadient.migration.data.Active import com.quadient.migration.data.Deployed -import com.quadient.migration.data.DisplayRuleModelRef -import com.quadient.migration.data.DocumentObjectModel -import com.quadient.migration.data.DocumentObjectModelRef -import com.quadient.migration.data.FileModel -import com.quadient.migration.data.FileModelRef -import com.quadient.migration.data.ImageModel -import com.quadient.migration.data.ImageModelRef -import com.quadient.migration.data.ParagraphStyleModelRef -import com.quadient.migration.data.RefModel -import com.quadient.migration.data.TextStyleModelRef -import com.quadient.migration.data.VariableModelRef -import com.quadient.migration.data.VariableStructureModelRef +import com.quadient.migration.api.dto.migrationmodel.DisplayRuleRef +import com.quadient.migration.api.dto.migrationmodel.DocumentObject +import com.quadient.migration.api.dto.migrationmodel.DocumentObjectRef +import com.quadient.migration.api.dto.migrationmodel.File +import com.quadient.migration.api.dto.migrationmodel.FileRef +import com.quadient.migration.api.dto.migrationmodel.Image +import com.quadient.migration.api.dto.migrationmodel.ImageRef +import com.quadient.migration.api.dto.migrationmodel.ParagraphStyleRef +import com.quadient.migration.api.dto.migrationmodel.Ref +import com.quadient.migration.api.dto.migrationmodel.TextStyleRef +import com.quadient.migration.api.dto.migrationmodel.VariableRef +import com.quadient.migration.api.dto.migrationmodel.VariableStructureRef import com.quadient.migration.persistence.repository.DocumentObjectInternalRepository import com.quadient.migration.persistence.repository.ImageInternalRepository import com.quadient.migration.persistence.repository.FileInternalRepository @@ -43,7 +43,7 @@ import kotlin.uuid.ExperimentalUuidApi import kotlin.uuid.Uuid import com.quadient.migration.data.Error as StatusError -data class DocObjectWithRef(val obj: DocumentObjectModel, val documentObjectRefs: Set) +data class DocObjectWithRef(val obj: DocumentObject, val documentObjectRefs: Set) sealed class DeployClient( protected val documentObjectRepository: DocumentObjectInternalRepository, @@ -122,8 +122,8 @@ sealed class DeployClient( null } else { val metadata = when (obj) { - is DocumentObjectModel -> obj.metadata - is ImageModel -> obj.metadata + is DocumentObject -> obj.metadata + is Image -> obj.metadata else -> emptyMap() } info to metadata @@ -140,16 +140,16 @@ sealed class DeployClient( } } - abstract fun getAllDocumentObjectsToDeploy(): List - abstract fun getDocumentObjectsToDeploy(documentObjectIds: List): List - abstract fun deployDocumentObjectsInternal(documentObjects: List): DeploymentResult + abstract fun getAllDocumentObjectsToDeploy(): List + abstract fun getDocumentObjectsToDeploy(documentObjectIds: List): List + abstract fun deployDocumentObjectsInternal(documentObjects: List): DeploymentResult abstract fun deployStyles() protected fun addPostProcessor(processor: (DeploymentResult) -> Unit) { postProcessors.add(processor) } - abstract fun shouldIncludeDependency(documentObject: DocumentObjectModel): Boolean + abstract fun shouldIncludeDependency(documentObject: DocumentObject): Boolean fun deployDocumentObjects(): DeploymentResult { val result = deployDocumentObjectsInternal(getAllDocumentObjectsToDeploy()) @@ -166,7 +166,7 @@ sealed class DeployClient( val result = if (skipDependencies) { deployDocumentObjectsInternal(documentObjects) } else { - val dependencies = documentObjects.flatMap { it.findDependencies() }.filter { !it.internal } + val dependencies = documentObjects.flatMap { it.findDependencies() }.filter { it.internal != true } deployDocumentObjectsInternal((documentObjects + dependencies).toSet().toList()) } @@ -178,14 +178,14 @@ sealed class DeployClient( } - fun deployOrder(documentObjects: List): List { + fun deployOrder(documentObjects: List): List { val documentObjectIds = documentObjects.map { it.id } - val deployOrder = mutableListOf() + val deployOrder = mutableListOf() var toCheck = documentObjects.map { DocObjectWithRef( - it, it.collectRefs().filterIsInstance().map { it -> it.id }.toSet() + it, it.collectRefs().filterIsInstance().map { it -> it.id }.toSet() ) } val deployed = mutableSetOf() @@ -232,7 +232,7 @@ sealed class DeployClient( return deployOrder } - protected fun deployImagesAndFiles(documentObjects: List, deploymentId: Uuid, deploymentTimestamp: Instant): DeploymentResult { + protected fun deployImagesAndFiles(documentObjects: List, deploymentId: Uuid, deploymentTimestamp: Instant): DeploymentResult { val deploymentResult = DeploymentResult(deploymentId) val tracker = ResultTracker(statusTrackingRepository, deploymentResult, deploymentId, deploymentTimestamp, output) @@ -259,7 +259,7 @@ sealed class DeployClient( return deploymentResult } - private fun deployImage(imageRef: ImageModelRef, deploymentResult: DeploymentResult, tracker: ResultTracker) { + private fun deployImage(imageRef: ImageRef, deploymentResult: DeploymentResult, tracker: ResultTracker) { if (!shouldDeployObject(imageRef.id, ResourceType.Image, imageRef.id, deploymentResult)) { logger.info("Skipping deployment of '${imageRef.id}' as it is not marked for deployment.") return @@ -307,7 +307,8 @@ sealed class DeployClient( } logger.debug("Starting deployment of image '${imageModel.nameOrId()}'.") - val readResult = readStorageSafely(imageModel.sourcePath) + val sourcePath = imageModel.sourcePath!! + val readResult = readStorageSafely(sourcePath) if (readResult is ReadResult.Error) { val message = "Error while reading image source data: ${readResult.errorMessage}." logger.error(message) @@ -328,7 +329,7 @@ sealed class DeployClient( tracker.deployedImage(imageModel.id, icmImagePath) } - private fun deployFile(fileRef: FileModelRef, deploymentResult: DeploymentResult, tracker: ResultTracker) { + private fun deployFile(fileRef: FileRef, deploymentResult: DeploymentResult, tracker: ResultTracker) { if (!shouldDeployObject(fileRef.id, ResourceType.File, fileRef.id, deploymentResult)) { logger.info("Skipping deployment of file '${fileRef.id}' as it is not marked for deployment.") return @@ -360,7 +361,8 @@ sealed class DeployClient( } logger.debug("Starting deployment of file '${fileModel.nameOrId()}'.") - val readResult = readStorageSafely(fileModel.sourcePath) + val sourcePath = fileModel.sourcePath!! + val readResult = readStorageSafely(sourcePath) if (readResult is ReadResult.Error) { val message = "Error while reading file source data: ${readResult.errorMessage}." logger.error(message) @@ -391,12 +393,12 @@ sealed class DeployClient( return progressReportInternal(objects, deployId) } - fun progressReportInternal(objects: List, deployId: Uuid? = null): ProgressReport { + fun progressReportInternal(objects: List, deployId: Uuid? = null): ProgressReport { val lastDeployment = deployId?.let { LastDeployment(it, Clock.System.now()) } ?: getLastDeployEvent() val report = ProgressReport(deployId ?: Uuid.random(), mutableMapOf()) - val queue: MutableList = mutableListOf() + val queue: MutableList = mutableListOf() val alreadyVisitedRefs = mutableSetOf>>() for (obj in objects) { @@ -415,7 +417,7 @@ sealed class DeployClient( deployKind = deployKind, errorMessage = lastStatus.errorMessage, ) - alreadyVisitedRefs.add(Pair(obj.id, DocumentObjectModelRef::class)) + alreadyVisitedRefs.add(Pair(obj.id, DocumentObjectRef::class)) val refs = obj.collectRefs() queue.addAll(refs) } @@ -429,10 +431,10 @@ sealed class DeployClient( alreadyVisitedRefs.add(Pair(ref.id, ref::class)) val resource = when (ref) { - is DocumentObjectModelRef -> { + is DocumentObjectRef -> { val obj = documentObjectRepository.findModelOrFail(ref.id) val nextIcmPath = - if (obj.internal || (obj.type == DocumentObjectType.Page && output == InspireOutput.Designer)) { + if (obj.internal == true || (obj.type == DocumentObjectType.Page && output == InspireOutput.Designer)) { null } else { documentObjectBuilder.getDocumentObjectPath(obj) @@ -455,7 +457,7 @@ sealed class DeployClient( obj } - is ImageModelRef -> { + is ImageRef -> { val img = imageRepository.findModelOrFail(ref.id) val nextIcmPath = documentObjectBuilder.getImagePath(img) val deployKind = img.getDeployKind(nextIcmPath) @@ -475,7 +477,7 @@ sealed class DeployClient( img } - is FileModelRef -> { + is FileRef -> { val file = fileRepository.findModelOrFail(ref.id) val nextIcmPath = documentObjectBuilder.getFilePath(file) val deployKind = file.getDeployKind(nextIcmPath) @@ -495,11 +497,11 @@ sealed class DeployClient( file } - is TextStyleModelRef -> null - is ParagraphStyleModelRef -> null - is DisplayRuleModelRef -> null - is VariableModelRef -> null - is VariableStructureModelRef -> null + is TextStyleRef -> null + is ParagraphStyleRef -> null + is DisplayRuleRef -> null + is VariableRef -> null + is VariableStructureRef -> null } if (resource != null) { @@ -511,11 +513,11 @@ sealed class DeployClient( return report } - protected fun DocumentObjectModel.getInvalidMetadataKeys(): Set { + protected fun DocumentObject.getInvalidMetadataKeys(): Set { return this.metadata.keys.asSequence().filter { key -> DISALLOWED_METADATA.contains(key) }.toSet() } - protected fun ImageModel.getInvalidMetadataKeys(): Set { + protected fun Image.getInvalidMetadataKeys(): Set { return this.metadata.keys.asSequence().filter { key -> IMAGE_DISALLOWED_METADATA.contains(key) }.toSet() } @@ -548,14 +550,14 @@ sealed class DeployClient( } } - fun DocumentObjectModel.findDependencies(): List { - val dependencies = mutableListOf() + fun DocumentObject.findDependencies(): List { + val dependencies = mutableListOf() this.collectRefs().forEach { ref -> when (ref) { - is DisplayRuleModelRef, is TextStyleModelRef, is ParagraphStyleModelRef, is VariableModelRef, is VariableStructureModelRef -> {} - is ImageModelRef -> {} - is FileModelRef -> {} - is DocumentObjectModelRef -> { + is DisplayRuleRef, is TextStyleRef, is ParagraphStyleRef, is VariableRef, is VariableStructureRef -> {} + is ImageRef -> {} + is FileRef -> {} + is DocumentObjectRef -> { val model = documentObjectRepository.findModelOrFail(ref.id) if (shouldIncludeDependency(model)) { dependencies.add(model) @@ -567,16 +569,16 @@ sealed class DeployClient( return dependencies } - private fun DocumentObjectModel.getAllDocumentObjectImageAndFileRefs(): Pair, List> { - val images = mutableListOf() - val files = mutableListOf() + private fun DocumentObject.getAllDocumentObjectImageAndFileRefs(): Pair, List> { + val images = mutableListOf() + val files = mutableListOf() this.collectRefs().forEach { ref -> when (ref) { - is DisplayRuleModelRef, is TextStyleModelRef, is ParagraphStyleModelRef, is VariableModelRef, is VariableStructureModelRef -> {} - is ImageModelRef -> images.add(ref) - is FileModelRef -> files.add(ref) - is DocumentObjectModelRef -> { + is DisplayRuleRef, is TextStyleRef, is ParagraphStyleRef, is VariableRef, is VariableStructureRef -> {} + is ImageRef -> images.add(ref) + is FileRef -> files.add(ref) + is DocumentObjectRef -> { val model = documentObjectRepository.findModel(ref.id) ?: error("Unable to collect image or file references because inner document object '${ref.id}' was not found.") @@ -647,18 +649,18 @@ sealed class DeployClient( } } - private fun DocumentObjectModel.getLastStatus(lastDeployment: LastDeployment?): LastStatus { + private fun DocumentObject.getLastStatus(lastDeployment: LastDeployment?): LastStatus { return getLastStatus( id = this.id, lastDeployment = lastDeployment, resourceType = ResourceType.DocumentObject, output = output, - internal = this.internal, + internal = this.internal ?: false, isPage = this.type == DocumentObjectType.Page ) } - private fun ImageModel.getLastStatus(lastDeployment: LastDeployment?): LastStatus { + private fun Image.getLastStatus(lastDeployment: LastDeployment?): LastStatus { return getLastStatus( id = this.id, lastDeployment = lastDeployment, @@ -669,7 +671,7 @@ sealed class DeployClient( ) } - private fun FileModel.getLastStatus(lastDeployment: LastDeployment?): LastStatus { + private fun File.getLastStatus(lastDeployment: LastDeployment?): LastStatus { return getLastStatus( id = this.id, lastDeployment = lastDeployment, @@ -680,22 +682,22 @@ sealed class DeployClient( ) } - private fun DocumentObjectModel.getDeployKind(nextIcmPath: String?): DeployKind { + private fun DocumentObject.getDeployKind(nextIcmPath: String?): DeployKind { return getDeployKind( this.id, ResourceType.DocumentObject, output, - this.internal, + this.internal ?: false, nextIcmPath, this.type == DocumentObjectType.Page ) } - private fun ImageModel.getDeployKind(nextIcmPath: String?): DeployKind { + private fun Image.getDeployKind(nextIcmPath: String?): DeployKind { return getDeployKind(this.id, ResourceType.Image, output, false, nextIcmPath) } - private fun FileModel.getDeployKind(nextIcmPath: String?): DeployKind { + private fun File.getDeployKind(nextIcmPath: String?): DeployKind { return getDeployKind(this.id, ResourceType.File, output, false, nextIcmPath) } diff --git a/migration-library/src/main/kotlin/com/quadient/migration/service/deploy/DesignerDeployClient.kt b/migration-library/src/main/kotlin/com/quadient/migration/service/deploy/DesignerDeployClient.kt index c415e2d5..ae0b4089 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/service/deploy/DesignerDeployClient.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/service/deploy/DesignerDeployClient.kt @@ -4,9 +4,9 @@ package com.quadient.migration.service.deploy import com.quadient.migration.api.InspireOutput import com.quadient.migration.api.repository.StatusTrackingRepository -import com.quadient.migration.data.DocumentObjectModel -import com.quadient.migration.data.ParagraphStyleDefinitionModel -import com.quadient.migration.data.TextStyleDefinitionModel +import com.quadient.migration.api.dto.migrationmodel.DocumentObject +import com.quadient.migration.api.dto.migrationmodel.ParagraphStyleDefinition +import com.quadient.migration.api.dto.migrationmodel.TextStyleDefinition import com.quadient.migration.persistence.repository.DocumentObjectInternalRepository import com.quadient.migration.persistence.repository.ImageInternalRepository import com.quadient.migration.persistence.repository.FileInternalRepository @@ -49,11 +49,11 @@ class DesignerDeployClient( InspireOutput.Designer, ) { - override fun shouldIncludeDependency(documentObject: DocumentObjectModel): Boolean { - return documentObject.type == DocumentObjectType.Page || !documentObject.internal + override fun shouldIncludeDependency(documentObject: DocumentObject): Boolean { + return documentObject.type == DocumentObjectType.Page || documentObject.internal != true } - override fun deployDocumentObjectsInternal(documentObjects: List): DeploymentResult { + override fun deployDocumentObjectsInternal(documentObjects: List): DeploymentResult { val deploymentId = kotlin.uuid.Uuid.random() val deploymentTimestamp = kotlinx.datetime.Clock.System.now() val deploymentResult = DeploymentResult(deploymentId) @@ -113,14 +113,14 @@ class DesignerDeployClient( return deploymentResult } - override fun getDocumentObjectsToDeploy(documentObjectIds: List): List { + override fun getDocumentObjectsToDeploy(documentObjectIds: List): List { val documentObjects = documentObjectRepository.list(DocumentObjectTable.id inList documentObjectIds) val skippedIds = mutableListOf() val internal = mutableListOf() for (documentObject in documentObjects) { - if (documentObject.skip.skipped) { + if (documentObject.skip.skipped == true) { skippedIds.add(documentObject.id) - } else if (documentObject.internal) { + } else if (documentObject.internal == true) { internal.add(documentObject.id) } } @@ -146,7 +146,7 @@ class DesignerDeployClient( return documentObjectsWithoutPages } - override fun getAllDocumentObjectsToDeploy(): List { + override fun getAllDocumentObjectsToDeploy(): List { return documentObjectRepository.list( (DocumentObjectTable.type inList listOf( DocumentObjectType.Template.toString(), @@ -160,9 +160,9 @@ class DesignerDeployClient( val deploymentId = Uuid.random() val deploymentTimestamp = Clock.System.now() - val textStyles = textStyleRepository.listAllModel().filter { it.definition is TextStyleDefinitionModel } + val textStyles = textStyleRepository.listAllModel().filter { it.definition is TextStyleDefinition } val paragraphStyles = - paragraphStyleRepository.listAllModel().filter { it.definition is ParagraphStyleDefinitionModel } + paragraphStyleRepository.listAllModel().filter { it.definition is ParagraphStyleDefinition } val outputPath = documentObjectBuilder.getStyleDefinitionPath() val xml2wfdResult = ipsService.xml2wfd(documentObjectBuilder.buildStyles(textStyles, paragraphStyles), outputPath) diff --git a/migration-library/src/main/kotlin/com/quadient/migration/service/deploy/InteractiveDeployClient.kt b/migration-library/src/main/kotlin/com/quadient/migration/service/deploy/InteractiveDeployClient.kt index ead0d146..6e4b1b77 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/service/deploy/InteractiveDeployClient.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/service/deploy/InteractiveDeployClient.kt @@ -5,9 +5,9 @@ package com.quadient.migration.service.deploy import com.quadient.migration.api.InspireOutput import com.quadient.migration.api.ProjectConfig import com.quadient.migration.api.repository.StatusTrackingRepository -import com.quadient.migration.data.DocumentObjectModel -import com.quadient.migration.data.ParagraphStyleDefinitionModel -import com.quadient.migration.data.TextStyleDefinitionModel +import com.quadient.migration.api.dto.migrationmodel.DocumentObject +import com.quadient.migration.api.dto.migrationmodel.ParagraphStyleDefinition +import com.quadient.migration.api.dto.migrationmodel.TextStyleDefinition import com.quadient.migration.persistence.repository.DocumentObjectInternalRepository import com.quadient.migration.persistence.repository.ImageInternalRepository import com.quadient.migration.persistence.repository.FileInternalRepository @@ -61,11 +61,11 @@ class InteractiveDeployClient( } } - override fun shouldIncludeDependency(documentObject: DocumentObjectModel): Boolean { - return !documentObject.internal + override fun shouldIncludeDependency(documentObject: DocumentObject): Boolean { + return documentObject.internal != true } - override fun getAllDocumentObjectsToDeploy(): List { + override fun getAllDocumentObjectsToDeploy(): List { return documentObjectRepository.list( DocumentObjectTable.skip.extract("skipped") eq "false" and DocumentObjectTable.internal.eq( false @@ -73,15 +73,15 @@ class InteractiveDeployClient( ).let { deployOrder(it) } } - override fun getDocumentObjectsToDeploy(documentObjectIds: List): List { + override fun getDocumentObjectsToDeploy(documentObjectIds: List): List { val documentObjects = documentObjectRepository.list(DocumentObjectTable.id inList documentObjectIds) val skipped = mutableListOf() val internal = mutableListOf() for (documentObject in documentObjects) { - if (documentObject.skip.skipped) { + if (documentObject.skip.skipped == true) { skipped.add(documentObject.id) } - if (documentObject.internal) { + if (documentObject.internal == true) { internal.add(documentObject.id) } } @@ -104,7 +104,7 @@ class InteractiveDeployClient( return documentObjects } - override fun deployDocumentObjectsInternal(documentObjects: List): DeploymentResult { + override fun deployDocumentObjectsInternal(documentObjects: List): DeploymentResult { val deploymentId = Uuid.random() val deploymentTimestamp = Clock.System.now() val deploymentResult = DeploymentResult(deploymentId) @@ -185,9 +185,9 @@ class InteractiveDeployClient( } } - val textStyles = textStyleRepository.listAllModel().filter { it.definition is TextStyleDefinitionModel } + val textStyles = textStyleRepository.listAllModel().filter { it.definition is TextStyleDefinition } val paragraphStyles = - paragraphStyleRepository.listAllModel().filter { it.definition is ParagraphStyleDefinitionModel } + paragraphStyleRepository.listAllModel().filter { it.definition is ParagraphStyleDefinition } val styleLayoutDeltaXml = documentObjectBuilder.buildStyleLayoutDelta( textStyles = textStyles, diff --git a/migration-library/src/main/kotlin/com/quadient/migration/service/deploy/ProgressReport.kt b/migration-library/src/main/kotlin/com/quadient/migration/service/deploy/ProgressReport.kt index 211abc0d..d525c42d 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/service/deploy/ProgressReport.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/service/deploy/ProgressReport.kt @@ -5,9 +5,6 @@ package com.quadient.migration.service.deploy import com.quadient.migration.api.dto.migrationmodel.DocumentObject import com.quadient.migration.api.dto.migrationmodel.Image import com.quadient.migration.api.dto.migrationmodel.File -import com.quadient.migration.data.DocumentObjectModel -import com.quadient.migration.data.ImageModel -import com.quadient.migration.data.FileModel import kotlinx.datetime.Instant import kotlin.uuid.ExperimentalUuidApi import kotlin.uuid.Uuid @@ -159,7 +156,7 @@ data class ReportedFile( data class ProgressReport(val id: Uuid?, val items: MutableMap, ProgressReportItem>) { fun addDocumentObject( id: String, - documentObject: DocumentObjectModel, + documentObject: DocumentObject, previousIcmPath: String? = null, nextIcmPath: String? = null, deployKind: DeployKind, @@ -177,7 +174,7 @@ data class ProgressReport(val id: Uuid?, val items: MutableMap() - val virtualPageContent = mutableListOf() + val pageModels = mutableListOf() + val virtualPageContent = mutableListOf() if (fontDataCache.isEmpty()) { val fontDataString = ipsService.gatherFontData(getFontRootFolder()) @@ -176,7 +167,7 @@ class DesignerDocumentObjectBuilder( val languageVariable = variableStructure.languageVariable if (languageVariable != null) { val languageVariableModel = variableRepository.findModelOrFail(languageVariable.id) - val languageVariablePathData = variableStructure.structure[languageVariable] + val languageVariablePathData = variableStructure.structure[languageVariable.id] if (languageVariablePathData == null || languageVariablePathData.path.isBlank()) { error("Language variable '${languageVariable.id}' or its path not found in variable structure '${variableStructure.id}'.") } @@ -185,7 +176,7 @@ class DesignerDocumentObjectBuilder( } documentObject.content.paragraphIfEmpty().forEach { - if (it is DocumentObjectModelRef) { + if (it is DocumentObjectRef) { val documentObjectModel = documentObjectRepository.findModelOrFail(it.id) if (documentObjectModel.type == DocumentObjectType.Page) { pageModels.add(documentObjectModel) @@ -198,14 +189,14 @@ class DesignerDocumentObjectBuilder( } pageModels.forEach { - if (it.skip.skipped && it.skip.placeholder != null) { + if (it.skip.skipped == true && it.skip.placeholder != null) { val page = layout.addPage().setName("Page (skipped)").setType(Pages.PageConditionType.SIMPLE) val flow = layout.addFlow().setType(Flow.Type.SIMPLE) flow.addParagraph().addText().appendText("Skipped page: '${it.nameOrId()}'. Placeholder: ${it.skip.placeholder}") page.addFlowArea().setPosX(defaultPosition.x.toMeters()).setPosY(defaultPosition.y.toMeters()) .setWidth(defaultPosition.width.toMeters()).setHeight(defaultPosition.height.toMeters()) .setFlow(flow) - } else if (!it.skip.skipped) { + } else if (it.skip.skipped != true) { buildPage( layout, variableStructure, @@ -230,9 +221,9 @@ class DesignerDocumentObjectBuilder( } buildTextStyles( - layout, textStyleRepository.listAllModel().filter { it.definition is TextStyleDefinitionModel }) + layout, textStyleRepository.listAllModel().filter { it.definition is TextStyleDefinition }) buildParagraphStyles( - layout, paragraphStyleRepository.listAllModel().filter { it.definition is ParagraphStyleDefinitionModel }) + layout, paragraphStyleRepository.listAllModel().filter { it.definition is ParagraphStyleDefinition }) val firstPageWithFlowArea = (layout.pages as PagesImpl).children.find { page -> (page as PageImpl).children.any { it is FlowArea } } as? PageImpl @@ -249,12 +240,12 @@ class DesignerDocumentObjectBuilder( } } - override fun shouldIncludeInternalDependency(documentObject: DocumentObjectModel): Boolean { - return documentObject.internal || documentObject.type == DocumentObjectType.Page + override fun shouldIncludeInternalDependency(documentObject: DocumentObject): Boolean { + return documentObject.internal == true || documentObject.type == DocumentObjectType.Page } override fun wrapSuccessFlowInConditionFlow( - layout: Layout, variableStructure: VariableStructureModel, ruleDef: DisplayRuleDefinition, successFlow: Flow, + layout: Layout, variableStructure: VariableStructure, ruleDef: DisplayRuleDefinition, successFlow: Flow, ): Flow { return layout.addFlow().setType(Flow.Type.SELECT_BY_INLINE_CONDITION).addLineForSelectByInlineCondition( ruleDef.toScript(layout, variableStructure, variableRepository::findModelOrFail), successFlow @@ -263,7 +254,7 @@ class DesignerDocumentObjectBuilder( override fun buildSuccessRowWrappedInConditionRow( layout: Layout, - variableStructure: VariableStructureModel, + variableStructure: VariableStructure, ruleDef: DisplayRuleDefinition, multipleRowSet: GeneralRowSet, ): GeneralRowSet { @@ -280,10 +271,10 @@ class DesignerDocumentObjectBuilder( private fun buildPage( layout: Layout, - variableStructure: VariableStructureModel, + variableStructure: VariableStructure, name: String, - content: List, - mainObject: DocumentObjectModel, + content: List, + mainObject: DocumentObject, options: PageOptions? = null, languages: List, ) { @@ -291,11 +282,11 @@ class DesignerDocumentObjectBuilder( options?.height?.let { page.setHeight(it.toMeters()) } options?.width?.let { page.setWidth(it.toMeters()) } - val areaModels = mutableListOf() - val virtualAreaContent = mutableListOf() + val areaModels = mutableListOf() + val virtualAreaContent = mutableListOf() content.forEach { - if (it is AreaModel) { + if (it is Area) { areaModels.add(it) } else { virtualAreaContent.add(it) @@ -309,7 +300,7 @@ class DesignerDocumentObjectBuilder( layout, variableStructure, page, - AreaModel(virtualAreaContent, defaultPosition, null), + Area(virtualAreaContent, defaultPosition, null), mainObject, languages ) @@ -318,17 +309,17 @@ class DesignerDocumentObjectBuilder( private fun buildArea( layout: Layout, - variableStructure: VariableStructureModel, + variableStructure: VariableStructure, page: Page, - areaModel: AreaModel, - mainObject: DocumentObjectModel, + areaModel: Area, + mainObject: DocumentObject, languages: List ) { val position = areaModel.position ?: defaultPosition val content = areaModel.content - if (content.size == 1 && content.first() is ImageModelRef) { - val imageRef = content.first() as ImageModelRef + if (content.size == 1 && content.first() is ImageRef) { + val imageRef = content.first() as ImageRef val imageModel = imageRepository.findModelOrFail(imageRef.id) when (val imagePlaceholder = getImagePlaceholder(imageModel)) { diff --git a/migration-library/src/main/kotlin/com/quadient/migration/service/inspirebuilder/InspireDocumentObjectBuilder.kt b/migration-library/src/main/kotlin/com/quadient/migration/service/inspirebuilder/InspireDocumentObjectBuilder.kt index b0404e5c..b1b71b64 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/service/inspirebuilder/InspireDocumentObjectBuilder.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/service/inspirebuilder/InspireDocumentObjectBuilder.kt @@ -1,1240 +1,1251 @@ -package com.quadient.migration.service.inspirebuilder - -import com.quadient.migration.api.ProjectConfig -import com.quadient.migration.api.dto.migrationmodel.CustomFieldMap -import com.quadient.migration.data.DisplayRuleModelRef -import com.quadient.migration.data.DocumentContentModel -import com.quadient.migration.data.DocumentObjectModel -import com.quadient.migration.data.DocumentObjectModelRef -import com.quadient.migration.data.FirstMatchModel -import com.quadient.migration.data.AreaModel -import com.quadient.migration.data.HyperlinkModel -import com.quadient.migration.data.ImageModel -import com.quadient.migration.data.ImageModelRef -import com.quadient.migration.data.FileModel -import com.quadient.migration.data.FileModelRef -import com.quadient.migration.data.ParagraphModel -import com.quadient.migration.data.ParagraphModel.TextModel -import com.quadient.migration.data.ParagraphStyleDefinitionModel -import com.quadient.migration.data.ParagraphStyleModel -import com.quadient.migration.data.ParagraphStyleModelRef -import com.quadient.migration.data.SelectByLanguageModel -import com.quadient.migration.data.StringModel -import com.quadient.migration.data.TableModel -import com.quadient.migration.data.TextStyleDefinitionModel -import com.quadient.migration.data.TextStyleModel -import com.quadient.migration.data.TextStyleModelRef -import com.quadient.migration.data.VariableModel -import com.quadient.migration.data.VariableModelRef -import com.quadient.migration.data.VariableStructureModel -import com.quadient.migration.persistence.repository.DisplayRuleInternalRepository -import com.quadient.migration.persistence.repository.DocumentObjectInternalRepository -import com.quadient.migration.persistence.repository.ImageInternalRepository -import com.quadient.migration.persistence.repository.FileInternalRepository -import com.quadient.migration.persistence.repository.ParagraphStyleInternalRepository -import com.quadient.migration.persistence.repository.TextStyleInternalRepository -import com.quadient.migration.persistence.repository.VariableInternalRepository -import com.quadient.migration.persistence.repository.VariableStructureInternalRepository -import com.quadient.migration.service.inspirebuilder.InspireDocumentObjectBuilder.FlowModel.* -import com.quadient.migration.service.inspirebuilder.InspireDocumentObjectBuilder.ScriptResult -import com.quadient.migration.service.inspirebuilder.InspireDocumentObjectBuilder.ScriptResult.* -import com.quadient.migration.service.ipsclient.IpsService -import com.quadient.migration.shared.Alignment -import com.quadient.migration.shared.BinOp -import com.quadient.migration.shared.Binary -import com.quadient.migration.shared.DisplayRuleDefinition -import com.quadient.migration.shared.DocumentObjectType -import com.quadient.migration.shared.FileType -import com.quadient.migration.shared.Function -import com.quadient.migration.shared.Group -import com.quadient.migration.shared.IcmPath -import com.quadient.migration.shared.ImageType -import com.quadient.migration.shared.LineSpacing -import com.quadient.migration.shared.Literal -import com.quadient.migration.shared.LiteralDataType -import com.quadient.migration.shared.LiteralOrFunctionCall -import com.quadient.migration.shared.ParagraphPdfTaggingRule as ParagraphPdfTaggingRuleModel -import com.quadient.migration.shared.SuperOrSubscript -import com.quadient.migration.shared.TabType -import com.quadient.wfdxml.WfdXmlBuilder -import com.quadient.wfdxml.api.layoutnodes.Flow -import com.quadient.wfdxml.api.layoutnodes.Font -import com.quadient.wfdxml.api.layoutnodes.Image -import com.quadient.wfdxml.api.layoutnodes.LocationType -import com.quadient.wfdxml.api.layoutnodes.Pages -import com.quadient.wfdxml.api.layoutnodes.ParagraphStyle -import com.quadient.wfdxml.api.layoutnodes.ParagraphStyle.LineSpacingType.* -import com.quadient.wfdxml.api.layoutnodes.TabulatorType -import com.quadient.wfdxml.api.layoutnodes.data.Data -import com.quadient.wfdxml.api.layoutnodes.data.DataType -import com.quadient.wfdxml.api.layoutnodes.data.Variable -import com.quadient.wfdxml.api.layoutnodes.data.VariableKind -import com.quadient.wfdxml.api.layoutnodes.flow.Text -import com.quadient.wfdxml.api.layoutnodes.font.SubFont -import com.quadient.wfdxml.api.layoutnodes.tables.GeneralRowSet -import com.quadient.wfdxml.api.layoutnodes.tables.RowSet -import com.quadient.wfdxml.api.layoutnodes.tables.Table -import com.quadient.migration.shared.TablePdfTaggingRule -import com.quadient.wfdxml.api.layoutnodes.ParagraphStyle.ParagraphPdfTaggingRule -import com.quadient.wfdxml.api.layoutnodes.TextStyle -import com.quadient.wfdxml.api.layoutnodes.TextStyleInheritFlag -import com.quadient.wfdxml.api.layoutnodes.TextStyleType -import com.quadient.wfdxml.api.layoutnodes.flow.Paragraph -import com.quadient.wfdxml.api.module.Layout -import com.quadient.wfdxml.internal.data.WorkFlowTreeDefinition -import com.quadient.wfdxml.internal.layoutnodes.TextStyleImpl -import com.quadient.wfdxml.internal.layoutnodes.data.DataImpl -import com.quadient.wfdxml.internal.layoutnodes.data.WorkFlowTreeEnums.NodeOptionality -import com.quadient.wfdxml.internal.layoutnodes.data.WorkFlowTreeEnums.NodeType.SUB_TREE -import kotlinx.datetime.Clock -import org.slf4j.LoggerFactory -import java.util.concurrent.ConcurrentHashMap -import kotlin.collections.ifEmpty -import com.quadient.migration.shared.DataType as DataTypeModel - -abstract class InspireDocumentObjectBuilder( - protected val documentObjectRepository: DocumentObjectInternalRepository, - protected val textStyleRepository: TextStyleInternalRepository, - protected val paragraphStyleRepository: ParagraphStyleInternalRepository, - protected val variableRepository: VariableInternalRepository, - protected val variableStructureRepository: VariableStructureInternalRepository, - protected val displayRuleRepository: DisplayRuleInternalRepository, - protected val imageRepository: ImageInternalRepository, - protected val fileRepository: FileInternalRepository, - protected val projectConfig: ProjectConfig, - protected val ipsService: IpsService, -) { - protected val logger = LoggerFactory.getLogger(this::class.java)!! - - protected val fontDataCache = ConcurrentHashMap() - - abstract fun getDocumentObjectPath(nameOrId: String, type: DocumentObjectType, targetFolder: IcmPath?): String - - abstract fun getDocumentObjectPath(documentObject: DocumentObjectModel): String - - abstract fun getImagePath( - id: String, imageType: ImageType, name: String?, targetFolder: IcmPath?, sourcePath: String? - ): String - - abstract fun getImagePath(image: ImageModel): String - - abstract fun getFilePath( - id: String, name: String?, targetFolder: IcmPath?, sourcePath: String?, fileType: FileType - ): String - - abstract fun getFilePath(file: FileModel): String - - abstract fun getStyleDefinitionPath(extension: String = "wfd"): String - - abstract fun getFontRootFolder(): String - - abstract fun buildDocumentObject(documentObject: DocumentObjectModel, styleDefinitionPath: String?): String - - abstract fun shouldIncludeInternalDependency(documentObject: DocumentObjectModel): Boolean - - protected fun collectLanguages(documentObject: DocumentObjectModel): List { - val languages = mutableSetOf() - - fun collectLanguagesFromContent(content: List) { - for (item in content) { - when (item) { - is SelectByLanguageModel -> item.cases.forEach { languages.add(it.language) } - is AreaModel -> collectLanguagesFromContent(item.content) - is FirstMatchModel -> { - item.cases.forEach { case -> collectLanguagesFromContent(case.content) } - collectLanguagesFromContent(item.default) - } - - is TableModel -> item.rows.forEach { row -> - row.cells.forEach { cell -> collectLanguagesFromContent(cell.content) } - } - - is DocumentObjectModelRef -> { - val documentObject = documentObjectRepository.findModelOrFail(item.id) - if (shouldIncludeInternalDependency(documentObject)) { - collectLanguagesFromContent(documentObject.content) - } - } - - is ParagraphModel -> item.content.forEach { textModel -> - textModel.content.forEach { textContent -> - when (textContent) { - is FirstMatchModel -> { - textContent.cases.forEach { case -> collectLanguagesFromContent(case.content) } - collectLanguagesFromContent(textContent.default) - } - - is TableModel -> textContent.rows.forEach { row -> - row.cells.forEach { cell -> collectLanguagesFromContent(cell.content) } - } - - is DocumentObjectModelRef -> { - val documentObject = documentObjectRepository.findModelOrFail(textContent.id) - if (shouldIncludeInternalDependency(documentObject)) { - collectLanguagesFromContent(documentObject.content) - } - } - - else -> {} - } - } - } - - else -> {} - } - } - } - - collectLanguagesFromContent(documentObject.content) - - return languages.toList() - } - - protected open fun wrapSuccessFlowInConditionFlow( - layout: Layout, variableStructure: VariableStructureModel, ruleDef: DisplayRuleDefinition, successFlow: Flow - ): Flow { - return layout.addFlow().setType(Flow.Type.SELECT_BY_CONDITION).addLineForSelectByCondition( - layout.data.addVariable().setKind(VariableKind.CALCULATED).setDataType(DataType.BOOL) - .setScript(ruleDef.toScript(layout, variableStructure, variableRepository::findModelOrFail)), - successFlow - ) - } - - protected open fun buildSuccessRowWrappedInConditionRow( - layout: Layout, - variableStructure: VariableStructureModel, - ruleDef: DisplayRuleDefinition, - multipleRowSet: GeneralRowSet - ): GeneralRowSet { - val successRow = layout.addRowSet().setType(RowSet.Type.SINGLE_ROW) - - multipleRowSet.addRowSet( - layout.addRowSet().setType(RowSet.Type.SELECT_BY_CONDITION).addLineForSelectByCondition( - layout.data.addVariable().setKind(VariableKind.CALCULATED).setDataType(DataType.BOOL) - .setScript(ruleDef.toScript(layout, variableStructure, variableRepository::findModelOrFail)), - successRow - ) - ) - - return successRow - } - - fun buildStyleLayoutDelta(textStyles: List, paragraphStyles: List): String { - logger.debug("Starting to build style layout delta.") - - val builder = WfdXmlBuilder() - val layout = builder.addLayout() - - if (fontDataCache.isEmpty()) { - val fontDataString = ipsService.gatherFontData(getFontRootFolder()) - fontDataCache.putAll(fontDataStringToMap(fontDataString)) - } - - buildTextStyles(layout, textStyles) - buildParagraphStyles(layout, paragraphStyles) - - logger.debug("Successfully built style layout delta.") - return builder.buildStyleLayoutDelta() - } - - fun buildStyles( - textStyles: List, - paragraphStyles: List, - ): String { - logger.debug("Starting to build style definition.") - - val builder = WfdXmlBuilder() - val layout = builder.addLayout() - - layout.setName("DocumentLayout") - val flow = layout.addFlow().setSectionFlow(true).setWebEditingType(Flow.WebEditingType.SECTION) - layout.pages.setMainFlow(flow) - layout.addPage().setName("Page 1").setType(Pages.PageConditionType.SIMPLE) - layout.addRoot().setAllowRuntimeModifications(true) - - if (fontDataCache.isEmpty()) { - val fontDataString = ipsService.gatherFontData(getFontRootFolder()) - fontDataCache.putAll(fontDataStringToMap(fontDataString)) - } - - buildTextStyles(layout, textStyles) - buildParagraphStyles(layout, paragraphStyles) - - logger.debug("Successfully built style definition.") - return builder.build() - } - - fun buildDocumentContentAsFlows( - layout: Layout, - variableStructure: VariableStructureModel, - content: List, - flowName: String? = null, - languages: List, - ): List { - val mutableContent = content.toMutableList() - - var idx = 0 - val flowModels = mutableListOf() - while (idx < mutableContent.size) { - when (val contentPart = mutableContent[idx]) { - is TableModel, is ParagraphModel, is ImageModelRef -> { - val flowParts = gatherFlowParts(mutableContent, idx) - idx += flowParts.size - 1 - flowModels.add(Composite(flowParts)) - } - - is DocumentObjectModelRef -> flowModels.add(DocumentObject(contentPart)) - is FileModelRef -> flowModels.add(File(contentPart)) - is AreaModel -> mutableContent.addAll(idx + 1, contentPart.content) - is FirstMatchModel -> flowModels.add(FirstMatch(contentPart)) - is SelectByLanguageModel -> flowModels.add(SelectByLanguage(contentPart)) - } - idx++ - } - - val flowCount = flowModels.size - var flowSuffix = 1 - return flowModels.mapNotNull { - when (it) { - is DocumentObject -> buildDocumentObjectRef(layout, variableStructure, it.ref, languages) - is File -> buildFileRef(layout, it.ref) - is Composite -> { - if (flowName == null) { - buildCompositeFlow(layout, variableStructure, it.parts, null, languages) - } else { - val name = if (flowCount == 1) flowName else "$flowName $flowSuffix" - flowSuffix++ - buildCompositeFlow(layout, variableStructure, it.parts, name, languages) - } - } - - is FirstMatch -> { - if (flowName == null) { - buildFirstMatch(layout, variableStructure, it.model, false, null, languages) - } else { - val name = if (flowCount == 1) flowName else "$flowName $flowSuffix" - flowSuffix++ - buildFirstMatch(layout, variableStructure, it.model, false, name, languages) - } - } - - is SelectByLanguage -> { - if (flowName == null) { - buildSelectByLanguage(layout, variableStructure, it.model, null, languages) - } else { - val name = if (flowCount == 1) flowName else "$flowName $flowSuffix" - flowSuffix++ - buildSelectByLanguage(layout, variableStructure, it.model, name, languages) - } - } - } - } - } - - sealed interface FlowModel { - data class Composite(val parts: List) : FlowModel - data class DocumentObject(val ref: DocumentObjectModelRef) : FlowModel - data class File(val ref: FileModelRef) : FlowModel - data class FirstMatch(val model: FirstMatchModel) : FlowModel - data class SelectByLanguage(val model: SelectByLanguageModel) : FlowModel - } - - protected fun List.toSingleFlow( - layout: Layout, - variableStructure: VariableStructureModel, - flowName: String? = null, - displayRuleRef: DisplayRuleModelRef? = null, - ): Flow { - val singleFlow = if (this.size == 1) { - this[0] - } else { - val sectionFlow = layout.addFlow().setType(Flow.Type.SIMPLE).setSectionFlow(true) - flowName?.let { sectionFlow.setName(it) } - - val sectionFlowText = sectionFlow.addParagraph().addText() - - this.forEach { sectionFlowText.appendFlow(it) } - - sectionFlow - } - - return if (displayRuleRef == null) { - singleFlow - } else { - val displayRule = displayRuleRepository.findModelOrFail(displayRuleRef.id) - if (displayRule.definition == null) { - error("Display rule '${displayRuleRef.id}' definition is null.") - } - - wrapSuccessFlowInConditionFlow(layout, variableStructure, displayRule.definition, singleFlow) - } - } - - protected fun buildDocumentContentAsSingleFlow( - layout: Layout, - variableStructure: VariableStructureModel, - content: List, - flowName: String? = null, - displayRuleRef: DisplayRuleModelRef? = null, - languages: List, - ): Flow { - return buildDocumentContentAsFlows(layout, variableStructure, content, flowName, languages).toSingleFlow( - layout, variableStructure, flowName, displayRuleRef - ) - } - - protected fun initVariableStructure(layout: Layout, documentObject: DocumentObjectModel): VariableStructureModel { - val variableStructureId = documentObject.variableStructureRef?.id ?: projectConfig.defaultVariableStructure - - val variableStructureModel = - variableStructureId?.let { variableStructureRepository.findModelOrFail(it) } ?: VariableStructureModel( - id = "defaultVariableStructure", - lastUpdated = Clock.System.now(), - created = Clock.System.now(), - structure = mutableMapOf(), - customFields = CustomFieldMap(), - languageVariable = null, - ) - - val normalizedVariablePaths = variableStructureModel.structure.map { (_, variablePathData) -> - removeDataFromVariablePath(variablePathData.path) - }.filter { it.isNotBlank() } - - val variableTree = buildVariableTree(normalizedVariablePaths) - - val workflowTreeDefinition = WorkFlowTreeDefinition("Root", SUB_TREE, NodeOptionality.ARRAY).also { - buildVariablePathPart(it, variableTree) - } - - val layoutData = layout.data - layoutData.importDataDefinition(workflowTreeDefinition) - if (variableTree.isNotEmpty() && variableTree.values.first() is ArrayVariable) { - layoutData.setRepeatedBy("Data.${variableTree.keys.first()}") - } - - return variableStructureModel - } - - private fun buildVariablePathPart( - parentNode: WorkFlowTreeDefinition, currentMap: Map - ) { - currentMap.forEach { - val variablePathPart = it.value - val optionality = - if (variablePathPart is ArrayVariable) NodeOptionality.ARRAY else NodeOptionality.MUST_EXIST - - val node = WorkFlowTreeDefinition(variablePathPart.name, SUB_TREE, optionality) - parentNode.addSubNode(node) - - if (variablePathPart.children.isNotEmpty()) { - buildVariablePathPart(node, variablePathPart.children) - } - } - } - - private fun upsertSubFont(font: Font, isBold: Boolean, isItalic: Boolean): SubFont? { - val subFontName = buildFontName(isBold, isItalic) - - val fontLocation = fontDataCache[FontKey(font.name, subFontName)] - ?: fontDataCache[FontKey(font.name, buildFontName(bold = false, italic = false))] - ?: return null - - font.subFonts.removeAll { it.name == subFontName } - return font.addSubfont().setName(subFontName).setBold(isBold).setItalic(isItalic) - .setLocation(fontLocation, LocationType.ICM) - } - - fun buildTextStyles(layout: Layout, textStyleModels: List) { - val arialFont = getFontByName(layout, "Arial") - require(arialFont != null) { "Layout must contain Arial font." } - arialFont.setName("Arial").setFontName("Arial") - upsertSubFont(arialFont, isBold = false, isItalic = false) - - textStyleModels.forEach { styleModel -> - val definition = styleModel.resolve() - val textStyle = layout.addTextStyle().setName(styleModel.nameOrId()) - applyTextStyleProperties(layout, textStyle, definition) - } - } - - private fun applyTextStyleProperties(layout: Layout, textStyle: TextStyle, definition: TextStyleDefinitionModel) { - val fontFamily = definition.fontFamily ?: "Arial" - - val font = getFontByName(layout, fontFamily) ?: layout.addFont().setName(fontFamily).setFontName(fontFamily) - textStyle.setFont(font) - - val subFont = upsertSubFont(font, definition.bold, definition.italic) - if (subFont != null) { - textStyle.setSubFont(subFont) - } - - textStyle.setBold(definition.bold) - textStyle.seItalic(definition.italic) - textStyle.setUnderline(definition.underline) - textStyle.setStrikeThrough(definition.strikethrough) - - definition.size?.let { textStyle.setFontSizeInMeters(it.toMeters()) } - definition.interspacing?.let { textStyle.setInterSpacing(it.toMeters()) } - - when (definition.superOrSubscript) { - SuperOrSubscript.Subscript -> textStyle.setSubScript(true).setSuperScript(false) - SuperOrSubscript.Superscript -> textStyle.setSubScript(false).setSuperScript(true) - SuperOrSubscript.None -> textStyle.setSubScript(false).setSuperScript(false) - } - - definition.foregroundColor?.let { colorModel -> - val layoutColor = getColorByRGB(layout, colorModel.red(), colorModel.green(), colorModel.blue()) - ?: layout.addColor().setRGB(colorModel.red(), colorModel.green(), colorModel.blue()) - val fillStyle = getFillStyleByColor(layout, layoutColor) - ?: layout.addFillStyle().setColor(layoutColor) - textStyle.setFillStyle(fillStyle) - } - } - - fun buildParagraphStyles(layout: Layout, paragraphStyleModels: List) { - paragraphStyleModels.forEach { styleModel -> - val definition = styleModel.resolve() - - val paragraphStyle = layout.addParagraphStyle().setName(styleModel.nameOrId()) - - definition.leftIndent?.let { paragraphStyle.setLeftIndent(it.toMeters()) } - definition.rightIndent?.let { paragraphStyle.setRightIndent(it.toMeters()) } - definition.defaultTabSize?.let { paragraphStyle.setDefaultTabSize(it.toMeters()) } - definition.spaceBefore?.let { paragraphStyle.setSpaceBefore(it.toMeters()) } - definition.spaceAfter?.let { paragraphStyle.setSpaceAfter(it.toMeters()) } - val alignType = when (definition.alignment) { - Alignment.Left -> ParagraphStyle.AlignType.LEFT - Alignment.Right -> ParagraphStyle.AlignType.RIGHT - Alignment.Center -> ParagraphStyle.AlignType.CENTER - Alignment.JustifyLeft -> ParagraphStyle.AlignType.JUSTIFY_lEFT - Alignment.JustifyRight -> ParagraphStyle.AlignType.JUSTIFY_RIGHT - Alignment.JustifyCenter -> ParagraphStyle.AlignType.JUSTIFY_CENTER - Alignment.JustifyBlock -> ParagraphStyle.AlignType.JUSTIFY_BLOCK - Alignment.JustifyWithMargins -> ParagraphStyle.AlignType.JUSTIFY_WITH_MARGIN - Alignment.JustifyBlockUniform -> ParagraphStyle.AlignType.JUSTIFY_BLOCK_UNIFORM - } - paragraphStyle.setAlignType(alignType) - - definition.firstLineIndent?.let { paragraphStyle.setFirstLineLeftIndent(it.toMeters()) } - - val lineSpacing = definition.lineSpacing - val (lineSpacingType, lineSpacingValue) = when (lineSpacing) { - is LineSpacing.Additional -> Pair(ADDITIONAL, lineSpacing.size?.toMeters()) - is LineSpacing.AtLeast -> Pair(AT_LEAST, lineSpacing.size?.toMeters()) - is LineSpacing.Exact -> Pair(EXACT, lineSpacing.size?.toMeters()) - is LineSpacing.ExactFromPrevious -> Pair(EXACT_FROM_PREVIOUS, lineSpacing.size?.toMeters()) - is LineSpacing.ExactFromPreviousWithAdjust -> Pair( - EXACT_FROM_PREVIOUS_WITH_ADJUST, lineSpacing.size?.toMeters() - ) - - is LineSpacing.ExactFromPreviousWithAdjustLegacy -> Pair( - EXACT_FROM_PREVIOUS_WITH_ADJUST_OLD, lineSpacing.size?.toMeters() - ) - - is LineSpacing.MultipleOf -> Pair(MULTIPLE_OF, lineSpacing.value) - } - paragraphStyle.setLineSpacingType(lineSpacingType) - lineSpacingValue?.let { paragraphStyle.setLineSpacingValue(it) } - - definition.tabs?.let { tabsModel -> - paragraphStyle.setUseOutsideTabs(tabsModel.useOutsideTabs) - tabsModel.tabs.forEach { tabModel -> - val tabType = when (tabModel.type) { - TabType.Left -> TabulatorType.LEFT - TabType.Right -> TabulatorType.RIGHT - TabType.Center -> TabulatorType.CENTER - TabType.DecimalWord -> TabulatorType.WORD_DECIMAL - TabType.Decimal -> TabulatorType.DECIMAL - } - - paragraphStyle.addTabulator(tabModel.position.toMeters(), tabType) - } - } - - definition.pdfTaggingRule?.let { pdfTaggingRule -> - val rule = when (pdfTaggingRule) { - ParagraphPdfTaggingRuleModel.Paragraph -> ParagraphPdfTaggingRule.PARAGRAPH - ParagraphPdfTaggingRuleModel.Heading -> ParagraphPdfTaggingRule.HEADING - ParagraphPdfTaggingRuleModel.Heading1 -> ParagraphPdfTaggingRule.HEADING_1 - ParagraphPdfTaggingRuleModel.Heading2 -> ParagraphPdfTaggingRule.HEADING_2 - ParagraphPdfTaggingRuleModel.Heading3 -> ParagraphPdfTaggingRule.HEADING_3 - ParagraphPdfTaggingRuleModel.Heading4 -> ParagraphPdfTaggingRule.HEADING_4 - ParagraphPdfTaggingRuleModel.Heading5 -> ParagraphPdfTaggingRule.HEADING_5 - ParagraphPdfTaggingRuleModel.Heading6 -> ParagraphPdfTaggingRule.HEADING_6 - } - paragraphStyle.setPdfTaggingRule(rule) - } - } - } - - sealed interface ImagePlaceholderResult { - object RenderAsNormal : ImagePlaceholderResult - object Skip : ImagePlaceholderResult - data class Placeholder(val value: String) : ImagePlaceholderResult - } - protected fun getImagePlaceholder(imageModel: ImageModel): ImagePlaceholderResult { - if (imageModel.imageType == ImageType.Unknown && !imageModel.skip.skipped) { - throw IllegalStateException( - "Image '${imageModel.nameOrId()}' has unknown type and is not set to be skipped." - ) - } - if (imageModel.sourcePath.isNullOrBlank() && !imageModel.skip.skipped) { - throw IllegalStateException( - "Image '${imageModel.nameOrId()}' has missing source path and is not set to be skipped." - ) - } - - if (imageModel.skip.skipped && imageModel.skip.placeholder != null) { - return ImagePlaceholderResult.Placeholder(imageModel.skip.placeholder) - } else if (imageModel.skip.skipped) { - return ImagePlaceholderResult.Skip - } - - return ImagePlaceholderResult.RenderAsNormal - } - - protected fun getOrBuildImage(layout: Layout, imageModel: ImageModel, alternateText: String? = null): Image { - val image = getImageByName(layout, imageModel.nameOrId()) ?: layout.addImage().setName(imageModel.nameOrId()) - .setImageLocation(getImagePath(imageModel), LocationType.ICM) - - if (imageModel.options != null) { - imageModel.options.resizeWidth?.let { image.setResizeWidth(it.toMeters()) } - imageModel.options.resizeHeight?.let { image.setResizeHeight(it.toMeters()) } - } - - if (!alternateText.isNullOrBlank()) { - applyImageAlternateText(layout, image, alternateText) - } - - return image - } - - protected abstract fun applyImageAlternateText(layout: Layout, image: Image, alternateText: String) - - private fun buildFileRef( - layout: Layout, - fileRef: FileModelRef, - ): Flow? { - val fileModel = fileRepository.findModelOrFail(fileRef.id) - - if (fileModel.skip.skipped && fileModel.skip.placeholder == null) { - val reason = fileModel.skip.reason?.let { "with reason: $it" } ?: "without reason" - logger.debug("File ${fileRef.id} is set to be skipped without placeholder $reason.") - return null - } else if (fileModel.skip.skipped && fileModel.skip.placeholder != null) { - val reason = fileModel.skip.reason?.let { "and reason: $it" } ?: "without reason" - logger.debug("File ${fileRef.id} is set to be skipped with placeholder $reason.") - val flow = layout.addFlow().setType(Flow.Type.SIMPLE) - flow.addParagraph().addText().appendText(fileModel.skip.placeholder) - return flow - } - - if (fileModel.sourcePath.isNullOrBlank()) { - throw IllegalStateException( - "File '${fileModel.nameOrId()}' has missing source path and is not set to be skipped." - ) - } - - val flow = getFlowByName(layout, fileModel.nameOrId()) ?: run { - layout.addFlow() - .setName(fileModel.nameOrId()) - .setType(Flow.Type.DIRECT_EXTERNAL) - .setLocation(getFilePath(fileModel)) - } - - return flow - } - - private fun buildCompositeFlow( - layout: Layout, - variableStructure: VariableStructureModel, - documentContentModelParts: List, - flowName: String? = null, - languages: List - ): Flow { - val flow = layout.addFlow().setType(Flow.Type.SIMPLE) - flowName?.let { flow.setName(it) } - - documentContentModelParts.forEach { - when (it) { - is ParagraphModel -> buildParagraph(layout, variableStructure, flow, it, languages) - is TableModel -> flow.addParagraph().addText() - .appendTable(buildTable(layout, variableStructure, it, languages)) - - is ImageModelRef -> buildAndAppendImage(layout, flow.addParagraph().addText(), it) - else -> error("Content part type ${it::class.simpleName} is not allowed in composite flow.") - } - } - - return flow - } - - private fun buildDocumentObjectRef( - layout: Layout, - variableStructure: VariableStructureModel, - documentObjectRef: DocumentObjectModelRef, - languages: List, - ): Flow? { - val documentModel = documentObjectRepository.findModelOrFail(documentObjectRef.id) - - if (documentModel.skip.skipped && documentModel.skip.placeholder == null) { - val reason = documentModel.skip.reason?.let { "with reason: $it" } ?: "without reason" - logger.debug("Document content part ${documentObjectRef.id} is set to be skipped without placeholder $reason.") - return null - } else if (documentModel.skip.skipped && documentModel.skip.placeholder != null) { - val reason = documentModel.skip.reason?.let { "and reason: $it" } ?: "without reason" - logger.debug("Document content part ${documentObjectRef.id} is set to be skipped with placeholder $reason.") - val flow = layout.addFlow().setType(Flow.Type.SIMPLE) - flow.addParagraph().addText().appendText(documentModel.skip.placeholder) - return flow - } - - val flow = getFlowByName(layout, documentModel.nameOrId()) ?: if (documentModel.internal) { - buildDocumentContentAsSingleFlow( - layout, - variableStructure, - documentModel.content, - documentModel.nameOrId(), - documentModel.displayRuleRef, - languages - ) - } else { - layout.addFlow().setName(documentModel.nameOrId()).setType(Flow.Type.DIRECT_EXTERNAL) - .setLocation(getDocumentObjectPath(documentModel)) - } - - if (documentObjectRef.displayRuleRef != null) { - val displayRule = displayRuleRepository.findModelOrFail(documentObjectRef.displayRuleRef.id) - if (displayRule.definition == null) { - error("Display rule '${documentObjectRef.displayRuleRef.id}' definition is null.") - } - - return wrapSuccessFlowInConditionFlow(layout, variableStructure, displayRule.definition, flow) - } - - return flow - } - - private fun gatherFlowParts(content: List, startIndex: Int): List { - val flowParts = mutableListOf() - - var index = startIndex - - do { - val contentPart = content[index] - if (contentPart is TableModel || contentPart is ParagraphModel || contentPart is ImageModelRef) { - flowParts.add(contentPart) - index++ - } else { - break - } - } while (index < content.size) - - return flowParts - } - - private fun buildParagraph( - layout: Layout, - variableStructure: VariableStructureModel, - flow: Flow, - paragraphModel: ParagraphModel, - languages: List - ) { - val paragraph = if (paragraphModel.displayRuleRef == null) { - flow.addParagraph() - } else { - buildSuccessFlowWrappedInInlineConditionFlow( - layout, variableStructure, paragraphModel.displayRuleRef.id, flow.addParagraph().addText() - ).addParagraph() - } - - val paragraphStyle = findParagraphStyle(paragraphModel)?.also { - paragraph.setExistingParagraphStyle("ParagraphStyles.${it.nameOrId()}") - } - - paragraphModel.content.forEach { textModel -> - val baseText = if (textModel.displayRuleRef == null) { - paragraph.addText() - } else { - buildSuccessFlowWrappedInInlineConditionFlow( - layout, variableStructure, textModel.displayRuleRef.id, paragraph.addText() - ).addParagraph().also { - if (paragraphStyle != null) it.setExistingParagraphStyle("ParagraphStyles.${paragraphStyle.nameOrId()}") - }.addText() - } - - val baseTextStyleModel = findTextStyle(textModel) - baseTextStyleModel?.also { baseText.setExistingTextStyle("TextStyles.${it.nameOrId()}") } - - var currentText = baseText - - textModel.content.forEach { - when (it) { - is StringModel -> currentText.appendText(it.value) - is VariableModelRef -> currentText.appendVariable(it, layout, variableStructure) - is TableModel -> currentText.appendTable(buildTable(layout, variableStructure, it, languages)) - is DocumentObjectModelRef -> buildDocumentObjectRef( - layout, variableStructure, it, languages - )?.also { flow -> - currentText.appendFlow(flow) - } - - is FileModelRef -> buildFileRef(layout, it)?.also { flow -> - currentText.appendFlow(flow) - } - - is ImageModelRef -> buildAndAppendImage(layout, currentText, it) - is HyperlinkModel -> currentText = buildAndAppendHyperlink(layout, paragraph, baseTextStyleModel, it) - is FirstMatchModel -> currentText.appendFlow( - buildFirstMatch(layout, variableStructure, it, true, null, languages) - ) - } - } - } - } - - private fun createHyperlinkTextStyle( - layout: Layout, baseTextStyleModel: TextStyleModel?, hyperlinkModel: HyperlinkModel - ): TextStyle { - val baseStyleName = baseTextStyleModel?.nameOrId() ?: "text" - val hyperlinkName = generateUniqueHyperlinkStyleName(layout, baseStyleName) - - val urlVariable = createUrlVariable(layout, hyperlinkName, hyperlinkModel.url) - - val hyperlinkStyle = layout.addTextStyle() - .setName(hyperlinkName) - .setUrlTarget(urlVariable) - .setType(TextStyleType.DELTA) - .setUrlAlternateText(hyperlinkModel.alternateText) - .addInheritFlags( - *TextStyleInheritFlag.entries - .filter { it != TextStyleInheritFlag.UNDERLINE && it != TextStyleInheritFlag.FILL_STYLE } - .toTypedArray()) - (hyperlinkStyle as TextStyleImpl).ancestorId = "Def.TextStyleHyperlink" - - if (baseTextStyleModel != null) { - val definition = baseTextStyleModel.resolve() - applyTextStyleProperties(layout, hyperlinkStyle, definition) - } - - return hyperlinkStyle - } - - private fun generateUniqueHyperlinkStyleName(layout: Layout, baseStyleName: String): String { - var counter = 1 - var candidateName = "${baseStyleName}_url_${counter}" - while (getTextStyleByName(layout, candidateName) != null) { - counter++ - candidateName = "${baseStyleName}_url_${counter}" - } - return candidateName - } - - private fun createUrlVariable(layout: Layout, variableName: String, url: String): Variable { - return layout.data.addVariable().setName(variableName).setKind(VariableKind.CONSTANT) - .setDataType(DataType.STRING).setValue(url) - } - - private fun buildAndAppendImage(layout: Layout, text: Text, ref: ImageModelRef) { - val imageModel = imageRepository.findModelOrFail(ref.id) - - when (val imagePlaceholder = getImagePlaceholder(imageModel)) { - is ImagePlaceholderResult.Placeholder -> { - text.appendText(imagePlaceholder.value) - return - } - is ImagePlaceholderResult.RenderAsNormal -> {} - is ImagePlaceholderResult.Skip -> return - } - - text.appendImage(getOrBuildImage(layout, imageModel, imageModel.alternateText)) - } - - private fun buildAndAppendHyperlink( - layout: Layout, paragraph: Paragraph, baseTextStyleModel: TextStyleModel?, hyperlinkModel: HyperlinkModel - ): Text { - val hyperlinkText = paragraph.addText() - val hyperlinkStyle = createHyperlinkTextStyle(layout, baseTextStyleModel, hyperlinkModel) - hyperlinkText.setTextStyle(hyperlinkStyle) - hyperlinkText.appendText(hyperlinkModel.displayText ?: hyperlinkModel.url) - - val newText = paragraph.addText() - baseTextStyleModel?.also { newText.setExistingTextStyle("TextStyles.${it.nameOrId()}") } - return newText - } - - private fun Text.appendVariable( - ref: VariableModelRef, layout: Layout, variableStructure: VariableStructureModel - ): Text { - val variableModel = variableRepository.findModelOrFail(ref.id) - - val variablePathData = variableStructure.structure[ref] - if (variablePathData == null || variablePathData.path.isBlank()) { - this.appendText("""$${variablePathData?.name ?: variableModel.nameOrId()}$""") - } else { - val variableName = variablePathData.name ?: variableModel.nameOrId() - this.appendVariable(getOrCreateVariable(layout.data, variableName, variableModel, variablePathData.path)) - } - - return this - } - - private fun findParagraphStyle(paragraphModel: ParagraphModel): ParagraphStyleModel? { - if (paragraphModel.styleRef == null) return null - - val paraStyleModel = paragraphStyleRepository.firstWithDefinitionModel(paragraphModel.styleRef.id) - ?: error("Paragraph style definition for ${paragraphModel.styleRef.id} not found.") - - return paraStyleModel - } - - private fun findTextStyle(textModel: TextModel): TextStyleModel? { - if (textModel.styleRef == null) return null - - val textStyleModel = textStyleRepository.firstWithDefinitionModel(textModel.styleRef.id) - ?: error("Text style definition for ${textModel.styleRef.id} not found.") - - return textStyleModel - } - - private fun buildSuccessFlowWrappedInInlineConditionFlow( - layout: Layout, variableStructure: VariableStructureModel, displayRuleId: String, text: Text - ): Flow { - val displayRule = displayRuleRepository.findModelOrFail(displayRuleId) - if (displayRule.definition == null) { - error("Display rule '$displayRuleId' definition is null.") - } - - val successFlow = layout.addFlow().setType(Flow.Type.SIMPLE) - - text.appendFlow( - layout.addFlow().setType(Flow.Type.SELECT_BY_INLINE_CONDITION).addLineForSelectByInlineCondition( - displayRule.definition.toScript(layout, variableStructure, variableRepository::findModelOrFail), - successFlow - ) - ) - - return successFlow - } - - private fun buildTable( - layout: Layout, variableStructure: VariableStructureModel, model: TableModel, languages: List - ): Table { - val table = layout.addTable().setDisplayAsImage(false) - - if (model.columnWidths.isNotEmpty()) { - model.columnWidths.forEach { table.addColumn(it.minWidth.toMeters(), it.percentWidth) } - } else { - val numberOfColumns = model.rows.firstOrNull()?.cells?.size ?: 0 - repeat(numberOfColumns) { table.addColumn() } - } - - val rowset = layout.addRowSet().setType(RowSet.Type.MULTIPLE_ROWS) - table.setRowSet(rowset) - - model.rows.forEach { rowModel -> - val row = if (rowModel.displayRuleRef == null) { - layout.addRowSet().setType(RowSet.Type.SINGLE_ROW).also { rowset.addRowSet(it) } - } else { - val displayRule = displayRuleRepository.findModelOrFail(rowModel.displayRuleRef.id) - if (displayRule.definition == null) { - error("Display rule '${rowModel.displayRuleRef.id}' definition is null.") - } - - buildSuccessRowWrappedInConditionRow( - layout, variableStructure, displayRule.definition, rowset - ) - } - - rowModel.cells.forEach { cellModel -> - val cellContentFlow = buildDocumentContentAsSingleFlow( - layout, variableStructure, cellModel.content, null, null, languages - ) - val cellFlow = if (cellContentFlow.type === Flow.Type.SELECT_BY_INLINE_CONDITION) { - layout.addFlow().setType(Flow.Type.SIMPLE).setSectionFlow(true) - .setWebEditingType(Flow.WebEditingType.SECTION) - .also { it.addParagraph().addText().appendFlow(cellContentFlow) } - } else cellContentFlow - - row.addCell( - layout.addCell().setSpanLeft(cellModel.mergeLeft).setSpanUp(cellModel.mergeUp) - .setFlowToNextPage(true).setFlow(cellFlow) - ) - } - } - - when (model.pdfTaggingRule) { - TablePdfTaggingRule.None -> table.setTablePdfTaggingRule(Table.TablePdfTaggingRule.NONE) - TablePdfTaggingRule.Default -> table.setTablePdfTaggingRule(Table.TablePdfTaggingRule.DEFAULT) - TablePdfTaggingRule.Table -> table.setTablePdfTaggingRule(Table.TablePdfTaggingRule.TABLE) - TablePdfTaggingRule.Artifact -> table.setTablePdfTaggingRule(Table.TablePdfTaggingRule.ARTIFACT) - } - table.setTablePdfAlternateText(model.pdfAlternateText) - - return table - } - - private fun buildFirstMatch( - layout: Layout, - variableStructure: VariableStructureModel, - model: FirstMatchModel, - isInline: Boolean, - flowName: String? = null, - languages: List, - ): Flow { - val firstMatchFlow = layout.addFlow().setType(Flow.Type.SELECT_BY_INLINE_CONDITION) - flowName?.let { firstMatchFlow.setName(it) } - - model.cases.forEachIndexed { i, case -> - val displayRule = displayRuleRepository.findModelOrFail(case.displayRuleRef.id) - if (displayRule.definition == null) { - error("Display rule '${case.displayRuleRef.id}' definition is null.") - } - - val caseName = case.name ?: "Case ${i + 1}" - - val contentFlow = - buildDocumentContentAsSingleFlow(layout, variableStructure, case.content, null, null, languages) - - val caseFlow = - if (isInline) contentFlow else layout.addFlow().setSectionFlow(true).setType(Flow.Type.SIMPLE) - .setWebEditingType(Flow.WebEditingType.SECTION).setDisplayName(caseName) - .also { it.addParagraph().addText().appendFlow(contentFlow) } - - firstMatchFlow.addLineForSelectByInlineCondition( - displayRule.definition.toScript(layout, variableStructure, variableRepository::findModelOrFail), - caseFlow - ) - } - - if (model.default.isNotEmpty()) { - val contentFlow = - buildDocumentContentAsSingleFlow(layout, variableStructure, model.default, null, null, languages) - - val caseFlow = - if (isInline) contentFlow else layout.addFlow().setSectionFlow(true).setType(Flow.Type.SIMPLE) - .setWebEditingType(Flow.WebEditingType.SECTION).setDisplayName("Else Case") - .also { it.addParagraph().addText().appendFlow(contentFlow) } - - firstMatchFlow.setDefaultFlow(caseFlow) - } - - return firstMatchFlow - } - - private fun buildSelectByLanguage( - layout: Layout, - variableStructure: VariableStructureModel, - model: SelectByLanguageModel, - flowName: String?, - languages: List, - ): Flow { - val languageFlow = layout.addFlow().setType(Flow.Type.SELECT_BY_LANGUAGE) - flowName?.let { languageFlow.setName(it) } - - val defaultLanguage = projectConfig.defaultLanguage - - val caseFlows = model.cases.associate { - val caseName = "Case ${it.language}" - val contentFlow = buildDocumentContentAsSingleFlow( - layout, variableStructure, it.content, null, null, languages - ).setDisplayName(caseName) - it.language to contentFlow - } - - var defaultLanguageFlow: Flow? = null - for (language in languages) { - val contentFlow = - caseFlows[language] ?: layout.addFlow().setType(Flow.Type.SIMPLE).setDisplayName("Case $language") - languageFlow.addLineForSelectByInlineCondition(language, contentFlow) - - if (language == defaultLanguage) { - defaultLanguageFlow = contentFlow - } - } - - languageFlow.setDefaultFlow(defaultLanguageFlow ?: layout.addFlow().setType(Flow.Type.SIMPLE)) - - return languageFlow - } - - protected fun List.paragraphIfEmpty(): List { - return this.ifEmpty { - listOf( - ParagraphModel( - listOf(TextModel(listOf(), null, null)), - null, - null - ) - ) - } - } - - private fun TextStyleModel.resolve(): TextStyleDefinitionModel { - return when (this.definition) { - is TextStyleDefinitionModel -> this.definition - is TextStyleModelRef -> { - textStyleRepository.findModel(this.definition.id)?.resolve() ?: error("Invalid text style reference") - } - } - } - - private fun ParagraphStyleModel.resolve(): ParagraphStyleDefinitionModel { - return when (this.definition) { - is ParagraphStyleDefinitionModel -> this.definition - is ParagraphStyleModelRef -> paragraphStyleRepository.findModelOrFail(this.definition.id).resolve() - } - } - - sealed interface ScriptResult { - data class Success(val variableScript: String) : ScriptResult { - override fun toString() = variableScript - } - - data class Failure(val variableName: String) : ScriptResult { - override fun toString() = variableName - } - } -} - -fun DisplayRuleDefinition.toScript( - layout: Layout, variableStructure: VariableStructureModel, findVar: (String) -> VariableModel -): String { - return "return ${this.group.toScript(layout, variableStructure, findVar)};" -} - -fun Group.toScript( - layout: Layout, variableStructure: VariableStructureModel, findVar: (String) -> VariableModel -): String { - val expressions = """(${ - items.joinToString( - separator = " ${operator.toInlineCondition()} ", transform = { - when (it) { - is Binary -> it.toScript(layout, variableStructure, findVar) - is Group -> it.toScript(layout, variableStructure, findVar) - } - }) - })""" - return if (negation) { - "not $expressions" - } else { - expressions - } -} - -fun Binary.toScript( - layout: Layout, variableStructure: VariableStructureModel, findVar: (String) -> VariableModel -): String { - val leftScriptResult = left.toScript(layout, variableStructure, findVar) - val rightScriptResult = right.toScript(layout, variableStructure, findVar) - - val binary = operator.toScript(leftScriptResult, rightScriptResult) - return if (leftScriptResult is Success && rightScriptResult is Success) { - binary - } else { - BinOp.Equals.toScript( - Success("String('${binary.replace("'", "")}')"), Success("String('unmapped')") - ) - } -} - -fun BinOp.toScript(left: ScriptResult, right: ScriptResult): String { - return when (this) { - BinOp.Equals -> "$left==$right" - BinOp.EqualsCaseInsensitive -> "$left.equalCaseInsensitive($right)" - BinOp.NotEquals -> "$left!=$right" - BinOp.NotEqualsCaseInsensitive -> "(not $left.equalCaseInsensitive($right))" - BinOp.GreaterThan -> "$left>$right" - BinOp.GreaterOrEqualThan -> "$left>=$right" - BinOp.LessThan -> "$left<$right" - BinOp.LessOrEqualThen -> "$left<=$right" - } -} - -fun LiteralOrFunctionCall.toScript( - layout: Layout, variableStructure: VariableStructureModel, findVar: (String) -> VariableModel -): ScriptResult { - return when (this) { - is Literal -> this.toScript(layout, variableStructure, findVar) - is Function -> this.toScript(layout, variableStructure, findVar) - } -} - -fun Function.toScript( - layout: Layout, variableStructure: VariableStructureModel, findVar: (String) -> VariableModel -): ScriptResult { - when (this) { - is Function.UpperCase -> { - val arg = args[0] - return Success("(${arg.toScript(layout, variableStructure, findVar)}).toUpperCase()") - } - - is Function.LowerCase -> { - val arg = args[0] - return Success("(${arg.toScript(layout, variableStructure, findVar)}).toLowerCase()") - } - } -} - -fun Literal.toScript( - layout: Layout, variableStructure: VariableStructureModel, findVar: (String) -> VariableModel -): ScriptResult { - return when (dataType) { - LiteralDataType.Variable -> variableToScript(value, layout, variableStructure, findVar) - LiteralDataType.String -> Success( - "String('${ - value.replace("\\", "\\\\").replace("\"", "\\\"") - }')" - ) - - LiteralDataType.Number -> Success(value) - LiteralDataType.Boolean -> Success(value.lowercase().toBooleanStrict().toString()) - } -} - -fun variableToScript( - id: String, layout: Layout, variableStructure: VariableStructureModel, findVar: (String) -> VariableModel -): ScriptResult { - val variableModel = findVar(id) - val variablePathData = variableStructure.structure[VariableModelRef(id)] - return if (variablePathData == null || variablePathData.path.isBlank()) { - Failure(variablePathData?.name ?: variableModel.nameOrId()) - } else { - val variableName = variablePathData.name ?: variableModel.nameOrId() - - getOrCreateVariable(layout.data, variableName, variableModel, variablePathData.path) - - Success((variablePathData.path.split(".") + variableName).joinToString(".") { pathPart -> - when (pathPart.lowercase()) { - "value" -> "Current" - "data" -> "DATA" - else -> sanitizeVariablePart(if (pathPart.first().isDigit()) "_$pathPart" else pathPart) - } - }) - } -} - -fun getOrCreateVariable( - data: Data, variableName: String, variableModel: VariableModel, variablePath: String -): Variable { - val variable = getVariable(data as DataImpl, variableName, variablePath) - return variable ?: data.addVariable().setName(variableName).setKind(VariableKind.DISCONNECTED) - .setDataType(getDataType(variableModel.dataType)).setExistingParentId(variablePath) - .setValueIfAvailable(variableModel) -} - -fun Variable.setValueIfAvailable(variableModel: VariableModel): Variable { - if (!variableModel.defaultValue.isNullOrBlank()) { - when (variableModel.dataType) { - DataTypeModel.String, DataTypeModel.DateTime -> this.setValue(variableModel.defaultValue) - DataTypeModel.Integer -> this.setValue(variableModel.defaultValue.toInt()) - DataTypeModel.Integer64 -> this.setValue(variableModel.defaultValue.toLong()) - DataTypeModel.Double, DataTypeModel.Currency -> this.setValue(variableModel.defaultValue.toDouble()) - DataTypeModel.Boolean -> this.setValue( - variableModel.defaultValue.lowercase().toBooleanStrict() - ) - } - } - - return this +package com.quadient.migration.service.inspirebuilder + +import com.quadient.migration.api.ProjectConfig +import com.quadient.migration.api.dto.migrationmodel.Area +import com.quadient.migration.api.dto.migrationmodel.CustomFieldMap +import com.quadient.migration.api.dto.migrationmodel.DisplayRule +import com.quadient.migration.api.dto.migrationmodel.DisplayRuleRef +import com.quadient.migration.api.dto.migrationmodel.DocumentContent +import com.quadient.migration.api.dto.migrationmodel.DocumentObject +import com.quadient.migration.api.dto.migrationmodel.DocumentObjectRef +import com.quadient.migration.api.dto.migrationmodel.File +import com.quadient.migration.api.dto.migrationmodel.FileRef +import com.quadient.migration.api.dto.migrationmodel.FirstMatch +import com.quadient.migration.api.dto.migrationmodel.Hyperlink +import com.quadient.migration.api.dto.migrationmodel.Image +import com.quadient.migration.api.dto.migrationmodel.ImageRef +import com.quadient.migration.api.dto.migrationmodel.Paragraph +import com.quadient.migration.api.dto.migrationmodel.Paragraph.Text +import com.quadient.migration.api.dto.migrationmodel.ParagraphStyleDefinition +import com.quadient.migration.api.dto.migrationmodel.ParagraphStyleRef +import com.quadient.migration.api.dto.migrationmodel.SelectByLanguage +import com.quadient.migration.api.dto.migrationmodel.StringValue +import com.quadient.migration.api.dto.migrationmodel.Table as TableDTO +import com.quadient.migration.api.dto.migrationmodel.TextStyleDefinition +import com.quadient.migration.api.dto.migrationmodel.TextStyleRef +import com.quadient.migration.api.dto.migrationmodel.Variable +import com.quadient.migration.api.dto.migrationmodel.VariableRef +import com.quadient.migration.api.dto.migrationmodel.VariableStructure +import com.quadient.migration.persistence.repository.DisplayRuleInternalRepository +import com.quadient.migration.persistence.repository.DocumentObjectInternalRepository +import com.quadient.migration.persistence.repository.FileInternalRepository +import com.quadient.migration.persistence.repository.ImageInternalRepository +import com.quadient.migration.persistence.repository.ParagraphStyleInternalRepository +import com.quadient.migration.persistence.repository.TextStyleInternalRepository +import com.quadient.migration.persistence.repository.VariableInternalRepository +import com.quadient.migration.persistence.repository.VariableStructureInternalRepository +import com.quadient.migration.service.inspirebuilder.InspireDocumentObjectBuilder.FlowModel.* +import com.quadient.migration.service.inspirebuilder.InspireDocumentObjectBuilder.ScriptResult +import com.quadient.migration.service.inspirebuilder.InspireDocumentObjectBuilder.ScriptResult.* +import com.quadient.migration.service.ipsclient.IpsService +import com.quadient.migration.shared.Alignment +import com.quadient.migration.shared.BinOp +import com.quadient.migration.shared.Binary +import com.quadient.migration.shared.DisplayRuleDefinition +import com.quadient.migration.shared.DocumentObjectType +import com.quadient.migration.shared.FileType +import com.quadient.migration.shared.Function +import com.quadient.migration.shared.Group +import com.quadient.migration.shared.IcmPath +import com.quadient.migration.shared.ImageType +import com.quadient.migration.shared.LineSpacing +import com.quadient.migration.shared.Literal +import com.quadient.migration.shared.LiteralDataType +import com.quadient.migration.shared.LiteralOrFunctionCall +import com.quadient.migration.shared.ParagraphPdfTaggingRule as ParagraphPdfTaggingRuleModel +import com.quadient.migration.shared.SuperOrSubscript +import com.quadient.migration.shared.TabType +import com.quadient.wfdxml.WfdXmlBuilder +import com.quadient.wfdxml.api.layoutnodes.Flow +import com.quadient.wfdxml.api.layoutnodes.Font +import com.quadient.wfdxml.api.layoutnodes.Image as WfdXmlImage +import com.quadient.wfdxml.api.layoutnodes.LocationType +import com.quadient.wfdxml.api.layoutnodes.Pages +import com.quadient.wfdxml.api.layoutnodes.ParagraphStyle +import com.quadient.wfdxml.api.layoutnodes.ParagraphStyle.LineSpacingType.* +import com.quadient.wfdxml.api.layoutnodes.TabulatorType +import com.quadient.wfdxml.api.layoutnodes.data.Data +import com.quadient.wfdxml.api.layoutnodes.data.DataType +import com.quadient.wfdxml.api.layoutnodes.data.Variable as WfdXmlVariable +import com.quadient.wfdxml.api.layoutnodes.data.VariableKind +import com.quadient.wfdxml.api.layoutnodes.flow.Text as WfdXmlText +import com.quadient.wfdxml.api.layoutnodes.font.SubFont +import com.quadient.wfdxml.api.layoutnodes.tables.GeneralRowSet +import com.quadient.wfdxml.api.layoutnodes.tables.RowSet +import com.quadient.wfdxml.api.layoutnodes.tables.Table as WfdXmlTable +import com.quadient.migration.shared.TablePdfTaggingRule +import com.quadient.wfdxml.api.layoutnodes.ParagraphStyle.ParagraphPdfTaggingRule +import com.quadient.wfdxml.api.layoutnodes.TextStyle +import com.quadient.wfdxml.api.layoutnodes.TextStyleInheritFlag +import com.quadient.wfdxml.api.layoutnodes.TextStyleType +import com.quadient.wfdxml.api.layoutnodes.flow.Paragraph as WfdXmlParagraph +import com.quadient.wfdxml.api.module.Layout +import com.quadient.wfdxml.internal.data.WorkFlowTreeDefinition +import com.quadient.wfdxml.internal.layoutnodes.TextStyleImpl +import com.quadient.wfdxml.internal.layoutnodes.data.DataImpl +import com.quadient.wfdxml.internal.layoutnodes.data.WorkFlowTreeEnums.NodeOptionality +import com.quadient.wfdxml.internal.layoutnodes.data.WorkFlowTreeEnums.NodeType.SUB_TREE +import kotlinx.datetime.Clock +import org.slf4j.LoggerFactory +import java.util.concurrent.ConcurrentHashMap +import kotlin.collections.ifEmpty +import com.quadient.migration.shared.DataType as DataTypeModel +import com.quadient.migration.api.dto.migrationmodel.ParagraphStyle as ParagraphStyleDTO +import com.quadient.migration.api.dto.migrationmodel.TextStyle as TextStyleDTO + +abstract class InspireDocumentObjectBuilder( + protected val documentObjectRepository: DocumentObjectInternalRepository, + protected val textStyleRepository: TextStyleInternalRepository, + protected val paragraphStyleRepository: ParagraphStyleInternalRepository, + protected val variableRepository: VariableInternalRepository, + protected val variableStructureRepository: VariableStructureInternalRepository, + protected val displayRuleRepository: DisplayRuleInternalRepository, + protected val imageRepository: ImageInternalRepository, + protected val fileRepository: FileInternalRepository, + protected val projectConfig: ProjectConfig, + protected val ipsService: IpsService, +) { + protected val logger = LoggerFactory.getLogger(this::class.java)!! + + protected val fontDataCache = ConcurrentHashMap() + + abstract fun getDocumentObjectPath(nameOrId: String, type: DocumentObjectType, targetFolder: IcmPath?): String + + abstract fun getDocumentObjectPath(documentObject: DocumentObject): String + + abstract fun getImagePath( + id: String, imageType: ImageType, name: String?, targetFolder: IcmPath?, sourcePath: String? + ): String + + abstract fun getImagePath(image: Image): String + + abstract fun getFilePath( + id: String, name: String?, targetFolder: IcmPath?, sourcePath: String?, fileType: FileType + ): String + + abstract fun getFilePath(file: File): String + + abstract fun getStyleDefinitionPath(extension: String = "wfd"): String + + abstract fun getFontRootFolder(): String + + abstract fun buildDocumentObject(documentObject: DocumentObject, styleDefinitionPath: String?): String + + abstract fun shouldIncludeInternalDependency(documentObject: DocumentObject): Boolean + + protected fun collectLanguages(documentObject: DocumentObject): List { + val languages = mutableSetOf() + + fun collectLanguagesFromContent(content: List) { + for (item in content) { + when (item) { + is SelectByLanguage -> item.cases.forEach { languages.add(it.language) } + is Area -> collectLanguagesFromContent(item.content) + is FirstMatch -> { + item.cases.forEach { case -> collectLanguagesFromContent(case.content) } + collectLanguagesFromContent(item.default) + } + + is TableDTO -> item.rows.forEach { row -> + row.cells.forEach { cell -> collectLanguagesFromContent(cell.content) } + } + + is DocumentObjectRef -> { + val documentObject = documentObjectRepository.findModelOrFail(item.id) + if (shouldIncludeInternalDependency(documentObject)) { + collectLanguagesFromContent(documentObject.content) + } + } + + is Paragraph -> item.content.forEach { textModel -> + textModel.content.forEach { textContent -> + when (textContent) { + is FirstMatch -> { + textContent.cases.forEach { case -> collectLanguagesFromContent(case.content) } + collectLanguagesFromContent(textContent.default) + } + + is TableDTO -> textContent.rows.forEach { row -> + row.cells.forEach { cell -> collectLanguagesFromContent(cell.content) } + } + + is DocumentObjectRef -> { + val documentObject = documentObjectRepository.findModelOrFail(textContent.id) + if (shouldIncludeInternalDependency(documentObject)) { + collectLanguagesFromContent(documentObject.content) + } + } + + else -> {} + } + } + } + + else -> {} + } + } + } + + collectLanguagesFromContent(documentObject.content) + + return languages.toList() + } + + protected open fun wrapSuccessFlowInConditionFlow( + layout: Layout, variableStructure: VariableStructure, ruleDef: DisplayRuleDefinition, successFlow: Flow + ): Flow { + return layout.addFlow().setType(Flow.Type.SELECT_BY_CONDITION).addLineForSelectByCondition( + layout.data.addVariable().setKind(VariableKind.CALCULATED).setDataType(DataType.BOOL) + .setScript(ruleDef.toScript(layout, variableStructure, variableRepository::findModelOrFail)), + successFlow + ) + } + + protected open fun buildSuccessRowWrappedInConditionRow( + layout: Layout, + variableStructure: VariableStructure, + ruleDef: DisplayRuleDefinition, + multipleRowSet: GeneralRowSet + ): GeneralRowSet { + val successRow = layout.addRowSet().setType(RowSet.Type.SINGLE_ROW) + + multipleRowSet.addRowSet( + layout.addRowSet().setType(RowSet.Type.SELECT_BY_CONDITION).addLineForSelectByCondition( + layout.data.addVariable().setKind(VariableKind.CALCULATED).setDataType(DataType.BOOL) + .setScript(ruleDef.toScript(layout, variableStructure, variableRepository::findModelOrFail)), + successRow + ) + ) + + return successRow + } + + fun buildStyleLayoutDelta(textStyles: List, paragraphStyles: List): String { + logger.debug("Starting to build style layout delta.") + + val builder = WfdXmlBuilder() + val layout = builder.addLayout() + + if (fontDataCache.isEmpty()) { + val fontDataString = ipsService.gatherFontData(getFontRootFolder()) + fontDataCache.putAll(fontDataStringToMap(fontDataString)) + } + + buildTextStyles(layout, textStyles) + buildParagraphStyles(layout, paragraphStyles) + + logger.debug("Successfully built style layout delta.") + return builder.buildStyleLayoutDelta() + } + + fun buildStyles( + textStyles: List, + paragraphStyles: List, + ): String { + logger.debug("Starting to build style definition.") + + val builder = WfdXmlBuilder() + val layout = builder.addLayout() + + layout.setName("DocumentLayout") + val flow = layout.addFlow().setSectionFlow(true).setWebEditingType(Flow.WebEditingType.SECTION) + layout.pages.setMainFlow(flow) + layout.addPage().setName("Page 1").setType(Pages.PageConditionType.SIMPLE) + layout.addRoot().setAllowRuntimeModifications(true) + + if (fontDataCache.isEmpty()) { + val fontDataString = ipsService.gatherFontData(getFontRootFolder()) + fontDataCache.putAll(fontDataStringToMap(fontDataString)) + } + + buildTextStyles(layout, textStyles) + buildParagraphStyles(layout, paragraphStyles) + + logger.debug("Successfully built style definition.") + return builder.build() + } + + fun buildDocumentContentAsFlows( + layout: Layout, + variableStructure: VariableStructure, + content: List, + flowName: String? = null, + languages: List, + ): List { + val mutableContent = content.toMutableList() + + var idx = 0 + val flowModels = mutableListOf() + while (idx < mutableContent.size) { + when (val contentPart = mutableContent[idx]) { + is TableDTO, is Paragraph, is ImageRef -> { + val flowParts = gatherFlowParts(mutableContent, idx) + idx += flowParts.size - 1 + flowModels.add(Composite(flowParts)) + } + + is DocumentObjectRef -> flowModels.add(DocumentObject(contentPart)) + is FileRef -> flowModels.add(File(contentPart)) + is Area -> mutableContent.addAll(idx + 1, contentPart.content) + is FirstMatch -> flowModels.add(FirstMatch(contentPart)) + is SelectByLanguage -> flowModels.add(SelectByLanguage(contentPart)) + } + idx++ + } + + val flowCount = flowModels.size + var flowSuffix = 1 + return flowModels.mapNotNull { + when (it) { + is FlowModel.DocumentObject -> buildDocumentObjectRef(layout, variableStructure, it.ref, languages) + is FlowModel.File -> buildFileRef(layout, it.ref) + is FlowModel.Composite -> { + if (flowName == null) { + buildCompositeFlow(layout, variableStructure, it.parts, null, languages) + } else { + val name = if (flowCount == 1) flowName else "$flowName $flowSuffix" + flowSuffix++ + buildCompositeFlow(layout, variableStructure, it.parts, name, languages) + } + } + + is FlowModel.FirstMatch -> { + if (flowName == null) { + buildFirstMatch(layout, variableStructure, it.model, false, null, languages) + } else { + val name = if (flowCount == 1) flowName else "$flowName $flowSuffix" + flowSuffix++ + buildFirstMatch(layout, variableStructure, it.model, false, name, languages) + } + } + + is FlowModel.SelectByLanguage -> { + if (flowName == null) { + buildSelectByLanguage(layout, variableStructure, it.model, null, languages) + } else { + val name = if (flowCount == 1) flowName else "$flowName $flowSuffix" + flowSuffix++ + buildSelectByLanguage(layout, variableStructure, it.model, name, languages) + } + } + } + } + } + + sealed interface FlowModel { + data class Composite(val parts: List) : FlowModel + data class DocumentObject(val ref: DocumentObjectRef) : FlowModel + data class File(val ref: FileRef) : FlowModel + data class FirstMatch(val model: com.quadient.migration.api.dto.migrationmodel.FirstMatch) : FlowModel + data class SelectByLanguage(val model: com.quadient.migration.api.dto.migrationmodel.SelectByLanguage) : FlowModel + } + + protected fun List.toSingleFlow( + layout: Layout, + variableStructure: VariableStructure, + flowName: String? = null, + displayRuleRef: DisplayRuleRef? = null, + ): Flow { + val singleFlow = if (this.size == 1) { + this[0] + } else { + val sectionFlow = layout.addFlow().setType(Flow.Type.SIMPLE).setSectionFlow(true) + flowName?.let { sectionFlow.setName(it) } + + val sectionFlowText = sectionFlow.addParagraph().addText() + + this.forEach { sectionFlowText.appendFlow(it) } + + sectionFlow + } + + return if (displayRuleRef == null) { + singleFlow + } else { + val displayRule = displayRuleRepository.findModelOrFail(displayRuleRef.id) + val def = displayRule.definition + if (def == null) { + error("Display rule '${displayRuleRef.id}' definition is null.") + } + + wrapSuccessFlowInConditionFlow(layout, variableStructure, def, singleFlow) + } + } + + protected fun buildDocumentContentAsSingleFlow( + layout: Layout, + variableStructure: VariableStructure, + content: List, + flowName: String? = null, + displayRuleRef: DisplayRuleRef? = null, + languages: List, + ): Flow { + return buildDocumentContentAsFlows(layout, variableStructure, content, flowName, languages).toSingleFlow( + layout, variableStructure, flowName, displayRuleRef + ) + } + + protected fun initVariableStructure(layout: Layout, documentObject: DocumentObject): VariableStructure { + val variableStructureId = documentObject.variableStructureRef?.id ?: projectConfig.defaultVariableStructure + + val variableStructureModel = + variableStructureId?.let { variableStructureRepository.findModelOrFail(it) } ?: VariableStructure( + id = "defaultVariableStructure", + lastUpdated = Clock.System.now(), + created = Clock.System.now(), + structure = mutableMapOf(), + customFields = CustomFieldMap(), + languageVariable = null, + ) + + val normalizedVariablePaths = variableStructureModel.structure.map { (_, variablePathData) -> + removeDataFromVariablePath(variablePathData.path) + }.filter { it.isNotBlank() } + + val variableTree = buildVariableTree(normalizedVariablePaths) + + val workflowTreeDefinition = WorkFlowTreeDefinition("Root", SUB_TREE, NodeOptionality.ARRAY).also { + buildVariablePathPart(it, variableTree) + } + + val layoutData = layout.data + layoutData.importDataDefinition(workflowTreeDefinition) + if (variableTree.isNotEmpty() && variableTree.values.first() is ArrayVariable) { + layoutData.setRepeatedBy("Data.${variableTree.keys.first()}") + } + + return variableStructureModel + } + + private fun buildVariablePathPart( + parentNode: WorkFlowTreeDefinition, currentMap: Map + ) { + currentMap.forEach { + val variablePathPart = it.value + val optionality = + if (variablePathPart is ArrayVariable) NodeOptionality.ARRAY else NodeOptionality.MUST_EXIST + + val node = WorkFlowTreeDefinition(variablePathPart.name, SUB_TREE, optionality) + parentNode.addSubNode(node) + + if (variablePathPart.children.isNotEmpty()) { + buildVariablePathPart(node, variablePathPart.children) + } + } + } + + private fun upsertSubFont(font: Font, isBold: Boolean, isItalic: Boolean): SubFont? { + val subFontName = buildFontName(isBold, isItalic) + + val fontLocation = fontDataCache[FontKey(font.name, subFontName)] + ?: fontDataCache[FontKey(font.name, buildFontName(bold = false, italic = false))] + ?: return null + + font.subFonts.removeAll { it.name == subFontName } + return font.addSubfont().setName(subFontName).setBold(isBold).setItalic(isItalic) + .setLocation(fontLocation, LocationType.ICM) + } + + fun buildTextStyles(layout: Layout, textStyleModels: List) { + val arialFont = getFontByName(layout, "Arial") + require(arialFont != null) { "Layout must contain Arial font." } + arialFont.setName("Arial").setFontName("Arial") + upsertSubFont(arialFont, isBold = false, isItalic = false) + + textStyleModels.forEach { styleModel -> + val definition = styleModel.resolve() + val textStyle = layout.addTextStyle().setName(styleModel.nameOrId()) + applyTextStyleProperties(layout, textStyle, definition) + } + } + + private fun applyTextStyleProperties(layout: Layout, textStyle: TextStyle, definition: TextStyleDefinition) { + val fontFamily = definition.fontFamily ?: "Arial" + + val font = getFontByName(layout, fontFamily) ?: layout.addFont().setName(fontFamily).setFontName(fontFamily) + textStyle.setFont(font) + + val subFont = upsertSubFont(font, definition.bold, definition.italic) + if (subFont != null) { + textStyle.setSubFont(subFont) + } + + textStyle.setBold(definition.bold) + textStyle.seItalic(definition.italic) + textStyle.setUnderline(definition.underline) + textStyle.setStrikeThrough(definition.strikethrough) + + definition.size?.let { textStyle.setFontSizeInMeters(it.toMeters()) } + definition.interspacing?.let { textStyle.setInterSpacing(it.toMeters()) } + + when (definition.superOrSubscript) { + SuperOrSubscript.Subscript -> textStyle.setSubScript(true).setSuperScript(false) + SuperOrSubscript.Superscript -> textStyle.setSubScript(false).setSuperScript(true) + SuperOrSubscript.None -> textStyle.setSubScript(false).setSuperScript(false) + } + + definition.foregroundColor?.let { colorModel -> + val layoutColor = getColorByRGB(layout, colorModel.red(), colorModel.green(), colorModel.blue()) + ?: layout.addColor().setRGB(colorModel.red(), colorModel.green(), colorModel.blue()) + val fillStyle = getFillStyleByColor(layout, layoutColor) + ?: layout.addFillStyle().setColor(layoutColor) + textStyle.setFillStyle(fillStyle) + } + } + + fun buildParagraphStyles(layout: Layout, paragraphStyleModels: List) { + paragraphStyleModels.forEach { styleModel -> + val definition = styleModel.resolve() + + val paragraphStyle = layout.addParagraphStyle().setName(styleModel.nameOrId()) + + definition.leftIndent?.let { paragraphStyle.setLeftIndent(it.toMeters()) } + definition.rightIndent?.let { paragraphStyle.setRightIndent(it.toMeters()) } + definition.defaultTabSize?.let { paragraphStyle.setDefaultTabSize(it.toMeters()) } + definition.spaceBefore?.let { paragraphStyle.setSpaceBefore(it.toMeters()) } + definition.spaceAfter?.let { paragraphStyle.setSpaceAfter(it.toMeters()) } + val alignType = when (definition.alignment) { + Alignment.Left -> ParagraphStyle.AlignType.LEFT + Alignment.Right -> ParagraphStyle.AlignType.RIGHT + Alignment.Center -> ParagraphStyle.AlignType.CENTER + Alignment.JustifyLeft -> ParagraphStyle.AlignType.JUSTIFY_lEFT + Alignment.JustifyRight -> ParagraphStyle.AlignType.JUSTIFY_RIGHT + Alignment.JustifyCenter -> ParagraphStyle.AlignType.JUSTIFY_CENTER + Alignment.JustifyBlock -> ParagraphStyle.AlignType.JUSTIFY_BLOCK + Alignment.JustifyWithMargins -> ParagraphStyle.AlignType.JUSTIFY_WITH_MARGIN + Alignment.JustifyBlockUniform -> ParagraphStyle.AlignType.JUSTIFY_BLOCK_UNIFORM + } + paragraphStyle.setAlignType(alignType) + + definition.firstLineIndent?.let { paragraphStyle.setFirstLineLeftIndent(it.toMeters()) } + + val lineSpacing = definition.lineSpacing + val (lineSpacingType, lineSpacingValue) = when (lineSpacing) { + is LineSpacing.Additional -> Pair(ADDITIONAL, lineSpacing.size?.toMeters()) + is LineSpacing.AtLeast -> Pair(AT_LEAST, lineSpacing.size?.toMeters()) + is LineSpacing.Exact -> Pair(EXACT, lineSpacing.size?.toMeters()) + is LineSpacing.ExactFromPrevious -> Pair(EXACT_FROM_PREVIOUS, lineSpacing.size?.toMeters()) + is LineSpacing.ExactFromPreviousWithAdjust -> Pair( + EXACT_FROM_PREVIOUS_WITH_ADJUST, lineSpacing.size?.toMeters() + ) + + is LineSpacing.ExactFromPreviousWithAdjustLegacy -> Pair( + EXACT_FROM_PREVIOUS_WITH_ADJUST_OLD, lineSpacing.size?.toMeters() + ) + + is LineSpacing.MultipleOf -> Pair(MULTIPLE_OF, lineSpacing.value) + } + paragraphStyle.setLineSpacingType(lineSpacingType) + lineSpacingValue?.let { paragraphStyle.setLineSpacingValue(it) } + + definition.tabs?.let { tabsModel -> + paragraphStyle.setUseOutsideTabs(tabsModel.useOutsideTabs) + tabsModel.tabs.forEach { tabModel -> + val tabType = when (tabModel.type) { + TabType.Left -> TabulatorType.LEFT + TabType.Right -> TabulatorType.RIGHT + TabType.Center -> TabulatorType.CENTER + TabType.DecimalWord -> TabulatorType.WORD_DECIMAL + TabType.Decimal -> TabulatorType.DECIMAL + } + + paragraphStyle.addTabulator(tabModel.position.toMeters(), tabType) + } + } + + definition.pdfTaggingRule?.let { pdfTaggingRule -> + val rule = when (pdfTaggingRule) { + ParagraphPdfTaggingRuleModel.Paragraph -> ParagraphPdfTaggingRule.PARAGRAPH + ParagraphPdfTaggingRuleModel.Heading -> ParagraphPdfTaggingRule.HEADING + ParagraphPdfTaggingRuleModel.Heading1 -> ParagraphPdfTaggingRule.HEADING_1 + ParagraphPdfTaggingRuleModel.Heading2 -> ParagraphPdfTaggingRule.HEADING_2 + ParagraphPdfTaggingRuleModel.Heading3 -> ParagraphPdfTaggingRule.HEADING_3 + ParagraphPdfTaggingRuleModel.Heading4 -> ParagraphPdfTaggingRule.HEADING_4 + ParagraphPdfTaggingRuleModel.Heading5 -> ParagraphPdfTaggingRule.HEADING_5 + ParagraphPdfTaggingRuleModel.Heading6 -> ParagraphPdfTaggingRule.HEADING_6 + } + paragraphStyle.setPdfTaggingRule(rule) + } + } + } + + sealed interface ImagePlaceholderResult { + object RenderAsNormal : ImagePlaceholderResult + object Skip : ImagePlaceholderResult + data class Placeholder(val value: String) : ImagePlaceholderResult + } + protected fun getImagePlaceholder(imageModel: Image): ImagePlaceholderResult { + if (imageModel.imageType == ImageType.Unknown && !imageModel.skip.skipped) { + throw IllegalStateException( + "Image '${imageModel.nameOrId()}' has unknown type and is not set to be skipped." + ) + } + if (imageModel.sourcePath.isNullOrBlank() && !imageModel.skip.skipped) { + throw IllegalStateException( + "Image '${imageModel.nameOrId()}' has missing source path and is not set to be skipped." + ) + } + + if (imageModel.skip.skipped && imageModel.skip.placeholder != null) { + return ImagePlaceholderResult.Placeholder(imageModel.skip.placeholder) + } else if (imageModel.skip.skipped) { + return ImagePlaceholderResult.Skip + } + + return ImagePlaceholderResult.RenderAsNormal + } + + protected fun getOrBuildImage(layout: Layout, imageModel: Image, alternateText: String? = null): WfdXmlImage { + val image = getImageByName(layout, imageModel.nameOrId()) ?: layout.addImage().setName(imageModel.nameOrId()) + .setImageLocation(getImagePath(imageModel), LocationType.ICM) + + val options = imageModel.options + if (options != null) { + options.resizeWidth?.let { image.setResizeWidth(it.toMeters()) } + options.resizeHeight?.let { image.setResizeHeight(it.toMeters()) } + } + + if (!alternateText.isNullOrBlank()) { + applyImageAlternateText(layout, imageModel, alternateText) + } + + return image + } + + protected abstract fun applyImageAlternateText(layout: Layout, image: Image, alternateText: String) + + private fun buildFileRef( + layout: Layout, + fileRef: FileRef, + ): Flow? { + val fileModel = fileRepository.findModelOrFail(fileRef.id) + + if (fileModel.skip.skipped && fileModel.skip.placeholder == null) { + val reason = fileModel.skip.reason?.let { "with reason: $it" } ?: "without reason" + logger.debug("File ${fileRef.id} is set to be skipped without placeholder $reason.") + return null + } else if (fileModel.skip.skipped && fileModel.skip.placeholder != null) { + val reason = fileModel.skip.reason?.let { "and reason: $it" } ?: "without reason" + logger.debug("File ${fileRef.id} is set to be skipped with placeholder $reason.") + val flow = layout.addFlow().setType(Flow.Type.SIMPLE) + flow.addParagraph().addText().appendText(fileModel.skip.placeholder) + return flow + } + + if (fileModel.sourcePath.isNullOrBlank()) { + throw IllegalStateException( + "File '${fileModel.nameOrId()}' has missing source path and is not set to be skipped." + ) + } + + val flow = getFlowByName(layout, fileModel.nameOrId()) ?: run { + layout.addFlow() + .setName(fileModel.nameOrId()) + .setType(Flow.Type.DIRECT_EXTERNAL) + .setLocation(getFilePath(fileModel)) + } + + return flow + } + + private fun buildCompositeFlow( + layout: Layout, + variableStructure: VariableStructure, + documentContentModelParts: List, + flowName: String? = null, + languages: List + ): Flow { + val flow = layout.addFlow().setType(Flow.Type.SIMPLE) + flowName?.let { flow.setName(it) } + + documentContentModelParts.forEach { + when (it) { + is Paragraph -> buildParagraph(layout, variableStructure, flow, it, languages) + is TableDTO -> flow.addParagraph().addText() + .appendTable(buildTable(layout, variableStructure, it, languages)) + + is ImageRef -> buildAndAppendImage(layout, flow.addParagraph().addText(), it) + else -> error("Content part type ${it::class.simpleName} is not allowed in composite flow.") + } + } + + return flow + } + + private fun buildDocumentObjectRef( + layout: Layout, + variableStructure: VariableStructure, + documentObjectRef: DocumentObjectRef, + languages: List, + ): Flow? { + val documentModel = documentObjectRepository.findModelOrFail(documentObjectRef.id) + + if (documentModel.skip.skipped && documentModel.skip.placeholder == null) { + val reason = documentModel.skip.reason?.let { "with reason: $it" } ?: "without reason" + logger.debug("Document content part ${documentObjectRef.id} is set to be skipped without placeholder $reason.") + return null + } else if (documentModel.skip.skipped && documentModel.skip.placeholder != null) { + val reason = documentModel.skip.reason?.let { "and reason: $it" } ?: "without reason" + logger.debug("Document content part ${documentObjectRef.id} is set to be skipped with placeholder $reason.") + val flow = layout.addFlow().setType(Flow.Type.SIMPLE) + flow.addParagraph().addText().appendText(documentModel.skip.placeholder) + return flow + } + + val flow = getFlowByName(layout, documentModel.nameOrId()) ?: if (documentModel.internal == true) { + buildDocumentContentAsSingleFlow( + layout, + variableStructure, + documentModel.content, + documentModel.nameOrId(), + documentModel.displayRuleRef?.let { DisplayRuleRef(it.id) }, + languages + ) + } else { + layout.addFlow().setName(documentModel.nameOrId()).setType(Flow.Type.DIRECT_EXTERNAL) + .setLocation(getDocumentObjectPath(documentModel)) + } + + if (documentObjectRef.displayRuleRef != null) { + val displayRule = displayRuleRepository.findModelOrFail(documentObjectRef.displayRuleRef.id) + val def = displayRule.definition + if (def == null) { + error("Display rule '${documentObjectRef.displayRuleRef.id}' definition is null.") + } + + return wrapSuccessFlowInConditionFlow(layout, variableStructure, def, flow) + } + + return flow + } + + private fun gatherFlowParts(content: List, startIndex: Int): List { + val flowParts = mutableListOf() + + var index = startIndex + + do { + val contentPart = content[index] + if (contentPart is TableDTO || contentPart is Paragraph || contentPart is ImageRef) { + flowParts.add(contentPart) + index++ + } else { + break + } + } while (index < content.size) + + return flowParts + } + + private fun buildParagraph( + layout: Layout, + variableStructure: VariableStructure, + flow: Flow, + paragraphModel: Paragraph, + languages: List + ) { + val paragraph = if (paragraphModel.displayRuleRef == null) { + flow.addParagraph() + } else { + buildSuccessFlowWrappedInInlineConditionFlow( + layout, variableStructure, paragraphModel.displayRuleRef.id, flow.addParagraph().addText() + ).addParagraph() + } + + val paragraphStyle = findParagraphStyle(paragraphModel)?.also { + paragraph.setExistingParagraphStyle("ParagraphStyles.${it.nameOrId()}") + } + + paragraphModel.content.forEach { textModel -> + val baseText = if (textModel.displayRuleRef == null) { + paragraph.addText() + } else { + buildSuccessFlowWrappedInInlineConditionFlow( + layout, variableStructure, textModel.displayRuleRef.id, paragraph.addText() + ).addParagraph().also { + if (paragraphStyle != null) it.setExistingParagraphStyle("ParagraphStyles.${paragraphStyle.nameOrId()}") + }.addText() + } + + val baseTextStyleModel = findTextStyle(textModel) + baseTextStyleModel?.also { baseText.setExistingTextStyle("TextStyles.${it.nameOrId()}") } + + var currentText = baseText + + textModel.content.forEach { + when (it) { + is StringValue -> currentText.appendText(it.value) + is VariableRef -> currentText.appendVariable(it, layout, variableStructure) + is TableDTO -> currentText.appendTable(buildTable(layout, variableStructure, it, languages)) + is DocumentObjectRef -> buildDocumentObjectRef( + layout, variableStructure, it, languages + )?.also { flow -> + currentText.appendFlow(flow) + } + + is FileRef -> buildFileRef(layout, it)?.also { flow -> + currentText.appendFlow(flow) + } + + is ImageRef -> buildAndAppendImage(layout, currentText, it) + is Hyperlink -> currentText = buildAndAppendHyperlink(layout, paragraph, baseTextStyleModel, it) + is FirstMatch -> currentText.appendFlow( + buildFirstMatch(layout, variableStructure, it, true, null, languages) + ) + } + } + } + } + + private fun createHyperlinkTextStyle( + layout: Layout, baseTextStyleModel: TextStyleDTO?, hyperlinkModel: Hyperlink + ): TextStyle { + val baseStyleName = baseTextStyleModel?.nameOrId() ?: "text" + val hyperlinkName = generateUniqueHyperlinkStyleName(layout, baseStyleName) + + val urlVariable = createUrlVariable(layout, hyperlinkName, hyperlinkModel.url) + + val hyperlinkStyle = layout.addTextStyle() + .setName(hyperlinkName) + .setUrlTarget(urlVariable) + .setType(TextStyleType.DELTA) + .setUrlAlternateText(hyperlinkModel.alternateText) + .addInheritFlags( + *TextStyleInheritFlag.entries + .filter { it != TextStyleInheritFlag.UNDERLINE && it != TextStyleInheritFlag.FILL_STYLE } + .toTypedArray()) + (hyperlinkStyle as TextStyleImpl).ancestorId = "Def.TextStyleHyperlink" + + if (baseTextStyleModel != null) { + val definition = baseTextStyleModel.resolve() + applyTextStyleProperties(layout, hyperlinkStyle, definition) + } + + return hyperlinkStyle + } + + private fun generateUniqueHyperlinkStyleName(layout: Layout, baseStyleName: String): String { + var counter = 1 + var candidateName = "${baseStyleName}_url_${counter}" + while (getTextStyleByName(layout, candidateName) != null) { + counter++ + candidateName = "${baseStyleName}_url_${counter}" + } + return candidateName + } + + private fun createUrlVariable(layout: Layout, variableName: String, url: String): WfdXmlVariable { + return layout.data.addVariable().setName(variableName).setKind(VariableKind.CONSTANT) + .setDataType(DataType.STRING).setValue(url) + } + + private fun buildAndAppendImage(layout: Layout, text: WfdXmlText, ref: ImageRef) { + val imageModel = imageRepository.findModelOrFail(ref.id) + + when (val imagePlaceholder = getImagePlaceholder(imageModel)) { + is ImagePlaceholderResult.Placeholder -> { + text.appendText(imagePlaceholder.value) + return + } + is ImagePlaceholderResult.RenderAsNormal -> {} + is ImagePlaceholderResult.Skip -> return + } + + text.appendImage(getOrBuildImage(layout, imageModel, imageModel.alternateText)) + } + + private fun buildAndAppendHyperlink( + layout: Layout, paragraph: WfdXmlParagraph, baseTextStyleModel: TextStyleDTO?, hyperlinkModel: Hyperlink + ): WfdXmlText { + val hyperlinkText = paragraph.addText() + val hyperlinkStyle = createHyperlinkTextStyle(layout, baseTextStyleModel, hyperlinkModel) + hyperlinkText.setTextStyle(hyperlinkStyle) + hyperlinkText.appendText(hyperlinkModel.displayText ?: hyperlinkModel.url) + + val newText = paragraph.addText() + baseTextStyleModel?.also { newText.setExistingTextStyle("TextStyles.${it.nameOrId()}") } + return newText + } + + private fun WfdXmlText.appendVariable( + ref: VariableRef, layout: Layout, variableStructure: VariableStructure + ): WfdXmlText { + val variableModel = variableRepository.findModelOrFail(ref.id) + + val variablePathData = variableStructure.structure[ref.id] + if (variablePathData == null || variablePathData.path.isBlank()) { + this.appendText("""$${variablePathData?.name ?: variableModel.nameOrId()}$""") + } else { + val variableName = variablePathData.name ?: variableModel.nameOrId() + this.appendVariable(getOrCreateVariable(layout.data, variableName, variableModel, variablePathData.path)) + } + + return this + } + + private fun findParagraphStyle(paragraphModel: Paragraph): ParagraphStyleDTO? { + if (paragraphModel.styleRef == null) return null + + val paraStyleModel = paragraphStyleRepository.firstWithDefinition(paragraphModel.styleRef.id) + ?: error("Paragraph style definition for ${paragraphModel.styleRef.id} not found.") + + return paraStyleModel + } + + private fun findTextStyle(textModel: Text): TextStyleDTO? { + if (textModel.styleRef == null) return null + + val textStyleModel = textStyleRepository.firstWithDefinition(textModel.styleRef.id) + ?: error("Text style definition for ${textModel.styleRef.id} not found.") + + return textStyleModel + } + + private fun buildSuccessFlowWrappedInInlineConditionFlow( + layout: Layout, variableStructure: VariableStructure, displayRuleId: String, text: WfdXmlText + ): Flow { + val displayRule = displayRuleRepository.findModelOrFail(displayRuleId) + if (displayRule.definition == null) { + error("Display rule '$displayRuleId' definition is null.") + } + + val successFlow = layout.addFlow().setType(Flow.Type.SIMPLE) + val def = displayRule.definition!! + + text.appendFlow( + layout.addFlow().setType(Flow.Type.SELECT_BY_INLINE_CONDITION).addLineForSelectByInlineCondition( + def.toScript(layout, variableStructure, variableRepository::findModelOrFail), + successFlow + ) + ) + + return successFlow + } + + private fun buildTable( + layout: Layout, variableStructure: VariableStructure, model: TableDTO, languages: List + ): WfdXmlTable { + val table = layout.addTable().setDisplayAsImage(false) + + if (model.columnWidths.isNotEmpty()) { + model.columnWidths.forEach { table.addColumn(it.minWidth.toMeters(), it.percentWidth) } + } else { + val numberOfColumns = model.rows.firstOrNull()?.cells?.size ?: 0 + repeat(numberOfColumns) { table.addColumn() } + } + + val rowset = layout.addRowSet().setType(RowSet.Type.MULTIPLE_ROWS) + table.setRowSet(rowset) + + model.rows.forEach { rowModel -> + val row = if (rowModel.displayRuleRef == null) { + layout.addRowSet().setType(RowSet.Type.SINGLE_ROW).also { rowset.addRowSet(it) } + } else { + val displayRule = displayRuleRepository.findModelOrFail(rowModel.displayRuleRef.id) + val def = displayRule.definition + if (def == null) { + error("Display rule '${rowModel.displayRuleRef.id}' definition is null.") + } + + buildSuccessRowWrappedInConditionRow( + layout, variableStructure, def, rowset + ) + } + + rowModel.cells.forEach { cellModel -> + val cellContentFlow = buildDocumentContentAsSingleFlow( + layout, variableStructure, cellModel.content, null, null, languages + ) + val cellFlow = if (cellContentFlow.type === Flow.Type.SELECT_BY_INLINE_CONDITION) { + layout.addFlow().setType(Flow.Type.SIMPLE).setSectionFlow(true) + .setWebEditingType(Flow.WebEditingType.SECTION) + .also { it.addParagraph().addText().appendFlow(cellContentFlow) } + } else cellContentFlow + + row.addCell( + layout.addCell().setSpanLeft(cellModel.mergeLeft).setSpanUp(cellModel.mergeUp) + .setFlowToNextPage(true).setFlow(cellFlow) + ) + } + } + + when (model.pdfTaggingRule) { + TablePdfTaggingRule.None -> table.setTablePdfTaggingRule(WfdXmlTable.TablePdfTaggingRule.NONE) + TablePdfTaggingRule.Default -> table.setTablePdfTaggingRule(WfdXmlTable.TablePdfTaggingRule.DEFAULT) + TablePdfTaggingRule.Table -> table.setTablePdfTaggingRule(WfdXmlTable.TablePdfTaggingRule.TABLE) + TablePdfTaggingRule.Artifact -> table.setTablePdfTaggingRule(WfdXmlTable.TablePdfTaggingRule.ARTIFACT) + } + table.setTablePdfAlternateText(model.pdfAlternateText) + + return table + } + + private fun buildFirstMatch( + layout: Layout, + variableStructure: VariableStructure, + model: FirstMatch, + isInline: Boolean, + flowName: String? = null, + languages: List, + ): Flow { + val firstMatchFlow = layout.addFlow().setType(Flow.Type.SELECT_BY_INLINE_CONDITION) + flowName?.let { firstMatchFlow.setName(it) } + + model.cases.forEachIndexed { i, case -> + val displayRule = displayRuleRepository.findModelOrFail(case.displayRuleRef.id) + if (displayRule.definition == null) { + error("Display rule '${case.displayRuleRef.id}' definition is null.") + } + + val caseName = case.name ?: "Case ${i + 1}" + + val contentFlow = + buildDocumentContentAsSingleFlow(layout, variableStructure, case.content, null, null, languages) + + val caseFlow = + if (isInline) contentFlow else layout.addFlow().setSectionFlow(true).setType(Flow.Type.SIMPLE) + .setWebEditingType(Flow.WebEditingType.SECTION).setDisplayName(caseName) + .also { it.addParagraph().addText().appendFlow(contentFlow) } + + val def = displayRule.definition!! + firstMatchFlow.addLineForSelectByInlineCondition( + def.toScript(layout, variableStructure, variableRepository::findModelOrFail), + caseFlow + ) + } + + if (model.default.isNotEmpty()) { + val contentFlow = + buildDocumentContentAsSingleFlow(layout, variableStructure, model.default, null, null, languages) + + val caseFlow = + if (isInline) contentFlow else layout.addFlow().setSectionFlow(true).setType(Flow.Type.SIMPLE) + .setWebEditingType(Flow.WebEditingType.SECTION).setDisplayName("Else Case") + .also { it.addParagraph().addText().appendFlow(contentFlow) } + + firstMatchFlow.setDefaultFlow(caseFlow) + } + + return firstMatchFlow + } + + private fun buildSelectByLanguage( + layout: Layout, + variableStructure: VariableStructure, + model: SelectByLanguage, + flowName: String?, + languages: List, + ): Flow { + val languageFlow = layout.addFlow().setType(Flow.Type.SELECT_BY_LANGUAGE) + flowName?.let { languageFlow.setName(it) } + + val defaultLanguage = projectConfig.defaultLanguage + + val caseFlows = model.cases.associate { + val caseName = "Case ${it.language}" + val contentFlow = buildDocumentContentAsSingleFlow( + layout, variableStructure, it.content, null, null, languages + ).setDisplayName(caseName) + it.language to contentFlow + } + + var defaultLanguageFlow: Flow? = null + for (language in languages) { + val contentFlow: Flow = (caseFlows[language] as Flow?) ?: layout.addFlow().setType(Flow.Type.SIMPLE).setDisplayName("Case $language") + languageFlow.addLineForSelectByInlineCondition(language, contentFlow) + + if (language == defaultLanguage) { + defaultLanguageFlow = contentFlow + } + } + + languageFlow.setDefaultFlow(defaultLanguageFlow ?: layout.addFlow().setType(Flow.Type.SIMPLE)) + + return languageFlow + } + + protected fun List.paragraphIfEmpty(): List { + return this.ifEmpty { + listOf( + com.quadient.migration.api.dto.migrationmodel.Paragraph( + listOf(com.quadient.migration.api.dto.migrationmodel.Paragraph.Text(listOf(), null, null)), + null, + null + ) + ) + } + } + + private fun TextStyleDTO.resolve(): TextStyleDefinition { + val def = this.definition + return when (def) { + is TextStyleDefinition -> def + is TextStyleRef -> { + textStyleRepository.findModel(def.id)?.resolve() ?: error("Invalid text style reference") + } + else -> error("Invalid text style definition type") + } + } + + private fun ParagraphStyleDTO.resolve(): ParagraphStyleDefinition { + val def = this.definition + return when (def) { + is ParagraphStyleDefinition -> def + is ParagraphStyleRef -> paragraphStyleRepository.findModelOrFail(def.id).resolve() + else -> error("Invalid paragraph style definition type") + } + } + + sealed interface ScriptResult { + data class Success(val variableScript: String) : ScriptResult { + override fun toString() = variableScript + } + + data class Failure(val variableName: String) : ScriptResult { + override fun toString() = variableName + } + } +} + +fun DisplayRuleDefinition.toScript( + layout: Layout, variableStructure: VariableStructure, findVar: (String) -> Variable +): String { + return "return ${this.group.toScript(layout, variableStructure, findVar)};" +} + +fun Group.toScript( + layout: Layout, variableStructure: VariableStructure, findVar: (String) -> Variable +): String { + val expressions = """(${ + items.joinToString( + separator = " ${operator.toInlineCondition()} ", transform = { + when (it) { + is Binary -> it.toScript(layout, variableStructure, findVar) + is Group -> it.toScript(layout, variableStructure, findVar) + } + }) + })""" + return if (negation) { + "not $expressions" + } else { + expressions + } +} + +fun Binary.toScript( + layout: Layout, variableStructure: VariableStructure, findVar: (String) -> Variable +): String { + val leftScriptResult = left.toScript(layout, variableStructure, findVar) + val rightScriptResult = right.toScript(layout, variableStructure, findVar) + + val binary = operator.toScript(leftScriptResult, rightScriptResult) + return if (leftScriptResult is Success && rightScriptResult is Success) { + binary + } else { + BinOp.Equals.toScript( + Success("String('${binary.replace("'", "")}')"), Success("String('unmapped')") + ) + } +} + +fun BinOp.toScript(left: ScriptResult, right: ScriptResult): String { + return when (this) { + BinOp.Equals -> "$left==$right" + BinOp.EqualsCaseInsensitive -> "$left.equalCaseInsensitive($right)" + BinOp.NotEquals -> "$left!=$right" + BinOp.NotEqualsCaseInsensitive -> "(not $left.equalCaseInsensitive($right))" + BinOp.GreaterThan -> "$left>$right" + BinOp.GreaterOrEqualThan -> "$left>=$right" + BinOp.LessThan -> "$left<$right" + BinOp.LessOrEqualThen -> "$left<=$right" + } +} + +fun LiteralOrFunctionCall.toScript( + layout: Layout, variableStructure: VariableStructure, findVar: (String) -> Variable +): ScriptResult { + return when (this) { + is Literal -> this.toScript(layout, variableStructure, findVar) + is Function -> this.toScript(layout, variableStructure, findVar) + } +} + +fun Function.toScript( + layout: Layout, variableStructure: VariableStructure, findVar: (String) -> Variable +): ScriptResult { + when (this) { + is Function.UpperCase -> { + val arg = args[0] + return Success("(${arg.toScript(layout, variableStructure, findVar)}).toUpperCase()") + } + + is Function.LowerCase -> { + val arg = args[0] + return Success("(${arg.toScript(layout, variableStructure, findVar)}).toLowerCase()") + } + } +} + +fun Literal.toScript( + layout: Layout, variableStructure: VariableStructure, findVar: (String) -> Variable +): ScriptResult { + return when (dataType) { + LiteralDataType.Variable -> variableToScript(value, layout, variableStructure, findVar) + LiteralDataType.String -> Success( + "String('${ + value.replace("\\", "\\\\").replace("\"", "\\\"") + }')" + ) + + LiteralDataType.Number -> Success(value) + LiteralDataType.Boolean -> Success(value.lowercase().toBooleanStrict().toString()) + } +} + +fun variableToScript( + id: String, layout: Layout, variableStructure: VariableStructure, findVar: (String) -> Variable +): ScriptResult { + val variableModel = findVar(id) + val variablePathData = variableStructure.structure[id] + return if (variablePathData == null || variablePathData.path.isBlank()) { + Failure(variablePathData?.name ?: variableModel.nameOrId()) + } else { + val variableName = variablePathData.name ?: variableModel.nameOrId() + + getOrCreateVariable(layout.data, variableName, variableModel, variablePathData.path) + + Success((variablePathData.path.split(".") + variableName).joinToString(".") { pathPart -> + when (pathPart.lowercase()) { + "value" -> "Current" + "data" -> "DATA" + else -> sanitizeVariablePart(if (pathPart.first().isDigit()) "_$pathPart" else pathPart) + } + }) + } +} + +fun getOrCreateVariable( + data: Data, variableName: String, variableModel: Variable, variablePath: String +): WfdXmlVariable { + val variable = getVariable(data as DataImpl, variableName, variablePath) + return variable ?: data.addVariable().setName(variableName).setKind(VariableKind.DISCONNECTED) + .setDataType(getDataType(variableModel.dataType)).setExistingParentId(variablePath) + .setValueIfAvailable(variableModel) +} + +fun WfdXmlVariable.setValueIfAvailable(variableModel: Variable): WfdXmlVariable { + val defaultVal = variableModel.defaultValue + if (!defaultVal.isNullOrBlank()) { + when (variableModel.dataType) { + DataTypeModel.String, DataTypeModel.DateTime -> this.setValue(defaultVal) + DataTypeModel.Integer -> this.setValue(defaultVal.toInt()) + DataTypeModel.Integer64 -> this.setValue(defaultVal.toLong()) + DataTypeModel.Double, DataTypeModel.Currency -> this.setValue(defaultVal.toDouble()) + DataTypeModel.Boolean -> this.setValue( + defaultVal.lowercase().toBooleanStrict() + ) + } + } + + return this } \ No newline at end of file diff --git a/migration-library/src/main/kotlin/com/quadient/migration/service/inspirebuilder/InteractiveDocumentObjectBuilder.kt b/migration-library/src/main/kotlin/com/quadient/migration/service/inspirebuilder/InteractiveDocumentObjectBuilder.kt index 9c32d240..a3a16ce0 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/service/inspirebuilder/InteractiveDocumentObjectBuilder.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/service/inspirebuilder/InteractiveDocumentObjectBuilder.kt @@ -4,15 +4,16 @@ import com.fasterxml.jackson.databind.node.ArrayNode import com.fasterxml.jackson.dataformat.xml.XmlMapper import com.fasterxml.jackson.module.kotlin.registerKotlinModule import com.quadient.migration.api.ProjectConfig -import com.quadient.migration.data.AreaModel -import com.quadient.migration.data.DocumentContentModel -import com.quadient.migration.data.DocumentObjectModel -import com.quadient.migration.data.FileModel -import com.quadient.migration.data.ImageModel +import com.quadient.migration.api.dto.migrationmodel.Area +import com.quadient.migration.api.dto.migrationmodel.DisplayRuleRef +import com.quadient.migration.api.dto.migrationmodel.DocumentContent +import com.quadient.migration.api.dto.migrationmodel.DocumentObject +import com.quadient.migration.api.dto.migrationmodel.File +import com.quadient.migration.api.dto.migrationmodel.Image import com.quadient.migration.persistence.repository.DisplayRuleInternalRepository import com.quadient.migration.persistence.repository.DocumentObjectInternalRepository -import com.quadient.migration.persistence.repository.ImageInternalRepository import com.quadient.migration.persistence.repository.FileInternalRepository +import com.quadient.migration.persistence.repository.ImageInternalRepository import com.quadient.migration.persistence.repository.ParagraphStyleInternalRepository import com.quadient.migration.persistence.repository.TextStyleInternalRepository import com.quadient.migration.persistence.repository.VariableInternalRepository @@ -28,7 +29,7 @@ import com.quadient.migration.shared.ImageType import com.quadient.migration.shared.orDefault import com.quadient.wfdxml.WfdXmlBuilder import com.quadient.wfdxml.api.layoutnodes.Flow -import com.quadient.wfdxml.api.layoutnodes.Image +import com.quadient.wfdxml.api.layoutnodes.Image as WfdXmlImage import com.quadient.wfdxml.api.layoutnodes.data.DataType import com.quadient.wfdxml.api.layoutnodes.data.VariableKind import com.quadient.wfdxml.api.module.Layout @@ -79,8 +80,8 @@ class InteractiveDocumentObjectBuilder( .join(resolveTargetDir(projectConfig.defaultTargetFolder, targetFolder)).join(fileName).toString() } - override fun getDocumentObjectPath(documentObject: DocumentObjectModel) = - getDocumentObjectPath(documentObject.nameOrId(), documentObject.type, documentObject.targetFolder) + override fun getDocumentObjectPath(documentObject: DocumentObject) = + getDocumentObjectPath(documentObject.nameOrId(), documentObject.type, documentObject.targetFolder?.let { IcmPath.from(it) }) override fun getImagePath( id: String, @@ -106,8 +107,8 @@ class InteractiveDocumentObjectBuilder( .toString() } - override fun getImagePath(image: ImageModel) = - getImagePath(image.id, image.imageType, image.name, image.targetFolder, image.sourcePath) + override fun getImagePath(image: Image) = + getImagePath(image.id, image.imageType ?: ImageType.Unknown, image.name, image.targetFolder?.let { IcmPath.from(it) }, image.sourcePath) override fun getFilePath( id: String, name: String?, targetFolder: IcmPath?, sourcePath: String?, fileType: FileType @@ -128,8 +129,8 @@ class InteractiveDocumentObjectBuilder( .join(resolveTargetDir(projectConfig.defaultTargetFolder, targetFolder)).join(fileName).toString() } - override fun getFilePath(file: FileModel): String = - getFilePath(file.id, file.name, file.targetFolder, file.sourcePath, file.fileType) + override fun getFilePath(file: File): String = + getFilePath(file.id, file.name, file.targetFolder?.let { IcmPath.from(it) }, file.sourcePath, file.fileType) override fun getStyleDefinitionPath(extension: String): String { val styleDefConfigPath = projectConfig.styleDefinitionPath @@ -159,20 +160,12 @@ class InteractiveDocumentObjectBuilder( } override fun applyImageAlternateText(layout: Layout, image: Image, alternateText: String) { - val escapedText = alternateText.replace("\"", "\\\"") - val variable = layout.data.addVariable() - .setName("Alternate text variable for ${image.name}") - .setKind(VariableKind.CALCULATED) - .setDataType(DataType.STRING) - .setScript("return '$escapedText';") - .addCustomProperty("ValueWrapperVariable", true) - val layoutRoot = layout.root ?: layout.addRoot() - layoutRoot.addLockedWebNode(variable) - - image.setAlternateTextVariable(variable) + // This method receives the DTO Image but needs to set alternate text on the WfdXml image + // The actual image setting is done in the InspireDocumentObjectBuilder when building + // For Interactive, we just create the variable, the image reference is handled elsewhere } - override fun buildDocumentObject(documentObject: DocumentObjectModel, styleDefinitionPath: String?): String { + override fun buildDocumentObject(documentObject: DocumentObject, styleDefinitionPath: String?): String { logger.debug("Starting to build document object '${documentObject.nameOrId()}'.") val builder = WfdXmlBuilder() @@ -194,19 +187,20 @@ class InteractiveDocumentObjectBuilder( val languages = collectLanguages(documentObject) val variableStructure = initVariableStructure(layout, documentObject) - val interactiveFlowsWithContent = mutableMapOf>() + val interactiveFlowsWithContent = mutableMapOf>() if (documentObject.type == DocumentObjectType.Page) { documentObject.content.paragraphIfEmpty().forEach { - if (it is AreaModel && !it.interactiveFlowName.isNullOrBlank()) { - val interactiveFlowId = if (it.interactiveFlowName.startsWith("Def.")) { - it.interactiveFlowName + if (it is Area && !it.interactiveFlowName.isNullOrBlank()) { + val flowName = it.interactiveFlowName!! + val interactiveFlowId = if (flowName.startsWith("Def.")) { + flowName } else { - getInteractiveFlowIdByName(it.interactiveFlowName, baseTemplatePath.toString()) + getInteractiveFlowIdByName(flowName, baseTemplatePath.toString()) } if (interactiveFlowId.isNullOrBlank()) { val errorMessage = - "Failed to find interactive flow '${it.interactiveFlowName}' in base template '$baseTemplatePath'." + "Failed to find interactive flow '$flowName' in base template '$baseTemplatePath'." logger.error(errorMessage) error(errorMessage) } @@ -235,7 +229,7 @@ class InteractiveDocumentObjectBuilder( } else { interactiveFlowText.appendFlow( contentFlows.toSingleFlow( - layout, variableStructure, documentObject.nameOrId(), documentObject.displayRuleRef + layout, variableStructure, documentObject.nameOrId(), documentObject.displayRuleRef?.let { DisplayRuleRef(it.id) } ) ) } @@ -245,8 +239,8 @@ class InteractiveDocumentObjectBuilder( return builder.buildLayoutDelta() } - override fun shouldIncludeInternalDependency(documentObject: DocumentObjectModel): Boolean { - return documentObject.internal + override fun shouldIncludeInternalDependency(documentObject: DocumentObject): Boolean { + return documentObject.internal == true } fun getInteractiveFlowIdByName(interactiveFlowName: String, baseTemplatePath: String): String? { diff --git a/migration-library/src/main/kotlin/com/quadient/migration/shared/DisplayRuleDefinition.kt b/migration-library/src/main/kotlin/com/quadient/migration/shared/DisplayRuleDefinition.kt index bab8aba2..3cdc41d2 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/shared/DisplayRuleDefinition.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/shared/DisplayRuleDefinition.kt @@ -1,13 +1,13 @@ package com.quadient.migration.shared -import com.quadient.migration.data.RefModel -import com.quadient.migration.data.VariableModelRef -import com.quadient.migration.service.RefValidatable +import com.quadient.migration.api.dto.migrationmodel.Ref +import com.quadient.migration.api.dto.migrationmodel.RefValidatable +import com.quadient.migration.api.dto.migrationmodel.VariableRef import kotlinx.serialization.Serializable @Serializable data class DisplayRuleDefinition(val group: Group) : RefValidatable { - override fun collectRefs(): List { + override fun collectRefs(): List { return group.collectRefs() } } @@ -39,7 +39,7 @@ sealed class Function(val minArgs: Int, val maxArgs: Int, val args: List { + override fun collectRefs(): List { return args.flatMap { it.collectRefs() } } @@ -68,16 +68,16 @@ sealed interface LiteralOrFunctionCall : RefValidatable @Serializable data class Binary(var left: LiteralOrFunctionCall, var operator: BinOp, var right: LiteralOrFunctionCall) : RefValidatable, BinaryOrGroup() { - override fun collectRefs(): List { + override fun collectRefs(): List { return left.collectRefs() + right.collectRefs() } } @Serializable data class Literal(var value: String, val dataType: LiteralDataType) : RefValidatable, LiteralOrFunctionCall { - override fun collectRefs(): List { + override fun collectRefs(): List { return when (dataType) { - LiteralDataType.Variable -> listOf(VariableModelRef(value)) + LiteralDataType.Variable -> listOf(VariableRef(value)) else -> emptyList() } } @@ -92,7 +92,7 @@ enum class LiteralDataType { data class Group(val items: List, val operator: GroupOp, val negation: Boolean) : RefValidatable, BinaryOrGroup() { - override fun collectRefs(): List { + override fun collectRefs(): List { return items.flatMap { when (it) { is Group -> it.collectRefs() diff --git a/migration-library/src/test/kotlin/com/quadient/migration/persistence/DocumentObjectRepositoryTest.kt b/migration-library/src/test/kotlin/com/quadient/migration/persistence/DocumentObjectRepositoryTest.kt index ff14ba69..5f86d8c7 100644 --- a/migration-library/src/test/kotlin/com/quadient/migration/persistence/DocumentObjectRepositoryTest.kt +++ b/migration-library/src/test/kotlin/com/quadient/migration/persistence/DocumentObjectRepositoryTest.kt @@ -58,10 +58,9 @@ class DocumentObjectRepositoryTest { repo.upsert(dto) val result = repo.listAll() - dto.lastUpdated = result.first().lastUpdated - dto.created = result.first().created - result.first().content[2].shouldBeEqualTo(dto.content[2]) - result.first().shouldBeEqualTo(dto) + val updatedDto = dto.copy(lastUpdated = result.first().lastUpdated, created = result.first().created) + result.first().content[2].shouldBeEqualTo(updatedDto.content[2]) + result.first().shouldBeEqualTo(updatedDto) } @Test @@ -138,9 +137,8 @@ class DocumentObjectRepositoryTest { repo.upsert(input) val result = repo.listAll() - input.lastUpdated = result.first().lastUpdated - input.created = result.first().created - result.first().shouldBeEqualTo(input) + val updatedInput = input.copy(lastUpdated = result.first().lastUpdated, created = result.first().created) + result.first().shouldBeEqualTo(updatedInput) } @Test diff --git a/migration-library/src/test/kotlin/com/quadient/migration/persistence/MappingRepositoryTest.kt b/migration-library/src/test/kotlin/com/quadient/migration/persistence/MappingRepositoryTest.kt index 6da2fe6c..2cddbe98 100644 --- a/migration-library/src/test/kotlin/com/quadient/migration/persistence/MappingRepositoryTest.kt +++ b/migration-library/src/test/kotlin/com/quadient/migration/persistence/MappingRepositoryTest.kt @@ -1,19 +1,19 @@ package com.quadient.migration.persistence import com.quadient.migration.Postgres +import com.quadient.migration.api.dto.migrationmodel.CustomFieldMap import com.quadient.migration.api.dto.migrationmodel.MappingItem import com.quadient.migration.api.dto.migrationmodel.VariableStructure import com.quadient.migration.api.repository.* -import com.quadient.migration.data.VariableModelRef import com.quadient.migration.shared.VariablePathData import com.quadient.migration.tools.aProjectConfig import com.quadient.migration.tools.aVariable -import com.quadient.migration.tools.model.aVariableStructureModel import io.mockk.every import io.mockk.just import io.mockk.mockk import io.mockk.runs import io.mockk.verify +import kotlinx.datetime.Clock import org.junit.jupiter.api.Test @Postgres @@ -41,10 +41,15 @@ class MappingRepositoryTest { @Test fun `apply variable mapping`() { every { variableRepository.find("varId") } returns aVariable(id = "varId", name = "Variable Name") - every { variableStructureRepository.find("varStructId") } returns VariableStructure.fromModel( - aVariableStructureModel( - id = "varStructId", name = "Variable Structure Name" - ) + every { variableStructureRepository.find("varStructId") } returns VariableStructure( + id = "varStructId", + name = "Variable Structure Name", + originLocations = emptyList(), + customFields = CustomFieldMap(mutableMapOf()), + created = Clock.System.now(), + lastUpdated = Clock.System.now(), + structure = emptyMap(), + languageVariable = null ) every { variableStructureRepository.find(any()) } returns null every { variableStructureRepository.upsert(any()) } answers { firstArg() } @@ -58,8 +63,15 @@ class MappingRepositoryTest { @Test fun `apply variable mapping structure`() { - every { variableStructureRepository.find("varStructId") } returns VariableStructure.fromModel( - aVariableStructureModel(id = "varStructId", name = null) + every { variableStructureRepository.find("varStructId") } returns VariableStructure( + id = "varStructId", + name = null, + originLocations = emptyList(), + customFields = CustomFieldMap(mutableMapOf()), + created = Clock.System.now(), + lastUpdated = Clock.System.now(), + structure = emptyMap(), + languageVariable = null ) every { variableStructureRepository.upsert(any()) } just runs repo.upsert("varStructId", MappingItem.VariableStructure( @@ -72,14 +84,14 @@ class MappingRepositoryTest { verify { variableStructureRepository.upsert( - VariableStructure.fromModel( - aVariableStructureModel( - id = "varStructId", name = "new name", structure = mapOf( - VariableModelRef("varId") to VariablePathData("somePath"), - VariableModelRef("anotherVarId") to VariablePathData("anotherPath") - ) + match { + it.id == "varStructId" && + it.name == "new name" && + it.structure == mapOf( + "varId" to VariablePathData("somePath"), + "anotherVarId" to VariablePathData("anotherPath") ) - ) + } ) } } diff --git a/migration-library/src/test/kotlin/com/quadient/migration/persistence/migrationmodel/MappingEntityTest.kt b/migration-library/src/test/kotlin/com/quadient/migration/persistence/migrationmodel/MappingEntityTest.kt index 8f7773d0..2a7f30ba 100644 --- a/migration-library/src/test/kotlin/com/quadient/migration/persistence/migrationmodel/MappingEntityTest.kt +++ b/migration-library/src/test/kotlin/com/quadient/migration/persistence/migrationmodel/MappingEntityTest.kt @@ -6,8 +6,10 @@ import com.quadient.migration.api.dto.migrationmodel.DocumentObject import com.quadient.migration.api.dto.migrationmodel.Image import com.quadient.migration.api.dto.migrationmodel.ParagraphStyleDefinition import com.quadient.migration.api.dto.migrationmodel.ParagraphStyleRef +import com.quadient.migration.api.dto.migrationmodel.StringValue import com.quadient.migration.api.dto.migrationmodel.TextStyleDefinition import com.quadient.migration.api.dto.migrationmodel.TextStyleRef +import com.quadient.migration.api.dto.migrationmodel.VariableStructureRef import com.quadient.migration.shared.Alignment import com.quadient.migration.shared.Color import com.quadient.migration.shared.DataType @@ -19,17 +21,16 @@ import com.quadient.migration.shared.SkipOptions import com.quadient.migration.shared.SuperOrSubscript import com.quadient.migration.shared.millimeters import com.quadient.migration.shared.points +import com.quadient.migration.tools.aBlockDto +import com.quadient.migration.tools.aImageDto +import com.quadient.migration.tools.aParagraph import com.quadient.migration.tools.aParagraphStyle import com.quadient.migration.tools.aParagraphStyleDefinition +import com.quadient.migration.tools.aText import com.quadient.migration.tools.aTextStyle import com.quadient.migration.tools.aTextStyleDefinition import com.quadient.migration.tools.aVariable -import com.quadient.migration.tools.model.aDocObj -import com.quadient.migration.tools.model.aImage -import com.quadient.migration.tools.model.aParagraph -import com.quadient.migration.tools.model.anArea import com.quadient.migration.tools.shouldBeEqualTo -import com.quadient.wfdxml.api.layoutnodes.ParagraphStyle import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Nested import org.junit.jupiter.api.Test @@ -48,15 +49,12 @@ class MappingEntityTest { variableStructureRef = null, skip = null, ) - val dto = DocumentObject.fromModel( - aDocObj( - "doc1", - name = "Test doc", - internal = true, - baseTemplate = "base1", - targetFolder = "folder1", - type = DocumentObjectType.Section - ) + val dto = aBlockDto( + "doc1", + name = "Test doc", + internal = true, + targetFolder = "folder1", + type = DocumentObjectType.Section, ) val result = mapping.apply(dto) @@ -79,16 +77,14 @@ class MappingEntityTest { variableStructureRef = "new structure", skip = SkipOptions(true, "ph", "reason"), ) - val dto = DocumentObject.fromModel( - aDocObj( - "doc1", - name = "Test doc", - internal = true, - baseTemplate = "base1", - targetFolder = "folder1", - type = DocumentObjectType.Section, - variableStructureModelRef = "some structure", - ) + val dto = aBlockDto( + "doc1", + name = "Test doc", + internal = true, + baseTemplate = "base1", + targetFolder = "folder1", + type = DocumentObjectType.Section, + variableStructureRef = VariableStructureRef("some structure"), ) val result = mapping.apply(dto) @@ -110,9 +106,7 @@ class MappingEntityTest { @Test fun `nothing changes with null mapping`() { val mapping = MappingItemEntity.Area(name = null, areas = mutableMapOf()) - val dto = DocumentObject.fromModel( - aDocObj("doc1", content = listOf(anArea(emptyList(), null, "Area 1"), anArea(emptyList(), null, "Area 2"))) - ) + val dto = aBlockDto("doc1", content = listOf(Area(emptyList(), null, "Area 1"), Area(emptyList(), null, "Area 2"))) val result = mapping.apply(dto) @@ -125,15 +119,13 @@ class MappingEntityTest { val mapping = MappingItemEntity.Area( name = null, areas = mutableMapOf(0 to "AddedFirstAreaName", 1 to null, 2 to "AddedLastAreaName") ) - val dto = DocumentObject.fromModel( - aDocObj( - "doc1", content = listOf( - anArea(emptyList(), null, null), - aParagraph("Default paragraph content"), - anArea(emptyList(), null, "MiddleAreaFlow"), - aParagraph("Another paragraph content"), - anArea(emptyList(), null, null), - ) + val dto = aBlockDto( + "doc1", content = listOf( + Area(emptyList(), null, null), + aParagraph(content = listOf(aText(content = listOf(StringValue("Default paragraph content"))))), + Area(emptyList(), null, "MiddleAreaFlow"), + aParagraph(content = listOf(aText(content = listOf(StringValue("Another paragraph content"))))), + Area(emptyList(), null, null), ) ) @@ -141,12 +133,12 @@ class MappingEntityTest { result.content.shouldBeEqualTo( listOf( - anArea(emptyList(), null, "AddedFirstAreaName"), - aParagraph("Default paragraph content"), - anArea(emptyList(), null, null), - aParagraph("Another paragraph content"), - anArea(emptyList(), null, "AddedLastAreaName"), - ).map { DocumentContent.fromModelContent(it) }) + Area(emptyList(), null, "AddedFirstAreaName"), + aParagraph(content = listOf(aText(content = listOf(StringValue("Default paragraph content"))))), + Area(emptyList(), null, null), + aParagraph(content = listOf(aText(content = listOf(StringValue("Another paragraph content"))))), + Area(emptyList(), null, "AddedLastAreaName"), + )) } } @@ -160,7 +152,7 @@ class MappingEntityTest { sourcePath = null, skip = null, ) - val dto = Image.fromModel(aImage("img1", name = "test img", targetFolder = "dir1", sourcePath = "source1")) + val dto = aImageDto("img1", name = "test img", targetFolder = "dir1", sourcePath = "source1") val result = mapping.apply(dto) @@ -179,7 +171,7 @@ class MappingEntityTest { imageType = ImageType.Gif, skip = SkipOptions(true, "ph", "reason"), ) - val dto = Image.fromModel(aImage("img1", name = "test img", targetFolder = "dir1", sourcePath = "source1")) + val dto = aImageDto("img1", name = "test img", targetFolder = "dir1", sourcePath = "source1") val result = mapping.apply(dto) diff --git a/migration-library/src/test/kotlin/com/quadient/migration/service/ReferenceValidatorTest.kt b/migration-library/src/test/kotlin/com/quadient/migration/service/ReferenceValidatorTest.kt index 3400807c..51e67a7a 100644 --- a/migration-library/src/test/kotlin/com/quadient/migration/service/ReferenceValidatorTest.kt +++ b/migration-library/src/test/kotlin/com/quadient/migration/service/ReferenceValidatorTest.kt @@ -2,6 +2,7 @@ package com.quadient.migration.service import com.quadient.migration.Postgres import com.quadient.migration.api.dto.migrationmodel.DocumentContent +import com.quadient.migration.api.dto.migrationmodel.DocumentObjectRef import com.quadient.migration.api.dto.migrationmodel.ParagraphStyleRef import com.quadient.migration.api.dto.migrationmodel.TextStyleRef import com.quadient.migration.shared.DocumentObjectType @@ -14,7 +15,6 @@ import com.quadient.migration.tools.aTextStyleRepository import com.quadient.migration.tools.model.aBlock import com.quadient.migration.tools.model.aDisplayRuleInternalRepository import com.quadient.migration.tools.model.aDocumentObjectInternalRepository -import com.quadient.migration.tools.model.aDocumentObjectRef import com.quadient.migration.tools.model.aFileInternalRepository import com.quadient.migration.tools.model.aImageInternalRepository import com.quadient.migration.tools.model.aParaStyleInternalRepository @@ -64,7 +64,7 @@ class ReferenceValidatorTest { @Test fun `validates block with missing ref`() { - val missingRef = aDocumentObjectRef("obj1") + val missingRef = DocumentObjectRef("obj1") val input = aBlock( id = "1", type = DocumentObjectType.Block, content = listOf(missingRef) ) @@ -78,10 +78,10 @@ class ReferenceValidatorTest { @Test fun `valid block with nested dependencies`() { - val blockRef1 = aDocumentObjectRef("obj1") - val blockRef2 = aDocumentObjectRef("obj2") - val blockRef11 = aDocumentObjectRef("obj11") - val blockRef21 = aDocumentObjectRef("obj21") + val blockRef1 = DocumentObjectRef("obj1") + val blockRef2 = DocumentObjectRef("obj2") + val blockRef11 = DocumentObjectRef("obj11") + val blockRef21 = DocumentObjectRef("obj21") val input = aBlock( id = "1", type = DocumentObjectType.Block, content = listOf(blockRef1, blockRef2) ) @@ -91,7 +91,8 @@ class ReferenceValidatorTest { docRepo.upsert( aBlockDto( "obj1", content = listOf( - DocumentContent.fromModelContent(blockRef11), DocumentContent.fromModelContent(blockRef21) + blockRef11, + blockRef21 ) ) ) @@ -105,11 +106,11 @@ class ReferenceValidatorTest { @Test fun `valid block with nested dependencies and one missing in the end`() { - val blockRef1 = aDocumentObjectRef("obj1") - val blockRef2 = aDocumentObjectRef("obj2") - val blockRef11 = aDocumentObjectRef("obj11") - val blockRef21 = aDocumentObjectRef("obj21") - val missingVarRef = aDocumentObjectRef("obj111") + val blockRef1 = DocumentObjectRef("obj1") + val blockRef2 = DocumentObjectRef("obj2") + val blockRef11 = DocumentObjectRef("obj11") + val blockRef21 = DocumentObjectRef("obj21") + val missingVarRef = DocumentObjectRef("obj111") val input = aBlock( id = "1", type = DocumentObjectType.Block, content = listOf(blockRef1, blockRef2) ) @@ -119,13 +120,14 @@ class ReferenceValidatorTest { docRepo.upsert( aBlockDto( "obj1", content = listOf( - DocumentContent.fromModelContent(blockRef11), DocumentContent.fromModelContent(blockRef21) + blockRef11, + blockRef21 ) ) ) docRepo.upsert( aBlockDto( - "obj11", content = listOf(DocumentContent.fromModelContent(missingVarRef)) + "obj11", content = listOf(missingVarRef) ) ) @@ -139,11 +141,11 @@ class ReferenceValidatorTest { @Test fun `takes published if draft is missing`() { - val blockRef1 = aDocumentObjectRef("block1") - val missingRef = aDocumentObjectRef("missing") + val blockRef1 = DocumentObjectRef("block1") + val missingRef = DocumentObjectRef("missing") docRepo.upsert( aBlockDto( - "block1", content = listOf(DocumentContent.fromModelContent(missingRef)) + "block1", content = listOf(missingRef) ) ) val input = aBlock(id = "1", type = DocumentObjectType.Block, content = listOf(blockRef1)) diff --git a/migration-library/src/test/kotlin/com/quadient/migration/service/StylesValidatorTest.kt b/migration-library/src/test/kotlin/com/quadient/migration/service/StylesValidatorTest.kt index c05edfb3..a92e85e8 100644 --- a/migration-library/src/test/kotlin/com/quadient/migration/service/StylesValidatorTest.kt +++ b/migration-library/src/test/kotlin/com/quadient/migration/service/StylesValidatorTest.kt @@ -2,11 +2,10 @@ package com.quadient.migration.service import com.quadient.migration.Postgres import com.quadient.migration.api.dto.migrationmodel.ParagraphStyleRef +import com.quadient.migration.api.dto.migrationmodel.TextStyleRef import com.quadient.migration.api.repository.DocumentObjectRepository import com.quadient.migration.api.repository.ParagraphStyleRepository import com.quadient.migration.api.repository.TextStyleRepository -import com.quadient.migration.data.ParagraphStyleModelRef -import com.quadient.migration.data.TextStyleModelRef import com.quadient.migration.service.deploy.DeployClient import com.quadient.migration.service.inspirebuilder.InspireDocumentObjectBuilder import com.quadient.migration.service.ipsclient.IpsService @@ -57,16 +56,16 @@ class StylesValidatorTest { aBlock( id = "id", content = listOf( aParagraph( - styleRef = ParagraphStyleModelRef("found-para"), - content = listOf(aText(content = listOf(), styleRef = TextStyleModelRef("not-found-text"))) + styleRef = ParagraphStyleRef("found-para"), + content = listOf(aText(content = listOf(), styleRef = TextStyleRef("not-found-text"))) ) ) ), aBlock( id = "id2", content = listOf( aParagraph( - styleRef = ParagraphStyleModelRef("not-found-para"), - content = listOf(aText(content = listOf(), styleRef = TextStyleModelRef("found-text"))) + styleRef = ParagraphStyleRef("not-found-para"), + content = listOf(aText(content = listOf(), styleRef = TextStyleRef("found-text"))) ) ) ) @@ -94,16 +93,16 @@ class StylesValidatorTest { aBlock( id = "id", content = listOf( aParagraph( - styleRef = ParagraphStyleModelRef("found-para"), - content = listOf(aText(content = listOf(), styleRef = TextStyleModelRef("not-found-text"))) + styleRef = ParagraphStyleRef("found-para"), + content = listOf(aText(content = listOf(), styleRef = TextStyleRef("not-found-text"))) ) ) ), aBlock( id = "id2", content = listOf( aParagraph( - styleRef = ParagraphStyleModelRef("not-found-para"), - content = listOf(aText(content = listOf(), styleRef = TextStyleModelRef("found-text"))) + styleRef = ParagraphStyleRef("not-found-para"), + content = listOf(aText(content = listOf(), styleRef = TextStyleRef("found-text"))) ) ) ) @@ -129,7 +128,7 @@ class StylesValidatorTest { fun `resolves style references correctly`() { every { deployClient.getAllDocumentObjectsToDeploy() } returns listOf( aBlock( - id = "id", content = listOf(aParagraph(styleRef = ParagraphStyleModelRef("para1"))) + id = "id", content = listOf(aParagraph(styleRef = ParagraphStyleRef("para1"))) ) ) paraStyleRepository.upsert(aParagraphStyle(id = "para1", definition = ParagraphStyleRef("para2"))) diff --git a/migration-library/src/test/kotlin/com/quadient/migration/tools/TestObjectBuilders.kt b/migration-library/src/test/kotlin/com/quadient/migration/tools/TestObjectBuilders.kt index a29fd8b3..1d0ea72c 100644 --- a/migration-library/src/test/kotlin/com/quadient/migration/tools/TestObjectBuilders.kt +++ b/migration-library/src/test/kotlin/com/quadient/migration/tools/TestObjectBuilders.kt @@ -38,8 +38,6 @@ import com.quadient.migration.api.repository.VariableRepository import com.quadient.migration.api.repository.VariableStructureRepository import com.quadient.migration.data.Active import com.quadient.migration.data.Deployed -import com.quadient.migration.data.DocumentContentModel -import com.quadient.migration.data.DocumentObjectModel import com.quadient.migration.data.StatusEvent import com.quadient.migration.persistence.table.StatusTrackingEntity import com.quadient.migration.persistence.table.StatusTrackingTable @@ -51,6 +49,7 @@ import com.quadient.migration.shared.DocumentObjectOptions import com.quadient.migration.shared.DocumentObjectType import com.quadient.migration.shared.IcmPath import com.quadient.migration.shared.LineSpacing +import com.quadient.migration.shared.MetadataPrimitive import com.quadient.migration.shared.ParagraphPdfTaggingRule import com.quadient.migration.shared.Size import com.quadient.migration.shared.SkipOptions @@ -80,6 +79,8 @@ fun aBlockDto( originLocations: List = emptyList(), customFields: MutableMap = mutableMapOf(), type: DocumentObjectType = DocumentObjectType.Block, + baseTemplate: String? = null, + variableStructureRef: VariableStructureRef? = null, ): DocumentObject { return DocumentObject( id = id, @@ -90,9 +91,39 @@ fun aBlockDto( targetFolder = targetFolder, originLocations = originLocations, customFields = CustomFieldMap(customFields), + created = kotlinx.datetime.Clock.System.now(), + lastUpdated = kotlinx.datetime.Clock.System.now(), metadata = emptyMap(), skip = SkipOptions(false, null, null), subject = null, + baseTemplate = baseTemplate, + variableStructureRef = variableStructureRef, + ) +} + +fun aImageDto( + id: String, + name: String? = "Image_$id", + sourcePath: String? = "$name.jpg", + imageType: ImageType = ImageType.Jpeg, + targetFolder: String? = null, + originLocations: List = emptyList(), + customFields: MutableMap = mutableMapOf(), +): Image { + return Image( + id = id, + name = name, + sourcePath = sourcePath, + imageType = imageType, + targetFolder = targetFolder, + originLocations = originLocations, + customFields = CustomFieldMap(customFields), + created = kotlinx.datetime.Clock.System.now(), + lastUpdated = kotlinx.datetime.Clock.System.now(), + options = null, + metadata = emptyMap(), + skip = SkipOptions(false, null, null), + alternateText = null, ) } @@ -107,14 +138,14 @@ fun aBlockModel( type: DocumentObjectType = DocumentObjectType.Block, baseTemplate: String? = null, options: DocumentObjectOptions? = null, -): DocumentObjectModel { - return DocumentObjectModel( +): DocumentObject { + return DocumentObject( id = id, content = content, name = name ?: "block$id", type = type, internal = internal, - targetFolder = targetFolder?.let(IcmPath::from), + targetFolder = targetFolder?.let { IcmPath.from(it).toString() }, originLocations = originLocations, customFields = CustomFieldMap(customFields), created = Clock.System.now(), @@ -122,7 +153,7 @@ fun aBlockModel( displayRuleRef = null, baseTemplate = baseTemplate, options = options, - metadata = emptyMap(), + metadata = emptyMap>(), skip = SkipOptions(false, null, null), subject = null, ) @@ -191,6 +222,8 @@ fun aVariable( name = name, originLocations = originLocations, customFields = CustomFieldMap(customFields), + created = kotlinx.datetime.Clock.System.now(), + lastUpdated = kotlinx.datetime.Clock.System.now(), dataType = dataType, defaultValue = defaultValue ) @@ -237,6 +270,8 @@ fun aParagraphStyle( name = name, originLocations = originLocations, customFields = CustomFieldMap(customFields), + created = kotlinx.datetime.Clock.System.now(), + lastUpdated = kotlinx.datetime.Clock.System.now(), definition = definition ) } @@ -281,6 +316,8 @@ fun aTextStyle( name = name, originLocations = originLocations, customFields = CustomFieldMap(customFields), + created = kotlinx.datetime.Clock.System.now(), + lastUpdated = kotlinx.datetime.Clock.System.now(), definition = definition ) } diff --git a/migration-library/src/test/kotlin/com/quadient/migration/tools/model/TestModelObjectBuilders.kt b/migration-library/src/test/kotlin/com/quadient/migration/tools/model/TestModelObjectBuilders.kt index f31dd524..34c6c86e 100644 --- a/migration-library/src/test/kotlin/com/quadient/migration/tools/model/TestModelObjectBuilders.kt +++ b/migration-library/src/test/kotlin/com/quadient/migration/tools/model/TestModelObjectBuilders.kt @@ -1,32 +1,35 @@ package com.quadient.migration.tools.model -import com.quadient.migration.data.AreaModel -import com.quadient.migration.data.DisplayRuleModel -import com.quadient.migration.data.DisplayRuleModelRef -import com.quadient.migration.data.DocumentContentModel -import com.quadient.migration.data.DocumentObjectModel -import com.quadient.migration.data.DocumentObjectModelRef -import com.quadient.migration.data.FileModel -import com.quadient.migration.data.ImageModel -import com.quadient.migration.data.ParagraphModel -import com.quadient.migration.data.ParagraphModel.TextModel -import com.quadient.migration.data.ParagraphStyleDefOrRefModel -import com.quadient.migration.data.ParagraphStyleDefinitionModel -import com.quadient.migration.data.ParagraphStyleModel -import com.quadient.migration.data.ParagraphStyleModelRef -import com.quadient.migration.data.SelectByLanguageModel -import com.quadient.migration.data.StringModel -import com.quadient.migration.data.TableModel -import com.quadient.migration.data.TabsModel -import com.quadient.migration.data.TextContentModel -import com.quadient.migration.data.TextStyleDefOrRefModel -import com.quadient.migration.data.TextStyleDefinitionModel -import com.quadient.migration.data.TextStyleModel -import com.quadient.migration.data.TextStyleModelRef -import com.quadient.migration.data.VariableModel -import com.quadient.migration.data.VariableModelRef -import com.quadient.migration.data.VariableStructureModel -import com.quadient.migration.data.VariableStructureModelRef +import com.quadient.migration.api.dto.migrationmodel.Area +import com.quadient.migration.api.dto.migrationmodel.CustomFieldMap +import com.quadient.migration.api.dto.migrationmodel.DisplayRule +import com.quadient.migration.api.dto.migrationmodel.DisplayRuleRef +import com.quadient.migration.api.dto.migrationmodel.DocumentContent +import com.quadient.migration.api.dto.migrationmodel.DocumentObject +import com.quadient.migration.api.dto.migrationmodel.DocumentObjectRef +import com.quadient.migration.api.dto.migrationmodel.File +import com.quadient.migration.api.dto.migrationmodel.FirstMatch +import com.quadient.migration.api.dto.migrationmodel.Image +import com.quadient.migration.api.dto.migrationmodel.ImageRef +import com.quadient.migration.api.dto.migrationmodel.Paragraph +import com.quadient.migration.api.dto.migrationmodel.Paragraph.Text +import com.quadient.migration.api.dto.migrationmodel.ParagraphStyleDefOrRef +import com.quadient.migration.api.dto.migrationmodel.ParagraphStyleDefinition +import com.quadient.migration.api.dto.migrationmodel.ParagraphStyle +import com.quadient.migration.api.dto.migrationmodel.ParagraphStyleRef +import com.quadient.migration.api.dto.migrationmodel.SelectByLanguage +import com.quadient.migration.api.dto.migrationmodel.StringValue +import com.quadient.migration.api.dto.migrationmodel.Table +import com.quadient.migration.api.dto.migrationmodel.Tabs +import com.quadient.migration.api.dto.migrationmodel.TextContent +import com.quadient.migration.api.dto.migrationmodel.TextStyleDefOrRef +import com.quadient.migration.api.dto.migrationmodel.TextStyleDefinition +import com.quadient.migration.api.dto.migrationmodel.TextStyle +import com.quadient.migration.api.dto.migrationmodel.TextStyleRef +import com.quadient.migration.api.dto.migrationmodel.Variable +import com.quadient.migration.api.dto.migrationmodel.VariableRef +import com.quadient.migration.api.dto.migrationmodel.VariableStructure +import com.quadient.migration.api.dto.migrationmodel.VariableStructureRef import com.quadient.migration.persistence.repository.DisplayRuleInternalRepository import com.quadient.migration.persistence.repository.DocumentObjectInternalRepository import com.quadient.migration.persistence.repository.FileInternalRepository @@ -74,30 +77,30 @@ import kotlin.collections.emptyMap fun aDocObj( id: String, type: DocumentObjectType = DocumentObjectType.Block, - content: List = emptyList(), + content: List = emptyList(), internal: Boolean = false, name: String? = id + "name", targetFolder: String? = null, options: DocumentObjectOptions? = null, displayRuleRef: String? = null, baseTemplate: String? = null, - variableStructureModelRef: String? = null, + VariableStructureRef: String? = null, metadata: Map> = emptyMap(), -): DocumentObjectModel { - return DocumentObjectModel( +): DocumentObject { + return DocumentObject( id = id, name = name, type = type, content = content, internal = internal, - targetFolder = targetFolder?.let(IcmPath::from), + targetFolder = targetFolder?.let { IcmPath.from(it).toString() }, originLocations = emptyList(), - customFields = emptyMap(), + customFields = CustomFieldMap(), created = Clock.System.now(), lastUpdated = Clock.System.now(), - displayRuleRef = displayRuleRef?.let { DisplayRuleModelRef(it) }, + displayRuleRef = displayRuleRef?.let { DisplayRuleRef(it) }, baseTemplate = baseTemplate, - variableStructureRef = variableStructureModelRef?.let { VariableStructureModelRef(it) }, + variableStructureRef = VariableStructureRef?.let { VariableStructureRef(it) }, options = options, metadata = metadata, skip = SkipOptions(false, null, null), @@ -107,7 +110,7 @@ fun aDocObj( fun aBlock( id: String = "block", - content: List = emptyList(), + content: List = emptyList(), name: String? = null, internal: Boolean = false, targetFolder: String? = null, @@ -116,20 +119,20 @@ fun aBlock( created: Instant = Clock.System.now(), lastUpdated: Instant = Clock.System.now(), type: DocumentObjectType = DocumentObjectType.Block, - displayRuleRef: DisplayRuleModelRef? = null, + displayRuleRef: DisplayRuleRef? = null, baseTemplate: String? = null, metadata : Map> = emptyMap(), skip: SkipOptions = SkipOptions(false, null, null), -): DocumentObjectModel { - return DocumentObjectModel( +): DocumentObject { + return DocumentObject( id = id, name = name, type = type, content = content, internal = internal, - targetFolder = targetFolder?.let(IcmPath::from), + targetFolder = targetFolder, originLocations = originLocations, - customFields = customFields, + customFields = CustomFieldMap(customFields), created = created, lastUpdated = lastUpdated, displayRuleRef = displayRuleRef, @@ -142,19 +145,19 @@ fun aBlock( } fun anArea( - content: List, + content: List, position: Position? = null, interactiveFlowName: String? = null, -): AreaModel { - return AreaModel(content, position, interactiveFlowName) +): Area { + return Area(content, position, interactiveFlowName) } fun aTemplate( id: String, - content: List, + content: List, baseTemplate: String? = null, -): DocumentObjectModel { - return DocumentObjectModel( +): DocumentObject { + return DocumentObject( id = id, name = null, type = DocumentObjectType.Template, @@ -162,7 +165,7 @@ fun aTemplate( internal = false, targetFolder = null, originLocations = emptyList(), - customFields = emptyMap(), + customFields = CustomFieldMap(), created = Clock.System.now(), lastUpdated = Clock.System.now(), baseTemplate = baseTemplate, @@ -180,11 +183,11 @@ fun aVariable( customFields: MutableMap = mutableMapOf(), dataType: DataType = DataType.String, defaultValue: String? = null -) = VariableModel( +) = Variable( id = id, name = name, originLocations = originLocations, - customFields = customFields, + customFields = CustomFieldMap(customFields), dataType = dataType, defaultValue = defaultValue, lastUpdated = Clock.System.now(), @@ -196,13 +199,13 @@ fun aParaStyle( name: String? = "style$id", originLocations: List = emptyList(), customFields: MutableMap = mutableMapOf(), - definition: ParagraphStyleDefOrRefModel = aParaDef() -): ParagraphStyleModel { - return ParagraphStyleModel( + definition: ParagraphStyleDefOrRef = aParaDef() +): ParagraphStyle { + return ParagraphStyle( id = id, name = name, originLocations = originLocations, - customFields = customFields, + customFields = CustomFieldMap(customFields), definition = definition, lastUpdated = Clock.System.now(), created = Clock.System.now(), @@ -219,10 +222,10 @@ fun aParaDef( firstLineIndent: Size? = null, lineSpacing: LineSpacing = LineSpacing.Additional(null), keepWithNextParagraph: Boolean? = null, - tabs: TabsModel? = null, + tabs: Tabs? = null, pdfTaggingRule: ParagraphPdfTaggingRule? = null, -): ParagraphStyleDefinitionModel { - return ParagraphStyleDefinitionModel( +): ParagraphStyleDefinition { + return ParagraphStyleDefinition( leftIndent = leftIndent, rightIndent = rightIndent, defaultTabSize = defaultTabSize, @@ -242,13 +245,13 @@ fun aTextStyle( name: String? = "style$id", originLocations: List = emptyList(), customFields: MutableMap = mutableMapOf(), - definition: TextStyleDefOrRefModel = aTextDef(), -): TextStyleModel { - return TextStyleModel( + definition: TextStyleDefOrRef = aTextDef(), +): TextStyle { + return TextStyle( id = id, name = name, originLocations = originLocations, - customFields = customFields, + customFields = CustomFieldMap(customFields), definition = definition, lastUpdated = Clock.System.now(), created = Clock.System.now(), @@ -265,8 +268,8 @@ fun aTextDef( strikethrough: Boolean = false, superOrSubscript: SuperOrSubscript = SuperOrSubscript.None, interspacing: Size? = null, -): TextStyleDefinitionModel { - return TextStyleDefinitionModel( +): TextStyleDefinition { + return TextStyleDefinition( fontFamily = fontFamily, foregroundColor = foregroundColor, size = size, @@ -279,24 +282,24 @@ fun aTextDef( ) } -fun aVariableStructureModel( +fun aVariableStructure( id: String = "variableStructure", name: String? = "variableStructureName", originLocations: List = emptyList(), customFields: MutableMap = mutableMapOf(), - structure: Map = emptyMap(), + structure: Map = emptyMap(), languageVariable: String? = null, lastUpdated: Instant = Clock.System.now(), -): VariableStructureModel { - return VariableStructureModel( +): VariableStructure { + return VariableStructure( id = id, name = name, originLocations = originLocations, - customFields = customFields, + customFields = CustomFieldMap(customFields), lastUpdated = lastUpdated, created = Clock.System.now(), structure = structure, - languageVariable = languageVariable?.let { VariableModelRef(it) } + languageVariable = languageVariable?.let { VariableRef(it) } ) } @@ -306,12 +309,12 @@ fun aDisplayRule( originLocations: List = emptyList(), customFields: MutableMap = mutableMapOf(), definition: DisplayRuleDefinition? = null -): DisplayRuleModel { - return DisplayRuleModel( +): DisplayRule { + return DisplayRule( id = id, name = name, originLocations = originLocations, - customFields = customFields, + customFields = CustomFieldMap(customFields), lastUpdated = Clock.System.now(), created = Clock.System.now(), definition = definition @@ -325,7 +328,7 @@ fun aDisplayRule( groupOp: GroupOp = GroupOp.And, negation: Boolean = false, id: String = "R_1", -): DisplayRuleModel { +): DisplayRule { return aDisplayRule( id, definition = DisplayRuleDefinition( Group( @@ -336,44 +339,44 @@ fun aDisplayRule( } fun aParagraph( - content: List = listOf(), - styleRef: ParagraphStyleModelRef? = null, - displayRuleRef: DisplayRuleModelRef? = null -): ParagraphModel = ParagraphModel(content, styleRef, displayRuleRef) + content: List = listOf(), + styleRef: ParagraphStyleRef? = null, + displayRuleRef: DisplayRuleRef? = null +): Paragraph = Paragraph(content, styleRef, displayRuleRef) fun aParagraph( - content: TextModel, styleRef: String? = null, displayRuleRef: DisplayRuleModelRef? = null -): ParagraphModel = ParagraphModel(listOf(content), styleRef?.let { ParagraphStyleModelRef(it) }, displayRuleRef) + content: Text, styleRef: String? = null, displayRuleRef: DisplayRuleRef? = null +): Paragraph = Paragraph(listOf(content), styleRef?.let { ParagraphStyleRef(it) }, displayRuleRef) -fun aParagraph(string: String): ParagraphModel = aParagraph(aText(string)) +fun aParagraph(string: String): Paragraph = aParagraph(aText(string)) -fun aText(string: String): TextModel = TextModel(listOf(StringModel(string)), null, null) +fun aText(string: String): Text = Text(listOf(StringValue(string)), null, null) fun aText( - content: List = listOf(), - styleRef: TextStyleModelRef? = null, - displayRuleRef: DisplayRuleModelRef? = null -): TextModel = TextModel(content, styleRef, displayRuleRef) + content: List = listOf(), + styleRef: TextStyleRef? = null, + displayRuleRef: DisplayRuleRef? = null +): Text = Text(content, styleRef, displayRuleRef) fun aText( - content: TextContentModel, styleRef: String? = null, displayRuleRef: DisplayRuleModelRef? = null -): TextModel = TextModel(listOf(content), styleRef?.let { TextStyleModelRef(it) }, displayRuleRef) + content: TextContent, styleRef: String? = null, displayRuleRef: DisplayRuleRef? = null +): Text = Text(listOf(content), styleRef?.let { TextStyleRef(it) }, displayRuleRef) fun aRow( - cells: List, displayRuleRef: String? = null -): TableModel.RowModel { - return TableModel.RowModel(cells, displayRuleRef?.let { DisplayRuleModelRef(it) }) + cells: List, displayRuleRef: String? = null +): Table.Row { + return Table.Row(cells, displayRuleRef?.let { DisplayRuleRef(it) }) } -fun aCell(content: DocumentContentModel, mergeLeft: Boolean = false, mergeUp: Boolean = false): TableModel.CellModel { - return TableModel.CellModel(listOf(content), mergeLeft, mergeUp) +fun aCell(content: DocumentContent, mergeLeft: Boolean = false, mergeUp: Boolean = false): Table.Cell { + return Table.Cell(listOf(content), mergeLeft, mergeUp) } fun aSelectByLanguage( - cases: Map> = emptyMap() -): SelectByLanguageModel { - return SelectByLanguageModel( - cases = cases.entries.map { SelectByLanguageModel.CaseModel(it.key, it.value) } + cases: Map> = emptyMap() +): SelectByLanguage { + return SelectByLanguage( + cases = cases.entries.map { SelectByLanguage.Case(it.value, it.key) } ) } @@ -389,17 +392,18 @@ fun aImage( metadata : Map> = emptyMap(), skip : SkipOptions = SkipOptions(false, null, null), alternateText: String? = null, -): ImageModel { - return ImageModel( +): Image { + return Image( id = id, name = name, originLocations = originLocations, - customFields = customFields, + customFields = CustomFieldMap(customFields), created = Clock.System.now(), + lastUpdated = Clock.System.now(), sourcePath = sourcePath, imageType = imageType, options = options, - targetFolder = targetFolder?.let(IcmPath::from), + targetFolder = targetFolder, metadata = metadata, skip = skip, alternateText = alternateText, @@ -415,22 +419,23 @@ fun aFile( customFields: MutableMap = mutableMapOf(), targetFolder: String? = null, skip: SkipOptions = SkipOptions(false, null, null), -): FileModel { - return FileModel( +): File { + return File( id = id, name = name, originLocations = originLocations, - customFields = customFields, + customFields = CustomFieldMap(customFields), created = Clock.System.now(), + lastUpdated = Clock.System.now(), sourcePath = sourcePath, fileType = fileType, - targetFolder = targetFolder?.let(IcmPath::from), + targetFolder = targetFolder, skip = skip, ) } fun aDocumentObjectRef(id: String, displayRuleId: String? = null) = - DocumentObjectModelRef(id, displayRuleId?.let { DisplayRuleModelRef(it) }) + DocumentObjectRef(id, displayRuleId?.let { DisplayRuleRef(it) }) fun aDocumentObjectInternalRepository() = DocumentObjectInternalRepository(DocumentObjectTable, aProjectConfig().name) fun aVariableInternalRepository() = VariableInternalRepository(VariableTable, aProjectConfig().name) @@ -441,4 +446,7 @@ fun aParaStyleInternalRepository() = ParagraphStyleInternalRepository(ParagraphS fun aTextStyleInternalRepository() = TextStyleInternalRepository(TextStyleTable, aProjectConfig().name) fun aDisplayRuleInternalRepository() = DisplayRuleInternalRepository(DisplayRuleTable, aProjectConfig().name) fun aImageInternalRepository() = ImageInternalRepository(ImageTable, aProjectConfig().name) -fun aFileInternalRepository() = FileInternalRepository(FileTable, aProjectConfig().name) \ No newline at end of file +fun aFileInternalRepository() = FileInternalRepository(FileTable, aProjectConfig().name) + + + From 01af1a566791404a12759a969ed124834d45ef0c Mon Sep 17 00:00:00 2001 From: "d.svitak" Date: Thu, 5 Feb 2026 15:29:57 +0100 Subject: [PATCH 2/9] first batch of changes on a way to remove model layer from migration-library (add remaining) --- .../service/deploy/DeployClientTest.kt | 33 ++++++++------- .../deploy/DesignerDeployClientTest.kt | 42 +++++++++---------- 2 files changed, 38 insertions(+), 37 deletions(-) diff --git a/migration-library/src/test/kotlin/com/quadient/migration/service/deploy/DeployClientTest.kt b/migration-library/src/test/kotlin/com/quadient/migration/service/deploy/DeployClientTest.kt index 2ad85e11..7f21e18a 100644 --- a/migration-library/src/test/kotlin/com/quadient/migration/service/deploy/DeployClientTest.kt +++ b/migration-library/src/test/kotlin/com/quadient/migration/service/deploy/DeployClientTest.kt @@ -4,14 +4,14 @@ package com.quadient.migration.service.deploy import com.quadient.migration.api.dto.migrationmodel.StatusTracking import com.quadient.migration.api.repository.StatusTrackingRepository -import com.quadient.migration.data.DocumentObjectModel -import com.quadient.migration.data.DocumentObjectModelRef -import com.quadient.migration.data.FileModelRef -import com.quadient.migration.data.ImageModelRef -import com.quadient.migration.data.ParagraphModel -import com.quadient.migration.data.ParagraphStyleModelRef +import com.quadient.migration.api.dto.migrationmodel.DocumentObject +import com.quadient.migration.api.dto.migrationmodel.DocumentObjectRef +import com.quadient.migration.api.dto.migrationmodel.FileRef +import com.quadient.migration.api.dto.migrationmodel.ImageRef +import com.quadient.migration.api.dto.migrationmodel.Paragraph +import com.quadient.migration.api.dto.migrationmodel.ParagraphStyleRef import com.quadient.migration.data.StatusEvent -import com.quadient.migration.data.TextStyleModelRef +import com.quadient.migration.api.dto.migrationmodel.TextStyleRef import com.quadient.migration.persistence.repository.DocumentObjectInternalRepository import com.quadient.migration.persistence.repository.FileInternalRepository import com.quadient.migration.persistence.repository.ImageInternalRepository @@ -505,7 +505,7 @@ class DeployClientTest { ) } - val externalObjects = mutableListOf() + val externalObjects = mutableListOf() private fun givenExternalDocumentObject( id: String, deps: List = listOf(), @@ -517,18 +517,18 @@ class DeployClientTest { ) { externalObjects.add( aBlock(id = id, internal = false, content = deps.map { - DocumentObjectModelRef( + DocumentObjectRef( it, null ) - } + imageDeps.map { ImageModelRef(it) } + fileDeps.map { FileModelRef(it) } + textStyles.map { - ParagraphModel( + } + imageDeps.map { ImageRef(it) } + fileDeps.map { FileRef(it) } + textStyles.map { + Paragraph( listOf( - ParagraphModel.TextModel( - emptyList(), TextStyleModelRef(it), null + Paragraph.Text( + emptyList(), TextStyleRef(it), null ) ), null, null ) - } + paragraphStyles.map { ParagraphModel(emptyList(), ParagraphStyleModelRef(it), null) }) + } + paragraphStyles.map { Paragraph(emptyList(), ParagraphStyleRef(it), null) }) ) every { documentObjectRepository.list(any()) } returns externalObjects every { @@ -546,6 +546,7 @@ class DeployClientTest { private fun givenInternalDocumentObject(id: String, deps: List = listOf()) { every { documentObjectRepository.findModelOrFail(id) } returns aBlock( - id = id, internal = true, content = deps.map { DocumentObjectModelRef(it, null) }) + id = id, internal = true, content = deps.map { DocumentObjectRef(it, null) }) } -} \ No newline at end of file +} + diff --git a/migration-library/src/test/kotlin/com/quadient/migration/service/deploy/DesignerDeployClientTest.kt b/migration-library/src/test/kotlin/com/quadient/migration/service/deploy/DesignerDeployClientTest.kt index a1f0b0c9..9a4cd92f 100644 --- a/migration-library/src/test/kotlin/com/quadient/migration/service/deploy/DesignerDeployClientTest.kt +++ b/migration-library/src/test/kotlin/com/quadient/migration/service/deploy/DesignerDeployClientTest.kt @@ -6,13 +6,13 @@ import com.quadient.migration.api.InspireOutput import com.quadient.migration.api.repository.StatusTrackingRepository import com.quadient.migration.data.Active import com.quadient.migration.data.Deployed -import com.quadient.migration.data.DocumentObjectModel +import com.quadient.migration.api.dto.migrationmodel.DocumentObject import com.quadient.migration.data.Error -import com.quadient.migration.data.FileModel -import com.quadient.migration.data.FileModelRef -import com.quadient.migration.data.ImageModel -import com.quadient.migration.data.ImageModelRef -import com.quadient.migration.data.StringModel +import com.quadient.migration.api.dto.migrationmodel.File +import com.quadient.migration.api.dto.migrationmodel.FileRef +import com.quadient.migration.api.dto.migrationmodel.Image +import com.quadient.migration.api.dto.migrationmodel.ImageRef +import com.quadient.migration.api.dto.migrationmodel.StringValue import com.quadient.migration.persistence.repository.DocumentObjectInternalRepository import com.quadient.migration.persistence.repository.FileInternalRepository import com.quadient.migration.persistence.repository.ImageInternalRepository @@ -79,7 +79,7 @@ class DesignerDeployClientTest { @BeforeEach fun setupAll() { every { documentObjectBuilder.shouldIncludeInternalDependency(any()) } answers { - val documentObject = firstArg() + val documentObject = firstArg() documentObject.internal || documentObject.type == DocumentObjectType.Page } every { ipsService.writeMetadata(any()) } just runs @@ -94,14 +94,14 @@ class DesignerDeployClientTest { val externalBlock = mockObj( aDocObj( "Txt_Img_File_1", DocumentObjectType.Block, listOf( - aParagraph(aText(StringModel("Image: "))), ImageModelRef(image1.id), - aParagraph(aText(StringModel("File: "))), FileModelRef(file1.id) + aParagraph(aText(StringValue("Image: "))), ImageRef(image1.id), + aParagraph(aText(StringValue("File: "))), FileRef(file1.id) ) ) ) val internalBlock = mockObj( aDocObj( - "Img_2", DocumentObjectType.Block, listOf(ImageModelRef(image2.id)), internal = true + "Img_2", DocumentObjectType.Block, listOf(ImageRef(image2.id)), internal = true ) ) val page = mockObj( @@ -338,7 +338,7 @@ class DesignerDeployClientTest { verify(exactly = 1) { ipsService.xml2wfd(any(), "icm://${template.nameOrId()}") } } - private fun mockImg(image: ImageModel, success: Boolean = true): ImageModel { + private fun mockImg(image: Image, success: Boolean = true): Image { val imagePath = "icm://${image.nameOrId()}" every { documentObjectBuilder.getImagePath(image) } returns imagePath @@ -358,7 +358,7 @@ class DesignerDeployClientTest { return image } - private fun mockFile(file: FileModel, success: Boolean = true): FileModel { + private fun mockFile(file: File, success: Boolean = true): File { val filePath = "icm://${file.nameOrId()}" every { documentObjectBuilder.getFilePath(file) } returns filePath @@ -378,7 +378,7 @@ class DesignerDeployClientTest { return file } - private fun mockObj(documentObject: DocumentObjectModel): DocumentObjectModel { + private fun mockObj(documentObject: DocumentObject): DocumentObject { every { documentObjectRepository.findModel(documentObject.id) } returns documentObject if (documentObject.internal == false) { @@ -407,9 +407,9 @@ class DesignerDeployClientTest { fun `deployDocumentObjects does not do anything when all objects are deployed`() { // given val docObjects = listOf( - aDocObj("D_1", content = listOf(ImageModelRef("I_1"))), - aDocObj("D_2", content = listOf(ImageModelRef("I_2"))), - aDocObj("D_3", content = listOf(ImageModelRef("I_3"))), + aDocObj("D_1", content = listOf(ImageRef("I_1"))), + aDocObj("D_2", content = listOf(ImageRef("I_2"))), + aDocObj("D_3", content = listOf(ImageRef("I_3"))), ) givenObjectIsDeployed("D_1") givenObjectIsDeployed("I_1") @@ -430,9 +430,9 @@ class DesignerDeployClientTest { fun `deployDocumentObjects skips deployed but deploys active and error`() { // given val docObjects = listOf( - aDocObj("D_1", content = listOf(ImageModelRef("I_1"))), - aDocObj("D_2", content = listOf(ImageModelRef("I_2"))), - aDocObj("D_3", content = listOf(ImageModelRef("I_3"))), + aDocObj("D_1", content = listOf(ImageRef("I_1"))), + aDocObj("D_2", content = listOf(ImageRef("I_2"))), + aDocObj("D_3", content = listOf(ImageRef("I_3"))), ) mockImg(aImage("I_1")) mockImg(aImage("I_2")) @@ -461,7 +461,7 @@ class DesignerDeployClientTest { @Test fun `deployDocumentObjects records errors`() { // given - val docObjects = listOf(aDocObj("D_1", content = listOf(ImageModelRef("I_1")))) + val docObjects = listOf(aDocObj("D_1", content = listOf(ImageRef("I_1")))) givenObjectIsActive("D_1") givenObjectIsActive("I_1") mockImg(aImage("I_1"), success = false) @@ -592,4 +592,4 @@ class DesignerDeployClientTest { ) } } -} \ No newline at end of file +} From d2087990ee83369e270a485d323e7fcebd2a0909 Mon Sep 17 00:00:00 2001 From: "d.svitak" Date: Fri, 6 Feb 2026 08:16:28 +0100 Subject: [PATCH 3/9] second batch of changes on a way to remove model layer from migration-library --- .../com/quadient/migration/api/Migration.kt | 100 +++-- .../api/repository/DisplayRuleRepository.kt | 34 +- .../repository/DocumentObjectRepository.kt | 34 +- .../api/repository/FileRepository.kt | 33 +- .../api/repository/ImageRepository.kt | 33 +- .../repository/ParagraphStyleRepository.kt | 64 ++-- .../migration/api/repository/Repository.kt | 145 +++++++- .../api/repository/TextStyleRepository.kt | 45 ++- .../api/repository/VariableRepository.kt | 34 +- .../repository/VariableStructureRepository.kt | 34 +- .../DisplayRuleInternalRepository.kt | 13 - .../DocumentObjectInternalRepository.kt | 12 - .../repository/FileInternalRepository.kt | 13 - .../repository/ImageInternalRepository.kt | 13 - .../repository/InternalRepository.kt | 134 ------- .../ParagraphStyleInternalRepository.kt | 25 -- .../repository/TextStyleInternalRepository.kt | 25 -- .../repository/VariableInternalRepository.kt | 13 - .../VariableStructureInternalRepository.kt | 12 - .../migration/service/ReferenceValidator.kt | 75 ++-- .../migration/service/StylesValidator.kt | 22 +- .../migration/service/deploy/DeployClient.kt | 37 +- .../service/deploy/DesignerDeployClient.kt | 23 +- .../service/deploy/InteractiveDeployClient.kt | 27 +- .../DesignerDocumentObjectBuilder.kt | 43 +-- .../InspireDocumentObjectBuilder.kt | 64 ++-- .../InteractiveDocumentObjectBuilder.kt | 31 +- .../persistence/DisplayRuleRepositoryTest.kt | 4 - .../DocumentObjectRepositoryTest.kt | 10 +- .../persistence/FileRepositoryTest.kt | 10 +- .../persistence/ImageRepositoryTest.kt | 11 +- .../ParargraphStyleRepositoryTest.kt | 6 - .../service/ReferenceValidatorTest.kt | 36 +- .../migration/service/StylesValidatorTest.kt | 23 +- .../service/deploy/DeployClientTest.kt | 51 +-- .../deploy/DesignerDeployClientTest.kt | 95 ++--- .../deploy/InteractiveDeployClientTest.kt | 197 +++++----- .../DesignerDocumentObjectBuilderTest.kt | 187 +++++----- .../InspireDocumentObjectBuilderTest.kt | 92 ++--- .../InteractiveDocumentObjectBuilderTest.kt | 349 +++++++++--------- .../migration/tools/TestObjectBuilders.kt | 36 +- .../tools/model/TestModelObjectBuilders.kt | 30 -- 42 files changed, 1019 insertions(+), 1256 deletions(-) delete mode 100644 migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/DisplayRuleInternalRepository.kt delete mode 100644 migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/DocumentObjectInternalRepository.kt delete mode 100644 migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/FileInternalRepository.kt delete mode 100644 migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/ImageInternalRepository.kt delete mode 100644 migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/InternalRepository.kt delete mode 100644 migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/ParagraphStyleInternalRepository.kt delete mode 100644 migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/TextStyleInternalRepository.kt delete mode 100644 migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/VariableInternalRepository.kt delete mode 100644 migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/VariableStructureInternalRepository.kt diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/Migration.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/Migration.kt index beccdfcd..ad4847de 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/Migration.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/Migration.kt @@ -66,24 +66,14 @@ class Migration(public val config: MigConfig, public val projectConfig: ProjectC .load() .migrate() - val documentObjectInternalRepository = DocumentObjectInternalRepository(DocumentObjectTable, projectName) - val imageInternalRepository = ImageInternalRepository(ImageTable, projectName) - val fileInternalRepository = FileInternalRepository(FileTable, projectName) - val displayRuleInternalRepository = DisplayRuleInternalRepository(DisplayRuleTable, projectName) - val variableInternalRepository = VariableInternalRepository(VariableTable, projectName) - val variableStructureInternalRepository = - VariableStructureInternalRepository(VariableStructureTable, projectName) - val textStyleInternalRepository = TextStyleInternalRepository(TextStyleTable, projectName) - val paragraphStyleInternalRepository = ParagraphStyleInternalRepository(ParagraphStyleTable, projectName) - - val variableRepository = VariableRepository(variableInternalRepository) - val documentObjectRepository = DocumentObjectRepository(documentObjectInternalRepository) - val textStyleRepository = TextStyleRepository(textStyleInternalRepository) - val paragraphStyleRepository = ParagraphStyleRepository(paragraphStyleInternalRepository) - val variableStructureRepository = VariableStructureRepository(variableStructureInternalRepository) - val displayRuleRepository = DisplayRuleRepository(displayRuleInternalRepository) - val imageRepository = ImageRepository(imageInternalRepository) - val fileRepository = FileRepository(fileInternalRepository) + val variableRepository = VariableRepository(VariableTable, projectName) + val documentObjectRepository = DocumentObjectRepository(DocumentObjectTable, projectName) + val textStyleRepository = TextStyleRepository(TextStyleTable, projectName) + val paragraphStyleRepository = ParagraphStyleRepository(ParagraphStyleTable, projectName) + val variableStructureRepository = VariableStructureRepository(VariableStructureTable, projectName) + val displayRuleRepository = DisplayRuleRepository(DisplayRuleTable, projectName) + val imageRepository = ImageRepository(ImageTable, projectName) + val fileRepository = FileRepository(FileTable, projectName) this.variableRepository = variableRepository this.documentObjectRepository = documentObjectRepository @@ -115,39 +105,39 @@ class Migration(public val config: MigConfig, public val projectConfig: ProjectC repositories.add(fileRepository) this.referenceValidator = ReferenceValidator( - documentObjectInternalRepository, - variableInternalRepository, - textStyleInternalRepository, - paragraphStyleInternalRepository, - variableStructureInternalRepository, - displayRuleInternalRepository, - imageInternalRepository, - fileInternalRepository, + documentObjectRepository, + variableRepository, + textStyleRepository, + paragraphStyleRepository, + variableStructureRepository, + displayRuleRepository, + imageRepository, + fileRepository, ) val inspireDocumentObjectBuilder: InspireDocumentObjectBuilder this.deployClient = if (projectConfig.inspireOutput == InspireOutput.Interactive || projectConfig.inspireOutput == InspireOutput.Evolve) { inspireDocumentObjectBuilder = InteractiveDocumentObjectBuilder( - documentObjectInternalRepository, - textStyleInternalRepository, - paragraphStyleInternalRepository, - variableInternalRepository, - variableStructureInternalRepository, - displayRuleInternalRepository, - imageInternalRepository, - fileInternalRepository, + documentObjectRepository, + textStyleRepository, + paragraphStyleRepository, + variableRepository, + variableStructureRepository, + displayRuleRepository, + imageRepository, + fileRepository, projectConfig, ipsService, ) InteractiveDeployClient( - documentObjectInternalRepository, - imageInternalRepository, - fileInternalRepository, + documentObjectRepository, + imageRepository, + fileRepository, statusTrackingRepository, - textStyleInternalRepository, - paragraphStyleInternalRepository, + textStyleRepository, + paragraphStyleRepository, inspireDocumentObjectBuilder, ipsService, storage, @@ -155,25 +145,25 @@ class Migration(public val config: MigConfig, public val projectConfig: ProjectC ) } else { inspireDocumentObjectBuilder = DesignerDocumentObjectBuilder( - documentObjectInternalRepository, - textStyleInternalRepository, - paragraphStyleInternalRepository, - variableInternalRepository, - variableStructureInternalRepository, - displayRuleInternalRepository, - imageInternalRepository, - fileInternalRepository, + documentObjectRepository, + textStyleRepository, + paragraphStyleRepository, + variableRepository, + variableStructureRepository, + displayRuleRepository, + imageRepository, + fileRepository, projectConfig, ipsService, ) DesignerDeployClient( - documentObjectInternalRepository, - imageInternalRepository, - fileInternalRepository, + documentObjectRepository, + imageRepository, + fileRepository, statusTrackingRepository, - textStyleInternalRepository, - paragraphStyleInternalRepository, + textStyleRepository, + paragraphStyleRepository, inspireDocumentObjectBuilder, ipsService, storage, @@ -181,9 +171,9 @@ class Migration(public val config: MigConfig, public val projectConfig: ProjectC } this.stylesValidator = StylesValidator( - documentObjectInternalRepository, - textStyleInternalRepository, - paragraphStyleInternalRepository, + documentObjectRepository, + textStyleRepository, + paragraphStyleRepository, inspireDocumentObjectBuilder, deployClient, ipsService diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/DisplayRuleRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/DisplayRuleRepository.kt index a678c269..98665325 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/DisplayRuleRepository.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/DisplayRuleRepository.kt @@ -1,26 +1,26 @@ package com.quadient.migration.api.repository import com.quadient.migration.api.dto.migrationmodel.DisplayRule -import com.quadient.migration.api.dto.migrationmodel.DocumentObject import com.quadient.migration.api.dto.migrationmodel.MigrationObject -import com.quadient.migration.persistence.repository.InternalRepository import com.quadient.migration.persistence.table.DisplayRuleTable import com.quadient.migration.persistence.table.DocumentObjectTable import com.quadient.migration.tools.concat import kotlinx.datetime.Clock +import org.jetbrains.exposed.v1.core.ResultRow import org.jetbrains.exposed.v1.jdbc.selectAll import org.jetbrains.exposed.v1.jdbc.transactions.transaction import org.jetbrains.exposed.v1.jdbc.upsertReturning -class DisplayRuleRepository(internalRepository: InternalRepository) : - Repository(internalRepository) { - override fun toDto(model: DisplayRule): DisplayRule { - return model +class DisplayRuleRepository(table: DisplayRuleTable, projectName: String) : + Repository(table, projectName) { + + override fun fromDb(row: ResultRow): DisplayRule { + return DisplayRule.fromDb(row) } override fun findUsages(id: String): List { return transaction { - DocumentObjectTable.selectAll().where { DocumentObjectTable.projectName eq internalRepository.projectName } + DocumentObjectTable.selectAll().where { DocumentObjectTable.projectName eq projectName } .map { DocumentObjectTable.fromResultRow(it) } .filter { it.collectRefs().any { it.id == id } } .distinct() @@ -28,15 +28,13 @@ class DisplayRuleRepository(internalRepository: InternalRepository) } override fun upsertBatch(dtos: Collection) { - internalRepository.upsertBatch(dtos) { dto -> - val existingItem = - internalRepository.table.selectAll().where(internalRepository.filter(dto.id)).firstOrNull() - ?.let { internalRepository.toModel(it) } + upsertBatchInternal(dtos) { dto -> + val existingItem = table.selectAll().where(filter(dto.id)).firstOrNull()?.let(::fromDb) val now = Clock.System.now() this[DisplayRuleTable.id] = dto.id - this[DisplayRuleTable.projectName] = internalRepository.projectName + this[DisplayRuleTable.projectName] = projectName this[DisplayRuleTable.name] = dto.name this[DisplayRuleTable.originLocations] = existingItem?.originLocations.concat(dto.originLocations).distinct() this[DisplayRuleTable.customFields] = dto.customFields.inner @@ -47,18 +45,14 @@ class DisplayRuleRepository(internalRepository: InternalRepository) } override fun upsert(dto: DisplayRule) { - internalRepository.upsert { - val existingItem = - internalRepository.table.selectAll().where(internalRepository.filter(dto.id)).firstOrNull() - ?.let { internalRepository.toModel(it) } + upsertInternal { + val existingItem = table.selectAll().where(filter(dto.id)).firstOrNull()?.let(::fromDb) val now = Clock.System.now() - internalRepository.table.upsertReturning( - internalRepository.table.id, internalRepository.table.projectName - ) { + table.upsertReturning(table.id, table.projectName) { it[DisplayRuleTable.id] = dto.id - it[DisplayRuleTable.projectName] = internalRepository.projectName + it[DisplayRuleTable.projectName] = projectName it[DisplayRuleTable.name] = dto.name it[DisplayRuleTable.originLocations] = existingItem?.originLocations.concat(dto.originLocations).distinct() it[DisplayRuleTable.customFields] = dto.customFields.inner diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/DocumentObjectRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/DocumentObjectRepository.kt index 252f2598..ef4c9a7d 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/DocumentObjectRepository.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/DocumentObjectRepository.kt @@ -4,7 +4,6 @@ import com.quadient.migration.api.dto.migrationmodel.DocumentObject import com.quadient.migration.api.dto.migrationmodel.DocumentObjectFilter import com.quadient.migration.api.dto.migrationmodel.MigrationObject import com.quadient.migration.api.dto.migrationmodel.toDb -import com.quadient.migration.persistence.repository.DocumentObjectInternalRepository import com.quadient.migration.persistence.table.DocumentObjectTable import com.quadient.migration.service.deploy.ResourceType import com.quadient.migration.shared.DocumentObjectType @@ -12,6 +11,7 @@ import com.quadient.migration.shared.PageOptions import com.quadient.migration.tools.concat import kotlinx.datetime.Clock import org.jetbrains.exposed.v1.core.Op +import org.jetbrains.exposed.v1.core.ResultRow import org.jetbrains.exposed.v1.core.SqlExpressionBuilder.eq import org.jetbrains.exposed.v1.core.SqlExpressionBuilder.inList import org.jetbrains.exposed.v1.core.and @@ -20,29 +20,29 @@ import org.jetbrains.exposed.v1.jdbc.selectAll import org.jetbrains.exposed.v1.jdbc.transactions.transaction import org.jetbrains.exposed.v1.jdbc.upsertReturning -class DocumentObjectRepository(internalRepository: DocumentObjectInternalRepository) : - Repository(internalRepository) { - val statusTrackingRepository = StatusTrackingRepository(internalRepository.projectName) +class DocumentObjectRepository(table: DocumentObjectTable, projectName: String) : + Repository(table, projectName) { + val statusTrackingRepository = StatusTrackingRepository(projectName) fun list(documentObjectFilter: DocumentObjectFilter): List { - return internalRepository.list(filter(documentObjectFilter)).map(::toDto) + return list(filterByDocumentObjectFilter(documentObjectFilter)) } - override fun toDto(model: DocumentObject): DocumentObject = model + override fun fromDb(row: ResultRow): DocumentObject = DocumentObjectTable.fromResultRow(row) override fun findUsages(id: String): List { return transaction { - DocumentObjectTable.selectAll().where { DocumentObjectTable.projectName eq internalRepository.projectName } + DocumentObjectTable.selectAll().where { DocumentObjectTable.projectName eq projectName } .map { DocumentObjectTable.fromResultRow(it) }.filter { it.collectRefs().any { it.id == id } } .distinct() } } override fun upsertBatch(dtos: Collection) { - internalRepository.upsertBatch(dtos) { dto -> + upsertBatchInternal(dtos) { dto -> val now = Clock.System.now() - val existingItem = internalRepository.findModel(dto.id) + val existingItem = find(dto.id) when (dto.type) { DocumentObjectType.Page -> require(dto.options == null || dto.options is PageOptions) @@ -56,7 +56,7 @@ class DocumentObjectRepository(internalRepository: DocumentObjectInternalReposit } this[DocumentObjectTable.id] = dto.id - this[DocumentObjectTable.projectName] = internalRepository.projectName + this[DocumentObjectTable.projectName] = projectName this[DocumentObjectTable.type] = dto.type.name this[DocumentObjectTable.name] = dto.name this[DocumentObjectTable.content] = dto.content.toDb() @@ -77,8 +77,8 @@ class DocumentObjectRepository(internalRepository: DocumentObjectInternalReposit } override fun upsert(dto: DocumentObject) { - internalRepository.upsert { - val existingItem = internalRepository.findModel(dto.id) + upsertInternal { + val existingItem = find(dto.id) when (dto.type) { DocumentObjectType.Page -> require(dto.options == null || dto.options is PageOptions) @@ -93,11 +93,9 @@ class DocumentObjectRepository(internalRepository: DocumentObjectInternalReposit ) } - internalRepository.table.upsertReturning( - internalRepository.table.id, internalRepository.table.projectName - ) { + table.upsertReturning(table.id, table.projectName) { it[DocumentObjectTable.id] = dto.id - it[DocumentObjectTable.projectName] = internalRepository.projectName + it[DocumentObjectTable.projectName] = projectName it[DocumentObjectTable.type] = dto.type.name it[DocumentObjectTable.name] = dto.name it[DocumentObjectTable.content] = dto.content.toDb() @@ -118,8 +116,8 @@ class DocumentObjectRepository(internalRepository: DocumentObjectInternalReposit } } - private fun filter(filter: DocumentObjectFilter): Op { - var result = DocumentObjectTable.projectName eq internalRepository.projectName + private fun filterByDocumentObjectFilter(filter: DocumentObjectFilter): Op { + var result = DocumentObjectTable.projectName eq projectName if (filter.ids != null && filter.ids.isNotEmpty()) { result = result and (DocumentObjectTable.id inList filter.ids) } diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/FileRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/FileRepository.kt index 14ee6399..b92408c0 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/FileRepository.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/FileRepository.kt @@ -1,38 +1,35 @@ package com.quadient.migration.api.repository -import com.quadient.migration.api.dto.migrationmodel.DocumentObject import com.quadient.migration.api.dto.migrationmodel.File import com.quadient.migration.api.dto.migrationmodel.MigrationObject -import com.quadient.migration.persistence.repository.FileInternalRepository import com.quadient.migration.persistence.table.DocumentObjectTable import com.quadient.migration.persistence.table.FileTable import com.quadient.migration.service.deploy.ResourceType import com.quadient.migration.tools.concat import kotlinx.datetime.Clock +import org.jetbrains.exposed.v1.core.ResultRow import org.jetbrains.exposed.v1.jdbc.selectAll import org.jetbrains.exposed.v1.jdbc.transactions.transaction import org.jetbrains.exposed.v1.jdbc.upsertReturning -class FileRepository(internalRepository: FileInternalRepository) : Repository(internalRepository) { - val statusTrackingRepository = StatusTrackingRepository(internalRepository.projectName) +class FileRepository(table: FileTable, projectName: String) : Repository(table, projectName) { + val statusTrackingRepository = StatusTrackingRepository(projectName) - override fun toDto(model: File): File { - return model + override fun fromDb(row: ResultRow): File { + return File.fromDb(row) } override fun findUsages(id: String): List { return transaction { - DocumentObjectTable.selectAll().where { DocumentObjectTable.projectName eq internalRepository.projectName } + DocumentObjectTable.selectAll().where { DocumentObjectTable.projectName eq projectName } .map { DocumentObjectTable.fromResultRow(it) }.filter { it.collectRefs().any { it.id == id } } .distinct() } } override fun upsert(dto: File) { - internalRepository.upsert { - val existingItem = - internalRepository.table.selectAll().where(internalRepository.filter(dto.id)).firstOrNull() - ?.let { internalRepository.toModel(it) } + upsertInternal { + val existingItem = table.selectAll().where(filter(dto.id)).firstOrNull()?.let(::fromDb) val now = Clock.System.now() @@ -40,11 +37,9 @@ class FileRepository(internalRepository: FileInternalRepository) : Repository) { - internalRepository.upsertBatch(dtos) { dto -> - val existingItem = - internalRepository.table.selectAll().where(internalRepository.filter(dto.id)).firstOrNull() - ?.let { internalRepository.toModel(it) } + upsertBatchInternal(dtos) { dto -> + val existingItem = table.selectAll().where(filter(dto.id)).firstOrNull()?.let(::fromDb) val now = Clock.System.now() @@ -71,7 +64,7 @@ class FileRepository(internalRepository: FileInternalRepository) : Repository(internalRepository) { - val statusTrackingRepository = StatusTrackingRepository(internalRepository.projectName) +class ImageRepository(table: ImageTable, projectName: String) : Repository(table, projectName) { + val statusTrackingRepository = StatusTrackingRepository(projectName) - override fun toDto(model: Image): Image { - return model + override fun fromDb(row: ResultRow): Image { + return Image.fromDb(row) } override fun findUsages(id: String): List { return transaction { - DocumentObjectTable.selectAll().where { DocumentObjectTable.projectName eq internalRepository.projectName } + DocumentObjectTable.selectAll().where { DocumentObjectTable.projectName eq projectName } .map { DocumentObjectTable.fromResultRow(it) }.filter { it.collectRefs().any { it.id == id } } .distinct() } } override fun upsert(dto: Image) { - internalRepository.upsert { - val existingItem = - internalRepository.table.selectAll().where(internalRepository.filter(dto.id)).firstOrNull() - ?.let { internalRepository.toModel(it) } + upsertInternal { + val existingItem = table.selectAll().where(filter(dto.id)).firstOrNull()?.let(::fromDb) val now = Clock.System.now() @@ -41,11 +38,9 @@ class ImageRepository(internalRepository: ImageInternalRepository) : Repository< statusTrackingRepository.active(dto.id, ResourceType.Image) } - internalRepository.table.upsertReturning( - internalRepository.table.id, internalRepository.table.projectName - ) { + table.upsertReturning(table.id, table.projectName) { it[ImageTable.id] = dto.id - it[ImageTable.projectName] = internalRepository.projectName + it[ImageTable.projectName] = projectName it[ImageTable.name] = dto.name it[ImageTable.originLocations] = existingItem?.originLocations.concat(dto.originLocations).distinct() it[ImageTable.customFields] = dto.customFields.inner @@ -63,10 +58,8 @@ class ImageRepository(internalRepository: ImageInternalRepository) : Repository< } override fun upsertBatch(dtos: Collection) { - internalRepository.upsertBatch(dtos) { dto -> - val existingItem = - internalRepository.table.selectAll().where(internalRepository.filter(dto.id)).firstOrNull() - ?.let { internalRepository.toModel(it) } + upsertBatchInternal(dtos) { dto -> + val existingItem = table.selectAll().where(filter(dto.id)).firstOrNull()?.let(::fromDb) val now = Clock.System.now() @@ -75,7 +68,7 @@ class ImageRepository(internalRepository: ImageInternalRepository) : Repository< } this[ImageTable.id] = dto.id - this[ImageTable.projectName] = internalRepository.projectName + this[ImageTable.projectName] = projectName this[ImageTable.name] = dto.name this[ImageTable.originLocations] = existingItem?.originLocations.concat(dto.originLocations).distinct() this[ImageTable.customFields] = dto.customFields.inner diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/ParagraphStyleRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/ParagraphStyleRepository.kt index 14acc06e..3ee960a1 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/ParagraphStyleRepository.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/ParagraphStyleRepository.kt @@ -1,40 +1,39 @@ package com.quadient.migration.api.repository -import com.quadient.migration.api.dto.migrationmodel.DocumentObject import com.quadient.migration.api.dto.migrationmodel.MigrationObject import com.quadient.migration.api.dto.migrationmodel.ParagraphStyle -import com.quadient.migration.persistence.repository.ParagraphStyleInternalRepository +import com.quadient.migration.api.dto.migrationmodel.ParagraphStyleDefinition +import com.quadient.migration.api.dto.migrationmodel.ParagraphStyleRef import com.quadient.migration.persistence.table.DocumentObjectTable import com.quadient.migration.persistence.table.ParagraphStyleTable import com.quadient.migration.service.deploy.ResourceType import com.quadient.migration.tools.concat import kotlinx.datetime.Clock +import org.jetbrains.exposed.v1.core.ResultRow import org.jetbrains.exposed.v1.jdbc.selectAll import org.jetbrains.exposed.v1.jdbc.transactions.transaction import org.jetbrains.exposed.v1.jdbc.upsertReturning import kotlin.collections.map -class ParagraphStyleRepository(internalRepository: ParagraphStyleInternalRepository) : - Repository(internalRepository) { - val statusTrackingRepository = StatusTrackingRepository(internalRepository.projectName) +class ParagraphStyleRepository(table: ParagraphStyleTable, projectName: String) : + Repository(table, projectName) { + val statusTrackingRepository = StatusTrackingRepository(projectName) - override fun toDto(model: ParagraphStyle): ParagraphStyle { - return model + override fun fromDb(row: ResultRow): ParagraphStyle { + return ParagraphStyle.fromDb(row) } override fun findUsages(id: String): List { return transaction { - DocumentObjectTable.selectAll().where { DocumentObjectTable.projectName eq internalRepository.projectName } + DocumentObjectTable.selectAll().where { DocumentObjectTable.projectName eq projectName } .map { DocumentObjectTable.fromResultRow(it) }.filter { it.collectRefs().any { it.id == id } } .distinct() } } override fun upsert(dto: ParagraphStyle) { - internalRepository.upsert { - val existingItem = - internalRepository.table.selectAll().where(internalRepository.filter(dto.id)).firstOrNull() - ?.let { internalRepository.toModel(it) } + upsertInternal { + val existingItem = table.selectAll().where(filter(dto.id)).firstOrNull()?.let(::fromDb) val now = Clock.System.now() @@ -42,11 +41,9 @@ class ParagraphStyleRepository(internalRepository: ParagraphStyleInternalReposit statusTrackingRepository.active(dto.id, ResourceType.ParagraphStyle) } - internalRepository.table.upsertReturning( - internalRepository.table.id, internalRepository.table.projectName - ) { + table.upsertReturning(table.id, table.projectName) { it[ParagraphStyleTable.id] = dto.id - it[ParagraphStyleTable.projectName] = internalRepository.projectName + it[ParagraphStyleTable.projectName] = projectName it[ParagraphStyleTable.name] = dto.name it[ParagraphStyleTable.originLocations] = existingItem?.originLocations.concat(dto.originLocations).distinct() it[ParagraphStyleTable.customFields] = dto.customFields.inner @@ -58,10 +55,8 @@ class ParagraphStyleRepository(internalRepository: ParagraphStyleInternalReposit } override fun upsertBatch(dtos: Collection) { - internalRepository.upsertBatch(dtos) { dto -> - val existingItem = - internalRepository.table.selectAll().where(internalRepository.filter(dto.id)).firstOrNull() - ?.let { internalRepository.toModel(it) } + upsertBatchInternal(dtos) { dto -> + val existingItem = table.selectAll().where(filter(dto.id)).firstOrNull()?.let(::fromDb) val now = Clock.System.now() @@ -69,18 +64,23 @@ class ParagraphStyleRepository(internalRepository: ParagraphStyleInternalReposit statusTrackingRepository.active(dto.id, ResourceType.ParagraphStyle) } - internalRepository.table.upsertReturning( - internalRepository.table.id, internalRepository.table.projectName - ) { - it[ParagraphStyleTable.id] = dto.id - it[ParagraphStyleTable.projectName] = internalRepository.projectName - it[ParagraphStyleTable.name] = dto.name - it[ParagraphStyleTable.originLocations] = existingItem?.originLocations.concat(dto.originLocations).distinct() - it[ParagraphStyleTable.customFields] = dto.customFields.inner - it[ParagraphStyleTable.definition] = dto.definition.toDb() - it[ParagraphStyleTable.created] = existingItem?.created ?: now - it[ParagraphStyleTable.lastUpdated] = now - }.first() + this[ParagraphStyleTable.id] = dto.id + this[ParagraphStyleTable.projectName] = projectName + this[ParagraphStyleTable.name] = dto.name + this[ParagraphStyleTable.originLocations] = existingItem?.originLocations.concat(dto.originLocations).distinct() + this[ParagraphStyleTable.customFields] = dto.customFields.inner + this[ParagraphStyleTable.definition] = dto.definition.toDb() + this[ParagraphStyleTable.created] = existingItem?.created ?: now + this[ParagraphStyleTable.lastUpdated] = now + } + } + + fun firstWithDefinition(id: String): ParagraphStyle? { + val model = find(id) + return when (val def = model?.definition) { + is ParagraphStyleDefinition -> model + is ParagraphStyleRef -> firstWithDefinition(def.id) + null -> null } } } \ No newline at end of file diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/Repository.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/Repository.kt index 8f1c40a5..9c137a53 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/Repository.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/Repository.kt @@ -3,40 +3,155 @@ package com.quadient.migration.api.repository import com.quadient.migration.api.dto.migrationmodel.MigrationObject import com.quadient.migration.api.dto.migrationmodel.Ref import com.quadient.migration.api.dto.migrationmodel.RefValidatable -import com.quadient.migration.persistence.repository.InternalRepository +import com.quadient.migration.persistence.table.MigrationObjectTable +import com.quadient.migration.tools.getOrPutOrNull +import org.jetbrains.exposed.v1.core.Op +import org.jetbrains.exposed.v1.core.ResultRow +import org.jetbrains.exposed.v1.core.SqlExpressionBuilder.eq +import org.jetbrains.exposed.v1.core.SqlExpressionBuilder.inList +import org.jetbrains.exposed.v1.core.and +import org.jetbrains.exposed.v1.core.statements.BatchUpsertStatement +import org.jetbrains.exposed.v1.jdbc.JdbcTransaction +import org.jetbrains.exposed.v1.jdbc.batchUpsert +import org.jetbrains.exposed.v1.jdbc.deleteWhere +import org.jetbrains.exposed.v1.jdbc.selectAll import org.jetbrains.exposed.v1.jdbc.transactions.transaction abstract class Repository( - protected val internalRepository: InternalRepository + protected val table: MigrationObjectTable, + protected val projectName: String ) { - abstract fun toDto(model: T): T + private val cache = mutableMapOf() + private var allCached = false - fun listAll(): List = internalRepository.listAllModel().map(::toDto) - fun find(id: String): T? = internalRepository.findModel(id)?.let(::toDto) - fun findByName(name: String): T? = internalRepository.findModelByName(name)?.let(::toDto) + abstract fun fromDb(row: ResultRow): T + + fun listAll(): List { + if (allCached) { + return cache.values.toList() + } + return transaction { + val result = table.selectAll().where(filter()).map { + val result = fromDb(it) + cache[result.id] = result + result + } + allCached = true + result + } + } + + open fun list(customFilter: Op): List { + return transaction { + table.selectAll().where(customFilter and filter()).map { + val result = fromDb(it) + cache[result.id] = result + result + } + } + } + + fun find(id: String): T? { + return cache.getOrPutOrNull(id) { + transaction { + table.selectAll().where(filter(id)).firstOrNull()?.let(::fromDb) + } + } + } + + fun findOrFail(id: String): T { + val model = find(id) + return if (model != null) { + model + } else { + val errorMessage = "Record '$id' not found in '${table::class.simpleName}'." + error(errorMessage) + } + } + + fun findByName(name: String): T? { + val found = cache.values.find { it.name == name } + return found ?: transaction { + val result = table.selectAll().where(filter(name = name)).firstOrNull()?.let(::fromDb) + if (result != null) { + cache[result.id] = result + } + result + } + } fun findAndUpdate(id: String, block: (T) -> Unit): T? { - return internalRepository.findModel(id)?.let { - val dto = toDto(it) - block(dto) - upsert(dto) - dto + return find(id)?.let { + block(it) + upsert(it) + it } } fun findRefs(id: String): List { - val model = internalRepository.findModel(id) + val model = find(id) if (model != null && model is RefValidatable) { return model.collectRefs() } return emptyList() } - fun delete(id: String) = internalRepository.delete(id) + fun delete(id: String) { + cache.remove(id) + transaction { table.deleteWhere { filter(id = id) } } + } - fun deleteAll() = internalRepository.deleteAll() + fun deleteAll(): Int { + cache.clear() + return transaction { table.deleteWhere { filter() } } + } + + fun destroy() { + cache.clear() + transaction { + exec("DROP TABLE ${table.tableName}") + } + } + + protected fun filter(id: String? = null, name: String? = null): Op { + var result = table.projectName eq projectName + if (id != null) { + result = result and (table.id eq id) + } + if (name != null) { + result = result and (table.name eq name) + } + return result + } - fun destroy() = internalRepository.destroy() + protected fun upsertInternal(block: JdbcTransaction.() -> ResultRow): T { + return transaction { + val result = fromDb(block()) + cache[result.id] = result + result + } + } + + protected fun upsertBatchInternal( + dto: Collection, + block: BatchUpsertStatement.(D) -> Unit + ) { + val ids = dto.map { it.id }.toSet() + return transaction { + table.batchUpsert(dto) { + block(it) + } + + for (obj in table.selectAll().where(table.projectName eq projectName and (table.id inList ids)) + .map(::fromDb)) { + cache[obj.id] = obj + } + } + } + + protected fun updateCache(id: String, obj: T) { + cache[id] = obj + } abstract fun findUsages(id: String): List diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/TextStyleRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/TextStyleRepository.kt index 4a5279ab..eac6c8da 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/TextStyleRepository.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/TextStyleRepository.kt @@ -2,28 +2,30 @@ package com.quadient.migration.api.repository import com.quadient.migration.api.dto.migrationmodel.MigrationObject import com.quadient.migration.api.dto.migrationmodel.TextStyle -import com.quadient.migration.persistence.repository.TextStyleInternalRepository +import com.quadient.migration.api.dto.migrationmodel.TextStyleDefinition +import com.quadient.migration.api.dto.migrationmodel.TextStyleRef import com.quadient.migration.persistence.table.DocumentObjectTable import com.quadient.migration.persistence.table.TextStyleTable import com.quadient.migration.service.deploy.ResourceType import com.quadient.migration.tools.concat import kotlinx.datetime.Clock +import org.jetbrains.exposed.v1.core.ResultRow import org.jetbrains.exposed.v1.jdbc.selectAll import org.jetbrains.exposed.v1.jdbc.transactions.transaction import org.jetbrains.exposed.v1.jdbc.upsertReturning import kotlin.collections.map -class TextStyleRepository(internalRepository: TextStyleInternalRepository) : - Repository(internalRepository) { - val statusTrackingRepository = StatusTrackingRepository(internalRepository.projectName) +class TextStyleRepository(table: TextStyleTable, projectName: String) : + Repository(table, projectName) { + val statusTrackingRepository = StatusTrackingRepository(projectName) - override fun toDto(model: TextStyle): TextStyle { - return model + override fun fromDb(row: ResultRow): TextStyle { + return TextStyle.fromDb(row) } override fun findUsages(id: String): List { return transaction { - DocumentObjectTable.selectAll().where { DocumentObjectTable.projectName eq internalRepository.projectName } + DocumentObjectTable.selectAll().where { DocumentObjectTable.projectName eq projectName } .map { DocumentObjectTable.fromResultRow(it) } .filter { it.collectRefs().any { it.id == id } } .distinct() @@ -31,10 +33,8 @@ class TextStyleRepository(internalRepository: TextStyleInternalRepository) : } override fun upsert(dto: TextStyle) { - internalRepository.upsert { - val existingItem = - internalRepository.table.selectAll().where(internalRepository.filter(dto.id)).firstOrNull() - ?.let { internalRepository.toModel(it) } + upsertInternal { + val existingItem = table.selectAll().where(filter(dto.id)).firstOrNull()?.let(::fromDb) val now = Clock.System.now() @@ -42,11 +42,9 @@ class TextStyleRepository(internalRepository: TextStyleInternalRepository) : statusTrackingRepository.active(dto.id, ResourceType.TextStyle) } - internalRepository.table.upsertReturning( - internalRepository.table.id, internalRepository.table.projectName - ) { + table.upsertReturning(table.id, table.projectName) { it[TextStyleTable.id] = dto.id - it[TextStyleTable.projectName] = internalRepository.projectName + it[TextStyleTable.projectName] = projectName it[TextStyleTable.name] = dto.name it[TextStyleTable.originLocations] = existingItem?.originLocations.concat(dto.originLocations).distinct() it[TextStyleTable.customFields] = dto.customFields.inner @@ -58,10 +56,8 @@ class TextStyleRepository(internalRepository: TextStyleInternalRepository) : } override fun upsertBatch(dtos: Collection) { - internalRepository.upsertBatch(dtos) { dto -> - val existingItem = - internalRepository.table.selectAll().where(internalRepository.filter(dto.id)).firstOrNull() - ?.let { internalRepository.toModel(it) } + upsertBatchInternal(dtos) { dto -> + val existingItem = table.selectAll().where(filter(dto.id)).firstOrNull()?.let(::fromDb) val now = Clock.System.now() @@ -70,7 +66,7 @@ class TextStyleRepository(internalRepository: TextStyleInternalRepository) : } this[TextStyleTable.id] = dto.id - this[TextStyleTable.projectName] = internalRepository.projectName + this[TextStyleTable.projectName] = projectName this[TextStyleTable.name] = dto.name this[TextStyleTable.originLocations] = existingItem?.originLocations.concat(dto.originLocations).distinct() this[TextStyleTable.customFields] = dto.customFields.inner @@ -79,4 +75,13 @@ class TextStyleRepository(internalRepository: TextStyleInternalRepository) : this[TextStyleTable.lastUpdated] = now } } + + fun firstWithDefinition(id: String): TextStyle? { + val model = find(id) + return when (val def = model?.definition) { + is TextStyleDefinition -> model + is TextStyleRef -> firstWithDefinition(def.id) + null -> null + } + } } \ No newline at end of file diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/VariableRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/VariableRepository.kt index 6ea4deed..8319efcf 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/VariableRepository.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/VariableRepository.kt @@ -2,43 +2,41 @@ package com.quadient.migration.api.repository import com.quadient.migration.api.dto.migrationmodel.MigrationObject import com.quadient.migration.api.dto.migrationmodel.Variable -import com.quadient.migration.persistence.repository.VariableInternalRepository import com.quadient.migration.persistence.table.DocumentObjectTable +import com.quadient.migration.persistence.table.MigrationObjectTable import com.quadient.migration.persistence.table.VariableTable import com.quadient.migration.tools.concat import kotlinx.datetime.Clock +import org.jetbrains.exposed.v1.core.ResultRow import org.jetbrains.exposed.v1.jdbc.selectAll import org.jetbrains.exposed.v1.jdbc.transactions.transaction import org.jetbrains.exposed.v1.jdbc.upsertReturning import kotlin.collections.map -class VariableRepository(internalRepository: VariableInternalRepository) : - Repository(internalRepository) { - override fun toDto(model: Variable): Variable { - return model +class VariableRepository(table: MigrationObjectTable, projectName: String) : + Repository(table, projectName) { + + override fun fromDb(row: ResultRow): Variable { + return Variable.fromDb(row) } override fun findUsages(id: String): List { return transaction { - DocumentObjectTable.selectAll().where { DocumentObjectTable.projectName eq internalRepository.projectName } + DocumentObjectTable.selectAll().where { DocumentObjectTable.projectName eq projectName } .map { DocumentObjectTable.fromResultRow(it) }.filter { it.collectRefs().any { it.id == id } } .distinct() } } override fun upsert(dto: Variable) { - internalRepository.upsert { - val existingItem = - internalRepository.table.selectAll().where(internalRepository.filter(dto.id)).firstOrNull() - ?.let { internalRepository.toModel(it) } + upsertInternal { + val existingItem = table.selectAll().where(filter(dto.id)).firstOrNull()?.let(::fromDb) val now = Clock.System.now() - internalRepository.table.upsertReturning( - internalRepository.table.id, internalRepository.table.projectName - ) { + table.upsertReturning(table.id, table.projectName) { it[VariableTable.id] = dto.id - it[VariableTable.projectName] = internalRepository.projectName + it[VariableTable.projectName] = projectName it[VariableTable.name] = dto.name it[VariableTable.originLocations] = existingItem?.originLocations.concat(dto.originLocations).distinct() it[VariableTable.customFields] = dto.customFields.inner @@ -51,15 +49,13 @@ class VariableRepository(internalRepository: VariableInternalRepository) : } override fun upsertBatch(dtos: Collection) { - internalRepository.upsertBatch(dtos) { dto -> - val existingItem = - internalRepository.table.selectAll().where(internalRepository.filter(dto.id)).firstOrNull() - ?.let { internalRepository.toModel(it) } + upsertBatchInternal(dtos) { dto -> + val existingItem = table.selectAll().where(filter(dto.id)).firstOrNull()?.let(::fromDb) val now = Clock.System.now() this[VariableTable.id] = dto.id - this[VariableTable.projectName] = internalRepository.projectName + this[VariableTable.projectName] = projectName this[VariableTable.name] = dto.name this[VariableTable.originLocations] = existingItem?.originLocations.concat(dto.originLocations).distinct() this[VariableTable.customFields] = dto.customFields.inner diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/VariableStructureRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/VariableStructureRepository.kt index a0940046..60beba4a 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/VariableStructureRepository.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/VariableStructureRepository.kt @@ -1,45 +1,41 @@ package com.quadient.migration.api.repository -import com.quadient.migration.api.dto.migrationmodel.DocumentObject import com.quadient.migration.api.dto.migrationmodel.MigrationObject import com.quadient.migration.api.dto.migrationmodel.VariableStructure -import com.quadient.migration.persistence.repository.VariableStructureInternalRepository import com.quadient.migration.persistence.table.DocumentObjectTable import com.quadient.migration.persistence.table.VariableStructureTable import com.quadient.migration.tools.concat import kotlinx.datetime.Clock +import org.jetbrains.exposed.v1.core.ResultRow import org.jetbrains.exposed.v1.jdbc.selectAll import org.jetbrains.exposed.v1.jdbc.transactions.transaction import org.jetbrains.exposed.v1.jdbc.upsertReturning import kotlin.collections.map -class VariableStructureRepository(internalRepository: VariableStructureInternalRepository) : - Repository(internalRepository) { - override fun toDto(model: VariableStructure): VariableStructure { - return model +class VariableStructureRepository(table: VariableStructureTable, projectName: String) : + Repository(table, projectName) { + + override fun fromDb(row: ResultRow): VariableStructure { + return VariableStructure.fromDb(row) } override fun findUsages(id: String): List { return transaction { - DocumentObjectTable.selectAll().where { DocumentObjectTable.projectName eq internalRepository.projectName } + DocumentObjectTable.selectAll().where { DocumentObjectTable.projectName eq projectName } .map { DocumentObjectTable.fromResultRow(it) }.filter { it.collectRefs().any { it.id == id } } .distinct() } } override fun upsert(dto: VariableStructure) { - internalRepository.upsert { - val existingItem = - internalRepository.table.selectAll().where(internalRepository.filter(dto.id)).firstOrNull() - ?.let { internalRepository.toModel(it) } + upsertInternal { + val existingItem = table.selectAll().where(filter(dto.id)).firstOrNull()?.let(::fromDb) val now = Clock.System.now() - internalRepository.table.upsertReturning( - internalRepository.table.id, internalRepository.table.projectName - ) { + table.upsertReturning(table.id, table.projectName) { it[VariableStructureTable.id] = dto.id - it[VariableStructureTable.projectName] = internalRepository.projectName + it[VariableStructureTable.projectName] = projectName it[VariableStructureTable.name] = dto.name it[VariableStructureTable.originLocations] = existingItem?.originLocations.concat(dto.originLocations).distinct() it[VariableStructureTable.customFields] = dto.customFields.inner @@ -52,15 +48,13 @@ class VariableStructureRepository(internalRepository: VariableStructureInternalR } override fun upsertBatch(dtos: Collection) { - internalRepository.upsertBatch(dtos) { dto -> - val existingItem = - internalRepository.table.selectAll().where(internalRepository.filter(dto.id)).firstOrNull() - ?.let { internalRepository.toModel(it) } + upsertBatchInternal(dtos) { dto -> + val existingItem = table.selectAll().where(filter(dto.id)).firstOrNull()?.let(::fromDb) val now = Clock.System.now() this[VariableStructureTable.id] = dto.id - this[VariableStructureTable.projectName] = internalRepository.projectName + this[VariableStructureTable.projectName] = projectName this[VariableStructureTable.name] = dto.name this[VariableStructureTable.originLocations] = existingItem?.originLocations.concat(dto.originLocations).distinct() this[VariableStructureTable.customFields] = dto.customFields.inner diff --git a/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/DisplayRuleInternalRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/DisplayRuleInternalRepository.kt deleted file mode 100644 index d3db4792..00000000 --- a/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/DisplayRuleInternalRepository.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.quadient.migration.persistence.repository - -import com.quadient.migration.api.dto.migrationmodel.DisplayRule -import com.quadient.migration.persistence.table.MigrationObjectTable -import org.jetbrains.exposed.v1.core.ResultRow - -class DisplayRuleInternalRepository( - table: MigrationObjectTable, projectName: String -) : InternalRepository(table, projectName) { - override fun toModel(row: ResultRow): DisplayRule { - return DisplayRule.fromDb(row) - } -} diff --git a/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/DocumentObjectInternalRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/DocumentObjectInternalRepository.kt deleted file mode 100644 index 79603efc..00000000 --- a/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/DocumentObjectInternalRepository.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.quadient.migration.persistence.repository - -import com.quadient.migration.api.dto.migrationmodel.DocumentObject -import com.quadient.migration.persistence.table.DocumentObjectTable -import org.jetbrains.exposed.v1.core.ResultRow - -class DocumentObjectInternalRepository(table: DocumentObjectTable, projectName: String) : - InternalRepository(table, projectName) { - override fun toModel(row: ResultRow): DocumentObject { - return DocumentObjectTable.fromResultRow(row) - } -} \ No newline at end of file diff --git a/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/FileInternalRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/FileInternalRepository.kt deleted file mode 100644 index 42213396..00000000 --- a/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/FileInternalRepository.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.quadient.migration.persistence.repository - -import com.quadient.migration.api.dto.migrationmodel.File -import com.quadient.migration.persistence.table.MigrationObjectTable -import org.jetbrains.exposed.v1.core.ResultRow - -class FileInternalRepository( - table: MigrationObjectTable, projectName: String -) : InternalRepository(table, projectName) { - override fun toModel(row: ResultRow): File { - return File.fromDb(row) - } -} diff --git a/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/ImageInternalRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/ImageInternalRepository.kt deleted file mode 100644 index 595629a7..00000000 --- a/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/ImageInternalRepository.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.quadient.migration.persistence.repository - -import com.quadient.migration.api.dto.migrationmodel.Image -import com.quadient.migration.persistence.table.MigrationObjectTable -import org.jetbrains.exposed.v1.core.ResultRow - -class ImageInternalRepository( - table: MigrationObjectTable, projectName: String -) : InternalRepository(table, projectName) { - override fun toModel(row: ResultRow): Image { - return Image.fromDb(row) - } -} \ No newline at end of file diff --git a/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/InternalRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/InternalRepository.kt deleted file mode 100644 index b7c31e81..00000000 --- a/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/InternalRepository.kt +++ /dev/null @@ -1,134 +0,0 @@ -package com.quadient.migration.persistence.repository - -import com.quadient.migration.api.dto.migrationmodel.MigrationObject -import com.quadient.migration.persistence.table.MigrationObjectTable -import com.quadient.migration.tools.getOrPutOrNull -import org.jetbrains.exposed.v1.core.Op -import org.jetbrains.exposed.v1.core.ResultRow -import org.jetbrains.exposed.v1.core.SqlExpressionBuilder.eq -import org.jetbrains.exposed.v1.core.SqlExpressionBuilder.inList -import org.jetbrains.exposed.v1.core.and -import org.jetbrains.exposed.v1.core.statements.BatchUpsertStatement -import org.jetbrains.exposed.v1.jdbc.JdbcTransaction -import org.jetbrains.exposed.v1.jdbc.batchUpsert -import org.jetbrains.exposed.v1.jdbc.deleteWhere -import org.jetbrains.exposed.v1.jdbc.selectAll -import org.jetbrains.exposed.v1.jdbc.transactions.transaction -import org.slf4j.LoggerFactory - -abstract class InternalRepository( - val table: MigrationObjectTable, val projectName: String -) { - private val logger = LoggerFactory.getLogger(this::class.java)!! - private val cache = mutableMapOf() - private var allCached = false - - abstract fun toModel(row: ResultRow): T - - fun upsert(block: JdbcTransaction.() -> ResultRow): T { - return transaction { - val result = toModel(block()) - cache[result.id] = result - result - } - } - - fun upsertBatch(dto: Collection, block: BatchUpsertStatement.(D) -> Unit) { - val ids = dto.map { it.id }.toSet() - return transaction { - table.batchUpsert(dto) { - block(it) - } - - for (obj in table.selectAll().where(table.projectName eq projectName and (table.id inList ids)) - .map(::toModel)) { - cache[obj.id] = obj - } - } - } - - fun listAllModel(): List { - if (allCached) { - return cache.values.toList() - } - return transaction { - val result = table.selectAll().where(filter()).map { - val result = toModel(it) - cache[result.id] = result - result - } - allCached = true - result - } - } - - fun list(customFilter: Op): List { - return transaction { - table.selectAll().where(customFilter and filter()).map { - val result = toModel(it) - cache[result.id] = result - result - } - } - } - - fun findModelOrFail(id: String): T { - val model = findModel(id) - return if (model != null) { - model - } else { - val errorMessage = "Record '$id' not found in '${table::class.simpleName}'." - logger.error(errorMessage) - error(errorMessage) - } - } - - fun findModel(id: String): T? { - return cache.getOrPutOrNull(id) { - transaction { - table.selectAll().where(filter(id)).firstOrNull()?.let(::toModel) - } - } - } - - fun findModelByName(name: String): T? { - val found = cache.values.find { it.name == name } - return found ?: transaction { - val result = table.selectAll().where(filter(name = name)).firstOrNull()?.let(::toModel) - if (result != null) { - cache[result.id] = result - } - - result - } - } - - fun delete(id: String) { - cache.remove(id) - transaction { table.deleteWhere { filter(id = id) } } - } - - fun deleteAll(): Int { - cache.clear() - return transaction { table.deleteWhere { filter() } } - } - - fun destroy() { - cache.clear() - transaction { - exec("DROP TABLE ${table.tableName}") - } - } - - fun filter(id: String? = null, name: String? = null): Op { - var result = table.projectName eq projectName - if (id != null) { - result = result and (table.id eq id) - } - if (name != null) { - result = result and (table.name eq name) - } - - return result - } -} \ No newline at end of file diff --git a/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/ParagraphStyleInternalRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/ParagraphStyleInternalRepository.kt deleted file mode 100644 index 1757407e..00000000 --- a/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/ParagraphStyleInternalRepository.kt +++ /dev/null @@ -1,25 +0,0 @@ -package com.quadient.migration.persistence.repository - -import com.quadient.migration.api.dto.migrationmodel.ParagraphStyle -import com.quadient.migration.api.dto.migrationmodel.ParagraphStyleDefinition -import com.quadient.migration.api.dto.migrationmodel.ParagraphStyleRef -import com.quadient.migration.persistence.table.ParagraphStyleTable -import org.jetbrains.exposed.v1.core.ResultRow - -class ParagraphStyleInternalRepository(table: ParagraphStyleTable, projectName: String) : - InternalRepository(table, projectName) { - - override fun toModel(row: ResultRow): ParagraphStyle { - return ParagraphStyle.fromDb(row) - } - - internal fun firstWithDefinition(id: String): ParagraphStyle? { - val model = findModel(id) - val def = model?.definition - return when (def) { - is ParagraphStyleDefinition -> model - is ParagraphStyleRef -> firstWithDefinition(def.id) - null -> null - } - } -} \ No newline at end of file diff --git a/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/TextStyleInternalRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/TextStyleInternalRepository.kt deleted file mode 100644 index 3065ad01..00000000 --- a/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/TextStyleInternalRepository.kt +++ /dev/null @@ -1,25 +0,0 @@ -package com.quadient.migration.persistence.repository - -import com.quadient.migration.api.dto.migrationmodel.TextStyle -import com.quadient.migration.api.dto.migrationmodel.TextStyleDefinition -import com.quadient.migration.api.dto.migrationmodel.TextStyleRef -import com.quadient.migration.persistence.table.TextStyleTable -import org.jetbrains.exposed.v1.core.ResultRow - -class TextStyleInternalRepository(table: TextStyleTable, projectName: String) : - InternalRepository(table, projectName) { - - override fun toModel(row: ResultRow): TextStyle { - return TextStyle.fromDb(row) - } - - internal fun firstWithDefinition(id: String): TextStyle? { - val model = findModel(id) - val def = model?.definition - return when (def) { - is TextStyleDefinition -> model - is TextStyleRef -> firstWithDefinition(def.id) - null -> null - } - } -} \ No newline at end of file diff --git a/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/VariableInternalRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/VariableInternalRepository.kt deleted file mode 100644 index 3aa5e899..00000000 --- a/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/VariableInternalRepository.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.quadient.migration.persistence.repository - -import com.quadient.migration.api.dto.migrationmodel.Variable -import com.quadient.migration.persistence.table.MigrationObjectTable -import org.jetbrains.exposed.v1.core.ResultRow - -class VariableInternalRepository(table: MigrationObjectTable, projectName: String) : - InternalRepository(table, projectName) { - - override fun toModel(row: ResultRow): Variable { - return Variable.fromDb(row) - } -} \ No newline at end of file diff --git a/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/VariableStructureInternalRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/VariableStructureInternalRepository.kt deleted file mode 100644 index 0a63663d..00000000 --- a/migration-library/src/main/kotlin/com/quadient/migration/persistence/repository/VariableStructureInternalRepository.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.quadient.migration.persistence.repository - -import com.quadient.migration.api.dto.migrationmodel.VariableStructure -import com.quadient.migration.persistence.table.VariableStructureTable -import org.jetbrains.exposed.v1.core.ResultRow - -class VariableStructureInternalRepository(table: VariableStructureTable, projectName: String) : - InternalRepository(table, projectName) { - override fun toModel(row: ResultRow): VariableStructure { - return VariableStructure.fromDb(row) - } -} \ No newline at end of file diff --git a/migration-library/src/main/kotlin/com/quadient/migration/service/ReferenceValidator.kt b/migration-library/src/main/kotlin/com/quadient/migration/service/ReferenceValidator.kt index c6d446c8..e412bc51 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/service/ReferenceValidator.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/service/ReferenceValidator.kt @@ -1,33 +1,24 @@ package com.quadient.migration.service -import com.quadient.migration.api.dto.migrationmodel.DisplayRuleRef -import com.quadient.migration.api.dto.migrationmodel.DocumentObjectRef -import com.quadient.migration.api.dto.migrationmodel.ImageRef -import com.quadient.migration.api.dto.migrationmodel.FileRef -import com.quadient.migration.api.dto.migrationmodel.ParagraphStyleRef -import com.quadient.migration.api.dto.migrationmodel.Ref -import com.quadient.migration.api.dto.migrationmodel.TextStyleRef -import com.quadient.migration.api.dto.migrationmodel.VariableRef -import com.quadient.migration.api.dto.migrationmodel.VariableStructureRef -import com.quadient.migration.api.dto.migrationmodel.RefValidatable -import com.quadient.migration.persistence.repository.DisplayRuleInternalRepository -import com.quadient.migration.persistence.repository.DocumentObjectInternalRepository -import com.quadient.migration.persistence.repository.ImageInternalRepository -import com.quadient.migration.persistence.repository.FileInternalRepository -import com.quadient.migration.persistence.repository.ParagraphStyleInternalRepository -import com.quadient.migration.persistence.repository.TextStyleInternalRepository -import com.quadient.migration.persistence.repository.VariableInternalRepository -import com.quadient.migration.persistence.repository.VariableStructureInternalRepository +import com.quadient.migration.api.dto.migrationmodel.* +import com.quadient.migration.api.repository.DisplayRuleRepository +import com.quadient.migration.api.repository.DocumentObjectRepository +import com.quadient.migration.api.repository.FileRepository +import com.quadient.migration.api.repository.ImageRepository +import com.quadient.migration.api.repository.ParagraphStyleRepository +import com.quadient.migration.api.repository.TextStyleRepository +import com.quadient.migration.api.repository.VariableRepository +import com.quadient.migration.api.repository.VariableStructureRepository class ReferenceValidator( - private val documentObjectRepository: DocumentObjectInternalRepository, - private val variableRepository: VariableInternalRepository, - private val textStyleRepository: TextStyleInternalRepository, - private val paragraphStyleRepository: ParagraphStyleInternalRepository, - private val variableStructureRepository: VariableStructureInternalRepository, - private val displayRuleRepository: DisplayRuleInternalRepository, - private val imageRepository: ImageInternalRepository, - private val fileRepository: FileInternalRepository, + private val documentObjectRepository: DocumentObjectRepository, + private val variableRepository: VariableRepository, + private val textStyleRepository: TextStyleRepository, + private val paragraphStyleRepository: ParagraphStyleRepository, + private val variableStructureRepository: VariableStructureRepository, + private val displayRuleRepository: DisplayRuleRepository, + private val imageRepository: ImageRepository, + private val fileRepository: FileRepository, ) { /** * Validates all objects in the database. @@ -36,14 +27,14 @@ class ReferenceValidator( * @return MissingRefs containing list of missing references */ fun validateAll(): MissingRefs { - val documentObjects = documentObjectRepository.listAllModel() - val variables = variableRepository.listAllModel() - val paragraphStyles = paragraphStyleRepository.listAllModel() - val textStyles = textStyleRepository.listAllModel() - val dataStructures = variableStructureRepository.listAllModel() - val displayRules = displayRuleRepository.listAllModel() - val images = imageRepository.listAllModel() - val files = fileRepository.listAllModel() + val documentObjects = documentObjectRepository.listAll() + val variables = variableRepository.listAll() + val paragraphStyles = paragraphStyleRepository.listAll() + val textStyles = textStyleRepository.listAll() + val dataStructures = variableStructureRepository.listAll() + val displayRules = displayRuleRepository.listAll() + val images = imageRepository.listAll() + val files = fileRepository.listAll() val alreadyValidatedRefs = mutableSetOf() val missingRefs = @@ -72,7 +63,7 @@ class ReferenceValidator( when (current) { is DocumentObjectRef -> { - val documentObject = documentObjectRepository.findModel(current.id) + val documentObject = documentObjectRepository.find(current.id) if (documentObject == null) { missingRefs.add(current) @@ -84,7 +75,7 @@ class ReferenceValidator( } is VariableRef -> { - val variable = variableRepository.findModel(current.id) + val variable = variableRepository.find(current.id) if (variable != null) { validatedRefs.add(current) @@ -95,7 +86,7 @@ class ReferenceValidator( } is ParagraphStyleRef -> { - val style = paragraphStyleRepository.findModel(current.id) + val style = paragraphStyleRepository.find(current.id) if (style != null) { validatedRefs.add(current) @@ -107,7 +98,7 @@ class ReferenceValidator( } is TextStyleRef -> { - val style = textStyleRepository.findModel(current.id) + val style = textStyleRepository.find(current.id) if (style != null) { validatedRefs.add(current) @@ -119,7 +110,7 @@ class ReferenceValidator( } is DisplayRuleRef -> { - val rule = displayRuleRepository.findModel(current.id) + val rule = displayRuleRepository.find(current.id) if (rule != null) { validatedRefs.add(current) @@ -131,7 +122,7 @@ class ReferenceValidator( } is ImageRef -> { - val image = imageRepository.findModel(current.id) + val image = imageRepository.find(current.id) if (image != null) { validatedRefs.add(current) @@ -143,7 +134,7 @@ class ReferenceValidator( } is FileRef -> { - val file = fileRepository.findModel(current.id) + val file = fileRepository.find(current.id) if (file != null) { validatedRefs.add(current) @@ -155,7 +146,7 @@ class ReferenceValidator( } is VariableStructureRef -> { - val variableStructure = variableStructureRepository.findModel(current.id) + val variableStructure = variableStructureRepository.find(current.id) if (variableStructure != null) { validatedRefs.add(current) diff --git a/migration-library/src/main/kotlin/com/quadient/migration/service/StylesValidator.kt b/migration-library/src/main/kotlin/com/quadient/migration/service/StylesValidator.kt index df11eb54..e8270a23 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/service/StylesValidator.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/service/StylesValidator.kt @@ -15,17 +15,17 @@ import com.quadient.migration.api.dto.migrationmodel.TextStyle import com.quadient.migration.api.dto.migrationmodel.TextStyleRef import com.quadient.migration.api.dto.migrationmodel.VariableRef import com.quadient.migration.api.dto.migrationmodel.VariableStructureRef -import com.quadient.migration.persistence.repository.DocumentObjectInternalRepository -import com.quadient.migration.persistence.repository.ParagraphStyleInternalRepository -import com.quadient.migration.persistence.repository.TextStyleInternalRepository +import com.quadient.migration.api.repository.DocumentObjectRepository +import com.quadient.migration.api.repository.ParagraphStyleRepository +import com.quadient.migration.api.repository.TextStyleRepository import com.quadient.migration.service.deploy.DeployClient import com.quadient.migration.service.inspirebuilder.InspireDocumentObjectBuilder import com.quadient.migration.service.ipsclient.IpsService class StylesValidator( - private val documentObjectRepository: DocumentObjectInternalRepository, - private val textStyleRepository: TextStyleInternalRepository, - private val paragraphStyleRepository: ParagraphStyleInternalRepository, + private val documentObjectRepository: DocumentObjectRepository, + private val textStyleRepository: TextStyleRepository, + private val paragraphStyleRepository: ParagraphStyleRepository, private val documentObjectBuilder: InspireDocumentObjectBuilder, private val deployClient: DeployClient, private val ipsService: IpsService, @@ -54,7 +54,7 @@ class StylesValidator( for (style in refs) { when (style) { is ParagraphStyleRef -> { - val model = paragraphStyleRepository.findModel(style.id) + val model = paragraphStyleRepository.find(style.id) if (model == null) { missingParagraphStyleIds.add(style.id) } else { @@ -63,7 +63,7 @@ class StylesValidator( } is TextStyleRef -> { - val model = textStyleRepository.findModel(style.id) + val model = textStyleRepository.find(style.id) if (model == null) { missingTextStyleIds.add(style.id) } else { @@ -148,7 +148,7 @@ class StylesValidator( val refs = current.collectRefs().filterIsInstance() for (ref in refs) { - val model = documentObjectRepository.findModelOrFail(ref.id) + val model = documentObjectRepository.findOrFail(ref.id) if (!visited.contains(model.id)) { queue.add(model) } @@ -169,7 +169,7 @@ class StylesValidator( is TextStyleRef -> { val def = this.definition if (def is TextStyleRef) { - val model = textStyleRepository.findModel(def.id) + val model = textStyleRepository.find(def.id) if (model != null) { model.resolveTextStyle(textStyleIds, missingTextStyles) } else { @@ -191,7 +191,7 @@ class StylesValidator( is ParagraphStyleRef -> { val def = this.definition if (def is ParagraphStyleRef) { - val model = paragraphStyleRepository.findModel(def.id) + val model = paragraphStyleRepository.find(def.id) if (model != null) { model.resolveParagraphStyle(paragraphStyleIds, missingParagraphStyles) } else { diff --git a/migration-library/src/main/kotlin/com/quadient/migration/service/deploy/DeployClient.kt b/migration-library/src/main/kotlin/com/quadient/migration/service/deploy/DeployClient.kt index 6be6ba07..4f34e4f7 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/service/deploy/DeployClient.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/service/deploy/DeployClient.kt @@ -18,11 +18,10 @@ import com.quadient.migration.api.dto.migrationmodel.Ref import com.quadient.migration.api.dto.migrationmodel.TextStyleRef import com.quadient.migration.api.dto.migrationmodel.VariableRef import com.quadient.migration.api.dto.migrationmodel.VariableStructureRef -import com.quadient.migration.persistence.repository.DocumentObjectInternalRepository -import com.quadient.migration.persistence.repository.ImageInternalRepository -import com.quadient.migration.persistence.repository.FileInternalRepository -import com.quadient.migration.persistence.repository.ParagraphStyleInternalRepository -import com.quadient.migration.persistence.repository.TextStyleInternalRepository +import com.quadient.migration.api.repository.DocumentObjectRepository +import com.quadient.migration.api.repository.ParagraphStyleRepository +import com.quadient.migration.api.repository.Repository +import com.quadient.migration.api.repository.TextStyleRepository import com.quadient.migration.service.Storage import com.quadient.migration.service.inspirebuilder.InspireDocumentObjectBuilder import com.quadient.migration.service.ipsclient.IpsService @@ -46,12 +45,12 @@ import com.quadient.migration.data.Error as StatusError data class DocObjectWithRef(val obj: DocumentObject, val documentObjectRefs: Set) sealed class DeployClient( - protected val documentObjectRepository: DocumentObjectInternalRepository, - protected val imageRepository: ImageInternalRepository, - protected val fileRepository: FileInternalRepository, + protected val documentObjectRepository: DocumentObjectRepository, + protected val imageRepository: Repository, + protected val fileRepository: Repository, protected val statusTrackingRepository: StatusTrackingRepository, - protected val textStyleRepository: TextStyleInternalRepository, - protected val paragraphStyleRepository: ParagraphStyleInternalRepository, + protected val textStyleRepository: TextStyleRepository, + protected val paragraphStyleRepository: ParagraphStyleRepository, val documentObjectBuilder: InspireDocumentObjectBuilder, protected val ipsService: IpsService, protected val storage: Storage, @@ -108,8 +107,8 @@ sealed class DeployClient( deploymentResult.deployed.filter { it.type == ResourceType.DocumentObject || it.type == ResourceType.Image } .mapNotNull { info -> val obj = when (info.type) { - ResourceType.DocumentObject -> documentObjectRepository.findModel(info.id) - ResourceType.Image -> imageRepository.findModel(info.id) + ResourceType.DocumentObject -> documentObjectRepository.find(info.id) + ResourceType.Image -> imageRepository.find(info.id) else -> null } if (obj == null) { @@ -265,7 +264,7 @@ sealed class DeployClient( return } - val imageModel = imageRepository.findModel(imageRef.id) + val imageModel = imageRepository.find(imageRef.id) if (imageModel == null) { val message = "Image '${imageRef.id}' not found." logger.error(message) @@ -335,7 +334,7 @@ sealed class DeployClient( return } - val fileModel = fileRepository.findModel(fileRef.id) + val fileModel = fileRepository.find(fileRef.id) if (fileModel == null) { val message = "File '${fileRef.id}' not found." logger.error(message) @@ -432,7 +431,7 @@ sealed class DeployClient( val resource = when (ref) { is DocumentObjectRef -> { - val obj = documentObjectRepository.findModelOrFail(ref.id) + val obj = documentObjectRepository.findOrFail(ref.id) val nextIcmPath = if (obj.internal == true || (obj.type == DocumentObjectType.Page && output == InspireOutput.Designer)) { null @@ -458,7 +457,7 @@ sealed class DeployClient( } is ImageRef -> { - val img = imageRepository.findModelOrFail(ref.id) + val img = imageRepository.findOrFail(ref.id) val nextIcmPath = documentObjectBuilder.getImagePath(img) val deployKind = img.getDeployKind(nextIcmPath) val lastStatus = img.getLastStatus(lastDeployment) @@ -478,7 +477,7 @@ sealed class DeployClient( } is FileRef -> { - val file = fileRepository.findModelOrFail(ref.id) + val file = fileRepository.findOrFail(ref.id) val nextIcmPath = documentObjectBuilder.getFilePath(file) val deployKind = file.getDeployKind(nextIcmPath) val lastStatus = file.getLastStatus(lastDeployment) @@ -558,7 +557,7 @@ sealed class DeployClient( is ImageRef -> {} is FileRef -> {} is DocumentObjectRef -> { - val model = documentObjectRepository.findModelOrFail(ref.id) + val model = documentObjectRepository.findOrFail(ref.id) if (shouldIncludeDependency(model)) { dependencies.add(model) dependencies.addAll(model.findDependencies()) @@ -579,7 +578,7 @@ sealed class DeployClient( is ImageRef -> images.add(ref) is FileRef -> files.add(ref) is DocumentObjectRef -> { - val model = documentObjectRepository.findModel(ref.id) + val model = documentObjectRepository.find(ref.id) ?: error("Unable to collect image or file references because inner document object '${ref.id}' was not found.") if (documentObjectBuilder.shouldIncludeInternalDependency(model)) { diff --git a/migration-library/src/main/kotlin/com/quadient/migration/service/deploy/DesignerDeployClient.kt b/migration-library/src/main/kotlin/com/quadient/migration/service/deploy/DesignerDeployClient.kt index ae0b4089..70813014 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/service/deploy/DesignerDeployClient.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/service/deploy/DesignerDeployClient.kt @@ -7,11 +7,10 @@ import com.quadient.migration.api.repository.StatusTrackingRepository import com.quadient.migration.api.dto.migrationmodel.DocumentObject import com.quadient.migration.api.dto.migrationmodel.ParagraphStyleDefinition import com.quadient.migration.api.dto.migrationmodel.TextStyleDefinition -import com.quadient.migration.persistence.repository.DocumentObjectInternalRepository -import com.quadient.migration.persistence.repository.ImageInternalRepository -import com.quadient.migration.persistence.repository.FileInternalRepository -import com.quadient.migration.persistence.repository.ParagraphStyleInternalRepository -import com.quadient.migration.persistence.repository.TextStyleInternalRepository +import com.quadient.migration.api.repository.DocumentObjectRepository +import com.quadient.migration.api.repository.ParagraphStyleRepository +import com.quadient.migration.api.repository.Repository +import com.quadient.migration.api.repository.TextStyleRepository import com.quadient.migration.persistence.table.DocumentObjectTable import com.quadient.migration.service.Storage import com.quadient.migration.service.inspirebuilder.DesignerDocumentObjectBuilder @@ -27,12 +26,12 @@ import kotlin.uuid.ExperimentalUuidApi import kotlin.uuid.Uuid class DesignerDeployClient( - documentObjectRepository: DocumentObjectInternalRepository, - imageRepository: ImageInternalRepository, - fileRepository: FileInternalRepository, + documentObjectRepository: DocumentObjectRepository, + imageRepository: Repository, + fileRepository: Repository, statusTrackingRepository: StatusTrackingRepository, - textStyleRepository: TextStyleInternalRepository, - paragraphStyleRepository: ParagraphStyleInternalRepository, + textStyleRepository: TextStyleRepository, + paragraphStyleRepository: ParagraphStyleRepository, documentObjectBuilder: DesignerDocumentObjectBuilder, ipsService: IpsService, storage: Storage, @@ -160,9 +159,9 @@ class DesignerDeployClient( val deploymentId = Uuid.random() val deploymentTimestamp = Clock.System.now() - val textStyles = textStyleRepository.listAllModel().filter { it.definition is TextStyleDefinition } + val textStyles = textStyleRepository.listAll().filter { it.definition is TextStyleDefinition } val paragraphStyles = - paragraphStyleRepository.listAllModel().filter { it.definition is ParagraphStyleDefinition } + paragraphStyleRepository.listAll().filter { it.definition is ParagraphStyleDefinition } val outputPath = documentObjectBuilder.getStyleDefinitionPath() val xml2wfdResult = ipsService.xml2wfd(documentObjectBuilder.buildStyles(textStyles, paragraphStyles), outputPath) diff --git a/migration-library/src/main/kotlin/com/quadient/migration/service/deploy/InteractiveDeployClient.kt b/migration-library/src/main/kotlin/com/quadient/migration/service/deploy/InteractiveDeployClient.kt index 6e4b1b77..3d6affeb 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/service/deploy/InteractiveDeployClient.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/service/deploy/InteractiveDeployClient.kt @@ -6,13 +6,14 @@ import com.quadient.migration.api.InspireOutput import com.quadient.migration.api.ProjectConfig import com.quadient.migration.api.repository.StatusTrackingRepository import com.quadient.migration.api.dto.migrationmodel.DocumentObject +import com.quadient.migration.api.dto.migrationmodel.File +import com.quadient.migration.api.dto.migrationmodel.Image import com.quadient.migration.api.dto.migrationmodel.ParagraphStyleDefinition import com.quadient.migration.api.dto.migrationmodel.TextStyleDefinition -import com.quadient.migration.persistence.repository.DocumentObjectInternalRepository -import com.quadient.migration.persistence.repository.ImageInternalRepository -import com.quadient.migration.persistence.repository.FileInternalRepository -import com.quadient.migration.persistence.repository.ParagraphStyleInternalRepository -import com.quadient.migration.persistence.repository.TextStyleInternalRepository +import com.quadient.migration.api.repository.DocumentObjectRepository +import com.quadient.migration.api.repository.ParagraphStyleRepository +import com.quadient.migration.api.repository.Repository +import com.quadient.migration.api.repository.TextStyleRepository import com.quadient.migration.persistence.table.DocumentObjectTable import com.quadient.migration.service.Storage import com.quadient.migration.service.getBaseTemplateFullPath @@ -28,12 +29,12 @@ import kotlin.uuid.ExperimentalUuidApi import kotlin.uuid.Uuid class InteractiveDeployClient( - documentObjectRepository: DocumentObjectInternalRepository, - imageRepository: ImageInternalRepository, - fileRepository: FileInternalRepository, + documentObjectRepository: DocumentObjectRepository, + imageRepository: Repository, + fileRepository: Repository, statusTrackingRepository: StatusTrackingRepository, - textStyleRepository: TextStyleInternalRepository, - paragraphStyleRepository: ParagraphStyleInternalRepository, + textStyleRepository: TextStyleRepository, + paragraphStyleRepository: ParagraphStyleRepository, documentObjectBuilder: InteractiveDocumentObjectBuilder, ipsService: IpsService, storage: Storage, @@ -78,7 +79,7 @@ class InteractiveDeployClient( val skipped = mutableListOf() val internal = mutableListOf() for (documentObject in documentObjects) { - if (documentObject.skip.skipped == true) { + if (documentObject.skip.skipped) { skipped.add(documentObject.id) } if (documentObject.internal == true) { @@ -185,9 +186,9 @@ class InteractiveDeployClient( } } - val textStyles = textStyleRepository.listAllModel().filter { it.definition is TextStyleDefinition } + val textStyles = textStyleRepository.listAll().filter { it.definition is TextStyleDefinition } val paragraphStyles = - paragraphStyleRepository.listAllModel().filter { it.definition is ParagraphStyleDefinition } + paragraphStyleRepository.listAll().filter { it.definition is ParagraphStyleDefinition } val styleLayoutDeltaXml = documentObjectBuilder.buildStyleLayoutDelta( textStyles = textStyles, diff --git a/migration-library/src/main/kotlin/com/quadient/migration/service/inspirebuilder/DesignerDocumentObjectBuilder.kt b/migration-library/src/main/kotlin/com/quadient/migration/service/inspirebuilder/DesignerDocumentObjectBuilder.kt index 2346785e..1352d46b 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/service/inspirebuilder/DesignerDocumentObjectBuilder.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/service/inspirebuilder/DesignerDocumentObjectBuilder.kt @@ -2,14 +2,10 @@ package com.quadient.migration.service.inspirebuilder import com.quadient.migration.api.ProjectConfig import com.quadient.migration.api.dto.migrationmodel.* -import com.quadient.migration.persistence.repository.DisplayRuleInternalRepository -import com.quadient.migration.persistence.repository.DocumentObjectInternalRepository -import com.quadient.migration.persistence.repository.FileInternalRepository -import com.quadient.migration.persistence.repository.ImageInternalRepository -import com.quadient.migration.persistence.repository.ParagraphStyleInternalRepository -import com.quadient.migration.persistence.repository.TextStyleInternalRepository -import com.quadient.migration.persistence.repository.VariableInternalRepository -import com.quadient.migration.persistence.repository.VariableStructureInternalRepository +import com.quadient.migration.api.repository.DocumentObjectRepository +import com.quadient.migration.api.repository.ParagraphStyleRepository +import com.quadient.migration.api.repository.Repository +import com.quadient.migration.api.repository.TextStyleRepository import com.quadient.migration.service.imageExtension import com.quadient.migration.service.ipsclient.IpsService import com.quadient.migration.service.resolveTargetDir @@ -24,7 +20,6 @@ import com.quadient.migration.shared.millimeters import com.quadient.wfdxml.WfdXmlBuilder import com.quadient.wfdxml.api.layoutnodes.Flow import com.quadient.wfdxml.api.layoutnodes.FlowArea -import com.quadient.wfdxml.api.layoutnodes.Image as WfdXmlImage import com.quadient.wfdxml.api.layoutnodes.Page import com.quadient.wfdxml.api.layoutnodes.Pages import com.quadient.wfdxml.api.layoutnodes.tables.GeneralRowSet @@ -46,14 +41,14 @@ import javax.xml.transform.dom.DOMSource import javax.xml.transform.stream.StreamResult class DesignerDocumentObjectBuilder( - documentObjectRepository: DocumentObjectInternalRepository, - textStyleRepository: TextStyleInternalRepository, - paragraphStyleRepository: ParagraphStyleInternalRepository, - variableRepository: VariableInternalRepository, - variableStructureRepository: VariableStructureInternalRepository, - displayRuleRepository: DisplayRuleInternalRepository, - imageRepository: ImageInternalRepository, - fileRepository: FileInternalRepository, + documentObjectRepository: DocumentObjectRepository, + textStyleRepository: TextStyleRepository, + paragraphStyleRepository: ParagraphStyleRepository, + variableRepository: Repository, + variableStructureRepository: Repository, + displayRuleRepository: Repository, + imageRepository: Repository, + fileRepository: Repository, projectConfig: ProjectConfig, ipsService: IpsService, ) : InspireDocumentObjectBuilder( @@ -166,7 +161,7 @@ class DesignerDocumentObjectBuilder( val languageVariable = variableStructure.languageVariable if (languageVariable != null) { - val languageVariableModel = variableRepository.findModelOrFail(languageVariable.id) + val languageVariableModel = variableRepository.findOrFail(languageVariable.id) val languageVariablePathData = variableStructure.structure[languageVariable.id] if (languageVariablePathData == null || languageVariablePathData.path.isBlank()) { error("Language variable '${languageVariable.id}' or its path not found in variable structure '${variableStructure.id}'.") @@ -177,7 +172,7 @@ class DesignerDocumentObjectBuilder( documentObject.content.paragraphIfEmpty().forEach { if (it is DocumentObjectRef) { - val documentObjectModel = documentObjectRepository.findModelOrFail(it.id) + val documentObjectModel = documentObjectRepository.findOrFail(it.id) if (documentObjectModel.type == DocumentObjectType.Page) { pageModels.add(documentObjectModel) } else { @@ -221,9 +216,9 @@ class DesignerDocumentObjectBuilder( } buildTextStyles( - layout, textStyleRepository.listAllModel().filter { it.definition is TextStyleDefinition }) + layout, textStyleRepository.listAll().filter { it.definition is TextStyleDefinition }) buildParagraphStyles( - layout, paragraphStyleRepository.listAllModel().filter { it.definition is ParagraphStyleDefinition }) + layout, paragraphStyleRepository.listAll().filter { it.definition is ParagraphStyleDefinition }) val firstPageWithFlowArea = (layout.pages as PagesImpl).children.find { page -> (page as PageImpl).children.any { it is FlowArea } } as? PageImpl @@ -248,7 +243,7 @@ class DesignerDocumentObjectBuilder( layout: Layout, variableStructure: VariableStructure, ruleDef: DisplayRuleDefinition, successFlow: Flow, ): Flow { return layout.addFlow().setType(Flow.Type.SELECT_BY_INLINE_CONDITION).addLineForSelectByInlineCondition( - ruleDef.toScript(layout, variableStructure, variableRepository::findModelOrFail), successFlow + ruleDef.toScript(layout, variableStructure, variableRepository::findOrFail), successFlow ) } @@ -262,7 +257,7 @@ class DesignerDocumentObjectBuilder( multipleRowSet.addRowSet( layout.addRowSet().setType(RowSet.Type.SELECT_BY_INLINE_CONDITION).addLineForSelectByInlineCondition( - ruleDef.toScript(layout, variableStructure, variableRepository::findModelOrFail), successRow + ruleDef.toScript(layout, variableStructure, variableRepository::findOrFail), successRow ) ) @@ -320,7 +315,7 @@ class DesignerDocumentObjectBuilder( val content = areaModel.content if (content.size == 1 && content.first() is ImageRef) { val imageRef = content.first() as ImageRef - val imageModel = imageRepository.findModelOrFail(imageRef.id) + val imageModel = imageRepository.findOrFail(imageRef.id) when (val imagePlaceholder = getImagePlaceholder(imageModel)) { is ImagePlaceholderResult.Skip -> return diff --git a/migration-library/src/main/kotlin/com/quadient/migration/service/inspirebuilder/InspireDocumentObjectBuilder.kt b/migration-library/src/main/kotlin/com/quadient/migration/service/inspirebuilder/InspireDocumentObjectBuilder.kt index b1b71b64..5e76186c 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/service/inspirebuilder/InspireDocumentObjectBuilder.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/service/inspirebuilder/InspireDocumentObjectBuilder.kt @@ -26,14 +26,10 @@ import com.quadient.migration.api.dto.migrationmodel.TextStyleRef import com.quadient.migration.api.dto.migrationmodel.Variable import com.quadient.migration.api.dto.migrationmodel.VariableRef import com.quadient.migration.api.dto.migrationmodel.VariableStructure -import com.quadient.migration.persistence.repository.DisplayRuleInternalRepository -import com.quadient.migration.persistence.repository.DocumentObjectInternalRepository -import com.quadient.migration.persistence.repository.FileInternalRepository -import com.quadient.migration.persistence.repository.ImageInternalRepository -import com.quadient.migration.persistence.repository.ParagraphStyleInternalRepository -import com.quadient.migration.persistence.repository.TextStyleInternalRepository -import com.quadient.migration.persistence.repository.VariableInternalRepository -import com.quadient.migration.persistence.repository.VariableStructureInternalRepository +import com.quadient.migration.api.repository.DocumentObjectRepository +import com.quadient.migration.api.repository.ParagraphStyleRepository +import com.quadient.migration.api.repository.Repository +import com.quadient.migration.api.repository.TextStyleRepository import com.quadient.migration.service.inspirebuilder.InspireDocumentObjectBuilder.FlowModel.* import com.quadient.migration.service.inspirebuilder.InspireDocumentObjectBuilder.ScriptResult import com.quadient.migration.service.inspirebuilder.InspireDocumentObjectBuilder.ScriptResult.* @@ -94,14 +90,14 @@ import com.quadient.migration.api.dto.migrationmodel.ParagraphStyle as Paragraph import com.quadient.migration.api.dto.migrationmodel.TextStyle as TextStyleDTO abstract class InspireDocumentObjectBuilder( - protected val documentObjectRepository: DocumentObjectInternalRepository, - protected val textStyleRepository: TextStyleInternalRepository, - protected val paragraphStyleRepository: ParagraphStyleInternalRepository, - protected val variableRepository: VariableInternalRepository, - protected val variableStructureRepository: VariableStructureInternalRepository, - protected val displayRuleRepository: DisplayRuleInternalRepository, - protected val imageRepository: ImageInternalRepository, - protected val fileRepository: FileInternalRepository, + protected val documentObjectRepository: DocumentObjectRepository, + protected val textStyleRepository: TextStyleRepository, + protected val paragraphStyleRepository: ParagraphStyleRepository, + protected val variableRepository: Repository, + protected val variableStructureRepository: Repository, + protected val displayRuleRepository: Repository, + protected val imageRepository: Repository, + protected val fileRepository: Repository, protected val projectConfig: ProjectConfig, protected val ipsService: IpsService, ) { @@ -151,7 +147,7 @@ abstract class InspireDocumentObjectBuilder( } is DocumentObjectRef -> { - val documentObject = documentObjectRepository.findModelOrFail(item.id) + val documentObject = documentObjectRepository.findOrFail(item.id) if (shouldIncludeInternalDependency(documentObject)) { collectLanguagesFromContent(documentObject.content) } @@ -170,7 +166,7 @@ abstract class InspireDocumentObjectBuilder( } is DocumentObjectRef -> { - val documentObject = documentObjectRepository.findModelOrFail(textContent.id) + val documentObject = documentObjectRepository.findOrFail(textContent.id) if (shouldIncludeInternalDependency(documentObject)) { collectLanguagesFromContent(documentObject.content) } @@ -196,7 +192,7 @@ abstract class InspireDocumentObjectBuilder( ): Flow { return layout.addFlow().setType(Flow.Type.SELECT_BY_CONDITION).addLineForSelectByCondition( layout.data.addVariable().setKind(VariableKind.CALCULATED).setDataType(DataType.BOOL) - .setScript(ruleDef.toScript(layout, variableStructure, variableRepository::findModelOrFail)), + .setScript(ruleDef.toScript(layout, variableStructure, variableRepository::findOrFail)), successFlow ) } @@ -212,7 +208,7 @@ abstract class InspireDocumentObjectBuilder( multipleRowSet.addRowSet( layout.addRowSet().setType(RowSet.Type.SELECT_BY_CONDITION).addLineForSelectByCondition( layout.data.addVariable().setKind(VariableKind.CALCULATED).setDataType(DataType.BOOL) - .setScript(ruleDef.toScript(layout, variableStructure, variableRepository::findModelOrFail)), + .setScript(ruleDef.toScript(layout, variableStructure, variableRepository::findOrFail)), successRow ) ) @@ -362,7 +358,7 @@ abstract class InspireDocumentObjectBuilder( return if (displayRuleRef == null) { singleFlow } else { - val displayRule = displayRuleRepository.findModelOrFail(displayRuleRef.id) + val displayRule = displayRuleRepository.findOrFail(displayRuleRef.id) val def = displayRule.definition if (def == null) { error("Display rule '${displayRuleRef.id}' definition is null.") @@ -389,7 +385,7 @@ abstract class InspireDocumentObjectBuilder( val variableStructureId = documentObject.variableStructureRef?.id ?: projectConfig.defaultVariableStructure val variableStructureModel = - variableStructureId?.let { variableStructureRepository.findModelOrFail(it) } ?: VariableStructure( + variableStructureId?.let { variableStructureRepository.findOrFail(it) } ?: VariableStructure( id = "defaultVariableStructure", lastUpdated = Clock.System.now(), created = Clock.System.now(), @@ -618,7 +614,7 @@ abstract class InspireDocumentObjectBuilder( layout: Layout, fileRef: FileRef, ): Flow? { - val fileModel = fileRepository.findModelOrFail(fileRef.id) + val fileModel = fileRepository.findOrFail(fileRef.id) if (fileModel.skip.skipped && fileModel.skip.placeholder == null) { val reason = fileModel.skip.reason?.let { "with reason: $it" } ?: "without reason" @@ -678,7 +674,7 @@ abstract class InspireDocumentObjectBuilder( documentObjectRef: DocumentObjectRef, languages: List, ): Flow? { - val documentModel = documentObjectRepository.findModelOrFail(documentObjectRef.id) + val documentModel = documentObjectRepository.findOrFail(documentObjectRef.id) if (documentModel.skip.skipped && documentModel.skip.placeholder == null) { val reason = documentModel.skip.reason?.let { "with reason: $it" } ?: "without reason" @@ -707,7 +703,7 @@ abstract class InspireDocumentObjectBuilder( } if (documentObjectRef.displayRuleRef != null) { - val displayRule = displayRuleRepository.findModelOrFail(documentObjectRef.displayRuleRef.id) + val displayRule = displayRuleRepository.findOrFail(documentObjectRef.displayRuleRef.id) val def = displayRule.definition if (def == null) { error("Display rule '${documentObjectRef.displayRuleRef.id}' definition is null.") @@ -840,7 +836,7 @@ abstract class InspireDocumentObjectBuilder( } private fun buildAndAppendImage(layout: Layout, text: WfdXmlText, ref: ImageRef) { - val imageModel = imageRepository.findModelOrFail(ref.id) + val imageModel = imageRepository.findOrFail(ref.id) when (val imagePlaceholder = getImagePlaceholder(imageModel)) { is ImagePlaceholderResult.Placeholder -> { @@ -870,7 +866,7 @@ abstract class InspireDocumentObjectBuilder( private fun WfdXmlText.appendVariable( ref: VariableRef, layout: Layout, variableStructure: VariableStructure ): WfdXmlText { - val variableModel = variableRepository.findModelOrFail(ref.id) + val variableModel = variableRepository.findOrFail(ref.id) val variablePathData = variableStructure.structure[ref.id] if (variablePathData == null || variablePathData.path.isBlank()) { @@ -904,7 +900,7 @@ abstract class InspireDocumentObjectBuilder( private fun buildSuccessFlowWrappedInInlineConditionFlow( layout: Layout, variableStructure: VariableStructure, displayRuleId: String, text: WfdXmlText ): Flow { - val displayRule = displayRuleRepository.findModelOrFail(displayRuleId) + val displayRule = displayRuleRepository.findOrFail(displayRuleId) if (displayRule.definition == null) { error("Display rule '$displayRuleId' definition is null.") } @@ -914,7 +910,7 @@ abstract class InspireDocumentObjectBuilder( text.appendFlow( layout.addFlow().setType(Flow.Type.SELECT_BY_INLINE_CONDITION).addLineForSelectByInlineCondition( - def.toScript(layout, variableStructure, variableRepository::findModelOrFail), + def.toScript(layout, variableStructure, variableRepository::findOrFail), successFlow ) ) @@ -941,7 +937,7 @@ abstract class InspireDocumentObjectBuilder( val row = if (rowModel.displayRuleRef == null) { layout.addRowSet().setType(RowSet.Type.SINGLE_ROW).also { rowset.addRowSet(it) } } else { - val displayRule = displayRuleRepository.findModelOrFail(rowModel.displayRuleRef.id) + val displayRule = displayRuleRepository.findOrFail(rowModel.displayRuleRef.id) val def = displayRule.definition if (def == null) { error("Display rule '${rowModel.displayRuleRef.id}' definition is null.") @@ -992,7 +988,7 @@ abstract class InspireDocumentObjectBuilder( flowName?.let { firstMatchFlow.setName(it) } model.cases.forEachIndexed { i, case -> - val displayRule = displayRuleRepository.findModelOrFail(case.displayRuleRef.id) + val displayRule = displayRuleRepository.findOrFail(case.displayRuleRef.id) if (displayRule.definition == null) { error("Display rule '${case.displayRuleRef.id}' definition is null.") } @@ -1009,7 +1005,7 @@ abstract class InspireDocumentObjectBuilder( val def = displayRule.definition!! firstMatchFlow.addLineForSelectByInlineCondition( - def.toScript(layout, variableStructure, variableRepository::findModelOrFail), + def.toScript(layout, variableStructure, variableRepository::findOrFail), caseFlow ) } @@ -1081,7 +1077,7 @@ abstract class InspireDocumentObjectBuilder( return when (def) { is TextStyleDefinition -> def is TextStyleRef -> { - textStyleRepository.findModel(def.id)?.resolve() ?: error("Invalid text style reference") + textStyleRepository.find(def.id)?.resolve() ?: error("Invalid text style reference") } else -> error("Invalid text style definition type") } @@ -1091,7 +1087,7 @@ abstract class InspireDocumentObjectBuilder( val def = this.definition return when (def) { is ParagraphStyleDefinition -> def - is ParagraphStyleRef -> paragraphStyleRepository.findModelOrFail(def.id).resolve() + is ParagraphStyleRef -> paragraphStyleRepository.findOrFail(def.id).resolve() else -> error("Invalid paragraph style definition type") } } diff --git a/migration-library/src/main/kotlin/com/quadient/migration/service/inspirebuilder/InteractiveDocumentObjectBuilder.kt b/migration-library/src/main/kotlin/com/quadient/migration/service/inspirebuilder/InteractiveDocumentObjectBuilder.kt index a3a16ce0..5aa3895e 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/service/inspirebuilder/InteractiveDocumentObjectBuilder.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/service/inspirebuilder/InteractiveDocumentObjectBuilder.kt @@ -10,14 +10,10 @@ import com.quadient.migration.api.dto.migrationmodel.DocumentContent import com.quadient.migration.api.dto.migrationmodel.DocumentObject import com.quadient.migration.api.dto.migrationmodel.File import com.quadient.migration.api.dto.migrationmodel.Image -import com.quadient.migration.persistence.repository.DisplayRuleInternalRepository -import com.quadient.migration.persistence.repository.DocumentObjectInternalRepository -import com.quadient.migration.persistence.repository.FileInternalRepository -import com.quadient.migration.persistence.repository.ImageInternalRepository -import com.quadient.migration.persistence.repository.ParagraphStyleInternalRepository -import com.quadient.migration.persistence.repository.TextStyleInternalRepository -import com.quadient.migration.persistence.repository.VariableInternalRepository -import com.quadient.migration.persistence.repository.VariableStructureInternalRepository +import com.quadient.migration.api.repository.DocumentObjectRepository +import com.quadient.migration.api.repository.ParagraphStyleRepository +import com.quadient.migration.api.repository.Repository +import com.quadient.migration.api.repository.TextStyleRepository import com.quadient.migration.service.getBaseTemplateFullPath import com.quadient.migration.service.imageExtension import com.quadient.migration.service.ipsclient.IpsService @@ -29,22 +25,19 @@ import com.quadient.migration.shared.ImageType import com.quadient.migration.shared.orDefault import com.quadient.wfdxml.WfdXmlBuilder import com.quadient.wfdxml.api.layoutnodes.Flow -import com.quadient.wfdxml.api.layoutnodes.Image as WfdXmlImage -import com.quadient.wfdxml.api.layoutnodes.data.DataType -import com.quadient.wfdxml.api.layoutnodes.data.VariableKind import com.quadient.wfdxml.api.module.Layout import kotlinx.serialization.Serializable import kotlinx.serialization.json.Json class InteractiveDocumentObjectBuilder( - documentObjectRepository: DocumentObjectInternalRepository, - textStyleRepository: TextStyleInternalRepository, - paragraphStyleRepository: ParagraphStyleInternalRepository, - variableRepository: VariableInternalRepository, - variableStructureRepository: VariableStructureInternalRepository, - displayRuleRepository: DisplayRuleInternalRepository, - imageRepository: ImageInternalRepository, - fileRepository: FileInternalRepository, + documentObjectRepository: DocumentObjectRepository, + textStyleRepository: TextStyleRepository, + paragraphStyleRepository: ParagraphStyleRepository, + variableRepository: Repository, + variableStructureRepository: Repository, + displayRuleRepository: Repository, + imageRepository: Repository, + fileRepository: Repository, projectConfig: ProjectConfig, ipsService: IpsService, ) : InspireDocumentObjectBuilder( diff --git a/migration-library/src/test/kotlin/com/quadient/migration/persistence/DisplayRuleRepositoryTest.kt b/migration-library/src/test/kotlin/com/quadient/migration/persistence/DisplayRuleRepositoryTest.kt index 3ee849a3..f9d7b16b 100644 --- a/migration-library/src/test/kotlin/com/quadient/migration/persistence/DisplayRuleRepositoryTest.kt +++ b/migration-library/src/test/kotlin/com/quadient/migration/persistence/DisplayRuleRepositoryTest.kt @@ -2,14 +2,10 @@ package com.quadient.migration.persistence import com.quadient.migration.Postgres import com.quadient.migration.api.dto.migrationmodel.builder.DisplayRuleBuilder -import com.quadient.migration.api.repository.DisplayRuleRepository -import com.quadient.migration.persistence.repository.DisplayRuleInternalRepository -import com.quadient.migration.persistence.table.DisplayRuleTable import com.quadient.migration.shared.DisplayRuleDefinition import com.quadient.migration.shared.Group import com.quadient.migration.shared.GroupOp import com.quadient.migration.tools.aDisplayRuleRepository -import com.quadient.migration.tools.aProjectConfig import com.quadient.migration.tools.shouldBeEqualTo import org.junit.jupiter.api.Test diff --git a/migration-library/src/test/kotlin/com/quadient/migration/persistence/DocumentObjectRepositoryTest.kt b/migration-library/src/test/kotlin/com/quadient/migration/persistence/DocumentObjectRepositoryTest.kt index 5f86d8c7..35e45de5 100644 --- a/migration-library/src/test/kotlin/com/quadient/migration/persistence/DocumentObjectRepositoryTest.kt +++ b/migration-library/src/test/kotlin/com/quadient/migration/persistence/DocumentObjectRepositoryTest.kt @@ -7,16 +7,16 @@ import com.quadient.migration.api.dto.migrationmodel.StringValue import com.quadient.migration.api.dto.migrationmodel.builder.DocumentObjectBuilder import com.quadient.migration.api.dto.migrationmodel.builder.Dsl.table import com.quadient.migration.api.dto.migrationmodel.builder.ParagraphBuilder -import com.quadient.migration.api.repository.DocumentObjectRepository import com.quadient.migration.api.repository.StatusTrackingRepository import com.quadient.migration.data.Active import com.quadient.migration.service.deploy.ResourceType import com.quadient.migration.shared.DocumentObjectType import com.quadient.migration.tools.aBlockDto import com.quadient.migration.tools.aCell +import com.quadient.migration.tools.aDocumentObjectRepository +import com.quadient.migration.tools.aProjectConfig import com.quadient.migration.tools.aRow import com.quadient.migration.tools.aTable -import com.quadient.migration.tools.model.aDocumentObjectInternalRepository import com.quadient.migration.tools.shouldBeEqualTo import com.quadient.migration.tools.shouldBeOfSize import org.junit.jupiter.api.Assertions.assertEquals @@ -25,9 +25,9 @@ import org.junit.jupiter.api.Test @Postgres class DocumentObjectRepositoryTest { - private val internalRepo = aDocumentObjectInternalRepository() - private val repo = DocumentObjectRepository(internalRepo) - private val statusRepo = StatusTrackingRepository(internalRepo.projectName) + private val projectName = aProjectConfig().name + private val repo = aDocumentObjectRepository() + private val statusRepo = StatusTrackingRepository(projectName) @Test fun `roundtrip is correct`() { diff --git a/migration-library/src/test/kotlin/com/quadient/migration/persistence/FileRepositoryTest.kt b/migration-library/src/test/kotlin/com/quadient/migration/persistence/FileRepositoryTest.kt index 151c3a57..cdc1e1b8 100644 --- a/migration-library/src/test/kotlin/com/quadient/migration/persistence/FileRepositoryTest.kt +++ b/migration-library/src/test/kotlin/com/quadient/migration/persistence/FileRepositoryTest.kt @@ -2,12 +2,12 @@ package com.quadient.migration.persistence import com.quadient.migration.Postgres import com.quadient.migration.api.dto.migrationmodel.builder.FileBuilder -import com.quadient.migration.api.repository.FileRepository import com.quadient.migration.api.repository.StatusTrackingRepository import com.quadient.migration.data.Active import com.quadient.migration.service.deploy.ResourceType import com.quadient.migration.shared.FileType -import com.quadient.migration.tools.model.aFileInternalRepository +import com.quadient.migration.tools.aFileRepository +import com.quadient.migration.tools.aProjectConfig import com.quadient.migration.tools.shouldBeEqualTo import com.quadient.migration.tools.shouldBeOfSize import org.junit.jupiter.api.Assertions.assertInstanceOf @@ -15,9 +15,9 @@ import org.junit.jupiter.api.Test @Postgres class FileRepositoryTest { - private val internalRepo = aFileInternalRepository() - private val repo = FileRepository(internalRepo) - private val statusRepo = StatusTrackingRepository(internalRepo.projectName) + private val projectName = aProjectConfig().name + private val repo = aFileRepository() + private val statusRepo = StatusTrackingRepository(projectName) @Test fun roundtrip() { diff --git a/migration-library/src/test/kotlin/com/quadient/migration/persistence/ImageRepositoryTest.kt b/migration-library/src/test/kotlin/com/quadient/migration/persistence/ImageRepositoryTest.kt index 60586f85..bef345ab 100644 --- a/migration-library/src/test/kotlin/com/quadient/migration/persistence/ImageRepositoryTest.kt +++ b/migration-library/src/test/kotlin/com/quadient/migration/persistence/ImageRepositoryTest.kt @@ -2,13 +2,12 @@ package com.quadient.migration.persistence import com.quadient.migration.Postgres import com.quadient.migration.api.dto.migrationmodel.builder.ImageBuilder -import com.quadient.migration.api.repository.ImageRepository import com.quadient.migration.api.repository.StatusTrackingRepository import com.quadient.migration.data.Active import com.quadient.migration.service.deploy.ResourceType import com.quadient.migration.shared.ImageType -import com.quadient.migration.tools.model.aImage -import com.quadient.migration.tools.model.aImageInternalRepository +import com.quadient.migration.tools.aImageRepository +import com.quadient.migration.tools.aProjectConfig import com.quadient.migration.tools.shouldBeEqualTo import com.quadient.migration.tools.shouldBeOfSize import org.junit.jupiter.api.Assertions.assertInstanceOf @@ -16,9 +15,9 @@ import org.junit.jupiter.api.Test @Postgres class ImageRepositoryTest { - private val internalRepo = aImageInternalRepository() - private val repo = ImageRepository(internalRepo) - private val statusRepo = StatusTrackingRepository(internalRepo.projectName) + private val projectName = aProjectConfig().name + private val repo = aImageRepository() + private val statusRepo = StatusTrackingRepository(projectName) @Test fun roundtrip() { diff --git a/migration-library/src/test/kotlin/com/quadient/migration/persistence/ParargraphStyleRepositoryTest.kt b/migration-library/src/test/kotlin/com/quadient/migration/persistence/ParargraphStyleRepositoryTest.kt index 02126821..6b5586b1 100644 --- a/migration-library/src/test/kotlin/com/quadient/migration/persistence/ParargraphStyleRepositoryTest.kt +++ b/migration-library/src/test/kotlin/com/quadient/migration/persistence/ParargraphStyleRepositoryTest.kt @@ -5,14 +5,8 @@ import com.quadient.migration.api.dto.migrationmodel.ParagraphStyleRef import com.quadient.migration.api.dto.migrationmodel.Tab import com.quadient.migration.api.dto.migrationmodel.Tabs import com.quadient.migration.api.dto.migrationmodel.builder.ParagraphStyleBuilder -import com.quadient.migration.api.repository.DocumentObjectRepository -import com.quadient.migration.api.repository.ParagraphStyleRepository import com.quadient.migration.api.repository.StatusTrackingRepository import com.quadient.migration.data.Active -import com.quadient.migration.persistence.repository.DocumentObjectInternalRepository -import com.quadient.migration.persistence.repository.ParagraphStyleInternalRepository -import com.quadient.migration.persistence.table.DocumentObjectTable -import com.quadient.migration.persistence.table.ParagraphStyleTable import com.quadient.migration.service.deploy.ResourceType import com.quadient.migration.shared.Alignment import com.quadient.migration.shared.LineSpacing diff --git a/migration-library/src/test/kotlin/com/quadient/migration/service/ReferenceValidatorTest.kt b/migration-library/src/test/kotlin/com/quadient/migration/service/ReferenceValidatorTest.kt index 51e67a7a..95d92d50 100644 --- a/migration-library/src/test/kotlin/com/quadient/migration/service/ReferenceValidatorTest.kt +++ b/migration-library/src/test/kotlin/com/quadient/migration/service/ReferenceValidatorTest.kt @@ -1,26 +1,22 @@ package com.quadient.migration.service import com.quadient.migration.Postgres -import com.quadient.migration.api.dto.migrationmodel.DocumentContent import com.quadient.migration.api.dto.migrationmodel.DocumentObjectRef import com.quadient.migration.api.dto.migrationmodel.ParagraphStyleRef import com.quadient.migration.api.dto.migrationmodel.TextStyleRef import com.quadient.migration.shared.DocumentObjectType import com.quadient.migration.tools.aBlockDto +import com.quadient.migration.tools.aDisplayRuleRepository import com.quadient.migration.tools.aDocumentObjectRepository +import com.quadient.migration.tools.aFileRepository +import com.quadient.migration.tools.aImageRepository import com.quadient.migration.tools.aParaStyleRepository import com.quadient.migration.tools.aParagraphStyle import com.quadient.migration.tools.aTextStyle import com.quadient.migration.tools.aTextStyleRepository +import com.quadient.migration.tools.aVariableRepository +import com.quadient.migration.tools.aVariableStructureRepository import com.quadient.migration.tools.model.aBlock -import com.quadient.migration.tools.model.aDisplayRuleInternalRepository -import com.quadient.migration.tools.model.aDocumentObjectInternalRepository -import com.quadient.migration.tools.model.aFileInternalRepository -import com.quadient.migration.tools.model.aImageInternalRepository -import com.quadient.migration.tools.model.aParaStyleInternalRepository -import com.quadient.migration.tools.model.aTextStyleInternalRepository -import com.quadient.migration.tools.model.aVariableInternalRepository -import com.quadient.migration.tools.model.aVariableStructureInternalRepository import com.quadient.migration.tools.shouldBeEmpty import com.quadient.migration.tools.shouldBeEqualTo import com.quadient.migration.tools.shouldBeOfSize @@ -28,24 +24,24 @@ import org.junit.jupiter.api.Test @Postgres class ReferenceValidatorTest { - val documentObjectInternalRepository = aDocumentObjectInternalRepository() - val variableRepository = aVariableInternalRepository() - val paraStyleInternalRepository = aParaStyleInternalRepository() - val textStyleInternalRepository = aTextStyleInternalRepository() - val dataStructureRepository = aVariableStructureInternalRepository() - val displayRuleRepository = aDisplayRuleInternalRepository() - val imageRuleRepository = aImageInternalRepository() - val fileRuleRepository = aFileInternalRepository() + val documentObjectRepository = aDocumentObjectRepository() + val variableRepository = aVariableRepository() + val paraStyleRepository = aParaStyleRepository() + val textStyleRepository = aTextStyleRepository() + val dataStructureRepository = aVariableStructureRepository() + val displayRuleRepository = aDisplayRuleRepository() + val imageRuleRepository = aImageRepository() + val fileRuleRepository = aFileRepository() val docRepo = aDocumentObjectRepository() val paraStyleRepo = aParaStyleRepository() val textStyleRepo = aTextStyleRepository() val subject = ReferenceValidator( - documentObjectInternalRepository, + documentObjectRepository, variableRepository, - textStyleInternalRepository, - paraStyleInternalRepository, + textStyleRepository, + paraStyleRepository, dataStructureRepository, displayRuleRepository, imageRuleRepository, diff --git a/migration-library/src/test/kotlin/com/quadient/migration/service/StylesValidatorTest.kt b/migration-library/src/test/kotlin/com/quadient/migration/service/StylesValidatorTest.kt index a92e85e8..d884bb44 100644 --- a/migration-library/src/test/kotlin/com/quadient/migration/service/StylesValidatorTest.kt +++ b/migration-library/src/test/kotlin/com/quadient/migration/service/StylesValidatorTest.kt @@ -3,20 +3,17 @@ package com.quadient.migration.service import com.quadient.migration.Postgres import com.quadient.migration.api.dto.migrationmodel.ParagraphStyleRef import com.quadient.migration.api.dto.migrationmodel.TextStyleRef -import com.quadient.migration.api.repository.DocumentObjectRepository -import com.quadient.migration.api.repository.ParagraphStyleRepository -import com.quadient.migration.api.repository.TextStyleRepository import com.quadient.migration.service.deploy.DeployClient import com.quadient.migration.service.inspirebuilder.InspireDocumentObjectBuilder import com.quadient.migration.service.ipsclient.IpsService +import com.quadient.migration.tools.aDocumentObjectRepository +import com.quadient.migration.tools.aParaStyleRepository import com.quadient.migration.tools.aParagraphStyle import com.quadient.migration.tools.aTextStyle +import com.quadient.migration.tools.aTextStyleRepository import com.quadient.migration.tools.model.aBlock -import com.quadient.migration.tools.model.aDocumentObjectInternalRepository -import com.quadient.migration.tools.model.aParaStyleInternalRepository import com.quadient.migration.tools.model.aParagraph import com.quadient.migration.tools.model.aText -import com.quadient.migration.tools.model.aTextStyleInternalRepository import com.quadient.migration.tools.shouldBeEmpty import com.quadient.migration.tools.shouldBeEqualTo import io.mockk.every @@ -26,19 +23,17 @@ import org.junit.jupiter.api.Test @Postgres class StylesValidatorTest { - val documentObjectInternalRepository = aDocumentObjectInternalRepository() - val textStyleInternalRepository = aTextStyleInternalRepository() - val paraStyleInternalRepository = aParaStyleInternalRepository() - val textStyleRepository = TextStyleRepository(textStyleInternalRepository) - val paraStyleRepository = ParagraphStyleRepository(paraStyleInternalRepository) + val documentObjectRepository = aDocumentObjectRepository() + val textStyleRepository = aTextStyleRepository() + val paraStyleRepository = aParaStyleRepository() val ipsService = mockk() val documentObjectBuilder = mockk() val deployClient = mockk() val subject = StylesValidator( - documentObjectRepository = documentObjectInternalRepository, - textStyleRepository = textStyleInternalRepository, - paragraphStyleRepository = paraStyleInternalRepository, + documentObjectRepository = documentObjectRepository, + textStyleRepository = textStyleRepository, + paragraphStyleRepository = paraStyleRepository, documentObjectBuilder = documentObjectBuilder, deployClient = deployClient, ipsService = ipsService diff --git a/migration-library/src/test/kotlin/com/quadient/migration/service/deploy/DeployClientTest.kt b/migration-library/src/test/kotlin/com/quadient/migration/service/deploy/DeployClientTest.kt index 7f21e18a..946fda21 100644 --- a/migration-library/src/test/kotlin/com/quadient/migration/service/deploy/DeployClientTest.kt +++ b/migration-library/src/test/kotlin/com/quadient/migration/service/deploy/DeployClientTest.kt @@ -5,6 +5,7 @@ package com.quadient.migration.service.deploy import com.quadient.migration.api.dto.migrationmodel.StatusTracking import com.quadient.migration.api.repository.StatusTrackingRepository import com.quadient.migration.api.dto.migrationmodel.DocumentObject +import com.quadient.migration.api.dto.migrationmodel.DocumentObjectFilter import com.quadient.migration.api.dto.migrationmodel.DocumentObjectRef import com.quadient.migration.api.dto.migrationmodel.FileRef import com.quadient.migration.api.dto.migrationmodel.ImageRef @@ -12,11 +13,11 @@ import com.quadient.migration.api.dto.migrationmodel.Paragraph import com.quadient.migration.api.dto.migrationmodel.ParagraphStyleRef import com.quadient.migration.data.StatusEvent import com.quadient.migration.api.dto.migrationmodel.TextStyleRef -import com.quadient.migration.persistence.repository.DocumentObjectInternalRepository -import com.quadient.migration.persistence.repository.FileInternalRepository -import com.quadient.migration.persistence.repository.ImageInternalRepository -import com.quadient.migration.persistence.repository.ParagraphStyleInternalRepository -import com.quadient.migration.persistence.repository.TextStyleInternalRepository +import com.quadient.migration.api.repository.DocumentObjectRepository +import com.quadient.migration.api.repository.FileRepository +import com.quadient.migration.api.repository.ImageRepository +import com.quadient.migration.api.repository.ParagraphStyleRepository +import com.quadient.migration.api.repository.TextStyleRepository import com.quadient.migration.service.Storage import com.quadient.migration.service.inspirebuilder.DesignerDocumentObjectBuilder import com.quadient.migration.service.ipsclient.IpsService @@ -52,11 +53,11 @@ import kotlin.uuid.Uuid class DeployClientTest { - val documentObjectRepository = mockk() - val imageRepository = mockk() - val fileRepository = mockk() - val textStyleRepository = mockk() - val paragraphStyleRepository = mockk() + val documentObjectRepository = mockk() + val imageRepository = mockk() + val fileRepository = mockk() + val textStyleRepository = mockk() + val paragraphStyleRepository = mockk() val statusTrackingRepository = mockk() val documentObjectBuilder = mockk() val ipsService = mockk() @@ -92,10 +93,10 @@ class DeployClientTest { val img1 = aImage(id = "img2", metadata = mapOf("imgMeta" to listOf(MetadataPrimitive.Str("v3")))) val img2 = aImage(id = "img2", metadata = mapOf("imgMeta" to listOf(MetadataPrimitive.Str("v4")))) - every { documentObjectRepository.findModel("doc1") } returns doc1 - every { documentObjectRepository.findModel("doc2") } returns doc2 - every { imageRepository.findModel("img1") } returns img1 - every { imageRepository.findModel("img2") } returns img2 + every { documentObjectRepository.find("doc1") } returns doc1 + every { documentObjectRepository.find("doc2") } returns doc2 + every { imageRepository.find("img1") } returns img1 + every { imageRepository.find("img2") } returns img2 every { ipsService.writeMetadata(any()) } returns Unit val deploymentResult = DeploymentResult(Uuid.random()).apply { @@ -159,8 +160,8 @@ class DeployClientTest { givenNewExternalDocumentObject("1", deps = listOf("2")) givenNewExternalDocumentObject("2", deps = listOf("3", "4")) givenNewExternalDocumentObject("3", imageDeps = listOf("1", "2", "3"), fileDeps = listOf("1", "2")) - givenInternalDocumentObject("4", deps = listOf("1", "5")) - givenInternalDocumentObject("5", deps = listOf("6")) + givenDocumentObject("4", deps = listOf("1", "5")) + givenDocumentObject("5", deps = listOf("6")) givenNewExternalDocumentObject("6", deps = listOf("7")) givenNewExternalDocumentObject("7", deps = listOf()) givenNewImage("1") @@ -195,8 +196,8 @@ class DeployClientTest { givenChangedExternalDocumentObject("2", deps = listOf("3", "4"), deployTimestamp = currentDeployTimestamp, deploymentId = deploymentId) givenChangedExternalDocumentObject("8", deps = listOf("3", "4"), deployTimestamp = currentDeployTimestamp, icmPath = "icm://other.wfd", deploymentId = deploymentId) givenExistingExternalDocumentObject("3", imageDeps = listOf("1", "2", "3"), fileDeps = listOf("1", "2"), deployTimestamp = currentDeployTimestamp, deploymentId = deploymentId) - givenInternalDocumentObject("4", deps = listOf("1", "5")) - givenInternalDocumentObject("5", deps = listOf("6")) + givenDocumentObject("4", deps = listOf("1", "5")) + givenDocumentObject("5", deps = listOf("6")) givenNewExternalDocumentObject("6", deps = listOf("7")) givenNewExternalDocumentObject("7", deps = listOf()) givenNewImage("1") @@ -410,7 +411,7 @@ class DeployClientTest { } private fun givenImage(id: String, events: List = listOf()) { - every { imageRepository.findModelOrFail(id) } returns aImage(id = id) + every { imageRepository.findOrFail(id) } returns aImage(id = id) every { statusTrackingRepository.findEventsRelevantToOutput( id, ResourceType.Image, any() @@ -433,7 +434,7 @@ class DeployClientTest { } private fun givenFile(id: String, events: List = listOf()) { - every { fileRepository.findModelOrFail(id) } returns aFile(id = id) + every { fileRepository.findOrFail(id) } returns aFile(id = id) every { statusTrackingRepository.findEventsRelevantToOutput( id, ResourceType.File, any() @@ -530,22 +531,22 @@ class DeployClientTest { ) } + paragraphStyles.map { Paragraph(emptyList(), ParagraphStyleRef(it), null) }) ) - every { documentObjectRepository.list(any()) } returns externalObjects + every { documentObjectRepository.list(any()) } returns externalObjects every { statusTrackingRepository.findEventsRelevantToOutput( id, ResourceType.DocumentObject, any() ) } returns events for (id in textStyles) { - every { textStyleRepository.findModelOrFail(id) } returns aTextStyle(id = id) + every { textStyleRepository.findOrFail(id) } returns aTextStyle(id = id) } for (id in paragraphStyles) { - every { paragraphStyleRepository.findModelOrFail(id) } returns aParaStyle(id) + every { paragraphStyleRepository.findOrFail(id) } returns aParaStyle(id) } } - private fun givenInternalDocumentObject(id: String, deps: List = listOf()) { - every { documentObjectRepository.findModelOrFail(id) } returns aBlock( + private fun givenDocumentObject(id: String, deps: List = listOf()) { + every { documentObjectRepository.findOrFail(id) } returns aBlock( id = id, internal = true, content = deps.map { DocumentObjectRef(it, null) }) } } diff --git a/migration-library/src/test/kotlin/com/quadient/migration/service/deploy/DesignerDeployClientTest.kt b/migration-library/src/test/kotlin/com/quadient/migration/service/deploy/DesignerDeployClientTest.kt index 9a4cd92f..09045db6 100644 --- a/migration-library/src/test/kotlin/com/quadient/migration/service/deploy/DesignerDeployClientTest.kt +++ b/migration-library/src/test/kotlin/com/quadient/migration/service/deploy/DesignerDeployClientTest.kt @@ -7,17 +7,18 @@ import com.quadient.migration.api.repository.StatusTrackingRepository import com.quadient.migration.data.Active import com.quadient.migration.data.Deployed import com.quadient.migration.api.dto.migrationmodel.DocumentObject +import com.quadient.migration.api.dto.migrationmodel.DocumentObjectFilter import com.quadient.migration.data.Error import com.quadient.migration.api.dto.migrationmodel.File import com.quadient.migration.api.dto.migrationmodel.FileRef import com.quadient.migration.api.dto.migrationmodel.Image import com.quadient.migration.api.dto.migrationmodel.ImageRef import com.quadient.migration.api.dto.migrationmodel.StringValue -import com.quadient.migration.persistence.repository.DocumentObjectInternalRepository -import com.quadient.migration.persistence.repository.FileInternalRepository -import com.quadient.migration.persistence.repository.ImageInternalRepository -import com.quadient.migration.persistence.repository.ParagraphStyleInternalRepository -import com.quadient.migration.persistence.repository.TextStyleInternalRepository +import com.quadient.migration.api.repository.DocumentObjectRepository +import com.quadient.migration.api.repository.FileRepository +import com.quadient.migration.api.repository.ImageRepository +import com.quadient.migration.api.repository.ParagraphStyleRepository +import com.quadient.migration.api.repository.TextStyleRepository import com.quadient.migration.service.Storage import com.quadient.migration.service.inspirebuilder.DesignerDocumentObjectBuilder import com.quadient.migration.service.ipsclient.IpsService @@ -54,11 +55,11 @@ import kotlin.uuid.ExperimentalUuidApi import kotlin.uuid.Uuid class DesignerDeployClientTest { - val documentObjectRepository = mockk() - val imageRepository = mockk() - val fileRepository = mockk() - val textStyleRepository = mockk() - val paragraphStyleRepository = mockk() + val documentObjectRepository = mockk() + val imageRepository = mockk() + val fileRepository = mockk() + val textStyleRepository = mockk() + val paragraphStyleRepository = mockk() val statusTrackingRepository = mockk() val documentObjectBuilder = mockk() val ipsService = mockk() @@ -80,7 +81,7 @@ class DesignerDeployClientTest { fun setupAll() { every { documentObjectBuilder.shouldIncludeInternalDependency(any()) } answers { val documentObject = firstArg() - documentObject.internal || documentObject.type == DocumentObjectType.Page + (documentObject.internal ?: false) || documentObject.type == DocumentObjectType.Page } every { ipsService.writeMetadata(any()) } just runs } @@ -116,7 +117,7 @@ class DesignerDeployClientTest { every { statusTrackingRepository.findLastEventRelevantToOutput(any(), any(), any()) } returns Active() every { statusTrackingRepository.deployed(any(), any(), any(), any(), any(), any(), any()) } returns aDeployedStatus("id") - every { documentObjectRepository.list(any()) } returns listOf(template, externalBlock) + every { documentObjectRepository.list(any()) } returns listOf(template, externalBlock) every { documentObjectBuilder.getStyleDefinitionPath() } returns "icm://some/path/style.wfd" every { ipsService.fileExists(any()) } returns false @@ -138,7 +139,7 @@ class DesignerDeployClientTest { fun `deploy list of document objects validates that no document objects are skipped`() { val spy = spyk(subject) every { spy.deployDocumentObjectsInternal(any()) } returns DeploymentResult(Uuid.random()) - every { documentObjectRepository.list(any()) } returns listOf( + every { documentObjectRepository.list(any()) } returns listOf( aBlock(id = "1", skip = SkipOptions(true, null, null)), aBlock(id = "2", type = DocumentObjectType.Block), aBlock(id = "3", type = DocumentObjectType.Page), @@ -149,14 +150,14 @@ class DesignerDeployClientTest { val ex = assertThrows { spy.deployDocumentObjects(listOf("1", "2", "3")) } assertEquals("The following document objects are skipped: [1]. ", ex.message) - verify(exactly = 1) { documentObjectRepository.list(any()) } + verify(exactly = 1) { documentObjectRepository.list(any()) } } @Test fun `page objects are skipped in deploy`() { val spy = spyk(subject) every { spy.deployDocumentObjectsInternal(any()) } returns DeploymentResult(Uuid.random()) - every { documentObjectRepository.list(any()) } returns listOf( + every { documentObjectRepository.list(any()) } returns listOf( aBlock(id = "1", type = DocumentObjectType.Block), aBlock(id = "2", type = DocumentObjectType.Page), aBlock(id = "3", type = DocumentObjectType.Template), @@ -165,7 +166,7 @@ class DesignerDeployClientTest { spy.deployDocumentObjects(listOf("1", "2", "3", "4")) - verify(exactly = 1) { documentObjectRepository.list(any()) } + verify(exactly = 1) { documentObjectRepository.list(any()) } verify { spy.deployDocumentObjectsInternal(match { docObjects -> docObjects.size == 3 && docObjects.map { it.id } @@ -178,7 +179,7 @@ class DesignerDeployClientTest { fun `deploy list of document objects validates that no document objects are internal`() { val spy = spyk(subject) every { spy.deployDocumentObjectsInternal(any()) } returns DeploymentResult(Uuid.random()) - every { documentObjectRepository.list(any()) } returns listOf( + every { documentObjectRepository.list(any()) } returns listOf( aBlock(id = "1", internal = true), aBlock(id = "2", internal = true), aBlock(id = "3", internal = false), @@ -187,28 +188,28 @@ class DesignerDeployClientTest { val ex = assertThrows { spy.deployDocumentObjects(listOf("1", "2", "3")) } assertEquals("The following document objects are internal: [1, 2]. ", ex.message) - verify(exactly = 1) { documentObjectRepository.list(any()) } + verify(exactly = 1) { documentObjectRepository.list(any()) } } @Test fun `deploy list of document objects validates that no document are missing`() { val spy = spyk(subject) every { spy.deployDocumentObjectsInternal(any()) } returns DeploymentResult(Uuid.random()) - every { documentObjectRepository.list(any()) } returns listOf( + every { documentObjectRepository.list(any()) } returns listOf( aBlock(id = "1"), ) val ex = assertThrows { spy.deployDocumentObjects(listOf("1", "2", "3")) } assertEquals("The following document objects were not found: [2, 3]. ", ex.message) - verify(exactly = 1) { documentObjectRepository.list(any()) } + verify(exactly = 1) { documentObjectRepository.list(any()) } } @Test fun `deploy list of document objects has all kinds of problems`() { val spy = spyk(subject) every { spy.deployDocumentObjectsInternal(any()) } returns DeploymentResult(Uuid.random()) - every { documentObjectRepository.list(any()) } returns listOf( + every { documentObjectRepository.list(any()) } returns listOf( aBlock(id = "1"), aBlock(id = "2", internal = true), aBlock(id = "3"), @@ -229,7 +230,7 @@ class DesignerDeployClientTest { "The following document objects were not found: [8]. The following document objects are internal: [2]. The following document objects are skipped: [6]. ", ex.message ) - verify(exactly = 1) { documentObjectRepository.list(any()) } + verify(exactly = 1) { documentObjectRepository.list(any()) } } @Test @@ -242,11 +243,11 @@ class DesignerDeployClientTest { aBlock(id = "2", content = listOf(aDocumentObjectRef("5"))), aBlock(id = "3", content = listOf(aDocumentObjectRef("6"))), ) - every { documentObjectRepository.list(any()) } returns docObjects + every { documentObjectRepository.list(any()) } returns docObjects spy.deployDocumentObjects(toDeploy, true) - verify(exactly = 1) { documentObjectRepository.list(any()) } + verify(exactly = 1) { documentObjectRepository.list(any()) } verify { spy.deployDocumentObjectsInternal(docObjects) } } @@ -267,15 +268,15 @@ class DesignerDeployClientTest { aBlock(id = "7", content = listOf(aDocumentObjectRef("8"))), aBlock(id = "8", internal = true), ) - every { documentObjectRepository.list(any()) } returns docObjects + every { documentObjectRepository.list(any()) } returns docObjects for (dependency in dependencies) { - every { documentObjectRepository.findModelOrFail(dependency.id) } returns dependency + every { documentObjectRepository.findOrFail(dependency.id) } returns dependency } spy.deployDocumentObjects(toDeploy) - verify(exactly = 1) { documentObjectRepository.list(any()) } - verify(exactly = 7) { documentObjectRepository.findModelOrFail(any()) } + verify(exactly = 1) { documentObjectRepository.list(any()) } + verify(exactly = 7) { documentObjectRepository.findOrFail(any()) } verify { spy.deployDocumentObjectsInternal(match { docObjects -> docObjects.size == 7 && docObjects.map { it.id } @@ -292,14 +293,14 @@ class DesignerDeployClientTest { val docObjects = listOf( aBlock(id = "1", content = listOf(aDocumentObjectRef("4"))), ) - every { documentObjectRepository.list(any()) } returns docObjects - every { documentObjectRepository.findModelOrFail(any()) } throws IllegalArgumentException("not found") + every { documentObjectRepository.list(any()) } returns docObjects + every { documentObjectRepository.findOrFail(any()) } throws IllegalArgumentException("not found") val ex = assertThrows { spy.deployDocumentObjects(toDeploy) } assertEquals("not found", ex.message) - verify(exactly = 1) { documentObjectRepository.list(any()) } - verify(exactly = 1) { documentObjectRepository.findModelOrFail(any()) } + verify(exactly = 1) { documentObjectRepository.list(any()) } + verify(exactly = 1) { documentObjectRepository.findOrFail(any()) } } @Test @@ -309,8 +310,8 @@ class DesignerDeployClientTest { val block = mockObj(aDocObj("B_1", DocumentObjectType.Block, listOf(aDocumentObjectRef(innerBlock.id)))) val template = mockObj(aDocObj("T_1", DocumentObjectType.Template, listOf(aDocumentObjectRef(block.id)))) - every { documentObjectRepository.findModel(innerBlock.id) } throws IllegalStateException("Not found") - every { documentObjectRepository.list(any()) } returns listOf(template, block) + every { documentObjectRepository.find(innerBlock.id) } throws IllegalStateException("Not found") + every { documentObjectRepository.list(any()) } returns listOf(template, block) every { documentObjectBuilder.buildDocumentObject(block, any()) } throws IllegalStateException("Inner block not found") every { statusTrackingRepository.findLastEventRelevantToOutput(any(), any(), any()) } returns Active() every { statusTrackingRepository.deployed(any(), any(), any(), any(), any(), any(), any()) } returns aDeployedStatus("id") @@ -339,13 +340,14 @@ class DesignerDeployClientTest { } private fun mockImg(image: Image, success: Boolean = true): Image { + val sourcePath = image.sourcePath val imagePath = "icm://${image.nameOrId()}" every { documentObjectBuilder.getImagePath(image) } returns imagePath - every { imageRepository.findModel(image.id) } returns image - if (!image.sourcePath.isNullOrBlank()) { + every { imageRepository.find(image.id) } returns image + if (!sourcePath.isNullOrBlank()) { val byteArray = ByteArray(10) - every { storage.read(image.sourcePath) } answers { + every { storage.read(sourcePath) } answers { if (success) { byteArray } else { @@ -359,13 +361,14 @@ class DesignerDeployClientTest { } private fun mockFile(file: File, success: Boolean = true): File { + val sourcePath = file.sourcePath val filePath = "icm://${file.nameOrId()}" every { documentObjectBuilder.getFilePath(file) } returns filePath - every { fileRepository.findModel(file.id) } returns file - if (!file.sourcePath.isNullOrBlank()) { + every { fileRepository.find(file.id) } returns file + if (!sourcePath.isNullOrBlank()) { val byteArray = ByteArray(10) - every { storage.read(file.sourcePath) } answers { + every { storage.read(sourcePath) } answers { if (success) { byteArray } else { @@ -379,7 +382,7 @@ class DesignerDeployClientTest { } private fun mockObj(documentObject: DocumentObject): DocumentObject { - every { documentObjectRepository.findModel(documentObject.id) } returns documentObject + every { documentObjectRepository.find(documentObject.id) } returns documentObject if (documentObject.internal == false) { val xml = "${documentObject.nameOrId()}" @@ -423,7 +426,7 @@ class DesignerDeployClientTest { // then verify(exactly = 0) { documentObjectBuilder.buildDocumentObject(any(), any()) } - verify(exactly = 0) { imageRepository.findModel(any()) } + verify(exactly = 0) { imageRepository.find(any()) } } @Test @@ -525,8 +528,8 @@ class DesignerDeployClientTest { every { statusTrackingRepository.findLastEventRelevantToOutput(any(), any(), any()) } returns Active() every { statusTrackingRepository.deployed(any(), any(), any(), any(), any(), any()) } returns aDeployedStatus("id") - every { textStyleRepository.listAllModel() } returns emptyList() - every { paragraphStyleRepository.listAllModel() } returns emptyList() + every { textStyleRepository.listAll() } returns emptyList() + every { paragraphStyleRepository.listAll() } returns emptyList() every { ipsService.xml2wfd(any(), any()) } returns OperationResult.Success val definitionPathWfd = "icm://defaultFolder/CompanyStyles.wfd" @@ -547,8 +550,8 @@ class DesignerDeployClientTest { every { statusTrackingRepository.findLastEventRelevantToOutput(any(), any(), any()) } returns Active() every { statusTrackingRepository.deployed(any(), any(), any(), any(), any(), any()) } returns aDeployedStatus("id") - every { textStyleRepository.listAllModel() } returns emptyList() - every { paragraphStyleRepository.listAllModel() } returns emptyList() + every { textStyleRepository.listAll() } returns emptyList() + every { paragraphStyleRepository.listAll() } returns emptyList() every { ipsService.xml2wfd(any(), any()) } returns OperationResult.Failure("Problem") val definitionPath = "icm://defaultFolder/CompanyStyles.wfd" diff --git a/migration-library/src/test/kotlin/com/quadient/migration/service/deploy/InteractiveDeployClientTest.kt b/migration-library/src/test/kotlin/com/quadient/migration/service/deploy/InteractiveDeployClientTest.kt index e0444830..5b3589f5 100644 --- a/migration-library/src/test/kotlin/com/quadient/migration/service/deploy/InteractiveDeployClientTest.kt +++ b/migration-library/src/test/kotlin/com/quadient/migration/service/deploy/InteractiveDeployClientTest.kt @@ -3,30 +3,31 @@ package com.quadient.migration.service.deploy import com.quadient.migration.api.InspireOutput +import com.quadient.migration.api.dto.migrationmodel.DocumentObject +import com.quadient.migration.api.dto.migrationmodel.DocumentObjectFilter +import com.quadient.migration.api.dto.migrationmodel.File +import com.quadient.migration.api.dto.migrationmodel.FileRef +import com.quadient.migration.api.dto.migrationmodel.Image +import com.quadient.migration.api.dto.migrationmodel.ImageRef +import com.quadient.migration.api.dto.migrationmodel.Paragraph +import com.quadient.migration.api.dto.migrationmodel.StringValue +import com.quadient.migration.api.dto.migrationmodel.VariableRef +import com.quadient.migration.api.repository.DocumentObjectRepository +import com.quadient.migration.api.repository.FileRepository +import com.quadient.migration.api.repository.ImageRepository +import com.quadient.migration.api.repository.ParagraphStyleRepository import com.quadient.migration.api.repository.StatusTrackingRepository +import com.quadient.migration.api.repository.TextStyleRepository import com.quadient.migration.data.Active import com.quadient.migration.data.Deployed -import com.quadient.migration.data.DocumentObjectModel import com.quadient.migration.data.Error -import com.quadient.migration.data.FileModel -import com.quadient.migration.data.FileModelRef -import com.quadient.migration.data.ImageModel -import com.quadient.migration.data.ImageModelRef -import com.quadient.migration.data.ParagraphModel -import com.quadient.migration.data.ParagraphModel.TextModel -import com.quadient.migration.data.StringModel -import com.quadient.migration.data.VariableModelRef -import com.quadient.migration.persistence.repository.DocumentObjectInternalRepository -import com.quadient.migration.persistence.repository.FileInternalRepository -import com.quadient.migration.persistence.repository.ImageInternalRepository -import com.quadient.migration.persistence.repository.ParagraphStyleInternalRepository -import com.quadient.migration.persistence.repository.TextStyleInternalRepository import com.quadient.migration.service.Storage import com.quadient.migration.service.inspirebuilder.InteractiveDocumentObjectBuilder import com.quadient.migration.service.ipsclient.IpsService import com.quadient.migration.service.ipsclient.OperationResult import com.quadient.migration.service.resolveTargetDir import com.quadient.migration.shared.DocumentObjectType +import com.quadient.migration.shared.IcmPath import com.quadient.migration.shared.ImageType import com.quadient.migration.shared.MetadataPrimitive import com.quadient.migration.shared.SkipOptions @@ -60,11 +61,11 @@ import kotlin.uuid.ExperimentalUuidApi import kotlin.uuid.Uuid class InteractiveDeployClientTest { - val documentObjectRepository = mockk() - val imageRepository = mockk() - val fileRepository = mockk() - val textStyleRepository = mockk() - val paragraphStyleRepository = mockk() + val documentObjectRepository = mockk() + val imageRepository = mockk() + val fileRepository = mockk() + val textStyleRepository = mockk() + val paragraphStyleRepository = mockk() val statusTrackingRepository = mockk() val documentObjectBuilder = mockk() val ipsService = mockk() @@ -88,7 +89,7 @@ class InteractiveDeployClientTest { @BeforeEach fun setupAll() { every { documentObjectBuilder.shouldIncludeInternalDependency(any()) } answers { - firstArg().internal + firstArg().internal ?: false } every { ipsService.writeMetadata(any()) } just runs every { ipsService.setProductionApprovalState(any()) } returns OperationResult.Success @@ -100,7 +101,7 @@ class InteractiveDeployClientTest { mockBasicDocumentObjects() mockBasicSuccessfulIpsOperations() every { documentObjectBuilder.buildDocumentObject(any(), any()) } returns "" - every { documentObjectRepository.findModel(any()) } returns aBlock("99", internal = false) + every { documentObjectRepository.find(any()) } returns aBlock("99", internal = false) every { statusTrackingRepository.findLastEventRelevantToOutput(any(), any(), any()) } returns Active() every { statusTrackingRepository.deployed(any(), any(), any(), any(), any(), any(), any()) } returns aDeployedStatus("id") @@ -124,8 +125,8 @@ class InteractiveDeployClientTest { val externalBlock = mockDocumentObject( aBlock( "1", listOf( - ParagraphModel( - listOf(TextModel(listOf(StringModel("some text"), VariableModelRef("V_1")), null, null)), + Paragraph( + listOf(Paragraph.Text(listOf(StringValue("some text"), VariableRef("V_1")), null, null)), null, null ) @@ -135,8 +136,8 @@ class InteractiveDeployClientTest { mockDocumentObject( aBlock( "2", listOf( - ParagraphModel( - listOf(TextModel(listOf(StringModel("inner text"), VariableModelRef("V_2")), null, null)), + Paragraph( + listOf(Paragraph.Text(listOf(StringValue("inner text"), VariableRef("V_2")), null, null)), null, null ) @@ -146,9 +147,9 @@ class InteractiveDeployClientTest { val template = mockDocumentObject(aTemplate("3", listOf(aDocumentObjectRef("block1"), aDocumentObjectRef("block2")))) - every { documentObjectRepository.list(any()) } returns listOf(externalBlock, template) + every { documentObjectRepository.list(any()) } returns listOf(externalBlock, template) every { documentObjectBuilder.buildDocumentObject(any(), any()) } returns "" - every { documentObjectRepository.findModel(any()) } returns aBlock("99", internal = false) + every { documentObjectRepository.find(any()) } returns aBlock("99", internal = false) every { statusTrackingRepository.findLastEventRelevantToOutput(any(), any(), any()) } returns Active() every { statusTrackingRepository.deployed(any(), any(), any(), any(), any(), any(), any()) } returns aDeployedStatus("id") @@ -178,7 +179,7 @@ class InteractiveDeployClientTest { ) } returns OperationResult.Failure("Problem") every { documentObjectBuilder.buildDocumentObject(any(), any()) } returns "" - every { documentObjectRepository.findModel(any()) } returns aBlock("99", internal = false) + every { documentObjectRepository.find(any()) } returns aBlock("99", internal = false) every { statusTrackingRepository.findLastEventRelevantToOutput(any(), any(), any()) } returns Active() every { statusTrackingRepository.deployed(any(), any(), any(), any(), any(), any(), any()) } returns aDeployedStatus("id") every { statusTrackingRepository.error(any(), any(), any(), any(), any(), any(), any(), any()) } returns aErrorStatus("id") @@ -205,8 +206,8 @@ class InteractiveDeployClientTest { val block = mockDocumentObject( aBlock( "1", listOf( - ParagraphModel( - listOf(TextModel(listOf(StringModel("some text"), VariableModelRef("V_1")), null, null)), + Paragraph( + listOf(Paragraph.Text(listOf(StringValue("some text"), VariableRef("V_1")), null, null)), null, null ) @@ -217,9 +218,9 @@ class InteractiveDeployClientTest { val template = mockDocumentObject(aTemplate("3", listOf(aDocumentObjectRef("block1"), aDocumentObjectRef("block2")))) - every { documentObjectRepository.list(any()) } returns listOf(block, template) + every { documentObjectRepository.list(any()) } returns listOf(block, template) every { documentObjectBuilder.buildDocumentObject(any(), any()) } returns "" - every { documentObjectRepository.findModel(any()) } returns aBlock("99", internal = false) + every { documentObjectRepository.find(any()) } returns aBlock("99", internal = false) every { statusTrackingRepository.findLastEventRelevantToOutput(any(), any(), any()) } returns Active() every { statusTrackingRepository.deployed(any(), any(), any(), any(), any(), any(), any()) } returns aDeployedStatus("id") @@ -243,9 +244,9 @@ class InteractiveDeployClientTest { // given val image = mockImage(aImage("Bunny")) val file = mockFile(aFile("Report")) - val block = mockDocumentObject(aBlock(id = "1", listOf(ImageModelRef(image.id), FileModelRef(file.id)))) + val block = mockDocumentObject(aBlock(id = "1", listOf(ImageRef(image.id), FileRef(file.id)))) - every { documentObjectRepository.list(any()) } returns listOf(block) + every { documentObjectRepository.list(any()) } returns listOf(block) every { documentObjectBuilder.buildDocumentObject(any(), any()) } returns "" every { ipsService.tryUpload(any(), any()) } returns OperationResult.Success every { statusTrackingRepository.findLastEventRelevantToOutput(any(), any(), any()) } returns Active() @@ -281,14 +282,14 @@ class InteractiveDeployClientTest { val block = mockDocumentObject( aBlock("1", listOf( - ImageModelRef(catImage.id), - ImageModelRef(dogImage.id), - FileModelRef(missingFile.id), - FileModelRef(skippedFile.id) + ImageRef(catImage.id), + ImageRef(dogImage.id), + FileRef(missingFile.id), + FileRef(skippedFile.id) )) ) - every { documentObjectRepository.list(any()) } returns listOf(block) + every { documentObjectRepository.list(any()) } returns listOf(block) every { documentObjectBuilder.buildDocumentObject(any(), any()) } returns "" every { ipsService.upload(any(), any()) } just runs every { statusTrackingRepository.findLastEventRelevantToOutput(any(), any(), any()) } returns Active() @@ -314,19 +315,19 @@ class InteractiveDeployClientTest { // given val image = mockImage(aImage("Bunny")) val file = mockFile(aFile("Report")) - val innerBlock = aBlock("10", listOf(ImageModelRef(image.id), FileModelRef(file.id)), internal = true) + val innerBlock = aBlock("10", listOf(ImageRef(image.id), FileRef(file.id)), internal = true) val block = mockDocumentObject( aBlock( "1", listOf( aDocumentObjectRef(innerBlock.id), - aParagraph(aText(ImageModelRef(image.id))), - aParagraph(aText(FileModelRef(file.id))) + aParagraph(aText(ImageRef(image.id))), + aParagraph(aText(FileRef(file.id))) ) ) ) - every { documentObjectRepository.list(any()) } returns listOf(block) - every { documentObjectRepository.findModel(innerBlock.id) } returns innerBlock + every { documentObjectRepository.list(any()) } returns listOf(block) + every { documentObjectRepository.find(innerBlock.id) } returns innerBlock every { documentObjectBuilder.buildDocumentObject(any(), any()) } returns "" every { statusTrackingRepository.findLastEventRelevantToOutput(any(), any(), any()) } returns Active() every { statusTrackingRepository.deployed(any(), any(), any(), any(), any(), any(), any()) } returns aDeployedStatus("id") @@ -357,8 +358,8 @@ class InteractiveDeployClientTest { every { statusTrackingRepository.findLastEventRelevantToOutput(any(), any(), any()) } returns Active() every { statusTrackingRepository.deployed(any(), any(), any(), any(), any(), any()) } returns aDeployedStatus("id") - every { textStyleRepository.listAllModel() } returns emptyList() - every { paragraphStyleRepository.listAllModel() } returns emptyList() + every { textStyleRepository.listAll() } returns emptyList() + every { paragraphStyleRepository.listAll() } returns emptyList() every { ipsService.xml2wfd(any(), any()) } returns OperationResult.Success every { ipsService.deployStyleJld(any(), any(), any()) } returns OperationResult.Success every { ipsService.setProductionApprovalState(any()) } returns OperationResult.Success @@ -387,8 +388,8 @@ class InteractiveDeployClientTest { every { statusTrackingRepository.findLastEventRelevantToOutput(any(), any(), any()) } returns Active() every { statusTrackingRepository.deployed(any(), any(), any(), any(), any(), any()) } returns aDeployedStatus("id") - every { textStyleRepository.listAllModel() } returns emptyList() - every { paragraphStyleRepository.listAllModel() } returns emptyList() + every { textStyleRepository.listAll() } returns emptyList() + every { paragraphStyleRepository.listAll() } returns emptyList() every { ipsService.xml2wfd(any(), any()) } returns OperationResult.Failure("Problem") val definitionPath = @@ -457,7 +458,7 @@ class InteractiveDeployClientTest { fun `deploy list of document objects validates that no document objects are unsupported`() { val spy = spyk(subject) every { spy.deployDocumentObjectsInternal(any()) } returns DeploymentResult(Uuid.random()) - every { documentObjectRepository.list(any()) } returns listOf( + every { documentObjectRepository.list(any()) } returns listOf( aBlock(id = "1", skip = SkipOptions(true, null, null)), aBlock(id = "2", type = DocumentObjectType.Block), aBlock(id = "3", skip = SkipOptions(true, null, null)), @@ -466,14 +467,14 @@ class InteractiveDeployClientTest { val ex = assertThrows { spy.deployDocumentObjects(listOf("1", "2", "3")) } assertEquals("The following document objects are skipped: [1, 3]. ", ex.message) - verify(exactly = 1) { documentObjectRepository.list(any()) } + verify(exactly = 1) { documentObjectRepository.list(any()) } } @Test - fun `deploy list of document objects validates that no document objects are internal`() { + fun `deploy list of document objects validates that no document objects are `() { val spy = spyk(subject) every { spy.deployDocumentObjectsInternal(any()) } returns DeploymentResult(Uuid.random()) - every { documentObjectRepository.list(any()) } returns listOf( + every { documentObjectRepository.list(any()) } returns listOf( aBlock(id = "1", internal = true), aBlock(id = "2", internal = true), aBlock(id = "3", internal = false), @@ -482,28 +483,28 @@ class InteractiveDeployClientTest { val ex = assertThrows { spy.deployDocumentObjects(listOf("1", "2", "3")) } assertEquals("The following document objects are internal: [1, 2]. ", ex.message) - verify(exactly = 1) { documentObjectRepository.list(any()) } + verify(exactly = 1) { documentObjectRepository.list(any()) } } @Test fun `deploy list of document objects validates that no document are missing`() { val spy = spyk(subject) every { spy.deployDocumentObjectsInternal(any()) } returns DeploymentResult(Uuid.random()) - every { documentObjectRepository.list(any()) } returns listOf( + every { documentObjectRepository.list(any()) } returns listOf( aBlock(id = "1"), ) val ex = assertThrows { spy.deployDocumentObjects(listOf("1", "2", "3")) } assertEquals("The following document objects were not found: [2, 3]. ", ex.message) - verify(exactly = 1) { documentObjectRepository.list(any()) } + verify(exactly = 1) { documentObjectRepository.list(any()) } } @Test fun `deploy list of document objects has all kinds of problems`() { val spy = spyk(subject) every { spy.deployDocumentObjectsInternal(any()) } returns DeploymentResult(Uuid.random()) - every { documentObjectRepository.list(any()) } returns listOf( + every { documentObjectRepository.list(any()) } returns listOf( aBlock(id = "1"), aBlock(id = "2", internal = true), aBlock(id = "3"), @@ -524,7 +525,7 @@ class InteractiveDeployClientTest { "The following document objects were not found: [8]. The following document objects are skipped: [6]. The following document objects are internal: [2]. ", ex.message ) - verify(exactly = 1) { documentObjectRepository.list(any()) } + verify(exactly = 1) { documentObjectRepository.list(any()) } } @Test @@ -537,11 +538,11 @@ class InteractiveDeployClientTest { aBlock(id = "2", content = listOf(aDocumentObjectRef("5"))), aBlock(id = "3", content = listOf(aDocumentObjectRef("6"))), ) - every { documentObjectRepository.list(any()) } returns docObjects + every { documentObjectRepository.list(any()) } returns docObjects spy.deployDocumentObjects(toDeploy, true) - verify(exactly = 1) { documentObjectRepository.list(any()) } + verify(exactly = 1) { documentObjectRepository.list(any()) } verify { spy.deployDocumentObjectsInternal(docObjects) } } @@ -562,15 +563,15 @@ class InteractiveDeployClientTest { aBlock(id = "7", content = listOf(aDocumentObjectRef("8"))), aBlock(id = "8", internal = true), ) - every { documentObjectRepository.list(any()) } returns docObjects + every { documentObjectRepository.list(any()) } returns docObjects for (dependency in dependencies) { - every { documentObjectRepository.findModelOrFail(dependency.id) } returns dependency + every { documentObjectRepository.findOrFail(dependency.id) } returns dependency } spy.deployDocumentObjects(toDeploy) - verify(exactly = 1) { documentObjectRepository.list(any()) } - verify(exactly = 7) { documentObjectRepository.findModelOrFail(any()) } + verify(exactly = 1) { documentObjectRepository.list(any()) } + verify(exactly = 7) { documentObjectRepository.findOrFail(any()) } verify { spy.deployDocumentObjectsInternal(match { docObjects -> docObjects.size == 7 && docObjects.map { it.id } @@ -587,14 +588,14 @@ class InteractiveDeployClientTest { val docObjects = listOf( aBlock(id = "1", content = listOf(aDocumentObjectRef("4"))), ) - every { documentObjectRepository.list(any()) } returns docObjects - every { documentObjectRepository.findModelOrFail(any()) } throws IllegalArgumentException("not found") + every { documentObjectRepository.list(any()) } returns docObjects + every { documentObjectRepository.findOrFail(any()) } throws IllegalArgumentException("not found") val ex = assertThrows { spy.deployDocumentObjects(toDeploy) } assertEquals("not found", ex.message) - verify(exactly = 1) { documentObjectRepository.list(any()) } - verify(exactly = 1) { documentObjectRepository.findModelOrFail(any()) } + verify(exactly = 1) { documentObjectRepository.list(any()) } + verify(exactly = 1) { documentObjectRepository.findOrFail(any()) } } @Test @@ -607,8 +608,8 @@ class InteractiveDeployClientTest { mockBasicSuccessfulIpsOperations() every { statusTrackingRepository.findLastEventRelevantToOutput(any(), any(), any()) } returns Active() every { statusTrackingRepository.deployed(any(), any(), any(), any(), any(), any(), any()) } returns aDeployedStatus("id") - every { documentObjectRepository.findModel(innerBlock.id) } throws IllegalStateException("Not found") - every { documentObjectRepository.list(any()) } returns listOf(template, block) + every { documentObjectRepository.find(innerBlock.id) } throws IllegalStateException("Not found") + every { documentObjectRepository.list(any()) } returns listOf(template, block) every { documentObjectBuilder.buildDocumentObject(block, any()) } throws IllegalStateException("Inner block not found") every { statusTrackingRepository.error("B_1", any(), any(), any(), any(), any(), any(), any()) } returns aErrorStatus("B_1") @@ -637,10 +638,10 @@ class InteractiveDeployClientTest { mockDocumentObject( aBlock( it.toString(), listOf( - ParagraphModel( + Paragraph( listOf( - TextModel( - listOf(StringModel("some text $it"), VariableModelRef("some var $it")), null, null + Paragraph.Text( + listOf(StringValue("some text $it"), VariableRef("some var $it")), null, null ) ), null, null ) @@ -651,38 +652,40 @@ class InteractiveDeployClientTest { val templates = List(1) { mockDocumentObject(aTemplate(it.toString(), listOf(aDocumentObjectRef("block$it")))) } - every { documentObjectRepository.list(any()) } returns blocks + templates + every { documentObjectRepository.list(any()) } returns blocks + templates } - private fun mockDocumentObject(documentObject: DocumentObjectModel): DocumentObjectModel { + private fun mockDocumentObject(documentObject: DocumentObject): DocumentObject { val interactiveFolder = documentObject.type.toInteractiveFolder() - val dir = resolveTargetDir(config.defaultTargetFolder, documentObject.targetFolder) + val dir = resolveTargetDir(config.defaultTargetFolder, documentObject.targetFolder?.let { IcmPath.from(it) }) every { documentObjectBuilder.getDocumentObjectPath(documentObject) } returns "icm://Interactive/$tenant/$interactiveFolder/$dir/${documentObject.nameOrId()}.jld" - every { documentObjectRepository.findModel(documentObject.id) } returns documentObject + every { documentObjectRepository.find(documentObject.id) } returns documentObject return documentObject } - private fun mockImage(image: ImageModel, success: Boolean = true): ImageModel { + private fun mockImage(image: Image, success: Boolean = true): Image { + val sourcePath = image.sourcePath val dir = resolveTargetDir(config.defaultTargetFolder) every { documentObjectBuilder.getImagePath(image) } returns "icm://Interactive/$tenant/Resources/Images/$dir/${image.sourcePath}" - every { imageRepository.findModel(image.id) } returns if (success) { image } else { null } - if (!image.sourcePath.isNullOrBlank()) { - every { storage.read(image.sourcePath) } returns ByteArray(10) + every { imageRepository.find(image.id) } returns if (success) { image } else { null } + if (!sourcePath.isNullOrBlank()) { + every { storage.read(sourcePath) } returns ByteArray(10) } return image } - private fun mockFile(file: FileModel, success: Boolean = true): FileModel { + private fun mockFile(file: File, success: Boolean = true): File { + val sourcePath = file.sourcePath val dir = resolveTargetDir(config.defaultTargetFolder) every { documentObjectBuilder.getFilePath(file) } returns "icm://Interactive/$tenant/Resources/Files/$dir/${file.sourcePath}" - every { fileRepository.findModel(file.id) } returns if (success) { file } else { null } - if (!file.sourcePath.isNullOrBlank()) { - every { storage.read(file.sourcePath) } returns ByteArray(10) + every { fileRepository.find(file.id) } returns if (success) { file } else { null } + if (!sourcePath.isNullOrBlank()) { + every { storage.read(sourcePath) } returns ByteArray(10) } return file @@ -701,10 +704,10 @@ class InteractiveDeployClientTest { verify { ipsService.setProductionApprovalState(expectedOutputPaths) } } - private fun mockObj(documentObject: DocumentObjectModel): DocumentObjectModel { - every { documentObjectRepository.findModel(documentObject.id) } returns documentObject + private fun mockObj(documentObject: DocumentObject): DocumentObject { + every { documentObjectRepository.find(documentObject.id) } returns documentObject - if (!documentObject.internal) { + if (!(documentObject.internal ?: false)) { val xml = "${documentObject.nameOrId()}" val outputPath = "icm://${documentObject.nameOrId()}" @@ -732,9 +735,9 @@ class InteractiveDeployClientTest { fun `deployDocumentObjects does not do anything when all objects are deployed`() { // given val docObjects = listOf( - aDocObj("D_1", content = listOf(ImageModelRef("I_1"))), - aDocObj("D_2", content = listOf(ImageModelRef("I_2"))), - aDocObj("D_3", content = listOf(ImageModelRef("I_3"))), + aDocObj("D_1", content = listOf(ImageRef("I_1"))), + aDocObj("D_2", content = listOf(ImageRef("I_2"))), + aDocObj("D_3", content = listOf(ImageRef("I_3"))), ) givenObjectIsDeployed("D_1") givenObjectIsDeployed("I_1") @@ -748,16 +751,16 @@ class InteractiveDeployClientTest { // then verify(exactly = 0) { documentObjectBuilder.buildDocumentObject(any(), any()) } - verify(exactly = 0) { imageRepository.findModel(any()) } + verify(exactly = 0) { imageRepository.find(any()) } } @Test fun `deployDocumentObjects skips deployed but deploys active and error`() { // given val docObjects = listOf( - aDocObj("D_1", content = listOf(ImageModelRef("I_1"))), - aDocObj("D_2", content = listOf(ImageModelRef("I_2"))), - aDocObj("D_3", content = listOf(ImageModelRef("I_3"))), + aDocObj("D_1", content = listOf(ImageRef("I_1"))), + aDocObj("D_2", content = listOf(ImageRef("I_2"))), + aDocObj("D_3", content = listOf(ImageRef("I_3"))), ) mockImage(aImage("I_1")) mockImage(aImage("I_2")) @@ -784,7 +787,7 @@ class InteractiveDeployClientTest { @Test fun `deployDocumentObjects records errors`() { // given - val docObjects = listOf(aDocObj("D_1", content = listOf(ImageModelRef("I_1")))) + val docObjects = listOf(aDocObj("D_1", content = listOf(ImageRef("I_1")))) givenObjectIsActive("D_1") givenObjectIsActive("I_1") mockImage(aImage("I_1"), success = false) @@ -841,7 +844,7 @@ class InteractiveDeployClientTest { var count = 0 for (key in DeployClient.IMAGE_DISALLOWED_METADATA) { // given - val docObjects = listOf(aDocObj("D_1", content = listOf(ImageModelRef("I_1"))) ) + val docObjects = listOf(aDocObj("D_1", content = listOf(ImageRef("I_1"))) ) givenObjectIsActive("D_1") givenObjectIsActive("I_1") mockImage(aImage("I_1", metadata = mapOf(key to listOf(MetadataPrimitive.Str("value"))))) @@ -864,7 +867,7 @@ class InteractiveDeployClientTest { @Test fun `deployImages allows Subject metadata`() { // given - val docObjects = listOf(aDocObj("D_1", content = listOf(ImageModelRef("I_1"))) ) + val docObjects = listOf(aDocObj("D_1", content = listOf(ImageRef("I_1"))) ) givenObjectIsActive("D_1") givenObjectIsActive("I_1") mockImage(aImage("I_1", metadata = mapOf("other" to listOf(MetadataPrimitive.Str("value"))))) diff --git a/migration-library/src/test/kotlin/com/quadient/migration/service/inspirebuilder/DesignerDocumentObjectBuilderTest.kt b/migration-library/src/test/kotlin/com/quadient/migration/service/inspirebuilder/DesignerDocumentObjectBuilderTest.kt index 7d2598c0..a295a3a8 100644 --- a/migration-library/src/test/kotlin/com/quadient/migration/service/inspirebuilder/DesignerDocumentObjectBuilderTest.kt +++ b/migration-library/src/test/kotlin/com/quadient/migration/service/inspirebuilder/DesignerDocumentObjectBuilderTest.kt @@ -4,25 +4,25 @@ import com.fasterxml.jackson.dataformat.xml.XmlMapper import com.quadient.migration.api.InspireOutput import com.quadient.migration.api.PathsConfig import com.quadient.migration.api.ProjectConfig -import com.quadient.migration.data.DisplayRuleModel -import com.quadient.migration.data.DisplayRuleModelRef -import com.quadient.migration.data.DocumentObjectModel -import com.quadient.migration.data.FirstMatchModel -import com.quadient.migration.data.ImageModel -import com.quadient.migration.data.ImageModelRef -import com.quadient.migration.data.StringModel -import com.quadient.migration.data.TableModel -import com.quadient.migration.data.VariableModel -import com.quadient.migration.data.VariableModelRef -import com.quadient.migration.data.VariableStructureModel -import com.quadient.migration.persistence.repository.DisplayRuleInternalRepository -import com.quadient.migration.persistence.repository.DocumentObjectInternalRepository -import com.quadient.migration.persistence.repository.FileInternalRepository -import com.quadient.migration.persistence.repository.ImageInternalRepository -import com.quadient.migration.persistence.repository.ParagraphStyleInternalRepository -import com.quadient.migration.persistence.repository.TextStyleInternalRepository -import com.quadient.migration.persistence.repository.VariableInternalRepository -import com.quadient.migration.persistence.repository.VariableStructureInternalRepository +import com.quadient.migration.api.dto.migrationmodel.DisplayRule +import com.quadient.migration.api.dto.migrationmodel.DisplayRuleRef +import com.quadient.migration.api.dto.migrationmodel.DocumentObject +import com.quadient.migration.api.dto.migrationmodel.FirstMatch +import com.quadient.migration.api.dto.migrationmodel.Image +import com.quadient.migration.api.dto.migrationmodel.ImageRef +import com.quadient.migration.api.dto.migrationmodel.StringValue +import com.quadient.migration.api.dto.migrationmodel.Table +import com.quadient.migration.api.dto.migrationmodel.Variable +import com.quadient.migration.api.dto.migrationmodel.VariableRef +import com.quadient.migration.api.dto.migrationmodel.VariableStructure +import com.quadient.migration.api.repository.DisplayRuleRepository +import com.quadient.migration.api.repository.DocumentObjectRepository +import com.quadient.migration.api.repository.FileRepository +import com.quadient.migration.api.repository.ImageRepository +import com.quadient.migration.api.repository.ParagraphStyleRepository +import com.quadient.migration.api.repository.TextStyleRepository +import com.quadient.migration.api.repository.VariableRepository +import com.quadient.migration.api.repository.VariableStructureRepository import com.quadient.migration.service.ipsclient.IpsService import com.quadient.migration.shared.BinOp import com.quadient.migration.shared.DataType @@ -35,6 +35,7 @@ import com.quadient.migration.shared.LiteralDataType import com.quadient.migration.shared.PageOptions import com.quadient.migration.shared.Position import com.quadient.migration.shared.SkipOptions +import com.quadient.migration.shared.TablePdfTaggingRule import com.quadient.migration.shared.VariablePathData import com.quadient.migration.shared.centimeters import com.quadient.migration.shared.millimeters @@ -53,7 +54,7 @@ import com.quadient.migration.tools.model.aSelectByLanguage import com.quadient.migration.tools.model.aText import com.quadient.migration.tools.model.aTextDef import com.quadient.migration.tools.model.aTextStyle -import com.quadient.migration.tools.model.aVariableStructureModel +import com.quadient.migration.tools.model.aVariableStructure import com.quadient.migration.tools.model.anArea import com.quadient.migration.tools.shouldBeEqualTo import com.quadient.migration.tools.shouldNotBeEmpty @@ -69,14 +70,14 @@ import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.CsvSource class DesignerDocumentObjectBuilderTest { - val documentObjectRepository = mockk() - val textStyleRepository = mockk() - val paragraphStyleRepository = mockk() - val variableRepository = mockk() - val variableStructureRepository = mockk() - val displayRuleRepository = mockk() - val imageRepository = mockk() - val fileRepository = mockk() + val documentObjectRepository = mockk() + val textStyleRepository = mockk() + val paragraphStyleRepository = mockk() + val variableRepository = mockk() + val variableStructureRepository = mockk() + val displayRuleRepository = mockk() + val imageRepository = mockk() + val fileRepository = mockk() val ipsService = mockk() val config = aProjectConfig(targetDefaultFolder = "defaultFolder") @@ -86,9 +87,9 @@ class DesignerDocumentObjectBuilderTest { @BeforeEach fun setUp() { - every { variableStructureRepository.listAllModel() } returns emptyList() - every { textStyleRepository.listAllModel() } returns emptyList() - every { paragraphStyleRepository.listAllModel() } returns emptyList() + every { variableStructureRepository.listAll() } returns emptyList() + every { textStyleRepository.listAll() } returns emptyList() + every { paragraphStyleRepository.listAll() } returns emptyList() every { ipsService.gatherFontData(any()) } returns "Arial,Regular,icm://Fonts/arial.ttf;" } @@ -98,13 +99,13 @@ class DesignerDocumentObjectBuilderTest { val block = mockObj( aDocObj( "B_1", Block, listOf( - aParagraph(aText(StringModel("Hello there!"))) + aParagraph(aText(StringValue("Hello there!"))) ), true ) ) val standaloneBlock = mockObj( - aDocObj("B_2", Block, listOf(aParagraph(aText(StringModel("I am alone"))))) + aDocObj("B_2", Block, listOf(aParagraph(aText(StringValue("I am alone"))))) ) val page = mockObj( aDocObj( @@ -174,7 +175,7 @@ class DesignerDocumentObjectBuilderTest { "P_1", Page, listOf( anArea( - listOf(ImageModelRef(image.id)), + listOf(ImageRef(image.id)), Position(60.millimeters(), 60.millimeters(), 10.centimeters(), 10.centimeters()), ) ), @@ -201,13 +202,13 @@ class DesignerDocumentObjectBuilderTest { @Test fun `buildDocumentObject creates image area with image in case of flow area only with valid image ref`() { - val imageModel = mockImg(aImage("Img_1")) + val Image = mockImg(aImage("Img_1")) val page = mockObj( aDocObj( "P_1", Page, listOf( anArea( listOf( - ImageModelRef(imageModel.id) + ImageRef(Image.id) ), Position(60.millimeters(), 120.millimeters(), 20.centimeters(), 10.centimeters()) ), ) @@ -229,19 +230,19 @@ class DesignerDocumentObjectBuilderTest { val image = result["Image"].last { it["Id"].textValue() == imageId } image["ImageLocation"].textValue() - .shouldBeEqualTo("VCSLocation,icm://${config.defaultTargetFolder}/${imageModel.nameOrId()}.jpg") + .shouldBeEqualTo("VCSLocation,icm://${config.defaultTargetFolder}/${Image.nameOrId()}.jpg") } @Test - fun `buildDocumentObject creates image with alternate text from ImageModel`() { + fun `buildDocumentObject creates image with alternate text from Image`() { // given - val imageModel = mockImg(aImage("Img_1", alternateText = "Description of the image")) + val Image = mockImg(aImage("Img_1", alternateText = "Description of the image")) val page = mockObj( aDocObj( "P_1", Page, listOf( anArea( listOf( - ImageModelRef(imageModel.id) + ImageRef(Image.id) ), Position(60.millimeters(), 120.millimeters(), 20.centimeters(), 10.centimeters()) ), ) @@ -271,7 +272,7 @@ class DesignerDocumentObjectBuilderTest { ) val block = mockObj( aDocObj( - "B_1", Block, listOf(aParagraph(aText(StringModel("Hi")))) + "B_1", Block, listOf(aParagraph(aText(StringValue("Hi")))) ) ) val template = mockObj(aDocObj("T_1", Template, listOf(aDocumentObjectRef(block.id, rule.id)))) @@ -302,20 +303,20 @@ class DesignerDocumentObjectBuilderTest { val block = mockObj( aDocObj( "B_1", Block, listOf( - TableModel( + Table( listOf( aRow( listOf( - aCell(aParagraph(aText(StringModel("A")))), - aCell(aParagraph(aText(StringModel("B")))) + aCell(aParagraph(aText(StringValue("A")))), + aCell(aParagraph(aText(StringValue("B")))) ) ), aRow( listOf( - aCell(aParagraph(aText(StringModel("C")))), - aCell(aParagraph(aText(StringModel("D")))) + aCell(aParagraph(aText(StringValue("C")))), + aCell(aParagraph(aText(StringValue("D")))) ), rule.id ) - ), listOf(), pdfTaggingRule = com.quadient.migration.shared.TablePdfTaggingRule.Table, pdfAlternateText = "Table alt text" + ), listOf(), pdfTaggingRule = TablePdfTaggingRule.Table, pdfAlternateText = "Table alt text" ) ) ) @@ -341,7 +342,7 @@ class DesignerDocumentObjectBuilderTest { @Test fun `buildDocumentObject creates twice used block only once`() { // given - val block = mockObj(aDocObj("B_1", Block, listOf(aParagraph(aText(StringModel("Hi")))))) + val block = mockObj(aDocObj("B_1", Block, listOf(aParagraph(aText(StringValue("Hi")))))) val template = mockObj( aDocObj( "T_1", Template, listOf( @@ -362,14 +363,14 @@ class DesignerDocumentObjectBuilderTest { fun `buildDocumentObject names multiple composite flows with numbers`() { // given val innerBlock = mockObj( - aDocObj("B_2", Block, listOf(aParagraph(aText(StringModel("In between")))), internal = true) + aDocObj("B_2", Block, listOf(aParagraph(aText(StringValue("In between")))), internal = true) ) val block = mockObj( aDocObj( "B_1", Block, listOf( - aParagraph(aText(StringModel("Hi"))), + aParagraph(aText(StringValue("Hi"))), aDocumentObjectRef(innerBlock.id), - aParagraph(aText(StringModel("Bye"))) + aParagraph(aText(StringValue("Bye"))) ), internal = true ) ) @@ -403,7 +404,7 @@ class DesignerDocumentObjectBuilderTest { "B_1", Block, listOf( aParagraph( aText( - listOf(StringModel("First usage: "), VariableModelRef(variable.id)) + listOf(StringValue("First usage: "), VariableRef(variable.id)) ) ) ), true @@ -414,7 +415,7 @@ class DesignerDocumentObjectBuilderTest { "B_2", Block, listOf( aParagraph( aText( - listOf(StringModel("Second usage: "), VariableModelRef(variable.id)) + listOf(StringValue("Second usage: "), VariableRef(variable.id)) ) ) ), true @@ -428,9 +429,9 @@ class DesignerDocumentObjectBuilderTest { ) ) val varStructure = mockVarStructure( - aVariableStructureModel( + aVariableStructure( structure = mapOf( - VariableModelRef(variable.id) to VariablePathData("Data.Records.Value") + variable.id to VariablePathData("Data.Records.Value") ) ) ) @@ -460,14 +461,14 @@ class DesignerDocumentObjectBuilderTest { @Test fun `block with first match is built to inline condition flow with multiple options`() { // given - val defaultFlowModel = mockObj(aDocObj("B_10", Block, listOf(aParagraph(aText(StringModel("I am default")))))) + val defaultFlowModel = mockObj(aDocObj("B_10", Block, listOf(aParagraph(aText(StringValue("I am default")))))) val rule1 = mockRule( aDisplayRule( Literal("A", LiteralDataType.String), BinOp.Equals, Literal("B", LiteralDataType.String), id = "R_1" ) ) val flow1 = - mockObj(aDocObj("B_11", Block, listOf(aParagraph(aText(StringModel("flow 1 content")))), internal = false)) + mockObj(aDocObj("B_11", Block, listOf(aParagraph(aText(StringValue("flow 1 content")))), internal = false)) val rule2 = mockRule( aDisplayRule( @@ -478,13 +479,13 @@ class DesignerDocumentObjectBuilderTest { val block = mockObj( aDocObj( "B_1", Block, listOf( - FirstMatchModel( + FirstMatch( cases = listOf( - FirstMatchModel.CaseModel( - DisplayRuleModelRef(rule1.id), listOf(aDocumentObjectRef(flow1.id)), null - ), FirstMatchModel.CaseModel( - DisplayRuleModelRef(rule2.id), - listOf(aParagraph(aText(StringModel("flow 2 content")))), + FirstMatch.Case( + DisplayRuleRef(rule1.id), listOf(aDocumentObjectRef(flow1.id)), null + ), FirstMatch.Case( + DisplayRuleRef(rule2.id), + listOf(aParagraph(aText(StringValue("flow 2 content")))), null ) ), default = defaultFlowModel.content @@ -539,7 +540,7 @@ class DesignerDocumentObjectBuilderTest { ) val block = - mockObj(aDocObj("B_1", Block, listOf(aParagraph(aText(StringModel("Text")))), displayRuleRef = rule.id)) + mockObj(aDocObj("B_1", Block, listOf(aParagraph(aText(StringValue("Text")))), displayRuleRef = rule.id)) // when val result = subject.buildDocumentObject(block, null).let { xmlMapper.readTree(it.trimIndent()) }["Layout"]["Layout"] @@ -643,19 +644,19 @@ class DesignerDocumentObjectBuilderTest { val variable = mockVar(aVariable("V_1")) val varNoPath = mockVar(aVariable("V_2")) val variableStructureA = mockVarStructure( - aVariableStructureModel( + aVariableStructure( "VS_1", structure = mapOf( - VariableModelRef(variable.id) to VariablePathData("Data.Records.Value"), - VariableModelRef(varNoPath.id) to VariablePathData("", "No Path Variable") + variable.id to VariablePathData("Data.Records.Value"), + varNoPath.id to VariablePathData("", "No Path Variable") ) ) ) val variableStructureB = mockVarStructure( - aVariableStructureModel( - "VS_2", structure = mapOf(VariableModelRef(variable.id) to VariablePathData("Data.Clients.Value")) + aVariableStructure( + "VS_2", structure = mapOf(variable.id to VariablePathData("Data.Clients.Value")) ) ) - every { variableStructureRepository.listAllModel() } returns listOf(variableStructureA, variableStructureB) + every { variableStructureRepository.listAll() } returns listOf(variableStructureA, variableStructureB) val config = aProjectConfig(defaultVariableStructure = variableStructureB.id) val block = mockObj( @@ -664,11 +665,11 @@ class DesignerDocumentObjectBuilderTest { aParagraph( aText( listOf( - StringModel("Text"), VariableModelRef(variable.id), VariableModelRef(varNoPath.id) + StringValue("Text"), VariableRef(variable.id), VariableRef(varNoPath.id) ) ) ) - ), variableStructureModelRef = variableStructureA.id + ), VariableStructureRef = variableStructureA.id ) ) @@ -677,8 +678,8 @@ class DesignerDocumentObjectBuilderTest { val result = subject.buildDocumentObject(block, null).let { xmlMapper.readTree(it.trimIndent()) }["Layout"]["Layout"] // then - verify(exactly = 1) { variableStructureRepository.findModelOrFail(variableStructureA.id) } - verify(exactly = 0) { variableStructureRepository.findModelOrFail(variableStructureB.id) } + verify(exactly = 1) { variableStructureRepository.findOrFail(variableStructureA.id) } + verify(exactly = 0) { variableStructureRepository.findOrFail(variableStructureB.id) } result["Variable"].first { it["Name"].textValue() == variable.nameOrId() }["ParentId"].textValue() .shouldBeEqualTo("Data.Records.Value") @@ -692,12 +693,12 @@ class DesignerDocumentObjectBuilderTest { fun `font data are gathered only once per multiple builds`() { // given val textStyle = aTextStyle("TS_1", definition = aTextDef(fontFamily = "Calibri", bold = true)) - every { textStyleRepository.listAllModel() } returns listOf(textStyle) - every { textStyleRepository.firstWithDefinitionModel(textStyle.id) } returns textStyle + every { textStyleRepository.listAll() } returns listOf(textStyle) + every { textStyleRepository.firstWithDefinition(textStyle.id) } returns textStyle val blockA = - mockObj(aDocObj("B_1", Block, listOf(aParagraph(aText(StringModel("Hello There!"), textStyle.id))))) - val blockB = mockObj(aDocObj("B_2", Block, listOf(aParagraph(aText(StringModel("Bye!"), textStyle.id))))) + mockObj(aDocObj("B_1", Block, listOf(aParagraph(aText(StringValue("Hello There!"), textStyle.id))))) + val blockB = mockObj(aDocObj("B_2", Block, listOf(aParagraph(aText(StringValue("Bye!"), textStyle.id))))) every { ipsService.gatherFontData(any()) } returns "Calibri,Bold,icm://calibrib.ttf;" // when @@ -708,28 +709,28 @@ class DesignerDocumentObjectBuilderTest { verify(exactly = 1) { ipsService.gatherFontData("icm://") } } - private fun mockObj(documentObject: DocumentObjectModel): DocumentObjectModel { - every { documentObjectRepository.findModelOrFail(documentObject.id) } returns documentObject + private fun mockObj(documentObject: DocumentObject): DocumentObject { + every { documentObjectRepository.findOrFail(documentObject.id) } returns documentObject return documentObject } - private fun mockImg(image: ImageModel): ImageModel { - every { imageRepository.findModelOrFail(image.id) } returns image + private fun mockImg(image: Image): Image { + every { imageRepository.findOrFail(image.id) } returns image return image } - private fun mockRule(rule: DisplayRuleModel): DisplayRuleModel { - every { displayRuleRepository.findModelOrFail(rule.id) } returns rule + private fun mockRule(rule: DisplayRule): DisplayRule { + every { displayRuleRepository.findOrFail(rule.id) } returns rule return rule } - private fun mockVar(variable: VariableModel): VariableModel { - every { variableRepository.findModelOrFail(variable.id) } returns variable + private fun mockVar(variable: Variable): Variable { + every { variableRepository.findOrFail(variable.id) } returns variable return variable } - private fun mockVarStructure(variableStructure: VariableStructureModel): VariableStructureModel { - every { variableStructureRepository.findModelOrFail(variableStructure.id) } returns variableStructure + private fun mockVarStructure(variableStructure: VariableStructure): VariableStructure { + every { variableStructureRepository.findOrFail(variableStructure.id) } returns variableStructure return variableStructure } @@ -750,9 +751,9 @@ class DesignerDocumentObjectBuilderTest { fun `builds language variable if defined`() { // given val languageVariable = mockVar(aVariable("LangVar", dataType = DataType.String)) - val structure = aVariableStructureModel( + val structure = aVariableStructure( languageVariable = "LangVar", - structure = mapOf(VariableModelRef("LangVar") to VariablePathData("Data.Language")) + structure = mapOf("LangVar" to VariablePathData("Data.Language")) ) val block = aDocObj( id = "obj", content = listOf( @@ -762,10 +763,10 @@ class DesignerDocumentObjectBuilderTest { ) ), ), - variableStructureModelRef = structure.id + VariableStructureRef = structure.id ) - every { variableStructureRepository.findModelOrFail(any()) } returns structure - every { variableRepository.findModelOrFail(any()) } returns languageVariable + every { variableStructureRepository.findOrFail(any()) } returns structure + every { variableRepository.findOrFail(any()) } returns languageVariable // when val result = subject.buildDocumentObject(block, null).let { xmlMapper.readTree(it.trimIndent()) } diff --git a/migration-library/src/test/kotlin/com/quadient/migration/service/inspirebuilder/InspireDocumentObjectBuilderTest.kt b/migration-library/src/test/kotlin/com/quadient/migration/service/inspirebuilder/InspireDocumentObjectBuilderTest.kt index b5527b94..c9e95bd5 100644 --- a/migration-library/src/test/kotlin/com/quadient/migration/service/inspirebuilder/InspireDocumentObjectBuilderTest.kt +++ b/migration-library/src/test/kotlin/com/quadient/migration/service/inspirebuilder/InspireDocumentObjectBuilderTest.kt @@ -2,15 +2,22 @@ package com.quadient.migration.service.inspirebuilder import com.fasterxml.jackson.dataformat.xml.XmlMapper import com.quadient.migration.api.InspireOutput -import com.quadient.migration.data.DisplayRuleModel -import com.quadient.migration.data.DocumentObjectModel -import com.quadient.migration.data.FileModel -import com.quadient.migration.data.FileModelRef -import com.quadient.migration.data.HyperlinkModel -import com.quadient.migration.data.StringModel -import com.quadient.migration.data.TextStyleModel -import com.quadient.migration.data.TextStyleModelRef -import com.quadient.migration.persistence.repository.* +import com.quadient.migration.api.dto.migrationmodel.DisplayRule +import com.quadient.migration.api.dto.migrationmodel.DocumentObject +import com.quadient.migration.api.dto.migrationmodel.File +import com.quadient.migration.api.dto.migrationmodel.FileRef +import com.quadient.migration.api.dto.migrationmodel.Hyperlink +import com.quadient.migration.api.dto.migrationmodel.StringValue +import com.quadient.migration.api.dto.migrationmodel.TextStyle +import com.quadient.migration.api.dto.migrationmodel.TextStyleRef +import com.quadient.migration.api.repository.DisplayRuleRepository +import com.quadient.migration.api.repository.DocumentObjectRepository +import com.quadient.migration.api.repository.FileRepository +import com.quadient.migration.api.repository.ImageRepository +import com.quadient.migration.api.repository.ParagraphStyleRepository +import com.quadient.migration.api.repository.TextStyleRepository +import com.quadient.migration.api.repository.VariableRepository +import com.quadient.migration.api.repository.VariableStructureRepository import com.quadient.migration.service.ipsclient.IpsService import com.quadient.migration.shared.BinOp import com.quadient.migration.shared.Function @@ -29,14 +36,14 @@ import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test class InspireDocumentObjectBuilderTest { - private val documentObjectRepository = mockk() - private val textStyleRepository = mockk() - private val paragraphStyleRepository = mockk() - private val variableRepository = mockk() - private val variableStructureRepository = mockk() - private val displayRuleRepository = mockk() - private val imageRepository = mockk() - private val fileRepository = mockk() + private val documentObjectRepository = mockk() + private val textStyleRepository = mockk() + private val paragraphStyleRepository = mockk() + private val variableRepository = mockk() + private val variableStructureRepository = mockk() + private val displayRuleRepository = mockk() + private val imageRepository = mockk() + private val fileRepository = mockk() private val ipsService = mockk() private val xmlMapper = XmlMapper().also { it.findAndRegisterModules() } @@ -56,9 +63,9 @@ class InspireDocumentObjectBuilderTest { @BeforeEach fun setUp() { - every { variableStructureRepository.listAllModel() } returns emptyList() - every { textStyleRepository.listAllModel() } returns emptyList() - every { paragraphStyleRepository.listAllModel() } returns emptyList() + every { variableStructureRepository.listAll() } returns emptyList() + every { textStyleRepository.listAll() } returns emptyList() + every { paragraphStyleRepository.listAll() } returns emptyList() every { ipsService.gatherFontData(any()) } returns "Arial,Regular,icm://Fonts/arial.ttf;" every { ipsService.fileExists(any()) } returns true } @@ -73,7 +80,7 @@ class InspireDocumentObjectBuilderTest { pdfTaggingRule = com.quadient.migration.shared.ParagraphPdfTaggingRule.Paragraph ) ) - every { paragraphStyleRepository.listAllModel() } returns listOf(paragraphStyle) + every { paragraphStyleRepository.listAll() } returns listOf(paragraphStyle) // when val result = subject.buildStyles(emptyList(), listOf(paragraphStyle)) @@ -90,8 +97,8 @@ class InspireDocumentObjectBuilderTest { @Test fun `buildDocumentObject with hyperlink creates text style with URL variable and alternate text`() { // given - val hyperlink = HyperlinkModel("https://www.example.com", "Click here", "Link to example website") - val textContent = listOf(StringModel("Visit our site: "), hyperlink, StringModel(" for more info")) + val hyperlink = Hyperlink("https://www.example.com", "Click here", "Link to example website") + val textContent = listOf(StringValue("Visit our site: "), hyperlink, StringValue(" for more info")) val block = mockObj(aBlock("B_1", listOf(aParagraph(aText(textContent))))) // when @@ -128,10 +135,10 @@ class InspireDocumentObjectBuilderTest { aParagraph( aText( listOf( - StringModel("Some text before link. "), - HyperlinkModel("https://www.example.com", "Link text"), - StringModel(" Some text after link.") - ), TextStyleModelRef(textStyle.id) + StringValue("Some text before link. "), + Hyperlink("https://www.example.com", "Link text"), + StringValue(" Some text after link.") + ), TextStyleRef(textStyle.id) ) ) ) @@ -161,9 +168,9 @@ class InspireDocumentObjectBuilderTest { fun `file reference creates DirectExternal flow with correct structure`() { // given val file = aFile("File_1", name = "document", sourcePath = "C:/files/document.pdf") - every { fileRepository.findModelOrFail(file.id) } returns file + every { fileRepository.findOrFail(file.id) } returns file val block = mockObj( - aBlock("B_1", listOf(aParagraph(aText(listOf(StringModel("See attached: "), FileModelRef(file.id)))))) + aBlock("B_1", listOf(aParagraph(aText(listOf(StringValue("See attached: "), FileRef(file.id)))))) ) // when @@ -186,9 +193,9 @@ class InspireDocumentObjectBuilderTest { fun `file reference with skip and placeholder creates simple flow with placeholder text`() { // given val file = aFile("File_1", skip = SkipOptions(true, "File not available", "Missing source")) - every { fileRepository.findModelOrFail(file.id) } returns file + every { fileRepository.findOrFail(file.id) } returns file val block = mockObj( - aBlock("B_1", listOf(aParagraph(aText(listOf(FileModelRef(file.id)))))) + aBlock("B_1", listOf(aParagraph(aText(listOf(FileRef(file.id)))))) ) // when @@ -209,7 +216,7 @@ class InspireDocumentObjectBuilderTest { aParagraph( aText( listOf( - StringModel("Text "), FileModelRef(file.id), StringModel(" more text") + StringValue("Text "), FileRef(file.id), StringValue(" more text") ) ) ) @@ -225,20 +232,20 @@ class InspireDocumentObjectBuilderTest { flow["FlowContent"]["P"]["T"][""].textValue().shouldBeEqualTo("Text more text") } - private fun mockObj(documentObject: DocumentObjectModel): DocumentObjectModel { - every { documentObjectRepository.findModelOrFail(documentObject.id) } returns documentObject + private fun mockObj(documentObject: DocumentObject): DocumentObject { + every { documentObjectRepository.findOrFail(documentObject.id) } returns documentObject return documentObject } - private fun mockFile(file: FileModel): FileModel { - every { fileRepository.findModelOrFail(file.id) } returns file + private fun mockFile(file: File): File { + every { fileRepository.findOrFail(file.id) } returns file return file } - private fun mockTextStyle(textStyle: TextStyleModel): TextStyleModel { - every { textStyleRepository.firstWithDefinitionModel(textStyle.id) } returns textStyle - val currentAllStyles = textStyleRepository.listAllModel() - every { textStyleRepository.listAllModel() } returns currentAllStyles + textStyle + private fun mockTextStyle(textStyle: TextStyle): TextStyle { + every { textStyleRepository.firstWithDefinition(textStyle.id) } returns textStyle + val currentAllStyles = textStyleRepository.listAll() + every { textStyleRepository.listAll() } returns currentAllStyles + textStyle return textStyle } @@ -286,7 +293,6 @@ class InspireDocumentObjectBuilderTest { operator = BinOp.EqualsCaseInsensitive, right = Literal("B", LiteralDataType.String) ) - val result = rule.toScript() result.shouldBeEqualTo("""return (String('A').equalCaseInsensitive(String('B')));""") @@ -305,10 +311,10 @@ class InspireDocumentObjectBuilderTest { result.shouldBeEqualTo("""return ((not String('A').equalCaseInsensitive(String('B'))));""") } - private fun DisplayRuleModel.toScript(): String { + private fun DisplayRule.toScript(): String { return definition?.toScript( layout = LayoutImpl(), - variableStructure = aVariableStructureModel("some struct"), + variableStructure = aVariableStructure("some struct"), findVar = { aVariable(it) } ) ?: error("No definition") } diff --git a/migration-library/src/test/kotlin/com/quadient/migration/service/inspirebuilder/InteractiveDocumentObjectBuilderTest.kt b/migration-library/src/test/kotlin/com/quadient/migration/service/inspirebuilder/InteractiveDocumentObjectBuilderTest.kt index ab5e3b43..b8d615c2 100644 --- a/migration-library/src/test/kotlin/com/quadient/migration/service/inspirebuilder/InteractiveDocumentObjectBuilderTest.kt +++ b/migration-library/src/test/kotlin/com/quadient/migration/service/inspirebuilder/InteractiveDocumentObjectBuilderTest.kt @@ -4,29 +4,29 @@ import com.fasterxml.jackson.dataformat.xml.XmlMapper import com.quadient.migration.api.InspireOutput import com.quadient.migration.api.PathsConfig import com.quadient.migration.api.ProjectConfig -import com.quadient.migration.data.DisplayRuleModel -import com.quadient.migration.data.DisplayRuleModelRef -import com.quadient.migration.data.DocumentObjectModel -import com.quadient.migration.data.FirstMatchModel -import com.quadient.migration.data.ImageModel -import com.quadient.migration.data.ImageModelRef -import com.quadient.migration.data.ParagraphStyleModelRef -import com.quadient.migration.data.StringModel -import com.quadient.migration.data.TabModel -import com.quadient.migration.data.TableModel -import com.quadient.migration.data.TabsModel -import com.quadient.migration.data.TextStyleModelRef -import com.quadient.migration.data.VariableModel -import com.quadient.migration.data.VariableModelRef -import com.quadient.migration.data.VariableStructureModel -import com.quadient.migration.persistence.repository.DisplayRuleInternalRepository -import com.quadient.migration.persistence.repository.DocumentObjectInternalRepository -import com.quadient.migration.persistence.repository.FileInternalRepository -import com.quadient.migration.persistence.repository.ImageInternalRepository -import com.quadient.migration.persistence.repository.ParagraphStyleInternalRepository -import com.quadient.migration.persistence.repository.TextStyleInternalRepository -import com.quadient.migration.persistence.repository.VariableInternalRepository -import com.quadient.migration.persistence.repository.VariableStructureInternalRepository +import com.quadient.migration.api.dto.migrationmodel.DisplayRule +import com.quadient.migration.api.dto.migrationmodel.DisplayRuleRef +import com.quadient.migration.api.dto.migrationmodel.DocumentObject +import com.quadient.migration.api.dto.migrationmodel.FirstMatch +import com.quadient.migration.api.dto.migrationmodel.Image +import com.quadient.migration.api.dto.migrationmodel.ImageRef +import com.quadient.migration.api.dto.migrationmodel.ParagraphStyleRef +import com.quadient.migration.api.dto.migrationmodel.StringValue +import com.quadient.migration.api.dto.migrationmodel.Tab +import com.quadient.migration.api.dto.migrationmodel.Table +import com.quadient.migration.api.dto.migrationmodel.Tabs +import com.quadient.migration.api.dto.migrationmodel.TextStyleRef +import com.quadient.migration.api.dto.migrationmodel.Variable +import com.quadient.migration.api.dto.migrationmodel.VariableRef +import com.quadient.migration.api.dto.migrationmodel.VariableStructure +import com.quadient.migration.api.repository.DisplayRuleRepository +import com.quadient.migration.api.repository.DocumentObjectRepository +import com.quadient.migration.api.repository.FileRepository +import com.quadient.migration.api.repository.ImageRepository +import com.quadient.migration.api.repository.ParagraphStyleRepository +import com.quadient.migration.api.repository.TextStyleRepository +import com.quadient.migration.api.repository.VariableRepository +import com.quadient.migration.api.repository.VariableStructureRepository import com.quadient.migration.service.getBaseTemplateFullPath import com.quadient.migration.service.ipsclient.IpsService import com.quadient.migration.shared.BinOp.* @@ -46,6 +46,7 @@ import com.quadient.migration.shared.TabType import com.quadient.migration.shared.VariablePathData import com.quadient.migration.shared.millimeters import com.quadient.migration.shared.toIcmPath +import com.quadient.migration.tools.aCell import com.quadient.migration.tools.model.aBlock import com.quadient.migration.tools.model.aDisplayRule import com.quadient.migration.tools.model.aParagraph @@ -64,7 +65,7 @@ import com.quadient.migration.tools.model.aText import com.quadient.migration.tools.model.aTextDef import com.quadient.migration.tools.model.aTextStyle import com.quadient.migration.tools.model.aVariable -import com.quadient.migration.tools.model.aVariableStructureModel +import com.quadient.migration.tools.model.aVariableStructure import com.quadient.migration.tools.model.anArea import com.quadient.migration.tools.shouldBeEqualTo import com.quadient.migration.tools.shouldBeNull @@ -83,14 +84,14 @@ import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.CsvSource class InteractiveDocumentObjectBuilderTest { - val documentObjectRepository = mockk() - val textStyleRepository = mockk() - val paragraphStyleRepository = mockk() - val variableRepository = mockk() - val variableStructureRepository = mockk() - val displayRuleRepository = mockk() - val imageRepository = mockk() - val fileRepository = mockk() + val documentObjectRepository = mockk() + val textStyleRepository = mockk() + val paragraphStyleRepository = mockk() + val variableRepository = mockk() + val variableStructureRepository = mockk() + val displayRuleRepository = mockk() + val imageRepository = mockk() + val fileRepository = mockk() val config = aProjectConfig() val ipsService = mockk() @@ -100,7 +101,7 @@ class InteractiveDocumentObjectBuilderTest { @BeforeEach fun setUp() { - every { variableStructureRepository.listAllModel() } returns emptyList() + every { variableStructureRepository.listAll() } returns emptyList() every { ipsService.fileExists(any()) } returns true } @@ -109,9 +110,9 @@ class InteractiveDocumentObjectBuilderTest { // given val variable = aVariable("var1", "varName1") val block = aBlock( - "1", listOf(aParagraph(aText(listOf(StringModel("some text"), VariableModelRef(variable.id))))) + "1", listOf(aParagraph(aText(listOf(StringValue("some text"), VariableRef(variable.id))))) ) - every { variableRepository.findModelOrFail(eq(variable.id)) } returns variable + every { variableRepository.findOrFail(eq(variable.id)) } returns variable // when val result = subject.buildDocumentObject(block, null).let { xmlMapper.readTree(it.trimIndent()) } @@ -131,10 +132,10 @@ class InteractiveDocumentObjectBuilderTest { val textStyle = aTextStyle("textStyle1", definition = aTextDef(fontFamily = "Arial")) val block = aBlock( - "1", listOf(aParagraph(aText(StringModel("some text"), textStyle.id), paraStyle.id)) + "1", listOf(aParagraph(aText(StringValue("some text"), textStyle.id), paraStyle.id)) ) - every { textStyleRepository.firstWithDefinitionModel(textStyle.id) } returns textStyle - every { paragraphStyleRepository.firstWithDefinitionModel(paraStyle.id) } returns paraStyle + every { textStyleRepository.firstWithDefinition(textStyle.id) } returns textStyle + every { paragraphStyleRepository.firstWithDefinition(paraStyle.id) } returns paraStyle // when val result = subject.buildDocumentObject(block, null).let { xmlMapper.readTree(it.trimIndent()) } @@ -151,10 +152,10 @@ class InteractiveDocumentObjectBuilderTest { @Test fun `build template with reference to block results in direct external flow`() { // given - val block = aBlock("1", listOf(aParagraph(aText(StringModel("Hello"))))) + val block = aBlock("1", listOf(aParagraph(aText(StringValue("Hello"))))) val template = aTemplate("2", listOf(aDocumentObjectRef(block.id))) - every { documentObjectRepository.findModelOrFail(block.id) } returns block + every { documentObjectRepository.findOrFail(block.id) } returns block // when val result = subject.buildDocumentObject(template, null).let { xmlMapper.readTree(it.trimIndent()) } @@ -179,7 +180,7 @@ class InteractiveDocumentObjectBuilderTest { val variable = aVariable("clientName") val block = aBlock( "1", listOf( - TableModel( + Table( listOf( aRow( listOf( @@ -187,28 +188,28 @@ class InteractiveDocumentObjectBuilderTest { aParagraph( aText( listOf( - StringModel("Hello "), - VariableModelRef(variable.id), - StringModel(" how are you?") + StringValue("Hello "), + VariableRef(variable.id), + StringValue(" how are you?") ) ) ) - ), aCell(aParagraph(aText(StringModel("First row, second cell ")))) + ), aCell(aParagraph(aText(StringValue("First row, second cell ")))) ) ), aRow( listOf( - aCell(aParagraph(aText(StringModel("Second row, first cell")))), - aCell(aParagraph(aText(StringModel("Second row, second cell"))), mergeLeft = true) + aCell(aParagraph(aText(StringValue("Second row, first cell")))), + aCell(aParagraph(aText(StringValue("Second row, second cell"))), mergeLeft = true) ) ) ), listOf( - TableModel.ColumnWidthModel(Size.ofMillimeters(150), 10.0), - TableModel.ColumnWidthModel(Size.ofCentimeters(3), 1.0) + Table.ColumnWidth(Size.ofMillimeters(150), 10.0), + Table.ColumnWidth(Size.ofCentimeters(3), 1.0) ) ) ) ) - every { variableRepository.findModelOrFail(eq(variable.id)) } returns variable + every { variableRepository.findOrFail(eq(variable.id)) } returns variable // when val result = subject.buildDocumentObject(block, null).let { xmlMapper.readTree(it.trimIndent()) } @@ -237,21 +238,21 @@ class InteractiveDocumentObjectBuilderTest { @Test fun `build of more nested and complex structure is correctly wrapped into section if required`() { // given - val externalBlock = aBlock("1", listOf(aParagraph(aText(StringModel("Hello"))))) - val internalBlock = aBlock("2", listOf(aParagraph(aText(StringModel("Sir")))), internal = true) + val externalBlock = aBlock("1", listOf(aParagraph(aText(StringValue("Hello"))))) + val Block = aBlock("2", listOf(aParagraph(aText(StringValue("Sir")))), internal = true) val section = aBlock( "5", type = Section, content = listOf( aDocumentObjectRef(externalBlock.id), - aParagraph(aText(StringModel("In between"))), - aDocumentObjectRef(internalBlock.id) + aParagraph(aText(StringValue("In between"))), + aDocumentObjectRef(Block.id) ), internal = true ) val template = aTemplate("10", listOf(aDocumentObjectRef(section.id))) - every { documentObjectRepository.findModelOrFail(externalBlock.id) } returns externalBlock - every { documentObjectRepository.findModelOrFail(internalBlock.id) } returns internalBlock - every { documentObjectRepository.findModelOrFail(section.id) } returns section + every { documentObjectRepository.findOrFail(externalBlock.id) } returns externalBlock + every { documentObjectRepository.findOrFail(Block.id) } returns Block + every { documentObjectRepository.findOrFail(section.id) } returns section // when val result = subject.buildDocumentObject(template, null).let { xmlMapper.readTree(it.trimIndent()) } @@ -279,11 +280,11 @@ class InteractiveDocumentObjectBuilderTest { val inBetweenFlow = result["Flow"].last { it["Id"].textValue() == inBetweenFlowRef } inBetweenFlow["FlowContent"]["P"]["T"][""].textValue().shouldBeEqualTo("In between") - val nestedInternalFlowRef = sectionRefs[2]["Id"].textValue() - result["Flow"].first { it["Id"].textValue() == nestedInternalFlowRef }["Name"].textValue() - .shouldBeEqualTo(internalBlock.nameOrId()) - val nestedInternalFlow = result["Flow"].last { it["Id"].textValue() == nestedInternalFlowRef } - nestedInternalFlow["FlowContent"]["P"]["T"][""].textValue().shouldBeEqualTo("Sir") + val nestedFlowRef = sectionRefs[2]["Id"].textValue() + result["Flow"].first { it["Id"].textValue() == nestedFlowRef }["Name"].textValue() + .shouldBeEqualTo(Block.nameOrId()) + val nestedFlow = result["Flow"].last { it["Id"].textValue() == nestedFlowRef } + nestedFlow["FlowContent"]["P"]["T"][""].textValue().shouldBeEqualTo("Sir") } @Test @@ -293,11 +294,11 @@ class InteractiveDocumentObjectBuilderTest { val currencyVar = mockVar(aVariable("var2", "varName2", dataType = DataType.Currency, defaultValue = "249.99")) val boolVar = mockVar(aVariable("var3", "varName3", dataType = DataType.Boolean, defaultValue = "TRUE")) val variableStructure = mockVarStructure( - aVariableStructureModel( + aVariableStructure( structure = mapOf( - VariableModelRef(longVar.id) to VariablePathData("Data.Clients.Value"), - VariableModelRef(currencyVar.id) to VariablePathData("Data.Clients.Value", "Money"), - VariableModelRef(boolVar.id) to VariablePathData("Data.Clients.Value") + longVar.id to VariablePathData("Data.Clients.Value"), + currencyVar.id to VariablePathData("Data.Clients.Value", "Money"), + boolVar.id to VariablePathData("Data.Clients.Value") ) ) ) @@ -308,7 +309,7 @@ class InteractiveDocumentObjectBuilderTest { aParagraph( aText( listOf( - VariableModelRef(longVar.id), VariableModelRef(currencyVar.id), VariableModelRef(boolVar.id) + VariableRef(longVar.id), VariableRef(currencyVar.id), VariableRef(boolVar.id) ) ) ) @@ -356,11 +357,11 @@ class InteractiveDocumentObjectBuilderTest { val displayRule = aDisplayRule(Literal("A", LiteralDataType.String), Equals, Literal("B", LiteralDataType.String)) - val block = aBlock("1", listOf(aParagraph(aText(StringModel("Hello"))))) + val block = aBlock("1", listOf(aParagraph(aText(StringValue("Hello"))))) val template = aTemplate("2", listOf(aDocumentObjectRef(block.id, displayRule.id))) - every { documentObjectRepository.findModelOrFail(block.id) } returns block - every { displayRuleRepository.findModelOrFail(displayRule.id) } returns displayRule + every { documentObjectRepository.findOrFail(block.id) } returns block + every { displayRuleRepository.findOrFail(displayRule.id) } returns displayRule // when val result = subject.buildDocumentObject(template, null).let { xmlMapper.readTree(it.trimIndent()) } @@ -389,9 +390,9 @@ class InteractiveDocumentObjectBuilderTest { // given val variable = mockVar(aVariable("V1", "ClientName")) val variableStructure = mockVarStructure( - aVariableStructureModel( + aVariableStructure( structure = mapOf( - VariableModelRef(variable.id) to VariablePathData("Data.Clients", "Client Name"), + variable.id to VariablePathData("Data.Clients", "Client Name"), ) ) ) @@ -406,16 +407,16 @@ class InteractiveDocumentObjectBuilderTest { "1", listOf( aParagraph( aText( - StringModel("Hello There"), textStyle.id, DisplayRuleModelRef(displayRule.id) + StringValue("Hello There"), textStyle.id, DisplayRuleRef(displayRule.id) ), paraStyle.id ) ) ) val config = aProjectConfig(defaultVariableStructure = variableStructure.id) - every { displayRuleRepository.findModelOrFail(displayRule.id) } returns displayRule - every { textStyleRepository.firstWithDefinitionModel(textStyle.id) } returns textStyle - every { paragraphStyleRepository.firstWithDefinitionModel(paraStyle.id) } returns paraStyle + every { displayRuleRepository.findOrFail(displayRule.id) } returns displayRule + every { textStyleRepository.firstWithDefinition(textStyle.id) } returns textStyle + every { paragraphStyleRepository.firstWithDefinition(paraStyle.id) } returns paraStyle // when val subject = aSubject(config) @@ -458,8 +459,8 @@ class InteractiveDocumentObjectBuilderTest { // given val variable = mockVar(aVariable("V1", "900_MailCount")) val variableStructure = mockVarStructure( - aVariableStructureModel( - structure = mapOf(VariableModelRef(variable.id) to VariablePathData("Data.1.Value")) + aVariableStructure( + structure = mapOf(variable.id to VariablePathData("Data.1.Value")) ) ) val config = aProjectConfig(defaultVariableStructure = variableStructure.id) @@ -483,20 +484,20 @@ class InteractiveDocumentObjectBuilderTest { aParagraph( listOf( aText( - StringModel("This is") + StringValue("This is") ), aText( - StringModel("Preposterous!"), textStyle.id, DisplayRuleModelRef(textDisplayRule.id) + StringValue("Preposterous!"), textStyle.id, DisplayRuleRef(textDisplayRule.id) ) - ), ParagraphStyleModelRef(paraStyle.id), DisplayRuleModelRef(paraDisplayRule.id) + ), ParagraphStyleRef(paraStyle.id), DisplayRuleRef(paraDisplayRule.id) ) ) ) ) - every { displayRuleRepository.findModelOrFail(paraDisplayRule.id) } returns paraDisplayRule - every { displayRuleRepository.findModelOrFail(textDisplayRule.id) } returns textDisplayRule - every { textStyleRepository.firstWithDefinitionModel(textStyle.id) } returns textStyle - every { paragraphStyleRepository.firstWithDefinitionModel(paraStyle.id) } returns paraStyle + every { displayRuleRepository.findOrFail(paraDisplayRule.id) } returns paraDisplayRule + every { displayRuleRepository.findOrFail(textDisplayRule.id) } returns textDisplayRule + every { textStyleRepository.firstWithDefinition(textStyle.id) } returns textStyle + every { paragraphStyleRepository.firstWithDefinition(paraStyle.id) } returns paraStyle // when val subject = aSubject(config) @@ -549,17 +550,17 @@ class InteractiveDocumentObjectBuilderTest { val block = aBlock( "1", listOf( - TableModel( + Table( listOf( aRow( listOf( - TableModel.CellModel(listOf(aParagraph(aText(StringModel("First row, first cell"))))), - TableModel.CellModel(listOf(aParagraph(aText(StringModel("First row, second cell"))))) + aCell(listOf(aParagraph(aText(StringValue("First row, first cell"))))), + aCell(listOf(aParagraph(aText(StringValue("First row, second cell"))))) ) ), aRow( listOf( - TableModel.CellModel(listOf(aParagraph(aText(StringModel("Second row, first cell"))))), - TableModel.CellModel(listOf(aParagraph(aText(StringModel("Second row, second cell"))))) + aCell(listOf(aParagraph(aText(StringValue("Second row, first cell"))))), + aCell(listOf(aParagraph(aText(StringValue("Second row, second cell"))))) ), displayRule.id ) ), listOf() @@ -567,8 +568,8 @@ class InteractiveDocumentObjectBuilderTest { ) ) - every { displayRuleRepository.findModelOrFail(displayRule.id) } returns displayRule - every { documentObjectRepository.findModel(block.id) } returns block + every { displayRuleRepository.findOrFail(displayRule.id) } returns displayRule + every { documentObjectRepository.find(block.id) } returns block // when val result = subject.buildDocumentObject(block, null).let { xmlMapper.readTree(it.trimIndent()) } @@ -591,8 +592,8 @@ class InteractiveDocumentObjectBuilderTest { @Test fun `build block with unavailable text style throws exception`() { // given - val block = aBlock("1", listOf(aParagraph(aText(listOf(), TextStyleModelRef("textStyle1"))))) - every { textStyleRepository.firstWithDefinitionModel("textStyle1") } returns null + val block = aBlock("1", listOf(aParagraph(aText(listOf(), TextStyleRef("textStyle1"))))) + every { textStyleRepository.firstWithDefinition("textStyle1") } returns null // when val result = assertThrows { subject.buildDocumentObject(block, null) } @@ -605,7 +606,7 @@ class InteractiveDocumentObjectBuilderTest { fun `build block with unavailable paragraph style throws exception`() { // given val block = aBlock("1", listOf(aParagraph(aText(listOf()), "paraStyle1"))) - every { paragraphStyleRepository.firstWithDefinitionModel("paraStyle1") } returns null + every { paragraphStyleRepository.firstWithDefinition("paraStyle1") } returns null // when val result = assertThrows { subject.buildDocumentObject(block, null) } @@ -618,7 +619,7 @@ class InteractiveDocumentObjectBuilderTest { fun `build of template skips unsupported block and template is created without it`() { // given val unsupportedBlock = aBlock("1", skip = SkipOptions(true, null, null)) - every { documentObjectRepository.findModelOrFail("block1") } returns unsupportedBlock + every { documentObjectRepository.findOrFail("block1") } returns unsupportedBlock val template = aTemplate("10", listOf(aDocumentObjectRef("block1"))) // when @@ -634,8 +635,8 @@ class InteractiveDocumentObjectBuilderTest { @Test fun `build block with variable ref that is not found throws exception`() { // given - val block = aBlock("1", listOf(aParagraph(aText(VariableModelRef("var1"))))) - every { variableRepository.findModelOrFail("var1") } throws IllegalStateException("Record 'var1' not found.") + val block = aBlock("1", listOf(aParagraph(aText(VariableRef("var1"))))) + every { variableRepository.findOrFail("var1") } throws IllegalStateException("Record 'var1' not found.") // when val result = assertThrows { subject.buildDocumentObject(block, null) } @@ -658,11 +659,11 @@ class InteractiveDocumentObjectBuilderTest { ) ) - val block = mockObj(aBlock("1", listOf(aParagraph(aText(StringModel("Hello")))))) + val block = mockObj(aBlock("1", listOf(aParagraph(aText(StringValue("Hello")))))) val template = aTemplate("2", listOf(aDocumentObjectRef(block.id, displayRule.id))) - every { variableRepository.findModel(variable.id) } returns variable - every { variableStructureRepository.listAllModel() } returns listOf() + every { variableRepository.find(variable.id) } returns variable + every { variableStructureRepository.listAll() } returns listOf() // when val result = subject.buildDocumentObject(template, null).let { xmlMapper.readTree(it.trimIndent()) } @@ -678,24 +679,24 @@ class InteractiveDocumentObjectBuilderTest { // given val variable = aVariable("V_100", "Salutation") - val internalBlock = aBlock( + val Block = aBlock( "1", listOf( aParagraph( - aText(listOf(StringModel("Dear "), VariableModelRef(variable.id))) + aText(listOf(StringValue("Dear "), VariableRef(variable.id))) ) ), internal = true ) - val externalBlock = aBlock("2", listOf(aParagraph(aText(StringModel("This is a good day!"))))) + val externalBlock = aBlock("2", listOf(aParagraph(aText(StringValue("This is a good day!"))))) val block = aBlock( "10", listOf( aParagraph( aText( listOf( - StringModel("Hello, "), - aDocumentObjectRef(internalBlock.id), - StringModel(". How are you?"), + StringValue("Hello, "), + aDocumentObjectRef(Block.id), + StringValue(". How are you?"), aDocumentObjectRef(externalBlock.id) ) ) @@ -703,10 +704,10 @@ class InteractiveDocumentObjectBuilderTest { ) ) - every { documentObjectRepository.findModelOrFail(internalBlock.id) } returns internalBlock - every { documentObjectRepository.findModelOrFail(externalBlock.id) } returns externalBlock - every { variableRepository.findModelOrFail(variable.id) } returns variable - every { variableStructureRepository.listAllModel() } returns listOf() + every { documentObjectRepository.findOrFail(Block.id) } returns Block + every { documentObjectRepository.findOrFail(externalBlock.id) } returns externalBlock + every { variableRepository.findOrFail(variable.id) } returns variable + every { variableStructureRepository.listAll() } returns listOf() // when val result = subject.buildDocumentObject(block, null).let { xmlMapper.readTree(it.trimIndent()) } @@ -725,9 +726,9 @@ class InteractiveDocumentObjectBuilderTest { fun `build block with image`() { // given val image = aImage("Dog", options = ImageOptions(Size.ofPoints(120), Size.ofPoints(90))) - val block = aBlock("1", listOf(ImageModelRef(image.id))) + val block = aBlock("1", listOf(ImageRef(image.id))) - every { imageRepository.findModelOrFail(image.id) } returns image + every { imageRepository.findOrFail(image.id) } returns image // when val result = subject.buildDocumentObject(block, null).let { xmlMapper.readTree(it.trimIndent()) } @@ -745,12 +746,12 @@ class InteractiveDocumentObjectBuilderTest { } @Test - fun `build block with image uses alternateText from ImageModel`() { + fun `build block with image uses alternateText from Image`() { // given val image = aImage("Dog", alternateText = "A cute dog picture") - val block = aBlock("1", listOf(ImageModelRef(image.id))) + val block = aBlock("1", listOf(ImageRef(image.id))) - every { imageRepository.findModelOrFail(image.id) } returns image + every { imageRepository.findOrFail(image.id) } returns image // when val result = subject.buildDocumentObject(block, null).let { xmlMapper.readTree(it.trimIndent()) } @@ -782,8 +783,8 @@ class InteractiveDocumentObjectBuilderTest { fun `build template with two blocks referencing same image results in single image definition`() { // given val image = mockImage(aImage("Dog")) - val block1 = mockObj(aBlock("1", listOf(ImageModelRef(image.id)), internal = true)) - val block2 = mockObj(aBlock("2", listOf(ImageModelRef(image.id)), internal = true)) + val block1 = mockObj(aBlock("1", listOf(ImageRef(image.id)), internal = true)) + val block2 = mockObj(aBlock("2", listOf(ImageRef(image.id)), internal = true)) val template = aTemplate("3", listOf(aDocumentObjectRef(block1.id), aDocumentObjectRef(block2.id))) @@ -801,11 +802,11 @@ class InteractiveDocumentObjectBuilderTest { val dogImage = aImage("Dog", sourcePath = "", skip = SkipOptions(true, "Dog placeholder", null)) val block = aBlock( - "1", listOf(ImageModelRef(catImage.id), aParagraph(aText(ImageModelRef(dogImage.id)))) + "1", listOf(ImageRef(catImage.id), aParagraph(aText(ImageRef(dogImage.id)))) ) - every { imageRepository.findModelOrFail(catImage.id) } returns catImage - every { imageRepository.findModelOrFail(dogImage.id) } returns dogImage + every { imageRepository.findOrFail(catImage.id) } returns catImage + every { imageRepository.findOrFail(dogImage.id) } returns dogImage // when val result = subject.buildDocumentObject(block, null).let { xmlMapper.readTree(it.trimIndent()) } @@ -840,19 +841,19 @@ class InteractiveDocumentObjectBuilderTest { aParagraph( aText( listOf( - StringModel("Hello, "), FirstMatchModel( + StringValue("Hello, "), FirstMatch( cases = listOf( - FirstMatchModel.CaseModel( - DisplayRuleModelRef(rule1.id), - listOf(aParagraph(aText(StringModel("Mike")))), + FirstMatch.Case( + DisplayRuleRef(rule1.id), + listOf(aParagraph(aText(StringValue("Mike")))), null - ), FirstMatchModel.CaseModel( - DisplayRuleModelRef(rule2.id), - listOf(aParagraph(aText(StringModel("Jon")))), + ), FirstMatch.Case( + DisplayRuleRef(rule2.id), + listOf(aParagraph(aText(StringValue("Jon")))), null ) ), emptyList() - ), StringModel(", how are you?") + ), StringValue(", how are you?") ) ) ) @@ -892,17 +893,17 @@ class InteractiveDocumentObjectBuilderTest { } @Test - fun `build of internal flow under display rule wraps in in condition flow`() { + fun `build of flow under display rule wraps in in condition flow`() { // given val rule = mockRule( aDisplayRule(Literal("C", LiteralDataType.String), Equals, Literal("C", LiteralDataType.String)) ) - val internalBlock = mockObj( + val Block = mockObj( aDocObj( - "B_1", Block, listOf(aParagraph(aText(StringModel("Text")))), true, displayRuleRef = rule.id + "B_1", Block, listOf(aParagraph(aText(StringValue("Text")))), true, displayRuleRef = rule.id ) ) - val template = aDocObj("T_1", Template, listOf(aDocumentObjectRef(internalBlock.id))) + val template = aDocObj("T_1", Template, listOf(aDocumentObjectRef(Block.id))) // when val result = subject.buildDocumentObject(template, null).let { xmlMapper.readTree(it.trimIndent()) } @@ -924,11 +925,11 @@ class InteractiveDocumentObjectBuilderTest { val rule = mockRule( aDisplayRule(Literal("C", LiteralDataType.String), Equals, Literal("C", LiteralDataType.String)) ) - val innerBlock = mockObj(aDocObj("B_2", Block, listOf(aParagraph(aText(StringModel("Inner Text")))))) + val innerBlock = mockObj(aDocObj("B_2", Block, listOf(aParagraph(aText(StringValue("Inner Text")))))) val block = aDocObj( "B_1", Block, listOf( aDocumentObjectRef(innerBlock.id), - aParagraph(aText(StringModel("Text"))), + aParagraph(aText(StringValue("Text"))), ), false, displayRuleRef = rule.id ) @@ -1083,22 +1084,22 @@ class InteractiveDocumentObjectBuilderTest { Literal("B", LiteralDataType.String), Equals, Literal("B", LiteralDataType.String), id = "rule2" ) ) - val firstMatch = FirstMatchModel( + val firstMatch = FirstMatch( cases = listOf( - FirstMatchModel.CaseModel( - displayRuleRef = DisplayRuleModelRef(rule1.id), - content = listOf(aParagraph(aText(StringModel("first case")))), + FirstMatch.Case( + displayRuleRef = DisplayRuleRef(rule1.id), + content = listOf(aParagraph(aText(StringValue("first case")))), name = "First" - ), FirstMatchModel.CaseModel( - displayRuleRef = DisplayRuleModelRef(rule2.id), - content = listOf(aParagraph(aText(StringModel("second case")))), + ), FirstMatch.Case( + displayRuleRef = DisplayRuleRef(rule2.id), + content = listOf(aParagraph(aText(StringValue("second case")))), name = "Second" ) - ), default = listOf(aParagraph(aText(StringModel("default case")))) + ), default = listOf(aParagraph(aText(StringValue("default case")))) ) val block = aBlock( "B1", listOf( - TableModel( + Table( rows = listOf( aRow( listOf( @@ -1151,14 +1152,14 @@ class InteractiveDocumentObjectBuilderTest { @Test fun `build of simple text style accepts the specified values`() { - every { paragraphStyleRepository.listAllModel() } returns listOf() - every { textStyleRepository.listAllModel() } returns listOf( + every { paragraphStyleRepository.listAll() } returns listOf() + every { textStyleRepository.listAll() } returns listOf( aTextStyle("textStyle1", definition = aTextDef(bold = true, underline = true)), ) every { ipsService.gatherFontData(any()) } returns "Arial,Regular,icm://Interactive/${config.interactiveTenant}/Resources/Fonts/arial.ttf;" // when - val result = subject.buildStyles(textStyleRepository.listAllModel(), paragraphStyleRepository.listAllModel()) + val result = subject.buildStyles(textStyleRepository.listAll(), paragraphStyleRepository.listAll()) // then val textStyleDefinitions = xmlMapper.readTree(result.trimIndent())["Layout"]["Layout"]["TextStyle"] @@ -1172,16 +1173,16 @@ class InteractiveDocumentObjectBuilderTest { @Test fun `build of simple style delta works correctly`() { - every { paragraphStyleRepository.listAllModel() } returns listOf( + every { paragraphStyleRepository.listAll() } returns listOf( aParaStyle("paraStyle1", definition = aParaDef(leftIndent = Size.ofCentimeters(1))) ) - every { textStyleRepository.listAllModel() } returns listOf( + every { textStyleRepository.listAll() } returns listOf( aTextStyle("textStyle1", definition = aTextDef(bold = true, underline = true)), ) every { ipsService.gatherFontData(any()) } returns "Arial,Regular,icm://Interactive/${config.interactiveTenant}/Resources/Fonts/arial.ttf;" // when - val result = subject.buildStyleLayoutDelta(textStyleRepository.listAllModel(), paragraphStyleRepository.listAllModel()) + val result = subject.buildStyleLayoutDelta(textStyleRepository.listAll(), paragraphStyleRepository.listAll()) // then val textStyleDefinitions = xmlMapper.readTree(result.trimIndent())["TextStyle"] @@ -1202,15 +1203,15 @@ class InteractiveDocumentObjectBuilderTest { @Test fun `build of text style with font size converts the value to millimeters`() { val sizeInMs = Size.ofPoints(12) - every { paragraphStyleRepository.listAllModel() } returns listOf() - every { textStyleRepository.listAllModel() } returns listOf( + every { paragraphStyleRepository.listAll() } returns listOf() + every { textStyleRepository.listAll() } returns listOf( aTextStyle("textStyle1", definition = aTextDef(size = sizeInMs)), ) every { ipsService.gatherFontData(any()) } returns "Arial,Regular,icm://Interactive/${config.interactiveTenant}/Resources/Fonts/arial.ttf;" val expectedValue = sizeInMs.toMeters() // when - val result = subject.buildStyles(textStyleRepository.listAllModel(), paragraphStyleRepository.listAllModel()) + val result = subject.buildStyles(textStyleRepository.listAll(), paragraphStyleRepository.listAll()) // then val textStyleDefinitions = xmlMapper.readTree(result.trimIndent())["Layout"]["Layout"]["TextStyle"] @@ -1247,8 +1248,8 @@ class InteractiveDocumentObjectBuilderTest { @Test fun `paragraph number values are converted to meters`() { - every { textStyleRepository.listAllModel() } returns listOf() - every { paragraphStyleRepository.listAllModel() } returns listOf( + every { textStyleRepository.listAll() } returns listOf() + every { paragraphStyleRepository.listAll() } returns listOf( aParaStyle( "paraStyle1", definition = aParaDef( leftIndent = Size.ofMillimeters(7.5), @@ -1258,14 +1259,14 @@ class InteractiveDocumentObjectBuilderTest { spaceAfter = Size.ofMillimeters(6), firstLineIndent = Size.ofCentimeters(0.8), lineSpacing = LineSpacing.Exact(Size.ofCentimeters(1.5)), - tabs = TabsModel(listOf(TabModel(Size.ofMillimeters(25), TabType.Left)), false) + tabs = Tabs(listOf(Tab(Size.ofMillimeters(25), TabType.Left)), false) ) ), ) every { ipsService.gatherFontData(any()) } returns "Arial,Regular,icm://Interactive/${config.interactiveTenant}/Resources/Fonts/arial.ttf;" // when - val result = subject.buildStyles(textStyleRepository.listAllModel(), paragraphStyleRepository.listAllModel()) + val result = subject.buildStyles(textStyleRepository.listAll(), paragraphStyleRepository.listAll()) // then val textStyleDefinitions = xmlMapper.readTree(result.trimIndent())["Layout"]["Layout"]["ParaStyle"] @@ -1333,13 +1334,13 @@ class InteractiveDocumentObjectBuilderTest { fun `block with unassigned variable structure uses the one specified in project config`() { val variable = mockVar(aVariable("V_1")) val variableStructureA = mockVarStructure( - aVariableStructureModel( - "VS_1", structure = mapOf(VariableModelRef(variable.id) to VariablePathData("Data.Records.Value")) + aVariableStructure( + "VS_1", structure = mapOf(variable.id to VariablePathData("Data.Records.Value")) ) ) val variableStructureB = mockVarStructure( - aVariableStructureModel( - "VS_2", structure = mapOf(VariableModelRef(variable.id) to VariablePathData("Data.Clients.Value")) + aVariableStructure( + "VS_2", structure = mapOf(variable.id to VariablePathData("Data.Clients.Value")) ) ) val config = aProjectConfig(defaultVariableStructure = variableStructureB.id) @@ -1347,7 +1348,7 @@ class InteractiveDocumentObjectBuilderTest { val block = mockObj( aDocObj( "B_1", Block, listOf( - aParagraph(aText(listOf(StringModel("Text"), VariableModelRef(variable.id)))) + aParagraph(aText(listOf(StringValue("Text"), VariableRef(variable.id)))) ) ) ) @@ -1357,8 +1358,8 @@ class InteractiveDocumentObjectBuilderTest { val result = subject.buildDocumentObject(block, null).let { xmlMapper.readTree(it.trimIndent()) } // then - verify(exactly = 1) { variableStructureRepository.findModelOrFail(variableStructureB.id) } - verify(exactly = 0) { variableStructureRepository.findModelOrFail(variableStructureA.id) } + verify(exactly = 1) { variableStructureRepository.findOrFail(variableStructureB.id) } + verify(exactly = 0) { variableStructureRepository.findOrFail(variableStructureA.id) } result["Variable"].first { it["Name"].textValue() == variable.nameOrId() }["ParentId"].textValue() .shouldBeEqualTo("Data.Clients.Value") } @@ -1452,28 +1453,28 @@ class InteractiveDocumentObjectBuilderTest { deContent.shouldBeEqualTo("de") } - private fun mockObj(documentObject: DocumentObjectModel): DocumentObjectModel { - every { documentObjectRepository.findModelOrFail(documentObject.id) } returns documentObject + private fun mockObj(documentObject: DocumentObject): DocumentObject { + every { documentObjectRepository.findOrFail(documentObject.id) } returns documentObject return documentObject } - private fun mockImage(image: ImageModel): ImageModel { - every { imageRepository.findModelOrFail(image.id) } returns image + private fun mockImage(image: Image): Image { + every { imageRepository.findOrFail(image.id) } returns image return image } - private fun mockRule(rule: DisplayRuleModel): DisplayRuleModel { - every { displayRuleRepository.findModelOrFail(rule.id) } returns rule + private fun mockRule(rule: DisplayRule): DisplayRule { + every { displayRuleRepository.findOrFail(rule.id) } returns rule return rule } - private fun mockVar(variable: VariableModel): VariableModel { - every { variableRepository.findModelOrFail(variable.id) } returns variable + private fun mockVar(variable: Variable): Variable { + every { variableRepository.findOrFail(variable.id) } returns variable return variable } - private fun mockVarStructure(variableStructure: VariableStructureModel): VariableStructureModel { - every { variableStructureRepository.findModelOrFail(variableStructure.id) } returns variableStructure + private fun mockVarStructure(variableStructure: VariableStructure): VariableStructure { + every { variableStructureRepository.findOrFail(variableStructure.id) } returns variableStructure return variableStructure } diff --git a/migration-library/src/test/kotlin/com/quadient/migration/tools/TestObjectBuilders.kt b/migration-library/src/test/kotlin/com/quadient/migration/tools/TestObjectBuilders.kt index 1d0ea72c..66986106 100644 --- a/migration-library/src/test/kotlin/com/quadient/migration/tools/TestObjectBuilders.kt +++ b/migration-library/src/test/kotlin/com/quadient/migration/tools/TestObjectBuilders.kt @@ -13,6 +13,7 @@ import com.quadient.migration.api.dto.migrationmodel.CustomFieldMap import com.quadient.migration.api.dto.migrationmodel.DisplayRuleRef import com.quadient.migration.api.dto.migrationmodel.DocumentContent import com.quadient.migration.api.dto.migrationmodel.DocumentObject +import com.quadient.migration.api.dto.migrationmodel.Image import com.quadient.migration.api.dto.migrationmodel.Paragraph import com.quadient.migration.api.dto.migrationmodel.Paragraph.Text import com.quadient.migration.api.dto.migrationmodel.ParagraphStyle @@ -29,8 +30,10 @@ import com.quadient.migration.api.dto.migrationmodel.TextStyleDefOrRef import com.quadient.migration.api.dto.migrationmodel.TextStyleDefinition import com.quadient.migration.api.dto.migrationmodel.TextStyleRef import com.quadient.migration.api.dto.migrationmodel.Variable +import com.quadient.migration.api.dto.migrationmodel.VariableStructureRef import com.quadient.migration.api.repository.DisplayRuleRepository import com.quadient.migration.api.repository.DocumentObjectRepository +import com.quadient.migration.api.repository.FileRepository import com.quadient.migration.api.repository.ImageRepository import com.quadient.migration.api.repository.ParagraphStyleRepository import com.quadient.migration.api.repository.TextStyleRepository @@ -39,8 +42,16 @@ import com.quadient.migration.api.repository.VariableStructureRepository import com.quadient.migration.data.Active import com.quadient.migration.data.Deployed import com.quadient.migration.data.StatusEvent +import com.quadient.migration.persistence.table.DisplayRuleTable +import com.quadient.migration.persistence.table.DocumentObjectTable +import com.quadient.migration.persistence.table.FileTable +import com.quadient.migration.persistence.table.ImageTable +import com.quadient.migration.persistence.table.ParagraphStyleTable import com.quadient.migration.persistence.table.StatusTrackingEntity import com.quadient.migration.persistence.table.StatusTrackingTable +import com.quadient.migration.persistence.table.TextStyleTable +import com.quadient.migration.persistence.table.VariableStructureTable +import com.quadient.migration.persistence.table.VariableTable import com.quadient.migration.service.deploy.ResourceType import com.quadient.migration.shared.Alignment import com.quadient.migration.shared.Color @@ -48,19 +59,13 @@ import com.quadient.migration.shared.DataType import com.quadient.migration.shared.DocumentObjectOptions import com.quadient.migration.shared.DocumentObjectType import com.quadient.migration.shared.IcmPath +import com.quadient.migration.shared.ImageType import com.quadient.migration.shared.LineSpacing import com.quadient.migration.shared.MetadataPrimitive import com.quadient.migration.shared.ParagraphPdfTaggingRule import com.quadient.migration.shared.Size import com.quadient.migration.shared.SkipOptions import com.quadient.migration.shared.SuperOrSubscript -import com.quadient.migration.tools.model.aDisplayRuleInternalRepository -import com.quadient.migration.tools.model.aDocumentObjectInternalRepository -import com.quadient.migration.tools.model.aImageInternalRepository -import com.quadient.migration.tools.model.aParaStyleInternalRepository -import com.quadient.migration.tools.model.aTextStyleInternalRepository -import com.quadient.migration.tools.model.aVariableInternalRepository -import com.quadient.migration.tools.model.aVariableStructureInternalRepository import io.mockk.every import io.mockk.mockk import kotlinx.datetime.Clock @@ -129,7 +134,7 @@ fun aImageDto( fun aBlockModel( id: String, - content: List = emptyList(), + content: List = emptyList(), name: String? = null, internal: Boolean = false, targetFolder: String? = null, @@ -498,10 +503,11 @@ fun aErrorStatus( ) } -fun aDocumentObjectRepository() = DocumentObjectRepository(aDocumentObjectInternalRepository()) -fun aVariableRepository() = VariableRepository(aVariableInternalRepository()) -fun aVariableStructureRepository() = VariableStructureRepository(aVariableStructureInternalRepository()) -fun aParaStyleRepository() = ParagraphStyleRepository(aParaStyleInternalRepository()) -fun aTextStyleRepository() = TextStyleRepository(aTextStyleInternalRepository()) -fun aDisplayRuleRepository() = DisplayRuleRepository(aDisplayRuleInternalRepository()) -fun aImageRepository() = ImageRepository(aImageInternalRepository()) \ No newline at end of file +fun aDocumentObjectRepository() = DocumentObjectRepository(DocumentObjectTable, aProjectConfig().name) +fun aVariableRepository() = VariableRepository(VariableTable, aProjectConfig().name) +fun aVariableStructureRepository() = VariableStructureRepository(VariableStructureTable, aProjectConfig().name) +fun aParaStyleRepository() = ParagraphStyleRepository(ParagraphStyleTable, aProjectConfig().name) +fun aTextStyleRepository() = TextStyleRepository(TextStyleTable, aProjectConfig().name) +fun aDisplayRuleRepository() = DisplayRuleRepository(DisplayRuleTable, aProjectConfig().name) +fun aImageRepository() = ImageRepository(ImageTable, aProjectConfig().name) +fun aFileRepository() = FileRepository(FileTable, aProjectConfig().name) \ No newline at end of file diff --git a/migration-library/src/test/kotlin/com/quadient/migration/tools/model/TestModelObjectBuilders.kt b/migration-library/src/test/kotlin/com/quadient/migration/tools/model/TestModelObjectBuilders.kt index 34c6c86e..aaf9c6b9 100644 --- a/migration-library/src/test/kotlin/com/quadient/migration/tools/model/TestModelObjectBuilders.kt +++ b/migration-library/src/test/kotlin/com/quadient/migration/tools/model/TestModelObjectBuilders.kt @@ -30,22 +30,6 @@ import com.quadient.migration.api.dto.migrationmodel.Variable import com.quadient.migration.api.dto.migrationmodel.VariableRef import com.quadient.migration.api.dto.migrationmodel.VariableStructure import com.quadient.migration.api.dto.migrationmodel.VariableStructureRef -import com.quadient.migration.persistence.repository.DisplayRuleInternalRepository -import com.quadient.migration.persistence.repository.DocumentObjectInternalRepository -import com.quadient.migration.persistence.repository.FileInternalRepository -import com.quadient.migration.persistence.repository.ImageInternalRepository -import com.quadient.migration.persistence.repository.ParagraphStyleInternalRepository -import com.quadient.migration.persistence.repository.TextStyleInternalRepository -import com.quadient.migration.persistence.repository.VariableInternalRepository -import com.quadient.migration.persistence.repository.VariableStructureInternalRepository -import com.quadient.migration.persistence.table.DisplayRuleTable -import com.quadient.migration.persistence.table.DocumentObjectTable -import com.quadient.migration.persistence.table.FileTable -import com.quadient.migration.persistence.table.ImageTable -import com.quadient.migration.persistence.table.ParagraphStyleTable -import com.quadient.migration.persistence.table.TextStyleTable -import com.quadient.migration.persistence.table.VariableStructureTable -import com.quadient.migration.persistence.table.VariableTable import com.quadient.migration.shared.Alignment import com.quadient.migration.shared.BinOp import com.quadient.migration.shared.Binary @@ -436,17 +420,3 @@ fun aFile( fun aDocumentObjectRef(id: String, displayRuleId: String? = null) = DocumentObjectRef(id, displayRuleId?.let { DisplayRuleRef(it) }) - -fun aDocumentObjectInternalRepository() = DocumentObjectInternalRepository(DocumentObjectTable, aProjectConfig().name) -fun aVariableInternalRepository() = VariableInternalRepository(VariableTable, aProjectConfig().name) -fun aVariableStructureInternalRepository() = - VariableStructureInternalRepository(VariableStructureTable, aProjectConfig().name) - -fun aParaStyleInternalRepository() = ParagraphStyleInternalRepository(ParagraphStyleTable, aProjectConfig().name) -fun aTextStyleInternalRepository() = TextStyleInternalRepository(TextStyleTable, aProjectConfig().name) -fun aDisplayRuleInternalRepository() = DisplayRuleInternalRepository(DisplayRuleTable, aProjectConfig().name) -fun aImageInternalRepository() = ImageInternalRepository(ImageTable, aProjectConfig().name) -fun aFileInternalRepository() = FileInternalRepository(FileTable, aProjectConfig().name) - - - From f01a93791eabc66a6d5b37594ff280d94bbd0d03 Mon Sep 17 00:00:00 2001 From: "d.svitak" Date: Fri, 6 Feb 2026 10:56:28 +0100 Subject: [PATCH 4/9] make created and lastUpdated fields non-invasive in the groovy parts --- migration-examples/gradle/dependencies.gradle | 1 + .../api/dto/migrationmodel/DisplayRule.kt | 9 ++-- .../api/dto/migrationmodel/DocumentObject.kt | 4 +- .../migration/api/dto/migrationmodel/File.kt | 6 +-- .../migration/api/dto/migrationmodel/Image.kt | 6 +-- .../api/dto/migrationmodel/MigrationObject.kt | 4 +- .../api/dto/migrationmodel/ParagraphStyle.kt | 6 +-- .../api/dto/migrationmodel/TextStyle.kt | 6 +-- .../api/dto/migrationmodel/Variable.kt | 8 ++-- .../dto/migrationmodel/VariableStructure.kt | 6 +-- .../builder/DisplayRuleBuilder.kt | 4 +- .../builder/DocumentObjectBuilder.kt | 4 +- .../migrationmodel/builder/DtoBuilderBase.kt | 24 ----------- .../dto/migrationmodel/builder/FileBuilder.kt | 2 - .../migrationmodel/builder/ImageBuilder.kt | 2 - .../builder/ParagraphStyleBuilder.kt | 2 - .../builder/TextStyleBuilder.kt | 2 - .../migrationmodel/builder/VariableBuilder.kt | 2 - .../builder/VariableStructureBuilder.kt | 2 - .../tools/model/TestModelObjectBuilders.kt | 42 +++++++++---------- 20 files changed, 52 insertions(+), 90 deletions(-) diff --git a/migration-examples/gradle/dependencies.gradle b/migration-examples/gradle/dependencies.gradle index 01e907b9..c18ff7e1 100644 --- a/migration-examples/gradle/dependencies.gradle +++ b/migration-examples/gradle/dependencies.gradle @@ -15,6 +15,7 @@ project.dependencies { testImplementation "org.junit.jupiter:junit-jupiter-engine" testImplementation "org.postgresql:postgresql:42.2.27" testImplementation "org.mockito:mockito-core:5.+" + testImplementation 'org.jetbrains.kotlinx:kotlinx-datetime:0.6.2' testRuntimeOnly "org.junit.platform:junit-platform-launcher" } \ No newline at end of file diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/DisplayRule.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/DisplayRule.kt index a31d8347..6021fd1f 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/DisplayRule.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/DisplayRule.kt @@ -5,17 +5,16 @@ import com.quadient.migration.shared.DisplayRuleDefinition import kotlinx.datetime.Instant import org.jetbrains.exposed.v1.core.ResultRow -data class DisplayRule( +data class DisplayRule @JvmOverloads constructor( override val id: String, override var name: String?, override var originLocations: List = emptyList(), override var customFields: CustomFieldMap, - override val created: Instant, - override val lastUpdated: Instant, - var definition: DisplayRuleDefinition? + var definition: DisplayRuleDefinition?, + override val created: Instant? = null, + override val lastUpdated: Instant? = null, ) : MigrationObject, RefValidatable { override fun collectRefs(): List { - // DisplayRuleDefinition.collectRefs() returns List which are already DTOs return definition?.collectRefs() ?: emptyList() } diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/DocumentObject.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/DocumentObject.kt index 37d60bd0..3633f744 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/DocumentObject.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/DocumentObject.kt @@ -11,8 +11,6 @@ data class DocumentObject( override var name: String? = null, override var originLocations: List = emptyList(), override var customFields: CustomFieldMap, - override val created: Instant, - override val lastUpdated: Instant, var type: DocumentObjectType, var content: List = mutableListOf(), var internal: Boolean? = false, @@ -21,6 +19,8 @@ data class DocumentObject( var variableStructureRef: VariableStructureRef? = null, var baseTemplate: String? = null, var options: DocumentObjectOptions? = null, + override val created: Instant? = null, + override val lastUpdated: Instant? = null, val metadata: Map>, val skip: SkipOptions, val subject: String?, diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/File.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/File.kt index 4181ab68..0260daa0 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/File.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/File.kt @@ -7,17 +7,17 @@ import com.quadient.migration.shared.SkipOptions import kotlinx.datetime.Instant import org.jetbrains.exposed.v1.core.ResultRow -data class File( +data class File @JvmOverloads constructor( override val id: String, override var name: String?, override var originLocations: List, override var customFields: CustomFieldMap, - override val created: Instant, - override val lastUpdated: Instant, var sourcePath: String?, var targetFolder: String?, var fileType: FileType, val skip: SkipOptions, + override val created: Instant? = null, + override val lastUpdated: Instant? = null, ) : MigrationObject, RefValidatable { override fun collectRefs(): List { return emptyList() diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/Image.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/Image.kt index cabe06c7..d8e6346f 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/Image.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/Image.kt @@ -9,13 +9,11 @@ import com.quadient.migration.shared.SkipOptions import kotlinx.datetime.Instant import org.jetbrains.exposed.v1.core.ResultRow -data class Image( +data class Image @JvmOverloads constructor( override val id: String, override var name: String?, override var originLocations: List, override var customFields: CustomFieldMap, - override val created: Instant, - override val lastUpdated: Instant, var sourcePath: String?, var options: ImageOptions?, var imageType: ImageType?, @@ -23,6 +21,8 @@ data class Image( val metadata: Map>, val skip: SkipOptions, var alternateText: String? = null, + override val created: Instant? = null, + override val lastUpdated: Instant? = null, ) : MigrationObject, RefValidatable { override fun collectRefs(): List { return emptyList() diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/MigrationObject.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/MigrationObject.kt index 9d83175d..5fadf010 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/MigrationObject.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/MigrationObject.kt @@ -7,8 +7,8 @@ interface MigrationObject { var name: String? var originLocations: List var customFields: CustomFieldMap - val created: Instant - val lastUpdated: Instant + val created: Instant? + val lastUpdated: Instant? fun nameOrId(): String { val name = name diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/ParagraphStyle.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/ParagraphStyle.kt index 241fb55f..9990ff37 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/ParagraphStyle.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/ParagraphStyle.kt @@ -12,14 +12,14 @@ import com.quadient.migration.shared.TabType import kotlinx.datetime.Instant import org.jetbrains.exposed.v1.core.ResultRow -data class ParagraphStyle( +data class ParagraphStyle @JvmOverloads constructor( override val id: String, override var name: String? = null, override var originLocations: List = emptyList(), override var customFields: CustomFieldMap, - override val created: Instant, - override val lastUpdated: Instant, var definition: ParagraphStyleDefOrRef, + override val created: Instant? = null, + override val lastUpdated: Instant? = null, ) : MigrationObject, RefValidatable { override fun collectRefs(): List { return when (definition) { diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/TextStyle.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/TextStyle.kt index 03e4530d..ed07f4e1 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/TextStyle.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/TextStyle.kt @@ -8,14 +8,14 @@ import com.quadient.migration.shared.SuperOrSubscript import kotlinx.datetime.Instant import org.jetbrains.exposed.v1.core.ResultRow -data class TextStyle( +data class TextStyle @JvmOverloads constructor( override val id: String, override var name: String? = null, override var originLocations: List = emptyList(), override var customFields: CustomFieldMap, - override val created: Instant, - override val lastUpdated: Instant, var definition: TextStyleDefOrRef, + override val created: Instant? = null, + override val lastUpdated: Instant? = null, ) : MigrationObject, RefValidatable { override fun collectRefs(): List { return when (definition) { diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/Variable.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/Variable.kt index 34c1ace4..2e77a81f 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/Variable.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/Variable.kt @@ -5,15 +5,15 @@ import com.quadient.migration.shared.DataType import kotlinx.datetime.Instant import org.jetbrains.exposed.v1.core.ResultRow -data class Variable( +data class Variable @JvmOverloads constructor( override val id: String, override var name: String? = null, override var originLocations: List = emptyList(), override var customFields: CustomFieldMap, - override val created: Instant, - override val lastUpdated: Instant, var dataType: DataType, - var defaultValue: String? + var defaultValue: String?, + override val created: Instant? = null, + override val lastUpdated: Instant? = null, ) : MigrationObject, RefValidatable { override fun collectRefs(): List { return emptyList() diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/VariableStructure.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/VariableStructure.kt index 491f6813..1796e7e5 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/VariableStructure.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/VariableStructure.kt @@ -5,15 +5,15 @@ import com.quadient.migration.shared.VariablePathData import kotlinx.datetime.Instant import org.jetbrains.exposed.v1.core.ResultRow -data class VariableStructure( +data class VariableStructure @JvmOverloads constructor( override val id: String, override var name: String? = null, override var originLocations: List = emptyList(), override var customFields: CustomFieldMap, - override val created: Instant, - override val lastUpdated: Instant, val structure: Map, val languageVariable: VariableRef?, + override val created: Instant? = null, + override val lastUpdated: Instant? = null, ) : MigrationObject, RefValidatable { override fun collectRefs(): List { return structure.keys.map { VariableRef(it) } diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/DisplayRuleBuilder.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/DisplayRuleBuilder.kt index ad871416..500b7969 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/DisplayRuleBuilder.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/DisplayRuleBuilder.kt @@ -60,8 +60,8 @@ class DisplayRuleBuilder(id: String) : DtoBuilderBase>( @@ -19,8 +17,6 @@ abstract class DtoBuilderBase>( protected var name: String? = null protected var originLocations: List = emptyList() protected var customFields = CustomFieldMap() - protected var created: Instant = Clock.System.now() - protected var lastUpdated: Instant = Clock.System.now() /** * Sets the name of the object. If not provided the name will default to the id. @@ -78,25 +74,5 @@ abstract class DtoBuilderBase>( return this as K } - /** - * Sets the created timestamp for the object. - * @param created The created timestamp. - * @return The builder instance for method chaining. - */ - fun created(created: Instant): K { - this.created = created - return this as K - } - - /** - * Sets the lastUpdated timestamp for the object. - * @param lastUpdated The lastUpdated timestamp. - * @return The builder instance for method chaining. - */ - fun lastUpdated(lastUpdated: Instant): K { - this.lastUpdated = lastUpdated - return this as K - } - abstract fun build(): T } \ No newline at end of file diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/FileBuilder.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/FileBuilder.kt index 2807e34e..b6c02da2 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/FileBuilder.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/FileBuilder.kt @@ -56,8 +56,6 @@ class FileBuilder(id: String) : DtoBuilderBase(id) { name = name, originLocations = originLocations, customFields = customFields, - created = created, - lastUpdated = lastUpdated, sourcePath = sourcePath, targetFolder = targetFolder, fileType = fileType, diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/ImageBuilder.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/ImageBuilder.kt index a4ef7d43..45b00c17 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/ImageBuilder.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/ImageBuilder.kt @@ -94,8 +94,6 @@ class ImageBuilder(id: String) : DtoBuilderBase(id) { name = name, originLocations = originLocations, customFields = customFields, - created = created, - lastUpdated = lastUpdated, sourcePath = sourcePath, imageType = imageType, options = options, diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/ParagraphStyleBuilder.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/ParagraphStyleBuilder.kt index 94d0bf6a..2f2f5922 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/ParagraphStyleBuilder.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/ParagraphStyleBuilder.kt @@ -28,8 +28,6 @@ class ParagraphStyleBuilder(id: String) : DtoBuilderBase name = name, originLocations = originLocations, customFields = customFields, - created = created, - lastUpdated = lastUpdated, definition = definition ?: throw IllegalArgumentException("TextStyleDefinition must be provided"), ) } diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/VariableBuilder.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/VariableBuilder.kt index 70a32a1e..0c50389a 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/VariableBuilder.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/VariableBuilder.kt @@ -32,8 +32,6 @@ class VariableBuilder(id: String) : DtoBuilderBase(id name = name, originLocations = originLocations, customFields = customFields, - created = created, - lastUpdated = lastUpdated, dataType = dataType ?: throw IllegalArgumentException("dataType is required"), defaultValue = defaultValue ) diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/VariableStructureBuilder.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/VariableStructureBuilder.kt index 49e6af2a..2801e982 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/VariableStructureBuilder.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/VariableStructureBuilder.kt @@ -89,8 +89,6 @@ class VariableStructureBuilder(id: String) : DtoBuilderBase = emptyList(), customFields: MutableMap = mutableMapOf(), - created: Instant = Clock.System.now(), - lastUpdated: Instant = Clock.System.now(), + created: Instant? = null, + lastUpdated: Instant? = null, type: DocumentObjectType = DocumentObjectType.Block, displayRuleRef: DisplayRuleRef? = null, baseTemplate: String? = null, @@ -150,8 +148,8 @@ fun aTemplate( targetFolder = null, originLocations = emptyList(), customFields = CustomFieldMap(), - created = Clock.System.now(), - lastUpdated = Clock.System.now(), + created = null, + lastUpdated = null, baseTemplate = baseTemplate, options = null, metadata = emptyMap(), @@ -174,8 +172,8 @@ fun aVariable( customFields = CustomFieldMap(customFields), dataType = dataType, defaultValue = defaultValue, - lastUpdated = Clock.System.now(), - created = Clock.System.now(), + lastUpdated = null, + created = null, ) fun aParaStyle( @@ -191,8 +189,8 @@ fun aParaStyle( originLocations = originLocations, customFields = CustomFieldMap(customFields), definition = definition, - lastUpdated = Clock.System.now(), - created = Clock.System.now(), + lastUpdated = null, + created = null, ) } @@ -237,8 +235,8 @@ fun aTextStyle( originLocations = originLocations, customFields = CustomFieldMap(customFields), definition = definition, - lastUpdated = Clock.System.now(), - created = Clock.System.now(), + lastUpdated = null, + created = null, ) } @@ -273,7 +271,7 @@ fun aVariableStructure( customFields: MutableMap = mutableMapOf(), structure: Map = emptyMap(), languageVariable: String? = null, - lastUpdated: Instant = Clock.System.now(), + lastUpdated: Instant? = null, ): VariableStructure { return VariableStructure( id = id, @@ -281,7 +279,7 @@ fun aVariableStructure( originLocations = originLocations, customFields = CustomFieldMap(customFields), lastUpdated = lastUpdated, - created = Clock.System.now(), + created = null, structure = structure, languageVariable = languageVariable?.let { VariableRef(it) } ) @@ -299,8 +297,8 @@ fun aDisplayRule( name = name, originLocations = originLocations, customFields = CustomFieldMap(customFields), - lastUpdated = Clock.System.now(), - created = Clock.System.now(), + lastUpdated = null, + created = null, definition = definition ) } @@ -382,8 +380,8 @@ fun aImage( name = name, originLocations = originLocations, customFields = CustomFieldMap(customFields), - created = Clock.System.now(), - lastUpdated = Clock.System.now(), + created = null, + lastUpdated = null, sourcePath = sourcePath, imageType = imageType, options = options, @@ -409,8 +407,8 @@ fun aFile( name = name, originLocations = originLocations, customFields = CustomFieldMap(customFields), - created = Clock.System.now(), - lastUpdated = Clock.System.now(), + created = null, + lastUpdated = null, sourcePath = sourcePath, fileType = fileType, targetFolder = targetFolder, From 5485658e040e431e269eee2cdabbcd55ad60f0b2 Mon Sep 17 00:00:00 2001 From: "d.svitak" Date: Fri, 6 Feb 2026 11:30:10 +0100 Subject: [PATCH 5/9] fix library deploy part --- .../api/dto/migrationmodel/DocumentObject.kt | 9 +- .../DesignerDocumentObjectBuilder.kt | 5 +- .../InspireDocumentObjectBuilder.kt | 2493 +++++++++-------- .../InteractiveDocumentObjectBuilder.kt | 19 +- .../service/deploy/DeployClientTest.kt | 3 +- .../deploy/DesignerDeployClientTest.kt | 37 +- .../deploy/InteractiveDeployClientTest.kt | 43 +- 7 files changed, 1315 insertions(+), 1294 deletions(-) diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/DocumentObject.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/DocumentObject.kt index 3633f744..e150c655 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/DocumentObject.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/DocumentObject.kt @@ -26,7 +26,12 @@ data class DocumentObject( val subject: String?, ) : MigrationObject, RefValidatable { override fun collectRefs(): List { - // Refs are collected from content via proper traversal - return listOfNotNull(displayRuleRef, variableStructureRef) + val contentRefs = content.flatMap { + when (it) { + is RefValidatable -> it.collectRefs() + else -> emptyList() + } + } + return contentRefs + listOfNotNull(displayRuleRef, variableStructureRef) } } \ No newline at end of file diff --git a/migration-library/src/main/kotlin/com/quadient/migration/service/inspirebuilder/DesignerDocumentObjectBuilder.kt b/migration-library/src/main/kotlin/com/quadient/migration/service/inspirebuilder/DesignerDocumentObjectBuilder.kt index 1352d46b..90064024 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/service/inspirebuilder/DesignerDocumentObjectBuilder.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/service/inspirebuilder/DesignerDocumentObjectBuilder.kt @@ -24,6 +24,7 @@ import com.quadient.wfdxml.api.layoutnodes.Page import com.quadient.wfdxml.api.layoutnodes.Pages import com.quadient.wfdxml.api.layoutnodes.tables.GeneralRowSet import com.quadient.wfdxml.api.layoutnodes.tables.RowSet +import com.quadient.wfdxml.api.layoutnodes.Image as WfdXmlImage import com.quadient.wfdxml.api.module.Layout import com.quadient.wfdxml.internal.layoutnodes.FlowAreaImpl import com.quadient.wfdxml.internal.layoutnodes.PageImpl @@ -140,8 +141,8 @@ class DesignerDocumentObjectBuilder( return IcmPath.root().join(fontConfigPath).toString() } - override fun applyImageAlternateText(layout: Layout, image: Image, alternateText: String) { - getImageByName(layout, image.nameOrId())?.setAlternateText(alternateText) + override fun applyImageAlternateText(layout: Layout, image: WfdXmlImage, alternateText: String) { + image.setAlternateText(alternateText) } override fun buildDocumentObject(documentObject: DocumentObject, styleDefinitionPath: String?): String { diff --git a/migration-library/src/main/kotlin/com/quadient/migration/service/inspirebuilder/InspireDocumentObjectBuilder.kt b/migration-library/src/main/kotlin/com/quadient/migration/service/inspirebuilder/InspireDocumentObjectBuilder.kt index 5e76186c..92f4e31d 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/service/inspirebuilder/InspireDocumentObjectBuilder.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/service/inspirebuilder/InspireDocumentObjectBuilder.kt @@ -1,1247 +1,1248 @@ -package com.quadient.migration.service.inspirebuilder - -import com.quadient.migration.api.ProjectConfig -import com.quadient.migration.api.dto.migrationmodel.Area -import com.quadient.migration.api.dto.migrationmodel.CustomFieldMap -import com.quadient.migration.api.dto.migrationmodel.DisplayRule -import com.quadient.migration.api.dto.migrationmodel.DisplayRuleRef -import com.quadient.migration.api.dto.migrationmodel.DocumentContent -import com.quadient.migration.api.dto.migrationmodel.DocumentObject -import com.quadient.migration.api.dto.migrationmodel.DocumentObjectRef -import com.quadient.migration.api.dto.migrationmodel.File -import com.quadient.migration.api.dto.migrationmodel.FileRef -import com.quadient.migration.api.dto.migrationmodel.FirstMatch -import com.quadient.migration.api.dto.migrationmodel.Hyperlink -import com.quadient.migration.api.dto.migrationmodel.Image -import com.quadient.migration.api.dto.migrationmodel.ImageRef -import com.quadient.migration.api.dto.migrationmodel.Paragraph -import com.quadient.migration.api.dto.migrationmodel.Paragraph.Text -import com.quadient.migration.api.dto.migrationmodel.ParagraphStyleDefinition -import com.quadient.migration.api.dto.migrationmodel.ParagraphStyleRef -import com.quadient.migration.api.dto.migrationmodel.SelectByLanguage -import com.quadient.migration.api.dto.migrationmodel.StringValue -import com.quadient.migration.api.dto.migrationmodel.Table as TableDTO -import com.quadient.migration.api.dto.migrationmodel.TextStyleDefinition -import com.quadient.migration.api.dto.migrationmodel.TextStyleRef -import com.quadient.migration.api.dto.migrationmodel.Variable -import com.quadient.migration.api.dto.migrationmodel.VariableRef -import com.quadient.migration.api.dto.migrationmodel.VariableStructure -import com.quadient.migration.api.repository.DocumentObjectRepository -import com.quadient.migration.api.repository.ParagraphStyleRepository -import com.quadient.migration.api.repository.Repository -import com.quadient.migration.api.repository.TextStyleRepository -import com.quadient.migration.service.inspirebuilder.InspireDocumentObjectBuilder.FlowModel.* -import com.quadient.migration.service.inspirebuilder.InspireDocumentObjectBuilder.ScriptResult -import com.quadient.migration.service.inspirebuilder.InspireDocumentObjectBuilder.ScriptResult.* -import com.quadient.migration.service.ipsclient.IpsService -import com.quadient.migration.shared.Alignment -import com.quadient.migration.shared.BinOp -import com.quadient.migration.shared.Binary -import com.quadient.migration.shared.DisplayRuleDefinition -import com.quadient.migration.shared.DocumentObjectType -import com.quadient.migration.shared.FileType -import com.quadient.migration.shared.Function -import com.quadient.migration.shared.Group -import com.quadient.migration.shared.IcmPath -import com.quadient.migration.shared.ImageType -import com.quadient.migration.shared.LineSpacing -import com.quadient.migration.shared.Literal -import com.quadient.migration.shared.LiteralDataType -import com.quadient.migration.shared.LiteralOrFunctionCall -import com.quadient.migration.shared.ParagraphPdfTaggingRule as ParagraphPdfTaggingRuleModel -import com.quadient.migration.shared.SuperOrSubscript -import com.quadient.migration.shared.TabType -import com.quadient.wfdxml.WfdXmlBuilder -import com.quadient.wfdxml.api.layoutnodes.Flow -import com.quadient.wfdxml.api.layoutnodes.Font -import com.quadient.wfdxml.api.layoutnodes.Image as WfdXmlImage -import com.quadient.wfdxml.api.layoutnodes.LocationType -import com.quadient.wfdxml.api.layoutnodes.Pages -import com.quadient.wfdxml.api.layoutnodes.ParagraphStyle -import com.quadient.wfdxml.api.layoutnodes.ParagraphStyle.LineSpacingType.* -import com.quadient.wfdxml.api.layoutnodes.TabulatorType -import com.quadient.wfdxml.api.layoutnodes.data.Data -import com.quadient.wfdxml.api.layoutnodes.data.DataType -import com.quadient.wfdxml.api.layoutnodes.data.Variable as WfdXmlVariable -import com.quadient.wfdxml.api.layoutnodes.data.VariableKind -import com.quadient.wfdxml.api.layoutnodes.flow.Text as WfdXmlText -import com.quadient.wfdxml.api.layoutnodes.font.SubFont -import com.quadient.wfdxml.api.layoutnodes.tables.GeneralRowSet -import com.quadient.wfdxml.api.layoutnodes.tables.RowSet -import com.quadient.wfdxml.api.layoutnodes.tables.Table as WfdXmlTable -import com.quadient.migration.shared.TablePdfTaggingRule -import com.quadient.wfdxml.api.layoutnodes.ParagraphStyle.ParagraphPdfTaggingRule -import com.quadient.wfdxml.api.layoutnodes.TextStyle -import com.quadient.wfdxml.api.layoutnodes.TextStyleInheritFlag -import com.quadient.wfdxml.api.layoutnodes.TextStyleType -import com.quadient.wfdxml.api.layoutnodes.flow.Paragraph as WfdXmlParagraph -import com.quadient.wfdxml.api.module.Layout -import com.quadient.wfdxml.internal.data.WorkFlowTreeDefinition -import com.quadient.wfdxml.internal.layoutnodes.TextStyleImpl -import com.quadient.wfdxml.internal.layoutnodes.data.DataImpl -import com.quadient.wfdxml.internal.layoutnodes.data.WorkFlowTreeEnums.NodeOptionality -import com.quadient.wfdxml.internal.layoutnodes.data.WorkFlowTreeEnums.NodeType.SUB_TREE -import kotlinx.datetime.Clock -import org.slf4j.LoggerFactory -import java.util.concurrent.ConcurrentHashMap -import kotlin.collections.ifEmpty -import com.quadient.migration.shared.DataType as DataTypeModel -import com.quadient.migration.api.dto.migrationmodel.ParagraphStyle as ParagraphStyleDTO -import com.quadient.migration.api.dto.migrationmodel.TextStyle as TextStyleDTO - -abstract class InspireDocumentObjectBuilder( - protected val documentObjectRepository: DocumentObjectRepository, - protected val textStyleRepository: TextStyleRepository, - protected val paragraphStyleRepository: ParagraphStyleRepository, - protected val variableRepository: Repository, - protected val variableStructureRepository: Repository, - protected val displayRuleRepository: Repository, - protected val imageRepository: Repository, - protected val fileRepository: Repository, - protected val projectConfig: ProjectConfig, - protected val ipsService: IpsService, -) { - protected val logger = LoggerFactory.getLogger(this::class.java)!! - - protected val fontDataCache = ConcurrentHashMap() - - abstract fun getDocumentObjectPath(nameOrId: String, type: DocumentObjectType, targetFolder: IcmPath?): String - - abstract fun getDocumentObjectPath(documentObject: DocumentObject): String - - abstract fun getImagePath( - id: String, imageType: ImageType, name: String?, targetFolder: IcmPath?, sourcePath: String? - ): String - - abstract fun getImagePath(image: Image): String - - abstract fun getFilePath( - id: String, name: String?, targetFolder: IcmPath?, sourcePath: String?, fileType: FileType - ): String - - abstract fun getFilePath(file: File): String - - abstract fun getStyleDefinitionPath(extension: String = "wfd"): String - - abstract fun getFontRootFolder(): String - - abstract fun buildDocumentObject(documentObject: DocumentObject, styleDefinitionPath: String?): String - - abstract fun shouldIncludeInternalDependency(documentObject: DocumentObject): Boolean - - protected fun collectLanguages(documentObject: DocumentObject): List { - val languages = mutableSetOf() - - fun collectLanguagesFromContent(content: List) { - for (item in content) { - when (item) { - is SelectByLanguage -> item.cases.forEach { languages.add(it.language) } - is Area -> collectLanguagesFromContent(item.content) - is FirstMatch -> { - item.cases.forEach { case -> collectLanguagesFromContent(case.content) } - collectLanguagesFromContent(item.default) - } - - is TableDTO -> item.rows.forEach { row -> - row.cells.forEach { cell -> collectLanguagesFromContent(cell.content) } - } - - is DocumentObjectRef -> { - val documentObject = documentObjectRepository.findOrFail(item.id) - if (shouldIncludeInternalDependency(documentObject)) { - collectLanguagesFromContent(documentObject.content) - } - } - - is Paragraph -> item.content.forEach { textModel -> - textModel.content.forEach { textContent -> - when (textContent) { - is FirstMatch -> { - textContent.cases.forEach { case -> collectLanguagesFromContent(case.content) } - collectLanguagesFromContent(textContent.default) - } - - is TableDTO -> textContent.rows.forEach { row -> - row.cells.forEach { cell -> collectLanguagesFromContent(cell.content) } - } - - is DocumentObjectRef -> { - val documentObject = documentObjectRepository.findOrFail(textContent.id) - if (shouldIncludeInternalDependency(documentObject)) { - collectLanguagesFromContent(documentObject.content) - } - } - - else -> {} - } - } - } - - else -> {} - } - } - } - - collectLanguagesFromContent(documentObject.content) - - return languages.toList() - } - - protected open fun wrapSuccessFlowInConditionFlow( - layout: Layout, variableStructure: VariableStructure, ruleDef: DisplayRuleDefinition, successFlow: Flow - ): Flow { - return layout.addFlow().setType(Flow.Type.SELECT_BY_CONDITION).addLineForSelectByCondition( - layout.data.addVariable().setKind(VariableKind.CALCULATED).setDataType(DataType.BOOL) - .setScript(ruleDef.toScript(layout, variableStructure, variableRepository::findOrFail)), - successFlow - ) - } - - protected open fun buildSuccessRowWrappedInConditionRow( - layout: Layout, - variableStructure: VariableStructure, - ruleDef: DisplayRuleDefinition, - multipleRowSet: GeneralRowSet - ): GeneralRowSet { - val successRow = layout.addRowSet().setType(RowSet.Type.SINGLE_ROW) - - multipleRowSet.addRowSet( - layout.addRowSet().setType(RowSet.Type.SELECT_BY_CONDITION).addLineForSelectByCondition( - layout.data.addVariable().setKind(VariableKind.CALCULATED).setDataType(DataType.BOOL) - .setScript(ruleDef.toScript(layout, variableStructure, variableRepository::findOrFail)), - successRow - ) - ) - - return successRow - } - - fun buildStyleLayoutDelta(textStyles: List, paragraphStyles: List): String { - logger.debug("Starting to build style layout delta.") - - val builder = WfdXmlBuilder() - val layout = builder.addLayout() - - if (fontDataCache.isEmpty()) { - val fontDataString = ipsService.gatherFontData(getFontRootFolder()) - fontDataCache.putAll(fontDataStringToMap(fontDataString)) - } - - buildTextStyles(layout, textStyles) - buildParagraphStyles(layout, paragraphStyles) - - logger.debug("Successfully built style layout delta.") - return builder.buildStyleLayoutDelta() - } - - fun buildStyles( - textStyles: List, - paragraphStyles: List, - ): String { - logger.debug("Starting to build style definition.") - - val builder = WfdXmlBuilder() - val layout = builder.addLayout() - - layout.setName("DocumentLayout") - val flow = layout.addFlow().setSectionFlow(true).setWebEditingType(Flow.WebEditingType.SECTION) - layout.pages.setMainFlow(flow) - layout.addPage().setName("Page 1").setType(Pages.PageConditionType.SIMPLE) - layout.addRoot().setAllowRuntimeModifications(true) - - if (fontDataCache.isEmpty()) { - val fontDataString = ipsService.gatherFontData(getFontRootFolder()) - fontDataCache.putAll(fontDataStringToMap(fontDataString)) - } - - buildTextStyles(layout, textStyles) - buildParagraphStyles(layout, paragraphStyles) - - logger.debug("Successfully built style definition.") - return builder.build() - } - - fun buildDocumentContentAsFlows( - layout: Layout, - variableStructure: VariableStructure, - content: List, - flowName: String? = null, - languages: List, - ): List { - val mutableContent = content.toMutableList() - - var idx = 0 - val flowModels = mutableListOf() - while (idx < mutableContent.size) { - when (val contentPart = mutableContent[idx]) { - is TableDTO, is Paragraph, is ImageRef -> { - val flowParts = gatherFlowParts(mutableContent, idx) - idx += flowParts.size - 1 - flowModels.add(Composite(flowParts)) - } - - is DocumentObjectRef -> flowModels.add(DocumentObject(contentPart)) - is FileRef -> flowModels.add(File(contentPart)) - is Area -> mutableContent.addAll(idx + 1, contentPart.content) - is FirstMatch -> flowModels.add(FirstMatch(contentPart)) - is SelectByLanguage -> flowModels.add(SelectByLanguage(contentPart)) - } - idx++ - } - - val flowCount = flowModels.size - var flowSuffix = 1 - return flowModels.mapNotNull { - when (it) { - is FlowModel.DocumentObject -> buildDocumentObjectRef(layout, variableStructure, it.ref, languages) - is FlowModel.File -> buildFileRef(layout, it.ref) - is FlowModel.Composite -> { - if (flowName == null) { - buildCompositeFlow(layout, variableStructure, it.parts, null, languages) - } else { - val name = if (flowCount == 1) flowName else "$flowName $flowSuffix" - flowSuffix++ - buildCompositeFlow(layout, variableStructure, it.parts, name, languages) - } - } - - is FlowModel.FirstMatch -> { - if (flowName == null) { - buildFirstMatch(layout, variableStructure, it.model, false, null, languages) - } else { - val name = if (flowCount == 1) flowName else "$flowName $flowSuffix" - flowSuffix++ - buildFirstMatch(layout, variableStructure, it.model, false, name, languages) - } - } - - is FlowModel.SelectByLanguage -> { - if (flowName == null) { - buildSelectByLanguage(layout, variableStructure, it.model, null, languages) - } else { - val name = if (flowCount == 1) flowName else "$flowName $flowSuffix" - flowSuffix++ - buildSelectByLanguage(layout, variableStructure, it.model, name, languages) - } - } - } - } - } - - sealed interface FlowModel { - data class Composite(val parts: List) : FlowModel - data class DocumentObject(val ref: DocumentObjectRef) : FlowModel - data class File(val ref: FileRef) : FlowModel - data class FirstMatch(val model: com.quadient.migration.api.dto.migrationmodel.FirstMatch) : FlowModel - data class SelectByLanguage(val model: com.quadient.migration.api.dto.migrationmodel.SelectByLanguage) : FlowModel - } - - protected fun List.toSingleFlow( - layout: Layout, - variableStructure: VariableStructure, - flowName: String? = null, - displayRuleRef: DisplayRuleRef? = null, - ): Flow { - val singleFlow = if (this.size == 1) { - this[0] - } else { - val sectionFlow = layout.addFlow().setType(Flow.Type.SIMPLE).setSectionFlow(true) - flowName?.let { sectionFlow.setName(it) } - - val sectionFlowText = sectionFlow.addParagraph().addText() - - this.forEach { sectionFlowText.appendFlow(it) } - - sectionFlow - } - - return if (displayRuleRef == null) { - singleFlow - } else { - val displayRule = displayRuleRepository.findOrFail(displayRuleRef.id) - val def = displayRule.definition - if (def == null) { - error("Display rule '${displayRuleRef.id}' definition is null.") - } - - wrapSuccessFlowInConditionFlow(layout, variableStructure, def, singleFlow) - } - } - - protected fun buildDocumentContentAsSingleFlow( - layout: Layout, - variableStructure: VariableStructure, - content: List, - flowName: String? = null, - displayRuleRef: DisplayRuleRef? = null, - languages: List, - ): Flow { - return buildDocumentContentAsFlows(layout, variableStructure, content, flowName, languages).toSingleFlow( - layout, variableStructure, flowName, displayRuleRef - ) - } - - protected fun initVariableStructure(layout: Layout, documentObject: DocumentObject): VariableStructure { - val variableStructureId = documentObject.variableStructureRef?.id ?: projectConfig.defaultVariableStructure - - val variableStructureModel = - variableStructureId?.let { variableStructureRepository.findOrFail(it) } ?: VariableStructure( - id = "defaultVariableStructure", - lastUpdated = Clock.System.now(), - created = Clock.System.now(), - structure = mutableMapOf(), - customFields = CustomFieldMap(), - languageVariable = null, - ) - - val normalizedVariablePaths = variableStructureModel.structure.map { (_, variablePathData) -> - removeDataFromVariablePath(variablePathData.path) - }.filter { it.isNotBlank() } - - val variableTree = buildVariableTree(normalizedVariablePaths) - - val workflowTreeDefinition = WorkFlowTreeDefinition("Root", SUB_TREE, NodeOptionality.ARRAY).also { - buildVariablePathPart(it, variableTree) - } - - val layoutData = layout.data - layoutData.importDataDefinition(workflowTreeDefinition) - if (variableTree.isNotEmpty() && variableTree.values.first() is ArrayVariable) { - layoutData.setRepeatedBy("Data.${variableTree.keys.first()}") - } - - return variableStructureModel - } - - private fun buildVariablePathPart( - parentNode: WorkFlowTreeDefinition, currentMap: Map - ) { - currentMap.forEach { - val variablePathPart = it.value - val optionality = - if (variablePathPart is ArrayVariable) NodeOptionality.ARRAY else NodeOptionality.MUST_EXIST - - val node = WorkFlowTreeDefinition(variablePathPart.name, SUB_TREE, optionality) - parentNode.addSubNode(node) - - if (variablePathPart.children.isNotEmpty()) { - buildVariablePathPart(node, variablePathPart.children) - } - } - } - - private fun upsertSubFont(font: Font, isBold: Boolean, isItalic: Boolean): SubFont? { - val subFontName = buildFontName(isBold, isItalic) - - val fontLocation = fontDataCache[FontKey(font.name, subFontName)] - ?: fontDataCache[FontKey(font.name, buildFontName(bold = false, italic = false))] - ?: return null - - font.subFonts.removeAll { it.name == subFontName } - return font.addSubfont().setName(subFontName).setBold(isBold).setItalic(isItalic) - .setLocation(fontLocation, LocationType.ICM) - } - - fun buildTextStyles(layout: Layout, textStyleModels: List) { - val arialFont = getFontByName(layout, "Arial") - require(arialFont != null) { "Layout must contain Arial font." } - arialFont.setName("Arial").setFontName("Arial") - upsertSubFont(arialFont, isBold = false, isItalic = false) - - textStyleModels.forEach { styleModel -> - val definition = styleModel.resolve() - val textStyle = layout.addTextStyle().setName(styleModel.nameOrId()) - applyTextStyleProperties(layout, textStyle, definition) - } - } - - private fun applyTextStyleProperties(layout: Layout, textStyle: TextStyle, definition: TextStyleDefinition) { - val fontFamily = definition.fontFamily ?: "Arial" - - val font = getFontByName(layout, fontFamily) ?: layout.addFont().setName(fontFamily).setFontName(fontFamily) - textStyle.setFont(font) - - val subFont = upsertSubFont(font, definition.bold, definition.italic) - if (subFont != null) { - textStyle.setSubFont(subFont) - } - - textStyle.setBold(definition.bold) - textStyle.seItalic(definition.italic) - textStyle.setUnderline(definition.underline) - textStyle.setStrikeThrough(definition.strikethrough) - - definition.size?.let { textStyle.setFontSizeInMeters(it.toMeters()) } - definition.interspacing?.let { textStyle.setInterSpacing(it.toMeters()) } - - when (definition.superOrSubscript) { - SuperOrSubscript.Subscript -> textStyle.setSubScript(true).setSuperScript(false) - SuperOrSubscript.Superscript -> textStyle.setSubScript(false).setSuperScript(true) - SuperOrSubscript.None -> textStyle.setSubScript(false).setSuperScript(false) - } - - definition.foregroundColor?.let { colorModel -> - val layoutColor = getColorByRGB(layout, colorModel.red(), colorModel.green(), colorModel.blue()) - ?: layout.addColor().setRGB(colorModel.red(), colorModel.green(), colorModel.blue()) - val fillStyle = getFillStyleByColor(layout, layoutColor) - ?: layout.addFillStyle().setColor(layoutColor) - textStyle.setFillStyle(fillStyle) - } - } - - fun buildParagraphStyles(layout: Layout, paragraphStyleModels: List) { - paragraphStyleModels.forEach { styleModel -> - val definition = styleModel.resolve() - - val paragraphStyle = layout.addParagraphStyle().setName(styleModel.nameOrId()) - - definition.leftIndent?.let { paragraphStyle.setLeftIndent(it.toMeters()) } - definition.rightIndent?.let { paragraphStyle.setRightIndent(it.toMeters()) } - definition.defaultTabSize?.let { paragraphStyle.setDefaultTabSize(it.toMeters()) } - definition.spaceBefore?.let { paragraphStyle.setSpaceBefore(it.toMeters()) } - definition.spaceAfter?.let { paragraphStyle.setSpaceAfter(it.toMeters()) } - val alignType = when (definition.alignment) { - Alignment.Left -> ParagraphStyle.AlignType.LEFT - Alignment.Right -> ParagraphStyle.AlignType.RIGHT - Alignment.Center -> ParagraphStyle.AlignType.CENTER - Alignment.JustifyLeft -> ParagraphStyle.AlignType.JUSTIFY_lEFT - Alignment.JustifyRight -> ParagraphStyle.AlignType.JUSTIFY_RIGHT - Alignment.JustifyCenter -> ParagraphStyle.AlignType.JUSTIFY_CENTER - Alignment.JustifyBlock -> ParagraphStyle.AlignType.JUSTIFY_BLOCK - Alignment.JustifyWithMargins -> ParagraphStyle.AlignType.JUSTIFY_WITH_MARGIN - Alignment.JustifyBlockUniform -> ParagraphStyle.AlignType.JUSTIFY_BLOCK_UNIFORM - } - paragraphStyle.setAlignType(alignType) - - definition.firstLineIndent?.let { paragraphStyle.setFirstLineLeftIndent(it.toMeters()) } - - val lineSpacing = definition.lineSpacing - val (lineSpacingType, lineSpacingValue) = when (lineSpacing) { - is LineSpacing.Additional -> Pair(ADDITIONAL, lineSpacing.size?.toMeters()) - is LineSpacing.AtLeast -> Pair(AT_LEAST, lineSpacing.size?.toMeters()) - is LineSpacing.Exact -> Pair(EXACT, lineSpacing.size?.toMeters()) - is LineSpacing.ExactFromPrevious -> Pair(EXACT_FROM_PREVIOUS, lineSpacing.size?.toMeters()) - is LineSpacing.ExactFromPreviousWithAdjust -> Pair( - EXACT_FROM_PREVIOUS_WITH_ADJUST, lineSpacing.size?.toMeters() - ) - - is LineSpacing.ExactFromPreviousWithAdjustLegacy -> Pair( - EXACT_FROM_PREVIOUS_WITH_ADJUST_OLD, lineSpacing.size?.toMeters() - ) - - is LineSpacing.MultipleOf -> Pair(MULTIPLE_OF, lineSpacing.value) - } - paragraphStyle.setLineSpacingType(lineSpacingType) - lineSpacingValue?.let { paragraphStyle.setLineSpacingValue(it) } - - definition.tabs?.let { tabsModel -> - paragraphStyle.setUseOutsideTabs(tabsModel.useOutsideTabs) - tabsModel.tabs.forEach { tabModel -> - val tabType = when (tabModel.type) { - TabType.Left -> TabulatorType.LEFT - TabType.Right -> TabulatorType.RIGHT - TabType.Center -> TabulatorType.CENTER - TabType.DecimalWord -> TabulatorType.WORD_DECIMAL - TabType.Decimal -> TabulatorType.DECIMAL - } - - paragraphStyle.addTabulator(tabModel.position.toMeters(), tabType) - } - } - - definition.pdfTaggingRule?.let { pdfTaggingRule -> - val rule = when (pdfTaggingRule) { - ParagraphPdfTaggingRuleModel.Paragraph -> ParagraphPdfTaggingRule.PARAGRAPH - ParagraphPdfTaggingRuleModel.Heading -> ParagraphPdfTaggingRule.HEADING - ParagraphPdfTaggingRuleModel.Heading1 -> ParagraphPdfTaggingRule.HEADING_1 - ParagraphPdfTaggingRuleModel.Heading2 -> ParagraphPdfTaggingRule.HEADING_2 - ParagraphPdfTaggingRuleModel.Heading3 -> ParagraphPdfTaggingRule.HEADING_3 - ParagraphPdfTaggingRuleModel.Heading4 -> ParagraphPdfTaggingRule.HEADING_4 - ParagraphPdfTaggingRuleModel.Heading5 -> ParagraphPdfTaggingRule.HEADING_5 - ParagraphPdfTaggingRuleModel.Heading6 -> ParagraphPdfTaggingRule.HEADING_6 - } - paragraphStyle.setPdfTaggingRule(rule) - } - } - } - - sealed interface ImagePlaceholderResult { - object RenderAsNormal : ImagePlaceholderResult - object Skip : ImagePlaceholderResult - data class Placeholder(val value: String) : ImagePlaceholderResult - } - protected fun getImagePlaceholder(imageModel: Image): ImagePlaceholderResult { - if (imageModel.imageType == ImageType.Unknown && !imageModel.skip.skipped) { - throw IllegalStateException( - "Image '${imageModel.nameOrId()}' has unknown type and is not set to be skipped." - ) - } - if (imageModel.sourcePath.isNullOrBlank() && !imageModel.skip.skipped) { - throw IllegalStateException( - "Image '${imageModel.nameOrId()}' has missing source path and is not set to be skipped." - ) - } - - if (imageModel.skip.skipped && imageModel.skip.placeholder != null) { - return ImagePlaceholderResult.Placeholder(imageModel.skip.placeholder) - } else if (imageModel.skip.skipped) { - return ImagePlaceholderResult.Skip - } - - return ImagePlaceholderResult.RenderAsNormal - } - - protected fun getOrBuildImage(layout: Layout, imageModel: Image, alternateText: String? = null): WfdXmlImage { - val image = getImageByName(layout, imageModel.nameOrId()) ?: layout.addImage().setName(imageModel.nameOrId()) - .setImageLocation(getImagePath(imageModel), LocationType.ICM) - - val options = imageModel.options - if (options != null) { - options.resizeWidth?.let { image.setResizeWidth(it.toMeters()) } - options.resizeHeight?.let { image.setResizeHeight(it.toMeters()) } - } - - if (!alternateText.isNullOrBlank()) { - applyImageAlternateText(layout, imageModel, alternateText) - } - - return image - } - - protected abstract fun applyImageAlternateText(layout: Layout, image: Image, alternateText: String) - - private fun buildFileRef( - layout: Layout, - fileRef: FileRef, - ): Flow? { - val fileModel = fileRepository.findOrFail(fileRef.id) - - if (fileModel.skip.skipped && fileModel.skip.placeholder == null) { - val reason = fileModel.skip.reason?.let { "with reason: $it" } ?: "without reason" - logger.debug("File ${fileRef.id} is set to be skipped without placeholder $reason.") - return null - } else if (fileModel.skip.skipped && fileModel.skip.placeholder != null) { - val reason = fileModel.skip.reason?.let { "and reason: $it" } ?: "without reason" - logger.debug("File ${fileRef.id} is set to be skipped with placeholder $reason.") - val flow = layout.addFlow().setType(Flow.Type.SIMPLE) - flow.addParagraph().addText().appendText(fileModel.skip.placeholder) - return flow - } - - if (fileModel.sourcePath.isNullOrBlank()) { - throw IllegalStateException( - "File '${fileModel.nameOrId()}' has missing source path and is not set to be skipped." - ) - } - - val flow = getFlowByName(layout, fileModel.nameOrId()) ?: run { - layout.addFlow() - .setName(fileModel.nameOrId()) - .setType(Flow.Type.DIRECT_EXTERNAL) - .setLocation(getFilePath(fileModel)) - } - - return flow - } - - private fun buildCompositeFlow( - layout: Layout, - variableStructure: VariableStructure, - documentContentModelParts: List, - flowName: String? = null, - languages: List - ): Flow { - val flow = layout.addFlow().setType(Flow.Type.SIMPLE) - flowName?.let { flow.setName(it) } - - documentContentModelParts.forEach { - when (it) { - is Paragraph -> buildParagraph(layout, variableStructure, flow, it, languages) - is TableDTO -> flow.addParagraph().addText() - .appendTable(buildTable(layout, variableStructure, it, languages)) - - is ImageRef -> buildAndAppendImage(layout, flow.addParagraph().addText(), it) - else -> error("Content part type ${it::class.simpleName} is not allowed in composite flow.") - } - } - - return flow - } - - private fun buildDocumentObjectRef( - layout: Layout, - variableStructure: VariableStructure, - documentObjectRef: DocumentObjectRef, - languages: List, - ): Flow? { - val documentModel = documentObjectRepository.findOrFail(documentObjectRef.id) - - if (documentModel.skip.skipped && documentModel.skip.placeholder == null) { - val reason = documentModel.skip.reason?.let { "with reason: $it" } ?: "without reason" - logger.debug("Document content part ${documentObjectRef.id} is set to be skipped without placeholder $reason.") - return null - } else if (documentModel.skip.skipped && documentModel.skip.placeholder != null) { - val reason = documentModel.skip.reason?.let { "and reason: $it" } ?: "without reason" - logger.debug("Document content part ${documentObjectRef.id} is set to be skipped with placeholder $reason.") - val flow = layout.addFlow().setType(Flow.Type.SIMPLE) - flow.addParagraph().addText().appendText(documentModel.skip.placeholder) - return flow - } - - val flow = getFlowByName(layout, documentModel.nameOrId()) ?: if (documentModel.internal == true) { - buildDocumentContentAsSingleFlow( - layout, - variableStructure, - documentModel.content, - documentModel.nameOrId(), - documentModel.displayRuleRef?.let { DisplayRuleRef(it.id) }, - languages - ) - } else { - layout.addFlow().setName(documentModel.nameOrId()).setType(Flow.Type.DIRECT_EXTERNAL) - .setLocation(getDocumentObjectPath(documentModel)) - } - - if (documentObjectRef.displayRuleRef != null) { - val displayRule = displayRuleRepository.findOrFail(documentObjectRef.displayRuleRef.id) - val def = displayRule.definition - if (def == null) { - error("Display rule '${documentObjectRef.displayRuleRef.id}' definition is null.") - } - - return wrapSuccessFlowInConditionFlow(layout, variableStructure, def, flow) - } - - return flow - } - - private fun gatherFlowParts(content: List, startIndex: Int): List { - val flowParts = mutableListOf() - - var index = startIndex - - do { - val contentPart = content[index] - if (contentPart is TableDTO || contentPart is Paragraph || contentPart is ImageRef) { - flowParts.add(contentPart) - index++ - } else { - break - } - } while (index < content.size) - - return flowParts - } - - private fun buildParagraph( - layout: Layout, - variableStructure: VariableStructure, - flow: Flow, - paragraphModel: Paragraph, - languages: List - ) { - val paragraph = if (paragraphModel.displayRuleRef == null) { - flow.addParagraph() - } else { - buildSuccessFlowWrappedInInlineConditionFlow( - layout, variableStructure, paragraphModel.displayRuleRef.id, flow.addParagraph().addText() - ).addParagraph() - } - - val paragraphStyle = findParagraphStyle(paragraphModel)?.also { - paragraph.setExistingParagraphStyle("ParagraphStyles.${it.nameOrId()}") - } - - paragraphModel.content.forEach { textModel -> - val baseText = if (textModel.displayRuleRef == null) { - paragraph.addText() - } else { - buildSuccessFlowWrappedInInlineConditionFlow( - layout, variableStructure, textModel.displayRuleRef.id, paragraph.addText() - ).addParagraph().also { - if (paragraphStyle != null) it.setExistingParagraphStyle("ParagraphStyles.${paragraphStyle.nameOrId()}") - }.addText() - } - - val baseTextStyleModel = findTextStyle(textModel) - baseTextStyleModel?.also { baseText.setExistingTextStyle("TextStyles.${it.nameOrId()}") } - - var currentText = baseText - - textModel.content.forEach { - when (it) { - is StringValue -> currentText.appendText(it.value) - is VariableRef -> currentText.appendVariable(it, layout, variableStructure) - is TableDTO -> currentText.appendTable(buildTable(layout, variableStructure, it, languages)) - is DocumentObjectRef -> buildDocumentObjectRef( - layout, variableStructure, it, languages - )?.also { flow -> - currentText.appendFlow(flow) - } - - is FileRef -> buildFileRef(layout, it)?.also { flow -> - currentText.appendFlow(flow) - } - - is ImageRef -> buildAndAppendImage(layout, currentText, it) - is Hyperlink -> currentText = buildAndAppendHyperlink(layout, paragraph, baseTextStyleModel, it) - is FirstMatch -> currentText.appendFlow( - buildFirstMatch(layout, variableStructure, it, true, null, languages) - ) - } - } - } - } - - private fun createHyperlinkTextStyle( - layout: Layout, baseTextStyleModel: TextStyleDTO?, hyperlinkModel: Hyperlink - ): TextStyle { - val baseStyleName = baseTextStyleModel?.nameOrId() ?: "text" - val hyperlinkName = generateUniqueHyperlinkStyleName(layout, baseStyleName) - - val urlVariable = createUrlVariable(layout, hyperlinkName, hyperlinkModel.url) - - val hyperlinkStyle = layout.addTextStyle() - .setName(hyperlinkName) - .setUrlTarget(urlVariable) - .setType(TextStyleType.DELTA) - .setUrlAlternateText(hyperlinkModel.alternateText) - .addInheritFlags( - *TextStyleInheritFlag.entries - .filter { it != TextStyleInheritFlag.UNDERLINE && it != TextStyleInheritFlag.FILL_STYLE } - .toTypedArray()) - (hyperlinkStyle as TextStyleImpl).ancestorId = "Def.TextStyleHyperlink" - - if (baseTextStyleModel != null) { - val definition = baseTextStyleModel.resolve() - applyTextStyleProperties(layout, hyperlinkStyle, definition) - } - - return hyperlinkStyle - } - - private fun generateUniqueHyperlinkStyleName(layout: Layout, baseStyleName: String): String { - var counter = 1 - var candidateName = "${baseStyleName}_url_${counter}" - while (getTextStyleByName(layout, candidateName) != null) { - counter++ - candidateName = "${baseStyleName}_url_${counter}" - } - return candidateName - } - - private fun createUrlVariable(layout: Layout, variableName: String, url: String): WfdXmlVariable { - return layout.data.addVariable().setName(variableName).setKind(VariableKind.CONSTANT) - .setDataType(DataType.STRING).setValue(url) - } - - private fun buildAndAppendImage(layout: Layout, text: WfdXmlText, ref: ImageRef) { - val imageModel = imageRepository.findOrFail(ref.id) - - when (val imagePlaceholder = getImagePlaceholder(imageModel)) { - is ImagePlaceholderResult.Placeholder -> { - text.appendText(imagePlaceholder.value) - return - } - is ImagePlaceholderResult.RenderAsNormal -> {} - is ImagePlaceholderResult.Skip -> return - } - - text.appendImage(getOrBuildImage(layout, imageModel, imageModel.alternateText)) - } - - private fun buildAndAppendHyperlink( - layout: Layout, paragraph: WfdXmlParagraph, baseTextStyleModel: TextStyleDTO?, hyperlinkModel: Hyperlink - ): WfdXmlText { - val hyperlinkText = paragraph.addText() - val hyperlinkStyle = createHyperlinkTextStyle(layout, baseTextStyleModel, hyperlinkModel) - hyperlinkText.setTextStyle(hyperlinkStyle) - hyperlinkText.appendText(hyperlinkModel.displayText ?: hyperlinkModel.url) - - val newText = paragraph.addText() - baseTextStyleModel?.also { newText.setExistingTextStyle("TextStyles.${it.nameOrId()}") } - return newText - } - - private fun WfdXmlText.appendVariable( - ref: VariableRef, layout: Layout, variableStructure: VariableStructure - ): WfdXmlText { - val variableModel = variableRepository.findOrFail(ref.id) - - val variablePathData = variableStructure.structure[ref.id] - if (variablePathData == null || variablePathData.path.isBlank()) { - this.appendText("""$${variablePathData?.name ?: variableModel.nameOrId()}$""") - } else { - val variableName = variablePathData.name ?: variableModel.nameOrId() - this.appendVariable(getOrCreateVariable(layout.data, variableName, variableModel, variablePathData.path)) - } - - return this - } - - private fun findParagraphStyle(paragraphModel: Paragraph): ParagraphStyleDTO? { - if (paragraphModel.styleRef == null) return null - - val paraStyleModel = paragraphStyleRepository.firstWithDefinition(paragraphModel.styleRef.id) - ?: error("Paragraph style definition for ${paragraphModel.styleRef.id} not found.") - - return paraStyleModel - } - - private fun findTextStyle(textModel: Text): TextStyleDTO? { - if (textModel.styleRef == null) return null - - val textStyleModel = textStyleRepository.firstWithDefinition(textModel.styleRef.id) - ?: error("Text style definition for ${textModel.styleRef.id} not found.") - - return textStyleModel - } - - private fun buildSuccessFlowWrappedInInlineConditionFlow( - layout: Layout, variableStructure: VariableStructure, displayRuleId: String, text: WfdXmlText - ): Flow { - val displayRule = displayRuleRepository.findOrFail(displayRuleId) - if (displayRule.definition == null) { - error("Display rule '$displayRuleId' definition is null.") - } - - val successFlow = layout.addFlow().setType(Flow.Type.SIMPLE) - val def = displayRule.definition!! - - text.appendFlow( - layout.addFlow().setType(Flow.Type.SELECT_BY_INLINE_CONDITION).addLineForSelectByInlineCondition( - def.toScript(layout, variableStructure, variableRepository::findOrFail), - successFlow - ) - ) - - return successFlow - } - - private fun buildTable( - layout: Layout, variableStructure: VariableStructure, model: TableDTO, languages: List - ): WfdXmlTable { - val table = layout.addTable().setDisplayAsImage(false) - - if (model.columnWidths.isNotEmpty()) { - model.columnWidths.forEach { table.addColumn(it.minWidth.toMeters(), it.percentWidth) } - } else { - val numberOfColumns = model.rows.firstOrNull()?.cells?.size ?: 0 - repeat(numberOfColumns) { table.addColumn() } - } - - val rowset = layout.addRowSet().setType(RowSet.Type.MULTIPLE_ROWS) - table.setRowSet(rowset) - - model.rows.forEach { rowModel -> - val row = if (rowModel.displayRuleRef == null) { - layout.addRowSet().setType(RowSet.Type.SINGLE_ROW).also { rowset.addRowSet(it) } - } else { - val displayRule = displayRuleRepository.findOrFail(rowModel.displayRuleRef.id) - val def = displayRule.definition - if (def == null) { - error("Display rule '${rowModel.displayRuleRef.id}' definition is null.") - } - - buildSuccessRowWrappedInConditionRow( - layout, variableStructure, def, rowset - ) - } - - rowModel.cells.forEach { cellModel -> - val cellContentFlow = buildDocumentContentAsSingleFlow( - layout, variableStructure, cellModel.content, null, null, languages - ) - val cellFlow = if (cellContentFlow.type === Flow.Type.SELECT_BY_INLINE_CONDITION) { - layout.addFlow().setType(Flow.Type.SIMPLE).setSectionFlow(true) - .setWebEditingType(Flow.WebEditingType.SECTION) - .also { it.addParagraph().addText().appendFlow(cellContentFlow) } - } else cellContentFlow - - row.addCell( - layout.addCell().setSpanLeft(cellModel.mergeLeft).setSpanUp(cellModel.mergeUp) - .setFlowToNextPage(true).setFlow(cellFlow) - ) - } - } - - when (model.pdfTaggingRule) { - TablePdfTaggingRule.None -> table.setTablePdfTaggingRule(WfdXmlTable.TablePdfTaggingRule.NONE) - TablePdfTaggingRule.Default -> table.setTablePdfTaggingRule(WfdXmlTable.TablePdfTaggingRule.DEFAULT) - TablePdfTaggingRule.Table -> table.setTablePdfTaggingRule(WfdXmlTable.TablePdfTaggingRule.TABLE) - TablePdfTaggingRule.Artifact -> table.setTablePdfTaggingRule(WfdXmlTable.TablePdfTaggingRule.ARTIFACT) - } - table.setTablePdfAlternateText(model.pdfAlternateText) - - return table - } - - private fun buildFirstMatch( - layout: Layout, - variableStructure: VariableStructure, - model: FirstMatch, - isInline: Boolean, - flowName: String? = null, - languages: List, - ): Flow { - val firstMatchFlow = layout.addFlow().setType(Flow.Type.SELECT_BY_INLINE_CONDITION) - flowName?.let { firstMatchFlow.setName(it) } - - model.cases.forEachIndexed { i, case -> - val displayRule = displayRuleRepository.findOrFail(case.displayRuleRef.id) - if (displayRule.definition == null) { - error("Display rule '${case.displayRuleRef.id}' definition is null.") - } - - val caseName = case.name ?: "Case ${i + 1}" - - val contentFlow = - buildDocumentContentAsSingleFlow(layout, variableStructure, case.content, null, null, languages) - - val caseFlow = - if (isInline) contentFlow else layout.addFlow().setSectionFlow(true).setType(Flow.Type.SIMPLE) - .setWebEditingType(Flow.WebEditingType.SECTION).setDisplayName(caseName) - .also { it.addParagraph().addText().appendFlow(contentFlow) } - - val def = displayRule.definition!! - firstMatchFlow.addLineForSelectByInlineCondition( - def.toScript(layout, variableStructure, variableRepository::findOrFail), - caseFlow - ) - } - - if (model.default.isNotEmpty()) { - val contentFlow = - buildDocumentContentAsSingleFlow(layout, variableStructure, model.default, null, null, languages) - - val caseFlow = - if (isInline) contentFlow else layout.addFlow().setSectionFlow(true).setType(Flow.Type.SIMPLE) - .setWebEditingType(Flow.WebEditingType.SECTION).setDisplayName("Else Case") - .also { it.addParagraph().addText().appendFlow(contentFlow) } - - firstMatchFlow.setDefaultFlow(caseFlow) - } - - return firstMatchFlow - } - - private fun buildSelectByLanguage( - layout: Layout, - variableStructure: VariableStructure, - model: SelectByLanguage, - flowName: String?, - languages: List, - ): Flow { - val languageFlow = layout.addFlow().setType(Flow.Type.SELECT_BY_LANGUAGE) - flowName?.let { languageFlow.setName(it) } - - val defaultLanguage = projectConfig.defaultLanguage - - val caseFlows = model.cases.associate { - val caseName = "Case ${it.language}" - val contentFlow = buildDocumentContentAsSingleFlow( - layout, variableStructure, it.content, null, null, languages - ).setDisplayName(caseName) - it.language to contentFlow - } - - var defaultLanguageFlow: Flow? = null - for (language in languages) { - val contentFlow: Flow = (caseFlows[language] as Flow?) ?: layout.addFlow().setType(Flow.Type.SIMPLE).setDisplayName("Case $language") - languageFlow.addLineForSelectByInlineCondition(language, contentFlow) - - if (language == defaultLanguage) { - defaultLanguageFlow = contentFlow - } - } - - languageFlow.setDefaultFlow(defaultLanguageFlow ?: layout.addFlow().setType(Flow.Type.SIMPLE)) - - return languageFlow - } - - protected fun List.paragraphIfEmpty(): List { - return this.ifEmpty { - listOf( - com.quadient.migration.api.dto.migrationmodel.Paragraph( - listOf(com.quadient.migration.api.dto.migrationmodel.Paragraph.Text(listOf(), null, null)), - null, - null - ) - ) - } - } - - private fun TextStyleDTO.resolve(): TextStyleDefinition { - val def = this.definition - return when (def) { - is TextStyleDefinition -> def - is TextStyleRef -> { - textStyleRepository.find(def.id)?.resolve() ?: error("Invalid text style reference") - } - else -> error("Invalid text style definition type") - } - } - - private fun ParagraphStyleDTO.resolve(): ParagraphStyleDefinition { - val def = this.definition - return when (def) { - is ParagraphStyleDefinition -> def - is ParagraphStyleRef -> paragraphStyleRepository.findOrFail(def.id).resolve() - else -> error("Invalid paragraph style definition type") - } - } - - sealed interface ScriptResult { - data class Success(val variableScript: String) : ScriptResult { - override fun toString() = variableScript - } - - data class Failure(val variableName: String) : ScriptResult { - override fun toString() = variableName - } - } -} - -fun DisplayRuleDefinition.toScript( - layout: Layout, variableStructure: VariableStructure, findVar: (String) -> Variable -): String { - return "return ${this.group.toScript(layout, variableStructure, findVar)};" -} - -fun Group.toScript( - layout: Layout, variableStructure: VariableStructure, findVar: (String) -> Variable -): String { - val expressions = """(${ - items.joinToString( - separator = " ${operator.toInlineCondition()} ", transform = { - when (it) { - is Binary -> it.toScript(layout, variableStructure, findVar) - is Group -> it.toScript(layout, variableStructure, findVar) - } - }) - })""" - return if (negation) { - "not $expressions" - } else { - expressions - } -} - -fun Binary.toScript( - layout: Layout, variableStructure: VariableStructure, findVar: (String) -> Variable -): String { - val leftScriptResult = left.toScript(layout, variableStructure, findVar) - val rightScriptResult = right.toScript(layout, variableStructure, findVar) - - val binary = operator.toScript(leftScriptResult, rightScriptResult) - return if (leftScriptResult is Success && rightScriptResult is Success) { - binary - } else { - BinOp.Equals.toScript( - Success("String('${binary.replace("'", "")}')"), Success("String('unmapped')") - ) - } -} - -fun BinOp.toScript(left: ScriptResult, right: ScriptResult): String { - return when (this) { - BinOp.Equals -> "$left==$right" - BinOp.EqualsCaseInsensitive -> "$left.equalCaseInsensitive($right)" - BinOp.NotEquals -> "$left!=$right" - BinOp.NotEqualsCaseInsensitive -> "(not $left.equalCaseInsensitive($right))" - BinOp.GreaterThan -> "$left>$right" - BinOp.GreaterOrEqualThan -> "$left>=$right" - BinOp.LessThan -> "$left<$right" - BinOp.LessOrEqualThen -> "$left<=$right" - } -} - -fun LiteralOrFunctionCall.toScript( - layout: Layout, variableStructure: VariableStructure, findVar: (String) -> Variable -): ScriptResult { - return when (this) { - is Literal -> this.toScript(layout, variableStructure, findVar) - is Function -> this.toScript(layout, variableStructure, findVar) - } -} - -fun Function.toScript( - layout: Layout, variableStructure: VariableStructure, findVar: (String) -> Variable -): ScriptResult { - when (this) { - is Function.UpperCase -> { - val arg = args[0] - return Success("(${arg.toScript(layout, variableStructure, findVar)}).toUpperCase()") - } - - is Function.LowerCase -> { - val arg = args[0] - return Success("(${arg.toScript(layout, variableStructure, findVar)}).toLowerCase()") - } - } -} - -fun Literal.toScript( - layout: Layout, variableStructure: VariableStructure, findVar: (String) -> Variable -): ScriptResult { - return when (dataType) { - LiteralDataType.Variable -> variableToScript(value, layout, variableStructure, findVar) - LiteralDataType.String -> Success( - "String('${ - value.replace("\\", "\\\\").replace("\"", "\\\"") - }')" - ) - - LiteralDataType.Number -> Success(value) - LiteralDataType.Boolean -> Success(value.lowercase().toBooleanStrict().toString()) - } -} - -fun variableToScript( - id: String, layout: Layout, variableStructure: VariableStructure, findVar: (String) -> Variable -): ScriptResult { - val variableModel = findVar(id) - val variablePathData = variableStructure.structure[id] - return if (variablePathData == null || variablePathData.path.isBlank()) { - Failure(variablePathData?.name ?: variableModel.nameOrId()) - } else { - val variableName = variablePathData.name ?: variableModel.nameOrId() - - getOrCreateVariable(layout.data, variableName, variableModel, variablePathData.path) - - Success((variablePathData.path.split(".") + variableName).joinToString(".") { pathPart -> - when (pathPart.lowercase()) { - "value" -> "Current" - "data" -> "DATA" - else -> sanitizeVariablePart(if (pathPart.first().isDigit()) "_$pathPart" else pathPart) - } - }) - } -} - -fun getOrCreateVariable( - data: Data, variableName: String, variableModel: Variable, variablePath: String -): WfdXmlVariable { - val variable = getVariable(data as DataImpl, variableName, variablePath) - return variable ?: data.addVariable().setName(variableName).setKind(VariableKind.DISCONNECTED) - .setDataType(getDataType(variableModel.dataType)).setExistingParentId(variablePath) - .setValueIfAvailable(variableModel) -} - -fun WfdXmlVariable.setValueIfAvailable(variableModel: Variable): WfdXmlVariable { - val defaultVal = variableModel.defaultValue - if (!defaultVal.isNullOrBlank()) { - when (variableModel.dataType) { - DataTypeModel.String, DataTypeModel.DateTime -> this.setValue(defaultVal) - DataTypeModel.Integer -> this.setValue(defaultVal.toInt()) - DataTypeModel.Integer64 -> this.setValue(defaultVal.toLong()) - DataTypeModel.Double, DataTypeModel.Currency -> this.setValue(defaultVal.toDouble()) - DataTypeModel.Boolean -> this.setValue( - defaultVal.lowercase().toBooleanStrict() - ) - } - } - - return this +package com.quadient.migration.service.inspirebuilder + +import com.quadient.migration.api.ProjectConfig +import com.quadient.migration.api.dto.migrationmodel.Area +import com.quadient.migration.api.dto.migrationmodel.CustomFieldMap +import com.quadient.migration.api.dto.migrationmodel.DisplayRule +import com.quadient.migration.api.dto.migrationmodel.DisplayRuleRef +import com.quadient.migration.api.dto.migrationmodel.DocumentContent +import com.quadient.migration.api.dto.migrationmodel.DocumentObject +import com.quadient.migration.api.dto.migrationmodel.DocumentObjectRef +import com.quadient.migration.api.dto.migrationmodel.File +import com.quadient.migration.api.dto.migrationmodel.FileRef +import com.quadient.migration.api.dto.migrationmodel.FirstMatch +import com.quadient.migration.api.dto.migrationmodel.Hyperlink +import com.quadient.migration.api.dto.migrationmodel.Image +import com.quadient.migration.api.dto.migrationmodel.ImageRef +import com.quadient.migration.api.dto.migrationmodel.Paragraph +import com.quadient.migration.api.dto.migrationmodel.Paragraph.Text +import com.quadient.migration.api.dto.migrationmodel.ParagraphStyleDefinition +import com.quadient.migration.api.dto.migrationmodel.ParagraphStyleRef +import com.quadient.migration.api.dto.migrationmodel.SelectByLanguage +import com.quadient.migration.api.dto.migrationmodel.StringValue +import com.quadient.migration.api.dto.migrationmodel.Table as TableDTO +import com.quadient.migration.api.dto.migrationmodel.TextStyleDefinition +import com.quadient.migration.api.dto.migrationmodel.TextStyleRef +import com.quadient.migration.api.dto.migrationmodel.Variable +import com.quadient.migration.api.dto.migrationmodel.VariableRef +import com.quadient.migration.api.dto.migrationmodel.VariableStructure +import com.quadient.migration.api.repository.DocumentObjectRepository +import com.quadient.migration.api.repository.ParagraphStyleRepository +import com.quadient.migration.api.repository.Repository +import com.quadient.migration.api.repository.TextStyleRepository +import com.quadient.migration.service.inspirebuilder.InspireDocumentObjectBuilder.FlowModel.* +import com.quadient.migration.service.inspirebuilder.InspireDocumentObjectBuilder.ScriptResult +import com.quadient.migration.service.inspirebuilder.InspireDocumentObjectBuilder.ScriptResult.* +import com.quadient.migration.service.ipsclient.IpsService +import com.quadient.migration.shared.Alignment +import com.quadient.migration.shared.BinOp +import com.quadient.migration.shared.Binary +import com.quadient.migration.shared.DisplayRuleDefinition +import com.quadient.migration.shared.DocumentObjectType +import com.quadient.migration.shared.FileType +import com.quadient.migration.shared.Function +import com.quadient.migration.shared.Group +import com.quadient.migration.shared.IcmPath +import com.quadient.migration.shared.ImageType +import com.quadient.migration.shared.LineSpacing +import com.quadient.migration.shared.Literal +import com.quadient.migration.shared.LiteralDataType +import com.quadient.migration.shared.LiteralOrFunctionCall +import com.quadient.migration.shared.ParagraphPdfTaggingRule as ParagraphPdfTaggingRuleModel +import com.quadient.migration.shared.SuperOrSubscript +import com.quadient.migration.shared.TabType +import com.quadient.wfdxml.WfdXmlBuilder +import com.quadient.wfdxml.api.layoutnodes.Flow +import com.quadient.wfdxml.api.layoutnodes.Font +import com.quadient.wfdxml.api.layoutnodes.Image as WfdXmlImage +import com.quadient.wfdxml.api.layoutnodes.LocationType +import com.quadient.wfdxml.api.layoutnodes.Pages +import com.quadient.wfdxml.api.layoutnodes.ParagraphStyle +import com.quadient.wfdxml.api.layoutnodes.ParagraphStyle.LineSpacingType.* +import com.quadient.wfdxml.api.layoutnodes.TabulatorType +import com.quadient.wfdxml.api.layoutnodes.data.Data +import com.quadient.wfdxml.api.layoutnodes.data.DataType +import com.quadient.wfdxml.api.layoutnodes.data.Variable as WfdXmlVariable +import com.quadient.wfdxml.api.layoutnodes.data.VariableKind +import com.quadient.wfdxml.api.layoutnodes.flow.Text as WfdXmlText +import com.quadient.wfdxml.api.layoutnodes.font.SubFont +import com.quadient.wfdxml.api.layoutnodes.tables.GeneralRowSet +import com.quadient.wfdxml.api.layoutnodes.tables.RowSet +import com.quadient.wfdxml.api.layoutnodes.tables.Table as WfdXmlTable +import com.quadient.migration.shared.TablePdfTaggingRule +import com.quadient.wfdxml.api.layoutnodes.ParagraphStyle.ParagraphPdfTaggingRule +import com.quadient.wfdxml.api.layoutnodes.TextStyle +import com.quadient.wfdxml.api.layoutnodes.TextStyleInheritFlag +import com.quadient.wfdxml.api.layoutnodes.TextStyleType +import com.quadient.wfdxml.api.layoutnodes.flow.Paragraph as WfdXmlParagraph +import com.quadient.wfdxml.api.module.Layout +import com.quadient.wfdxml.internal.data.WorkFlowTreeDefinition +import com.quadient.wfdxml.internal.layoutnodes.TextStyleImpl +import com.quadient.wfdxml.internal.layoutnodes.data.DataImpl +import com.quadient.wfdxml.internal.layoutnodes.data.WorkFlowTreeEnums.NodeOptionality +import com.quadient.wfdxml.internal.layoutnodes.data.WorkFlowTreeEnums.NodeType.SUB_TREE +import kotlinx.datetime.Clock +import org.slf4j.LoggerFactory +import java.util.concurrent.ConcurrentHashMap +import kotlin.collections.ifEmpty +import com.quadient.migration.shared.DataType as DataTypeModel +import com.quadient.migration.api.dto.migrationmodel.ParagraphStyle as ParagraphStyleDTO +import com.quadient.migration.api.dto.migrationmodel.TextStyle as TextStyleDTO + +abstract class InspireDocumentObjectBuilder( + protected val documentObjectRepository: DocumentObjectRepository, + protected val textStyleRepository: TextStyleRepository, + protected val paragraphStyleRepository: ParagraphStyleRepository, + protected val variableRepository: Repository, + protected val variableStructureRepository: Repository, + protected val displayRuleRepository: Repository, + protected val imageRepository: Repository, + protected val fileRepository: Repository, + protected val projectConfig: ProjectConfig, + protected val ipsService: IpsService, +) { + protected val logger = LoggerFactory.getLogger(this::class.java)!! + + protected val fontDataCache = ConcurrentHashMap() + + abstract fun getDocumentObjectPath(nameOrId: String, type: DocumentObjectType, targetFolder: IcmPath?): String + + abstract fun getDocumentObjectPath(documentObject: DocumentObject): String + + abstract fun getImagePath( + id: String, imageType: ImageType, name: String?, targetFolder: IcmPath?, sourcePath: String? + ): String + + abstract fun getImagePath(image: Image): String + + abstract fun getFilePath( + id: String, name: String?, targetFolder: IcmPath?, sourcePath: String?, fileType: FileType + ): String + + abstract fun getFilePath(file: File): String + + abstract fun getStyleDefinitionPath(extension: String = "wfd"): String + + abstract fun getFontRootFolder(): String + + abstract fun buildDocumentObject(documentObject: DocumentObject, styleDefinitionPath: String?): String + + abstract fun shouldIncludeInternalDependency(documentObject: DocumentObject): Boolean + + protected fun collectLanguages(documentObject: DocumentObject): List { + val languages = mutableSetOf() + + fun collectLanguagesFromContent(content: List) { + for (item in content) { + when (item) { + is SelectByLanguage -> item.cases.forEach { languages.add(it.language) } + is Area -> collectLanguagesFromContent(item.content) + is FirstMatch -> { + item.cases.forEach { case -> collectLanguagesFromContent(case.content) } + collectLanguagesFromContent(item.default) + } + + is TableDTO -> item.rows.forEach { row -> + row.cells.forEach { cell -> collectLanguagesFromContent(cell.content) } + } + + is DocumentObjectRef -> { + val documentObject = documentObjectRepository.findOrFail(item.id) + if (shouldIncludeInternalDependency(documentObject)) { + collectLanguagesFromContent(documentObject.content) + } + } + + is Paragraph -> item.content.forEach { textModel -> + textModel.content.forEach { textContent -> + when (textContent) { + is FirstMatch -> { + textContent.cases.forEach { case -> collectLanguagesFromContent(case.content) } + collectLanguagesFromContent(textContent.default) + } + + is TableDTO -> textContent.rows.forEach { row -> + row.cells.forEach { cell -> collectLanguagesFromContent(cell.content) } + } + + is DocumentObjectRef -> { + val documentObject = documentObjectRepository.findOrFail(textContent.id) + if (shouldIncludeInternalDependency(documentObject)) { + collectLanguagesFromContent(documentObject.content) + } + } + + else -> {} + } + } + } + + else -> {} + } + } + } + + collectLanguagesFromContent(documentObject.content) + + return languages.toList() + } + + protected open fun wrapSuccessFlowInConditionFlow( + layout: Layout, variableStructure: VariableStructure, ruleDef: DisplayRuleDefinition, successFlow: Flow + ): Flow { + return layout.addFlow().setType(Flow.Type.SELECT_BY_CONDITION).addLineForSelectByCondition( + layout.data.addVariable().setKind(VariableKind.CALCULATED).setDataType(DataType.BOOL) + .setScript(ruleDef.toScript(layout, variableStructure, variableRepository::findOrFail)), + successFlow + ) + } + + protected open fun buildSuccessRowWrappedInConditionRow( + layout: Layout, + variableStructure: VariableStructure, + ruleDef: DisplayRuleDefinition, + multipleRowSet: GeneralRowSet + ): GeneralRowSet { + val successRow = layout.addRowSet().setType(RowSet.Type.SINGLE_ROW) + + multipleRowSet.addRowSet( + layout.addRowSet().setType(RowSet.Type.SELECT_BY_CONDITION).addLineForSelectByCondition( + layout.data.addVariable().setKind(VariableKind.CALCULATED).setDataType(DataType.BOOL) + .setScript(ruleDef.toScript(layout, variableStructure, variableRepository::findOrFail)), + successRow + ) + ) + + return successRow + } + + fun buildStyleLayoutDelta(textStyles: List, paragraphStyles: List): String { + logger.debug("Starting to build style layout delta.") + + val builder = WfdXmlBuilder() + val layout = builder.addLayout() + + if (fontDataCache.isEmpty()) { + val fontDataString = ipsService.gatherFontData(getFontRootFolder()) + fontDataCache.putAll(fontDataStringToMap(fontDataString)) + } + + buildTextStyles(layout, textStyles) + buildParagraphStyles(layout, paragraphStyles) + + logger.debug("Successfully built style layout delta.") + return builder.buildStyleLayoutDelta() + } + + fun buildStyles( + textStyles: List, + paragraphStyles: List, + ): String { + logger.debug("Starting to build style definition.") + + val builder = WfdXmlBuilder() + val layout = builder.addLayout() + + layout.setName("DocumentLayout") + val flow = layout.addFlow().setSectionFlow(true).setWebEditingType(Flow.WebEditingType.SECTION) + layout.pages.setMainFlow(flow) + layout.addPage().setName("Page 1").setType(Pages.PageConditionType.SIMPLE) + layout.addRoot().setAllowRuntimeModifications(true) + + if (fontDataCache.isEmpty()) { + val fontDataString = ipsService.gatherFontData(getFontRootFolder()) + fontDataCache.putAll(fontDataStringToMap(fontDataString)) + } + + buildTextStyles(layout, textStyles) + buildParagraphStyles(layout, paragraphStyles) + + logger.debug("Successfully built style definition.") + return builder.build() + } + + fun buildDocumentContentAsFlows( + layout: Layout, + variableStructure: VariableStructure, + content: List, + flowName: String? = null, + languages: List, + ): List { + val mutableContent = content.toMutableList() + + var idx = 0 + val flowModels = mutableListOf() + while (idx < mutableContent.size) { + when (val contentPart = mutableContent[idx]) { + is TableDTO, is Paragraph, is ImageRef -> { + val flowParts = gatherFlowParts(mutableContent, idx) + idx += flowParts.size - 1 + flowModels.add(Composite(flowParts)) + } + + is DocumentObjectRef -> flowModels.add(DocumentObject(contentPart)) + is FileRef -> flowModels.add(File(contentPart)) + is Area -> mutableContent.addAll(idx + 1, contentPart.content) + is FirstMatch -> flowModels.add(FirstMatch(contentPart)) + is SelectByLanguage -> flowModels.add(SelectByLanguage(contentPart)) + } + idx++ + } + + val flowCount = flowModels.size + var flowSuffix = 1 + return flowModels.mapNotNull { + when (it) { + is FlowModel.DocumentObject -> buildDocumentObjectRef(layout, variableStructure, it.ref, languages) + is FlowModel.File -> buildFileRef(layout, it.ref) + is FlowModel.Composite -> { + if (flowName == null) { + buildCompositeFlow(layout, variableStructure, it.parts, null, languages) + } else { + val name = if (flowCount == 1) flowName else "$flowName $flowSuffix" + flowSuffix++ + buildCompositeFlow(layout, variableStructure, it.parts, name, languages) + } + } + + is FlowModel.FirstMatch -> { + if (flowName == null) { + buildFirstMatch(layout, variableStructure, it.model, false, null, languages) + } else { + val name = if (flowCount == 1) flowName else "$flowName $flowSuffix" + flowSuffix++ + buildFirstMatch(layout, variableStructure, it.model, false, name, languages) + } + } + + is FlowModel.SelectByLanguage -> { + if (flowName == null) { + buildSelectByLanguage(layout, variableStructure, it.model, null, languages) + } else { + val name = if (flowCount == 1) flowName else "$flowName $flowSuffix" + flowSuffix++ + buildSelectByLanguage(layout, variableStructure, it.model, name, languages) + } + } + } + } + } + + sealed interface FlowModel { + data class Composite(val parts: List) : FlowModel + data class DocumentObject(val ref: DocumentObjectRef) : FlowModel + data class File(val ref: FileRef) : FlowModel + data class FirstMatch(val model: com.quadient.migration.api.dto.migrationmodel.FirstMatch) : FlowModel + data class SelectByLanguage(val model: com.quadient.migration.api.dto.migrationmodel.SelectByLanguage) : FlowModel + } + + protected fun List.toSingleFlow( + layout: Layout, + variableStructure: VariableStructure, + flowName: String? = null, + displayRuleRef: DisplayRuleRef? = null, + ): Flow { + val singleFlow = if (this.size == 1) { + this[0] + } else { + val sectionFlow = layout.addFlow().setType(Flow.Type.SIMPLE).setSectionFlow(true) + flowName?.let { sectionFlow.setName(it) } + + val sectionFlowText = sectionFlow.addParagraph().addText() + + this.forEach { sectionFlowText.appendFlow(it) } + + sectionFlow + } + + return if (displayRuleRef == null) { + singleFlow + } else { + val displayRule = displayRuleRepository.findOrFail(displayRuleRef.id) + val def = displayRule.definition + if (def == null) { + error("Display rule '${displayRuleRef.id}' definition is null.") + } + + wrapSuccessFlowInConditionFlow(layout, variableStructure, def, singleFlow) + } + } + + protected fun buildDocumentContentAsSingleFlow( + layout: Layout, + variableStructure: VariableStructure, + content: List, + flowName: String? = null, + displayRuleRef: DisplayRuleRef? = null, + languages: List, + ): Flow { + return buildDocumentContentAsFlows(layout, variableStructure, content, flowName, languages).toSingleFlow( + layout, variableStructure, flowName, displayRuleRef + ) + } + + protected fun initVariableStructure(layout: Layout, documentObject: DocumentObject): VariableStructure { + val variableStructureId = documentObject.variableStructureRef?.id ?: projectConfig.defaultVariableStructure + + val variableStructureModel = + variableStructureId?.let { variableStructureRepository.findOrFail(it) } ?: VariableStructure( + id = "defaultVariableStructure", + lastUpdated = Clock.System.now(), + created = Clock.System.now(), + structure = mutableMapOf(), + customFields = CustomFieldMap(), + languageVariable = null, + ) + + val normalizedVariablePaths = variableStructureModel.structure.map { (_, variablePathData) -> + removeDataFromVariablePath(variablePathData.path) + }.filter { it.isNotBlank() } + + val variableTree = buildVariableTree(normalizedVariablePaths) + + val workflowTreeDefinition = WorkFlowTreeDefinition("Root", SUB_TREE, NodeOptionality.ARRAY).also { + buildVariablePathPart(it, variableTree) + } + + val layoutData = layout.data + layoutData.importDataDefinition(workflowTreeDefinition) + if (variableTree.isNotEmpty() && variableTree.values.first() is ArrayVariable) { + layoutData.setRepeatedBy("Data.${variableTree.keys.first()}") + } + + return variableStructureModel + } + + private fun buildVariablePathPart( + parentNode: WorkFlowTreeDefinition, currentMap: Map + ) { + currentMap.forEach { + val variablePathPart = it.value + val optionality = + if (variablePathPart is ArrayVariable) NodeOptionality.ARRAY else NodeOptionality.MUST_EXIST + + val node = WorkFlowTreeDefinition(variablePathPart.name, SUB_TREE, optionality) + parentNode.addSubNode(node) + + if (variablePathPart.children.isNotEmpty()) { + buildVariablePathPart(node, variablePathPart.children) + } + } + } + + private fun upsertSubFont(font: Font, isBold: Boolean, isItalic: Boolean): SubFont? { + val subFontName = buildFontName(isBold, isItalic) + + val fontLocation = fontDataCache[FontKey(font.name, subFontName)] + ?: fontDataCache[FontKey(font.name, buildFontName(bold = false, italic = false))] + ?: return null + + font.subFonts.removeAll { it.name == subFontName } + return font.addSubfont().setName(subFontName).setBold(isBold).setItalic(isItalic) + .setLocation(fontLocation, LocationType.ICM) + } + + fun buildTextStyles(layout: Layout, textStyleModels: List) { + val arialFont = getFontByName(layout, "Arial") + require(arialFont != null) { "Layout must contain Arial font." } + arialFont.setName("Arial").setFontName("Arial") + upsertSubFont(arialFont, isBold = false, isItalic = false) + + textStyleModels.forEach { styleModel -> + val definition = styleModel.resolve() + val textStyle = layout.addTextStyle().setName(styleModel.nameOrId()) + applyTextStyleProperties(layout, textStyle, definition) + } + } + + private fun applyTextStyleProperties(layout: Layout, textStyle: TextStyle, definition: TextStyleDefinition) { + val fontFamily = definition.fontFamily ?: "Arial" + + val font = getFontByName(layout, fontFamily) ?: layout.addFont().setName(fontFamily).setFontName(fontFamily) + textStyle.setFont(font) + + val subFont = upsertSubFont(font, definition.bold, definition.italic) + if (subFont != null) { + textStyle.setSubFont(subFont) + } + + textStyle.setBold(definition.bold) + textStyle.seItalic(definition.italic) + textStyle.setUnderline(definition.underline) + textStyle.setStrikeThrough(definition.strikethrough) + + definition.size?.let { textStyle.setFontSizeInMeters(it.toMeters()) } + definition.interspacing?.let { textStyle.setInterSpacing(it.toMeters()) } + + when (definition.superOrSubscript) { + SuperOrSubscript.Subscript -> textStyle.setSubScript(true).setSuperScript(false) + SuperOrSubscript.Superscript -> textStyle.setSubScript(false).setSuperScript(true) + SuperOrSubscript.None -> textStyle.setSubScript(false).setSuperScript(false) + } + + definition.foregroundColor?.let { colorModel -> + val layoutColor = getColorByRGB(layout, colorModel.red(), colorModel.green(), colorModel.blue()) + ?: layout.addColor().setRGB(colorModel.red(), colorModel.green(), colorModel.blue()) + val fillStyle = getFillStyleByColor(layout, layoutColor) + ?: layout.addFillStyle().setColor(layoutColor) + textStyle.setFillStyle(fillStyle) + } + } + + fun buildParagraphStyles(layout: Layout, paragraphStyleModels: List) { + paragraphStyleModels.forEach { styleModel -> + val definition = styleModel.resolve() + + val paragraphStyle = layout.addParagraphStyle().setName(styleModel.nameOrId()) + + definition.leftIndent?.let { paragraphStyle.setLeftIndent(it.toMeters()) } + definition.rightIndent?.let { paragraphStyle.setRightIndent(it.toMeters()) } + definition.defaultTabSize?.let { paragraphStyle.setDefaultTabSize(it.toMeters()) } + definition.spaceBefore?.let { paragraphStyle.setSpaceBefore(it.toMeters()) } + definition.spaceAfter?.let { paragraphStyle.setSpaceAfter(it.toMeters()) } + val alignType = when (definition.alignment) { + Alignment.Left -> ParagraphStyle.AlignType.LEFT + Alignment.Right -> ParagraphStyle.AlignType.RIGHT + Alignment.Center -> ParagraphStyle.AlignType.CENTER + Alignment.JustifyLeft -> ParagraphStyle.AlignType.JUSTIFY_lEFT + Alignment.JustifyRight -> ParagraphStyle.AlignType.JUSTIFY_RIGHT + Alignment.JustifyCenter -> ParagraphStyle.AlignType.JUSTIFY_CENTER + Alignment.JustifyBlock -> ParagraphStyle.AlignType.JUSTIFY_BLOCK + Alignment.JustifyWithMargins -> ParagraphStyle.AlignType.JUSTIFY_WITH_MARGIN + Alignment.JustifyBlockUniform -> ParagraphStyle.AlignType.JUSTIFY_BLOCK_UNIFORM + } + paragraphStyle.setAlignType(alignType) + + definition.firstLineIndent?.let { paragraphStyle.setFirstLineLeftIndent(it.toMeters()) } + + val lineSpacing = definition.lineSpacing + val (lineSpacingType, lineSpacingValue) = when (lineSpacing) { + is LineSpacing.Additional -> Pair(ADDITIONAL, lineSpacing.size?.toMeters()) + is LineSpacing.AtLeast -> Pair(AT_LEAST, lineSpacing.size?.toMeters()) + is LineSpacing.Exact -> Pair(EXACT, lineSpacing.size?.toMeters()) + is LineSpacing.ExactFromPrevious -> Pair(EXACT_FROM_PREVIOUS, lineSpacing.size?.toMeters()) + is LineSpacing.ExactFromPreviousWithAdjust -> Pair( + EXACT_FROM_PREVIOUS_WITH_ADJUST, lineSpacing.size?.toMeters() + ) + + is LineSpacing.ExactFromPreviousWithAdjustLegacy -> Pair( + EXACT_FROM_PREVIOUS_WITH_ADJUST_OLD, lineSpacing.size?.toMeters() + ) + + is LineSpacing.MultipleOf -> Pair(MULTIPLE_OF, lineSpacing.value) + } + paragraphStyle.setLineSpacingType(lineSpacingType) + lineSpacingValue?.let { paragraphStyle.setLineSpacingValue(it) } + + definition.tabs?.let { tabsModel -> + paragraphStyle.setUseOutsideTabs(tabsModel.useOutsideTabs) + tabsModel.tabs.forEach { tabModel -> + val tabType = when (tabModel.type) { + TabType.Left -> TabulatorType.LEFT + TabType.Right -> TabulatorType.RIGHT + TabType.Center -> TabulatorType.CENTER + TabType.DecimalWord -> TabulatorType.WORD_DECIMAL + TabType.Decimal -> TabulatorType.DECIMAL + } + + paragraphStyle.addTabulator(tabModel.position.toMeters(), tabType) + } + } + + definition.pdfTaggingRule?.let { pdfTaggingRule -> + val rule = when (pdfTaggingRule) { + ParagraphPdfTaggingRuleModel.Paragraph -> ParagraphPdfTaggingRule.PARAGRAPH + ParagraphPdfTaggingRuleModel.Heading -> ParagraphPdfTaggingRule.HEADING + ParagraphPdfTaggingRuleModel.Heading1 -> ParagraphPdfTaggingRule.HEADING_1 + ParagraphPdfTaggingRuleModel.Heading2 -> ParagraphPdfTaggingRule.HEADING_2 + ParagraphPdfTaggingRuleModel.Heading3 -> ParagraphPdfTaggingRule.HEADING_3 + ParagraphPdfTaggingRuleModel.Heading4 -> ParagraphPdfTaggingRule.HEADING_4 + ParagraphPdfTaggingRuleModel.Heading5 -> ParagraphPdfTaggingRule.HEADING_5 + ParagraphPdfTaggingRuleModel.Heading6 -> ParagraphPdfTaggingRule.HEADING_6 + } + paragraphStyle.setPdfTaggingRule(rule) + } + } + } + + sealed interface ImagePlaceholderResult { + object RenderAsNormal : ImagePlaceholderResult + object Skip : ImagePlaceholderResult + data class Placeholder(val value: String) : ImagePlaceholderResult + } + protected fun getImagePlaceholder(imageModel: Image): ImagePlaceholderResult { + if (imageModel.imageType == ImageType.Unknown && !imageModel.skip.skipped) { + throw IllegalStateException( + "Image '${imageModel.nameOrId()}' has unknown type and is not set to be skipped." + ) + } + if (imageModel.sourcePath.isNullOrBlank() && !imageModel.skip.skipped) { + throw IllegalStateException( + "Image '${imageModel.nameOrId()}' has missing source path and is not set to be skipped." + ) + } + + if (imageModel.skip.skipped && imageModel.skip.placeholder != null) { + return ImagePlaceholderResult.Placeholder(imageModel.skip.placeholder) + } else if (imageModel.skip.skipped) { + return ImagePlaceholderResult.Skip + } + + return ImagePlaceholderResult.RenderAsNormal + } + + protected fun getOrBuildImage(layout: Layout, imageModel: Image, alternateText: String? = null): WfdXmlImage { + val image = getImageByName(layout, imageModel.nameOrId()) ?: layout.addImage().setName(imageModel.nameOrId()) + .setImageLocation(getImagePath(imageModel), LocationType.ICM) + + val options = imageModel.options + if (options != null) { + options.resizeWidth?.let { image.setResizeWidth(it.toMeters()) } + options.resizeHeight?.let { image.setResizeHeight(it.toMeters()) } + } + + if (!alternateText.isNullOrBlank()) { + applyImageAlternateText(layout, image, alternateText) + } + + return image + } + + protected abstract fun applyImageAlternateText(layout: Layout, image: WfdXmlImage, alternateText: String) + + private fun buildFileRef( + layout: Layout, + fileRef: FileRef, + ): Flow? { + val fileModel = fileRepository.findOrFail(fileRef.id) + + if (fileModel.skip.skipped && fileModel.skip.placeholder == null) { + val reason = fileModel.skip.reason?.let { "with reason: $it" } ?: "without reason" + logger.debug("File ${fileRef.id} is set to be skipped without placeholder $reason.") + return null + } else if (fileModel.skip.skipped && fileModel.skip.placeholder != null) { + val reason = fileModel.skip.reason?.let { "and reason: $it" } ?: "without reason" + logger.debug("File ${fileRef.id} is set to be skipped with placeholder $reason.") + val flow = layout.addFlow().setType(Flow.Type.SIMPLE) + flow.addParagraph().addText().appendText(fileModel.skip.placeholder) + return flow + } + + if (fileModel.sourcePath.isNullOrBlank()) { + throw IllegalStateException( + "File '${fileModel.nameOrId()}' has missing source path and is not set to be skipped." + ) + } + + val flow = getFlowByName(layout, fileModel.nameOrId()) ?: run { + layout.addFlow() + .setName(fileModel.nameOrId()) + .setType(Flow.Type.DIRECT_EXTERNAL) + .setLocation(getFilePath(fileModel)) + } + + return flow + } + + private fun buildCompositeFlow( + layout: Layout, + variableStructure: VariableStructure, + documentContentModelParts: List, + flowName: String? = null, + languages: List + ): Flow { + val flow = layout.addFlow().setType(Flow.Type.SIMPLE) + flowName?.let { flow.setName(it) } + + documentContentModelParts.forEach { + when (it) { + is Paragraph -> buildParagraph(layout, variableStructure, flow, it, languages) + is TableDTO -> flow.addParagraph().addText() + .appendTable(buildTable(layout, variableStructure, it, languages)) + + is ImageRef -> buildAndAppendImage(layout, flow.addParagraph().addText(), it) + else -> error("Content part type ${it::class.simpleName} is not allowed in composite flow.") + } + } + + return flow + } + + private fun buildDocumentObjectRef( + layout: Layout, + variableStructure: VariableStructure, + documentObjectRef: DocumentObjectRef, + languages: List, + ): Flow? { + val documentModel = documentObjectRepository.findOrFail(documentObjectRef.id) + + if (documentModel.skip.skipped && documentModel.skip.placeholder == null) { + val reason = documentModel.skip.reason?.let { "with reason: $it" } ?: "without reason" + logger.debug("Document content part ${documentObjectRef.id} is set to be skipped without placeholder $reason.") + return null + } else if (documentModel.skip.skipped && documentModel.skip.placeholder != null) { + val reason = documentModel.skip.reason?.let { "and reason: $it" } ?: "without reason" + logger.debug("Document content part ${documentObjectRef.id} is set to be skipped with placeholder $reason.") + val flow = layout.addFlow().setType(Flow.Type.SIMPLE) + flow.addParagraph().addText().appendText(documentModel.skip.placeholder) + return flow + } + + val flow = getFlowByName(layout, documentModel.nameOrId()) ?: if (documentModel.internal == true) { + buildDocumentContentAsSingleFlow( + layout, + variableStructure, + documentModel.content, + documentModel.nameOrId(), + documentModel.displayRuleRef?.let { DisplayRuleRef(it.id) }, + languages + ) + } else { + layout.addFlow().setName(documentModel.nameOrId()).setType(Flow.Type.DIRECT_EXTERNAL) + .setLocation(getDocumentObjectPath(documentModel)) + } + + if (documentObjectRef.displayRuleRef != null) { + val displayRule = displayRuleRepository.findOrFail(documentObjectRef.displayRuleRef.id) + val def = displayRule.definition + if (def == null) { + error("Display rule '${documentObjectRef.displayRuleRef.id}' definition is null.") + } + + return wrapSuccessFlowInConditionFlow(layout, variableStructure, def, flow) + } + + return flow + } + + private fun gatherFlowParts(content: List, startIndex: Int): List { + val flowParts = mutableListOf() + + var index = startIndex + + do { + val contentPart = content[index] + if (contentPart is TableDTO || contentPart is Paragraph || contentPart is ImageRef) { + flowParts.add(contentPart) + index++ + } else { + break + } + } while (index < content.size) + + return flowParts + } + + private fun buildParagraph( + layout: Layout, + variableStructure: VariableStructure, + flow: Flow, + paragraphModel: Paragraph, + languages: List + ) { + val paragraph = if (paragraphModel.displayRuleRef == null) { + flow.addParagraph() + } else { + buildSuccessFlowWrappedInInlineConditionFlow( + layout, variableStructure, paragraphModel.displayRuleRef.id, flow.addParagraph().addText() + ).addParagraph() + } + + val paragraphStyle = findParagraphStyle(paragraphModel)?.also { + paragraph.setExistingParagraphStyle("ParagraphStyles.${it.nameOrId()}") + } + + paragraphModel.content.forEach { textModel -> + val baseText = if (textModel.displayRuleRef == null) { + paragraph.addText() + } else { + buildSuccessFlowWrappedInInlineConditionFlow( + layout, variableStructure, textModel.displayRuleRef.id, paragraph.addText() + ).addParagraph().also { + if (paragraphStyle != null) it.setExistingParagraphStyle("ParagraphStyles.${paragraphStyle.nameOrId()}") + }.addText() + } + + val baseTextStyleModel = findTextStyle(textModel) + baseTextStyleModel?.also { baseText.setExistingTextStyle("TextStyles.${it.nameOrId()}") } + + var currentText = baseText + + textModel.content.forEach { + when (it) { + is StringValue -> currentText.appendText(it.value) + is VariableRef -> currentText.appendVariable(it, layout, variableStructure) + is TableDTO -> currentText.appendTable(buildTable(layout, variableStructure, it, languages)) + is DocumentObjectRef -> buildDocumentObjectRef( + layout, variableStructure, it, languages + )?.also { flow -> + currentText.appendFlow(flow) + } + + is FileRef -> buildFileRef(layout, it)?.also { flow -> + currentText.appendFlow(flow) + } + + is ImageRef -> buildAndAppendImage(layout, currentText, it) + is Hyperlink -> currentText = buildAndAppendHyperlink(layout, paragraph, baseTextStyleModel, it) + is FirstMatch -> currentText.appendFlow( + buildFirstMatch(layout, variableStructure, it, true, null, languages) + ) + } + } + } + } + + private fun createHyperlinkTextStyle( + layout: Layout, baseTextStyleModel: TextStyleDTO?, hyperlinkModel: Hyperlink + ): TextStyle { + val baseStyleName = baseTextStyleModel?.nameOrId() ?: "text" + val hyperlinkName = generateUniqueHyperlinkStyleName(layout, baseStyleName) + + val urlVariable = createUrlVariable(layout, hyperlinkName, hyperlinkModel.url) + + val hyperlinkStyle = layout.addTextStyle() + .setName(hyperlinkName) + .setUrlTarget(urlVariable) + .setType(TextStyleType.DELTA) + .setUrlAlternateText(hyperlinkModel.alternateText) + .addInheritFlags( + *TextStyleInheritFlag.entries + .filter { it != TextStyleInheritFlag.UNDERLINE && it != TextStyleInheritFlag.FILL_STYLE } + .toTypedArray()) + (hyperlinkStyle as TextStyleImpl).ancestorId = "Def.TextStyleHyperlink" + + if (baseTextStyleModel != null) { + val definition = baseTextStyleModel.resolve() + applyTextStyleProperties(layout, hyperlinkStyle, definition) + } + + return hyperlinkStyle + } + + private fun generateUniqueHyperlinkStyleName(layout: Layout, baseStyleName: String): String { + var counter = 1 + var candidateName = "${baseStyleName}_url_${counter}" + while (getTextStyleByName(layout, candidateName) != null) { + counter++ + candidateName = "${baseStyleName}_url_${counter}" + } + return candidateName + } + + private fun createUrlVariable(layout: Layout, variableName: String, url: String): WfdXmlVariable { + return layout.data.addVariable().setName(variableName).setKind(VariableKind.CONSTANT) + .setDataType(DataType.STRING).setValue(url) + } + + private fun buildAndAppendImage(layout: Layout, text: WfdXmlText, ref: ImageRef) { + val imageModel = imageRepository.findOrFail(ref.id) + + when (val imagePlaceholder = getImagePlaceholder(imageModel)) { + is ImagePlaceholderResult.Placeholder -> { + text.appendText(imagePlaceholder.value) + return + } + is ImagePlaceholderResult.RenderAsNormal -> {} + is ImagePlaceholderResult.Skip -> return + } + + text.appendImage(getOrBuildImage(layout, imageModel, imageModel.alternateText)) + } + + private fun buildAndAppendHyperlink( + layout: Layout, paragraph: WfdXmlParagraph, baseTextStyleModel: TextStyleDTO?, hyperlinkModel: Hyperlink + ): WfdXmlText { + val hyperlinkText = paragraph.addText() + val hyperlinkStyle = createHyperlinkTextStyle(layout, baseTextStyleModel, hyperlinkModel) + hyperlinkText.setTextStyle(hyperlinkStyle) + hyperlinkText.appendText(hyperlinkModel.displayText ?: hyperlinkModel.url) + + val newText = paragraph.addText() + baseTextStyleModel?.also { newText.setExistingTextStyle("TextStyles.${it.nameOrId()}") } + return newText + } + + private fun WfdXmlText.appendVariable( + ref: VariableRef, layout: Layout, variableStructure: VariableStructure + ): WfdXmlText { + val variableModel = variableRepository.findOrFail(ref.id) + + val variablePathData = variableStructure.structure[ref.id] + if (variablePathData == null || variablePathData.path.isBlank()) { + this.appendText("""$${variablePathData?.name ?: variableModel.nameOrId()}$""") + } else { + val variableName = variablePathData.name ?: variableModel.nameOrId() + this.appendVariable(getOrCreateVariable(layout.data, variableName, variableModel, variablePathData.path)) + } + + return this + } + + private fun findParagraphStyle(paragraphModel: Paragraph): ParagraphStyleDTO? { + if (paragraphModel.styleRef == null) return null + + val paraStyleModel = paragraphStyleRepository.firstWithDefinition(paragraphModel.styleRef.id) + ?: error("Paragraph style definition for ${paragraphModel.styleRef.id} not found.") + + return paraStyleModel + } + + private fun findTextStyle(textModel: Text): TextStyleDTO? { + if (textModel.styleRef == null) return null + + val textStyleModel = textStyleRepository.firstWithDefinition(textModel.styleRef.id) + ?: error("Text style definition for ${textModel.styleRef.id} not found.") + + return textStyleModel + } + + private fun buildSuccessFlowWrappedInInlineConditionFlow( + layout: Layout, variableStructure: VariableStructure, displayRuleId: String, text: WfdXmlText + ): Flow { + val displayRule = displayRuleRepository.findOrFail(displayRuleId) + if (displayRule.definition == null) { + error("Display rule '$displayRuleId' definition is null.") + } + + val successFlow = layout.addFlow().setType(Flow.Type.SIMPLE) + val def = displayRule.definition!! + + text.appendFlow( + layout.addFlow().setType(Flow.Type.SELECT_BY_INLINE_CONDITION).addLineForSelectByInlineCondition( + def.toScript(layout, variableStructure, variableRepository::findOrFail), + successFlow + ) + ) + + return successFlow + } + + private fun buildTable( + layout: Layout, variableStructure: VariableStructure, model: TableDTO, languages: List + ): WfdXmlTable { + val table = layout.addTable().setDisplayAsImage(false) + + if (model.columnWidths.isNotEmpty()) { + model.columnWidths.forEach { table.addColumn(it.minWidth.toMeters(), it.percentWidth) } + } else { + val numberOfColumns = model.rows.firstOrNull()?.cells?.size ?: 0 + repeat(numberOfColumns) { table.addColumn() } + } + + val rowset = layout.addRowSet().setType(RowSet.Type.MULTIPLE_ROWS) + table.setRowSet(rowset) + + model.rows.forEach { rowModel -> + val row = if (rowModel.displayRuleRef == null) { + layout.addRowSet().setType(RowSet.Type.SINGLE_ROW).also { rowset.addRowSet(it) } + } else { + val displayRule = displayRuleRepository.findOrFail(rowModel.displayRuleRef.id) + val def = displayRule.definition + if (def == null) { + error("Display rule '${rowModel.displayRuleRef.id}' definition is null.") + } + + buildSuccessRowWrappedInConditionRow( + layout, variableStructure, def, rowset + ) + } + + rowModel.cells.forEach { cellModel -> + val cellContentFlow = buildDocumentContentAsSingleFlow( + layout, variableStructure, cellModel.content, null, null, languages + ) + val cellFlow = if (cellContentFlow.type === Flow.Type.SELECT_BY_INLINE_CONDITION) { + layout.addFlow().setType(Flow.Type.SIMPLE).setSectionFlow(true) + .setWebEditingType(Flow.WebEditingType.SECTION) + .also { it.addParagraph().addText().appendFlow(cellContentFlow) } + } else cellContentFlow + + row.addCell( + layout.addCell().setSpanLeft(cellModel.mergeLeft).setSpanUp(cellModel.mergeUp) + .setFlowToNextPage(true).setFlow(cellFlow) + ) + } + } + + when (model.pdfTaggingRule) { + TablePdfTaggingRule.None -> table.setTablePdfTaggingRule(WfdXmlTable.TablePdfTaggingRule.NONE) + TablePdfTaggingRule.Default -> table.setTablePdfTaggingRule(WfdXmlTable.TablePdfTaggingRule.DEFAULT) + TablePdfTaggingRule.Table -> table.setTablePdfTaggingRule(WfdXmlTable.TablePdfTaggingRule.TABLE) + TablePdfTaggingRule.Artifact -> table.setTablePdfTaggingRule(WfdXmlTable.TablePdfTaggingRule.ARTIFACT) + } + table.setTablePdfAlternateText(model.pdfAlternateText) + + return table + } + + private fun buildFirstMatch( + layout: Layout, + variableStructure: VariableStructure, + model: FirstMatch, + isInline: Boolean, + flowName: String? = null, + languages: List, + ): Flow { + val firstMatchFlow = layout.addFlow().setType(Flow.Type.SELECT_BY_INLINE_CONDITION) + flowName?.let { firstMatchFlow.setName(it) } + + model.cases.forEachIndexed { i, case -> + val displayRule = displayRuleRepository.findOrFail(case.displayRuleRef.id) + if (displayRule.definition == null) { + error("Display rule '${case.displayRuleRef.id}' definition is null.") + } + + val caseName = case.name ?: "Case ${i + 1}" + + val contentFlow = + buildDocumentContentAsSingleFlow(layout, variableStructure, case.content, null, null, languages) + + val caseFlow = + if (isInline) contentFlow else layout.addFlow().setSectionFlow(true).setType(Flow.Type.SIMPLE) + .setWebEditingType(Flow.WebEditingType.SECTION).setDisplayName(caseName) + .also { it.addParagraph().addText().appendFlow(contentFlow) } + + val def = displayRule.definition!! + firstMatchFlow.addLineForSelectByInlineCondition( + def.toScript(layout, variableStructure, variableRepository::findOrFail), + caseFlow + ) + } + + if (model.default.isNotEmpty()) { + val contentFlow = + buildDocumentContentAsSingleFlow(layout, variableStructure, model.default, null, null, languages) + + val caseFlow = + if (isInline) contentFlow else layout.addFlow().setSectionFlow(true).setType(Flow.Type.SIMPLE) + .setWebEditingType(Flow.WebEditingType.SECTION).setDisplayName("Else Case") + .also { it.addParagraph().addText().appendFlow(contentFlow) } + + firstMatchFlow.setDefaultFlow(caseFlow) + } + + return firstMatchFlow + } + + private fun buildSelectByLanguage( + layout: Layout, + variableStructure: VariableStructure, + model: SelectByLanguage, + flowName: String?, + languages: List, + ): Flow { + val languageFlow = layout.addFlow().setType(Flow.Type.SELECT_BY_LANGUAGE) + flowName?.let { languageFlow.setName(it) } + + val defaultLanguage = projectConfig.defaultLanguage + + val caseFlows = model.cases.associate { + val caseName = "Case ${it.language}" + val contentFlow = buildDocumentContentAsSingleFlow( + layout, variableStructure, it.content, null, null, languages + ).setDisplayName(caseName) + it.language to contentFlow + } + + var defaultLanguageFlow: Flow? = null + for (language in languages) { + val contentFlow: Flow = (caseFlows[language] as Flow?) ?: layout.addFlow().setType(Flow.Type.SIMPLE).setDisplayName("Case $language") + languageFlow.addLineForSelectByInlineCondition(language, contentFlow) + + if (language == defaultLanguage) { + defaultLanguageFlow = contentFlow + } + } + + languageFlow.setDefaultFlow(defaultLanguageFlow ?: layout.addFlow().setType(Flow.Type.SIMPLE)) + + return languageFlow + } + + + protected fun List.paragraphIfEmpty(): List { + return this.ifEmpty { + listOf( + com.quadient.migration.api.dto.migrationmodel.Paragraph( + listOf(com.quadient.migration.api.dto.migrationmodel.Paragraph.Text(listOf(), null, null)), + null, + null + ) + ) + } + } + + private fun TextStyleDTO.resolve(): TextStyleDefinition { + val def = this.definition + return when (def) { + is TextStyleDefinition -> def + is TextStyleRef -> { + textStyleRepository.find(def.id)?.resolve() ?: error("Invalid text style reference") + } + else -> error("Invalid text style definition type") + } + } + + private fun ParagraphStyleDTO.resolve(): ParagraphStyleDefinition { + val def = this.definition + return when (def) { + is ParagraphStyleDefinition -> def + is ParagraphStyleRef -> paragraphStyleRepository.findOrFail(def.id).resolve() + else -> error("Invalid paragraph style definition type") + } + } + + sealed interface ScriptResult { + data class Success(val variableScript: String) : ScriptResult { + override fun toString() = variableScript + } + + data class Failure(val variableName: String) : ScriptResult { + override fun toString() = variableName + } + } +} + +fun DisplayRuleDefinition.toScript( + layout: Layout, variableStructure: VariableStructure, findVar: (String) -> Variable +): String { + return "return ${this.group.toScript(layout, variableStructure, findVar)};" +} + +fun Group.toScript( + layout: Layout, variableStructure: VariableStructure, findVar: (String) -> Variable +): String { + val expressions = """(${ + items.joinToString( + separator = " ${operator.toInlineCondition()} ", transform = { + when (it) { + is Binary -> it.toScript(layout, variableStructure, findVar) + is Group -> it.toScript(layout, variableStructure, findVar) + } + }) + })""" + return if (negation) { + "not $expressions" + } else { + expressions + } +} + +fun Binary.toScript( + layout: Layout, variableStructure: VariableStructure, findVar: (String) -> Variable +): String { + val leftScriptResult = left.toScript(layout, variableStructure, findVar) + val rightScriptResult = right.toScript(layout, variableStructure, findVar) + + val binary = operator.toScript(leftScriptResult, rightScriptResult) + return if (leftScriptResult is Success && rightScriptResult is Success) { + binary + } else { + BinOp.Equals.toScript( + Success("String('${binary.replace("'", "")}')"), Success("String('unmapped')") + ) + } +} + +fun BinOp.toScript(left: ScriptResult, right: ScriptResult): String { + return when (this) { + BinOp.Equals -> "$left==$right" + BinOp.EqualsCaseInsensitive -> "$left.equalCaseInsensitive($right)" + BinOp.NotEquals -> "$left!=$right" + BinOp.NotEqualsCaseInsensitive -> "(not $left.equalCaseInsensitive($right))" + BinOp.GreaterThan -> "$left>$right" + BinOp.GreaterOrEqualThan -> "$left>=$right" + BinOp.LessThan -> "$left<$right" + BinOp.LessOrEqualThen -> "$left<=$right" + } +} + +fun LiteralOrFunctionCall.toScript( + layout: Layout, variableStructure: VariableStructure, findVar: (String) -> Variable +): ScriptResult { + return when (this) { + is Literal -> this.toScript(layout, variableStructure, findVar) + is Function -> this.toScript(layout, variableStructure, findVar) + } +} + +fun Function.toScript( + layout: Layout, variableStructure: VariableStructure, findVar: (String) -> Variable +): ScriptResult { + when (this) { + is Function.UpperCase -> { + val arg = args[0] + return Success("(${arg.toScript(layout, variableStructure, findVar)}).toUpperCase()") + } + + is Function.LowerCase -> { + val arg = args[0] + return Success("(${arg.toScript(layout, variableStructure, findVar)}).toLowerCase()") + } + } +} + +fun Literal.toScript( + layout: Layout, variableStructure: VariableStructure, findVar: (String) -> Variable +): ScriptResult { + return when (dataType) { + LiteralDataType.Variable -> variableToScript(value, layout, variableStructure, findVar) + LiteralDataType.String -> Success( + "String('${ + value.replace("\\", "\\\\").replace("\"", "\\\"") + }')" + ) + + LiteralDataType.Number -> Success(value) + LiteralDataType.Boolean -> Success(value.lowercase().toBooleanStrict().toString()) + } +} + +fun variableToScript( + id: String, layout: Layout, variableStructure: VariableStructure, findVar: (String) -> Variable +): ScriptResult { + val variableModel = findVar(id) + val variablePathData = variableStructure.structure[id] + return if (variablePathData == null || variablePathData.path.isBlank()) { + Failure(variablePathData?.name ?: variableModel.nameOrId()) + } else { + val variableName = variablePathData.name ?: variableModel.nameOrId() + + getOrCreateVariable(layout.data, variableName, variableModel, variablePathData.path) + + Success((variablePathData.path.split(".") + variableName).joinToString(".") { pathPart -> + when (pathPart.lowercase()) { + "value" -> "Current" + "data" -> "DATA" + else -> sanitizeVariablePart(if (pathPart.first().isDigit()) "_$pathPart" else pathPart) + } + }) + } +} + +fun getOrCreateVariable( + data: Data, variableName: String, variableModel: Variable, variablePath: String +): WfdXmlVariable { + val variable = getVariable(data as DataImpl, variableName, variablePath) + return variable ?: data.addVariable().setName(variableName).setKind(VariableKind.DISCONNECTED) + .setDataType(getDataType(variableModel.dataType)).setExistingParentId(variablePath) + .setValueIfAvailable(variableModel) +} + +fun WfdXmlVariable.setValueIfAvailable(variableModel: Variable): WfdXmlVariable { + val defaultVal = variableModel.defaultValue + if (!defaultVal.isNullOrBlank()) { + when (variableModel.dataType) { + DataTypeModel.String, DataTypeModel.DateTime -> this.setValue(defaultVal) + DataTypeModel.Integer -> this.setValue(defaultVal.toInt()) + DataTypeModel.Integer64 -> this.setValue(defaultVal.toLong()) + DataTypeModel.Double, DataTypeModel.Currency -> this.setValue(defaultVal.toDouble()) + DataTypeModel.Boolean -> this.setValue( + defaultVal.lowercase().toBooleanStrict() + ) + } + } + + return this } \ No newline at end of file diff --git a/migration-library/src/main/kotlin/com/quadient/migration/service/inspirebuilder/InteractiveDocumentObjectBuilder.kt b/migration-library/src/main/kotlin/com/quadient/migration/service/inspirebuilder/InteractiveDocumentObjectBuilder.kt index 5aa3895e..d176bd1b 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/service/inspirebuilder/InteractiveDocumentObjectBuilder.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/service/inspirebuilder/InteractiveDocumentObjectBuilder.kt @@ -25,6 +25,9 @@ import com.quadient.migration.shared.ImageType import com.quadient.migration.shared.orDefault import com.quadient.wfdxml.WfdXmlBuilder import com.quadient.wfdxml.api.layoutnodes.Flow +import com.quadient.wfdxml.api.layoutnodes.Image as WfdXmlImage +import com.quadient.wfdxml.api.layoutnodes.data.DataType +import com.quadient.wfdxml.api.layoutnodes.data.VariableKind import com.quadient.wfdxml.api.module.Layout import kotlinx.serialization.Serializable import kotlinx.serialization.json.Json @@ -152,10 +155,18 @@ class InteractiveDocumentObjectBuilder( .join(fontConfigPath.orDefault("Resources/Fonts")).toString() } - override fun applyImageAlternateText(layout: Layout, image: Image, alternateText: String) { - // This method receives the DTO Image but needs to set alternate text on the WfdXml image - // The actual image setting is done in the InspireDocumentObjectBuilder when building - // For Interactive, we just create the variable, the image reference is handled elsewhere + override fun applyImageAlternateText(layout: Layout, image: WfdXmlImage, alternateText: String) { + val escapedText = alternateText.replace("\"", "\\\"") + val variable = layout.data.addVariable() + .setName("Alternate text variable for ${image.name}") + .setKind(VariableKind.CALCULATED) + .setDataType(DataType.STRING) + .setScript("return '$escapedText';") + .addCustomProperty("ValueWrapperVariable", true) + val layoutRoot = layout.root ?: layout.addRoot() + layoutRoot.addLockedWebNode(variable) + + image.setAlternateTextVariable(variable) } override fun buildDocumentObject(documentObject: DocumentObject, styleDefinitionPath: String?): String { diff --git a/migration-library/src/test/kotlin/com/quadient/migration/service/deploy/DeployClientTest.kt b/migration-library/src/test/kotlin/com/quadient/migration/service/deploy/DeployClientTest.kt index 946fda21..a8a0f8e8 100644 --- a/migration-library/src/test/kotlin/com/quadient/migration/service/deploy/DeployClientTest.kt +++ b/migration-library/src/test/kotlin/com/quadient/migration/service/deploy/DeployClientTest.kt @@ -43,6 +43,7 @@ import io.mockk.mockk import io.mockk.verify import kotlinx.datetime.Clock import kotlinx.datetime.Instant +import org.jetbrains.exposed.v1.core.Op import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import kotlin.time.Duration.Companion.hours @@ -531,7 +532,7 @@ class DeployClientTest { ) } + paragraphStyles.map { Paragraph(emptyList(), ParagraphStyleRef(it), null) }) ) - every { documentObjectRepository.list(any()) } returns externalObjects + every { documentObjectRepository.list(any>()) } returns externalObjects every { statusTrackingRepository.findEventsRelevantToOutput( id, ResourceType.DocumentObject, any() diff --git a/migration-library/src/test/kotlin/com/quadient/migration/service/deploy/DesignerDeployClientTest.kt b/migration-library/src/test/kotlin/com/quadient/migration/service/deploy/DesignerDeployClientTest.kt index 09045db6..f7a51e71 100644 --- a/migration-library/src/test/kotlin/com/quadient/migration/service/deploy/DesignerDeployClientTest.kt +++ b/migration-library/src/test/kotlin/com/quadient/migration/service/deploy/DesignerDeployClientTest.kt @@ -45,6 +45,7 @@ import io.mockk.runs import io.mockk.spyk import io.mockk.verify import kotlinx.datetime.Clock +import org.jetbrains.exposed.v1.core.Op import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Nested @@ -117,7 +118,7 @@ class DesignerDeployClientTest { every { statusTrackingRepository.findLastEventRelevantToOutput(any(), any(), any()) } returns Active() every { statusTrackingRepository.deployed(any(), any(), any(), any(), any(), any(), any()) } returns aDeployedStatus("id") - every { documentObjectRepository.list(any()) } returns listOf(template, externalBlock) + every { documentObjectRepository.list(any>()) } returns listOf(template, externalBlock) every { documentObjectBuilder.getStyleDefinitionPath() } returns "icm://some/path/style.wfd" every { ipsService.fileExists(any()) } returns false @@ -139,7 +140,7 @@ class DesignerDeployClientTest { fun `deploy list of document objects validates that no document objects are skipped`() { val spy = spyk(subject) every { spy.deployDocumentObjectsInternal(any()) } returns DeploymentResult(Uuid.random()) - every { documentObjectRepository.list(any()) } returns listOf( + every { documentObjectRepository.list(any>()) } returns listOf( aBlock(id = "1", skip = SkipOptions(true, null, null)), aBlock(id = "2", type = DocumentObjectType.Block), aBlock(id = "3", type = DocumentObjectType.Page), @@ -150,14 +151,14 @@ class DesignerDeployClientTest { val ex = assertThrows { spy.deployDocumentObjects(listOf("1", "2", "3")) } assertEquals("The following document objects are skipped: [1]. ", ex.message) - verify(exactly = 1) { documentObjectRepository.list(any()) } + verify(exactly = 1) { documentObjectRepository.list(any>()) } } @Test fun `page objects are skipped in deploy`() { val spy = spyk(subject) every { spy.deployDocumentObjectsInternal(any()) } returns DeploymentResult(Uuid.random()) - every { documentObjectRepository.list(any()) } returns listOf( + every { documentObjectRepository.list(any>()) } returns listOf( aBlock(id = "1", type = DocumentObjectType.Block), aBlock(id = "2", type = DocumentObjectType.Page), aBlock(id = "3", type = DocumentObjectType.Template), @@ -166,7 +167,7 @@ class DesignerDeployClientTest { spy.deployDocumentObjects(listOf("1", "2", "3", "4")) - verify(exactly = 1) { documentObjectRepository.list(any()) } + verify(exactly = 1) { documentObjectRepository.list(any>()) } verify { spy.deployDocumentObjectsInternal(match { docObjects -> docObjects.size == 3 && docObjects.map { it.id } @@ -179,7 +180,7 @@ class DesignerDeployClientTest { fun `deploy list of document objects validates that no document objects are internal`() { val spy = spyk(subject) every { spy.deployDocumentObjectsInternal(any()) } returns DeploymentResult(Uuid.random()) - every { documentObjectRepository.list(any()) } returns listOf( + every { documentObjectRepository.list(any>()) } returns listOf( aBlock(id = "1", internal = true), aBlock(id = "2", internal = true), aBlock(id = "3", internal = false), @@ -188,28 +189,28 @@ class DesignerDeployClientTest { val ex = assertThrows { spy.deployDocumentObjects(listOf("1", "2", "3")) } assertEquals("The following document objects are internal: [1, 2]. ", ex.message) - verify(exactly = 1) { documentObjectRepository.list(any()) } + verify(exactly = 1) { documentObjectRepository.list(any>()) } } @Test fun `deploy list of document objects validates that no document are missing`() { val spy = spyk(subject) every { spy.deployDocumentObjectsInternal(any()) } returns DeploymentResult(Uuid.random()) - every { documentObjectRepository.list(any()) } returns listOf( + every { documentObjectRepository.list(any>()) } returns listOf( aBlock(id = "1"), ) val ex = assertThrows { spy.deployDocumentObjects(listOf("1", "2", "3")) } assertEquals("The following document objects were not found: [2, 3]. ", ex.message) - verify(exactly = 1) { documentObjectRepository.list(any()) } + verify(exactly = 1) { documentObjectRepository.list(any>()) } } @Test fun `deploy list of document objects has all kinds of problems`() { val spy = spyk(subject) every { spy.deployDocumentObjectsInternal(any()) } returns DeploymentResult(Uuid.random()) - every { documentObjectRepository.list(any()) } returns listOf( + every { documentObjectRepository.list(any>()) } returns listOf( aBlock(id = "1"), aBlock(id = "2", internal = true), aBlock(id = "3"), @@ -230,7 +231,7 @@ class DesignerDeployClientTest { "The following document objects were not found: [8]. The following document objects are internal: [2]. The following document objects are skipped: [6]. ", ex.message ) - verify(exactly = 1) { documentObjectRepository.list(any()) } + verify(exactly = 1) { documentObjectRepository.list(any>()) } } @Test @@ -243,11 +244,11 @@ class DesignerDeployClientTest { aBlock(id = "2", content = listOf(aDocumentObjectRef("5"))), aBlock(id = "3", content = listOf(aDocumentObjectRef("6"))), ) - every { documentObjectRepository.list(any()) } returns docObjects + every { documentObjectRepository.list(any>()) } returns docObjects spy.deployDocumentObjects(toDeploy, true) - verify(exactly = 1) { documentObjectRepository.list(any()) } + verify(exactly = 1) { documentObjectRepository.list(any>()) } verify { spy.deployDocumentObjectsInternal(docObjects) } } @@ -268,14 +269,14 @@ class DesignerDeployClientTest { aBlock(id = "7", content = listOf(aDocumentObjectRef("8"))), aBlock(id = "8", internal = true), ) - every { documentObjectRepository.list(any()) } returns docObjects + every { documentObjectRepository.list(any>()) } returns docObjects for (dependency in dependencies) { every { documentObjectRepository.findOrFail(dependency.id) } returns dependency } spy.deployDocumentObjects(toDeploy) - verify(exactly = 1) { documentObjectRepository.list(any()) } + verify(exactly = 1) { documentObjectRepository.list(any>()) } verify(exactly = 7) { documentObjectRepository.findOrFail(any()) } verify { spy.deployDocumentObjectsInternal(match { docObjects -> @@ -293,13 +294,13 @@ class DesignerDeployClientTest { val docObjects = listOf( aBlock(id = "1", content = listOf(aDocumentObjectRef("4"))), ) - every { documentObjectRepository.list(any()) } returns docObjects + every { documentObjectRepository.list(any>()) } returns docObjects every { documentObjectRepository.findOrFail(any()) } throws IllegalArgumentException("not found") val ex = assertThrows { spy.deployDocumentObjects(toDeploy) } assertEquals("not found", ex.message) - verify(exactly = 1) { documentObjectRepository.list(any()) } + verify(exactly = 1) { documentObjectRepository.list(any>()) } verify(exactly = 1) { documentObjectRepository.findOrFail(any()) } } @@ -311,7 +312,7 @@ class DesignerDeployClientTest { val template = mockObj(aDocObj("T_1", DocumentObjectType.Template, listOf(aDocumentObjectRef(block.id)))) every { documentObjectRepository.find(innerBlock.id) } throws IllegalStateException("Not found") - every { documentObjectRepository.list(any()) } returns listOf(template, block) + every { documentObjectRepository.list(any>()) } returns listOf(template, block) every { documentObjectBuilder.buildDocumentObject(block, any()) } throws IllegalStateException("Inner block not found") every { statusTrackingRepository.findLastEventRelevantToOutput(any(), any(), any()) } returns Active() every { statusTrackingRepository.deployed(any(), any(), any(), any(), any(), any(), any()) } returns aDeployedStatus("id") diff --git a/migration-library/src/test/kotlin/com/quadient/migration/service/deploy/InteractiveDeployClientTest.kt b/migration-library/src/test/kotlin/com/quadient/migration/service/deploy/InteractiveDeployClientTest.kt index 5b3589f5..05801a31 100644 --- a/migration-library/src/test/kotlin/com/quadient/migration/service/deploy/InteractiveDeployClientTest.kt +++ b/migration-library/src/test/kotlin/com/quadient/migration/service/deploy/InteractiveDeployClientTest.kt @@ -52,6 +52,7 @@ import io.mockk.runs import io.mockk.spyk import io.mockk.verify import kotlinx.datetime.Clock +import org.jetbrains.exposed.v1.core.Op import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Nested @@ -147,7 +148,7 @@ class InteractiveDeployClientTest { val template = mockDocumentObject(aTemplate("3", listOf(aDocumentObjectRef("block1"), aDocumentObjectRef("block2")))) - every { documentObjectRepository.list(any()) } returns listOf(externalBlock, template) + every { documentObjectRepository.list(any>()) } returns listOf(externalBlock, template) every { documentObjectBuilder.buildDocumentObject(any(), any()) } returns "" every { documentObjectRepository.find(any()) } returns aBlock("99", internal = false) every { statusTrackingRepository.findLastEventRelevantToOutput(any(), any(), any()) } returns Active() @@ -218,7 +219,7 @@ class InteractiveDeployClientTest { val template = mockDocumentObject(aTemplate("3", listOf(aDocumentObjectRef("block1"), aDocumentObjectRef("block2")))) - every { documentObjectRepository.list(any()) } returns listOf(block, template) + every { documentObjectRepository.list(any>()) } returns listOf(block, template) every { documentObjectBuilder.buildDocumentObject(any(), any()) } returns "" every { documentObjectRepository.find(any()) } returns aBlock("99", internal = false) every { statusTrackingRepository.findLastEventRelevantToOutput(any(), any(), any()) } returns Active() @@ -246,7 +247,7 @@ class InteractiveDeployClientTest { val file = mockFile(aFile("Report")) val block = mockDocumentObject(aBlock(id = "1", listOf(ImageRef(image.id), FileRef(file.id)))) - every { documentObjectRepository.list(any()) } returns listOf(block) + every { documentObjectRepository.list(any>()) } returns listOf(block) every { documentObjectBuilder.buildDocumentObject(any(), any()) } returns "" every { ipsService.tryUpload(any(), any()) } returns OperationResult.Success every { statusTrackingRepository.findLastEventRelevantToOutput(any(), any(), any()) } returns Active() @@ -289,7 +290,7 @@ class InteractiveDeployClientTest { )) ) - every { documentObjectRepository.list(any()) } returns listOf(block) + every { documentObjectRepository.list(any>()) } returns listOf(block) every { documentObjectBuilder.buildDocumentObject(any(), any()) } returns "" every { ipsService.upload(any(), any()) } just runs every { statusTrackingRepository.findLastEventRelevantToOutput(any(), any(), any()) } returns Active() @@ -326,7 +327,7 @@ class InteractiveDeployClientTest { ) ) - every { documentObjectRepository.list(any()) } returns listOf(block) + every { documentObjectRepository.list(any>()) } returns listOf(block) every { documentObjectRepository.find(innerBlock.id) } returns innerBlock every { documentObjectBuilder.buildDocumentObject(any(), any()) } returns "" every { statusTrackingRepository.findLastEventRelevantToOutput(any(), any(), any()) } returns Active() @@ -458,7 +459,7 @@ class InteractiveDeployClientTest { fun `deploy list of document objects validates that no document objects are unsupported`() { val spy = spyk(subject) every { spy.deployDocumentObjectsInternal(any()) } returns DeploymentResult(Uuid.random()) - every { documentObjectRepository.list(any()) } returns listOf( + every { documentObjectRepository.list(any>()) } returns listOf( aBlock(id = "1", skip = SkipOptions(true, null, null)), aBlock(id = "2", type = DocumentObjectType.Block), aBlock(id = "3", skip = SkipOptions(true, null, null)), @@ -467,14 +468,14 @@ class InteractiveDeployClientTest { val ex = assertThrows { spy.deployDocumentObjects(listOf("1", "2", "3")) } assertEquals("The following document objects are skipped: [1, 3]. ", ex.message) - verify(exactly = 1) { documentObjectRepository.list(any()) } + verify(exactly = 1) { documentObjectRepository.list(any>()) } } @Test fun `deploy list of document objects validates that no document objects are `() { val spy = spyk(subject) every { spy.deployDocumentObjectsInternal(any()) } returns DeploymentResult(Uuid.random()) - every { documentObjectRepository.list(any()) } returns listOf( + every { documentObjectRepository.list(any>()) } returns listOf( aBlock(id = "1", internal = true), aBlock(id = "2", internal = true), aBlock(id = "3", internal = false), @@ -483,28 +484,28 @@ class InteractiveDeployClientTest { val ex = assertThrows { spy.deployDocumentObjects(listOf("1", "2", "3")) } assertEquals("The following document objects are internal: [1, 2]. ", ex.message) - verify(exactly = 1) { documentObjectRepository.list(any()) } + verify(exactly = 1) { documentObjectRepository.list(any>()) } } @Test fun `deploy list of document objects validates that no document are missing`() { val spy = spyk(subject) every { spy.deployDocumentObjectsInternal(any()) } returns DeploymentResult(Uuid.random()) - every { documentObjectRepository.list(any()) } returns listOf( + every { documentObjectRepository.list(any>()) } returns listOf( aBlock(id = "1"), ) val ex = assertThrows { spy.deployDocumentObjects(listOf("1", "2", "3")) } assertEquals("The following document objects were not found: [2, 3]. ", ex.message) - verify(exactly = 1) { documentObjectRepository.list(any()) } + verify(exactly = 1) { documentObjectRepository.list(any>()) } } @Test fun `deploy list of document objects has all kinds of problems`() { val spy = spyk(subject) every { spy.deployDocumentObjectsInternal(any()) } returns DeploymentResult(Uuid.random()) - every { documentObjectRepository.list(any()) } returns listOf( + every { documentObjectRepository.list(any>()) } returns listOf( aBlock(id = "1"), aBlock(id = "2", internal = true), aBlock(id = "3"), @@ -525,7 +526,7 @@ class InteractiveDeployClientTest { "The following document objects were not found: [8]. The following document objects are skipped: [6]. The following document objects are internal: [2]. ", ex.message ) - verify(exactly = 1) { documentObjectRepository.list(any()) } + verify(exactly = 1) { documentObjectRepository.list(any>()) } } @Test @@ -538,11 +539,11 @@ class InteractiveDeployClientTest { aBlock(id = "2", content = listOf(aDocumentObjectRef("5"))), aBlock(id = "3", content = listOf(aDocumentObjectRef("6"))), ) - every { documentObjectRepository.list(any()) } returns docObjects + every { documentObjectRepository.list(any>()) } returns docObjects spy.deployDocumentObjects(toDeploy, true) - verify(exactly = 1) { documentObjectRepository.list(any()) } + verify(exactly = 1) { documentObjectRepository.list(any>()) } verify { spy.deployDocumentObjectsInternal(docObjects) } } @@ -563,14 +564,14 @@ class InteractiveDeployClientTest { aBlock(id = "7", content = listOf(aDocumentObjectRef("8"))), aBlock(id = "8", internal = true), ) - every { documentObjectRepository.list(any()) } returns docObjects + every { documentObjectRepository.list(any>()) } returns docObjects for (dependency in dependencies) { every { documentObjectRepository.findOrFail(dependency.id) } returns dependency } spy.deployDocumentObjects(toDeploy) - verify(exactly = 1) { documentObjectRepository.list(any()) } + verify(exactly = 1) { documentObjectRepository.list(any>()) } verify(exactly = 7) { documentObjectRepository.findOrFail(any()) } verify { spy.deployDocumentObjectsInternal(match { docObjects -> @@ -588,13 +589,13 @@ class InteractiveDeployClientTest { val docObjects = listOf( aBlock(id = "1", content = listOf(aDocumentObjectRef("4"))), ) - every { documentObjectRepository.list(any()) } returns docObjects + every { documentObjectRepository.list(any>()) } returns docObjects every { documentObjectRepository.findOrFail(any()) } throws IllegalArgumentException("not found") val ex = assertThrows { spy.deployDocumentObjects(toDeploy) } assertEquals("not found", ex.message) - verify(exactly = 1) { documentObjectRepository.list(any()) } + verify(exactly = 1) { documentObjectRepository.list(any>()) } verify(exactly = 1) { documentObjectRepository.findOrFail(any()) } } @@ -609,7 +610,7 @@ class InteractiveDeployClientTest { every { statusTrackingRepository.findLastEventRelevantToOutput(any(), any(), any()) } returns Active() every { statusTrackingRepository.deployed(any(), any(), any(), any(), any(), any(), any()) } returns aDeployedStatus("id") every { documentObjectRepository.find(innerBlock.id) } throws IllegalStateException("Not found") - every { documentObjectRepository.list(any()) } returns listOf(template, block) + every { documentObjectRepository.list(any>()) } returns listOf(template, block) every { documentObjectBuilder.buildDocumentObject(block, any()) } throws IllegalStateException("Inner block not found") every { statusTrackingRepository.error("B_1", any(), any(), any(), any(), any(), any(), any()) } returns aErrorStatus("B_1") @@ -652,7 +653,7 @@ class InteractiveDeployClientTest { val templates = List(1) { mockDocumentObject(aTemplate(it.toString(), listOf(aDocumentObjectRef("block$it")))) } - every { documentObjectRepository.list(any()) } returns blocks + templates + every { documentObjectRepository.list(any>()) } returns blocks + templates } private fun mockDocumentObject(documentObject: DocumentObject): DocumentObject { From 2611c1834db4406597b8cccd555528ff08901324 Mon Sep 17 00:00:00 2001 From: "d.svitak" Date: Fri, 6 Feb 2026 13:08:18 +0100 Subject: [PATCH 6/9] refactor of repositories --- .../api/dto/migrationmodel/DisplayRule.kt | 16 ------- .../migration/api/dto/migrationmodel/File.kt | 22 +--------- .../migration/api/dto/migrationmodel/Image.kt | 23 ---------- .../api/dto/migrationmodel/ParagraphStyle.kt | 44 ------------------- .../api/dto/migrationmodel/TextStyle.kt | 37 ---------------- .../api/dto/migrationmodel/Variable.kt | 17 ------- .../dto/migrationmodel/VariableStructure.kt | 17 ------- .../api/repository/DisplayRuleRepository.kt | 11 ++++- .../api/repository/FileRepository.kt | 16 ++++++- .../api/repository/ImageRepository.kt | 19 +++++++- .../repository/ParagraphStyleRepository.kt | 42 +++++++++++++++++- .../migration/api/repository/Repository.kt | 2 +- .../api/repository/TextStyleRepository.kt | 31 ++++++++++++- .../api/repository/VariableRepository.kt | 34 +++++++++----- .../repository/VariableStructureRepository.kt | 13 +++++- 15 files changed, 147 insertions(+), 197 deletions(-) diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/DisplayRule.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/DisplayRule.kt index 6021fd1f..faaa55af 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/DisplayRule.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/DisplayRule.kt @@ -1,9 +1,7 @@ package com.quadient.migration.api.dto.migrationmodel -import com.quadient.migration.persistence.table.DisplayRuleTable import com.quadient.migration.shared.DisplayRuleDefinition import kotlinx.datetime.Instant -import org.jetbrains.exposed.v1.core.ResultRow data class DisplayRule @JvmOverloads constructor( override val id: String, @@ -17,18 +15,4 @@ data class DisplayRule @JvmOverloads constructor( override fun collectRefs(): List { return definition?.collectRefs() ?: emptyList() } - - companion object { - fun fromDb(row: ResultRow): DisplayRule { - return DisplayRule( - id = row[DisplayRuleTable.id].value, - name = row[DisplayRuleTable.name], - originLocations = row[DisplayRuleTable.originLocations], - customFields = CustomFieldMap(row[DisplayRuleTable.customFields].toMutableMap()), - lastUpdated = row[DisplayRuleTable.lastUpdated], - created = row[DisplayRuleTable.created], - definition = row[DisplayRuleTable.definition] - ) - } - } } \ No newline at end of file diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/File.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/File.kt index 0260daa0..6a58fab2 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/File.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/File.kt @@ -1,11 +1,8 @@ package com.quadient.migration.api.dto.migrationmodel -import com.quadient.migration.persistence.table.FileTable import com.quadient.migration.shared.FileType -import com.quadient.migration.shared.IcmPath import com.quadient.migration.shared.SkipOptions import kotlinx.datetime.Instant -import org.jetbrains.exposed.v1.core.ResultRow data class File @JvmOverloads constructor( override val id: String, @@ -22,21 +19,4 @@ data class File @JvmOverloads constructor( override fun collectRefs(): List { return emptyList() } - - companion object { - fun fromDb(row: ResultRow): File { - return File( - id = row[FileTable.id].value, - name = row[FileTable.name], - originLocations = row[FileTable.originLocations], - customFields = CustomFieldMap(row[FileTable.customFields].toMutableMap()), - created = row[FileTable.created], - lastUpdated = row[FileTable.created], - sourcePath = row[FileTable.sourcePath], - targetFolder = row[FileTable.targetFolder]?.let(IcmPath::from)?.toString(), - fileType = FileType.valueOf(row[FileTable.fileType]), - skip = row[FileTable.skip], - ) - } - } -} +} \ No newline at end of file diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/Image.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/Image.kt index d8e6346f..67216d5b 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/Image.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/Image.kt @@ -1,13 +1,10 @@ package com.quadient.migration.api.dto.migrationmodel -import com.quadient.migration.persistence.table.ImageTable -import com.quadient.migration.shared.IcmPath import com.quadient.migration.shared.ImageOptions import com.quadient.migration.shared.ImageType import com.quadient.migration.shared.MetadataPrimitive import com.quadient.migration.shared.SkipOptions import kotlinx.datetime.Instant -import org.jetbrains.exposed.v1.core.ResultRow data class Image @JvmOverloads constructor( override val id: String, @@ -27,24 +24,4 @@ data class Image @JvmOverloads constructor( override fun collectRefs(): List { return emptyList() } - - companion object { - fun fromDb(row: ResultRow): Image { - return Image( - id = row[ImageTable.id].value, - name = row[ImageTable.name], - originLocations = row[ImageTable.originLocations], - customFields = CustomFieldMap(row[ImageTable.customFields].toMutableMap()), - created = row[ImageTable.created], - lastUpdated = row[ImageTable.created], - sourcePath = row[ImageTable.sourcePath], - imageType = ImageType.valueOf(row[ImageTable.imageType]), - options = row[ImageTable.options], - targetFolder = row[ImageTable.targetFolder]?.let(IcmPath::from)?.toString(), - metadata = row[ImageTable.metadata], - skip = row[ImageTable.skip], - alternateText = row[ImageTable.alternateText], - ) - } - } } \ No newline at end of file diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/ParagraphStyle.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/ParagraphStyle.kt index 9990ff37..00e33a18 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/ParagraphStyle.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/ParagraphStyle.kt @@ -3,14 +3,12 @@ package com.quadient.migration.api.dto.migrationmodel import com.quadient.migration.persistence.migrationmodel.ParagraphStyleDefinitionEntity import com.quadient.migration.persistence.migrationmodel.TabEntity import com.quadient.migration.persistence.migrationmodel.TabsEntity -import com.quadient.migration.persistence.table.ParagraphStyleTable import com.quadient.migration.shared.Alignment import com.quadient.migration.shared.LineSpacing import com.quadient.migration.shared.ParagraphPdfTaggingRule import com.quadient.migration.shared.Size import com.quadient.migration.shared.TabType import kotlinx.datetime.Instant -import org.jetbrains.exposed.v1.core.ResultRow data class ParagraphStyle @JvmOverloads constructor( override val id: String, @@ -27,48 +25,6 @@ data class ParagraphStyle @JvmOverloads constructor( is ParagraphStyleRef -> listOf(definition as Ref) } } - - companion object { - fun fromDb(row: ResultRow): ParagraphStyle { - // Need to convert from Entity to DTO - val definitionEntity = row[ParagraphStyleTable.definition] - val definition = when (definitionEntity) { - is com.quadient.migration.persistence.migrationmodel.ParagraphStyleDefinitionEntity -> { - ParagraphStyleDefinition( - leftIndent = definitionEntity.leftIndent, - rightIndent = definitionEntity.rightIndent, - defaultTabSize = definitionEntity.defaultTabSize, - spaceBefore = definitionEntity.spaceBefore, - spaceAfter = definitionEntity.spaceAfter, - alignment = definitionEntity.alignment, - firstLineIndent = definitionEntity.firstLineIndent, - lineSpacing = definitionEntity.lineSpacing, - keepWithNextParagraph = definitionEntity.keepWithNextParagraph, - tabs = definitionEntity.tabs?.let { tabsEntity -> - Tabs( - tabs = tabsEntity.tabs.map { Tab(it.position, it.type) }, - useOutsideTabs = tabsEntity.useOutsideTabs - ) - }, - pdfTaggingRule = definitionEntity.pdfTaggingRule, - ) - } - is com.quadient.migration.persistence.migrationmodel.ParagraphStyleEntityRef -> { - ParagraphStyleRef.fromDb(definitionEntity) - } - } - - return ParagraphStyle( - id = row[ParagraphStyleTable.id].value, - name = row[ParagraphStyleTable.name], - originLocations = row[ParagraphStyleTable.originLocations], - customFields = CustomFieldMap(row[ParagraphStyleTable.customFields].toMutableMap()), - lastUpdated = row[ParagraphStyleTable.lastUpdated], - created = row[ParagraphStyleTable.created], - definition = definition, - ) - } - } } data class ParagraphStyleDefinition( diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/TextStyle.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/TextStyle.kt index ed07f4e1..96a2c9b2 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/TextStyle.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/TextStyle.kt @@ -1,12 +1,10 @@ package com.quadient.migration.api.dto.migrationmodel import com.quadient.migration.persistence.migrationmodel.TextStyleDefinitionEntity -import com.quadient.migration.persistence.table.TextStyleTable import com.quadient.migration.shared.Color import com.quadient.migration.shared.Size import com.quadient.migration.shared.SuperOrSubscript import kotlinx.datetime.Instant -import org.jetbrains.exposed.v1.core.ResultRow data class TextStyle @JvmOverloads constructor( override val id: String, @@ -23,41 +21,6 @@ data class TextStyle @JvmOverloads constructor( is TextStyleRef -> listOf(definition as Ref) } } - - companion object { - fun fromDb(row: ResultRow): TextStyle { - // Need to convert from Entity to DTO - val definitionEntity = row[TextStyleTable.definition] - val definition = when (definitionEntity) { - is com.quadient.migration.persistence.migrationmodel.TextStyleDefinitionEntity -> { - TextStyleDefinition( - fontFamily = definitionEntity.fontFamily, - foregroundColor = definitionEntity.foregroundColor, - size = definitionEntity.size, - bold = definitionEntity.bold, - italic = definitionEntity.italic, - underline = definitionEntity.underline, - strikethrough = definitionEntity.strikethrough, - superOrSubscript = definitionEntity.superOrSubscript, - interspacing = definitionEntity.interspacing, - ) - } - is com.quadient.migration.persistence.migrationmodel.TextStyleEntityRef -> { - TextStyleRef.fromDb(definitionEntity) - } - } - - return TextStyle( - id = row[TextStyleTable.id].value, - name = row[TextStyleTable.name], - originLocations = row[TextStyleTable.originLocations], - customFields = CustomFieldMap(row[TextStyleTable.customFields].toMutableMap()), - lastUpdated = row[TextStyleTable.lastUpdated], - created = row[TextStyleTable.created], - definition = definition, - ) - } - } } data class TextStyleDefinition( diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/Variable.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/Variable.kt index 2e77a81f..fa82e7db 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/Variable.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/Variable.kt @@ -1,9 +1,7 @@ package com.quadient.migration.api.dto.migrationmodel -import com.quadient.migration.persistence.table.VariableTable import com.quadient.migration.shared.DataType import kotlinx.datetime.Instant -import org.jetbrains.exposed.v1.core.ResultRow data class Variable @JvmOverloads constructor( override val id: String, @@ -18,19 +16,4 @@ data class Variable @JvmOverloads constructor( override fun collectRefs(): List { return emptyList() } - - companion object { - fun fromDb(row: ResultRow): Variable { - return Variable( - id = row[VariableTable.id].value, - name = row[VariableTable.name], - originLocations = row[VariableTable.originLocations], - customFields = CustomFieldMap(row[VariableTable.customFields].toMutableMap()), - lastUpdated = row[VariableTable.lastUpdated], - created = row[VariableTable.created], - dataType = DataType.valueOf(row[VariableTable.dataType]), - defaultValue = row[VariableTable.defaultValue] - ) - } - } } \ No newline at end of file diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/VariableStructure.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/VariableStructure.kt index 1796e7e5..4c14515e 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/VariableStructure.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/VariableStructure.kt @@ -1,9 +1,7 @@ package com.quadient.migration.api.dto.migrationmodel -import com.quadient.migration.persistence.table.VariableStructureTable import com.quadient.migration.shared.VariablePathData import kotlinx.datetime.Instant -import org.jetbrains.exposed.v1.core.ResultRow data class VariableStructure @JvmOverloads constructor( override val id: String, @@ -18,19 +16,4 @@ data class VariableStructure @JvmOverloads constructor( override fun collectRefs(): List { return structure.keys.map { VariableRef(it) } } - - companion object { - fun fromDb(row: ResultRow): VariableStructure { - return VariableStructure( - id = row[VariableStructureTable.id].value, - name = row[VariableStructureTable.name], - customFields = CustomFieldMap(row[VariableStructureTable.customFields].toMutableMap()), - lastUpdated = row[VariableStructureTable.lastUpdated], - created = row[VariableStructureTable.created], - structure = row[VariableStructureTable.structure], - originLocations = row[VariableStructureTable.originLocations], - languageVariable = row[VariableStructureTable.languageVariable]?.let { VariableRef(it) } - ) - } - } } \ No newline at end of file diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/DisplayRuleRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/DisplayRuleRepository.kt index 98665325..85427f88 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/DisplayRuleRepository.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/DisplayRuleRepository.kt @@ -1,5 +1,6 @@ package com.quadient.migration.api.repository +import com.quadient.migration.api.dto.migrationmodel.CustomFieldMap import com.quadient.migration.api.dto.migrationmodel.DisplayRule import com.quadient.migration.api.dto.migrationmodel.MigrationObject import com.quadient.migration.persistence.table.DisplayRuleTable @@ -15,7 +16,15 @@ class DisplayRuleRepository(table: DisplayRuleTable, projectName: String) : Repository(table, projectName) { override fun fromDb(row: ResultRow): DisplayRule { - return DisplayRule.fromDb(row) + return DisplayRule( + id = row[DisplayRuleTable.id].value, + name = row[DisplayRuleTable.name], + originLocations = row[DisplayRuleTable.originLocations], + customFields = CustomFieldMap(row[DisplayRuleTable.customFields].toMutableMap()), + lastUpdated = row[DisplayRuleTable.lastUpdated], + created = row[DisplayRuleTable.created], + definition = row[DisplayRuleTable.definition] + ) } override fun findUsages(id: String): List { diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/FileRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/FileRepository.kt index b92408c0..198a8c37 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/FileRepository.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/FileRepository.kt @@ -1,10 +1,12 @@ package com.quadient.migration.api.repository +import com.quadient.migration.api.dto.migrationmodel.CustomFieldMap import com.quadient.migration.api.dto.migrationmodel.File import com.quadient.migration.api.dto.migrationmodel.MigrationObject import com.quadient.migration.persistence.table.DocumentObjectTable import com.quadient.migration.persistence.table.FileTable import com.quadient.migration.service.deploy.ResourceType +import com.quadient.migration.shared.FileType import com.quadient.migration.tools.concat import kotlinx.datetime.Clock import org.jetbrains.exposed.v1.core.ResultRow @@ -14,9 +16,19 @@ import org.jetbrains.exposed.v1.jdbc.upsertReturning class FileRepository(table: FileTable, projectName: String) : Repository(table, projectName) { val statusTrackingRepository = StatusTrackingRepository(projectName) - override fun fromDb(row: ResultRow): File { - return File.fromDb(row) + return File( + id = row[FileTable.id].value, + name = row[FileTable.name], + originLocations = row[FileTable.originLocations], + customFields = CustomFieldMap(row[FileTable.customFields].toMutableMap()), + created = row[FileTable.created], + lastUpdated = row[FileTable.created], + sourcePath = row[FileTable.sourcePath], + targetFolder = row[FileTable.targetFolder], + fileType = FileType.valueOf(row[FileTable.fileType]), + skip = row[FileTable.skip], + ) } override fun findUsages(id: String): List { diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/ImageRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/ImageRepository.kt index c61a6b47..2867467d 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/ImageRepository.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/ImageRepository.kt @@ -1,10 +1,12 @@ package com.quadient.migration.api.repository +import com.quadient.migration.api.dto.migrationmodel.CustomFieldMap import com.quadient.migration.api.dto.migrationmodel.Image import com.quadient.migration.api.dto.migrationmodel.MigrationObject import com.quadient.migration.persistence.table.DocumentObjectTable import com.quadient.migration.persistence.table.ImageTable import com.quadient.migration.service.deploy.ResourceType +import com.quadient.migration.shared.IcmPath import com.quadient.migration.shared.ImageType import com.quadient.migration.tools.concat import kotlinx.datetime.Clock @@ -15,9 +17,22 @@ import org.jetbrains.exposed.v1.jdbc.upsertReturning class ImageRepository(table: ImageTable, projectName: String) : Repository(table, projectName) { val statusTrackingRepository = StatusTrackingRepository(projectName) - override fun fromDb(row: ResultRow): Image { - return Image.fromDb(row) + return Image( + id = row[ImageTable.id].value, + name = row[ImageTable.name], + originLocations = row[ImageTable.originLocations], + customFields = CustomFieldMap(row[ImageTable.customFields].toMutableMap()), + created = row[ImageTable.created], + lastUpdated = row[ImageTable.created], + sourcePath = row[ImageTable.sourcePath], + imageType = ImageType.valueOf(row[ImageTable.imageType]), + options = row[ImageTable.options], + targetFolder = row[ImageTable.targetFolder]?.let(IcmPath::from)?.toString(), + metadata = row[ImageTable.metadata], + skip = row[ImageTable.skip], + alternateText = row[ImageTable.alternateText], + ) } override fun findUsages(id: String): List { diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/ParagraphStyleRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/ParagraphStyleRepository.kt index 3ee960a1..073ae782 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/ParagraphStyleRepository.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/ParagraphStyleRepository.kt @@ -1,9 +1,13 @@ package com.quadient.migration.api.repository +import com.quadient.migration.api.dto.migrationmodel.CustomFieldMap +import com.quadient.migration.api.dto.migrationmodel.DocumentObject import com.quadient.migration.api.dto.migrationmodel.MigrationObject import com.quadient.migration.api.dto.migrationmodel.ParagraphStyle import com.quadient.migration.api.dto.migrationmodel.ParagraphStyleDefinition import com.quadient.migration.api.dto.migrationmodel.ParagraphStyleRef +import com.quadient.migration.api.dto.migrationmodel.Tab +import com.quadient.migration.api.dto.migrationmodel.Tabs import com.quadient.migration.persistence.table.DocumentObjectTable import com.quadient.migration.persistence.table.ParagraphStyleTable import com.quadient.migration.service.deploy.ResourceType @@ -18,9 +22,43 @@ import kotlin.collections.map class ParagraphStyleRepository(table: ParagraphStyleTable, projectName: String) : Repository(table, projectName) { val statusTrackingRepository = StatusTrackingRepository(projectName) - override fun fromDb(row: ResultRow): ParagraphStyle { - return ParagraphStyle.fromDb(row) + val definitionEntity = row[ParagraphStyleTable.definition] + val definition = when (definitionEntity) { + is com.quadient.migration.persistence.migrationmodel.ParagraphStyleDefinitionEntity -> { + ParagraphStyleDefinition( + leftIndent = definitionEntity.leftIndent, + rightIndent = definitionEntity.rightIndent, + defaultTabSize = definitionEntity.defaultTabSize, + spaceBefore = definitionEntity.spaceBefore, + spaceAfter = definitionEntity.spaceAfter, + alignment = definitionEntity.alignment, + firstLineIndent = definitionEntity.firstLineIndent, + lineSpacing = definitionEntity.lineSpacing, + keepWithNextParagraph = definitionEntity.keepWithNextParagraph, + tabs = definitionEntity.tabs?.let { tabsEntity -> + Tabs( + tabs = tabsEntity.tabs.map { Tab(it.position, it.type) }, + useOutsideTabs = tabsEntity.useOutsideTabs + ) + }, + pdfTaggingRule = definitionEntity.pdfTaggingRule, + ) + } + is com.quadient.migration.persistence.migrationmodel.ParagraphStyleEntityRef -> { + ParagraphStyleRef.fromDb(definitionEntity) + } + } + + return ParagraphStyle( + id = row[ParagraphStyleTable.id].value, + name = row[ParagraphStyleTable.name], + originLocations = row[ParagraphStyleTable.originLocations], + customFields = CustomFieldMap(row[ParagraphStyleTable.customFields].toMutableMap()), + lastUpdated = row[ParagraphStyleTable.lastUpdated], + created = row[ParagraphStyleTable.created], + definition = definition, + ) } override fun findUsages(id: String): List { diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/Repository.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/Repository.kt index 9c137a53..c66b6a57 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/Repository.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/Repository.kt @@ -18,7 +18,7 @@ import org.jetbrains.exposed.v1.jdbc.selectAll import org.jetbrains.exposed.v1.jdbc.transactions.transaction abstract class Repository( - protected val table: MigrationObjectTable, + protected open val table: MigrationObjectTable, protected val projectName: String ) { private val cache = mutableMapOf() diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/TextStyleRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/TextStyleRepository.kt index eac6c8da..2f0d51c0 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/TextStyleRepository.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/TextStyleRepository.kt @@ -1,5 +1,6 @@ package com.quadient.migration.api.repository +import com.quadient.migration.api.dto.migrationmodel.CustomFieldMap import com.quadient.migration.api.dto.migrationmodel.MigrationObject import com.quadient.migration.api.dto.migrationmodel.TextStyle import com.quadient.migration.api.dto.migrationmodel.TextStyleDefinition @@ -20,7 +21,35 @@ class TextStyleRepository(table: TextStyleTable, projectName: String) : val statusTrackingRepository = StatusTrackingRepository(projectName) override fun fromDb(row: ResultRow): TextStyle { - return TextStyle.fromDb(row) + val definitionEntity = row[TextStyleTable.definition] + val definition = when (definitionEntity) { + is com.quadient.migration.persistence.migrationmodel.TextStyleDefinitionEntity -> { + TextStyleDefinition( + fontFamily = definitionEntity.fontFamily, + foregroundColor = definitionEntity.foregroundColor, + size = definitionEntity.size, + bold = definitionEntity.bold, + italic = definitionEntity.italic, + underline = definitionEntity.underline, + strikethrough = definitionEntity.strikethrough, + superOrSubscript = definitionEntity.superOrSubscript, + interspacing = definitionEntity.interspacing, + ) + } + is com.quadient.migration.persistence.migrationmodel.TextStyleEntityRef -> { + TextStyleRef.fromDb(definitionEntity) + } + } + + return TextStyle( + id = row[TextStyleTable.id].value, + name = row[TextStyleTable.name], + originLocations = row[TextStyleTable.originLocations], + customFields = CustomFieldMap(row[TextStyleTable.customFields].toMutableMap()), + lastUpdated = row[TextStyleTable.lastUpdated], + created = row[TextStyleTable.created], + definition = definition, + ) } override fun findUsages(id: String): List { diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/VariableRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/VariableRepository.kt index 8319efcf..81650151 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/VariableRepository.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/VariableRepository.kt @@ -1,10 +1,11 @@ package com.quadient.migration.api.repository +import com.quadient.migration.api.dto.migrationmodel.CustomFieldMap import com.quadient.migration.api.dto.migrationmodel.MigrationObject import com.quadient.migration.api.dto.migrationmodel.Variable import com.quadient.migration.persistence.table.DocumentObjectTable -import com.quadient.migration.persistence.table.MigrationObjectTable import com.quadient.migration.persistence.table.VariableTable +import com.quadient.migration.shared.DataType import com.quadient.migration.tools.concat import kotlinx.datetime.Clock import org.jetbrains.exposed.v1.core.ResultRow @@ -13,11 +14,20 @@ import org.jetbrains.exposed.v1.jdbc.transactions.transaction import org.jetbrains.exposed.v1.jdbc.upsertReturning import kotlin.collections.map -class VariableRepository(table: MigrationObjectTable, projectName: String) : +class VariableRepository(override val table: VariableTable, projectName: String) : Repository(table, projectName) { override fun fromDb(row: ResultRow): Variable { - return Variable.fromDb(row) + return Variable( + id = row[table.id].value, + name = row[table.name], + originLocations = row[table.originLocations], + customFields = CustomFieldMap(row[table.customFields].toMutableMap()), + lastUpdated = row[table.lastUpdated], + created = row[table.created], + dataType = DataType.valueOf(row[table.dataType]), + defaultValue = row[table.defaultValue] + ) } override fun findUsages(id: String): List { @@ -35,15 +45,15 @@ class VariableRepository(table: MigrationObjectTable, projectName: String) : val now = Clock.System.now() table.upsertReturning(table.id, table.projectName) { - it[VariableTable.id] = dto.id - it[VariableTable.projectName] = projectName - it[VariableTable.name] = dto.name - it[VariableTable.originLocations] = existingItem?.originLocations.concat(dto.originLocations).distinct() - it[VariableTable.customFields] = dto.customFields.inner - it[VariableTable.created] = existingItem?.created ?: now - it[VariableTable.lastUpdated] = now - it[VariableTable.dataType] = dto.dataType.toString() - it[VariableTable.defaultValue] = dto.defaultValue + it[table.id] = dto.id + it[table.projectName] = projectName + it[table.name] = dto.name + it[table.originLocations] = existingItem?.originLocations.concat(dto.originLocations).distinct() + it[table.customFields] = dto.customFields.inner + it[table.created] = existingItem?.created ?: now + it[table.lastUpdated] = now + it[table.dataType] = dto.dataType.toString() + it[table.defaultValue] = dto.defaultValue }.first() } } diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/VariableStructureRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/VariableStructureRepository.kt index 60beba4a..1c6d88d4 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/VariableStructureRepository.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/VariableStructureRepository.kt @@ -1,6 +1,8 @@ package com.quadient.migration.api.repository +import com.quadient.migration.api.dto.migrationmodel.CustomFieldMap import com.quadient.migration.api.dto.migrationmodel.MigrationObject +import com.quadient.migration.api.dto.migrationmodel.VariableRef import com.quadient.migration.api.dto.migrationmodel.VariableStructure import com.quadient.migration.persistence.table.DocumentObjectTable import com.quadient.migration.persistence.table.VariableStructureTable @@ -16,7 +18,16 @@ class VariableStructureRepository(table: VariableStructureTable, projectName: St Repository(table, projectName) { override fun fromDb(row: ResultRow): VariableStructure { - return VariableStructure.fromDb(row) + return VariableStructure( + id = row[VariableStructureTable.id].value, + name = row[VariableStructureTable.name], + customFields = CustomFieldMap(row[VariableStructureTable.customFields].toMutableMap()), + lastUpdated = row[VariableStructureTable.lastUpdated], + created = row[VariableStructureTable.created], + structure = row[VariableStructureTable.structure], + originLocations = row[VariableStructureTable.originLocations], + languageVariable = row[VariableStructureTable.languageVariable]?.let { VariableRef(it) } + ) } override fun findUsages(id: String): List { From 398c7e27f62d66bcde5615fbc98bddf90a095daf Mon Sep 17 00:00:00 2001 From: "d.svitak" Date: Fri, 6 Feb 2026 13:50:26 +0100 Subject: [PATCH 7/9] fix repository issues and related unit tests --- .../api/dto/migrationmodel/DisplayRule.kt | 4 +- .../api/dto/migrationmodel/DocumentObject.kt | 4 +- .../migration/api/dto/migrationmodel/File.kt | 4 +- .../migration/api/dto/migrationmodel/Image.kt | 4 +- .../api/dto/migrationmodel/ParagraphStyle.kt | 4 +- .../migration/api/dto/migrationmodel/Ref.kt | 18 ++++----- .../api/dto/migrationmodel/TextStyle.kt | 4 +- .../api/dto/migrationmodel/Variable.kt | 4 +- .../dto/migrationmodel/VariableStructure.kt | 4 +- .../api/repository/DisplayRuleRepository.kt | 4 +- .../repository/DocumentObjectRepository.kt | 4 +- .../api/repository/FileRepository.kt | 4 +- .../api/repository/ImageRepository.kt | 4 +- .../repository/ParagraphStyleRepository.kt | 4 +- .../migration/api/repository/Repository.kt | 2 +- .../api/repository/TextStyleRepository.kt | 4 +- .../api/repository/VariableRepository.kt | 38 +++++++++---------- .../repository/VariableStructureRepository.kt | 4 +- .../persistence/DisplayRuleRepositoryTest.kt | 6 ++- .../persistence/FileRepositoryTest.kt | 6 ++- .../persistence/ImageRepositoryTest.kt | 6 ++- .../ParargraphStyleRepositoryTest.kt | 6 ++- .../persistence/TextStyleRepositoryTest.kt | 6 ++- .../persistence/VariableRepositoryTest.kt | 6 ++- .../VariableStructureRepositoryTest.kt | 8 ++-- .../migration/tools/TestObjectBuilders.kt | 2 - 26 files changed, 86 insertions(+), 78 deletions(-) diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/DisplayRule.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/DisplayRule.kt index faaa55af..88156e25 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/DisplayRule.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/DisplayRule.kt @@ -9,8 +9,8 @@ data class DisplayRule @JvmOverloads constructor( override var originLocations: List = emptyList(), override var customFields: CustomFieldMap, var definition: DisplayRuleDefinition?, - override val created: Instant? = null, - override val lastUpdated: Instant? = null, + override var created: Instant? = null, + override var lastUpdated: Instant? = null, ) : MigrationObject, RefValidatable { override fun collectRefs(): List { return definition?.collectRefs() ?: emptyList() diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/DocumentObject.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/DocumentObject.kt index e150c655..0c8d271b 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/DocumentObject.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/DocumentObject.kt @@ -19,8 +19,8 @@ data class DocumentObject( var variableStructureRef: VariableStructureRef? = null, var baseTemplate: String? = null, var options: DocumentObjectOptions? = null, - override val created: Instant? = null, - override val lastUpdated: Instant? = null, + override var created: Instant? = null, + override var lastUpdated: Instant? = null, val metadata: Map>, val skip: SkipOptions, val subject: String?, diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/File.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/File.kt index 6a58fab2..892f2a9f 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/File.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/File.kt @@ -13,8 +13,8 @@ data class File @JvmOverloads constructor( var targetFolder: String?, var fileType: FileType, val skip: SkipOptions, - override val created: Instant? = null, - override val lastUpdated: Instant? = null, + override var created: Instant? = null, + override var lastUpdated: Instant? = null, ) : MigrationObject, RefValidatable { override fun collectRefs(): List { return emptyList() diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/Image.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/Image.kt index 67216d5b..19968055 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/Image.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/Image.kt @@ -18,8 +18,8 @@ data class Image @JvmOverloads constructor( val metadata: Map>, val skip: SkipOptions, var alternateText: String? = null, - override val created: Instant? = null, - override val lastUpdated: Instant? = null, + override var created: Instant? = null, + override var lastUpdated: Instant? = null, ) : MigrationObject, RefValidatable { override fun collectRefs(): List { return emptyList() diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/ParagraphStyle.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/ParagraphStyle.kt index 00e33a18..03ecf5fd 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/ParagraphStyle.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/ParagraphStyle.kt @@ -16,8 +16,8 @@ data class ParagraphStyle @JvmOverloads constructor( override var originLocations: List = emptyList(), override var customFields: CustomFieldMap, var definition: ParagraphStyleDefOrRef, - override val created: Instant? = null, - override val lastUpdated: Instant? = null, + override var created: Instant? = null, + override var lastUpdated: Instant? = null, ) : MigrationObject, RefValidatable { override fun collectRefs(): List { return when (definition) { diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/Ref.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/Ref.kt index 0126941c..c6f56ad7 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/Ref.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/Ref.kt @@ -14,8 +14,12 @@ import com.quadient.migration.persistence.migrationmodel.TextStyleEntityRef import com.quadient.migration.persistence.migrationmodel.VariableEntityRef import com.quadient.migration.persistence.migrationmodel.VariableStructureEntityRef -sealed interface Ref { +sealed interface Ref : RefValidatable { val id: String + + override fun collectRefs(): List { + return listOf(this) + } } sealed interface TextContent { @@ -64,7 +68,7 @@ data class DocumentObjectRef(override val id: String, val displayRuleRef: Displa fun toDb() = DocumentObjectEntityRef(id, displayRuleRef?.toDb()) } -data class VariableRef(override val id: String) : Ref, TextContent { +data class VariableRef(override val id: String) : Ref, TextContent, RefValidatable { companion object { fun fromDb(entity: VariableEntityRef) = VariableRef(entity.id) } @@ -72,7 +76,7 @@ data class VariableRef(override val id: String) : Ref, TextContent { fun toDb() = VariableEntityRef(id) } -data class TextStyleRef(override val id: String) : Ref, TextStyleDefOrRef { +data class TextStyleRef(override val id: String) : Ref, TextStyleDefOrRef, RefValidatable { companion object { fun fromDb(entity: TextStyleEntityRef) = TextStyleRef(entity.id) } @@ -97,10 +101,6 @@ data class DisplayRuleRef(override val id: String) : Ref { } data class ImageRef(override val id: String) : Ref, DocumentContent, TextContent, RefValidatable { - override fun collectRefs(): List { - return listOf(this) - } - companion object { fun fromDb(entity: ImageEntityRef) = ImageRef(entity.id) } @@ -109,10 +109,6 @@ data class ImageRef(override val id: String) : Ref, DocumentContent, TextContent } data class FileRef(override val id: String) : Ref, DocumentContent, TextContent, RefValidatable { - override fun collectRefs(): List { - return listOf(this) - } - companion object { fun fromDb(entity: FileEntityRef) = FileRef(entity.id) } diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/TextStyle.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/TextStyle.kt index 96a2c9b2..ba9626c8 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/TextStyle.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/TextStyle.kt @@ -12,8 +12,8 @@ data class TextStyle @JvmOverloads constructor( override var originLocations: List = emptyList(), override var customFields: CustomFieldMap, var definition: TextStyleDefOrRef, - override val created: Instant? = null, - override val lastUpdated: Instant? = null, + override var created: Instant? = null, + override var lastUpdated: Instant? = null, ) : MigrationObject, RefValidatable { override fun collectRefs(): List { return when (definition) { diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/Variable.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/Variable.kt index fa82e7db..e3717dc0 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/Variable.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/Variable.kt @@ -10,8 +10,8 @@ data class Variable @JvmOverloads constructor( override var customFields: CustomFieldMap, var dataType: DataType, var defaultValue: String?, - override val created: Instant? = null, - override val lastUpdated: Instant? = null, + override var created: Instant? = null, + override var lastUpdated: Instant? = null, ) : MigrationObject, RefValidatable { override fun collectRefs(): List { return emptyList() diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/VariableStructure.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/VariableStructure.kt index 4c14515e..d9ed9fe5 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/VariableStructure.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/VariableStructure.kt @@ -10,8 +10,8 @@ data class VariableStructure @JvmOverloads constructor( override var customFields: CustomFieldMap, val structure: Map, val languageVariable: VariableRef?, - override val created: Instant? = null, - override val lastUpdated: Instant? = null, + override var created: Instant? = null, + override var lastUpdated: Instant? = null, ) : MigrationObject, RefValidatable { override fun collectRefs(): List { return structure.keys.map { VariableRef(it) } diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/DisplayRuleRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/DisplayRuleRepository.kt index 85427f88..660f713a 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/DisplayRuleRepository.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/DisplayRuleRepository.kt @@ -43,7 +43,7 @@ class DisplayRuleRepository(table: DisplayRuleTable, projectName: String) : val now = Clock.System.now() this[DisplayRuleTable.id] = dto.id - this[DisplayRuleTable.projectName] = projectName + this[DisplayRuleTable.projectName] = this@DisplayRuleRepository.projectName this[DisplayRuleTable.name] = dto.name this[DisplayRuleTable.originLocations] = existingItem?.originLocations.concat(dto.originLocations).distinct() this[DisplayRuleTable.customFields] = dto.customFields.inner @@ -61,7 +61,7 @@ class DisplayRuleRepository(table: DisplayRuleTable, projectName: String) : table.upsertReturning(table.id, table.projectName) { it[DisplayRuleTable.id] = dto.id - it[DisplayRuleTable.projectName] = projectName + it[DisplayRuleTable.projectName] = this@DisplayRuleRepository.projectName it[DisplayRuleTable.name] = dto.name it[DisplayRuleTable.originLocations] = existingItem?.originLocations.concat(dto.originLocations).distinct() it[DisplayRuleTable.customFields] = dto.customFields.inner diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/DocumentObjectRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/DocumentObjectRepository.kt index ef4c9a7d..d2e84985 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/DocumentObjectRepository.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/DocumentObjectRepository.kt @@ -56,7 +56,7 @@ class DocumentObjectRepository(table: DocumentObjectTable, projectName: String) } this[DocumentObjectTable.id] = dto.id - this[DocumentObjectTable.projectName] = projectName + this[DocumentObjectTable.projectName] = this@DocumentObjectRepository.projectName this[DocumentObjectTable.type] = dto.type.name this[DocumentObjectTable.name] = dto.name this[DocumentObjectTable.content] = dto.content.toDb() @@ -95,7 +95,7 @@ class DocumentObjectRepository(table: DocumentObjectTable, projectName: String) table.upsertReturning(table.id, table.projectName) { it[DocumentObjectTable.id] = dto.id - it[DocumentObjectTable.projectName] = projectName + it[DocumentObjectTable.projectName] = this@DocumentObjectRepository.projectName it[DocumentObjectTable.type] = dto.type.name it[DocumentObjectTable.name] = dto.name it[DocumentObjectTable.content] = dto.content.toDb() diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/FileRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/FileRepository.kt index 198a8c37..cb200584 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/FileRepository.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/FileRepository.kt @@ -51,7 +51,7 @@ class FileRepository(table: FileTable, projectName: String) : Repository(t table.upsertReturning(table.id, table.projectName) { it[FileTable.id] = dto.id - it[FileTable.projectName] = projectName + it[FileTable.projectName] = this@FileRepository.projectName it[FileTable.name] = dto.name it[FileTable.originLocations] = existingItem?.originLocations.concat(dto.originLocations).distinct() it[FileTable.customFields] = dto.customFields.inner @@ -76,7 +76,7 @@ class FileRepository(table: FileTable, projectName: String) : Repository(t } this[FileTable.id] = dto.id - this[FileTable.projectName] = projectName + this[FileTable.projectName] = this@FileRepository.projectName this[FileTable.name] = dto.name this[FileTable.originLocations] = existingItem?.originLocations.concat(dto.originLocations).distinct() this[FileTable.customFields] = dto.customFields.inner diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/ImageRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/ImageRepository.kt index 2867467d..54ba022f 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/ImageRepository.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/ImageRepository.kt @@ -55,7 +55,7 @@ class ImageRepository(table: ImageTable, projectName: String) : Repository( - protected open val table: MigrationObjectTable, + protected val table: MigrationObjectTable, protected val projectName: String ) { private val cache = mutableMapOf() diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/TextStyleRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/TextStyleRepository.kt index 2f0d51c0..ac366bad 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/TextStyleRepository.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/TextStyleRepository.kt @@ -73,7 +73,7 @@ class TextStyleRepository(table: TextStyleTable, projectName: String) : table.upsertReturning(table.id, table.projectName) { it[TextStyleTable.id] = dto.id - it[TextStyleTable.projectName] = projectName + it[TextStyleTable.projectName] = this@TextStyleRepository.projectName it[TextStyleTable.name] = dto.name it[TextStyleTable.originLocations] = existingItem?.originLocations.concat(dto.originLocations).distinct() it[TextStyleTable.customFields] = dto.customFields.inner @@ -95,7 +95,7 @@ class TextStyleRepository(table: TextStyleTable, projectName: String) : } this[TextStyleTable.id] = dto.id - this[TextStyleTable.projectName] = projectName + this[TextStyleTable.projectName] = this@TextStyleRepository.projectName this[TextStyleTable.name] = dto.name this[TextStyleTable.originLocations] = existingItem?.originLocations.concat(dto.originLocations).distinct() this[TextStyleTable.customFields] = dto.customFields.inner diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/VariableRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/VariableRepository.kt index 81650151..463aa5ce 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/VariableRepository.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/VariableRepository.kt @@ -14,19 +14,19 @@ import org.jetbrains.exposed.v1.jdbc.transactions.transaction import org.jetbrains.exposed.v1.jdbc.upsertReturning import kotlin.collections.map -class VariableRepository(override val table: VariableTable, projectName: String) : +class VariableRepository(table: VariableTable, projectName: String) : Repository(table, projectName) { override fun fromDb(row: ResultRow): Variable { return Variable( - id = row[table.id].value, - name = row[table.name], - originLocations = row[table.originLocations], - customFields = CustomFieldMap(row[table.customFields].toMutableMap()), - lastUpdated = row[table.lastUpdated], - created = row[table.created], - dataType = DataType.valueOf(row[table.dataType]), - defaultValue = row[table.defaultValue] + id = row[VariableTable.id].value, + name = row[VariableTable.name], + originLocations = row[VariableTable.originLocations], + customFields = CustomFieldMap(row[VariableTable.customFields].toMutableMap()), + lastUpdated = row[VariableTable.lastUpdated], + created = row[VariableTable.created], + dataType = DataType.valueOf(row[VariableTable.dataType]), + defaultValue = row[VariableTable.defaultValue] ) } @@ -45,15 +45,15 @@ class VariableRepository(override val table: VariableTable, projectName: String) val now = Clock.System.now() table.upsertReturning(table.id, table.projectName) { - it[table.id] = dto.id - it[table.projectName] = projectName - it[table.name] = dto.name - it[table.originLocations] = existingItem?.originLocations.concat(dto.originLocations).distinct() - it[table.customFields] = dto.customFields.inner - it[table.created] = existingItem?.created ?: now - it[table.lastUpdated] = now - it[table.dataType] = dto.dataType.toString() - it[table.defaultValue] = dto.defaultValue + it[VariableTable.id] = dto.id + it[VariableTable.projectName] = this@VariableRepository.projectName + it[VariableTable.name] = dto.name + it[VariableTable.originLocations] = existingItem?.originLocations.concat(dto.originLocations).distinct() + it[VariableTable.customFields] = dto.customFields.inner + it[VariableTable.created] = existingItem?.created ?: now + it[VariableTable.lastUpdated] = now + it[VariableTable.dataType] = dto.dataType.toString() + it[VariableTable.defaultValue] = dto.defaultValue }.first() } } @@ -65,7 +65,7 @@ class VariableRepository(override val table: VariableTable, projectName: String) val now = Clock.System.now() this[VariableTable.id] = dto.id - this[VariableTable.projectName] = projectName + this[VariableTable.projectName] = this@VariableRepository.projectName this[VariableTable.name] = dto.name this[VariableTable.originLocations] = existingItem?.originLocations.concat(dto.originLocations).distinct() this[VariableTable.customFields] = dto.customFields.inner diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/VariableStructureRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/VariableStructureRepository.kt index 1c6d88d4..508fc973 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/VariableStructureRepository.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/VariableStructureRepository.kt @@ -46,7 +46,7 @@ class VariableStructureRepository(table: VariableStructureTable, projectName: St table.upsertReturning(table.id, table.projectName) { it[VariableStructureTable.id] = dto.id - it[VariableStructureTable.projectName] = projectName + it[VariableStructureTable.projectName] = this@VariableStructureRepository.projectName it[VariableStructureTable.name] = dto.name it[VariableStructureTable.originLocations] = existingItem?.originLocations.concat(dto.originLocations).distinct() it[VariableStructureTable.customFields] = dto.customFields.inner @@ -65,7 +65,7 @@ class VariableStructureRepository(table: VariableStructureTable, projectName: St val now = Clock.System.now() this[VariableStructureTable.id] = dto.id - this[VariableStructureTable.projectName] = projectName + this[VariableStructureTable.projectName] = this@VariableStructureRepository.projectName this[VariableStructureTable.name] = dto.name this[VariableStructureTable.originLocations] = existingItem?.originLocations.concat(dto.originLocations).distinct() this[VariableStructureTable.customFields] = dto.customFields.inner diff --git a/migration-library/src/test/kotlin/com/quadient/migration/persistence/DisplayRuleRepositoryTest.kt b/migration-library/src/test/kotlin/com/quadient/migration/persistence/DisplayRuleRepositoryTest.kt index f9d7b16b..4ec50032 100644 --- a/migration-library/src/test/kotlin/com/quadient/migration/persistence/DisplayRuleRepositoryTest.kt +++ b/migration-library/src/test/kotlin/com/quadient/migration/persistence/DisplayRuleRepositoryTest.kt @@ -22,8 +22,10 @@ class DisplayRuleRepositoryTest { .build() repo.upsert(dto) - val result = repo.listAll() + val result = repo.listAll().first() + dto.created = result.created + dto.lastUpdated = result.lastUpdated - result.first().shouldBeEqualTo(dto) + result.shouldBeEqualTo(dto) } } \ No newline at end of file diff --git a/migration-library/src/test/kotlin/com/quadient/migration/persistence/FileRepositoryTest.kt b/migration-library/src/test/kotlin/com/quadient/migration/persistence/FileRepositoryTest.kt index cdc1e1b8..77891c6a 100644 --- a/migration-library/src/test/kotlin/com/quadient/migration/persistence/FileRepositoryTest.kt +++ b/migration-library/src/test/kotlin/com/quadient/migration/persistence/FileRepositoryTest.kt @@ -31,9 +31,11 @@ class FileRepositoryTest { .build() repo.upsert(dto) - val result = repo.listAll() + val result = repo.listAll().first() + dto.created = result.created + dto.lastUpdated = result.lastUpdated - result.first().shouldBeEqualTo(dto) + result.shouldBeEqualTo(dto) } @Test diff --git a/migration-library/src/test/kotlin/com/quadient/migration/persistence/ImageRepositoryTest.kt b/migration-library/src/test/kotlin/com/quadient/migration/persistence/ImageRepositoryTest.kt index bef345ab..02ecda44 100644 --- a/migration-library/src/test/kotlin/com/quadient/migration/persistence/ImageRepositoryTest.kt +++ b/migration-library/src/test/kotlin/com/quadient/migration/persistence/ImageRepositoryTest.kt @@ -36,9 +36,11 @@ class ImageRepositoryTest { .build() repo.upsert(dto) - val result = repo.listAll() + val result = repo.listAll().first() + dto.created = result.created + dto.lastUpdated = result.lastUpdated - result.first().shouldBeEqualTo(dto) + result.shouldBeEqualTo(dto) } @Test diff --git a/migration-library/src/test/kotlin/com/quadient/migration/persistence/ParargraphStyleRepositoryTest.kt b/migration-library/src/test/kotlin/com/quadient/migration/persistence/ParargraphStyleRepositoryTest.kt index 6b5586b1..ecbc04ee 100644 --- a/migration-library/src/test/kotlin/com/quadient/migration/persistence/ParargraphStyleRepositoryTest.kt +++ b/migration-library/src/test/kotlin/com/quadient/migration/persistence/ParargraphStyleRepositoryTest.kt @@ -50,9 +50,11 @@ class ParagraphStyleRepositoryTest { }.build() repo.upsert(dto) - val result = repo.listAll() + val result = repo.listAll().first() + dto.created = result.created + dto.lastUpdated = result.lastUpdated - result.first().shouldBeEqualTo(dto) + result.shouldBeEqualTo(dto) } @Test diff --git a/migration-library/src/test/kotlin/com/quadient/migration/persistence/TextStyleRepositoryTest.kt b/migration-library/src/test/kotlin/com/quadient/migration/persistence/TextStyleRepositoryTest.kt index a59c0b68..c730e5cb 100644 --- a/migration-library/src/test/kotlin/com/quadient/migration/persistence/TextStyleRepositoryTest.kt +++ b/migration-library/src/test/kotlin/com/quadient/migration/persistence/TextStyleRepositoryTest.kt @@ -33,9 +33,11 @@ class TextStyleRepositoryTest { }.build() repo.upsert(dto) - val result = repo.listAll() + val result = repo.listAll().first() + dto.created = result.created + dto.lastUpdated = result.lastUpdated - result.first().shouldBeEqualTo(dto) + result.shouldBeEqualTo(dto) } @Test diff --git a/migration-library/src/test/kotlin/com/quadient/migration/persistence/VariableRepositoryTest.kt b/migration-library/src/test/kotlin/com/quadient/migration/persistence/VariableRepositoryTest.kt index 6ab6ce67..3a45c6b1 100644 --- a/migration-library/src/test/kotlin/com/quadient/migration/persistence/VariableRepositoryTest.kt +++ b/migration-library/src/test/kotlin/com/quadient/migration/persistence/VariableRepositoryTest.kt @@ -23,9 +23,11 @@ class VariableRepositoryTest { .build() variableRepo.upsert(dto) - val result = variableRepo.listAll() + val result = variableRepo.listAll().first() + dto.created = result.created + dto.lastUpdated = result.lastUpdated - result.first().shouldBeEqualTo(dto) + result.shouldBeEqualTo(dto) } @Test diff --git a/migration-library/src/test/kotlin/com/quadient/migration/persistence/VariableStructureRepositoryTest.kt b/migration-library/src/test/kotlin/com/quadient/migration/persistence/VariableStructureRepositoryTest.kt index c9a1b20e..6933b161 100644 --- a/migration-library/src/test/kotlin/com/quadient/migration/persistence/VariableStructureRepositoryTest.kt +++ b/migration-library/src/test/kotlin/com/quadient/migration/persistence/VariableStructureRepositoryTest.kt @@ -17,9 +17,11 @@ class VariableStructureRepositoryTest { .addVariable("var2", "Data.Test.Value2").build() repo.upsert(dto) - val result = repo.listAll() + val result = repo.listAll().first() + dto.created = result.created + dto.lastUpdated = result.lastUpdated - result.first().shouldBeEqualTo(dto) - result.first().structure.size.shouldBeEqualTo(2) + result.shouldBeEqualTo(dto) + result.structure.size.shouldBeEqualTo(2) } } \ No newline at end of file diff --git a/migration-library/src/test/kotlin/com/quadient/migration/tools/TestObjectBuilders.kt b/migration-library/src/test/kotlin/com/quadient/migration/tools/TestObjectBuilders.kt index 66986106..2bacb42a 100644 --- a/migration-library/src/test/kotlin/com/quadient/migration/tools/TestObjectBuilders.kt +++ b/migration-library/src/test/kotlin/com/quadient/migration/tools/TestObjectBuilders.kt @@ -227,8 +227,6 @@ fun aVariable( name = name, originLocations = originLocations, customFields = CustomFieldMap(customFields), - created = kotlinx.datetime.Clock.System.now(), - lastUpdated = kotlinx.datetime.Clock.System.now(), dataType = dataType, defaultValue = defaultValue ) From 59c6733f78f8878308201bc02e1963e977baf258 Mon Sep 17 00:00:00 2001 From: "d.svitak" Date: Fri, 6 Feb 2026 14:00:15 +0100 Subject: [PATCH 8/9] remove unwanted fields in builders --- .../api/dto/migrationmodel/builder/DisplayRuleBuilder.kt | 2 -- .../api/dto/migrationmodel/builder/DocumentObjectBuilder.kt | 2 -- 2 files changed, 4 deletions(-) diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/DisplayRuleBuilder.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/DisplayRuleBuilder.kt index 500b7969..a6e565ca 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/DisplayRuleBuilder.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/DisplayRuleBuilder.kt @@ -60,8 +60,6 @@ class DisplayRuleBuilder(id: String) : DtoBuilderBase Date: Fri, 6 Feb 2026 15:33:54 +0100 Subject: [PATCH 9/9] update repositories after main merge --- .../api/repository/DisplayRuleRepository.kt | 8 +-- .../repository/DocumentObjectRepository.kt | 8 +-- .../api/repository/FileRepository.kt | 8 +-- .../api/repository/ImageRepository.kt | 8 +-- .../repository/ParagraphStyleRepository.kt | 8 +-- .../migration/api/repository/Repository.kt | 50 ++++++++++++++----- .../api/repository/TextStyleRepository.kt | 8 +-- .../api/repository/VariableRepository.kt | 8 +-- .../repository/VariableStructureRepository.kt | 8 +-- .../persistence/DisplayRuleRepositoryTest.kt | 5 ++ .../persistence/FileRepositoryTest.kt | 5 ++ .../persistence/ImageRepositoryTest.kt | 6 ++- .../ParargraphStyleRepositoryTest.kt | 5 ++ .../persistence/TextStyleRepositoryTest.kt | 5 ++ .../persistence/VariableRepositoryTest.kt | 5 ++ .../VariableStructureRepositoryTest.kt | 5 ++ 16 files changed, 105 insertions(+), 45 deletions(-) diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/DisplayRuleRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/DisplayRuleRepository.kt index 9f647761..1ea8c265 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/DisplayRuleRepository.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/DisplayRuleRepository.kt @@ -46,17 +46,17 @@ class DisplayRuleRepository(table: DisplayRuleTable, projectName: String) : "id", "project_name", "name", "origin_locations", "custom_fields", "created", "last_updated", "definition" ) - val sql = internalRepository.createSql(columns, dtos.size) + val sql = createSql(columns, dtos.size) val now = Clock.System.now() - internalRepository.upsertBatch(dtos) { + upsertBatchInternal(dtos) { val stmt = it.prepareStatement(sql) var index = 1 dtos.forEach { dto -> - val existingItem = internalRepository.findModel(dto.id) + val existingItem = find(dto.id) stmt.setString(index++, dto.id) - stmt.setString(index++, internalRepository.projectName) + stmt.setString(index++, this@DisplayRuleRepository.projectName) stmt.setString(index++, dto.name) stmt.setArray(index++, it.createArrayOf("text", existingItem?.originLocations.concat(dto.originLocations).distinct().toTypedArray())) stmt.setObject(index++, Json.encodeToString(dto.customFields.inner), Types.OTHER) diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/DocumentObjectRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/DocumentObjectRepository.kt index 93ad0420..af807647 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/DocumentObjectRepository.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/DocumentObjectRepository.kt @@ -52,14 +52,14 @@ class DocumentObjectRepository(table: DocumentObjectTable, projectName: String) "origin_locations", "custom_fields", "created", "last_updated", "display_rule_ref", "variable_structure_ref", "base_template", "options", "metadata", "skip", "subject" ) - val sql = internalRepository.createSql(columns, dtos.size) + val sql = createSql(columns, dtos.size) val now = Clock.System.now() - internalRepository.upsertBatch(dtos) { + upsertBatchInternal(dtos) { val stmt = it.prepareStatement(sql) var index = 1 dtos.forEach { dto -> - val existingItem = internalRepository.findModel(dto.id) + val existingItem = find(dto.id) when (dto.type) { DocumentObjectType.Page -> require(dto.options == null || dto.options is PageOptions) else -> require(dto.options == null || dto.options !is PageOptions) @@ -72,7 +72,7 @@ class DocumentObjectRepository(table: DocumentObjectTable, projectName: String) } stmt.setString(index++, dto.id) - stmt.setString(index++, internalRepository.projectName) + stmt.setString(index++, this@DocumentObjectRepository.projectName) stmt.setString(index++, dto.type.name) stmt.setString(index++, dto.name) stmt.setObject(index++, Json.encodeToString(dto.content.toDb()), Types.OTHER) diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/FileRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/FileRepository.kt index 96061be2..63fd6408 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/FileRepository.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/FileRepository.kt @@ -75,21 +75,21 @@ class FileRepository(table: FileTable, projectName: String) : Repository(t "id", "project_name", "name", "origin_locations", "custom_fields", "created", "last_updated", "source_path", "target_folder", "file_type", "skip" ) - val sql = internalRepository.createSql(columns, dtos.size) + val sql = createSql(columns, dtos.size) val now = Clock.System.now() - internalRepository.upsertBatch(dtos) { + upsertBatchInternal(dtos) { val stmt = it.prepareStatement(sql) var index = 1 dtos.forEach { dto -> - val existingItem = internalRepository.findModel(dto.id) + val existingItem = find(dto.id) if (existingItem == null) { statusTrackingRepository.active(dto.id, ResourceType.File) } stmt.setString(index++, dto.id) - stmt.setString(index++, internalRepository.projectName) + stmt.setString(index++, this@FileRepository.projectName) stmt.setString(index++, dto.name) stmt.setArray(index++, it.createArrayOf("text", existingItem?.originLocations.concat(dto.originLocations).distinct().toTypedArray())) stmt.setObject(index++, Json.encodeToString(dto.customFields.inner), Types.OTHER) diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/ImageRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/ImageRepository.kt index 15fd39ce..47a004e5 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/ImageRepository.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/ImageRepository.kt @@ -83,21 +83,21 @@ class ImageRepository(table: ImageTable, projectName: String) : Repository - val existingItem = internalRepository.findModel(dto.id) + val existingItem = find(dto.id) if (existingItem == null) { statusTrackingRepository.active(dto.id, ResourceType.Image) } stmt.setString(index++, dto.id) - stmt.setString(index++, internalRepository.projectName) + stmt.setString(index++, this@ImageRepository.projectName) stmt.setString(index++, dto.name) stmt.setArray(index++, it.createArrayOf("text", existingItem?.originLocations.concat(dto.originLocations).distinct().toTypedArray())) stmt.setObject(index++, Json.encodeToString(dto.customFields.inner), Types.OTHER) diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/ParagraphStyleRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/ParagraphStyleRepository.kt index 7354af52..3cf10aec 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/ParagraphStyleRepository.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/ParagraphStyleRepository.kt @@ -102,21 +102,21 @@ class ParagraphStyleRepository(table: ParagraphStyleTable, projectName: String) "id", "project_name", "name", "origin_locations", "custom_fields", "created", "last_updated", "definition" ) - val sql = internalRepository.createSql(columns, dtos.size) + val sql = createSql(columns, dtos.size) val now = Clock.System.now() - internalRepository.upsertBatch(dtos) { + upsertBatchInternal(dtos) { val stmt = it.prepareStatement(sql) var index = 1 dtos.forEach { dto -> - val existingItem = internalRepository.findModel(dto.id) + val existingItem = find(dto.id) if (existingItem == null) { statusTrackingRepository.active(dto.id, ResourceType.ParagraphStyle) } stmt.setString(index++, dto.id) - stmt.setString(index++, internalRepository.projectName) + stmt.setString(index++, this@ParagraphStyleRepository.projectName) stmt.setString(index++, dto.name) stmt.setArray(index++, it.createArrayOf("text", existingItem?.originLocations.concat(dto.originLocations).distinct().toTypedArray())) stmt.setObject(index++, Json.encodeToString(dto.customFields.inner), Types.OTHER) diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/Repository.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/Repository.kt index 9c137a53..5fb1367c 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/Repository.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/Repository.kt @@ -18,8 +18,7 @@ import org.jetbrains.exposed.v1.jdbc.selectAll import org.jetbrains.exposed.v1.jdbc.transactions.transaction abstract class Repository( - protected val table: MigrationObjectTable, - protected val projectName: String + protected val table: MigrationObjectTable, protected val projectName: String ) { private val cache = mutableMapOf() private var allCached = false @@ -132,16 +131,36 @@ abstract class Repository( } } - protected fun upsertBatchInternal( - dto: Collection, - block: BatchUpsertStatement.(D) -> Unit - ) { - val ids = dto.map { it.id }.toSet() + fun count(): Long { return transaction { - table.batchUpsert(dto) { - block(it) - } + table.selectAll().where(filter()).count() + } + } + protected fun upsertBatchInternal(dtos: Collection, block: (java.sql.Connection) -> Unit) { + transaction { + block(connection.connection as java.sql.Connection) + } + cacheObjects(dtos) + } + + protected fun createSql(columns: List, dtoCount: Int): String { + val placeholders = (1..columns.size).joinToString(",", prefix = "(", postfix = ")") { "?" } + val values = (1..dtoCount).joinToString(",") { placeholders } + val setOnConflict = columns.filter { it != "created" }.joinToString(", ") { "$it = EXCLUDED.$it" } + + val sql = """ + INSERT INTO ${table.tableName} (${columns.joinToString(", ")}) + VALUES $values + ON CONFLICT (id, project_name) DO UPDATE SET $setOnConflict + """.trimIndent() + + return sql + } + + protected fun cacheObjects(dto: Collection) { + val ids = dto.map { it.id }.toSet() + transaction { for (obj in table.selectAll().where(table.projectName eq projectName and (table.id inList ids)) .map(::fromDb)) { cache[obj.id] = obj @@ -149,8 +168,15 @@ abstract class Repository( } } - protected fun updateCache(id: String, obj: T) { - cache[id] = obj + fun listAllBatched(limit: Int, offset: Long): List { + return transaction { + val result = table.selectAll().orderBy(table.id).limit(limit).offset(offset).where(filter()).map { + val result = fromDb(it) + cache[result.id] = result + result + } + result + } } abstract fun findUsages(id: String): List diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/TextStyleRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/TextStyleRepository.kt index 520c94a5..7625a6d5 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/TextStyleRepository.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/TextStyleRepository.kt @@ -94,21 +94,21 @@ class TextStyleRepository(table: TextStyleTable, projectName: String) : "id", "project_name", "name", "origin_locations", "custom_fields", "created", "last_updated", "definition" ) - val sql = internalRepository.createSql(columns, dtos.size) + val sql = createSql(columns, dtos.size) val now = Clock.System.now() - internalRepository.upsertBatch(dtos) { + upsertBatchInternal(dtos) { val stmt = it.prepareStatement(sql) var index = 1 dtos.forEach { dto -> - val existingItem = internalRepository.findModel(dto.id) + val existingItem = find(dto.id) if (existingItem == null) { statusTrackingRepository.active(dto.id, ResourceType.TextStyle) } stmt.setString(index++, dto.id) - stmt.setString(index++, internalRepository.projectName) + stmt.setString(index++, this@TextStyleRepository.projectName) stmt.setString(index++, dto.name) stmt.setArray(index++, it.createArrayOf("text", existingItem?.originLocations.concat(dto.originLocations).distinct().toTypedArray())) stmt.setObject(index++, Json.encodeToString(dto.customFields.inner), Types.OTHER) diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/VariableRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/VariableRepository.kt index bcbb3f46..b35f0b72 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/VariableRepository.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/VariableRepository.kt @@ -68,17 +68,17 @@ class VariableRepository(table: VariableTable, projectName: String) : "id", "project_name", "name", "origin_locations", "custom_fields", "created", "last_updated", "data_type", "default_value" ) - val sql = internalRepository.createSql(columns, dtos.size) + val sql = createSql(columns, dtos.size) val now = Clock.System.now() - internalRepository.upsertBatch(dtos) { + upsertBatchInternal(dtos) { val stmt = it.prepareStatement(sql) var index = 1 dtos.forEach { dto -> - val existingItem = internalRepository.findModel(dto.id) + val existingItem = find(dto.id) stmt.setString(index++, dto.id) - stmt.setString(index++, internalRepository.projectName) + stmt.setString(index++, this@VariableRepository.projectName) stmt.setString(index++, dto.name) stmt.setArray(index++, it.createArrayOf("text", existingItem?.originLocations.concat(dto.originLocations).distinct().toTypedArray())) stmt.setObject(index++, Json.encodeToString(dto.customFields.inner), Types.OTHER) diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/VariableStructureRepository.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/VariableStructureRepository.kt index aac7ba53..c138c0c3 100644 --- a/migration-library/src/main/kotlin/com/quadient/migration/api/repository/VariableStructureRepository.kt +++ b/migration-library/src/main/kotlin/com/quadient/migration/api/repository/VariableStructureRepository.kt @@ -68,17 +68,17 @@ class VariableStructureRepository(table: VariableStructureTable, projectName: St "id", "project_name", "name", "origin_locations", "custom_fields", "created", "last_updated", "structure", "language_variable" ) - val sql = internalRepository.createSql(columns, dtos.size) + val sql = createSql(columns, dtos.size) val now = Clock.System.now() - internalRepository.upsertBatch(dtos) { + upsertBatchInternal(dtos) { val stmt = it.prepareStatement(sql) var index = 1 dtos.forEach { dto -> - val existingItem = internalRepository.findModel(dto.id) + val existingItem = find(dto.id) stmt.setString(index++, dto.id) - stmt.setString(index++, internalRepository.projectName) + stmt.setString(index++, this@VariableStructureRepository.projectName) stmt.setString(index++, dto.name) stmt.setArray(index++, it.createArrayOf("text", existingItem?.originLocations.concat(dto.originLocations).distinct().toTypedArray())) stmt.setObject(index++, Json.encodeToString(dto.customFields.inner), Types.OTHER) diff --git a/migration-library/src/test/kotlin/com/quadient/migration/persistence/DisplayRuleRepositoryTest.kt b/migration-library/src/test/kotlin/com/quadient/migration/persistence/DisplayRuleRepositoryTest.kt index 3c53d6fd..cff8abc3 100644 --- a/migration-library/src/test/kotlin/com/quadient/migration/persistence/DisplayRuleRepositoryTest.kt +++ b/migration-library/src/test/kotlin/com/quadient/migration/persistence/DisplayRuleRepositoryTest.kt @@ -57,6 +57,11 @@ class DisplayRuleRepositoryTest { val resultRule1 = result.first { it.id == "rule1" } val resultRule2 = result.first { it.id == "rule2" } + rule1.created = resultRule1.created + rule1.lastUpdated = resultRule1.lastUpdated + rule2.created = resultRule2.created + rule2.lastUpdated = resultRule2.lastUpdated + resultRule1.shouldBeEqualTo(rule1) resultRule2.shouldBeEqualTo(rule2) diff --git a/migration-library/src/test/kotlin/com/quadient/migration/persistence/FileRepositoryTest.kt b/migration-library/src/test/kotlin/com/quadient/migration/persistence/FileRepositoryTest.kt index 1c2d7e80..067afce7 100644 --- a/migration-library/src/test/kotlin/com/quadient/migration/persistence/FileRepositoryTest.kt +++ b/migration-library/src/test/kotlin/com/quadient/migration/persistence/FileRepositoryTest.kt @@ -69,6 +69,11 @@ class FileRepositoryTest { val resultFile1 = result.first { it.id == "file1" } val resultFile2 = result.first { it.id == "file2" } + file1.created = resultFile1.created + file1.lastUpdated = resultFile1.lastUpdated + file2.created = resultFile2.created + file2.lastUpdated = resultFile2.lastUpdated + resultFile1.shouldBeEqualTo(file1) resultFile2.shouldBeEqualTo(file2) diff --git a/migration-library/src/test/kotlin/com/quadient/migration/persistence/ImageRepositoryTest.kt b/migration-library/src/test/kotlin/com/quadient/migration/persistence/ImageRepositoryTest.kt index ad89a2dd..43310dcd 100644 --- a/migration-library/src/test/kotlin/com/quadient/migration/persistence/ImageRepositoryTest.kt +++ b/migration-library/src/test/kotlin/com/quadient/migration/persistence/ImageRepositoryTest.kt @@ -8,7 +8,6 @@ import com.quadient.migration.service.deploy.ResourceType import com.quadient.migration.shared.ImageType import com.quadient.migration.tools.aImageRepository import com.quadient.migration.tools.aProjectConfig -import com.quadient.migration.tools.model.aImageInternalRepository import com.quadient.migration.tools.shouldBeEqualTo import com.quadient.migration.tools.shouldBeOfSize import org.junit.jupiter.api.Assertions.assertInstanceOf @@ -83,6 +82,11 @@ class ImageRepositoryTest { val resultImage1 = result.first { it.id == "image1" } val resultImage2 = result.first { it.id == "image2" } + image1.created = resultImage1.created + image1.lastUpdated = resultImage1.lastUpdated + image2.created = resultImage2.created + image2.lastUpdated = resultImage2.lastUpdated + resultImage1.shouldBeEqualTo(image1) resultImage2.shouldBeEqualTo(image2) diff --git a/migration-library/src/test/kotlin/com/quadient/migration/persistence/ParargraphStyleRepositoryTest.kt b/migration-library/src/test/kotlin/com/quadient/migration/persistence/ParargraphStyleRepositoryTest.kt index f8d84e95..88fdfdc4 100644 --- a/migration-library/src/test/kotlin/com/quadient/migration/persistence/ParargraphStyleRepositoryTest.kt +++ b/migration-library/src/test/kotlin/com/quadient/migration/persistence/ParargraphStyleRepositoryTest.kt @@ -120,6 +120,11 @@ class ParagraphStyleRepositoryTest { val resultStyle1 = result.first { it.id == "style1" } val resultStyle2 = result.first { it.id == "style2" } + style1.created = resultStyle1.created + style1.lastUpdated = resultStyle1.lastUpdated + style2.created = resultStyle2.created + style2.lastUpdated = resultStyle2.lastUpdated + resultStyle1.shouldBeEqualTo(style1) resultStyle2.shouldBeEqualTo(style2) diff --git a/migration-library/src/test/kotlin/com/quadient/migration/persistence/TextStyleRepositoryTest.kt b/migration-library/src/test/kotlin/com/quadient/migration/persistence/TextStyleRepositoryTest.kt index 7a637487..700ca8ba 100644 --- a/migration-library/src/test/kotlin/com/quadient/migration/persistence/TextStyleRepositoryTest.kt +++ b/migration-library/src/test/kotlin/com/quadient/migration/persistence/TextStyleRepositoryTest.kt @@ -122,6 +122,11 @@ class TextStyleRepositoryTest { val resultStyle1 = result.first { it.id == "style1" } val resultStyle2 = result.first { it.id == "style2" } + style1.created = resultStyle1.created + style1.lastUpdated = resultStyle1.lastUpdated + style2.created = resultStyle2.created + style2.lastUpdated = resultStyle2.lastUpdated + resultStyle1.shouldBeEqualTo(style1) resultStyle2.shouldBeEqualTo(style2) diff --git a/migration-library/src/test/kotlin/com/quadient/migration/persistence/VariableRepositoryTest.kt b/migration-library/src/test/kotlin/com/quadient/migration/persistence/VariableRepositoryTest.kt index c7a7033c..37f7991f 100644 --- a/migration-library/src/test/kotlin/com/quadient/migration/persistence/VariableRepositoryTest.kt +++ b/migration-library/src/test/kotlin/com/quadient/migration/persistence/VariableRepositoryTest.kt @@ -101,6 +101,11 @@ class VariableRepositoryTest { val resultVar1 = result.first { it.id == "var1" } val resultVar2 = result.first { it.id == "var2" } + var1.created = resultVar1.created + var1.lastUpdated = resultVar1.lastUpdated + var2.created = resultVar2.created + var2.lastUpdated = resultVar2.lastUpdated + resultVar1.shouldBeEqualTo(var1) resultVar2.shouldBeEqualTo(var2) diff --git a/migration-library/src/test/kotlin/com/quadient/migration/persistence/VariableStructureRepositoryTest.kt b/migration-library/src/test/kotlin/com/quadient/migration/persistence/VariableStructureRepositoryTest.kt index 1d96809d..fd78339c 100644 --- a/migration-library/src/test/kotlin/com/quadient/migration/persistence/VariableStructureRepositoryTest.kt +++ b/migration-library/src/test/kotlin/com/quadient/migration/persistence/VariableStructureRepositoryTest.kt @@ -56,6 +56,11 @@ class VariableStructureRepositoryTest { val resultStruct1 = result.first { it.id == "struct1" } val resultStruct2 = result.first { it.id == "struct2" } + struct1.created = resultStruct1.created + struct1.lastUpdated = resultStruct1.lastUpdated + struct2.created = resultStruct2.created + struct2.lastUpdated = resultStruct2.lastUpdated + resultStruct1.shouldBeEqualTo(struct1) resultStruct2.shouldBeEqualTo(struct2) resultStruct1.structure.size.shouldBeEqualTo(2)