Merge branch 'improve-bundle-builder' into issue-2534-new-tx-pointcut

This commit is contained in:
Tadgh 2021-04-21 16:53:49 -04:00
commit a5f81988fc
73 changed files with 355 additions and 474 deletions

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -24,6 +24,7 @@ import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
import ca.uhn.fhir.context.BaseRuntimeElementDefinition;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.model.primitive.IdDt;
import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseBackboneElement;
@ -194,6 +195,45 @@ public class BundleBuilder {
return new CreateBuilder(request);
}
/**
* Adds an entry containing a delete (DELETE) request.
* Also sets the Bundle.type value to "transaction" if it is not already set.
*
* Note that the resource is only used to extract its ID and type, and the body of the resource is not included in the entry,
*
* @param theResource The resource to delete.
*/
public void addTransactionDeleteEntry(IBaseResource theResource) {
String resourceType = myContext.getResourceType(theResource);
String idPart = theResource.getIdElement().toUnqualifiedVersionless().getIdPart();
addTransactionDeleteEntry(resourceType, idPart);
}
/**
* Adds an entry containing a delete (DELETE) request.
* Also sets the Bundle.type value to "transaction" if it is not already set.
*
* @param theResourceType The type resource to delete.
* @param theIdPart the ID of the resource to delete.
*/
public void addTransactionDeleteEntry(String theResourceType, String theIdPart) {
setBundleField("type", "transaction");
IBase request = addEntryAndReturnRequest();
IdDt idDt = new IdDt(theIdPart);
// Bundle.entry.request.url
IPrimitiveType<?> url = (IPrimitiveType<?>) myContext.getElementDefinition("uri").newInstance();
url.setValueAsString(idDt.toUnqualifiedVersionless().withResourceType(theResourceType).getValue());
myEntryRequestUrlChild.getMutator().setValue(request, url);
// Bundle.entry.request.method
IPrimitiveType<?> method = (IPrimitiveType<?>) myEntryRequestMethodDef.newInstance(myEntryRequestMethodChild.getInstanceConstructorArguments());
method.setValueAsString("DELETE");
myEntryRequestMethodChild.getMutator().setValue(request, method);
}
/**
* Adds an entry for a Collection bundle type
*/
@ -251,6 +291,16 @@ public class BundleBuilder {
return request;
}
public IBase addEntryAndReturnRequest() {
IBase entry = addEntry();
// Bundle.entry.request
IBase request = myEntryRequestDef.newInstance();
myEntryRequestChild.getMutator().setValue(entry, request);
return request;
}
public IBaseBundle getBundle() {
return myBundle;

View File

@ -25,6 +25,7 @@ import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition;
import ca.uhn.fhir.context.BaseRuntimeElementDefinition;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import org.apache.commons.lang3.tuple.Triple;
import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.slf4j.Logger;
@ -48,9 +49,15 @@ public final class TerserUtil {
private static final String EQUALS_DEEP = "equalsDeep";
/**
* Exclude for id, identifier and meta fields of a resource.
*/
public static final Collection<String> IDS_AND_META_EXCLUDES =
Collections.unmodifiableSet(Stream.of("id", "identifier", "meta").collect(Collectors.toSet()));
/**
* Exclusion predicate for id, identifier, meta fields.
*/
public static final Predicate<String> EXCLUDE_IDS_AND_META = new Predicate<String>() {
@Override
public boolean test(String s) {
@ -58,6 +65,25 @@ public final class TerserUtil {
}
};
/**
* Exclusion predicate for id/identifier, meta and fields with empty values. This ensures that source / target resources,
* empty source fields will not results in erasure of target fields.
*/
public static final Predicate<Triple<BaseRuntimeChildDefinition, IBase, IBase>> EXCLUDE_IDS_META_AND_EMPTY = new Predicate<Triple<BaseRuntimeChildDefinition, IBase, IBase>>() {
@Override
public boolean test(Triple<BaseRuntimeChildDefinition, IBase, IBase> theTriple) {
if (!EXCLUDE_IDS_AND_META.test(theTriple.getLeft().getElementName())) {
return false;
}
BaseRuntimeChildDefinition childDefinition = theTriple.getLeft();
boolean isSourceFieldEmpty = childDefinition.getAccessor().getValues(theTriple.getMiddle()).isEmpty();
return !isSourceFieldEmpty;
}
};
/**
* Exclusion predicate for keeping all fields.
*/
public static final Predicate<String> INCLUDE_ALL = new Predicate<String>() {
@Override
public boolean test(String s) {
@ -235,24 +261,35 @@ public final class TerserUtil {
}
/**
* Replaces all fields that test positive by the given inclusion strategy. <code>theTo</code> will contain a copy of the
* Replaces all fields that have matching field names by the given inclusion strategy. <code>theTo</code> will contain a copy of the
* values from <code>theFrom</code> instance.
*
* @param theFhirContext Context holding resource definition
* @param theFrom The resource to merge the fields from
* @param theTo The resource to merge the fields into
* @param inclusionStrategy Inclusion strategy that checks if a given field should be replaced by checking {@link Predicate#test(Object)}
* @param theFhirContext Context holding resource definition
* @param theFrom The resource to merge the fields from
* @param theTo The resource to merge the fields into
* @param theFieldNameInclusion Inclusion strategy that checks if a given field should be replaced
*/
public static void replaceFields(FhirContext theFhirContext, IBaseResource theFrom, IBaseResource theTo, Predicate<String> inclusionStrategy) {
FhirTerser terser = theFhirContext.newTerser();
public static void replaceFields(FhirContext theFhirContext, IBaseResource theFrom, IBaseResource theTo, Predicate<String> theFieldNameInclusion) {
Predicate<Triple<BaseRuntimeChildDefinition, IBase, IBase>> predicate
= (t) -> theFieldNameInclusion.test(t.getLeft().getElementName());
replaceFieldsByPredicate(theFhirContext, theFrom, theTo, predicate);
}
/**
* Replaces fields on theTo resource that test positive by the given predicate. <code>theTo</code> will contain a copy of the
* values from <code>theFrom</code> for which predicate tests positive. Please note that composite fields will be replaced fully.
*
* @param theFhirContext Context holding resource definition
* @param theFrom The resource to merge the fields from
* @param theTo The resource to merge the fields into
* @param thePredicate Predicate that checks if a given field should be replaced
*/
public static void replaceFieldsByPredicate(FhirContext theFhirContext, IBaseResource theFrom, IBaseResource theTo, Predicate<Triple<BaseRuntimeChildDefinition, IBase, IBase>> thePredicate) {
RuntimeResourceDefinition definition = theFhirContext.getResourceDefinition(theFrom);
for (BaseRuntimeChildDefinition childDefinition : definition.getChildrenAndExtension()) {
if (!inclusionStrategy.test(childDefinition.getElementName())) {
continue;
if (thePredicate.test(Triple.of(childDefinition, theFrom, theTo))) {
replaceField(theFrom, theTo, childDefinition);
}
replaceField(theFrom, theTo, childDefinition);
}
}
@ -277,14 +314,11 @@ public final class TerserUtil {
* @param theTo The resource to replace the field on
*/
public static void replaceField(FhirContext theFhirContext, String theFieldName, IBaseResource theFrom, IBaseResource theTo) {
replaceField(theFhirContext, theFhirContext.newTerser(), theFieldName, theFrom, theTo);
}
/**
* @deprecated Use {@link #replaceField(FhirContext, String, IBaseResource, IBaseResource)} instead
*/
public static void replaceField(FhirContext theFhirContext, FhirTerser theTerser, String theFieldName, IBaseResource theFrom, IBaseResource theTo) {
replaceField(theFrom, theTo, getBaseRuntimeChildDefinition(theFhirContext, theFieldName, theFrom));
RuntimeResourceDefinition definition = theFhirContext.getResourceDefinition(theFrom);
if (definition == null) {
throw new IllegalArgumentException(String.format("Field %s does not exist in %s", theFieldName, theFrom));
}
replaceField(theFrom, theTo, theFhirContext.getResourceDefinition(theFrom).getChildByName(theFieldName));
}
/**
@ -301,7 +335,7 @@ public final class TerserUtil {
/**
* Sets the provided field with the given values. This method will add to the collection of existing field values
* in case of multiple cardinality. Use {@link #clearField(FhirContext, FhirTerser, String, IBaseResource, IBase...)}
* in case of multiple cardinality. Use {@link #clearField(FhirContext, String, IBaseResource)}
* to remove values before setting
*
* @param theFhirContext Context holding resource definition
@ -315,7 +349,7 @@ public final class TerserUtil {
/**
* Sets the provided field with the given values. This method will add to the collection of existing field values
* in case of multiple cardinality. Use {@link #clearField(FhirContext, FhirTerser, String, IBaseResource, IBase...)}
* in case of multiple cardinality. Use {@link #clearField(FhirContext, String, IBaseResource)}
* to remove values before setting
*
* @param theFhirContext Context holding resource definition
@ -370,10 +404,26 @@ public final class TerserUtil {
setFieldByFhirPath(theFhirContext.newTerser(), theFhirPath, theResource, theValue);
}
/**
* Returns field values ant the specified FHIR path from the resource.
*
* @param theFhirContext Context holding resource definition
* @param theFhirPath The FHIR path to get the field from
* @param theResource The resource from which the value should be retrieved
* @return Returns the list of field values at the given FHIR path
*/
public static List<IBase> getFieldByFhirPath(FhirContext theFhirContext, String theFhirPath, IBase theResource) {
return theFhirContext.newTerser().getValues(theResource, theFhirPath, false, false);
}
/**
* Returns the first available field value at the specified FHIR path from the resource.
*
* @param theFhirContext Context holding resource definition
* @param theFhirPath The FHIR path to get the field from
* @param theResource The resource from which the value should be retrieved
* @return Returns the first available value or null if no values can be retrieved
*/
public static IBase getFirstFieldByFhirPath(FhirContext theFhirContext, String theFhirPath, IBase theResource) {
List<IBase> values = getFieldByFhirPath(theFhirContext, theFhirPath, theResource);
if (values == null || values.isEmpty()) {

View File

@ -11,5 +11,4 @@ public class PlaceholderTest {
public void testPass() {
// nothing
}
}

View File

@ -3,14 +3,14 @@
<modelVersion>4.0.0</modelVersion>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-bom</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<packaging>pom</packaging>
<name>HAPI FHIR BOM</name>
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -31,6 +31,7 @@ import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
@ -70,6 +71,9 @@ public abstract class BaseCommand implements Comparable<BaseCommand> {
protected static final String VERBOSE_LOGGING_PARAM = "l";
protected static final String VERBOSE_LOGGING_PARAM_LONGOPT = "logging";
protected static final String VERBOSE_LOGGING_PARAM_DESC = "If specified, verbose logging will be used.";
protected static final int DEFAULT_THREAD_COUNT = 10;
protected static final String THREAD_COUNT = "thread-count";
// TODO: Don't use qualified names for loggers in HAPI CLI.
private static final Logger ourLog = LoggerFactory.getLogger(BaseCommand.class);
protected FhirContext myFhirCtx;
@ -87,6 +91,11 @@ public abstract class BaseCommand implements Comparable<BaseCommand> {
addOptionalOption(theOptions, null, BEARER_TOKEN_PARAM_LONGOPT, BEARER_TOKEN_PARAM_NAME, BEARER_TOKEN_PARAM_DESC);
}
protected void addThreadCountOption(Options theOptions) {
addOptionalOption(theOptions, null, THREAD_COUNT, "count", "If specified, this argument specifies the number of worker threads used (default is " + DEFAULT_THREAD_COUNT + ")");
}
protected String promptUser(String thePrompt) throws ParseException {
System.out.print(ansi().bold().fgBrightDefault());
System.out.print(thePrompt);
@ -309,6 +318,12 @@ public abstract class BaseCommand implements Comparable<BaseCommand> {
return getFhirContext().getResourceDefinition("Bundle").getImplementingClass(IBaseBundle.class);
}
protected int getThreadCount(CommandLine theCommandLine) throws ParseException {
Integer parallelismThreadCount = getAndParsePositiveIntegerParam(theCommandLine, THREAD_COUNT);
parallelismThreadCount = ObjectUtils.defaultIfNull(parallelismThreadCount, DEFAULT_THREAD_COUNT);
return parallelismThreadCount.intValue();
}
public abstract String getCommandDescription();
public abstract String getCommandName();

View File

@ -6,7 +6,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-cli</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<relativePath>../../hapi-deployable-pom</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
@ -78,13 +78,13 @@
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu2</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-jpaserver-subscription</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
@ -101,7 +101,7 @@
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-testpage-overlay</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<classifier>classes</classifier>
</dependency>
<dependency>

View File

@ -0,0 +1,4 @@
---
type: fix
issue: 2515
title: "Fixed issues with application of survivorship rules when matching golden record to a single resource"

View File

@ -11,7 +11,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -7,7 +7,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
@ -144,13 +144,13 @@
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-test-utilities</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-jpaserver-test-utilities</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<scope>test</scope>
</dependency>
</dependencies>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
@ -55,13 +55,13 @@
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-test-utilities</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-jpaserver-test-utilities</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>

View File

@ -31,7 +31,6 @@ import ca.uhn.fhir.mdm.log.Logs;
import ca.uhn.fhir.mdm.model.MdmTransactionContext;
import ca.uhn.fhir.mdm.util.GoldenResourceHelper;
import ca.uhn.fhir.mdm.util.MdmResourceUtil;
import ca.uhn.fhir.mdm.util.TerserUtil;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.slf4j.Logger;

View File

@ -134,6 +134,11 @@ public class MdmEidUpdateService {
ourLog.debug(theMessage);
}
public void applySurvivorshipRulesAndSaveGoldenResource(IAnyResource theTargetResource, IAnyResource theGoldenResource, MdmTransactionContext theMdmTransactionContext) {
myMdmSurvivorshipService.applySurvivorshipRulesToGoldenResource(theTargetResource, theGoldenResource, theMdmTransactionContext);
myMdmResourceDaoSvc.upsertGoldenResource(theGoldenResource, theMdmTransactionContext.getResourceType());
}
/**
* Data class to hold context surrounding an update operation for an MDM target.
*/
@ -162,7 +167,7 @@ public class MdmEidUpdateService {
if (theExistingMatchLink.isPresent()) {
MdmLink mdmLink = theExistingMatchLink.get();
Long existingGoldenResourcePid = mdmLink.getGoldenResourcePid();
myExistingGoldenResource = myMdmResourceDaoSvc.readGoldenResourceByPid(new ResourcePersistentId(existingGoldenResourcePid), resourceType);
myExistingGoldenResource = myMdmResourceDaoSvc.readGoldenResourceByPid(new ResourcePersistentId(existingGoldenResourcePid), resourceType);
myRemainsMatchedToSameGoldenResource = candidateIsSameAsMdmLinkGoldenResource(mdmLink, theMatchedGoldenResourceCandidate);
} else {
myRemainsMatchedToSameGoldenResource = false;

View File

@ -46,6 +46,7 @@ import java.util.List;
*/
@Service
public class MdmMatchLinkSvc {
private static final Logger ourLog = Logs.getMdmTroubleshootingLog();
@Autowired
@ -62,7 +63,7 @@ public class MdmMatchLinkSvc {
* or create one if one does not exist. Performs matching based on rules defined in mdm-rules.json.
* Does nothing if resource is determined to be not managed by MDM.
*
* @param theResource the incoming MDM source, which can be any supported MDM type.
* @param theResource the incoming MDM source, which can be any supported MDM type.
* @param theMdmTransactionContext
* @return an {@link TransactionLogMessages} which contains all informational messages related to MDM processing of this resource.
*/
@ -130,20 +131,21 @@ public class MdmMatchLinkSvc {
myMdmLinkSvc.updateLink(newGoldenResource, theResource, MdmMatchOutcome.NEW_GOLDEN_RESOURCE_MATCH, MdmLinkSourceEnum.AUTO, theMdmTransactionContext);
}
private void handleMdmCreate(IAnyResource theSourceResource, MatchedGoldenResourceCandidate theGoldenResourceCandidate, MdmTransactionContext theMdmTransactionContext) {
private void handleMdmCreate(IAnyResource theTargetResource, MatchedGoldenResourceCandidate theGoldenResourceCandidate, MdmTransactionContext theMdmTransactionContext) {
log(theMdmTransactionContext, "MDM has narrowed down to one candidate for matching.");
IAnyResource golenResource = myMdmGoldenResourceFindingSvc.getGoldenResourceFromMatchedGoldenResourceCandidate(theGoldenResourceCandidate, theMdmTransactionContext.getResourceType());
IAnyResource goldenResource = myMdmGoldenResourceFindingSvc.getGoldenResourceFromMatchedGoldenResourceCandidate(theGoldenResourceCandidate, theMdmTransactionContext.getResourceType());
if (myGoldenResourceHelper.isPotentialDuplicate(golenResource, theSourceResource)) {
if (myGoldenResourceHelper.isPotentialDuplicate(goldenResource, theTargetResource)) {
log(theMdmTransactionContext, "Duplicate detected based on the fact that both resources have different external EIDs.");
IAnyResource newGoldenResource = myGoldenResourceHelper.createGoldenResourceFromMdmSourceResource(theSourceResource, theMdmTransactionContext);
myMdmLinkSvc.updateLink(newGoldenResource, theSourceResource, MdmMatchOutcome.NEW_GOLDEN_RESOURCE_MATCH, MdmLinkSourceEnum.AUTO, theMdmTransactionContext);
myMdmLinkSvc.updateLink(newGoldenResource, golenResource, MdmMatchOutcome.POSSIBLE_DUPLICATE, MdmLinkSourceEnum.AUTO, theMdmTransactionContext);
IAnyResource newGoldenResource = myGoldenResourceHelper.createGoldenResourceFromMdmSourceResource(theTargetResource, theMdmTransactionContext);
myMdmLinkSvc.updateLink(newGoldenResource, theTargetResource, MdmMatchOutcome.NEW_GOLDEN_RESOURCE_MATCH, MdmLinkSourceEnum.AUTO, theMdmTransactionContext);
myMdmLinkSvc.updateLink(newGoldenResource, goldenResource, MdmMatchOutcome.POSSIBLE_DUPLICATE, MdmLinkSourceEnum.AUTO, theMdmTransactionContext);
} else {
if (theGoldenResourceCandidate.isMatch()) {
myGoldenResourceHelper.handleExternalEidAddition(golenResource, theSourceResource, theMdmTransactionContext);
myGoldenResourceHelper.handleExternalEidAddition(goldenResource, theTargetResource, theMdmTransactionContext);
myEidUpdateService.applySurvivorshipRulesAndSaveGoldenResource(theTargetResource, goldenResource, theMdmTransactionContext);
}
myMdmLinkSvc.updateLink(golenResource, theSourceResource, theGoldenResourceCandidate.getMatchResult(), MdmLinkSourceEnum.AUTO, theMdmTransactionContext);
myMdmLinkSvc.updateLink(goldenResource, theTargetResource, theGoldenResourceCandidate.getMatchResult(), MdmLinkSourceEnum.AUTO, theMdmTransactionContext);
}
}

View File

@ -23,7 +23,7 @@ package ca.uhn.fhir.jpa.mdm.svc;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.mdm.api.IMdmSurvivorshipService;
import ca.uhn.fhir.mdm.model.MdmTransactionContext;
import ca.uhn.fhir.mdm.util.TerserUtil;
import ca.uhn.fhir.util.TerserUtil;
import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.springframework.beans.factory.annotation.Autowired;

View File

@ -4,9 +4,9 @@ import ca.uhn.fhir.jpa.entity.MdmLink;
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
import ca.uhn.fhir.mdm.util.MdmResourceUtil;
import ca.uhn.fhir.mdm.util.TerserUtil;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.util.TerserUtil;
import org.hl7.fhir.r4.model.Patient;
import org.hl7.fhir.r4.model.StringType;
import org.junit.jupiter.api.BeforeEach;

View File

@ -0,0 +1,70 @@
package ca.uhn.fhir.jpa.mdm.svc;
import ca.uhn.fhir.jpa.entity.MdmLink;
import ca.uhn.fhir.jpa.mdm.BaseMdmR4Test;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.mdm.api.IMdmLinkSvc;
import ca.uhn.fhir.mdm.api.IMdmSurvivorshipService;
import ca.uhn.fhir.mdm.api.MdmConstants;
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
import ca.uhn.fhir.mdm.api.MdmMatchOutcome;
import ca.uhn.fhir.mdm.model.MdmTransactionContext;
import ca.uhn.fhir.mdm.util.GoldenResourceHelper;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.param.TokenParam;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r4.model.Patient;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mockito;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.mock.mockito.SpyBean;
import javax.annotation.Nullable;
import static ca.uhn.fhir.mdm.api.MdmMatchResultEnum.*;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
import static org.mockito.Mockito.times;
import static org.slf4j.LoggerFactory.getLogger;
public class MdmMatchLinkSvcSurvivorshipTest extends BaseMdmR4Test {
private static final Logger ourLog = getLogger(MdmMatchLinkSvcSurvivorshipTest.class);
@Autowired
IMdmLinkSvc myMdmLinkSvc;
@SpyBean
IMdmSurvivorshipService myMdmSurvivorshipService;
@Autowired
private GoldenResourceHelper myGoldenResourceHelper;
@Captor
ArgumentCaptor<Patient> myPatientCaptor;
@Captor
ArgumentCaptor<MdmTransactionContext> myContext;
@Test
public void testSurvivorshipIsCalledOnMatchingToTheSameGoldenResource() {
// no candidates
createPatientAndUpdateLinks(buildJanePatient());
verifySurvivorshipCalled(1);
// single candidate
createPatientAndUpdateLinks(buildJanePatient());
verifySurvivorshipCalled(2);
// multiple candidates matching to the same golden record
createPatientAndUpdateLinks(buildJanePatient());
verifySurvivorshipCalled(3);
}
private void verifySurvivorshipCalled(int theNumberOfTimes) {
Mockito.verify(myMdmSurvivorshipService, times(theNumberOfTimes)).applySurvivorshipRulesToGoldenResource(myPatientCaptor.capture(), myPatientCaptor.capture(), myContext.capture());
}
}

View File

@ -476,28 +476,6 @@ public class MdmMatchLinkSvcTest extends BaseMdmR4Test {
assertThat(nameFirstRep.getGivenAsSingleString(), is(equalToIgnoringCase("paul")));
}
@Test
public void testPatientCreateDoesNotOverwriteGoldenResourceAttributesThatAreInvolvedInLinking() {
Patient paul = buildPaulPatient();
paul.setGender(Enumerations.AdministrativeGender.MALE);
paul = createPatientAndUpdateLinks(paul);
Patient sourcePatientFromTarget = (Patient) getGoldenResourceFromTargetResource(paul);
assertThat(sourcePatientFromTarget.getGender(), is(equalTo(Enumerations.AdministrativeGender.MALE)));
Patient paul2 = buildPaulPatient();
paul2.setGender(Enumerations.AdministrativeGender.FEMALE);
paul2 = createPatientAndUpdateLinks(paul2);
assertThat(paul2, is(sameGoldenResourceAs(paul)));
//Newly matched patients aren't allowed to overwrite GoldenResource Attributes unless they are empty,
// so gender should still be set to male.
Patient paul2GoldenResource = (Patient) getGoldenResourceFromTargetResource(paul2);
assertThat(paul2GoldenResource.getGender(), is(equalTo(Enumerations.AdministrativeGender.MALE)));
}
@Test
//Test Case #1
public void testPatientUpdatesOverwriteGoldenResourceData() {

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
@ -164,7 +164,7 @@
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-converter</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
</dependency>
</dependencies>

View File

@ -7,7 +7,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -1,147 +0,0 @@
package ca.uhn.fhir.mdm.util;
/*-
* #%L
* HAPI FHIR - Master Data Management
* %%
* Copyright (C) 2014 - 2021 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%
*/
import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.mdm.model.CanonicalEID;
import ca.uhn.fhir.util.FhirTerser;
import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.slf4j.Logger;
import java.util.Collection;
import java.util.List;
import java.util.function.Predicate;
import static org.slf4j.LoggerFactory.getLogger;
@Deprecated
public final class TerserUtil {
private static final Logger ourLog = getLogger(TerserUtil.class);
public static final Collection<String> IDS_AND_META_EXCLUDES = ca.uhn.fhir.util.TerserUtil.IDS_AND_META_EXCLUDES;
public static final Predicate<String> EXCLUDE_IDS_AND_META = ca.uhn.fhir.util.TerserUtil.EXCLUDE_IDS_AND_META;
private TerserUtil() {
}
/**
* @deprecated Use {@link ca.uhn.fhir.util.TerserUtil} instead
*/
public static void cloneEidIntoResource(FhirContext theFhirContext, BaseRuntimeChildDefinition theIdentifierDefinition, IBase theEid, IBase theResourceToCloneEidInto) {
ca.uhn.fhir.util.TerserUtil.cloneEidIntoResource(theFhirContext, theIdentifierDefinition, theEid, theResourceToCloneEidInto);
}
/**
* @deprecated Use {@link ca.uhn.fhir.util.TerserUtil} instead
*/
public static boolean hasValues(FhirContext theFhirContext, IBaseResource theResource, String theFieldName) {
return ca.uhn.fhir.util.TerserUtil.hasValues(theFhirContext, theResource, theFieldName);
}
/**
* @deprecated Use {@link ca.uhn.fhir.util.TerserUtil} instead
*/
public static List<IBase> getValues(FhirContext theFhirContext, IBaseResource theResource, String theFieldName) {
return ca.uhn.fhir.util.TerserUtil.getValues(theFhirContext, theResource, theFieldName);
}
/**
* @deprecated Use {@link ca.uhn.fhir.util.TerserUtil} instead
*/
public static void cloneCompositeField(FhirContext theFhirContext, IBaseResource theFrom, IBaseResource theTo, String field) {
ca.uhn.fhir.util.TerserUtil.cloneCompositeField(theFhirContext, theFrom, theTo, field);
}
/**
* @deprecated Use {@link ca.uhn.fhir.util.TerserUtil} instead
*/
public static void mergeAllFields(FhirContext theFhirContext, IBaseResource theFrom, IBaseResource theTo) {
ca.uhn.fhir.util.TerserUtil.mergeAllFields(theFhirContext, theFrom, theTo);
}
/**
* @deprecated Use {@link ca.uhn.fhir.util.TerserUtil} instead
*/
public static void replaceFields(FhirContext theFhirContext, IBaseResource theFrom, IBaseResource theTo, Predicate<String> inclusionStrategy) {
ca.uhn.fhir.util.TerserUtil.replaceFields(theFhirContext, theFrom, theTo, inclusionStrategy);
}
/**
* @deprecated Use {@link ca.uhn.fhir.util.TerserUtil} instead
*/
public static boolean fieldExists(FhirContext theFhirContext, String theFieldName, IBaseResource theInstance) {
return ca.uhn.fhir.util.TerserUtil.fieldExists(theFhirContext, theFieldName, theInstance);
}
/**
* @deprecated Use {@link ca.uhn.fhir.util.TerserUtil} instead
*/
public static void replaceField(FhirContext theFhirContext, String theFieldName, IBaseResource theFrom, IBaseResource theTo) {
ca.uhn.fhir.util.TerserUtil.replaceField(theFhirContext, theFieldName, theFrom, theTo);
}
/**
* @deprecated Use {@link ca.uhn.fhir.util.TerserUtil} instead
*/
public static void replaceField(FhirContext theFhirContext, FhirTerser theTerser, String theFieldName, IBaseResource theFrom, IBaseResource theTo) {
ca.uhn.fhir.util.TerserUtil.replaceField(theFhirContext, theTerser, theFieldName, theFrom, theTo);
}
/**
* @deprecated Use {@link ca.uhn.fhir.util.TerserUtil} instead
*/
public static void mergeFieldsExceptIdAndMeta(FhirContext theFhirContext, IBaseResource theFrom, IBaseResource theTo) {
ca.uhn.fhir.util.TerserUtil.mergeFieldsExceptIdAndMeta(theFhirContext, theFrom, theTo);
}
/**
* @deprecated Use {@link ca.uhn.fhir.util.TerserUtil} instead
*/
public static void mergeFields(FhirContext theFhirContext, IBaseResource theFrom, IBaseResource theTo, Predicate<String> inclusionStrategy) {
ca.uhn.fhir.util.TerserUtil.mergeFields(theFhirContext, theFrom, theTo, inclusionStrategy);
}
/**
* @deprecated Use {@link ca.uhn.fhir.util.TerserUtil} instead
*/
public static void mergeField(FhirContext theFhirContext, String theFieldName, IBaseResource theFrom, IBaseResource theTo) {
ca.uhn.fhir.util.TerserUtil.mergeField(theFhirContext, theFieldName, theFrom, theTo);
}
/**
* @deprecated Use {@link ca.uhn.fhir.util.TerserUtil} instead
*/
public static void mergeField(FhirContext theFhirContext, FhirTerser theTerser, String theFieldName, IBaseResource theFrom, IBaseResource theTo) {
ca.uhn.fhir.util.TerserUtil.mergeField(theFhirContext, theTerser, theFieldName, theFrom, theTo);
}
/**
* @deprecated Use {@link ca.uhn.fhir.util.TerserUtil} instead
*/
public static <T extends IBaseResource> T clone(FhirContext theFhirContext, T theInstance) {
return ca.uhn.fhir.util.TerserUtil.clone(theFhirContext, theInstance);
}
}

View File

@ -1,197 +0,0 @@
package ca.uhn.fhir.mdm.util;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.mdm.BaseR4Test;
import org.hl7.fhir.r4.model.DateTimeType;
import org.hl7.fhir.r4.model.Extension;
import org.hl7.fhir.r4.model.Identifier;
import org.hl7.fhir.r4.model.Patient;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasSize;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
class TerserUtilTest extends BaseR4Test {
@Test
void testCloneEidIntoResource() {
Identifier identifier = new Identifier().setSystem("http://org.com/sys").setValue("123");
Patient p1 = new Patient();
p1.addIdentifier(identifier);
Patient p2 = new Patient();
RuntimeResourceDefinition definition = ourFhirContext.getResourceDefinition(p1);
TerserUtil.cloneEidIntoResource(ourFhirContext, definition.getChildByName("identifier"), identifier, p2);
assertEquals(1, p2.getIdentifier().size());
assertEquals(p1.getIdentifier().get(0).getSystem(), p2.getIdentifier().get(0).getSystem());
assertEquals(p1.getIdentifier().get(0).getValue(), p2.getIdentifier().get(0).getValue());
}
@Test
void testFieldExists() {
assertTrue(TerserUtil.fieldExists(ourFhirContext, "identifier", new Patient()));
assertFalse(TerserUtil.fieldExists(ourFhirContext, "randomFieldName", new Patient()));
}
@Test
void testCloneFields() {
Patient p1 = buildJohny();
p1.addName().addGiven("Sigizmund");
p1.setId("Patient/22");
Patient p2 = new Patient();
TerserUtil.mergeFieldsExceptIdAndMeta(ourFhirContext, p1, p2);
assertTrue(p2.getIdentifier().isEmpty());
assertNull(p2.getId());
assertEquals(1, p2.getName().size());
assertEquals(p1.getName().get(0).getNameAsSingleString(), p2.getName().get(0).getNameAsSingleString());
}
@Test
void testCloneWithNonPrimitives() {
Patient p1 = new Patient();
Patient p2 = new Patient();
p1.addName().addGiven("Joe");
p1.getNameFirstRep().addGiven("George");
assertThat(p1.getName(), hasSize(1));
assertThat(p1.getName().get(0).getGiven(), hasSize(2));
p2.addName().addGiven("Jeff");
p2.getNameFirstRep().addGiven("George");
assertThat(p2.getName(), hasSize(1));
assertThat(p2.getName().get(0).getGiven(), hasSize(2));
TerserUtil.mergeAllFields(ourFhirContext, p1, p2);
assertThat(p2.getName(), hasSize(2));
assertThat(p2.getName().get(0).getGiven(), hasSize(2));
assertThat(p2.getName().get(1).getGiven(), hasSize(2));
}
@Test
void testMergeForAddressWithExtensions() {
Extension ext = new Extension();
ext.setUrl("http://hapifhir.io/extensions/address#create-timestamp");
ext.setValue(new DateTimeType("2021-01-02T11:13:15"));
Patient p1 = new Patient();
p1.addAddress()
.addLine("10 Main Street")
.setCity("Hamilton")
.setState("ON")
.setPostalCode("Z0Z0Z0")
.setCountry("Canada")
.addExtension(ext);
Patient p2 = new Patient();
p2.addAddress().addLine("10 Lenin Street").setCity("Severodvinsk").setCountry("Russia");
TerserUtil.mergeField(ourFhirContext,"address", p1, p2);
assertEquals(2, p2.getAddress().size());
assertEquals("[10 Lenin Street]", p2.getAddress().get(0).getLine().toString());
assertEquals("[10 Main Street]", p2.getAddress().get(1).getLine().toString());
assertTrue(p2.getAddress().get(1).hasExtension());
p1 = new Patient();
p1.addAddress().addLine("10 Main Street").addExtension(ext);
p2 = new Patient();
p2.addAddress().addLine("10 Main Street").addExtension(new Extension("demo", new DateTimeType("2021-01-02")));
TerserUtil.mergeField(ourFhirContext,"address", p1, p2);
assertEquals(2, p2.getAddress().size());
assertTrue(p2.getAddress().get(0).hasExtension());
assertTrue(p2.getAddress().get(1).hasExtension());
}
@Test
void testReplaceForAddressWithExtensions() {
Extension ext = new Extension();
ext.setUrl("http://hapifhir.io/extensions/address#create-timestamp");
ext.setValue(new DateTimeType("2021-01-02T11:13:15"));
Patient p1 = new Patient();
p1.addAddress()
.addLine("10 Main Street")
.setCity("Hamilton")
.setState("ON")
.setPostalCode("Z0Z0Z0")
.setCountry("Canada")
.addExtension(ext);
Patient p2 = new Patient();
p2.addAddress().addLine("10 Lenin Street").setCity("Severodvinsk").setCountry("Russia");
TerserUtil.replaceField(ourFhirContext,"address", p1, p2);
assertEquals(1, p2.getAddress().size());
assertEquals("[10 Main Street]", p2.getAddress().get(0).getLine().toString());
assertTrue(p2.getAddress().get(0).hasExtension());
}
@Test
void testMergeForSimilarAddresses() {
Extension ext = new Extension();
ext.setUrl("http://hapifhir.io/extensions/address#create-timestamp");
ext.setValue(new DateTimeType("2021-01-02T11:13:15"));
Patient p1 = new Patient();
p1.addAddress()
.addLine("10 Main Street")
.setCity("Hamilton")
.setState("ON")
.setPostalCode("Z0Z0Z0")
.setCountry("Canada")
.addExtension(ext);
Patient p2 = new Patient();
p2.addAddress()
.addLine("10 Main Street")
.setCity("Hamilton")
.setState("ON")
.setPostalCode("Z0Z0Z1")
.setCountry("Canada")
.addExtension(ext);
TerserUtil.mergeField(ourFhirContext,"address", p1, p2);
assertEquals(2, p2.getAddress().size());
assertEquals("[10 Main Street]", p2.getAddress().get(0).getLine().toString());
assertEquals("[10 Main Street]", p2.getAddress().get(1).getLine().toString());
assertTrue(p2.getAddress().get(1).hasExtension());
}
@Test
void testCloneWithDuplicateNonPrimitives() {
Patient p1 = new Patient();
Patient p2 = new Patient();
p1.addName().addGiven("Jim");
p1.getNameFirstRep().addGiven("George");
assertThat(p1.getName(), hasSize(1));
assertThat(p1.getName().get(0).getGiven(), hasSize(2));
p2.addName().addGiven("Jim");
p2.getNameFirstRep().addGiven("George");
assertThat(p2.getName(), hasSize(1));
assertThat(p2.getName().get(0).getGiven(), hasSize(2));
TerserUtil.mergeAllFields(ourFhirContext, p1, p2);
assertThat(p2.getName(), hasSize(1));
assertThat(p2.getName().get(0).getGiven(), hasSize(2));
}
}

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
</parent>
<artifactId>hapi-fhir-spring-boot-sample-client-apache</artifactId>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
</parent>
<artifactId>hapi-fhir-spring-boot-sample-client-okhttp</artifactId>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
</parent>
<artifactId>hapi-fhir-spring-boot-sample-server-jersey</artifactId>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-spring-boot</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
</parent>
<artifactId>hapi-fhir-spring-boot-samples</artifactId>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -156,6 +156,36 @@ public class BundleBuilderTest {
assertEquals(Bundle.HTTPVerb.POST, bundle.getEntry().get(0).getRequest().getMethod());
}
@Test
public void testAddEntryDelete() {
BundleBuilder builder = new BundleBuilder(myFhirContext);
Patient patient = new Patient();
patient.setActive(true);
patient.setId("123");
builder.addTransactionDeleteEntry(patient);
builder.addTransactionDeleteEntry("Patient", "123");
Bundle bundle = (Bundle) builder.getBundle();
ourLog.info("Bundle:\n{}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(bundle));
assertEquals(Bundle.BundleType.TRANSACTION, bundle.getType());
assertEquals(2, bundle.getEntry().size());
//Check the IBaseresource style entry
assertNull(bundle.getEntry().get(0).getResource());
assertEquals("Patient/123", bundle.getEntry().get(0).getRequest().getUrl());
assertEquals(Bundle.HTTPVerb.DELETE, bundle.getEntry().get(0).getRequest().getMethod());
//Check the resourcetype + id style entry.
assertNull(bundle.getEntry().get(1).getResource());
assertEquals("Patient/123", bundle.getEntry().get(1).getRequest().getUrl());
assertEquals(Bundle.HTTPVerb.DELETE, bundle.getEntry().get(1).getRequest().getMethod());
}
@Test
public void testAddEntryCreateConditional() {
BundleBuilder builder = new BundleBuilder(myFhirContext);

View File

@ -13,6 +13,8 @@ import org.hl7.fhir.r4.model.Patient;
import org.hl7.fhir.r4.model.PrimitiveType;
import org.junit.jupiter.api.Test;
import java.util.Date;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasSize;
import static org.junit.jupiter.api.Assertions.*;
@ -77,6 +79,7 @@ class TerserUtilTest {
assertEquals(check.getValue(), p.getBirthDate());
}
@Test
void testFieldExists() {
assertTrue(TerserUtil.fieldExists(ourFhirContext, "identifier", TerserUtil.newResource(ourFhirContext, "Patient")));
@ -294,6 +297,26 @@ class TerserUtilTest {
assertEquals("Doe", p2.getName().get(0).getFamily());
}
@Test
public void testReplaceFieldsByPredicate() {
Patient p1 = new Patient();
p1.addName().setFamily("Doe");
p1.setGender(Enumerations.AdministrativeGender.MALE);
Patient p2 = new Patient();
p2.addName().setFamily("Smith");
Date dob = new Date();
p2.setBirthDate(dob);
TerserUtil.replaceFieldsByPredicate(ourFhirContext, p1, p2, TerserUtil.EXCLUDE_IDS_META_AND_EMPTY);
// expect p2 to have "Doe" and MALE after replace
assertEquals(1, p2.getName().size());
assertEquals("Doe", p2.getName().get(0).getFamily());
assertEquals(Enumerations.AdministrativeGender.MALE, p2.getGender());
assertEquals(dob, p2.getBirthDate());
}
@Test
public void testClearFields() {
Patient p1 = new Patient();

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
@ -58,37 +58,37 @@
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu3</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-hl7org-dstu2</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-r4</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-r5</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-validation-resources-dstu2</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-validation-resources-dstu3</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-validation-resources-r4</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,7 @@
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<packaging>pom</packaging>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<name>HAPI-FHIR</name>
<description>An open-source implementation of the FHIR specification in Java.</description>
<url>https://hapifhir.io</url>

View File

@ -8,7 +8,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>5.4.0-PRE6-SNAPSHOT</version>
<version>5.4.0-PRE7-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>