Merge remote-tracking branch 'remotes/origin/master' into im_20200316_lastn_operation_elasticsearch

# Conflicts:
#	hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/extractor/BaseSearchParamExtractor.java
This commit is contained in:
ianmarshall 2020-05-29 23:54:11 -04:00
commit f48214deda
33 changed files with 1262 additions and 478 deletions

View File

@ -0,0 +1,4 @@
---
type: add
issue: 1666
title: "The email sender used by email subscriptions can now be configured with TLS parameters."

View File

@ -0,0 +1,5 @@
---
type: add
issue: 1865
title: "The validator will now correctly issue a warning instead of an error if a code can't be found when validating a
code in a CodeSystem where the content mode (CodeSystem.content) has a value of *fragment*."

View File

@ -0,0 +1,7 @@
---
type: add
issue: 1871
title: "In the JPA server, when indexing Date SearchParameters where the value being indexed is a
FHIR Period that is missing either a lower bound or an upper bound, a default value representing an
extreme 'beginning of time' or 'end of time' is now used. This allows range searches to return more
accurate results."

View File

@ -522,3 +522,72 @@ The following columns are common to **all HFJ_SPIDX_xxx tables**.
</tbody> </tbody>
</table> </table>
# HFJ_SPIDX_DATE: Date Search Parameters
For any FHIR Search Parameter of type *date* that generates a database index, a row in the *HFJ_SPIDX_DATE* table will be created.
## Columns
The following columns are common to **all HFJ_SPIDX_xxx tables**.
<table class="table table-striped table-condensed">
<thead>
<tr>
<th>Name</th>
<th>Relationships</th>
<th>Datatype</th>
<th>Nullable</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>SP_VALUE_LOW</td>
<td></td>
<td>Timestamp</td>
<td>Nullable</td>
<td>
This is the lower bound of the date in question.
<ul>
<li>For a point in time date to millisecond precision (such as an Instant with a value of <code>2020-05-26T15:00:00.000</code>) this represents the exact value.</li>
<li>For an instant value with lower precision, this represents the start of the possible range denoted by the value. For example, for a value of <code>2020-05-26</code> this represents <code>2020-05-26T00:00:00.000</code>.</li>
<li>For a Period with a lower (start) value present, this column contains that value.</li>
<li>For a Period with no lower (start) value present, this column contains a timestamp representing the "start of time".</li>
</ul>
</td>
</tr>
<tr>
<td>SP_VALUE_HIGH</td>
<td></td>
<td>Timestamp</td>
<td>Nullable</td>
<td>
This is the upper bound of the date in question.
<ul>
<li>For a point in time date to millisecond precision (such as an Instant with a value of <code>2020-05-26T15:00:00.000</code>) this represents the exact value.</li>
<li>For an instant value with lower precision, this represents the start of the possible range denoted by the value. For example, for a value of <code>2020-05-26</code> this represents <code>2020-05-26T23:59:59.999</code>.</li>
<li>For a Period with an upper (end) value present, this column contains that value.</li>
<li>For a Period with no upper (end) value present, this column contains a timestamp representing the "end of time".</li>
</ul>
</td>
</tr>
<tr>
<td>SP_VALUE_LOW_DATE_ORDINAL</td>
<td></td>
<td>Integer</td>
<td>Nullable</td>
<td>
This column contains the same Timestamp as <code>SP_VALUE_LOW</code>, but truncated to Date precision and formatted as an integer in the format "YYYYMMDD".
</td>
</tr>
<tr>
<td>SP_VALUE_HIGH_DATE_ORDINAL</td>
<td></td>
<td>Integer</td>
<td>Nullable</td>
<td>
This column contains the same Timestamp as <code>SP_VALUE_HIGH</code>, but truncated to Date precision and formatted as an integer in the format "YYYYMMDD".
</td>
</tr>
</tbody>
</table>

View File

@ -14,7 +14,7 @@ There are a several implementations of the [IValidationSupport](/hapi-fhir/apido
[JavaDoc](/hapi-fhir/apidocs/hapi-fhir-validation/org/hl7/fhir/common/hapi/validation/support/ValidationSupportChain.html) / [Source](https://github.com/jamesagnew/hapi-fhir/blob/ja_20200218_validation_api_changes/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/support/ValidationSupportChain.java) [JavaDoc](/hapi-fhir/apidocs/hapi-fhir-validation/org/hl7/fhir/common/hapi/validation/support/ValidationSupportChain.html) / [Source](https://github.com/jamesagnew/hapi-fhir/blob/ja_20200218_validation_api_changes/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/support/ValidationSupportChain.java)
This module can be used to combine multiple implementations together so that for every request, each support class instance in the chain is tried in sequence. Note that nearly all methods in the [IValidationSupport](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/context/support/IValidationSupport.html) interface are permitted to return `null` if they are not able to service a particular method call. So for example, if a call to the [`validateCode`](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/context/support/IValidationSupport.html#validateCode(ca.uhn.fhir.context.support.IValidationSupport,ca.uhn.fhir.context.support.ConceptValidationOptions,java.lang.String,java.lang.String,java.lang.String,java.lang.String)) method is made, the validator will try each module in the chain until one of them returns a non-null response. This module can be used to combine multiple implementations together so that for every request, each support class instance in the chain is tried in sequence. Note that nearly all methods in the [IValidationSupport](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/context/support/IValidationSupport.html) interface are permitted to return `null` if they are not able to service a particular method call. So for example, if a call to the [`validateCode`](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/context/support/IValidationSupport.html#validateCode(ca.uhn.fhir.context.support.ValidationSupportContext,ca.uhn.fhir.context.support.ConceptValidationOptions,java.lang.String,java.lang.String,java.lang.String,java.lang.String)) method is made, the validator will try each module in the chain until one of them returns a non-null response.
# DefaultProfileValidationSupport # DefaultProfileValidationSupport

View File

@ -204,6 +204,9 @@ public interface IFhirResourceDao<T extends IBaseResource> extends IDao {
IBundleProvider search(SearchParameterMap theParams, RequestDetails theRequestDetails, HttpServletResponse theServletResponse); IBundleProvider search(SearchParameterMap theParams, RequestDetails theRequestDetails, HttpServletResponse theServletResponse);
/**
* Search for IDs for processing a match URLs, etc.
*/
Set<ResourcePersistentId> searchForIds(SearchParameterMap theParams, RequestDetails theRequest); Set<ResourcePersistentId> searchForIds(SearchParameterMap theParams, RequestDetails theRequest);
/** /**

View File

@ -1221,9 +1221,9 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
@Override @Override
public ResourceTable updateInternal(RequestDetails theRequestDetails, T theResource, boolean thePerformIndexing, boolean theForceUpdateVersion, public ResourceTable updateInternal(RequestDetails theRequestDetails, T theResource, boolean thePerformIndexing, boolean theForceUpdateVersion,
IBasePersistedResource theEntity2, IIdType theResourceId, IBaseResource theOldResource, TransactionDetails theTransactionDetails) { IBasePersistedResource theEntity, IIdType theResourceId, IBaseResource theOldResource, TransactionDetails theTransactionDetails) {
ResourceTable entity = (ResourceTable) theEntity2; ResourceTable entity = (ResourceTable) theEntity;
// We'll update the resource ID with the correct version later but for // We'll update the resource ID with the correct version later but for
// now at least set it to something useful for the interceptors // now at least set it to something useful for the interceptors

View File

@ -35,6 +35,7 @@ import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceContextType; import javax.persistence.PersistenceContextType;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet;
import java.util.List; import java.util.List;
@Service @Service
@ -67,13 +68,20 @@ public class DaoSearchParamSynchronizer {
} }
private <T extends BaseResourceIndex> void synchronize(ResourceTable theEntity, AddRemoveCount theAddRemoveCount, Collection<T> theNewParams, Collection<T> theExistingParams) { private <T extends BaseResourceIndex> void synchronize(ResourceTable theEntity, AddRemoveCount theAddRemoveCount, Collection<T> theNewParams, Collection<T> theExistingParams) {
for (T next : theNewParams) { Collection<T> newParams = theNewParams;
for (T next : newParams) {
next.setPartitionId(theEntity.getPartitionId()); next.setPartitionId(theEntity.getPartitionId());
next.calculateHashes(); next.calculateHashes();
} }
List<T> paramsToRemove = subtract(theExistingParams, theNewParams); /*
List<T> paramsToAdd = subtract(theNewParams, theExistingParams); * HashCodes may have changed as a result of setting the partition ID, so
* create a new set that will reflect the new hashcodes
*/
newParams = new HashSet<>(newParams);
List<T> paramsToRemove = subtract(theExistingParams, newParams);
List<T> paramsToAdd = subtract(newParams, theExistingParams);
tryToReuseIndexEntities(paramsToRemove, paramsToAdd); tryToReuseIndexEntities(paramsToRemove, paramsToAdd);
for (T next : paramsToRemove) { for (T next : paramsToRemove) {
@ -127,8 +135,12 @@ public class DaoSearchParamSynchronizer {
return new ArrayList<>(); return new ArrayList<>();
} }
ArrayList<T> retVal = new ArrayList<>(theSubtractFrom); ArrayList<T> retVal = new ArrayList<>();
retVal.removeAll(theToSubtract); for (T next : theSubtractFrom) {
if (!theToSubtract.contains(next)) {
retVal.add(next);
}
}
return retVal; return retVal;
} }
} }

View File

@ -36,8 +36,6 @@ import static org.apache.commons.lang3.StringUtils.length;
@Entity @Entity
@Table(name = "TRM_CONCEPT_PROPERTY", uniqueConstraints = { @Table(name = "TRM_CONCEPT_PROPERTY", uniqueConstraints = {
}, indexes = {
@Index(name = "IDX_CONCEPTPROP_CONCEPTPID", columnList = "CONCEPT_PID")
}) })
public class TermConceptProperty implements Serializable { public class TermConceptProperty implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;

View File

@ -67,7 +67,7 @@ public class TermReadSvcR4 extends BaseTermReadSvcImpl implements ITermReadSvcR4
@Transactional(dontRollbackOn = {ExpansionTooCostlyException.class}) @Transactional(dontRollbackOn = {ExpansionTooCostlyException.class})
@Override @Override
public IValidationSupport.ValueSetExpansionOutcome expandValueSet(ValidationSupportContext theValidationSupportContext, ValueSetExpansionOptions theExpansionOptions, IBaseResource theValueSetToExpand) { public IValidationSupport.ValueSetExpansionOutcome expandValueSet(ValidationSupportContext theValidationSupportContext, ValueSetExpansionOptions theExpansionOptions, IBaseResource theValueSetToExpand) {
ValueSet expanded = super.expandValueSet(theExpansionOptions, (ValueSet) theValueSetToExpand); ValueSet expanded = super.expandValueSet(theExpansionOptions, (ValueSet) theValueSetToExpand);
return new IValidationSupport.ValueSetExpansionOutcome(expanded); return new IValidationSupport.ValueSetExpansionOutcome(expanded);
} }
@ -110,21 +110,21 @@ public class TermReadSvcR4 extends BaseTermReadSvcImpl implements ITermReadSvcR4
} }
if (!haveValidated) { if (!haveValidated) {
TransactionTemplate txTemplate = new TransactionTemplate(myTransactionManager); TransactionTemplate txTemplate = new TransactionTemplate(myTransactionManager);
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
codeOpt = txTemplate.execute(t -> findCode(theCodeSystem, theCode).map(c->c.toVersionIndependentConcept())); codeOpt = txTemplate.execute(t -> findCode(theCodeSystem, theCode).map(c -> c.toVersionIndependentConcept()));
} }
if (codeOpt != null && codeOpt.isPresent()) { if (codeOpt != null && codeOpt.isPresent()) {
VersionIndependentConcept code = codeOpt.get(); VersionIndependentConcept code = codeOpt.get();
IValidationSupport.CodeValidationResult retVal = new IValidationSupport.CodeValidationResult() IValidationSupport.CodeValidationResult retVal = new IValidationSupport.CodeValidationResult()
.setCode(code.getCode()); // AAAAAAAAAAA format .setCode(code.getCode());
return retVal; return retVal;
} }
return new IValidationSupport.CodeValidationResult() return new IValidationSupport.CodeValidationResult()
.setSeverity(IssueSeverity.ERROR) .setSeverity(IssueSeverity.ERROR)
.setMessage("Unknown code {" + theCodeSystem + "}" + theCode); .setMessage("Unknown code {" + theCodeSystem + "}" + theCode);
} }
@Override @Override

View File

@ -432,6 +432,145 @@ public class FhirResourceDaoDstu2SearchNoFtTest extends BaseJpaDstu2Test {
} }
@Test
public void testDatePeriodParamEndOnly() {
{
Encounter enc = new Encounter();
enc.addIdentifier().setSystem("testDatePeriodParam").setValue("02");
enc.getPeriod().getEndElement().setValueAsString("2001-01-02");
myEncounterDao.create(enc, mySrd);
}
SearchParameterMap params;
List<Encounter> encs;
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam(null, "2001-01-03"));
params.add(Encounter.SP_IDENTIFIER, new IdentifierDt("testDatePeriodParam", "02"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-01", "2001-01-03"));
params.add(Encounter.SP_IDENTIFIER, new IdentifierDt("testDatePeriodParam", "02"));
// encs = toList(ourEncounterDao.search(params));
// assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-01", null));
params.add(Encounter.SP_IDENTIFIER, new IdentifierDt("testDatePeriodParam", "02"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam(null, "2001-01-01"));
params.add(Encounter.SP_IDENTIFIER, new IdentifierDt("testDatePeriodParam", "02"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-03", null));
params.add(Encounter.SP_IDENTIFIER, new IdentifierDt("testDatePeriodParam", "02"));
encs = toList(myEncounterDao.search(params));
assertEquals(0, encs.size());
}
@Test
public void testDatePeriodParamStartAndEnd() {
{
Encounter enc = new Encounter();
enc.addIdentifier().setSystem("testDatePeriodParam").setValue("03");
enc.getPeriod().getStartElement().setValueAsString("2001-01-02");
enc.getPeriod().getEndElement().setValueAsString("2001-01-03");
myEncounterDao.create(enc, mySrd);
}
SearchParameterMap params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-01", "2001-01-03"));
params.add(Encounter.SP_IDENTIFIER, new IdentifierDt("testDatePeriodParam", "03"));
List<Encounter> encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-02", "2001-01-06"));
params.add(Encounter.SP_IDENTIFIER, new IdentifierDt("testDatePeriodParam", "03"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-01", null));
params.add(Encounter.SP_IDENTIFIER, new IdentifierDt("testDatePeriodParam", "03"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam(null, "2001-01-03"));
params.add(Encounter.SP_IDENTIFIER, new IdentifierDt("testDatePeriodParam", "03"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam(null, "2001-01-05"));
params.add(Encounter.SP_IDENTIFIER, new IdentifierDt("testDatePeriodParam", "03"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam(null, "2001-01-01"));
params.add(Encounter.SP_IDENTIFIER, new IdentifierDt("testDatePeriodParam", "03"));
encs = toList(myEncounterDao.search(params));
assertEquals(0, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-05", null));
params.add(Encounter.SP_IDENTIFIER, new IdentifierDt("testDatePeriodParam", "03"));
encs = toList(myEncounterDao.search(params));
assertEquals(0, encs.size());
}
@Test
public void testDatePeriodParamStartOnly() {
{
Encounter enc = new Encounter();
enc.addIdentifier().setSystem("testDatePeriodParam").setValue("01");
enc.getPeriod().getStartElement().setValueAsString("2001-01-02");
myEncounterDao.create(enc, mySrd);
}
SearchParameterMap params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-01", "2001-01-03"));
params.add(Encounter.SP_IDENTIFIER, new IdentifierDt("testDatePeriodParam", "01"));
List<Encounter> encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-01", null));
params.add(Encounter.SP_IDENTIFIER, new IdentifierDt("testDatePeriodParam", "01"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam(null, "2001-01-03"));
params.add(Encounter.SP_IDENTIFIER, new IdentifierDt("testDatePeriodParam", "01"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam(null, "2001-01-01"));
params.add(Encounter.SP_IDENTIFIER, new IdentifierDt("testDatePeriodParam", "01"));
encs = toList(myEncounterDao.search(params));
assertEquals(0, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-03", null));
params.add(Encounter.SP_IDENTIFIER, new IdentifierDt("testDatePeriodParam", "01"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
}
@Test @Test
public void testSearchCompositeParam() { public void testSearchCompositeParam() {
Observation o1 = new Observation(); Observation o1 = new Observation();

View File

@ -584,143 +584,6 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
} }
} }
@Test
public void testDatePeriodParamEndOnly() {
{
Encounter enc = new Encounter();
enc.addIdentifier().setSystem("testDatePeriodParam").setValue("02");
enc.getPeriod().getEndElement().setValueAsString("2001-01-02");
myEncounterDao.create(enc, mySrd);
}
SearchParameterMap params;
List<Encounter> encs;
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam(null, "2001-01-03"));
params.add(Encounter.SP_IDENTIFIER, new IdentifierDt("testDatePeriodParam", "02"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-01", "2001-01-03"));
params.add(Encounter.SP_IDENTIFIER, new IdentifierDt("testDatePeriodParam", "02"));
// encs = toList(ourEncounterDao.search(params));
// assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-01", null));
params.add(Encounter.SP_IDENTIFIER, new IdentifierDt("testDatePeriodParam", "02"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam(null, "2001-01-01"));
params.add(Encounter.SP_IDENTIFIER, new IdentifierDt("testDatePeriodParam", "02"));
encs = toList(myEncounterDao.search(params));
assertEquals(0, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-03", null));
params.add(Encounter.SP_IDENTIFIER, new IdentifierDt("testDatePeriodParam", "02"));
encs = toList(myEncounterDao.search(params));
assertEquals(0, encs.size());
}
@Test
public void testDatePeriodParamStartAndEnd() {
{
Encounter enc = new Encounter();
enc.addIdentifier().setSystem("testDatePeriodParam").setValue("03");
enc.getPeriod().getStartElement().setValueAsString("2001-01-02");
enc.getPeriod().getEndElement().setValueAsString("2001-01-03");
myEncounterDao.create(enc, mySrd);
}
SearchParameterMap params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-01", "2001-01-03"));
params.add(Encounter.SP_IDENTIFIER, new IdentifierDt("testDatePeriodParam", "03"));
List<Encounter> encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-02", "2001-01-06"));
params.add(Encounter.SP_IDENTIFIER, new IdentifierDt("testDatePeriodParam", "03"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-01", null));
params.add(Encounter.SP_IDENTIFIER, new IdentifierDt("testDatePeriodParam", "03"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam(null, "2001-01-03"));
params.add(Encounter.SP_IDENTIFIER, new IdentifierDt("testDatePeriodParam", "03"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam(null, "2001-01-05"));
params.add(Encounter.SP_IDENTIFIER, new IdentifierDt("testDatePeriodParam", "03"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam(null, "2001-01-01"));
params.add(Encounter.SP_IDENTIFIER, new IdentifierDt("testDatePeriodParam", "03"));
encs = toList(myEncounterDao.search(params));
assertEquals(0, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-05", null));
params.add(Encounter.SP_IDENTIFIER, new IdentifierDt("testDatePeriodParam", "03"));
encs = toList(myEncounterDao.search(params));
assertEquals(0, encs.size());
}
@Test
public void testDatePeriodParamStartOnly() {
{
Encounter enc = new Encounter();
enc.addIdentifier().setSystem("testDatePeriodParam").setValue("01");
enc.getPeriod().getStartElement().setValueAsString("2001-01-02");
myEncounterDao.create(enc, mySrd);
}
SearchParameterMap params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-01", "2001-01-03"));
params.add(Encounter.SP_IDENTIFIER, new IdentifierDt("testDatePeriodParam", "01"));
List<Encounter> encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-01", null));
params.add(Encounter.SP_IDENTIFIER, new IdentifierDt("testDatePeriodParam", "01"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam(null, "2001-01-03"));
params.add(Encounter.SP_IDENTIFIER, new IdentifierDt("testDatePeriodParam", "01"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam(null, "2001-01-01"));
params.add(Encounter.SP_IDENTIFIER, new IdentifierDt("testDatePeriodParam", "01"));
encs = toList(myEncounterDao.search(params));
assertEquals(0, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-03", null));
params.add(Encounter.SP_IDENTIFIER, new IdentifierDt("testDatePeriodParam", "01"));
encs = toList(myEncounterDao.search(params));
assertEquals(0, encs.size());
}
@Test @Test
public void testDeleteFailsIfIncomingLinks() { public void testDeleteFailsIfIncomingLinks() {

View File

@ -959,6 +959,145 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
} }
@Test
public void testDatePeriodParamEndOnly() {
{
Encounter enc = new Encounter();
enc.addIdentifier().setSystem("testDatePeriodParam").setValue("02");
enc.getPeriod().getEndElement().setValueAsString("2001-01-02");
myEncounterDao.create(enc, mySrd);
}
SearchParameterMap params;
List<Encounter> encs;
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam(null, "2001-01-03"));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "02"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-01", "2001-01-03"));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "02"));
// encs = toList(ourEncounterDao.search(params));
// assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-01", null));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "02"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam(null, "2001-01-01"));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "02"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-03", null));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "02"));
encs = toList(myEncounterDao.search(params));
assertEquals(0, encs.size());
}
@Test
public void testDatePeriodParamStartAndEnd() {
{
Encounter enc = new Encounter();
enc.addIdentifier().setSystem("testDatePeriodParam").setValue("03");
enc.getPeriod().getStartElement().setValueAsString("2001-01-02");
enc.getPeriod().getEndElement().setValueAsString("2001-01-03");
myEncounterDao.create(enc, mySrd);
}
SearchParameterMap params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-01", "2001-01-03"));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "03"));
List<Encounter> encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-02", "2001-01-06"));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "03"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-01", null));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "03"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam(null, "2001-01-03"));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "03"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam(null, "2001-01-05"));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "03"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam(null, "2001-01-01"));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "03"));
encs = toList(myEncounterDao.search(params));
assertEquals(0, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-05", null));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "03"));
encs = toList(myEncounterDao.search(params));
assertEquals(0, encs.size());
}
@Test
public void testDatePeriodParamStartOnly() {
{
Encounter enc = new Encounter();
enc.addIdentifier().setSystem("testDatePeriodParam").setValue("01");
enc.getPeriod().getStartElement().setValueAsString("2001-01-02");
myEncounterDao.create(enc, mySrd);
}
SearchParameterMap params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-01", "2001-01-03"));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "01"));
List<Encounter> encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-01", null));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "01"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam(null, "2001-01-03"));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "01"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam(null, "2001-01-01"));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "01"));
encs = toList(myEncounterDao.search(params));
assertEquals(0, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-03", null));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "01"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
}
/** /**
* #222 * #222
*/ */

View File

@ -870,143 +870,6 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
} }
} }
@Test
public void testDatePeriodParamEndOnly() {
{
Encounter enc = new Encounter();
enc.addIdentifier().setSystem("testDatePeriodParam").setValue("02");
enc.getPeriod().getEndElement().setValueAsString("2001-01-02");
myEncounterDao.create(enc, mySrd);
}
SearchParameterMap params;
List<Encounter> encs;
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam(null, "2001-01-03"));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "02"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-01", "2001-01-03"));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "02"));
// encs = toList(ourEncounterDao.search(params));
// assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-01", null));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "02"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam(null, "2001-01-01"));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "02"));
encs = toList(myEncounterDao.search(params));
assertEquals(0, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-03", null));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "02"));
encs = toList(myEncounterDao.search(params));
assertEquals(0, encs.size());
}
@Test
public void testDatePeriodParamStartAndEnd() {
{
Encounter enc = new Encounter();
enc.addIdentifier().setSystem("testDatePeriodParam").setValue("03");
enc.getPeriod().getStartElement().setValueAsString("2001-01-02");
enc.getPeriod().getEndElement().setValueAsString("2001-01-03");
myEncounterDao.create(enc, mySrd);
}
SearchParameterMap params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-01", "2001-01-03"));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "03"));
List<Encounter> encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-02", "2001-01-06"));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "03"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-01", null));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "03"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam(null, "2001-01-03"));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "03"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam(null, "2001-01-05"));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "03"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam(null, "2001-01-01"));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "03"));
encs = toList(myEncounterDao.search(params));
assertEquals(0, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-05", null));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "03"));
encs = toList(myEncounterDao.search(params));
assertEquals(0, encs.size());
}
@Test
public void testDatePeriodParamStartOnly() {
{
Encounter enc = new Encounter();
enc.addIdentifier().setSystem("testDatePeriodParam").setValue("01");
enc.getPeriod().getStartElement().setValueAsString("2001-01-02");
myEncounterDao.create(enc, mySrd);
}
SearchParameterMap params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-01", "2001-01-03"));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "01"));
List<Encounter> encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-01", null));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "01"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam(null, "2001-01-03"));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "01"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam(null, "2001-01-01"));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "01"));
encs = toList(myEncounterDao.search(params));
assertEquals(0, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-03", null));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "01"));
encs = toList(myEncounterDao.search(params));
assertEquals(0, encs.size());
}
@Test @Test
public void testDeleteFailsIfIncomingLinks() { public void testDeleteFailsIfIncomingLinks() {

View File

@ -530,7 +530,7 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
myCaptureQueriesListener.clear(); myCaptureQueriesListener.clear();
map = new SearchParameterMap(); map = new SearchParameterMap();
map.setLoadSynchronous(true); map.setLoadSynchronous(true);
map.add(DiagnosticReport.SP_PERFORMER, new ReferenceParam( "CareTeam").setChain(PARAM_TYPE)); map.add(DiagnosticReport.SP_PERFORMER, new ReferenceParam("CareTeam").setChain(PARAM_TYPE));
results = myDiagnosticReportDao.search(map); results = myDiagnosticReportDao.search(map);
ids = toUnqualifiedVersionlessIdValues(results); ids = toUnqualifiedVersionlessIdValues(results);
assertThat(ids.toString(), ids, contains(drId1.getValue())); assertThat(ids.toString(), ids, contains(drId1.getValue()));
@ -1690,6 +1690,338 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
} }
@Test
public void testDateRangeOnPeriod_SearchByDateTime_NoUpperBound() {
Encounter enc = new Encounter();
enc.getPeriod().getStartElement().setValueAsString("2020-05-26T12:00:00Z");
String id1 = myEncounterDao.create(enc).getId().toUnqualifiedVersionless().getValue();
runInTransaction(() -> {
ourLog.info("Date indexes:\n * {}", myResourceIndexedSearchParamDateDao.findAll().stream().map(t -> t.toString()).collect(Collectors.joining("\n * ")));
});
// ge -> above the lower bound
SearchParameterMap map = SearchParameterMap.newSynchronous();
map.add(Encounter.SP_DATE, new DateParam("ge2020-05-26T13:00:00Z"));
myCaptureQueriesListener.clear();
IBundleProvider results = myEncounterDao.search(map);
List<String> ids = toUnqualifiedVersionlessIdValues(results);
myCaptureQueriesListener.logSelectQueriesForCurrentThread();
assertThat(ids, contains(id1));
// ge -> Below the lower bound
map = SearchParameterMap.newSynchronous();
map.add(Encounter.SP_DATE, new DateParam("ge2020-05-26T11:00:00Z"));
myCaptureQueriesListener.clear();
results = myEncounterDao.search(map);
ids = toUnqualifiedVersionlessIdValues(results);
myCaptureQueriesListener.logSelectQueriesForCurrentThread();
assertThat(ids, contains(id1));
// le -> above the lower bound
map = SearchParameterMap.newSynchronous();
map.add(Encounter.SP_DATE, new DateParam("le2020-05-26T13:00:00Z"));
myCaptureQueriesListener.clear();
results = myEncounterDao.search(map);
ids = toUnqualifiedVersionlessIdValues(results);
myCaptureQueriesListener.logSelectQueriesForCurrentThread();
assertThat(ids, contains(id1));
// le -> Below the lower bound
map = SearchParameterMap.newSynchronous();
map.add(Encounter.SP_DATE, new DateParam("le2020-05-26T11:00:00Z"));
myCaptureQueriesListener.clear();
results = myEncounterDao.search(map);
ids = toUnqualifiedVersionlessIdValues(results);
myCaptureQueriesListener.logSelectQueriesForCurrentThread();
assertThat(ids, empty());
}
@Test
public void testDateRangeOnPeriod_SearchByDate_NoUpperBound() {
Encounter enc = new Encounter();
enc.getPeriod().getStartElement().setValueAsString("2020-05-26T12:00:00Z");
String id1 = myEncounterDao.create(enc).getId().toUnqualifiedVersionless().getValue();
runInTransaction(() -> {
ourLog.info("Date indexes:\n * {}", myResourceIndexedSearchParamDateDao.findAll().stream().map(t -> t.toString()).collect(Collectors.joining("\n * ")));
});
// ge -> above the lower bound
SearchParameterMap map = SearchParameterMap.newSynchronous();
map.add(Encounter.SP_DATE, new DateParam("ge2020-05-27"));
myCaptureQueriesListener.clear();
IBundleProvider results = myEncounterDao.search(map);
List<String> ids = toUnqualifiedVersionlessIdValues(results);
myCaptureQueriesListener.logSelectQueriesForCurrentThread();
assertThat(ids, contains(id1));
// ge -> Below the lower bound
map = SearchParameterMap.newSynchronous();
map.add(Encounter.SP_DATE, new DateParam("ge2020-05-25"));
myCaptureQueriesListener.clear();
results = myEncounterDao.search(map);
ids = toUnqualifiedVersionlessIdValues(results);
myCaptureQueriesListener.logSelectQueriesForCurrentThread();
assertThat(ids, contains(id1));
// le -> above the lower bound
map = SearchParameterMap.newSynchronous();
map.add(Encounter.SP_DATE, new DateParam("le2020-05-27"));
myCaptureQueriesListener.clear();
results = myEncounterDao.search(map);
ids = toUnqualifiedVersionlessIdValues(results);
myCaptureQueriesListener.logSelectQueriesForCurrentThread();
assertThat(ids, contains(id1));
// le -> Below the lower bound
map = SearchParameterMap.newSynchronous();
map.add(Encounter.SP_DATE, new DateParam("le2020-05-25"));
myCaptureQueriesListener.clear();
results = myEncounterDao.search(map);
ids = toUnqualifiedVersionlessIdValues(results);
myCaptureQueriesListener.logSelectQueriesForCurrentThread();
assertThat(ids, empty());
}
@Test
public void testDateRangeOnPeriod_SearchByDateTime_NoLowerBound() {
Encounter enc = new Encounter();
enc.getPeriod().getEndElement().setValueAsString("2020-05-26T12:00:00Z");
String id1 = myEncounterDao.create(enc).getId().toUnqualifiedVersionless().getValue();
runInTransaction(() -> {
ourLog.info("Date indexes:\n * {}", myResourceIndexedSearchParamDateDao.findAll().stream().map(t -> t.toString()).collect(Collectors.joining("\n * ")));
});
// le -> above the upper bound
SearchParameterMap map = SearchParameterMap.newSynchronous();
map.add(Encounter.SP_DATE, new DateParam("le2020-05-26T13:00:00Z"));
myCaptureQueriesListener.clear();
IBundleProvider results = myEncounterDao.search(map);
List<String> ids = toUnqualifiedVersionlessIdValues(results);
myCaptureQueriesListener.logSelectQueriesForCurrentThread();
assertThat(ids, contains(id1));
// le -> Below the upper bound
map = SearchParameterMap.newSynchronous();
map.add(Encounter.SP_DATE, new DateParam("le2020-05-26T11:00:00Z"));
myCaptureQueriesListener.clear();
results = myEncounterDao.search(map);
ids = toUnqualifiedVersionlessIdValues(results);
myCaptureQueriesListener.logSelectQueriesForCurrentThread();
assertThat(ids, contains(id1));
// ge -> above the upper bound
map = SearchParameterMap.newSynchronous();
map.add(Encounter.SP_DATE, new DateParam("ge2020-05-26T13:00:00Z"));
myCaptureQueriesListener.clear();
results = myEncounterDao.search(map);
ids = toUnqualifiedVersionlessIdValues(results);
myCaptureQueriesListener.logSelectQueriesForCurrentThread();
assertThat(ids, empty());
// ge -> Below the upper bound
map = SearchParameterMap.newSynchronous();
map.add(Encounter.SP_DATE, new DateParam("ge2020-05-26T11:00:00Z"));
myCaptureQueriesListener.clear();
results = myEncounterDao.search(map);
ids = toUnqualifiedVersionlessIdValues(results);
myCaptureQueriesListener.logSelectQueriesForCurrentThread();
assertThat(ids, contains(id1));
}
@Test
public void testDateRangeOnPeriod_SearchByDate_NoLowerBound() {
Encounter enc = new Encounter();
enc.getPeriod().getEndElement().setValueAsString("2020-05-26T12:00:00Z");
String id1 = myEncounterDao.create(enc).getId().toUnqualifiedVersionless().getValue();
runInTransaction(() -> {
ourLog.info("Date indexes:\n * {}", myResourceIndexedSearchParamDateDao.findAll().stream().map(t -> t.toString()).collect(Collectors.joining("\n * ")));
});
// le -> above the upper bound
SearchParameterMap map = SearchParameterMap.newSynchronous();
map.add(Encounter.SP_DATE, new DateParam("le2020-05-27"));
myCaptureQueriesListener.clear();
IBundleProvider results = myEncounterDao.search(map);
List<String> ids = toUnqualifiedVersionlessIdValues(results);
myCaptureQueriesListener.logSelectQueriesForCurrentThread();
assertThat(ids, contains(id1));
// le -> Below the upper bound
map = SearchParameterMap.newSynchronous();
map.add(Encounter.SP_DATE, new DateParam("le2020-05-25"));
myCaptureQueriesListener.clear();
results = myEncounterDao.search(map);
ids = toUnqualifiedVersionlessIdValues(results);
myCaptureQueriesListener.logSelectQueriesForCurrentThread();
assertThat(ids, contains(id1));
// ge -> above the upper bound
map = SearchParameterMap.newSynchronous();
map.add(Encounter.SP_DATE, new DateParam("ge2020-05-27"));
myCaptureQueriesListener.clear();
results = myEncounterDao.search(map);
ids = toUnqualifiedVersionlessIdValues(results);
myCaptureQueriesListener.logSelectQueriesForCurrentThread();
assertThat(ids, empty());
// ge -> Below the upper bound
map = SearchParameterMap.newSynchronous();
map.add(Encounter.SP_DATE, new DateParam("ge2020-05-25"));
myCaptureQueriesListener.clear();
results = myEncounterDao.search(map);
ids = toUnqualifiedVersionlessIdValues(results);
myCaptureQueriesListener.logSelectQueriesForCurrentThread();
assertThat(ids, contains(id1));
}
@Test
public void testDatePeriodParamEndOnly() {
{
Encounter enc = new Encounter();
enc.addIdentifier().setSystem("testDatePeriodParam").setValue("02");
enc.getPeriod().getEndElement().setValueAsString("2001-01-02");
myEncounterDao.create(enc, mySrd);
}
SearchParameterMap params;
List<Encounter> encs;
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam(null, "2001-01-03"));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "02"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-01", "2001-01-03"));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "02"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-01", null));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "02"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam(null, "2001-01-01"));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "02"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-03", null));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "02"));
encs = toList(myEncounterDao.search(params));
assertEquals(0, encs.size());
}
@Test
public void testDatePeriodParamStartAndEnd() {
{
Encounter enc = new Encounter();
enc.addIdentifier().setSystem("testDatePeriodParam").setValue("03");
enc.getPeriod().getStartElement().setValueAsString("2001-01-02");
enc.getPeriod().getEndElement().setValueAsString("2001-01-03");
myEncounterDao.create(enc, mySrd);
}
SearchParameterMap params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-01", "2001-01-03"));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "03"));
List<Encounter> encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-02", "2001-01-06"));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "03"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-01", null));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "03"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam(null, "2001-01-03"));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "03"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam(null, "2001-01-05"));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "03"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam(null, "2001-01-01"));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "03"));
encs = toList(myEncounterDao.search(params));
assertEquals(0, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-05", null));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "03"));
encs = toList(myEncounterDao.search(params));
assertEquals(0, encs.size());
}
@Test
public void testDatePeriodParamStartOnly() {
{
Encounter enc = new Encounter();
enc.addIdentifier().setSystem("testDatePeriodParam").setValue("01");
enc.getPeriod().getStartElement().setValueAsString("2001-01-02");
myEncounterDao.create(enc, mySrd);
}
SearchParameterMap params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-01", "2001-01-03"));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "01"));
List<Encounter> encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-01", null));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "01"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam(null, "2001-01-03"));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "01"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam(null, "2001-01-01"));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "01"));
encs = toList(myEncounterDao.search(params));
assertEquals(0, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-03", null));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "01"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
}
/** /**
* See #1174 * See #1174
*/ */

View File

@ -311,7 +311,7 @@ public class FhirResourceDaoR4SearchOptimizedTest extends BaseJpaR4Test {
* 20 should be prefetched since that's the initial page size * 20 should be prefetched since that's the initial page size
*/ */
await().until(()-> runInTransaction(()->{ await().until(() -> runInTransaction(() -> {
Search search = mySearchEntityDao.findByUuidAndFetchIncludes(uuid).orElseThrow(() -> new InternalErrorException("")); Search search = mySearchEntityDao.findByUuidAndFetchIncludes(uuid).orElseThrow(() -> new InternalErrorException(""));
return search.getNumFound() >= 200; return search.getNumFound() >= 200;
})); }));
@ -371,8 +371,8 @@ public class FhirResourceDaoR4SearchOptimizedTest extends BaseJpaR4Test {
* 20 should be prefetched since that's the initial page size * 20 should be prefetched since that's the initial page size
*/ */
await().until(()->{ await().until(() -> {
return runInTransaction(()->{ return runInTransaction(() -> {
return mySearchEntityDao return mySearchEntityDao
.findByUuidAndFetchIncludes(uuid) .findByUuidAndFetchIncludes(uuid)
.orElseThrow(() -> new InternalErrorException("")) .orElseThrow(() -> new InternalErrorException(""))
@ -507,8 +507,8 @@ public class FhirResourceDaoR4SearchOptimizedTest extends BaseJpaR4Test {
* 20 should be prefetched since that's the initial page size * 20 should be prefetched since that's the initial page size
*/ */
await().until(()->{ await().until(() -> {
return runInTransaction(()->{ return runInTransaction(() -> {
Search search = mySearchEntityDao.findByUuidAndFetchIncludes(uuid).orElseThrow(() -> new InternalErrorException("")); Search search = mySearchEntityDao.findByUuidAndFetchIncludes(uuid).orElseThrow(() -> new InternalErrorException(""));
return search.getNumFound() >= 50; return search.getNumFound() >= 50;
}); });
@ -547,8 +547,8 @@ public class FhirResourceDaoR4SearchOptimizedTest extends BaseJpaR4Test {
/* /*
* 20 should be prefetched since that's the initial page size * 20 should be prefetched since that's the initial page size
*/ */
await().until(()->{ await().until(() -> {
return runInTransaction(()->{ return runInTransaction(() -> {
Search search = mySearchEntityDao.findByUuidAndFetchIncludes(uuid).orElseThrow(() -> new InternalErrorException("")); Search search = mySearchEntityDao.findByUuidAndFetchIncludes(uuid).orElseThrow(() -> new InternalErrorException(""));
return search.getNumFound() == 20; return search.getNumFound() == 20;
}); });
@ -611,7 +611,12 @@ public class FhirResourceDaoR4SearchOptimizedTest extends BaseJpaR4Test {
* 20 should be prefetched since that's the initial page size * 20 should be prefetched since that's the initial page size
*/ */
waitForSize(20, () -> runInTransaction(() -> mySearchEntityDao.findByUuidAndFetchIncludes(uuid).orElseThrow(() -> new InternalErrorException("")).getNumFound())); waitForSize(
20,
10000,
() -> runInTransaction(() -> mySearchEntityDao.findByUuidAndFetchIncludes(uuid).orElseThrow(() -> new InternalErrorException("")).getNumFound()),
() -> "Wanted 20: " + runInTransaction(() -> mySearchEntityDao.findByUuidAndFetchIncludes(uuid).orElseThrow(() -> new InternalErrorException("")).toString()));
runInTransaction(() -> { runInTransaction(() -> {
Search search = mySearchEntityDao.findByUuidAndFetchIncludes(uuid).orElseThrow(() -> new InternalErrorException("")); Search search = mySearchEntityDao.findByUuidAndFetchIncludes(uuid).orElseThrow(() -> new InternalErrorException(""));
assertEquals(20, search.getNumFound()); assertEquals(20, search.getNumFound());
@ -673,7 +678,7 @@ public class FhirResourceDaoR4SearchOptimizedTest extends BaseJpaR4Test {
assertEquals("Patient/PT00000", ids.get(0)); assertEquals("Patient/PT00000", ids.get(0));
assertEquals(1, ids.size()); assertEquals(1, ids.size());
await().until(()-> runInTransaction(()-> mySearchEntityDao await().until(() -> runInTransaction(() -> mySearchEntityDao
.findByUuidAndFetchIncludes(uuid).orElseThrow(() -> new InternalErrorException("")) .findByUuidAndFetchIncludes(uuid).orElseThrow(() -> new InternalErrorException(""))
.getStatus() == SearchStatusEnum.FINISHED)); .getStatus() == SearchStatusEnum.FINISHED));
@ -821,7 +826,7 @@ public class FhirResourceDaoR4SearchOptimizedTest extends BaseJpaR4Test {
search.getResources(0, 20); search.getResources(0, 20);
ourLog.info("** Done retrieving resources"); ourLog.info("** Done retrieving resources");
await().until(()->myCaptureQueriesListener.countSelectQueries() == 4); await().until(() -> myCaptureQueriesListener.countSelectQueries() == 4);
myCaptureQueriesListener.logSelectQueriesForCurrentThread(); myCaptureQueriesListener.logSelectQueriesForCurrentThread();
assertEquals(4, myCaptureQueriesListener.countSelectQueries()); assertEquals(4, myCaptureQueriesListener.countSelectQueries());

View File

@ -1118,143 +1118,6 @@ public class FhirResourceDaoR4Test extends BaseJpaR4Test {
} }
} }
@Test
public void testDatePeriodParamEndOnly() {
{
Encounter enc = new Encounter();
enc.addIdentifier().setSystem("testDatePeriodParam").setValue("02");
enc.getPeriod().getEndElement().setValueAsString("2001-01-02");
myEncounterDao.create(enc, mySrd);
}
SearchParameterMap params;
List<Encounter> encs;
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam(null, "2001-01-03"));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "02"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-01", "2001-01-03"));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "02"));
// encs = toList(ourEncounterDao.search(params));
// assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-01", null));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "02"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam(null, "2001-01-01"));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "02"));
encs = toList(myEncounterDao.search(params));
assertEquals(0, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-03", null));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "02"));
encs = toList(myEncounterDao.search(params));
assertEquals(0, encs.size());
}
@Test
public void testDatePeriodParamStartAndEnd() {
{
Encounter enc = new Encounter();
enc.addIdentifier().setSystem("testDatePeriodParam").setValue("03");
enc.getPeriod().getStartElement().setValueAsString("2001-01-02");
enc.getPeriod().getEndElement().setValueAsString("2001-01-03");
myEncounterDao.create(enc, mySrd);
}
SearchParameterMap params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-01", "2001-01-03"));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "03"));
List<Encounter> encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-02", "2001-01-06"));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "03"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-01", null));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "03"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam(null, "2001-01-03"));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "03"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam(null, "2001-01-05"));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "03"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam(null, "2001-01-01"));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "03"));
encs = toList(myEncounterDao.search(params));
assertEquals(0, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-05", null));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "03"));
encs = toList(myEncounterDao.search(params));
assertEquals(0, encs.size());
}
@Test
public void testDatePeriodParamStartOnly() {
{
Encounter enc = new Encounter();
enc.addIdentifier().setSystem("testDatePeriodParam").setValue("01");
enc.getPeriod().getStartElement().setValueAsString("2001-01-02");
myEncounterDao.create(enc, mySrd);
}
SearchParameterMap params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-01", "2001-01-03"));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "01"));
List<Encounter> encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-01", null));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "01"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam(null, "2001-01-03"));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "01"));
encs = toList(myEncounterDao.search(params));
assertEquals(1, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam(null, "2001-01-01"));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "01"));
encs = toList(myEncounterDao.search(params));
assertEquals(0, encs.size());
params = new SearchParameterMap();
params.add(Encounter.SP_DATE, new DateRangeParam("2001-01-03", null));
params.add(Encounter.SP_IDENTIFIER, new TokenParam("testDatePeriodParam", "01"));
encs = toList(myEncounterDao.search(params));
assertEquals(0, encs.size());
}
@Test @Test
public void testDeleteFailsIfIncomingLinks() { public void testDeleteFailsIfIncomingLinks() {

View File

@ -134,10 +134,71 @@ public class FhirResourceDaoR4ValidateTest extends BaseJpaR4Test {
obs.getCode().getCodingFirstRep().setSystem("http://loinc.org").setCode("CODE3").setDisplay("Display 3"); obs.getCode().getCodingFirstRep().setSystem("http://loinc.org").setCode("CODE3").setDisplay("Display 3");
obs.getCategoryFirstRep().addCoding().setSystem("http://terminology.hl7.org/CodeSystem/observation-category").setCode("FOO"); obs.getCategoryFirstRep().addCoding().setSystem("http://terminology.hl7.org/CodeSystem/observation-category").setCode("FOO");
oo = validateAndReturnOutcome(obs); oo = validateAndReturnOutcome(obs);
assertEquals(encode(oo), "Unknown code {http://terminology.hl7.org/CodeSystem/observation-category}FOO", oo.getIssueFirstRep().getDiagnostics()); assertEquals(encode(oo), "Unknown code 'http://terminology.hl7.org/CodeSystem/observation-category#FOO'", oo.getIssueFirstRep().getDiagnostics());
} }
/**
* Per: https://chat.fhir.org/#narrow/stream/179166-implementers/topic/Handling.20incomplete.20CodeSystems
*
* We should generate a warning if a code can't be found but the codesystem is a fragment
*/
@Test
public void testValidateWithFragmentCodeSystem() throws IOException {
myStructureDefinitionDao.create(loadResourceFromClasspath(StructureDefinition.class, "/r4/fragment/structuredefinition.json"));
myCodeSystemDao.create(loadResourceFromClasspath(CodeSystem.class, "/r4/fragment/codesystem.json"));
myValueSetDao.create(loadResourceFromClasspath(ValueSet.class, "/r4/fragment/valueset.json"));
createPatient(withId("A"), withActiveTrue());
Observation obs = new Observation();
obs.setStatus(ObservationStatus.FINAL);
obs.getSubject().setReference("Patient/A");
obs.getText().setStatus(Narrative.NarrativeStatus.GENERATED);
obs.getText().getDiv().setValue("<div>hello</div>");
obs.setValue(new StringType("hello"));
obs.getPerformerFirstRep().setReference("Patient/A");
obs.setEffective(new DateTimeType("2020-01-01"));
OperationOutcome outcome;
// Correct codesystem, but code not in codesystem
obs.getCode().getCodingFirstRep().setSystem("http://example.com/codesystem");
obs.getCode().getCodingFirstRep().setCode("foo-foo");
obs.getCode().getCodingFirstRep().setDisplay("Some Code");
outcome = (OperationOutcome) myObservationDao.validate(obs, null, null, null, ValidationModeEnum.CREATE, "http://example.com/structuredefinition", mySrd).getOperationOutcome();
ourLog.info("Outcome: {}", myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
assertEquals("Unknown code in fragment CodeSystem 'http://example.com/codesystem#foo-foo'", outcome.getIssueFirstRep().getDiagnostics());
assertEquals(OperationOutcome.IssueSeverity.WARNING, outcome.getIssueFirstRep().getSeverity());
// Correct codesystem, Code in codesystem
obs.getCode().getCodingFirstRep().setSystem("http://example.com/codesystem");
obs.getCode().getCodingFirstRep().setCode("some-code");
obs.getCode().getCodingFirstRep().setDisplay("Some Code");
outcome = (OperationOutcome) myObservationDao.validate(obs, null, null, null, ValidationModeEnum.CREATE, "http://example.com/structuredefinition", mySrd).getOperationOutcome();
ourLog.info("Outcome: {}", myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
assertEquals("No issues detected during validation", outcome.getIssueFirstRep().getDiagnostics());
assertEquals(OperationOutcome.IssueSeverity.INFORMATION, outcome.getIssueFirstRep().getSeverity());
// Code in wrong codesystem
obs.getCode().getCodingFirstRep().setSystem("http://example.com/foo-foo");
obs.getCode().getCodingFirstRep().setCode("some-code");
obs.getCode().getCodingFirstRep().setDisplay("Some Code");
try {
outcome = (OperationOutcome) myObservationDao.validate(obs, null, null, null, ValidationModeEnum.CREATE, "http://example.com/structuredefinition", mySrd).getOperationOutcome();
ourLog.info("Outcome: {}", myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
assertEquals("", outcome.getIssueFirstRep().getDiagnostics());
assertEquals(OperationOutcome.IssueSeverity.INFORMATION, outcome.getIssueFirstRep().getSeverity());
fail();
} catch (PreconditionFailedException e) {
outcome = (OperationOutcome) e.getOperationOutcome();
ourLog.info("Outcome: {}", myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
assertEquals("None of the codes provided are in the value set http://example.com/valueset (http://example.com/valueset), and a code from this value set is required) (codes = http://example.com/foo-foo#some-code)", outcome.getIssueFirstRep().getDiagnostics());
assertEquals(OperationOutcome.IssueSeverity.ERROR, outcome.getIssueFirstRep().getSeverity());
}
}
/** /**
* Create a loinc valueset that expands to more results than the expander is willing to do * Create a loinc valueset that expands to more results than the expander is willing to do
* in memory, and make sure we can still validate correctly, even if we're using * in memory, and make sure we can still validate correctly, even if we're using
@ -217,7 +278,7 @@ public class FhirResourceDaoR4ValidateTest extends BaseJpaR4Test {
obs.getCode().getCodingFirstRep().setSystem("http://loinc.org").setCode("CODE3").setDisplay("Display 3"); obs.getCode().getCodingFirstRep().setSystem("http://loinc.org").setCode("CODE3").setDisplay("Display 3");
obs.getCategoryFirstRep().addCoding().setSystem("http://terminology.hl7.org/CodeSystem/observation-category").setCode("FOO"); obs.getCategoryFirstRep().addCoding().setSystem("http://terminology.hl7.org/CodeSystem/observation-category").setCode("FOO");
oo = validateAndReturnOutcome(obs); oo = validateAndReturnOutcome(obs);
assertEquals(encode(oo), "Unknown code {http://terminology.hl7.org/CodeSystem/observation-category}FOO", oo.getIssueFirstRep().getDiagnostics()); assertEquals(encode(oo), "Unknown code 'http://terminology.hl7.org/CodeSystem/observation-category#FOO'", oo.getIssueFirstRep().getDiagnostics());
} }

View File

@ -68,6 +68,7 @@ import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.stream.Collector;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast; import static ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast;
@ -701,6 +702,60 @@ public class PartitioningR4Test extends BaseJpaR4SystemTest {
} }
@Test
public void testUpdateConditionalInPartition() {
myDaoConfig.setIndexMissingFields(DaoConfig.IndexEnabledEnum.DISABLED);
createRequestId();
// Create a resource
addCreatePartition(myPartitionId, myPartitionDate);
addReadPartition(myPartitionId);
Patient p = new Patient();
p.setActive(false);
p.addIdentifier().setValue("12345");
Long patientId = myPatientDao.update(p, "Patient?identifier=12345", mySrd).getId().getIdPartAsLong();
runInTransaction(() -> {
// HFJ_RESOURCE
assertEquals(1, myResourceTableDao.count());
ResourceTable resourceTable = myResourceTableDao.findById(patientId).orElseThrow(IllegalArgumentException::new);
assertEquals(myPartitionId, resourceTable.getPartitionId().getPartitionId().intValue());
assertEquals(myPartitionDate, resourceTable.getPartitionId().getPartitionDate());
// HFJ_SPIDX_TOKEN
ourLog.info("Tokens:\n * {}", myResourceIndexedSearchParamTokenDao.findAll().stream().map(t->t.toString()).collect(Collectors.joining("\n * ")));
assertEquals(3, myResourceIndexedSearchParamTokenDao.countForResourceId(patientId));
});
// Update that resource
addReadPartition(myPartitionId);
p = new Patient();
p.setActive(true);
p.addIdentifier().setValue("12345");
Long patientId2 = myPatientDao.update(p, "Patient?identifier=12345", mySrd).getId().getIdPartAsLong();
assertEquals(patientId, patientId2);
runInTransaction(() -> {
// HFJ_RESOURCE
assertEquals(1, myResourceTableDao.count());
ResourceTable resourceTable = myResourceTableDao.findById(patientId).orElseThrow(IllegalArgumentException::new);
assertEquals(myPartitionId, resourceTable.getPartitionId().getPartitionId().intValue());
assertEquals(myPartitionDate, resourceTable.getPartitionId().getPartitionDate());
// HFJ_SPIDX_TOKEN
ourLog.info("Tokens:\n * {}", myResourceIndexedSearchParamTokenDao.findAll().stream().map(t->t.toString()).collect(Collectors.joining("\n * ")));
assertEquals(3, myResourceIndexedSearchParamTokenDao.countForResourceId(patientId));
// HFJ_RES_VER
int version = 2;
ResourceHistoryTable resVer = myResourceHistoryTableDao.findForIdAndVersionAndFetchProvenance(patientId, version);
assertEquals(myPartitionId, resVer.getPartitionId().getPartitionId().intValue());
assertEquals(myPartitionDate, resVer.getPartitionId().getPartitionDate());
});
}
@Test @Test
public void testRead_PidId_AllPartitions() { public void testRead_PidId_AllPartitions() {
IIdType patientId1 = createPatient(withPartition(1), withActiveTrue()); IIdType patientId1 = createPatient(withPartition(1), withActiveTrue());

View File

@ -0,0 +1,25 @@
{
"resourceType": "CodeSystem",
"id": "22472",
"meta": {
"versionId": "3",
"lastUpdated": "2017-01-27T10:53:39.457-05:00"
},
"url": "http://example.com/codesystem",
"name": "AddressUse",
"status": "active",
"publisher": "x1v1-mci",
"date": "2016-04-07",
"description": "AddressUse",
"caseSensitive": true,
"compositional": false,
"versionNeeded": false,
"content": "fragment",
"concept": [
{
"code": "some-code",
"display": "Some Code",
"definition": "Blah blah"
}
]
}

View File

@ -0,0 +1,57 @@
{
"resourceType": "StructureDefinition",
"id": "vitalsigns",
"url": "http://example.com/structuredefinition",
"version": "4.0.0",
"name": "observation-vitalsigns",
"title": "Vital Signs Profile",
"status": "draft",
"experimental": false,
"date": "2016-03-25",
"publisher": "Health Level Seven International (Orders and Observations Workgroup)",
"description": "FHIR Vital Signs Profile",
"fhirVersion": "4.0.0",
"kind": "resource",
"abstract": false,
"type": "Observation",
"baseDefinition": "http://hl7.org/fhir/StructureDefinition/Observation",
"derivation": "constraint",
"differential": {
"element": [
{
"id": "Observation",
"path": "Observation",
"short": "FHIR Vital Signs Profile",
"definition": "The FHIR Vitals Signs profile sets minimum expectations for the Observation Resource to record, search and fetch the vital signs associated with a patient.",
"alias": [
"Vital Signs",
"Measurement",
"Results",
"Tests"
],
"min": 0,
"max": "*"
},
{
"id": "Observation.code",
"path": "Observation.code",
"short": "Coded Responses from C-CDA Vital Sign Results",
"definition": "Coded Responses from C-CDA Vital Sign Results.",
"requirements": "5. SHALL contain exactly one [1..1] code, where the @code SHOULD be selected from ValueSet HITSP Vital Sign Result Type 2.16.840.1.113883.3.88.12.80.62 DYNAMIC (CONF:7301).",
"min": 1,
"max": "1",
"type": [
{
"code": "CodeableConcept"
}
],
"mustSupport": true,
"binding": {
"strength": "required",
"description": "This identifies the vital sign result type.",
"valueSet": "http://example.com/valueset"
}
}
]
}
}

View File

@ -0,0 +1,18 @@
{
"resourceType" : "ValueSet",
"id" : "message-category",
"url" : "http://example.com/valueset",
"version" : "0.0.1",
"name" : "MessageCategory",
"status" : "active",
"experimental" : true,
"date" : "2019-02-08T00:00:00+00:00",
"publisher" : "ehealth.sundhed.dk",
"compose" : {
"include" : [
{
"system" : "http://example.com/codesystem"
}
]
}
}

View File

@ -103,6 +103,7 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks<VersionEnum> {
empiLink.addIndex("20200517.5", "IDX_EMPI_PERSON_TGT").unique(true).withColumns("PERSON_PID", "TARGET_PID"); empiLink.addIndex("20200517.5", "IDX_EMPI_PERSON_TGT").unique(true).withColumns("PERSON_PID", "TARGET_PID");
} }
protected void init500() { // 20200218 - 20200519 protected void init500() { // 20200218 - 20200519
@ -181,8 +182,6 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks<VersionEnum> {
.setColumnName("SP_VALUE_LOW_DATE_ORDINAL") //It doesn't matter which of the two we choose as they will both be null. .setColumnName("SP_VALUE_LOW_DATE_ORDINAL") //It doesn't matter which of the two we choose as they will both be null.
); );
// TRM_CONCEPT_PROPERTY
version.onTable("TRM_CONCEPT_PROPERTY").addIndex("20200523.1", "IDX_CONCEPTPROP_CONCEPTPID").unique(false).withColumns("CONCEPT_PID");
} }
/** /**

View File

@ -20,13 +20,17 @@ package ca.uhn.fhir.jpa.model.entity;
* #L% * #L%
*/ */
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.Validate;
import org.hl7.fhir.dstu2.model.Subscription; import org.hl7.fhir.dstu2.model.Subscription;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
import org.hl7.fhir.r4.model.DateTimeType;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.Date;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
@ -50,6 +54,21 @@ public class ModelConfig {
"http://hl7.org/fhir/StructureDefinition/*"))); "http://hl7.org/fhir/StructureDefinition/*")));
public static final String DEFAULT_WEBSOCKET_CONTEXT_PATH = "/websocket"; public static final String DEFAULT_WEBSOCKET_CONTEXT_PATH = "/websocket";
/*
* <p>
* Note the following database documented limitations:
* <ul>
* <li>JDBC Timestamp Datatype Low Value -4713 and High Value 9999</li>
* <li>MySQL 8: the range for DATETIME values is '1000-01-01 00:00:00.000000' to '9999-12-31 23:59:59.999999`</li>
* <li>Postgresql 12: Timestamp [without time zone] Low Value 4713 BC and High Value 294276 AD</li>
* <li>Oracle: Timestamp Low Value 4712 BC and High Value 9999 CE</li>
* <li>H2: datetime2 Low Value -4713 and High Value 9999</li>
* </ul>
* </p>
*/
protected static final String DEFAULT_PERIOD_INDEX_START_OF_TIME = "1001-01-01";
protected static final String DEFAULT_PERIOD_INDEX_END_OF_TIME = "9000-01-01";
/** /**
* update setter javadoc if default changes * update setter javadoc if default changes
*/ */
@ -67,11 +86,15 @@ public class ModelConfig {
private boolean myUseOrdinalDatesForDayPrecisionSearches = true; private boolean myUseOrdinalDatesForDayPrecisionSearches = true;
private boolean mySuppressStringIndexingInTokens = false; private boolean mySuppressStringIndexingInTokens = false;
private IPrimitiveType<Date> myPeriodIndexStartOfTime;
private IPrimitiveType<Date> myPeriodIndexEndOfTime;
/** /**
* Constructor * Constructor
*/ */
public ModelConfig() { public ModelConfig() {
super(); setPeriodIndexStartOfTime(new DateTimeType(DEFAULT_PERIOD_INDEX_START_OF_TIME));
setPeriodIndexEndOfTime(new DateTimeType(DEFAULT_PERIOD_INDEX_END_OF_TIME));
} }
/** /**
@ -373,8 +396,8 @@ public class ModelConfig {
/** /**
* <p> * <p>
* Should searches use the integer field {@code SP_VALUE_LOW_DATE_ORDINAL} and {@code SP_VALUE_HIGH_DATE_ORDINAL} in * Should searches use the integer field {@code SP_VALUE_LOW_DATE_ORDINAL} and {@code SP_VALUE_HIGH_DATE_ORDINAL} in
* {@link ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate} when resolving searches where all predicates are using * {@link ResourceIndexedSearchParamDate} when resolving searches where all predicates are using
* precision of {@link ca.uhn.fhir.model.api.TemporalPrecisionEnum#DAY}. * precision of {@link TemporalPrecisionEnum#DAY}.
* <p> * <p>
* For example, if enabled, the search of {@code Observation?date=2020-02-25} will cause the date to be collapsed down to an * For example, if enabled, the search of {@code Observation?date=2020-02-25} will cause the date to be collapsed down to an
* integer representing the ordinal date {@code 20200225}. It would then be compared against {@link ResourceIndexedSearchParamDate#getValueLowDateOrdinal()} * integer representing the ordinal date {@code 20200225}. It would then be compared against {@link ResourceIndexedSearchParamDate#getValueLowDateOrdinal()}
@ -392,8 +415,8 @@ public class ModelConfig {
/** /**
* <p> * <p>
* Should searches use the integer field {@code SP_VALUE_LOW_DATE_ORDINAL} and {@code SP_VALUE_HIGH_DATE_ORDINAL} in * Should searches use the integer field {@code SP_VALUE_LOW_DATE_ORDINAL} and {@code SP_VALUE_HIGH_DATE_ORDINAL} in
* {@link ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate} when resolving searches where all predicates are using * {@link ResourceIndexedSearchParamDate} when resolving searches where all predicates are using
* precision of {@link ca.uhn.fhir.model.api.TemporalPrecisionEnum#DAY}. * precision of {@link TemporalPrecisionEnum#DAY}.
* <p> * <p>
* For example, if enabled, the search of {@code Observation?date=2020-02-25} will cause the date to be collapsed down to an * For example, if enabled, the search of {@code Observation?date=2020-02-25} will cause the date to be collapsed down to an
* ordinal {@code 20200225}. It would then be compared against {@link ResourceIndexedSearchParamDate#getValueLowDateOrdinal()} * ordinal {@code 20200225}. It would then be compared against {@link ResourceIndexedSearchParamDate#getValueLowDateOrdinal()}
@ -417,6 +440,7 @@ public class ModelConfig {
* <li>Coding.display</li> * <li>Coding.display</li>
* <li>Identifier.use.text</li> * <li>Identifier.use.text</li>
* </ul> * </ul>
*
* @since 5.0.0 * @since 5.0.0
*/ */
public boolean isSuppressStringIndexingInTokens() { public boolean isSuppressStringIndexingInTokens() {
@ -432,12 +456,124 @@ public class ModelConfig {
* <li>Coding.display</li> * <li>Coding.display</li>
* <li>Identifier.use.text</li> * <li>Identifier.use.text</li>
* </ul> * </ul>
*
* @since 5.0.0 * @since 5.0.0
*/ */
public void setSuppressStringIndexingInTokens(boolean theSuppressStringIndexingInTokens) { public void setSuppressStringIndexingInTokens(boolean theSuppressStringIndexingInTokens) {
mySuppressStringIndexingInTokens = theSuppressStringIndexingInTokens; mySuppressStringIndexingInTokens = theSuppressStringIndexingInTokens;
} }
/**
* When indexing a Period (e.g. Encounter.period) where the period has an upper bound
* but not a lower bound, a canned "start of time" value can be used as the lower bound
* in order to allow range searches to correctly identify all values in the range.
* <p>
* The default value for this is {@link #DEFAULT_PERIOD_INDEX_START_OF_TIME} which
* is probably good enough for almost any application, but this can be changed if
* needed.
* </p>
* <p>
* Note the following database documented limitations:
* <ul>
* <li>JDBC Timestamp Datatype Low Value -4713 and High Value 9999</li>
* <li>MySQL 8: the range for DATETIME values is '1000-01-01 00:00:00.000000' to '9999-12-31 23:59:59.999999`</li>
* <li>Postgresql 12: Timestamp [without time zone] Low Value 4713 BC and High Value 294276 AD</li>
* <li>Oracle: Timestamp Low Value 4712 BC and High Value 9999 CE</li>
* <li>H2: datetime2 Low Value -4713 and High Value 9999</li>
* </ul>
* </p>
*
* @see #getPeriodIndexEndOfTime()
* @since 5.1.0
*/
public IPrimitiveType<Date> getPeriodIndexStartOfTime() {
return myPeriodIndexStartOfTime;
}
/**
* When indexing a Period (e.g. Encounter.period) where the period has an upper bound
* but not a lower bound, a canned "start of time" value can be used as the lower bound
* in order to allow range searches to correctly identify all values in the range.
* <p>
* The default value for this is {@link #DEFAULT_PERIOD_INDEX_START_OF_TIME} which
* is probably good enough for almost any application, but this can be changed if
* needed.
* </p>
* <p>
* Note the following database documented limitations:
* <ul>
* <li>JDBC Timestamp Datatype Low Value -4713 and High Value 9999</li>
* <li>MySQL 8: the range for DATETIME values is '1000-01-01 00:00:00.000000' to '9999-12-31 23:59:59.999999`</li>
* <li>Postgresql 12: Timestamp [without time zone] Low Value 4713 BC and High Value 294276 AD</li>
* <li>Oracle: Timestamp Low Value 4712 BC and High Value 9999 CE</li>
* <li>H2: datetime2 Low Value -4713 and High Value 9999</li>
* </ul>
* </p>
*
* @see #getPeriodIndexEndOfTime()
* @since 5.1.0
*/
public void setPeriodIndexStartOfTime(IPrimitiveType<Date> thePeriodIndexStartOfTime) {
Validate.notNull(thePeriodIndexStartOfTime, "thePeriodIndexStartOfTime must not be null");
myPeriodIndexStartOfTime = thePeriodIndexStartOfTime;
}
/**
* When indexing a Period (e.g. Encounter.period) where the period has a lower bound
* but not an upper bound, a canned "end of time" value can be used as the upper bound
* in order to allow range searches to correctly identify all values in the range.
* <p>
* The default value for this is {@link #DEFAULT_PERIOD_INDEX_START_OF_TIME} which
* is probably good enough for almost any application, but this can be changed if
* needed.
* </p>
* <p>
* Note the following database documented limitations:
* <ul>
* <li>JDBC Timestamp Datatype Low Value -4713 and High Value 9999</li>
* <li>MySQL 8: the range for DATETIME values is '1000-01-01 00:00:00.000000' to '9999-12-31 23:59:59.999999`</li>
* <li>Postgresql 12: Timestamp [without time zone] Low Value 4713 BC and High Value 294276 AD</li>
* <li>Oracle: Timestamp Low Value 4712 BC and High Value 9999 CE</li>
* <li>H2: datetime2 Low Value -4713 and High Value 9999</li>
* </ul>
* </p>
*
* @see #getPeriodIndexStartOfTime()
* @since 5.1.0
*/
public IPrimitiveType<Date> getPeriodIndexEndOfTime() {
return myPeriodIndexEndOfTime;
}
/**
* When indexing a Period (e.g. Encounter.period) where the period has an upper bound
* but not a lower bound, a canned "start of time" value can be used as the lower bound
* in order to allow range searches to correctly identify all values in the range.
* <p>
* The default value for this is {@link #DEFAULT_PERIOD_INDEX_START_OF_TIME} which
* is probably good enough for almost any application, but this can be changed if
* needed.
* </p>
* <p>
* Note the following database documented limitations:
* <ul>
* <li>JDBC Timestamp Datatype Low Value -4713 and High Value 9999</li>
* <li>MySQL 8: the range for DATETIME values is '1000-01-01 00:00:00.000000' to '9999-12-31 23:59:59.999999`</li>
* <li>Postgresql 12: Timestamp [without time zone] Low Value 4713 BC and High Value 294276 AD</li>
* <li>Oracle: Timestamp Low Value 4712 BC and High Value 9999 CE</li>
* <li>H2: datetime2 Low Value -4713 and High Value 9999</li>
* </ul>
* </p>
*
* @see #getPeriodIndexStartOfTime()
* @since 5.1.0
*/
public void setPeriodIndexEndOfTime(IPrimitiveType<Date> thePeriodIndexEndOfTime) {
Validate.notNull(thePeriodIndexEndOfTime, "thePeriodIndexEndOfTime must not be null");
myPeriodIndexEndOfTime = thePeriodIndexEndOfTime;
}
private static void validateTreatBaseUrlsAsLocal(String theUrl) { private static void validateTreatBaseUrlsAsLocal(String theUrl) {
Validate.notBlank(theUrl, "Base URL must not be null or empty"); Validate.notBlank(theUrl, "Base URL must not be null or empty");

View File

@ -59,7 +59,7 @@ import static org.apache.commons.lang3.StringUtils.trim;
@Index(name = "IDX_SP_TOKEN_HASH_S", columnList = "HASH_SYS"), @Index(name = "IDX_SP_TOKEN_HASH_S", columnList = "HASH_SYS"),
@Index(name = "IDX_SP_TOKEN_HASH_SV", columnList = "HASH_SYS_AND_VALUE"), @Index(name = "IDX_SP_TOKEN_HASH_SV", columnList = "HASH_SYS_AND_VALUE"),
// TODO PERF change this to: // TODO PERF change this to:
// @Index(name = "IDX_SP_TOKEN_HASH_V", columnList = "HASH_VALUE,RES_ID"), // @Index(name = "IDX_SP_TOKEN_HASH_V", columnList = "HASH_VALUE,RES_ID"),
@Index(name = "IDX_SP_TOKEN_HASH_V", columnList = "HASH_VALUE"), @Index(name = "IDX_SP_TOKEN_HASH_V", columnList = "HASH_VALUE"),
@Index(name = "IDX_SP_TOKEN_UPDATED", columnList = "SP_UPDATED"), @Index(name = "IDX_SP_TOKEN_UPDATED", columnList = "SP_UPDATED"),
@ -232,6 +232,7 @@ public class ResourceIndexedSearchParamToken extends BaseResourceIndexedSearchPa
b.append(getHashValue()); b.append(getHashValue());
b.append(getHashSystem()); b.append(getHashSystem());
b.append(getHashSystemAndValue()); b.append(getHashSystemAndValue());
return b.toHashCode(); return b.toHashCode();
} }

View File

@ -444,6 +444,16 @@ public abstract class BaseSearchParamExtractor implements ISearchParamExtractor
String endAsString = extractValueAsString(myPeriodEndValueChild, theValue); String endAsString = extractValueAsString(myPeriodEndValueChild, theValue);
if (start != null || end != null) { if (start != null || end != null) {
if (start == null) {
start = myModelConfig.getPeriodIndexStartOfTime().getValue();
startAsString = myModelConfig.getPeriodIndexStartOfTime().getValueAsString();
}
if (end == null) {
end = myModelConfig.getPeriodIndexEndOfTime().getValue();
endAsString = myModelConfig.getPeriodIndexEndOfTime().getValueAsString();
}
myIndexedSearchParamDate = new ResourceIndexedSearchParamDate(myPartitionSettings, theResourceType, theSearchParam.getName(), start, startAsString, end, endAsString, startAsString); myIndexedSearchParamDate = new ResourceIndexedSearchParamDate(myPartitionSettings, theResourceType, theSearchParam.getName(), start, startAsString, end, endAsString, startAsString);
theParams.add(myIndexedSearchParamDate); theParams.add(myIndexedSearchParamDate);
} }
@ -822,6 +832,71 @@ public abstract class BaseSearchParamExtractor implements ISearchParamExtractor
} }
} }
private void addDate_Period(String theResourceType, Set<ResourceIndexedSearchParamDate> theParams, RuntimeSearchParam theSearchParam, IBase theValue) {
Date start = extractValueAsDate(myPeriodStartValueChild, theValue);
String startAsString = extractValueAsString(myPeriodStartValueChild, theValue);
Date end = extractValueAsDate(myPeriodEndValueChild, theValue);
String endAsString = extractValueAsString(myPeriodEndValueChild, theValue);
if (start != null || end != null) {
if (start == null) {
start = myModelConfig.getPeriodIndexStartOfTime().getValue();
startAsString = myModelConfig.getPeriodIndexStartOfTime().getValueAsString();
}
if (end == null) {
end = myModelConfig.getPeriodIndexEndOfTime().getValue();
endAsString = myModelConfig.getPeriodIndexEndOfTime().getValueAsString();
}
ResourceIndexedSearchParamDate nextEntity = new ResourceIndexedSearchParamDate(myPartitionSettings, theResourceType, theSearchParam.getName(), start, startAsString, end, endAsString, startAsString);
theParams.add(nextEntity);
}
}
private void addDate_Timing(String theResourceType, Set<ResourceIndexedSearchParamDate> theParams, RuntimeSearchParam theSearchParam, IBase theValue) {
List<IPrimitiveType<Date>> values = extractValuesAsFhirDates(myTimingEventValueChild, theValue);
TreeSet<Date> dates = new TreeSet<>();
TreeSet<String> dateStrings = new TreeSet<>();
String firstValue = null;
String finalValue = null;
for (IPrimitiveType<Date> nextEvent : values) {
if (nextEvent.getValue() != null) {
dates.add(nextEvent.getValue());
if (firstValue == null) {
firstValue = nextEvent.getValueAsString();
}
finalValue = nextEvent.getValueAsString();
}
}
Optional<IBase> repeat = myTimingRepeatValueChild.getAccessor().getFirstValueOrNull(theValue);
if (repeat.isPresent()) {
Optional<IBase> bounds = myTimingRepeatBoundsValueChild.getAccessor().getFirstValueOrNull(repeat.get());
if (bounds.isPresent()) {
String boundsType = toRootTypeName(bounds.get());
if ("Period".equals(boundsType)) {
Date start = extractValueAsDate(myPeriodStartValueChild, bounds.get());
Date end = extractValueAsDate(myPeriodEndValueChild, bounds.get());
String endString = extractValueAsString(myPeriodEndValueChild, bounds.get());
dates.add(start);
dates.add(end);
//TODO Check if this logic is valid. Does the start of the first period indicate a lower bound??
if (firstValue == null) {
firstValue = extractValueAsString(myPeriodStartValueChild, bounds.get());
}
finalValue = endString;
}
}
}
if (!dates.isEmpty()) {
ResourceIndexedSearchParamDate nextEntity = new ResourceIndexedSearchParamDate(myPartitionSettings, theResourceType, theSearchParam.getName(), dates.first(), firstValue, dates.last(), finalValue, firstValue);
theParams.add(nextEntity);
}
}
private void addNumber_Duration(String theResourceType, Set<ResourceIndexedSearchParamNumber> theParams, RuntimeSearchParam theSearchParam, IBase theValue) { private void addNumber_Duration(String theResourceType, Set<ResourceIndexedSearchParamNumber> theParams, RuntimeSearchParam theSearchParam, IBase theValue) {
String system = extractValueAsString(myDurationSystemValueChild, theValue); String system = extractValueAsString(myDurationSystemValueChild, theValue);
String code = extractValueAsString(myDurationCodeValueChild, theValue); String code = extractValueAsString(myDurationCodeValueChild, theValue);

View File

@ -41,6 +41,7 @@ import javax.mail.internet.MimeMessage;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Properties;
import static org.apache.commons.lang3.StringUtils.isNotBlank; import static org.apache.commons.lang3.StringUtils.isNotBlank;
import static org.apache.commons.lang3.StringUtils.trim; import static org.apache.commons.lang3.StringUtils.trim;
@ -53,6 +54,7 @@ public class JavaMailEmailSender implements IEmailSender {
private JavaMailSenderImpl mySender; private JavaMailSenderImpl mySender;
private String mySmtpServerUsername; private String mySmtpServerUsername;
private String mySmtpServerPassword; private String mySmtpServerPassword;
private final Properties myJavaMailProperties = new Properties();
public String getSmtpServerHostname() { public String getSmtpServerHostname() {
return mySmtpServerHostname; return mySmtpServerHostname;
@ -92,6 +94,38 @@ public class JavaMailEmailSender implements IEmailSender {
mySmtpServerUsername = theSmtpServerUsername; mySmtpServerUsername = theSmtpServerUsername;
} }
/**
* Set the "mail.smtp.auth" Java Mail Property
*/
public void setAuth(Boolean theAuth) {
myJavaMailProperties.setProperty("mail.smtp.auth", theAuth.toString());
}
/**
* Set the "mail.smtp.starttls.enable" Java Mail Property
*/
public void setStartTlsEnable(Boolean theStartTlsEnable) {
myJavaMailProperties.setProperty("mail.smtp.starttls.enable", theStartTlsEnable.toString());
}
/**
* Set the "mail.smtp.starttls.required" Java Mail Property
*/
public void setStartTlsRequired(Boolean theStartTlsRequired) {
myJavaMailProperties.setProperty("mail.smtp.starttls.required", theStartTlsRequired.toString());
}
/**
* Set the "mail.smtp.quitwait" Java Mail Property
*/
public void setQuitWait(Boolean theQuitWait) {
myJavaMailProperties.setProperty("mail.smtp.quitwait", theQuitWait.toString());
}
@Override @Override
public void send(EmailDetails theDetails) { public void send(EmailDetails theDetails) {
String subscriptionId = theDetails.getSubscription().toUnqualifiedVersionless().getValue(); String subscriptionId = theDetails.getSubscription().toUnqualifiedVersionless().getValue();
@ -144,6 +178,7 @@ public class JavaMailEmailSender implements IEmailSender {
mySender.setUsername(getSmtpServerUsername()); mySender.setUsername(getSmtpServerUsername());
mySender.setPassword(getSmtpServerPassword()); mySender.setPassword(getSmtpServerPassword());
mySender.setDefaultEncoding(Constants.CHARSET_UTF8.name()); mySender.setDefaultEncoding(Constants.CHARSET_UTF8.name());
mySender.setJavaMailProperties(myJavaMailProperties);
} }
private static String toTrimmedCommaSeparatedString(List<String> theTo) { private static String toTrimmedCommaSeparatedString(List<String> theTo) {

View File

@ -222,6 +222,7 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
String codeSystemName = null; String codeSystemName = null;
String codeSystemVersion = null; String codeSystemVersion = null;
String codeSystemContentMode = null;
if (system != null) { if (system != null) {
switch (system.getStructureFhirVersionEnum()) { switch (system.getStructureFhirVersionEnum()) {
case DSTU2_HL7ORG: { case DSTU2_HL7ORG: {
@ -233,6 +234,7 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
caseSensitive = systemDstu3.getCaseSensitive(); caseSensitive = systemDstu3.getCaseSensitive();
codeSystemName = systemDstu3.getName(); codeSystemName = systemDstu3.getName();
codeSystemVersion = systemDstu3.getVersion(); codeSystemVersion = systemDstu3.getVersion();
codeSystemContentMode = systemDstu3.getContentElement().getValueAsString();
break; break;
} }
case R4: { case R4: {
@ -240,6 +242,7 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
caseSensitive = systemR4.getCaseSensitive(); caseSensitive = systemR4.getCaseSensitive();
codeSystemName = systemR4.getName(); codeSystemName = systemR4.getName();
codeSystemVersion = systemR4.getVersion(); codeSystemVersion = systemR4.getVersion();
codeSystemContentMode = systemR4.getContentElement().getValueAsString();
break; break;
} }
case R5: { case R5: {
@ -247,6 +250,7 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
caseSensitive = systemR5.getCaseSensitive(); caseSensitive = systemR5.getCaseSensitive();
codeSystemName = systemR5.getName(); codeSystemName = systemR5.getName();
codeSystemVersion = systemR5.getVersion(); codeSystemVersion = systemR5.getVersion();
codeSystemContentMode = systemR5.getContentElement().getValueAsString();
break; break;
} }
case DSTU2: case DSTU2:
@ -275,9 +279,16 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
} }
} }
ValidationMessage.IssueSeverity severity = ValidationMessage.IssueSeverity.ERROR; ValidationMessage.IssueSeverity severity;
String message;
if ("fragment".equals(codeSystemContentMode)) {
severity = ValidationMessage.IssueSeverity.WARNING;
message = "Unknown code in fragment CodeSystem '" + (isNotBlank(theCodeSystem) ? theCodeSystem + "#" : "") + theCode + "'";
} else {
severity = ValidationMessage.IssueSeverity.ERROR;
message = "Unknown code '" + (isNotBlank(theCodeSystem) ? theCodeSystem + "#" : "") + theCode + "'";
}
String message = "Unknown code '" + (isNotBlank(theCodeSystem) ? theCodeSystem + "#" : "") + theCode + "'";
return new CodeValidationResult() return new CodeValidationResult()
.setSeverityCode(severity.toCode()) .setSeverityCode(severity.toCode())
.setMessage(message); .setMessage(message);

View File

@ -236,9 +236,11 @@ public class ValidationSupportChain implements IValidationSupport {
@Override @Override
public CodeValidationResult validateCodeInValueSet(ValidationSupportContext theValidationSupportContext, ConceptValidationOptions theOptions, String theCodeSystem, String theCode, String theDisplay, @Nonnull IBaseResource theValueSet) { public CodeValidationResult validateCodeInValueSet(ValidationSupportContext theValidationSupportContext, ConceptValidationOptions theOptions, String theCodeSystem, String theCode, String theDisplay, @Nonnull IBaseResource theValueSet) {
for (IValidationSupport next : myChain) { for (IValidationSupport next : myChain) {
CodeValidationResult retVal = next.validateCodeInValueSet(theValidationSupportContext, theOptions, theCodeSystem, theCode, theDisplay, theValueSet); if (theOptions.isInferSystem() || (theCodeSystem != null && next.isCodeSystemSupported(theValidationSupportContext, theCodeSystem))) {
if (retVal != null) { CodeValidationResult retVal = next.validateCodeInValueSet(theValidationSupportContext, theOptions, theCodeSystem, theCode, theDisplay, theValueSet);
return retVal; if (retVal != null) {
return retVal;
}
} }
} }
return null; return null;

View File

@ -907,6 +907,14 @@ public class QuestionnaireResponseValidatorDstu3Test {
@Test @Test
public void testValidateQuestionnaireResponseWithValueSetChoiceAnswer() { public void testValidateQuestionnaireResponseWithValueSetChoiceAnswer() {
/*
* Create CodeSystem
*/
CodeSystem codeSystem = new CodeSystem();
codeSystem.setContent(CodeSystemContentMode.COMPLETE);
codeSystem.setUrl(SYSTEMURI_ICC_SCHOOLTYPE);
codeSystem.addConcept().setCode(CODE_ICC_SCHOOLTYPE_PT);
/* /*
* Create valueset * Create valueset
*/ */
@ -959,6 +967,7 @@ public class QuestionnaireResponseValidatorDstu3Test {
when(myValSupport.fetchResource(eq(ValueSet.class), eq(ID_VS_SCHOOLTYPE.getValue()))).thenReturn(iccSchoolTypeVs); when(myValSupport.fetchResource(eq(ValueSet.class), eq(ID_VS_SCHOOLTYPE.getValue()))).thenReturn(iccSchoolTypeVs);
when(myValSupport.validateCodeInValueSet(any(), any(), eq(SYSTEMURI_ICC_SCHOOLTYPE), eq(CODE_ICC_SCHOOLTYPE_PT), any(), nullable(ValueSet.class))) when(myValSupport.validateCodeInValueSet(any(), any(), eq(SYSTEMURI_ICC_SCHOOLTYPE), eq(CODE_ICC_SCHOOLTYPE_PT), any(), nullable(ValueSet.class)))
.thenReturn(new IValidationSupport.CodeValidationResult().setCode(CODE_ICC_SCHOOLTYPE_PT)); .thenReturn(new IValidationSupport.CodeValidationResult().setCode(CODE_ICC_SCHOOLTYPE_PT));
when(myValSupport.fetchCodeSystem(eq(SYSTEMURI_ICC_SCHOOLTYPE))).thenReturn(codeSystem);
ValidationResult errors = myVal.validateWithResult(questionnaireResponse); ValidationResult errors = myVal.validateWithResult(questionnaireResponse);

View File

@ -733,6 +733,14 @@ public class QuestionnaireResponseValidatorR4Test {
@Test @Test
public void testValidateQuestionnaireResponseWithValueSetChoiceAnswer() { public void testValidateQuestionnaireResponseWithValueSetChoiceAnswer() {
/*
* Create CodeSystem
*/
CodeSystem codeSystem = new CodeSystem();
codeSystem.setContent(CodeSystem.CodeSystemContentMode.COMPLETE);
codeSystem.setUrl(SYSTEMURI_ICC_SCHOOLTYPE);
codeSystem.addConcept().setCode(CODE_ICC_SCHOOLTYPE_PT);
/* /*
* Create valueset * Create valueset
*/ */
@ -785,6 +793,7 @@ public class QuestionnaireResponseValidatorR4Test {
when(myValSupport.fetchResource(eq(Questionnaire.class), eq(qa.getQuestionnaire()))).thenReturn(questionnaire); when(myValSupport.fetchResource(eq(Questionnaire.class), eq(qa.getQuestionnaire()))).thenReturn(questionnaire);
when(myValSupport.fetchResource(eq(ValueSet.class), eq(ID_VS_SCHOOLTYPE))).thenReturn(iccSchoolTypeVs); when(myValSupport.fetchResource(eq(ValueSet.class), eq(ID_VS_SCHOOLTYPE))).thenReturn(iccSchoolTypeVs);
when(myValSupport.validateCodeInValueSet(any(), any(), any(), any(), any(), any(ValueSet.class))).thenReturn(new IValidationSupport.CodeValidationResult().setCode(CODE_ICC_SCHOOLTYPE_PT)); when(myValSupport.validateCodeInValueSet(any(), any(), any(), any(), any(), any(ValueSet.class))).thenReturn(new IValidationSupport.CodeValidationResult().setCode(CODE_ICC_SCHOOLTYPE_PT));
when(myValSupport.fetchCodeSystem(eq(SYSTEMURI_ICC_SCHOOLTYPE))).thenReturn(codeSystem);
ValidationResult errors = myVal.validateWithResult(qa); ValidationResult errors = myVal.validateWithResult(qa);
ourLog.info(errors.toString()); ourLog.info(errors.toString());

View File

@ -625,6 +625,14 @@ public class QuestionnaireResponseValidatorR5Test {
@Test @Test
public void testValidateQuestionnaireResponseWithValueSetChoiceAnswer() { public void testValidateQuestionnaireResponseWithValueSetChoiceAnswer() {
/*
* Create CodeSystem
*/
CodeSystem codeSystem = new CodeSystem();
codeSystem.setContent(CodeSystem.CodeSystemContentMode.COMPLETE);
codeSystem.setUrl(SYSTEMURI_ICC_SCHOOLTYPE);
codeSystem.addConcept().setCode(CODE_ICC_SCHOOLTYPE_PT);
/* /*
* Create valueset * Create valueset
*/ */
@ -677,6 +685,7 @@ public class QuestionnaireResponseValidatorR5Test {
when(myValSupport.fetchResource(eq(Questionnaire.class), eq(qa.getQuestionnaire()))).thenReturn(questionnaire); when(myValSupport.fetchResource(eq(Questionnaire.class), eq(qa.getQuestionnaire()))).thenReturn(questionnaire);
when(myValSupport.fetchResource(eq(ValueSet.class), eq(ID_VS_SCHOOLTYPE))).thenReturn(iccSchoolTypeVs); when(myValSupport.fetchResource(eq(ValueSet.class), eq(ID_VS_SCHOOLTYPE))).thenReturn(iccSchoolTypeVs);
when(myValSupport.validateCodeInValueSet(any(), any(), any(), any(), any(), any(ValueSet.class))).thenReturn(new IValidationSupport.CodeValidationResult().setCode(CODE_ICC_SCHOOLTYPE_PT)); when(myValSupport.validateCodeInValueSet(any(), any(), any(), any(), any(), any(ValueSet.class))).thenReturn(new IValidationSupport.CodeValidationResult().setCode(CODE_ICC_SCHOOLTYPE_PT));
when(myValSupport.fetchCodeSystem(eq(SYSTEMURI_ICC_SCHOOLTYPE))).thenReturn(codeSystem);
ValidationResult errors = myVal.validateWithResult(qa); ValidationResult errors = myVal.validateWithResult(qa);
ourLog.info(errors.toString()); ourLog.info(errors.toString());

20
pom.xml
View File

@ -2043,26 +2043,6 @@
</execution> </execution>
</executions> </executions>
</plugin> </plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<executions>
<execution>
<id>enforce-property</id>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<requireJavaVersion>
<version>11</version>
</requireJavaVersion>
</rules>
<fail>true</fail>
</configuration>
</execution>
</executions>
</plugin>
<plugin> <plugin>
<artifactId>maven-antrun-plugin</artifactId> <artifactId>maven-antrun-plugin</artifactId>
<inherited>false</inherited> <inherited>false</inherited>