Skip to content

Commit

Permalink
6486 implement patient merge (#6568)
Browse files Browse the repository at this point in the history
* begin with failing test

* wpi merge operation provider

* wip code resolve references and some refactoring

* respect status code set in providers

* more validation and code to update resources after refs are updated

* added source-delete parameter and some validation tests on result-patient

* update test

* update test

* return target patient as output parameter, do not add replacedby link to target if src is to be deleted

* output definition

* ignore identifiers in ref, more unit tests, return target in preview mode

* output definition

* return input parameters in the merge operation output

* copy identifiers from source to target (no duplicate check)

* add shared identifier

* add shared identifier

* moar asserts

* moar asserts

* fixing result patient

* fixing result patient

* fixing result patient

* add duplicate check when copying source identifiers to target

* copy result-patient before passing it to service

* add preview to test

* update preview asserts

* move IReplaceReferencesSvc to storage-package, and call replaceReference in patient merge

* moar tests

* cleanup

* add task test

* add replace references test

* kebab-case replace references

* add sync -> async switch

* test

* test

* start migrating to stream

* validate result-patient does not have link to source if delete-source is true

* add update count to msg in preview mode

* spotless

* change page size -> batch size and create new default max in storage settings

* spotless

* switched to patch transaction

* switched to patch transaction

* switched to patch transaction

* switched to patch transaction

* strip version from returned task

* spotless

* spotless

* async replace references test passes

* align tests

* test small batch size

* do src and target updates in trx, add validation src is not already replaced

* start building batch 2
improve dao

* start building batch 2
improve dao

* start building batch 2
improve dao

* move test setup out to helper

* move replace references tests out

* switch helper to use dao

* incresed unit test coverage

* build out batch

* build out batch

* update test to add link to result-patient only if the source is not to be deleted

* batch passes test

* batch passes test

* batch passes test

* made patient-merge return the Task returned from replace references

* batch passes test

* batch passes test

* consolidate async and sync supporting methods into a single storage service

* consolidate async and sync supporting methods into a single storage service

* add merge batch job

* add merge batch job

* added FIXMES for ED

* added FIXMES for ED

* update test to not validate task in preview mode

* mark identfier copied from source to target as old

* copyright headers

* runMaintenancePass before checking merge task status, and renamed test method for merge

* fix test

* fix test

* default

* invoke async merge job in merge service

* starting work on new docs

* starting work on new docs

* document $replace-references

* separate default from max

* fixme

* moar fixme

* moar fixme

* ken last fixme

* return 202 status on async merge, update MergeBatchTest to do more validations

* async success message, inject mergeservice, add async merge unit tests

* make validatePatchResultBundle static again

* added test for adding reference while merge in progress, and merge error handler

* fixed

* fixed

* added error handler to replace references job

* review

* javadoc

* organize imports

* make ValidationResult immutable

* make ValidationResult immutable

* rename ReplaceReferencesRequest

* rename ReplaceReferencesRequest

* rename MergeResourceHelper

* rename MergeResourceHelper

* javadoc

* split merge validation service out from merge service

* split merge validation service out from merge service

* split merge validation service out from merge service

* review feedback

* review feedback

* rename param constants

* rename param constants

* remove IdentifierUtil for visibility

* remove IdentifierUtil for visibility

* final review of hapi side

* review feedback

* review feedback

* fix checkstyle errors, rename MergeOperationInputParameters and add Msg.code

* fix replace reference parameter type, and some copyright headers

* review feedback

* review feedback

* review feedback

* review feedback

* review feedback

* review feedback

* review feedback

* review feedback

* move $merge into JPA R4

* move $merge into JPA R4

* still need to return 412

* still need to return 412

* return 412

* moar tests

* moar tests

* fix async batch size

* fix async batch size

* fix async batch size

* exception code

* exception code

* fix bean wiring

* fix bean wiring

* fix test

* fix test

* fix test

* fix test

* fix test

* bump pom versions

---------

Co-authored-by: Ken Stevens <[email protected]>
  • Loading branch information
mrdnctrk and Ken Stevens authored Dec 24, 2024
1 parent 3594770 commit 4feb489
Show file tree
Hide file tree
Showing 146 changed files with 6,383 additions and 364 deletions.
2 changes: 1 addition & 1 deletion hapi-deployable-pom/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>7.7.15-SNAPSHOT</version>
<version>7.7.16-SNAPSHOT</version>

<relativePath>../pom.xml</relativePath>
</parent>
Expand Down
2 changes: 1 addition & 1 deletion hapi-fhir-android/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>7.7.15-SNAPSHOT</version>
<version>7.7.16-SNAPSHOT</version>

<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
Expand Down
2 changes: 1 addition & 1 deletion hapi-fhir-base/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>7.7.15-SNAPSHOT</version>
<version>7.7.16-SNAPSHOT</version>

<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -265,30 +265,48 @@ public static IBase addIssueWithMessageId(
}

public static void addDetailsToIssue(FhirContext theFhirContext, IBase theIssue, String theSystem, String theCode) {
addDetailsToIssue(theFhirContext, theIssue, theSystem, theCode, null);
}

public static void addDetailsToIssue(
FhirContext theFhirContext, IBase theIssue, String theSystem, String theCode, String theText) {
BaseRuntimeElementCompositeDefinition<?> issueElement =
(BaseRuntimeElementCompositeDefinition<?>) theFhirContext.getElementDefinition(theIssue.getClass());
BaseRuntimeChildDefinition detailsChildDef = issueElement.getChildByName("details");

BaseRuntimeElementCompositeDefinition<?> codingDef =
(BaseRuntimeElementCompositeDefinition<?>) theFhirContext.getElementDefinition("Coding");
ICompositeType coding = (ICompositeType) codingDef.newInstance();

// System
IPrimitiveType<?> system =
(IPrimitiveType<?>) theFhirContext.getElementDefinition("uri").newInstance();
system.setValueAsString(theSystem);
codingDef.getChildByName("system").getMutator().addValue(coding, system);

// Code
IPrimitiveType<?> code =
(IPrimitiveType<?>) theFhirContext.getElementDefinition("code").newInstance();
code.setValueAsString(theCode);
codingDef.getChildByName("code").getMutator().addValue(coding, code);
BaseRuntimeElementCompositeDefinition<?> ccDef =
(BaseRuntimeElementCompositeDefinition<?>) theFhirContext.getElementDefinition("CodeableConcept");

ICompositeType codeableConcept = (ICompositeType) ccDef.newInstance();
ccDef.getChildByName("coding").getMutator().addValue(codeableConcept, coding);

if (isNotBlank(theSystem) || isNotBlank(theCode)) {
BaseRuntimeElementCompositeDefinition<?> codingDef =
(BaseRuntimeElementCompositeDefinition<?>) theFhirContext.getElementDefinition("Coding");
ICompositeType coding = (ICompositeType) codingDef.newInstance();

// System
if (isNotBlank(theSystem)) {
IPrimitiveType<?> system = (IPrimitiveType<?>)
theFhirContext.getElementDefinition("uri").newInstance();
system.setValueAsString(theSystem);
codingDef.getChildByName("system").getMutator().addValue(coding, system);
}

// Code
if (isNotBlank(theCode)) {
IPrimitiveType<?> code = (IPrimitiveType<?>)
theFhirContext.getElementDefinition("code").newInstance();
code.setValueAsString(theCode);
codingDef.getChildByName("code").getMutator().addValue(coding, code);
}

ccDef.getChildByName("coding").getMutator().addValue(codeableConcept, coding);
}

if (isNotBlank(theText)) {
IPrimitiveType<?> textElem = (IPrimitiveType<?>)
ccDef.getChildByName("text").getChildByName("text").newInstance(theText);
ccDef.getChildByName("text").getMutator().addValue(codeableConcept, textElem);
}

detailsChildDef.getMutator().addValue(theIssue, codeableConcept);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*-
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2024 Smile CDR, Inc.
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
package ca.uhn.fhir.util;

import jakarta.annotation.Nonnull;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Stream;

/**
* This class collects items from a stream to a given limit and know whether there are
* still more items beyond that limit.
*
* @param <T> the type of object being streamed
*/
public class StopLimitAccumulator<T> {
private final boolean isTruncated;
private final List<T> myList;

private StopLimitAccumulator(List<T> theList, boolean theIsTruncated) {
myList = Collections.unmodifiableList(theList);
isTruncated = theIsTruncated;
}

public static <T> StopLimitAccumulator<T> fromStreamAndLimit(@Nonnull Stream<T> theItemStream, long theLimit) {
assert theLimit > 0;
AtomicBoolean isBeyondLimit = new AtomicBoolean(false);
List<T> accumulator = new ArrayList<>();

theItemStream
.limit(theLimit + 1) // Fetch one extra item to see if there are any more items past our limit
.forEach(item -> {
if (accumulator.size() < theLimit) {
accumulator.add(item);
} else {
isBeyondLimit.set(true);
}
});
return new StopLimitAccumulator<>(accumulator, isBeyondLimit.get());
}

public boolean isTruncated() {
return isTruncated;
}

public List<T> getItemList() {
return myList;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package ca.uhn.fhir.util;

import org.junit.jupiter.api.Test;

import java.util.List;
import java.util.stream.Stream;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;

class StopLimitAccumulatorTest {

@Test
void testFromStreamAndLimit_withNoTruncation() {
// setup
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);
int limit = 5;

// execute
StopLimitAccumulator<Integer> accumulator = StopLimitAccumulator.fromStreamAndLimit(stream, limit);

// verify
assertFalse(accumulator.isTruncated(), "The result should not be truncated");
assertEquals(List.of(1, 2, 3, 4, 5), accumulator.getItemList(), "The list should contain all items within the limit");
}

@Test
void testFromStreamAndLimit_withTruncation() {
// setup
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6, 7);
int limit = 5;

// execute
StopLimitAccumulator<Integer> accumulator = StopLimitAccumulator.fromStreamAndLimit(stream, limit);

// verify
assertTrue(accumulator.isTruncated(), "The result should be truncated");
assertEquals(List.of(1, 2, 3, 4, 5), accumulator.getItemList(), "The list should contain only the items within the limit");
}

@Test
void testFromStreamAndLimit_withEmptyStream() {
// setup
Stream<Integer> stream = Stream.empty();
int limit = 5;

// execute
StopLimitAccumulator<Integer> accumulator = StopLimitAccumulator.fromStreamAndLimit(stream, limit);

// verify
assertFalse(accumulator.isTruncated(), "The result should not be truncated for an empty stream");
assertTrue(accumulator.getItemList().isEmpty(), "The list should be empty");
}

@Test
void testImmutabilityOfItemList() {
// setup
Stream<Integer> stream = Stream.of(1, 2, 3);
int limit = 3;

StopLimitAccumulator<Integer> accumulator = StopLimitAccumulator.fromStreamAndLimit(stream, limit);

// execute and Assert
List<Integer> itemList = accumulator.getItemList();
assertThrows(UnsupportedOperationException.class, () -> itemList.add(4), "The list should be immutable");
}
}
4 changes: 2 additions & 2 deletions hapi-fhir-bom/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@
<modelVersion>4.0.0</modelVersion>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-bom</artifactId>
<version>7.7.15-SNAPSHOT</version>
<version>7.7.16-SNAPSHOT</version>

<packaging>pom</packaging>
<name>HAPI FHIR BOM</name>

<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>7.7.15-SNAPSHOT</version>
<version>7.7.16-SNAPSHOT</version>

<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
Expand Down
2 changes: 1 addition & 1 deletion hapi-fhir-checkstyle/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>7.7.15-SNAPSHOT</version>
<version>7.7.16-SNAPSHOT</version>

<relativePath>../pom.xml</relativePath>
</parent>
Expand Down
2 changes: 1 addition & 1 deletion hapi-fhir-cli/hapi-fhir-cli-api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>7.7.15-SNAPSHOT</version>
<version>7.7.16-SNAPSHOT</version>

<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
</parent>
Expand Down
2 changes: 1 addition & 1 deletion hapi-fhir-cli/hapi-fhir-cli-app/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-cli</artifactId>
<version>7.7.15-SNAPSHOT</version>
<version>7.7.16-SNAPSHOT</version>

<relativePath>../pom.xml</relativePath>
</parent>
Expand Down
2 changes: 1 addition & 1 deletion hapi-fhir-cli/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>7.7.15-SNAPSHOT</version>
<version>7.7.16-SNAPSHOT</version>

<relativePath>../pom.xml</relativePath>
</parent>
Expand Down
2 changes: 1 addition & 1 deletion hapi-fhir-client-apache-http5/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>7.7.15-SNAPSHOT</version>
<version>7.7.16-SNAPSHOT</version>

<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
Expand Down
2 changes: 1 addition & 1 deletion hapi-fhir-client-okhttp/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>7.7.15-SNAPSHOT</version>
<version>7.7.16-SNAPSHOT</version>

<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
Expand Down
2 changes: 1 addition & 1 deletion hapi-fhir-client/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>7.7.15-SNAPSHOT</version>
<version>7.7.16-SNAPSHOT</version>

<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
Expand Down
2 changes: 1 addition & 1 deletion hapi-fhir-converter/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>7.7.15-SNAPSHOT</version>
<version>7.7.16-SNAPSHOT</version>

<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
Expand Down
2 changes: 1 addition & 1 deletion hapi-fhir-dist/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>7.7.15-SNAPSHOT</version>
<version>7.7.16-SNAPSHOT</version>

<relativePath>../pom.xml</relativePath>
</parent>
Expand Down
2 changes: 1 addition & 1 deletion hapi-fhir-docs/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>7.7.15-SNAPSHOT</version>
<version>7.7.16-SNAPSHOT</version>

<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
Expand Down
2 changes: 1 addition & 1 deletion hapi-fhir-jacoco/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>7.7.15-SNAPSHOT</version>
<version>7.7.16-SNAPSHOT</version>

<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
Expand Down
2 changes: 1 addition & 1 deletion hapi-fhir-jaxrsserver-base/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>7.7.15-SNAPSHOT</version>
<version>7.7.16-SNAPSHOT</version>

<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
Expand Down
2 changes: 1 addition & 1 deletion hapi-fhir-jpa/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>7.7.15-SNAPSHOT</version>
<version>7.7.16-SNAPSHOT</version>

<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
Expand Down
2 changes: 1 addition & 1 deletion hapi-fhir-jpaserver-base/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>7.7.15-SNAPSHOT</version>
<version>7.7.16-SNAPSHOT</version>

<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
Expand Down
Loading

0 comments on commit 4feb489

Please sign in to comment.