Work on subscriptions, and correct indexing of codes in JPA
This commit is contained in:
parent
9664174b6a
commit
900c93949a
|
@ -49,13 +49,8 @@ public class BoundCodeDt<T extends Enum<?>> extends CodeDt {
|
||||||
setValueAsEnum(theValue);
|
setValueAsEnum(theValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setValueAsEnum(T theValue) {
|
public IValueSetEnumBinder<T> getBinder() {
|
||||||
Validate.notNull(myBinder, "This object does not have a binder. Constructor BoundCodeDt() should not be called!");
|
return myBinder;
|
||||||
if (theValue==null) {
|
|
||||||
setValue(null);
|
|
||||||
} else {
|
|
||||||
setValue(myBinder.toCodeString(theValue));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public T getValueAsEnum() {
|
public T getValueAsEnum() {
|
||||||
|
@ -66,4 +61,13 @@ public class BoundCodeDt<T extends Enum<?>> extends CodeDt {
|
||||||
}
|
}
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setValueAsEnum(T theValue) {
|
||||||
|
Validate.notNull(myBinder, "This object does not have a binder. Constructor BoundCodeDt() should not be called!");
|
||||||
|
if (theValue==null) {
|
||||||
|
setValue(null);
|
||||||
|
} else {
|
||||||
|
setValue(myBinder.toCodeString(theValue));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<classpath>
|
<classpath>
|
||||||
<classpathentry kind="src" path="src/test/java">
|
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
|
||||||
<attributes>
|
<attributes>
|
||||||
<attribute name="optional" value="true"/>
|
<attribute name="optional" value="true"/>
|
||||||
<attribute name="maven.pomderived" value="true"/>
|
<attribute name="maven.pomderived" value="true"/>
|
||||||
</attributes>
|
</attributes>
|
||||||
</classpathentry>
|
</classpathentry>
|
||||||
<classpathentry kind="src" path="src/test/resources"/>
|
<classpathentry kind="src" output="target/test-classes" path="src/test/resources"/>
|
||||||
<classpathentry kind="src" path="src/main/java">
|
<classpathentry kind="src" path="src/main/java">
|
||||||
<attributes>
|
<attributes>
|
||||||
<attribute name="optional" value="true"/>
|
<attribute name="optional" value="true"/>
|
||||||
|
|
|
@ -52,6 +52,7 @@ import ca.uhn.fhir.jpa.entity.ResourceTable;
|
||||||
import ca.uhn.fhir.model.api.IDatatype;
|
import ca.uhn.fhir.model.api.IDatatype;
|
||||||
import ca.uhn.fhir.model.api.IPrimitiveDatatype;
|
import ca.uhn.fhir.model.api.IPrimitiveDatatype;
|
||||||
import ca.uhn.fhir.model.api.IResource;
|
import ca.uhn.fhir.model.api.IResource;
|
||||||
|
import ca.uhn.fhir.model.api.IValueSetEnumBinder;
|
||||||
import ca.uhn.fhir.model.base.composite.BaseHumanNameDt;
|
import ca.uhn.fhir.model.base.composite.BaseHumanNameDt;
|
||||||
import ca.uhn.fhir.model.dstu2.composite.AddressDt;
|
import ca.uhn.fhir.model.dstu2.composite.AddressDt;
|
||||||
import ca.uhn.fhir.model.dstu2.composite.BoundCodeableConceptDt;
|
import ca.uhn.fhir.model.dstu2.composite.BoundCodeableConceptDt;
|
||||||
|
@ -71,6 +72,7 @@ import ca.uhn.fhir.model.dstu2.resource.Questionnaire;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.ValueSet;
|
import ca.uhn.fhir.model.dstu2.resource.ValueSet;
|
||||||
import ca.uhn.fhir.model.dstu2.valueset.RestfulSecurityServiceEnum;
|
import ca.uhn.fhir.model.dstu2.valueset.RestfulSecurityServiceEnum;
|
||||||
import ca.uhn.fhir.model.primitive.BaseDateTimeDt;
|
import ca.uhn.fhir.model.primitive.BaseDateTimeDt;
|
||||||
|
import ca.uhn.fhir.model.primitive.BoundCodeDt;
|
||||||
import ca.uhn.fhir.model.primitive.IntegerDt;
|
import ca.uhn.fhir.model.primitive.IntegerDt;
|
||||||
import ca.uhn.fhir.model.primitive.StringDt;
|
import ca.uhn.fhir.model.primitive.StringDt;
|
||||||
import ca.uhn.fhir.model.primitive.UriDt;
|
import ca.uhn.fhir.model.primitive.UriDt;
|
||||||
|
@ -115,7 +117,8 @@ public class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implemen
|
||||||
/*
|
/*
|
||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
*
|
*
|
||||||
* @see ca.uhn.fhir.jpa.dao.ISearchParamExtractor#extractSearchParamDates(ca.uhn.fhir.jpa.entity.ResourceTable, ca.uhn.fhir.model.api.IResource)
|
* @see ca.uhn.fhir.jpa.dao.ISearchParamExtractor#extractSearchParamDates(ca.uhn.fhir.jpa.entity.ResourceTable,
|
||||||
|
* ca.uhn.fhir.model.api.IResource)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Set<ResourceIndexedSearchParamDate> extractSearchParamDates(ResourceTable theEntity, IResource theResource) {
|
public Set<ResourceIndexedSearchParamDate> extractSearchParamDates(ResourceTable theEntity, IResource theResource) {
|
||||||
|
@ -175,7 +178,8 @@ public class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implemen
|
||||||
/*
|
/*
|
||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
*
|
*
|
||||||
* @see ca.uhn.fhir.jpa.dao.ISearchParamExtractor#extractSearchParamNumber(ca.uhn.fhir.jpa.entity.ResourceTable, ca.uhn.fhir.model.api.IResource)
|
* @see ca.uhn.fhir.jpa.dao.ISearchParamExtractor#extractSearchParamNumber(ca.uhn.fhir.jpa.entity.ResourceTable,
|
||||||
|
* ca.uhn.fhir.model.api.IResource)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public HashSet<ResourceIndexedSearchParamNumber> extractSearchParamNumber(ResourceTable theEntity, IResource theResource) {
|
public HashSet<ResourceIndexedSearchParamNumber> extractSearchParamNumber(ResourceTable theEntity, IResource theResource) {
|
||||||
|
@ -222,12 +226,17 @@ public class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implemen
|
||||||
nextValue = newValue;
|
nextValue = newValue;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @SuppressWarnings("unchecked") PhysicsUnit<? extends org.unitsofmeasurement.quantity.Quantity<?>> unit = (PhysicsUnit<? extends org.unitsofmeasurement.quantity.Quantity<?>>)
|
* @SuppressWarnings("unchecked") PhysicsUnit<? extends
|
||||||
* UCUMFormat.getCaseInsensitiveInstance().parse(nextValue.getCode().getValue(), null); if (unit.isCompatible(UCUM.DAY)) {
|
* org.unitsofmeasurement.quantity.Quantity<?>> unit = (PhysicsUnit<? extends
|
||||||
|
* org.unitsofmeasurement.quantity.Quantity<?>>)
|
||||||
|
* UCUMFormat.getCaseInsensitiveInstance().parse(nextValue.getCode().getValue(), null); if
|
||||||
|
* (unit.isCompatible(UCUM.DAY)) {
|
||||||
*
|
*
|
||||||
* @SuppressWarnings("unchecked") PhysicsUnit<org.unitsofmeasurement.quantity.Time> timeUnit = (PhysicsUnit<Time>) unit; UnitConverter conv = timeUnit.getConverterTo(UCUM.DAY);
|
* @SuppressWarnings("unchecked") PhysicsUnit<org.unitsofmeasurement.quantity.Time> timeUnit =
|
||||||
* double dayValue = conv.convert(nextValue.getValue().getValue().doubleValue()); DurationDt newValue = new DurationDt(); newValue.setSystem(UCUM_NS);
|
* (PhysicsUnit<Time>) unit; UnitConverter conv = timeUnit.getConverterTo(UCUM.DAY); double
|
||||||
* newValue.setCode(UCUM.DAY.getSymbol()); newValue.setValue(dayValue); nextValue=newValue; }
|
* dayValue = conv.convert(nextValue.getValue().getValue().doubleValue()); DurationDt newValue =
|
||||||
|
* new DurationDt(); newValue.setSystem(UCUM_NS); newValue.setCode(UCUM.DAY.getSymbol());
|
||||||
|
* newValue.setValue(dayValue); nextValue=newValue; }
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -269,7 +278,8 @@ public class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implemen
|
||||||
/*
|
/*
|
||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
*
|
*
|
||||||
* @see ca.uhn.fhir.jpa.dao.ISearchParamExtractor#extractSearchParamQuantity(ca.uhn.fhir.jpa.entity.ResourceTable, ca.uhn.fhir.model.api.IResource)
|
* @see ca.uhn.fhir.jpa.dao.ISearchParamExtractor#extractSearchParamQuantity(ca.uhn.fhir.jpa.entity.ResourceTable,
|
||||||
|
* ca.uhn.fhir.model.api.IResource)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Set<ResourceIndexedSearchParamQuantity> extractSearchParamQuantity(ResourceTable theEntity, IResource theResource) {
|
public Set<ResourceIndexedSearchParamQuantity> extractSearchParamQuantity(ResourceTable theEntity, IResource theResource) {
|
||||||
|
@ -303,8 +313,7 @@ public class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implemen
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResourceIndexedSearchParamQuantity nextEntity = new ResourceIndexedSearchParamQuantity(resourceName, nextValue.getValueElement().getValue(),
|
ResourceIndexedSearchParamQuantity nextEntity = new ResourceIndexedSearchParamQuantity(resourceName, nextValue.getValueElement().getValue(), nextValue.getSystemElement().getValueAsString(), nextValue.getCode());
|
||||||
nextValue.getSystemElement().getValueAsString(), nextValue.getCode());
|
|
||||||
nextEntity.setResource(theEntity);
|
nextEntity.setResource(theEntity);
|
||||||
retVal.add(nextEntity);
|
retVal.add(nextEntity);
|
||||||
} else {
|
} else {
|
||||||
|
@ -323,7 +332,8 @@ public class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implemen
|
||||||
/*
|
/*
|
||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
*
|
*
|
||||||
* @see ca.uhn.fhir.jpa.dao.ISearchParamExtractor#extractSearchParamStrings(ca.uhn.fhir.jpa.entity.ResourceTable, ca.uhn.fhir.model.api.IResource)
|
* @see ca.uhn.fhir.jpa.dao.ISearchParamExtractor#extractSearchParamStrings(ca.uhn.fhir.jpa.entity.ResourceTable,
|
||||||
|
* ca.uhn.fhir.model.api.IResource)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Set<ResourceIndexedSearchParamString> extractSearchParamStrings(ResourceTable theEntity, IResource theResource) {
|
public Set<ResourceIndexedSearchParamString> extractSearchParamStrings(ResourceTable theEntity, IResource theResource) {
|
||||||
|
@ -404,7 +414,8 @@ public class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implemen
|
||||||
/*
|
/*
|
||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
*
|
*
|
||||||
* @see ca.uhn.fhir.jpa.dao.ISearchParamExtractor#extractSearchParamTokens(ca.uhn.fhir.jpa.entity.ResourceTable, ca.uhn.fhir.model.api.IResource)
|
* @see ca.uhn.fhir.jpa.dao.ISearchParamExtractor#extractSearchParamTokens(ca.uhn.fhir.jpa.entity.ResourceTable,
|
||||||
|
* ca.uhn.fhir.model.api.IResource)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Set<BaseResourceIndexedSearchParam> extractSearchParamTokens(ResourceTable theEntity, IResource theResource) {
|
public Set<BaseResourceIndexedSearchParam> extractSearchParamTokens(ResourceTable theEntity, IResource theResource) {
|
||||||
|
@ -481,6 +492,14 @@ public class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implemen
|
||||||
}
|
}
|
||||||
systems.add(nextValue.getSystemElement().getValueAsString());
|
systems.add(nextValue.getSystemElement().getValueAsString());
|
||||||
codes.add(nextValue.getValueElement().getValue());
|
codes.add(nextValue.getValueElement().getValue());
|
||||||
|
} else if (nextObject instanceof BoundCodeDt) {
|
||||||
|
BoundCodeDt<?> obj = (BoundCodeDt<?>) nextObject;
|
||||||
|
String system = extractSystem(obj);
|
||||||
|
String code = obj.getValue();
|
||||||
|
if (isNotBlank(code)) {
|
||||||
|
systems.add(system);
|
||||||
|
codes.add(code);
|
||||||
|
}
|
||||||
} else if (nextObject instanceof IPrimitiveDatatype<?>) {
|
} else if (nextObject instanceof IPrimitiveDatatype<?>) {
|
||||||
IPrimitiveDatatype<?> nextValue = (IPrimitiveDatatype<?>) nextObject;
|
IPrimitiveDatatype<?> nextValue = (IPrimitiveDatatype<?>) nextObject;
|
||||||
if (nextValue.isEmpty()) {
|
if (nextValue.isEmpty()) {
|
||||||
|
@ -503,7 +522,8 @@ public class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implemen
|
||||||
|
|
||||||
extractTokensFromCodeableConcept(systems, codes, nextCC, theEntity, retVal, nextSpDef);
|
extractTokensFromCodeableConcept(systems, codes, nextCC, theEntity, retVal, nextSpDef);
|
||||||
} else if (nextObject instanceof RestSecurity) {
|
} else if (nextObject instanceof RestSecurity) {
|
||||||
// Conformance.security search param points to something kind of useless right now - This should probably be fixed.
|
// Conformance.security search param points to something kind of useless right now - This should probably
|
||||||
|
// be fixed.
|
||||||
RestSecurity sec = (RestSecurity) nextObject;
|
RestSecurity sec = (RestSecurity) nextObject;
|
||||||
for (BoundCodeableConceptDt<RestfulSecurityServiceEnum> nextCC : sec.getService()) {
|
for (BoundCodeableConceptDt<RestfulSecurityServiceEnum> nextCC : sec.getService()) {
|
||||||
extractTokensFromCodeableConcept(systems, codes, nextCC, theEntity, retVal, nextSpDef);
|
extractTokensFromCodeableConcept(systems, codes, nextCC, theEntity, retVal, nextSpDef);
|
||||||
|
@ -606,16 +626,13 @@ public class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implemen
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void extractTokensFromCodeableConcept(List<String> theSystems, List<String> theCodes, CodeableConceptDt theCodeableConcept, ResourceTable theEntity, Set<BaseResourceIndexedSearchParam> theListToPopulate, RuntimeSearchParam theParameterDef) {
|
||||||
private void extractTokensFromCodeableConcept(List<String> theSystems, List<String> theCodes, CodeableConceptDt theCodeableConcept, ResourceTable theEntity,
|
|
||||||
Set<BaseResourceIndexedSearchParam> theListToPopulate, RuntimeSearchParam theParameterDef) {
|
|
||||||
for (CodingDt nextCoding : theCodeableConcept.getCoding()) {
|
for (CodingDt nextCoding : theCodeableConcept.getCoding()) {
|
||||||
extractTokensFromCoding(theSystems, theCodes, theEntity, theListToPopulate, theParameterDef, nextCoding);
|
extractTokensFromCoding(theSystems, theCodes, theEntity, theListToPopulate, theParameterDef, nextCoding);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void extractTokensFromCoding(List<String> theSystems, List<String> theCodes, ResourceTable theEntity, Set<BaseResourceIndexedSearchParam> theListToPopulate,
|
private void extractTokensFromCoding(List<String> theSystems, List<String> theCodes, ResourceTable theEntity, Set<BaseResourceIndexedSearchParam> theListToPopulate, RuntimeSearchParam theParameterDef, CodingDt nextCoding) {
|
||||||
RuntimeSearchParam theParameterDef, CodingDt nextCoding) {
|
|
||||||
if (nextCoding != null && !nextCoding.isEmpty()) {
|
if (nextCoding != null && !nextCoding.isEmpty()) {
|
||||||
|
|
||||||
String nextSystem = nextCoding.getSystemElement().getValueAsString();
|
String nextSystem = nextCoding.getSystemElement().getValueAsString();
|
||||||
|
@ -632,4 +649,12 @@ public class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implemen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static <T extends Enum<?>> String extractSystem(BoundCodeDt<T> theBoundCode) {
|
||||||
|
if (theBoundCode.getValueAsEnum() != null) {
|
||||||
|
IValueSetEnumBinder<T> binder = theBoundCode.getBinder();
|
||||||
|
return binder.toSystemString(theBoundCode.getValueAsEnum());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,8 @@ import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.model.dstu2.resource.Bundle;
|
||||||
|
import ca.uhn.fhir.model.dstu2.resource.Bundle.Entry;
|
||||||
import ca.uhn.fhir.rest.server.IBundleProvider;
|
import ca.uhn.fhir.rest.server.IBundleProvider;
|
||||||
|
|
||||||
public class BaseJpaTest {
|
public class BaseJpaTest {
|
||||||
|
@ -35,6 +37,16 @@ public class BaseJpaTest {
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected List<IIdType> toUnqualifiedVersionlessIds(Bundle theFound) {
|
||||||
|
List<IIdType> retVal = new ArrayList<IIdType>();
|
||||||
|
for (Entry next : theFound.getEntry()) {
|
||||||
|
// if (next.getResource()!= null) {
|
||||||
|
retVal.add(next.getResource().getId().toUnqualifiedVersionless());
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
protected List<IIdType> toUnqualifiedVersionlessIds(List<IBaseResource> theFound) {
|
protected List<IIdType> toUnqualifiedVersionlessIds(List<IBaseResource> theFound) {
|
||||||
List<IIdType> retVal = new ArrayList<IIdType>();
|
List<IIdType> retVal = new ArrayList<IIdType>();
|
||||||
for (IBaseResource next : theFound) {
|
for (IBaseResource next : theFound) {
|
||||||
|
|
|
@ -56,9 +56,12 @@ import ca.uhn.fhir.model.dstu2.resource.Observation;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.Organization;
|
import ca.uhn.fhir.model.dstu2.resource.Organization;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.Patient;
|
import ca.uhn.fhir.model.dstu2.resource.Patient;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.Practitioner;
|
import ca.uhn.fhir.model.dstu2.resource.Practitioner;
|
||||||
|
import ca.uhn.fhir.model.dstu2.resource.Subscription;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.Substance;
|
import ca.uhn.fhir.model.dstu2.resource.Substance;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.ValueSet;
|
import ca.uhn.fhir.model.dstu2.resource.ValueSet;
|
||||||
import ca.uhn.fhir.model.dstu2.valueset.ContactPointSystemEnum;
|
import ca.uhn.fhir.model.dstu2.valueset.ContactPointSystemEnum;
|
||||||
|
import ca.uhn.fhir.model.dstu2.valueset.SubscriptionChannelTypeEnum;
|
||||||
|
import ca.uhn.fhir.model.dstu2.valueset.SubscriptionStatusEnum;
|
||||||
import ca.uhn.fhir.model.primitive.CodeDt;
|
import ca.uhn.fhir.model.primitive.CodeDt;
|
||||||
import ca.uhn.fhir.model.primitive.DateDt;
|
import ca.uhn.fhir.model.primitive.DateDt;
|
||||||
import ca.uhn.fhir.model.primitive.DateTimeDt;
|
import ca.uhn.fhir.model.primitive.DateTimeDt;
|
||||||
|
@ -100,6 +103,19 @@ public class FhirResourceDaoDstu2SearchTest extends BaseJpaDstu2Test {
|
||||||
assertEquals(0, results.size());
|
assertEquals(0, results.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCodeSearch() {
|
||||||
|
Subscription subs = new Subscription();
|
||||||
|
subs.setStatus(SubscriptionStatusEnum.ACTIVE);
|
||||||
|
subs.getChannel().setType(SubscriptionChannelTypeEnum.WEBSOCKET);
|
||||||
|
subs.setCriteria("Observation?");
|
||||||
|
IIdType id = mySubscriptionDao.create(subs).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
|
SearchParameterMap map = new SearchParameterMap();
|
||||||
|
map.add(Subscription.SP_TYPE, new TokenParam(null, SubscriptionChannelTypeEnum.WEBSOCKET.getCode()));
|
||||||
|
map.add(Subscription.SP_STATUS, new TokenParam(null, SubscriptionStatusEnum.ACTIVE.getCode()));
|
||||||
|
assertThat(toUnqualifiedVersionlessIds(mySubscriptionDao.search(map)), contains(id));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIndexNoDuplicatesString() {
|
public void testIndexNoDuplicatesString() {
|
||||||
|
|
|
@ -4,6 +4,7 @@ import static org.hamcrest.Matchers.contains;
|
||||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||||
import static org.hamcrest.Matchers.containsInRelativeOrder;
|
import static org.hamcrest.Matchers.containsInRelativeOrder;
|
||||||
import static org.hamcrest.Matchers.containsString;
|
import static org.hamcrest.Matchers.containsString;
|
||||||
|
import static org.hamcrest.Matchers.empty;
|
||||||
import static org.hamcrest.Matchers.greaterThan;
|
import static org.hamcrest.Matchers.greaterThan;
|
||||||
import static org.hamcrest.Matchers.hasItems;
|
import static org.hamcrest.Matchers.hasItems;
|
||||||
import static org.hamcrest.Matchers.not;
|
import static org.hamcrest.Matchers.not;
|
||||||
|
@ -69,12 +70,15 @@ import ca.uhn.fhir.model.dstu2.resource.Parameters;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.Patient;
|
import ca.uhn.fhir.model.dstu2.resource.Patient;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.Questionnaire;
|
import ca.uhn.fhir.model.dstu2.resource.Questionnaire;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.QuestionnaireResponse;
|
import ca.uhn.fhir.model.dstu2.resource.QuestionnaireResponse;
|
||||||
|
import ca.uhn.fhir.model.dstu2.resource.Subscription;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.ValueSet;
|
import ca.uhn.fhir.model.dstu2.resource.ValueSet;
|
||||||
import ca.uhn.fhir.model.dstu2.valueset.AnswerFormatEnum;
|
import ca.uhn.fhir.model.dstu2.valueset.AnswerFormatEnum;
|
||||||
import ca.uhn.fhir.model.dstu2.valueset.EncounterClassEnum;
|
import ca.uhn.fhir.model.dstu2.valueset.EncounterClassEnum;
|
||||||
import ca.uhn.fhir.model.dstu2.valueset.EncounterStateEnum;
|
import ca.uhn.fhir.model.dstu2.valueset.EncounterStateEnum;
|
||||||
import ca.uhn.fhir.model.dstu2.valueset.HTTPVerbEnum;
|
import ca.uhn.fhir.model.dstu2.valueset.HTTPVerbEnum;
|
||||||
import ca.uhn.fhir.model.dstu2.valueset.SearchEntryModeEnum;
|
import ca.uhn.fhir.model.dstu2.valueset.SearchEntryModeEnum;
|
||||||
|
import ca.uhn.fhir.model.dstu2.valueset.SubscriptionChannelTypeEnum;
|
||||||
|
import ca.uhn.fhir.model.dstu2.valueset.SubscriptionStatusEnum;
|
||||||
import ca.uhn.fhir.model.primitive.DateDt;
|
import ca.uhn.fhir.model.primitive.DateDt;
|
||||||
import ca.uhn.fhir.model.primitive.DateTimeDt;
|
import ca.uhn.fhir.model.primitive.DateTimeDt;
|
||||||
import ca.uhn.fhir.model.primitive.IdDt;
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
|
@ -104,6 +108,53 @@ public class ResourceProviderDstu2Test extends BaseResourceProviderDstu2Test {
|
||||||
assertEquals(200, resp.getStatusLine().getStatusCode());
|
assertEquals(200, resp.getStatusLine().getStatusCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCodeSearch() {
|
||||||
|
Subscription subs = new Subscription();
|
||||||
|
subs.setStatus(SubscriptionStatusEnum.ACTIVE);
|
||||||
|
subs.getChannel().setType(SubscriptionChannelTypeEnum.WEBSOCKET);
|
||||||
|
subs.setCriteria("Observation?");
|
||||||
|
IIdType id = ourClient.create().resource(subs).execute().getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
|
//@formatter:off
|
||||||
|
ca.uhn.fhir.model.dstu2.resource.Bundle resp = ourClient
|
||||||
|
.search()
|
||||||
|
.forResource(Subscription.class)
|
||||||
|
.where(Subscription.TYPE.exactly().code(SubscriptionChannelTypeEnum.WEBSOCKET.getCode()))
|
||||||
|
.and(Subscription.STATUS.exactly().code(SubscriptionStatusEnum.ACTIVE.getCode()))
|
||||||
|
.returnBundle(ca.uhn.fhir.model.dstu2.resource.Bundle.class)
|
||||||
|
.execute();
|
||||||
|
//@formatter:off
|
||||||
|
|
||||||
|
assertThat(toUnqualifiedVersionlessIds(resp), contains(id));
|
||||||
|
|
||||||
|
//@formatter:off
|
||||||
|
resp = ourClient
|
||||||
|
.search()
|
||||||
|
.forResource(Subscription.class)
|
||||||
|
.where(Subscription.TYPE.exactly().systemAndCode(SubscriptionChannelTypeEnum.WEBSOCKET.getSystem(), SubscriptionChannelTypeEnum.WEBSOCKET.getCode()))
|
||||||
|
.and(Subscription.STATUS.exactly().systemAndCode(SubscriptionStatusEnum.ACTIVE.getSystem(), SubscriptionStatusEnum.ACTIVE.getCode()))
|
||||||
|
.returnBundle(ca.uhn.fhir.model.dstu2.resource.Bundle.class)
|
||||||
|
.execute();
|
||||||
|
//@formatter:off
|
||||||
|
|
||||||
|
assertThat(toUnqualifiedVersionlessIds(resp), contains(id));
|
||||||
|
|
||||||
|
//@formatter:off
|
||||||
|
resp = ourClient
|
||||||
|
.search()
|
||||||
|
.forResource(Subscription.class)
|
||||||
|
.where(Subscription.TYPE.exactly().systemAndCode(SubscriptionChannelTypeEnum.WEBSOCKET.getSystem(), SubscriptionChannelTypeEnum.WEBSOCKET.getCode()))
|
||||||
|
.and(Subscription.STATUS.exactly().systemAndCode("foo", SubscriptionStatusEnum.ACTIVE.getCode()))
|
||||||
|
.returnBundle(ca.uhn.fhir.model.dstu2.resource.Bundle.class)
|
||||||
|
.execute();
|
||||||
|
//@formatter:off
|
||||||
|
|
||||||
|
assertThat(toUnqualifiedVersionlessIds(resp), empty());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// private void delete(String theResourceType, String theParamName, String theParamValue) {
|
// private void delete(String theResourceType, String theParamName, String theParamValue) {
|
||||||
// Bundle resources;
|
// Bundle resources;
|
||||||
// do {
|
// do {
|
||||||
|
|
|
@ -1,10 +1,19 @@
|
||||||
package ca.uhn.fhirtest.mvc;
|
package ca.uhn.fhirtest.mvc;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
import org.springframework.ui.ModelMap;
|
import org.springframework.ui.ModelMap;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.model.dstu2.resource.Bundle;
|
||||||
|
import ca.uhn.fhir.model.dstu2.resource.Bundle.Entry;
|
||||||
|
import ca.uhn.fhir.model.dstu2.resource.Subscription;
|
||||||
|
import ca.uhn.fhir.model.dstu2.valueset.SubscriptionChannelTypeEnum;
|
||||||
|
import ca.uhn.fhir.model.dstu2.valueset.SubscriptionStatusEnum;
|
||||||
|
import ca.uhn.fhir.rest.client.GenericClient;
|
||||||
import ca.uhn.fhir.to.BaseController;
|
import ca.uhn.fhir.to.BaseController;
|
||||||
import ca.uhn.fhir.to.model.HomeRequest;
|
import ca.uhn.fhir.to.model.HomeRequest;
|
||||||
|
|
||||||
|
@ -21,6 +30,28 @@ public class SubscriptionPlaygroundController extends BaseController {
|
||||||
|
|
||||||
ourLog.info(logPrefix(theModel) + "Displayed subscriptions playground page");
|
ourLog.info(logPrefix(theModel) + "Displayed subscriptions playground page");
|
||||||
|
|
||||||
|
CaptureInterceptor interceptor = new CaptureInterceptor();
|
||||||
|
GenericClient client = theRequest.newClient(theServletRequest, getContext(theRequest), myConfig, interceptor);
|
||||||
|
|
||||||
|
//@formatter:off
|
||||||
|
Bundle resp = client
|
||||||
|
.search()
|
||||||
|
.forResource(Subscription.class)
|
||||||
|
.where(Subscription.TYPE.exactly().code(SubscriptionChannelTypeEnum.WEBSOCKET.getCode()))
|
||||||
|
.and(Subscription.STATUS.exactly().code(SubscriptionStatusEnum.ACTIVE.getCode()))
|
||||||
|
.returnBundle(Bundle.class)
|
||||||
|
.execute();
|
||||||
|
//@formatter:off
|
||||||
|
|
||||||
|
List<Subscription> subscriptions = new ArrayList<Subscription>();
|
||||||
|
for (Entry next : resp.getEntry()) {
|
||||||
|
if (next.getResource() instanceof Subscription) {
|
||||||
|
subscriptions.add((Subscription) next.getResource());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
theModel.put("subscriptions", subscriptions);
|
||||||
|
|
||||||
return "subscriptions";
|
return "subscriptions";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,9 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Subscription Creation -->
|
||||||
|
<div id="subscription_creation">
|
||||||
|
|
||||||
<!-- Nav tabs -->
|
<!-- Nav tabs -->
|
||||||
<ul class="nav nav-tabs" role="tablist">
|
<ul class="nav nav-tabs" role="tablist">
|
||||||
<li role="presentation" class="active"><a href="#wss"
|
<li role="presentation" class="active"><a href="#wss"
|
||||||
|
@ -48,33 +51,29 @@
|
||||||
|
|
||||||
<!-- Tab panes -->
|
<!-- Tab panes -->
|
||||||
<div class="tab-content">
|
<div class="tab-content">
|
||||||
<div role="tabpanel" class="tab-pane active" id="wss">...1</div>
|
|
||||||
|
<!-- Static Websocket -->
|
||||||
|
<div role="tabpanel" class="tab-pane active" id="wss">
|
||||||
|
|
||||||
|
<table class="table table-striped table-condensed">
|
||||||
|
<tr>
|
||||||
|
<td>ID</td>
|
||||||
|
<td>Criteria</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
<tr th:each="subscription : ${subscriptions}">
|
||||||
|
<td th:text="${subscription.id.toUnqualified()}"/>
|
||||||
|
<td th:text="${subscription.criteria}"/>
|
||||||
|
<td>
|
||||||
|
<button type="button" class="btn btn-default btn-primary btn-block" id="dws_create" th:onclick="'dwsCreate(\'' + ${subscription.id.getIdPart()} + '\');'"><i class="glyphicon glyphicon-cog"></i> Subscribe</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Dynamic WebSocket -->
|
<!-- Dynamic WebSocket -->
|
||||||
<div role="tabpanel" class="tab-pane" id="wsd">
|
<div role="tabpanel" class="tab-pane" id="wsd">
|
||||||
<script type="text/javascript">
|
|
||||||
function dwsCreate() {
|
|
||||||
try {
|
|
||||||
var socket = new WebSocket("ws://localhost:8888/websocket/dstu2");
|
|
||||||
alert('Socket Status: '+socket.readyState);
|
|
||||||
|
|
||||||
socket.onopen = function() {
|
|
||||||
alert("Opening Socket: " + socket.readyState);
|
|
||||||
socket.send("bind Observation?");
|
|
||||||
}
|
|
||||||
socket.onmessage = function(msg) {
|
|
||||||
alert("New message: " + msg);
|
|
||||||
}
|
|
||||||
socket.onerror = function(error) {
|
|
||||||
alert("error: " + error);
|
|
||||||
}
|
|
||||||
} catch (exception) {
|
|
||||||
alert('Error'+exception);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
Enter a criteria in the text box below and then click subscribe to
|
Enter a criteria in the text box below and then click subscribe to
|
||||||
|
@ -93,36 +92,82 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-3">
|
<div class="col-sm-3">
|
||||||
<button type="button" class="btn btn-default btn-primary btn-block" id="dws_create" onclick="dwsCreate();"><i class="glyphicon glyphicon-cog"></i> Subscribe</button>
|
<button type="button" class="btn btn-default btn-primary btn-block" id="dws_create" onclick="dwsCreate(document.getElementById('dws_criteria').value, true);"><i class="glyphicon glyphicon-cog"></i> Subscribe</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Dynamic Subscription Results -->
|
<!-- Subscription Results -->
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default" style="display:none;" id="resultsDiv">
|
||||||
<div class="panel-heading">Subscription Results</div>
|
<div class="panel-heading">Subscription Results</div>
|
||||||
<div class="panel-body">
|
<ul class="list-group" id="subscription_status_list">
|
||||||
<p>
|
|
||||||
This will be status...
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- List group -->
|
|
||||||
<ul class="list-group">
|
|
||||||
<li class="list-group-item">Cras justo odio</li>
|
|
||||||
<li class="list-group-item">Dapibus ac facilisis in</li>
|
|
||||||
<li class="list-group-item">Morbi leo risus</li>
|
|
||||||
<li class="list-group-item">Porta ac consectetur ac</li>
|
|
||||||
<li class="list-group-item">Vestibulum at eros</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
function messageStatus(message) {
|
||||||
|
var listItem = $('<li />', { 'class': 'list-group-item' });
|
||||||
|
listItem.append($('<div class="glyphicon glyphicon-info-sign" style="width: 20px;"/>'));
|
||||||
|
listItem.append($('<span>' + message + '</span>'));
|
||||||
|
$('#subscription_status_list').append(listItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
function messageIn(message, remainder) {
|
||||||
|
var listItem = $('<li />', { 'class': 'list-group-item' });
|
||||||
|
listItem.append($('<div class="glyphicon glyphicon-download" style="width: 20px;"/>'));
|
||||||
|
listItem.append($('<span>' + message + '</span>'));
|
||||||
|
if (remainder) {
|
||||||
|
listItem.append($('<p>(' + remainder + ' bytes)</p>'));
|
||||||
|
listItem.append($('<pre style="display:none;"/>').text(remainder));
|
||||||
|
}
|
||||||
|
$('#subscription_status_list').append(listItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
function dwsCreate(bindArgument, dynamic) {
|
||||||
|
$('#resultsDiv').css("display","");
|
||||||
|
$('#subscription_creation').hide();
|
||||||
|
try {
|
||||||
|
var url = "ws://fhirtest.uhn.ca/websocket/dstu2";
|
||||||
|
messageStatus("Connecting to: " + url);
|
||||||
|
var socket = new WebSocket(url);
|
||||||
|
|
||||||
|
socket.onopen = function() {
|
||||||
|
messageStatus("Connected to: " + url);
|
||||||
|
$('#subscription_status_list')
|
||||||
|
.append(
|
||||||
|
$('<li />', { 'class': 'list-group-item' })
|
||||||
|
.append($('<div class="glyphicon glyphicon-upload" style="width: 20px;"/>'))
|
||||||
|
.append($('<span>bind ' + bindArgument + '</span>'))
|
||||||
|
);
|
||||||
|
socket.send("bind " + bindArgument);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function is called when a new message comes from the server
|
||||||
|
socket.onmessage = function(msg) {
|
||||||
|
var data = msg.data;
|
||||||
|
var remainder = null;
|
||||||
|
if (data.indexOf('\n') != -1) {
|
||||||
|
data = data.substring(0, data.indexOf('\n'));
|
||||||
|
remainder = data.substring(data.indexOf('\n') + 1);
|
||||||
|
}
|
||||||
|
messageIn(data, remainder);
|
||||||
|
}
|
||||||
|
socket.onerror = function(error) {
|
||||||
|
messageStatus("Error: " + error);
|
||||||
|
}
|
||||||
|
} catch (exception) {
|
||||||
|
messageStatus("Error: " + exception);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,9 @@ import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
|
||||||
import ca.uhn.fhir.model.api.TagList;
|
import ca.uhn.fhir.model.api.TagList;
|
||||||
import ca.uhn.fhir.model.dstu.resource.Organization;
|
import ca.uhn.fhir.model.dstu.resource.Organization;
|
||||||
import ca.uhn.fhir.model.dstu.resource.Patient;
|
import ca.uhn.fhir.model.dstu.resource.Patient;
|
||||||
|
import ca.uhn.fhir.model.dstu2.resource.Subscription;
|
||||||
|
import ca.uhn.fhir.model.dstu2.valueset.SubscriptionChannelTypeEnum;
|
||||||
|
import ca.uhn.fhir.model.dstu2.valueset.SubscriptionStatusEnum;
|
||||||
import ca.uhn.fhir.model.primitive.IdDt;
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||||
import ca.uhn.fhir.rest.client.IGenericClient;
|
import ca.uhn.fhir.rest.client.IGenericClient;
|
||||||
|
@ -21,7 +24,7 @@ public class UhnFhirTestApp {
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
|
|
||||||
int myPort = 8888;
|
int myPort = 8888;
|
||||||
String base = "http://localhost:" + myPort + "/base";
|
String base = "http://localhost:" + myPort + "/baseDstu2";
|
||||||
|
|
||||||
// new File("target/testdb").mkdirs();
|
// new File("target/testdb").mkdirs();
|
||||||
System.setProperty("fhir.db.location", "./target/testdb");
|
System.setProperty("fhir.db.location", "./target/testdb");
|
||||||
|
@ -47,13 +50,13 @@ public class UhnFhirTestApp {
|
||||||
// base = "http://spark.furore.com/fhir";
|
// base = "http://spark.furore.com/fhir";
|
||||||
|
|
||||||
if (true) {
|
if (true) {
|
||||||
FhirContext ctx = new FhirContext();
|
FhirContext ctx = FhirContext.forDstu2();
|
||||||
IGenericClient client = ctx.newRestfulGenericClient(base);
|
IGenericClient client = ctx.newRestfulGenericClient(base);
|
||||||
// client.setLogRequestAndResponse(true);
|
// client.setLogRequestAndResponse(true);
|
||||||
|
|
||||||
Organization o1 = new Organization();
|
Organization o1 = new Organization();
|
||||||
o1.getName().setValue("Some Org");
|
o1.getName().setValue("Some Org");
|
||||||
MethodOutcome create = client.create(o1);
|
MethodOutcome create = client.create().resource(o1).execute();
|
||||||
IdDt orgId = (IdDt) create.getId();
|
IdDt orgId = (IdDt) create.getId();
|
||||||
|
|
||||||
Patient p1 = new Patient();
|
Patient p1 = new Patient();
|
||||||
|
@ -64,10 +67,13 @@ public class UhnFhirTestApp {
|
||||||
TagList list = new TagList();
|
TagList list = new TagList();
|
||||||
list.addTag("http://hl7.org/fhir/tag", "urn:happytag", "This is a happy resource");
|
list.addTag("http://hl7.org/fhir/tag", "urn:happytag", "This is a happy resource");
|
||||||
ResourceMetadataKeyEnum.TAG_LIST.put(p1, list);
|
ResourceMetadataKeyEnum.TAG_LIST.put(p1, list);
|
||||||
client.create(p1);
|
client.create().resource(p1).execute();
|
||||||
|
|
||||||
List<IResource> resources = ctx.newJsonParser().parseBundle(IOUtils.toString(UhnFhirTestApp.class.getResourceAsStream("/bundle.json"))).toListOfResources();
|
Subscription subs = new Subscription();
|
||||||
// client.transaction().withResources(resources).execute();
|
subs.setStatus(SubscriptionStatusEnum.ACTIVE);
|
||||||
|
subs.getChannel().setType(SubscriptionChannelTypeEnum.WEBSOCKET);
|
||||||
|
subs.setCriteria("Observation?");
|
||||||
|
client.create().resource(subs).execute();
|
||||||
|
|
||||||
// for (int i = 0; i < 1000; i++) {
|
// for (int i = 0; i < 1000; i++) {
|
||||||
//
|
//
|
||||||
|
@ -78,22 +84,22 @@ public class UhnFhirTestApp {
|
||||||
// client.transaction(resources);
|
// client.transaction(resources);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
client.create(p1);
|
client.create().resource(p1).execute();
|
||||||
client.create(p1);
|
client.create().resource(p1).execute();
|
||||||
client.create(p1);
|
client.create().resource(p1).execute();
|
||||||
client.create(p1);
|
client.create().resource(p1).execute();
|
||||||
client.create(p1);
|
client.create().resource(p1).execute();
|
||||||
client.create(p1);
|
client.create().resource(p1).execute();
|
||||||
client.create(p1);
|
client.create().resource(p1).execute();
|
||||||
client.create(p1);
|
client.create().resource(p1).execute();
|
||||||
client.create(p1);
|
client.create().resource(p1).execute();
|
||||||
client.create(p1);
|
client.create().resource(p1).execute();
|
||||||
client.create(p1);
|
client.create().resource(p1).execute();
|
||||||
client.create(p1);
|
client.create().resource(p1).execute();
|
||||||
client.create(p1);
|
client.create().resource(p1).execute();
|
||||||
client.create(p1);
|
client.create().resource(p1).execute();
|
||||||
|
|
||||||
client.create(p1);
|
client.create().resource(p1).execute();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -106,6 +106,11 @@
|
||||||
did not have latest valueset definitions applied. Thanks
|
did not have latest valueset definitions applied. Thanks
|
||||||
to Bill de Beaubien for reporting!
|
to Bill de Beaubien for reporting!
|
||||||
</action>
|
</action>
|
||||||
|
<action type="fix">
|
||||||
|
JPA server can now successfully search for tokens pointing at code values
|
||||||
|
(values with no explicit system but an implied one, such as Patient.gender)
|
||||||
|
even if the system is supplied in the query.
|
||||||
|
</action>
|
||||||
</release>
|
</release>
|
||||||
<release version="1.2" date="2015-09-18">
|
<release version="1.2" date="2015-09-18">
|
||||||
<action type="add">
|
<action type="add">
|
||||||
|
|
Loading…
Reference in New Issue