Merge remote-tracking branch 'remotes/origin/master' into ks-20200120-near-search
# Conflicts: # hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/4_2_0/changes.yaml
This commit is contained in:
commit
eff4b294df
|
@ -19,7 +19,7 @@ jobs:
|
||||||
steps:
|
steps:
|
||||||
- task: Cache@2
|
- task: Cache@2
|
||||||
inputs:
|
inputs:
|
||||||
key: 'maven | "$(Agent.OS)" | **/pom.xml'
|
key: 'maven | "$(Agent.OS)" | ./pom.xml'
|
||||||
path: $(MAVEN_CACHE_FOLDER)
|
path: $(MAVEN_CACHE_FOLDER)
|
||||||
- task: Bash@3
|
- task: Bash@3
|
||||||
inputs:
|
inputs:
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
type: fix
|
||||||
|
issue: 1679
|
||||||
|
title: "An issue with the new flyway migrator hashCode generation was resolved.
|
||||||
|
Thanks to Jafer Khan for the pull request!"
|
|
@ -82,6 +82,9 @@ Sean McIlvenna for reporting!"
|
||||||
title: "When using a custom structure that changes the cardinality from 0..* to 0..1, the Parser was encoding
|
title: "When using a custom structure that changes the cardinality from 0..* to 0..1, the Parser was encoding
|
||||||
a plain field instead of an array (as required by the FHIR specification). Thanks to
|
a plain field instead of an array (as required by the FHIR specification). Thanks to
|
||||||
Petro Mykhailysyn for the pull request!"
|
Petro Mykhailysyn for the pull request!"
|
||||||
|
- item:
|
||||||
|
type: "fix"
|
||||||
|
title: "A meomery leak was resolved in the JPA terminology service delta upload operations."
|
||||||
- item:
|
- item:
|
||||||
type: "add"
|
type: "add"
|
||||||
title: "Searching Location.position by latitude, longitude and distance for DSTU3, R4 and R5 is now supported using a simple 'box' search.
|
title: "Searching Location.position by latitude, longitude and distance for DSTU3, R4 and R5 is now supported using a simple 'box' search.
|
||||||
|
|
|
@ -97,7 +97,7 @@ public class TermConcept implements Serializable {
|
||||||
@Column(name = "PARENT_PIDS", nullable = true)
|
@Column(name = "PARENT_PIDS", nullable = true)
|
||||||
private String myParentPids;
|
private String myParentPids;
|
||||||
@OneToMany(cascade = {}, fetch = FetchType.LAZY, mappedBy = "myChild")
|
@OneToMany(cascade = {}, fetch = FetchType.LAZY, mappedBy = "myChild")
|
||||||
private Collection<TermConceptParentChildLink> myParents;
|
private List<TermConceptParentChildLink> myParents;
|
||||||
@Column(name = "CODE_SEQUENCE", nullable = true)
|
@Column(name = "CODE_SEQUENCE", nullable = true)
|
||||||
private Integer mySequence;
|
private Integer mySequence;
|
||||||
|
|
||||||
|
@ -269,7 +269,7 @@ public class TermConcept implements Serializable {
|
||||||
return myParentPids;
|
return myParentPids;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<TermConceptParentChildLink> getParents() {
|
public List<TermConceptParentChildLink> getParents() {
|
||||||
if (myParents == null) {
|
if (myParents == null) {
|
||||||
myParents = new ArrayList<>();
|
myParents = new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,10 +24,21 @@ import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||||
import ca.uhn.fhir.jpa.dao.BaseHapiFhirDao;
|
import ca.uhn.fhir.jpa.dao.BaseHapiFhirDao;
|
||||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||||
import ca.uhn.fhir.jpa.model.cross.ResourcePersistentId;
|
import ca.uhn.fhir.jpa.dao.data.IResourceTableDao;
|
||||||
import ca.uhn.fhir.jpa.dao.data.*;
|
import ca.uhn.fhir.jpa.dao.data.ITermCodeSystemDao;
|
||||||
|
import ca.uhn.fhir.jpa.dao.data.ITermCodeSystemVersionDao;
|
||||||
|
import ca.uhn.fhir.jpa.dao.data.ITermConceptDao;
|
||||||
|
import ca.uhn.fhir.jpa.dao.data.ITermConceptDesignationDao;
|
||||||
|
import ca.uhn.fhir.jpa.dao.data.ITermConceptParentChildLinkDao;
|
||||||
|
import ca.uhn.fhir.jpa.dao.data.ITermConceptPropertyDao;
|
||||||
import ca.uhn.fhir.jpa.dao.index.IdHelperService;
|
import ca.uhn.fhir.jpa.dao.index.IdHelperService;
|
||||||
import ca.uhn.fhir.jpa.entity.*;
|
import ca.uhn.fhir.jpa.entity.TermCodeSystem;
|
||||||
|
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
|
||||||
|
import ca.uhn.fhir.jpa.entity.TermConcept;
|
||||||
|
import ca.uhn.fhir.jpa.entity.TermConceptDesignation;
|
||||||
|
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink;
|
||||||
|
import ca.uhn.fhir.jpa.entity.TermConceptProperty;
|
||||||
|
import ca.uhn.fhir.jpa.model.cross.ResourcePersistentId;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||||
import ca.uhn.fhir.jpa.term.api.ITermCodeSystemStorageSvc;
|
import ca.uhn.fhir.jpa.term.api.ITermCodeSystemStorageSvc;
|
||||||
import ca.uhn.fhir.jpa.term.api.ITermDeferredStorageSvc;
|
import ca.uhn.fhir.jpa.term.api.ITermDeferredStorageSvc;
|
||||||
|
@ -166,10 +177,17 @@ public class TermCodeSystemStorageSvcImpl implements ITermCodeSystemStorageSvc {
|
||||||
TypedQuery<TermConcept> typedQuery = myEntityManager.createQuery(query.select(root));
|
TypedQuery<TermConcept> typedQuery = myEntityManager.createQuery(query.select(root));
|
||||||
org.hibernate.query.Query<TermConcept> hibernateQuery = (org.hibernate.query.Query<TermConcept>) typedQuery;
|
org.hibernate.query.Query<TermConcept> hibernateQuery = (org.hibernate.query.Query<TermConcept>) typedQuery;
|
||||||
ScrollableResults scrollableResults = hibernateQuery.scroll(ScrollMode.FORWARD_ONLY);
|
ScrollableResults scrollableResults = hibernateQuery.scroll(ScrollMode.FORWARD_ONLY);
|
||||||
|
int count = 0;
|
||||||
try (ScrollableResultsIterator<TermConcept> scrollableResultsIterator = new ScrollableResultsIterator<>(scrollableResults)) {
|
try (ScrollableResultsIterator<TermConcept> scrollableResultsIterator = new ScrollableResultsIterator<>(scrollableResults)) {
|
||||||
while (scrollableResultsIterator.hasNext()) {
|
while (scrollableResultsIterator.hasNext()) {
|
||||||
TermConcept next = scrollableResultsIterator.next();
|
TermConcept next = scrollableResultsIterator.next();
|
||||||
codeToConceptPid.put(next.getCode(), next.getId());
|
codeToConceptPid.put(next.getCode(), next.getId());
|
||||||
|
|
||||||
|
// We don't want to keep the loaded entities in the L1 cache because they can take up a loooot of memory
|
||||||
|
if (count % 100 == 0) {
|
||||||
|
myEntityManager.clear();
|
||||||
|
}
|
||||||
|
count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ourLog.info("Loaded {} concepts in {}", codeToConceptPid.size(), sw.toString());
|
ourLog.info("Loaded {} concepts in {}", codeToConceptPid.size(), sw.toString());
|
||||||
|
@ -199,12 +217,20 @@ public class TermCodeSystemStorageSvcImpl implements ITermCodeSystemStorageSvc {
|
||||||
String childCode = next.getChild().getCode();
|
String childCode = next.getChild().getCode();
|
||||||
parentCodeToChildCodes.put(parentCode, childCode);
|
parentCodeToChildCodes.put(parentCode, childCode);
|
||||||
childCodeToParentCodes.put(childCode, parentCode);
|
childCodeToParentCodes.put(childCode, parentCode);
|
||||||
|
|
||||||
|
// We don't want to keep the loaded entities in the L1 cache because they can take up a loooot of memory
|
||||||
|
if (count % 100 == 0) {
|
||||||
|
myEntityManager.clear();
|
||||||
|
}
|
||||||
|
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ourLog.info("Loaded {} parent/child relationships in {}", count, sw.toString());
|
ourLog.info("Loaded {} parent/child relationships in {}", count, sw.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ourLog.trace("Starting delta application");
|
||||||
|
|
||||||
// Account for root codes in the parent->child map
|
// Account for root codes in the parent->child map
|
||||||
for (String nextCode : codeToConceptPid.keySet()) {
|
for (String nextCode : codeToConceptPid.keySet()) {
|
||||||
if (childCodeToParentCodes.get(nextCode).isEmpty()) {
|
if (childCodeToParentCodes.get(nextCode).isEmpty()) {
|
||||||
|
@ -217,13 +243,7 @@ public class TermCodeSystemStorageSvcImpl implements ITermCodeSystemStorageSvc {
|
||||||
// Add root concepts
|
// Add root concepts
|
||||||
for (TermConcept nextRootConcept : theAdditions.getRootConcepts()) {
|
for (TermConcept nextRootConcept : theAdditions.getRootConcepts()) {
|
||||||
List<String> parentCodes = Collections.emptyList();
|
List<String> parentCodes = Collections.emptyList();
|
||||||
addConcept(csv, codeToConceptPid, parentCodes, nextRootConcept, parentCodeToChildCodes, retVal, true);
|
addConcept(csv, codeToConceptPid, parentCodes, nextRootConcept, parentCodeToChildCodes, retVal, theAdditions.getRootConceptCodes(), true);
|
||||||
}
|
|
||||||
|
|
||||||
// Add unanchored child concepts
|
|
||||||
for (TermConcept nextUnanchoredChild : theAdditions.getUnanchoredChildConceptsToParentCodes().keySet()) {
|
|
||||||
List<String> nextParentCodes = theAdditions.getUnanchoredChildConceptsToParentCodes().get(nextUnanchoredChild);
|
|
||||||
addConcept(csv, codeToConceptPid, nextParentCodes, nextUnanchoredChild, parentCodeToChildCodes, retVal, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return retVal;
|
return retVal;
|
||||||
|
@ -499,10 +519,11 @@ public class TermCodeSystemStorageSvcImpl implements ITermCodeSystemStorageSvc {
|
||||||
Validate.isTrue(myContext.getVersion().getVersion().isEqualOrNewerThan(FhirVersionEnum.DSTU3), "Terminology operations only supported in DSTU3+ mode");
|
Validate.isTrue(myContext.getVersion().getVersion().isEqualOrNewerThan(FhirVersionEnum.DSTU3), "Terminology operations only supported in DSTU3+ mode");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addConcept(TermCodeSystemVersion theCsv, Map<String, Long> theCodeToConceptPid, Collection<String> theParentCodes, TermConcept theConceptToAdd, ListMultimap<String, String> theParentCodeToChildCodes, UploadStatistics theStatisticsTracker, boolean theForceResequence) {
|
private void addConcept(TermCodeSystemVersion theCsv, Map<String, Long> theCodeToConceptPid, Collection<String> theParentCodes, TermConcept theConceptToAdd, ListMultimap<String, String> theParentCodeToChildCodes, UploadStatistics theStatisticsTracker, Set<String> theAdditionSetRootConceptCodes, boolean theRootConcept) {
|
||||||
TermConcept nextConceptToAdd = theConceptToAdd;
|
TermConcept conceptToAdd = theConceptToAdd;
|
||||||
|
List<TermConceptParentChildLink> childrenToAdd = theConceptToAdd.getChildren();
|
||||||
|
|
||||||
String nextCodeToAdd = nextConceptToAdd.getCode();
|
String nextCodeToAdd = conceptToAdd.getCode();
|
||||||
String parentDescription = "(root concept)";
|
String parentDescription = "(root concept)";
|
||||||
Set<TermConcept> parentConcepts = new HashSet<>();
|
Set<TermConcept> parentConcepts = new HashSet<>();
|
||||||
if (!theParentCodes.isEmpty()) {
|
if (!theParentCodes.isEmpty()) {
|
||||||
|
@ -522,12 +543,12 @@ public class TermCodeSystemStorageSvcImpl implements ITermCodeSystemStorageSvc {
|
||||||
|
|
||||||
TermConcept existingCode = myConceptDao.getOne(theCodeToConceptPid.get(nextCodeToAdd));
|
TermConcept existingCode = myConceptDao.getOne(theCodeToConceptPid.get(nextCodeToAdd));
|
||||||
existingCode.setIndexStatus(null);
|
existingCode.setIndexStatus(null);
|
||||||
existingCode.setDisplay(nextConceptToAdd.getDisplay());
|
existingCode.setDisplay(conceptToAdd.getDisplay());
|
||||||
nextConceptToAdd = existingCode;
|
conceptToAdd = existingCode;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (theConceptToAdd.getSequence() == null || theForceResequence) {
|
if (conceptToAdd.getSequence() == null || !theRootConcept) {
|
||||||
// If this is a new code, give it a sequence number based on how many concepts the
|
// If this is a new code, give it a sequence number based on how many concepts the
|
||||||
// parent already has (or the highest number, if the code has multiple parents)
|
// parent already has (or the highest number, if the code has multiple parents)
|
||||||
int sequence = 0;
|
int sequence = 0;
|
||||||
|
@ -539,17 +560,15 @@ public class TermCodeSystemStorageSvcImpl implements ITermCodeSystemStorageSvc {
|
||||||
theParentCodeToChildCodes.put("", nextCodeToAdd);
|
theParentCodeToChildCodes.put("", nextCodeToAdd);
|
||||||
sequence = Math.max(sequence, theParentCodeToChildCodes.get("").size());
|
sequence = Math.max(sequence, theParentCodeToChildCodes.get("").size());
|
||||||
}
|
}
|
||||||
nextConceptToAdd.setSequence(sequence);
|
conceptToAdd.setSequence(sequence);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Drop any old parent-child links if they aren't explicitly specified in the
|
// Drop any old parent-child links if they aren't explicitly specified in the
|
||||||
// hierarchy being added
|
// hierarchy being added
|
||||||
for (Iterator<TermConceptParentChildLink> iter = nextConceptToAdd.getParents().iterator(); iter.hasNext(); ) {
|
if (!theRootConcept) {
|
||||||
TermConceptParentChildLink nextLink = iter.next();
|
for (Iterator<TermConceptParentChildLink> iter = conceptToAdd.getParents().iterator(); iter.hasNext(); ) {
|
||||||
String parentCode = nextLink.getParent().getCode();
|
TermConceptParentChildLink nextLink = iter.next();
|
||||||
boolean shouldRemove = !theParentCodes.contains(parentCode);
|
String parentCode = nextLink.getParent().getCode();
|
||||||
if (shouldRemove) {
|
|
||||||
ourLog.info("Dropping existing parent/child link from {} -> {}", parentCode, nextCodeToAdd);
|
ourLog.info("Dropping existing parent/child link from {} -> {}", parentCode, nextCodeToAdd);
|
||||||
myConceptParentChildLinkDao.delete(nextLink);
|
myConceptParentChildLinkDao.delete(nextLink);
|
||||||
iter.remove();
|
iter.remove();
|
||||||
|
@ -559,42 +578,49 @@ public class TermCodeSystemStorageSvcImpl implements ITermCodeSystemStorageSvc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nextConceptToAdd.setParentPids(null);
|
// Null out the hierarchy PIDs for this concept always. We do this because we're going to
|
||||||
nextConceptToAdd.setCodeSystemVersion(theCsv);
|
// force a reindex, and it'll be regenerated then
|
||||||
nextConceptToAdd = myConceptDao.save(nextConceptToAdd);
|
conceptToAdd.setParentPids(null);
|
||||||
|
conceptToAdd.setCodeSystemVersion(theCsv);
|
||||||
|
conceptToAdd = myConceptDao.save(conceptToAdd);
|
||||||
|
|
||||||
Long nextConceptPid = nextConceptToAdd.getId();
|
Long nextConceptPid = conceptToAdd.getId();
|
||||||
Validate.notNull(nextConceptPid);
|
Validate.notNull(nextConceptPid);
|
||||||
theCodeToConceptPid.put(nextCodeToAdd, nextConceptPid);
|
theCodeToConceptPid.put(nextCodeToAdd, nextConceptPid);
|
||||||
theStatisticsTracker.incrementUpdatedConceptCount();
|
theStatisticsTracker.incrementUpdatedConceptCount();
|
||||||
|
|
||||||
// Add link to new child to the parent if this link doesn't already exist (this will be the
|
// Add link to new child to the parent
|
||||||
// case for concepts being added to an existing child concept, but won't be the case when
|
|
||||||
// we're recursively adding children)
|
|
||||||
for (TermConcept nextParentConcept : parentConcepts) {
|
for (TermConcept nextParentConcept : parentConcepts) {
|
||||||
if (nextParentConcept.getChildren().stream().noneMatch(t -> t.getChild().getCode().equals(nextCodeToAdd))) {
|
TermConceptParentChildLink parentLink = new TermConceptParentChildLink();
|
||||||
TermConceptParentChildLink parentLink = new TermConceptParentChildLink();
|
parentLink.setParent(nextParentConcept);
|
||||||
parentLink.setParent(nextParentConcept);
|
parentLink.setChild(conceptToAdd);
|
||||||
parentLink.setChild(nextConceptToAdd);
|
parentLink.setCodeSystem(theCsv);
|
||||||
parentLink.setCodeSystem(theCsv);
|
parentLink.setRelationshipType(TermConceptParentChildLink.RelationshipTypeEnum.ISA);
|
||||||
parentLink.setRelationshipType(TermConceptParentChildLink.RelationshipTypeEnum.ISA);
|
nextParentConcept.getChildren().add(parentLink);
|
||||||
nextParentConcept.getChildren().add(parentLink);
|
conceptToAdd.getParents().add(parentLink);
|
||||||
nextConceptToAdd.getParents().add(parentLink);
|
ourLog.info("Saving parent/child link - Parent[{}] Child[{}]", parentLink.getParent().getCode(), parentLink.getChild().getCode());
|
||||||
myConceptParentChildLinkDao.save(parentLink);
|
myConceptParentChildLinkDao.save(parentLink);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ourLog.trace("About to save parent-child links");
|
||||||
|
|
||||||
// Save children recursively
|
// Save children recursively
|
||||||
for (TermConceptParentChildLink nextChildConceptLink : nextConceptToAdd.getChildren()) {
|
for (TermConceptParentChildLink nextChildConceptLink : new ArrayList<>(childrenToAdd)) {
|
||||||
|
|
||||||
TermConcept nextChild = nextChildConceptLink.getChild();
|
TermConcept nextChild = nextChildConceptLink.getChild();
|
||||||
Collection<String> parentCodes = nextChild.getParents().stream().map(t -> t.getParent().getCode()).collect(Collectors.toList());
|
|
||||||
addConcept(theCsv, theCodeToConceptPid, parentCodes, nextChild, theParentCodeToChildCodes, theStatisticsTracker, false);
|
|
||||||
|
|
||||||
if (nextChildConceptLink.getId() == null) {
|
for (int i = 0; i < nextChild.getParents().size(); i++) {
|
||||||
nextChildConceptLink.setCodeSystem(theCsv);
|
if (nextChild.getParents().get(i).getId() == null) {
|
||||||
myConceptParentChildLinkDao.save(nextChildConceptLink);
|
String parentCode = nextChild.getParents().get(i).getParent().getCode();
|
||||||
|
Long parentPid = theCodeToConceptPid.get(parentCode);
|
||||||
|
TermConcept parentConcept = myConceptDao.findById(parentPid).orElseThrow(() -> new IllegalArgumentException("Unknown parent code: " + parentCode));
|
||||||
|
nextChild.getParents().get(i).setParent(parentConcept);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Collection<String> parentCodes = nextChild.getParents().stream().map(t -> t.getParent().getCode()).collect(Collectors.toList());
|
||||||
|
addConcept(theCsv, theCodeToConceptPid, parentCodes, nextChild, theParentCodeToChildCodes, theStatisticsTracker, theAdditionSetRootConceptCodes, false);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,40 +28,38 @@ import ca.uhn.fhir.jpa.term.TermLoaderSvcImpl;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
import com.google.common.collect.ArrayListMultimap;
|
import com.google.common.collect.ArrayListMultimap;
|
||||||
import com.google.common.collect.ListMultimap;
|
import com.google.common.collect.ListMultimap;
|
||||||
import com.google.common.collect.Multimaps;
|
|
||||||
import org.apache.commons.csv.QuoteMode;
|
import org.apache.commons.csv.QuoteMode;
|
||||||
import org.apache.commons.lang3.Validate;
|
import org.apache.commons.lang3.Validate;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class CustomTerminologySet {
|
public class CustomTerminologySet {
|
||||||
|
|
||||||
private final int mySize;
|
private final int mySize;
|
||||||
private final ListMultimap<TermConcept, String> myUnanchoredChildConceptsToParentCodes;
|
|
||||||
private final List<TermConcept> myRootConcepts;
|
private final List<TermConcept> myRootConcepts;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for an empty object
|
* Constructor for an empty object
|
||||||
*/
|
*/
|
||||||
public CustomTerminologySet() {
|
public CustomTerminologySet() {
|
||||||
this(0, ArrayListMultimap.create(), new ArrayList<>());
|
this(0, new ArrayList<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
private CustomTerminologySet(int theSize, ListMultimap<TermConcept, String> theUnanchoredChildConceptsToParentCodes, Collection<TermConcept> theRootConcepts) {
|
private CustomTerminologySet(int theSize, List<TermConcept> theRootConcepts) {
|
||||||
this(theSize, theUnanchoredChildConceptsToParentCodes, new ArrayList<>(theRootConcepts));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*/
|
|
||||||
private CustomTerminologySet(int theSize, ListMultimap<TermConcept, String> theUnanchoredChildConceptsToParentCodes, List<TermConcept> theRootConcepts) {
|
|
||||||
mySize = theSize;
|
mySize = theSize;
|
||||||
myUnanchoredChildConceptsToParentCodes = theUnanchoredChildConceptsToParentCodes;
|
|
||||||
myRootConcepts = theRootConcepts;
|
myRootConcepts = theRootConcepts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,10 +78,6 @@ public class CustomTerminologySet {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public ListMultimap<TermConcept, String> getUnanchoredChildConceptsToParentCodes() {
|
|
||||||
return Multimaps.unmodifiableListMultimap(myUnanchoredChildConceptsToParentCodes);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getSize() {
|
public int getSize() {
|
||||||
return mySize;
|
return mySize;
|
||||||
}
|
}
|
||||||
|
@ -111,22 +105,9 @@ public class CustomTerminologySet {
|
||||||
return Collections.unmodifiableList(myRootConcepts);
|
return Collections.unmodifiableList(myRootConcepts);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addUnanchoredChildConcept(String theParentCode, String theCode, String theDisplay) {
|
|
||||||
Validate.notBlank(theParentCode);
|
|
||||||
Validate.notBlank(theCode);
|
|
||||||
|
|
||||||
TermConcept code = new TermConcept()
|
|
||||||
.setCode(theCode)
|
|
||||||
.setDisplay(theDisplay);
|
|
||||||
myUnanchoredChildConceptsToParentCodes.put(code, theParentCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void validateNoCycleOrThrowInvalidRequest() {
|
public void validateNoCycleOrThrowInvalidRequest() {
|
||||||
Set<String> codes = new HashSet<>();
|
Set<String> codes = new HashSet<>();
|
||||||
validateNoCycleOrThrowInvalidRequest(codes, getRootConcepts());
|
validateNoCycleOrThrowInvalidRequest(codes, getRootConcepts());
|
||||||
for (TermConcept next : myUnanchoredChildConceptsToParentCodes.keySet()) {
|
|
||||||
validateNoCycleOrThrowInvalidRequest(codes, next);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validateNoCycleOrThrowInvalidRequest(Set<String> theCodes, List<TermConcept> theRootConcepts) {
|
private void validateNoCycleOrThrowInvalidRequest(Set<String> theCodes, List<TermConcept> theRootConcepts) {
|
||||||
|
@ -142,25 +123,30 @@ public class CustomTerminologySet {
|
||||||
validateNoCycleOrThrowInvalidRequest(theCodes, next.getChildCodes());
|
validateNoCycleOrThrowInvalidRequest(theCodes, next.getChildCodes());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set<String> getRootConceptCodes() {
|
||||||
|
return getRootConcepts()
|
||||||
|
.stream()
|
||||||
|
.map(TermConcept::getCode)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
public static CustomTerminologySet load(LoadedFileDescriptors theDescriptors, boolean theFlat) {
|
public static CustomTerminologySet load(LoadedFileDescriptors theDescriptors, boolean theFlat) {
|
||||||
|
|
||||||
final Map<String, TermConcept> code2concept = new LinkedHashMap<>();
|
final Map<String, TermConcept> code2concept = new LinkedHashMap<>();
|
||||||
ArrayListMultimap<TermConcept, String> unanchoredChildConceptsToParentCodes = ArrayListMultimap.create();
|
|
||||||
|
|
||||||
// Concepts
|
// Concepts
|
||||||
IRecordHandler conceptHandler = new ConceptHandler(code2concept);
|
IRecordHandler conceptHandler = new ConceptHandler(code2concept);
|
||||||
TermLoaderSvcImpl.iterateOverZipFile(theDescriptors, TermLoaderSvcImpl.CUSTOM_CONCEPTS_FILE, conceptHandler, ',', QuoteMode.NON_NUMERIC, false);
|
TermLoaderSvcImpl.iterateOverZipFile(theDescriptors, TermLoaderSvcImpl.CUSTOM_CONCEPTS_FILE, conceptHandler, ',', QuoteMode.NON_NUMERIC, false);
|
||||||
if (theFlat) {
|
if (theFlat) {
|
||||||
|
|
||||||
return new CustomTerminologySet(code2concept.size(), ArrayListMultimap.create(), code2concept.values());
|
return new CustomTerminologySet(code2concept.size(), new ArrayList<>(code2concept.values()));
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// Hierarchy
|
// Hierarchy
|
||||||
if (theDescriptors.hasFile(TermLoaderSvcImpl.CUSTOM_HIERARCHY_FILE)) {
|
if (theDescriptors.hasFile(TermLoaderSvcImpl.CUSTOM_HIERARCHY_FILE)) {
|
||||||
IRecordHandler hierarchyHandler = new HierarchyHandler(code2concept, unanchoredChildConceptsToParentCodes);
|
IRecordHandler hierarchyHandler = new HierarchyHandler(code2concept);
|
||||||
TermLoaderSvcImpl.iterateOverZipFile(theDescriptors, TermLoaderSvcImpl.CUSTOM_HIERARCHY_FILE, hierarchyHandler, ',', QuoteMode.NON_NUMERIC, false);
|
TermLoaderSvcImpl.iterateOverZipFile(theDescriptors, TermLoaderSvcImpl.CUSTOM_HIERARCHY_FILE, hierarchyHandler, ',', QuoteMode.NON_NUMERIC, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,7 +164,7 @@ public class CustomTerminologySet {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort children so they appear in the same order as they did in the concepts.csv file
|
// Sort children so they appear in the same order as they did in the concepts.csv file
|
||||||
nextConcept.getChildren().sort((o1,o2)->{
|
nextConcept.getChildren().sort((o1, o2) -> {
|
||||||
String code1 = o1.getChild().getCode();
|
String code1 = o1.getChild().getCode();
|
||||||
String code2 = o2.getChild().getCode();
|
String code2 = o2.getChild().getCode();
|
||||||
int order1 = codesInOrder.get(code1);
|
int order1 = codesInOrder.get(code1);
|
||||||
|
@ -188,7 +174,7 @@ public class CustomTerminologySet {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new CustomTerminologySet(code2concept.size(), unanchoredChildConceptsToParentCodes, rootConcepts);
|
return new CustomTerminologySet(code2concept.size(), rootConcepts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,6 @@ import ca.uhn.fhir.jpa.entity.TermConcept;
|
||||||
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink;
|
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink;
|
||||||
import ca.uhn.fhir.jpa.term.IRecordHandler;
|
import ca.uhn.fhir.jpa.term.IRecordHandler;
|
||||||
import ca.uhn.fhir.util.ValidateUtil;
|
import ca.uhn.fhir.util.ValidateUtil;
|
||||||
import com.google.common.collect.ArrayListMultimap;
|
|
||||||
import org.apache.commons.csv.CSVRecord;
|
import org.apache.commons.csv.CSVRecord;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -37,11 +36,9 @@ public class HierarchyHandler implements IRecordHandler {
|
||||||
public static final String PARENT = "PARENT";
|
public static final String PARENT = "PARENT";
|
||||||
public static final String CHILD = "CHILD";
|
public static final String CHILD = "CHILD";
|
||||||
private final Map<String, TermConcept> myCode2Concept;
|
private final Map<String, TermConcept> myCode2Concept;
|
||||||
private final ArrayListMultimap<TermConcept, String> myUnanchoredChildConceptsToParentCodes;
|
|
||||||
|
|
||||||
public HierarchyHandler(Map<String, TermConcept> theCode2concept, ArrayListMultimap<TermConcept, String> theunanchoredChildConceptsToParentCodes) {
|
public HierarchyHandler(Map<String, TermConcept> theCode2concept) {
|
||||||
myCode2Concept = theCode2concept;
|
myCode2Concept = theCode2concept;
|
||||||
myUnanchoredChildConceptsToParentCodes = theunanchoredChildConceptsToParentCodes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -51,14 +48,12 @@ public class HierarchyHandler implements IRecordHandler {
|
||||||
if (isNotBlank(parent) && isNotBlank(child)) {
|
if (isNotBlank(parent) && isNotBlank(child)) {
|
||||||
|
|
||||||
TermConcept childConcept = myCode2Concept.get(child);
|
TermConcept childConcept = myCode2Concept.get(child);
|
||||||
ValidateUtil.isNotNullOrThrowUnprocessableEntity(childConcept, "Child code %s not found", child);
|
ValidateUtil.isNotNullOrThrowUnprocessableEntity(childConcept, "Child code %s not found in file", child);
|
||||||
|
|
||||||
TermConcept parentConcept = myCode2Concept.get(parent);
|
TermConcept parentConcept = myCode2Concept.get(parent);
|
||||||
if (parentConcept == null) {
|
ValidateUtil.isNotNullOrThrowUnprocessableEntity(parentConcept, "Parent code %s not found in file", child);
|
||||||
myUnanchoredChildConceptsToParentCodes.put(childConcept, parent);
|
|
||||||
} else {
|
parentConcept.addChild(childConcept, TermConceptParentChildLink.RelationshipTypeEnum.ISA);
|
||||||
parentConcept.addChild(childConcept, TermConceptParentChildLink.RelationshipTypeEnum.ISA);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,6 @@ package ca.uhn.fhir.jpa.term;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.support.IContextValidationSupport;
|
import ca.uhn.fhir.context.support.IContextValidationSupport;
|
||||||
import ca.uhn.fhir.jpa.dao.r4.BaseJpaR4Test;
|
import ca.uhn.fhir.jpa.dao.r4.BaseJpaR4Test;
|
||||||
import ca.uhn.fhir.jpa.entity.TermCodeSystem;
|
|
||||||
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
|
|
||||||
import ca.uhn.fhir.jpa.entity.TermConcept;
|
import ca.uhn.fhir.jpa.entity.TermConcept;
|
||||||
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink;
|
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink;
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
|
@ -12,23 +10,26 @@ import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||||
import ca.uhn.fhir.rest.param.UriParam;
|
import ca.uhn.fhir.rest.param.UriParam;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
import ca.uhn.fhir.util.TestUtil;
|
import ca.uhn.fhir.util.TestUtil;
|
||||||
import org.hl7.fhir.r4.model.*;
|
import org.hl7.fhir.r4.model.CodeSystem;
|
||||||
|
import org.hl7.fhir.r4.model.CodeType;
|
||||||
|
import org.hl7.fhir.r4.model.Coding;
|
||||||
|
import org.hl7.fhir.r4.model.Parameters;
|
||||||
|
import org.hl7.fhir.r4.model.StringType;
|
||||||
|
import org.hl7.fhir.r4.model.ValueSet;
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.test.context.TestPropertySource;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.containsString;
|
import static org.hamcrest.CoreMatchers.containsString;
|
||||||
import static org.hamcrest.Matchers.contains;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.hamcrest.Matchers.empty;
|
import static org.junit.Assert.assertThat;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
public class TerminologySvcDeltaR4Test extends BaseJpaR4Test {
|
public class TerminologySvcDeltaR4Test extends BaseJpaR4Test {
|
||||||
private static final Logger ourLog = LoggerFactory.getLogger(TerminologySvcDeltaR4Test.class);
|
private static final Logger ourLog = LoggerFactory.getLogger(TerminologySvcDeltaR4Test.class);
|
||||||
|
@ -114,8 +115,9 @@ public class TerminologySvcDeltaR4Test extends BaseJpaR4Test {
|
||||||
});
|
});
|
||||||
|
|
||||||
delta = new CustomTerminologySet();
|
delta = new CustomTerminologySet();
|
||||||
delta.addUnanchoredChildConcept("RootA", "ChildAA", "Child AA");
|
TermConcept root = delta.addRootConcept("RootA", "Root A");
|
||||||
delta.addUnanchoredChildConcept("RootA", "ChildAB", "Child AB");
|
root.addChild(TermConceptParentChildLink.RelationshipTypeEnum.ISA).setCode("ChildAA").setDisplay("Child AA");
|
||||||
|
root.addChild(TermConceptParentChildLink.RelationshipTypeEnum.ISA).setCode("ChildAB").setDisplay("Child AB");
|
||||||
myTermCodeSystemStorageSvc.applyDeltaCodeSystemsAdd("http://foo/cs", delta);
|
myTermCodeSystemStorageSvc.applyDeltaCodeSystemsAdd("http://foo/cs", delta);
|
||||||
assertHierarchyContains(
|
assertHierarchyContains(
|
||||||
"RootA seq=1",
|
"RootA seq=1",
|
||||||
|
@ -135,25 +137,29 @@ public class TerminologySvcDeltaR4Test extends BaseJpaR4Test {
|
||||||
|
|
||||||
delta = new CustomTerminologySet();
|
delta = new CustomTerminologySet();
|
||||||
delta.addRootConcept("RootA", "Root A")
|
delta.addRootConcept("RootA", "Root A")
|
||||||
.addChild(TermConceptParentChildLink.RelationshipTypeEnum.ISA).setCode("ChildAA").setDisplay("Child AA");
|
.addChild(TermConceptParentChildLink.RelationshipTypeEnum.ISA).setCode("ChildAA").setDisplay("Child AA")
|
||||||
|
.addChild(TermConceptParentChildLink.RelationshipTypeEnum.ISA).setCode("ChildAAA").setDisplay("Child AAA");
|
||||||
delta.addRootConcept("RootB", "Root B");
|
delta.addRootConcept("RootB", "Root B");
|
||||||
outcome = myTermCodeSystemStorageSvc.applyDeltaCodeSystemsAdd("http://foo/cs", delta);
|
outcome = myTermCodeSystemStorageSvc.applyDeltaCodeSystemsAdd("http://foo/cs", delta);
|
||||||
assertHierarchyContains(
|
assertHierarchyContains(
|
||||||
"RootA seq=1",
|
"RootA seq=1",
|
||||||
" ChildAA seq=1",
|
" ChildAA seq=1",
|
||||||
|
" ChildAAA seq=1",
|
||||||
"RootB seq=2"
|
"RootB seq=2"
|
||||||
);
|
);
|
||||||
assertEquals(3, outcome.getUpdatedConceptCount());
|
assertEquals(4, outcome.getUpdatedConceptCount());
|
||||||
|
|
||||||
delta = new CustomTerminologySet();
|
delta = new CustomTerminologySet();
|
||||||
delta.addUnanchoredChildConcept("RootB", "ChildAA", "Child AA");
|
delta.addRootConcept("RootB", "Root B")
|
||||||
|
.addChild(TermConceptParentChildLink.RelationshipTypeEnum.ISA).setCode("ChildAA").setDisplay("Child AA");
|
||||||
outcome = myTermCodeSystemStorageSvc.applyDeltaCodeSystemsAdd("http://foo/cs", delta);
|
outcome = myTermCodeSystemStorageSvc.applyDeltaCodeSystemsAdd("http://foo/cs", delta);
|
||||||
assertEquals(1, outcome.getUpdatedConceptCount());
|
|
||||||
assertHierarchyContains(
|
assertHierarchyContains(
|
||||||
"RootA seq=1",
|
"RootA seq=1",
|
||||||
"RootB seq=2",
|
"RootB seq=2",
|
||||||
" ChildAA seq=1"
|
" ChildAA seq=1",
|
||||||
|
" ChildAAA seq=1"
|
||||||
);
|
);
|
||||||
|
assertEquals(2, outcome.getUpdatedConceptCount());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,11 +172,6 @@ public class TerminologySvcDeltaR4Test extends BaseJpaR4Test {
|
||||||
cs.setContent(CodeSystem.CodeSystemContentMode.COMPLETE);
|
cs.setContent(CodeSystem.CodeSystemContentMode.COMPLETE);
|
||||||
myCodeSystemDao.create(cs);
|
myCodeSystemDao.create(cs);
|
||||||
|
|
||||||
CodeSystem delta = new CodeSystem();
|
|
||||||
delta
|
|
||||||
.addConcept()
|
|
||||||
.setCode("codeA")
|
|
||||||
.setDisplay("displayA");
|
|
||||||
try {
|
try {
|
||||||
myTermCodeSystemStorageSvc.applyDeltaCodeSystemsAdd("http://foo", new CustomTerminologySet());
|
myTermCodeSystemStorageSvc.applyDeltaCodeSystemsAdd("http://foo", new CustomTerminologySet());
|
||||||
fail();
|
fail();
|
||||||
|
@ -180,6 +181,44 @@ public class TerminologySvcDeltaR4Test extends BaseJpaR4Test {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddChildToExistingChild() {
|
||||||
|
CustomTerminologySet set;
|
||||||
|
|
||||||
|
// Create not-present
|
||||||
|
CodeSystem cs = new CodeSystem();
|
||||||
|
cs.setUrl("http://foo");
|
||||||
|
cs.setContent(CodeSystem.CodeSystemContentMode.NOTPRESENT);
|
||||||
|
myCodeSystemDao.create(cs);
|
||||||
|
|
||||||
|
// Add parent with 1 child
|
||||||
|
set = new CustomTerminologySet();
|
||||||
|
set.addRootConcept("ParentA", "Parent A")
|
||||||
|
.addChild(TermConceptParentChildLink.RelationshipTypeEnum.ISA).setCode("ChildA").setDisplay("Child A");
|
||||||
|
myTermCodeSystemStorageSvc.applyDeltaCodeSystemsAdd("http://foo", set);
|
||||||
|
|
||||||
|
// Check so far
|
||||||
|
assertHierarchyContains(
|
||||||
|
"ParentA seq=1",
|
||||||
|
" ChildA seq=1"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Add sub-child to existing child
|
||||||
|
ourLog.info("*** Adding child to existing child");
|
||||||
|
set = new CustomTerminologySet();
|
||||||
|
set.addRootConcept("ChildA", "Child A")
|
||||||
|
.addChild(TermConceptParentChildLink.RelationshipTypeEnum.ISA).setCode("ChildAA").setDisplay("Child AA");
|
||||||
|
myTermCodeSystemStorageSvc.applyDeltaCodeSystemsAdd("http://foo", set);
|
||||||
|
|
||||||
|
// Check so far
|
||||||
|
assertHierarchyContains(
|
||||||
|
"ParentA seq=1",
|
||||||
|
" ChildA seq=1",
|
||||||
|
" ChildAA seq=1"
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAddWithoutPreExistingCodeSystem() {
|
public void testAddWithoutPreExistingCodeSystem() {
|
||||||
|
|
||||||
|
@ -229,27 +268,6 @@ public class TerminologySvcDeltaR4Test extends BaseJpaR4Test {
|
||||||
assertEquals("CODEA1", myTermSvc.lookupCode(myFhirCtx, "http://foo", "codea").getCodeDisplay());
|
assertEquals("CODEA1", myTermSvc.lookupCode(myFhirCtx, "http://foo", "codea").getCodeDisplay());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testAddUnanchoredWithUnknownParent() {
|
|
||||||
createNotPresentCodeSystem();
|
|
||||||
|
|
||||||
// Add root code
|
|
||||||
CustomTerminologySet delta = new CustomTerminologySet();
|
|
||||||
delta.addRootConcept("CodeA", "Code A");
|
|
||||||
UploadStatistics outcome = myTermCodeSystemStorageSvc.applyDeltaCodeSystemsAdd("http://foo", delta);
|
|
||||||
assertEquals(1, outcome.getUpdatedConceptCount());
|
|
||||||
|
|
||||||
// Try to add child to nonexistent root code
|
|
||||||
delta = new CustomTerminologySet();
|
|
||||||
delta.addUnanchoredChildConcept("CodeB", "CodeBB", "Code BB");
|
|
||||||
try {
|
|
||||||
myTermCodeSystemStorageSvc.applyDeltaCodeSystemsAdd("http://foo/cs", delta);
|
|
||||||
fail();
|
|
||||||
} catch (InvalidRequestException e) {
|
|
||||||
assertThat(e.getMessage(), containsString("Unable to add code \"CodeBB\" to unknown parent: CodeB"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAddRelocateHierarchy() {
|
public void testAddRelocateHierarchy() {
|
||||||
createNotPresentCodeSystem();
|
createNotPresentCodeSystem();
|
||||||
|
@ -280,9 +298,11 @@ public class TerminologySvcDeltaR4Test extends BaseJpaR4Test {
|
||||||
// Move a single child code to a new spot and make sure the hierarchy comes along
|
// Move a single child code to a new spot and make sure the hierarchy comes along
|
||||||
// for the ride..
|
// for the ride..
|
||||||
delta = new CustomTerminologySet();
|
delta = new CustomTerminologySet();
|
||||||
delta.addUnanchoredChildConcept("CodeB", "CodeAA", "Code AA");
|
delta
|
||||||
|
.addRootConcept("CodeB", "Code B")
|
||||||
|
.addChild(TermConceptParentChildLink.RelationshipTypeEnum.ISA).setCode("CodeAA").setDisplay("Code AA");
|
||||||
outcome = myTermCodeSystemStorageSvc.applyDeltaCodeSystemsAdd("http://foo/cs", delta);
|
outcome = myTermCodeSystemStorageSvc.applyDeltaCodeSystemsAdd("http://foo/cs", delta);
|
||||||
assertEquals(3, outcome.getUpdatedConceptCount());
|
assertEquals(2, outcome.getUpdatedConceptCount());
|
||||||
assertHierarchyContains(
|
assertHierarchyContains(
|
||||||
"CodeA seq=1",
|
"CodeA seq=1",
|
||||||
"CodeB seq=2",
|
"CodeB seq=2",
|
||||||
|
@ -431,8 +451,6 @@ public class TerminologySvcDeltaR4Test extends BaseJpaR4Test {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private ValueSet expandNotPresentCodeSystem() {
|
private ValueSet expandNotPresentCodeSystem() {
|
||||||
ValueSet vs = new ValueSet();
|
ValueSet vs = new ValueSet();
|
||||||
vs.setUrl("http://foo/vs");
|
vs.setUrl("http://foo/vs");
|
||||||
|
|
|
@ -146,8 +146,6 @@ public class RenameColumnTask extends BaseTableTask<RenameColumnTask> {
|
||||||
|
|
||||||
return new EqualsBuilder()
|
return new EqualsBuilder()
|
||||||
.appendSuper(super.equals(theO))
|
.appendSuper(super.equals(theO))
|
||||||
.append(myIsOkayIfNeitherColumnExists, that.myIsOkayIfNeitherColumnExists)
|
|
||||||
.append(myDeleteTargetColumnFirstIfBothExist, that.myDeleteTargetColumnFirstIfBothExist)
|
|
||||||
.append(myOldName, that.myOldName)
|
.append(myOldName, that.myOldName)
|
||||||
.append(myNewName, that.myNewName)
|
.append(myNewName, that.myNewName)
|
||||||
.isEquals();
|
.isEquals();
|
||||||
|
|
Loading…
Reference in New Issue