Skip to content

Updated ContactMapper for participantList deserialization with new SDK#282

Merged
TestaDiRapa merged 2 commits intomainfrom
patch/sdk-version-aware-inverse-mapping-of-contact
Mar 9, 2026
Merged

Updated ContactMapper for participantList deserialization with new SDK#282
TestaDiRapa merged 2 commits intomainfrom
patch/sdk-version-aware-inverse-mapping-of-contact

Conversation

@TestaDiRapa
Copy link
Collaborator

No description provided.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the v2 contact mapping layer to support participantList deserialization behavior for the newer Cardinal SDK model by introducing a version/config switch and propagating suspendable mapping through controllers and pagination helpers.

Changes:

  • Add CardinalVersionConfig and use it in ContactV2Mapper to decide whether to map participants vs participantList.
  • Convert several v2 mappers and mapping call-sites to suspend to allow config-dependent (potentially I/O) mapping decisions.
  • Update pagination utilities to accept suspend mappers and bump kmap version; remove multiple mapper unit test files.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
mapper/src/test/kotlin/org/taktik/icure/services/external/rest/v2/mapper/ContactMapperTest.kt Deleted v2 contact mapper tests that previously covered participants/participantList behavior.
mapper/src/test/kotlin/org/taktik/icure/services/external/rest/v1/mapper/embed/MeasureMapperTest.kt Deleted v1 measure mapper tests.
mapper/src/test/kotlin/org/taktik/icure/services/external/rest/v1/mapper/ContactMapperTest.kt Deleted v1 contact mapper tests.
mapper/src/main/kotlin/org/taktik/icure/services/external/rest/v2/mapper/requests/ContactBulkShareResultV2Mapper.kt Makes mapping suspend to align with suspend ContactV2Mapper.map.
mapper/src/main/kotlin/org/taktik/icure/services/external/rest/v2/mapper/embed/ImportResultMapper.kt Makes import result mapping suspend (transitively depends on suspend mappers).
mapper/src/main/kotlin/org/taktik/icure/services/external/rest/v2/mapper/ContactMapper.kt Adds config-driven participant mapping logic and makes mapper methods suspend.
libs.versions.toml Updates kmap version (now includes a -dirty suffix).
domain/src/main/kotlin/org/taktik/icure/pagination/PaginationUtils.kt Changes mapElements to accept a suspend mapper.
domain/src/main/kotlin/org/taktik/icure/config/CardinalVersionConfig.kt Introduces new config interface used by mapping layer.
core/src/main/kotlin/org/taktik/icure/services/external/rest/v2/utils/FlowUtils.kt Changes paginatedList mapper parameter to suspend.
core/src/main/kotlin/org/taktik/icure/services/external/rest/v2/controllers/core/ContactController.kt Adapts controller endpoints to suspend mapping; removes deduplicate param from /match.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +450 to +452
): Flux<ContactDto> = flow {
val contacts = contactService.createContacts(contactDtos.map { f -> contactV2Mapper.map(f) })
return contacts.map { f -> contactV2Mapper.map(f) }.injectReactorContext()
}
emitAll(contacts.map { f -> contactV2Mapper.map(f) })
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue as above: contactDtos.map { ... } uses the non-suspending List.map but calls the suspending contactV2Mapper.map(...), which will not compile. Please perform the DTO->entity mapping using a suspend-capable approach (e.g. via asFlow().map { ... }.toList() inside the flow {}) before passing the collection to contactService.createContacts(...).

Copilot uses AI. Check for mistakes.
Comment on lines 474 to 478
@Operation(summary = "Get the ids of the Contacts matching the provided filter.")
@PostMapping("/match", produces = [APPLICATION_JSON_VALUE])
fun matchContactsBy(
@RequestBody filter: AbstractFilterDto<ContactDto>,
@RequestParam(required = false) deduplicate: Boolean? = null,
): Flux<String> = contactService
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The deduplicate query parameter was removed from the public /rest/v2/contact/match endpoint. Even if it was unused, removing it is a breaking API change for clients still sending the parameter. Consider keeping it (possibly deprecated/ignored) or ensuring this change is versioned/communicated appropriately.

Copilot uses AI. Check for mistakes.
Comment on lines +5 to +13
interface CardinalVersionConfig {

companion object {
val minCardinalModelVersion = SemanticVersion("2.0.0")
}

suspend fun getUserCardinalVersion(): SemanticVersion?

suspend fun shouldUseCardinalModel(): Boolean
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CardinalVersionConfig is introduced as a dependency and is now injected into ContactV2Mapper (via uses = [...]). In this repo there is currently no Spring bean implementing this interface, so application startup will fail with an unsatisfied dependency when the mapper is created. Provide a default implementation (e.g. in core under the app profile) or otherwise ensure a bean is defined wherever these mappers/controllers are used.

Copilot uses AI. Check for mistakes.
kotest = "5.9.1"
hibernateValidator = "8.0.1.Final"
kmap = "0.1.84-g107c985e93"
kmap = "0.1.92-gd1d925cb84-dirty"
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The kmap version is set to a -dirty build identifier. This is typically not reproducible and is often not published to artifact repositories, which can break dependency resolution in CI/release builds. Prefer pinning to a clean, published version/tag (without -dirty) or a released semver.

Copilot uses AI. Check for mistakes.
Comment on lines +78 to +80
it.groupingBy { participantDto -> participantDto.type }.eachCount().any { entry -> entry.value > 1 } // If there are multiple participant with the same type
|| it.any { (type) -> type == ParticipantTypeDto.Recorder } // or at least one participant with type "Recorder"
|| cardinalVersionConfig.shouldUseCardinalModel() // or the contact was created with the Cardinal SDK
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment typos: "multiple participant" should be "multiple participants".

Copilot uses AI. Check for mistakes.
Comment on lines +441 to +443
): Flux<ContactDto> = flow {
val contacts = contactService.modifyContacts(contactDtos.map { f -> contactV2Mapper.map(f) })
return contacts.map { f -> contactV2Mapper.map(f) }.injectReactorContext()
}
emitAll(contacts.map { f -> contactV2Mapper.map(f) })
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this flow {} block, contactDtos.map { ... } is the stdlib List.map, whose lambda is not suspend. Since contactV2Mapper.map(...) is now suspend, this will not compile. Convert the list to a Flow and map with a suspend lambda (or otherwise perform the DTO->entity mapping in a suspend-aware way) before calling contactService.modifyContacts(...).

Copilot uses AI. Check for mistakes.
@TestaDiRapa TestaDiRapa merged commit 196cdb6 into main Mar 9, 2026
@TestaDiRapa TestaDiRapa deleted the patch/sdk-version-aware-inverse-mapping-of-contact branch March 9, 2026 14:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants