Merge branch 'master' of github.com:jamesagnew/hapi-fhir

This commit is contained in:
James Agnew 2018-10-30 15:23:00 -04:00
commit 600f4585d1
15 changed files with 2824 additions and 928 deletions

View File

@ -20,10 +20,10 @@ package ca.uhn.fhir.model.api;
* #L% * #L%
*/ */
import java.util.List;
import org.hl7.fhir.instance.model.api.IBaseDatatype; import org.hl7.fhir.instance.model.api.IBaseDatatype;
import java.util.List;
public interface ISupportsUndeclaredExtensions extends IElement { public interface ISupportsUndeclaredExtensions extends IElement {
/** /**
@ -42,7 +42,8 @@ public interface ISupportsUndeclaredExtensions extends IElement {
/** /**
* Returns an <b>immutable</b> list containing all extensions (modifier and non-modifier). * Returns an <b>immutable</b> list containing all extensions (modifier and non-modifier).
* *
* @see #getUndeclaredExtensions() To return a mutable list which may be used to remove extensions * @see #getUndeclaredExtensions() To return a mutable list which may be used to remove undeclared non-modifier extensions
* @see #getUndeclaredModifierExtensions() To return a mutable list which may be used to remove undeclared modifier extensions
*/ */
List<ExtensionDt> getAllUndeclaredExtensions(); List<ExtensionDt> getAllUndeclaredExtensions();

View File

@ -1,36 +1,5 @@
package ca.uhn.fhir.util; package ca.uhn.fhir.util;
import static org.apache.commons.lang3.StringUtils.defaultString;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2018 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.util.*;
import java.util.function.Predicate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.api.*;
import ca.uhn.fhir.context.*; import ca.uhn.fhir.context.*;
import ca.uhn.fhir.context.BaseRuntimeElementDefinition.ChildTypeEnum; import ca.uhn.fhir.context.BaseRuntimeElementDefinition.ChildTypeEnum;
import ca.uhn.fhir.model.api.ExtensionDt; import ca.uhn.fhir.model.api.ExtensionDt;
@ -40,6 +9,35 @@ import ca.uhn.fhir.model.base.composite.BaseContainedDt;
import ca.uhn.fhir.model.base.composite.BaseResourceReferenceDt; import ca.uhn.fhir.model.base.composite.BaseResourceReferenceDt;
import ca.uhn.fhir.model.primitive.StringDt; import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.parser.DataFormatException; import ca.uhn.fhir.parser.DataFormatException;
import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.api.*;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static org.apache.commons.lang3.StringUtils.*;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2018 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
public class FhirTerser { public class FhirTerser {
@ -60,7 +58,41 @@ public class FhirTerser {
newList.add(theChildDefinition.getElementName()); newList.add(theChildDefinition.getElementName());
return newList; return newList;
} }
private ExtensionDt createEmptyExtensionDt(IBaseExtension theBaseExtension, String theUrl) {
return createEmptyExtensionDt(theBaseExtension, false, theUrl);
}
@SuppressWarnings("unchecked")
private ExtensionDt createEmptyExtensionDt(IBaseExtension theBaseExtension, boolean theIsModifier, String theUrl) {
ExtensionDt retVal = new ExtensionDt(theIsModifier, theUrl);
theBaseExtension.getExtension().add(retVal);
return retVal;
}
private ExtensionDt createEmptyExtensionDt(ISupportsUndeclaredExtensions theSupportsUndeclaredExtensions, String theUrl) {
return createEmptyExtensionDt(theSupportsUndeclaredExtensions, false, theUrl);
}
private ExtensionDt createEmptyExtensionDt(ISupportsUndeclaredExtensions theSupportsUndeclaredExtensions, boolean theIsModifier, String theUrl) {
return theSupportsUndeclaredExtensions.addUndeclaredExtension(theIsModifier, theUrl);
}
private IBaseExtension createEmptyExtension(IBaseHasExtensions theBaseHasExtensions, String theUrl) {
return (IBaseExtension) theBaseHasExtensions.addExtension().setUrl(theUrl);
}
private IBaseExtension createEmptyModifierExtension(IBaseHasModifierExtensions theBaseHasModifierExtensions, String theUrl) {
return (IBaseExtension) theBaseHasModifierExtensions.addModifierExtension().setUrl(theUrl);
}
private ExtensionDt createEmptyModifierExtensionDt(IBaseExtension theBaseExtension, String theUrl) {
return createEmptyExtensionDt(theBaseExtension, true, theUrl);
}
private ExtensionDt createEmptyModifierExtensionDt(ISupportsUndeclaredExtensions theSupportsUndeclaredExtensions, String theUrl) {
return createEmptyExtensionDt(theSupportsUndeclaredExtensions, true, theUrl);
}
/** /**
* Clones all values from a source object into the equivalent fields in a target object * Clones all values from a source object into the equivalent fields in a target object
@ -215,8 +247,12 @@ public class FhirTerser {
return retVal.get(0); return retVal.get(0);
} }
@SuppressWarnings("unchecked")
private <T> List<T> getValues(BaseRuntimeElementCompositeDefinition<?> theCurrentDef, Object theCurrentObj, List<String> theSubList, Class<T> theWantedClass) { private <T> List<T> getValues(BaseRuntimeElementCompositeDefinition<?> theCurrentDef, Object theCurrentObj, List<String> theSubList, Class<T> theWantedClass) {
return getValues(theCurrentDef, theCurrentObj, theSubList, theWantedClass, false, false);
}
@SuppressWarnings("unchecked")
private <T> List<T> getValues(BaseRuntimeElementCompositeDefinition<?> theCurrentDef, Object theCurrentObj, List<String> theSubList, Class<T> theWantedClass, boolean theCreate, boolean theAddExtension) {
String name = theSubList.get(0); String name = theSubList.get(0);
List<T> retVal = new ArrayList<>(); List<T> retVal = new ArrayList<>();
@ -227,16 +263,67 @@ public class FhirTerser {
extensionUrl = extensionUrl.substring(0, endIndex); extensionUrl = extensionUrl.substring(0, endIndex);
} }
List<ExtensionDt> extensions= Collections.emptyList(); if (myContext.getVersion().getVersion().isOlderThan(FhirVersionEnum.DSTU3)) {
if (theCurrentObj instanceof ISupportsUndeclaredExtensions) { // DTSU2
extensions = ((ISupportsUndeclaredExtensions) theCurrentObj).getUndeclaredExtensionsByUrl(extensionUrl); final String extensionDtUrlForLambda = extensionUrl;
} else if (theCurrentObj instanceof IBaseExtension) { List<ExtensionDt> extensionDts = Collections.emptyList();
extensions = ((IBaseExtension)theCurrentObj).getExtension(); if (theCurrentObj instanceof ISupportsUndeclaredExtensions) {
} extensionDts = ((ISupportsUndeclaredExtensions) theCurrentObj).getUndeclaredExtensions()
.stream()
.filter(t -> t.getUrl().equals(extensionDtUrlForLambda))
.collect(Collectors.toList());
for (ExtensionDt next : extensions) { if (theAddExtension
if (theWantedClass.isAssignableFrom(next.getClass())) { && (!(theCurrentObj instanceof IBaseExtension) || (extensionDts.isEmpty() && theSubList.size() == 1))) {
retVal.add((T) next); extensionDts.add(createEmptyExtensionDt((ISupportsUndeclaredExtensions) theCurrentObj, extensionUrl));
}
if (extensionDts.isEmpty() && theCreate) {
extensionDts.add(createEmptyExtensionDt((ISupportsUndeclaredExtensions) theCurrentObj, extensionUrl));
}
} else if (theCurrentObj instanceof IBaseExtension) {
extensionDts = ((IBaseExtension) theCurrentObj).getExtension();
if (theAddExtension
&& (extensionDts.isEmpty() && theSubList.size() == 1)) {
extensionDts.add(createEmptyExtensionDt((IBaseExtension) theCurrentObj, extensionUrl));
}
if (extensionDts.isEmpty() && theCreate) {
extensionDts.add(createEmptyExtensionDt((IBaseExtension) theCurrentObj, extensionUrl));
}
}
for (ExtensionDt next : extensionDts) {
if (theWantedClass.isAssignableFrom(next.getClass())) {
retVal.add((T) next);
}
}
} else {
// DSTU3+
final String extensionUrlForLambda = extensionUrl;
List<IBaseExtension> extensions = Collections.emptyList();
if (theCurrentObj instanceof IBaseHasExtensions) {
extensions = ((IBaseHasExtensions) theCurrentObj).getExtension()
.stream()
.filter(t -> t.getUrl().equals(extensionUrlForLambda))
.collect(Collectors.toList());
if (theAddExtension
&& (!(theCurrentObj instanceof IBaseExtension) || (extensions.isEmpty() && theSubList.size() == 1))) {
extensions.add(createEmptyExtension((IBaseHasExtensions) theCurrentObj, extensionUrl));
}
if (extensions.isEmpty() && theCreate) {
extensions.add(createEmptyExtension((IBaseHasExtensions) theCurrentObj, extensionUrl));
}
}
for (IBaseExtension next : extensions) {
if (theWantedClass.isAssignableFrom(next.getClass())) {
retVal.add((T) next);
}
} }
} }
@ -245,7 +332,92 @@ public class FhirTerser {
retVal = new ArrayList<>(); retVal = new ArrayList<>();
for (T nextElement : values) { for (T nextElement : values) {
BaseRuntimeElementCompositeDefinition<?> nextChildDef = (BaseRuntimeElementCompositeDefinition<?>) myContext.getElementDefinition((Class<? extends IBase>) nextElement.getClass()); BaseRuntimeElementCompositeDefinition<?> nextChildDef = (BaseRuntimeElementCompositeDefinition<?>) myContext.getElementDefinition((Class<? extends IBase>) nextElement.getClass());
List<T> foundValues = getValues(nextChildDef, nextElement, theSubList.subList(1, theSubList.size()), theWantedClass); List<T> foundValues = getValues(nextChildDef, nextElement, theSubList.subList(1, theSubList.size()), theWantedClass, theCreate, theAddExtension);
retVal.addAll(foundValues);
}
}
return retVal;
}
if (name.startsWith("modifierExtension('")) {
String extensionUrl = name.substring("modifierExtension('".length());
int endIndex = extensionUrl.indexOf('\'');
if (endIndex != -1) {
extensionUrl = extensionUrl.substring(0, endIndex);
}
if (myContext.getVersion().getVersion().isOlderThan(FhirVersionEnum.DSTU3)) {
// DSTU2
final String extensionDtUrlForLambda = extensionUrl;
List<ExtensionDt> extensionDts = Collections.emptyList();
if (theCurrentObj instanceof ISupportsUndeclaredExtensions) {
extensionDts = ((ISupportsUndeclaredExtensions) theCurrentObj).getUndeclaredModifierExtensions()
.stream()
.filter(t -> t.getUrl().equals(extensionDtUrlForLambda))
.collect(Collectors.toList());
if (theAddExtension
&& (!(theCurrentObj instanceof IBaseExtension) || (extensionDts.isEmpty() && theSubList.size() == 1))) {
extensionDts.add(createEmptyModifierExtensionDt((ISupportsUndeclaredExtensions) theCurrentObj, extensionUrl));
}
if (extensionDts.isEmpty() && theCreate) {
extensionDts.add(createEmptyModifierExtensionDt((ISupportsUndeclaredExtensions) theCurrentObj, extensionUrl));
}
} else if (theCurrentObj instanceof IBaseExtension) {
extensionDts = ((IBaseExtension) theCurrentObj).getExtension();
if (theAddExtension
&& (extensionDts.isEmpty() && theSubList.size() == 1)) {
extensionDts.add(createEmptyExtensionDt((IBaseExtension) theCurrentObj, extensionUrl));
}
if (extensionDts.isEmpty() && theCreate) {
extensionDts.add(createEmptyExtensionDt((IBaseExtension) theCurrentObj, extensionUrl));
}
}
for (ExtensionDt next : extensionDts) {
if (theWantedClass.isAssignableFrom(next.getClass())) {
retVal.add((T) next);
}
}
} else {
// DSTU3+
final String extensionUrlForLambda = extensionUrl;
List<IBaseExtension> extensions = Collections.emptyList();
if (theCurrentObj instanceof IBaseHasModifierExtensions) {
extensions = ((IBaseHasModifierExtensions) theCurrentObj).getModifierExtension()
.stream()
.filter(t -> t.getUrl().equals(extensionUrlForLambda))
.collect(Collectors.toList());
if (theAddExtension
&& (!(theCurrentObj instanceof IBaseExtension) || (extensions.isEmpty() && theSubList.size() == 1))) {
extensions.add(createEmptyModifierExtension((IBaseHasModifierExtensions) theCurrentObj, extensionUrl));
}
if (extensions.isEmpty() && theCreate) {
extensions.add(createEmptyModifierExtension((IBaseHasModifierExtensions) theCurrentObj, extensionUrl));
}
}
for (IBaseExtension next : extensions) {
if (theWantedClass.isAssignableFrom(next.getClass())) {
retVal.add((T) next);
}
}
}
if (theSubList.size() > 1) {
List<T> values = retVal;
retVal = new ArrayList<>();
for (T nextElement : values) {
BaseRuntimeElementCompositeDefinition<?> nextChildDef = (BaseRuntimeElementCompositeDefinition<?>) myContext.getElementDefinition((Class<? extends IBase>) nextElement.getClass());
List<T> foundValues = getValues(nextChildDef, nextElement, theSubList.subList(1, theSubList.size()), theWantedClass, theCreate, theAddExtension);
retVal.addAll(foundValues); retVal.addAll(foundValues);
} }
} }
@ -256,6 +428,14 @@ public class FhirTerser {
BaseRuntimeChildDefinition nextDef = theCurrentDef.getChildByNameOrThrowDataFormatException(name); BaseRuntimeChildDefinition nextDef = theCurrentDef.getChildByNameOrThrowDataFormatException(name);
List<? extends IBase> values = nextDef.getAccessor().getValues(theCurrentObj); List<? extends IBase> values = nextDef.getAccessor().getValues(theCurrentObj);
if (values.isEmpty() && theCreate) {
IBase value = nextDef.getChildByName(name).newInstance();
nextDef.getMutator().addValue(theCurrentObj, value);
List<IBase> list = new ArrayList<>();
list.add(value);
values = list;
}
if (theSubList.size() == 1) { if (theSubList.size() == 1) {
if (nextDef instanceof RuntimeChildChoiceDefinition) { if (nextDef instanceof RuntimeChildChoiceDefinition) {
for (IBase next : values) { for (IBase next : values) {
@ -286,26 +466,109 @@ public class FhirTerser {
} else { } else {
for (IBase nextElement : values) { for (IBase nextElement : values) {
BaseRuntimeElementCompositeDefinition<?> nextChildDef = (BaseRuntimeElementCompositeDefinition<?>) myContext.getElementDefinition(nextElement.getClass()); BaseRuntimeElementCompositeDefinition<?> nextChildDef = (BaseRuntimeElementCompositeDefinition<?>) myContext.getElementDefinition(nextElement.getClass());
List<T> foundValues = getValues(nextChildDef, nextElement, theSubList.subList(1, theSubList.size()), theWantedClass); List<T> foundValues = getValues(nextChildDef, nextElement, theSubList.subList(1, theSubList.size()), theWantedClass, theCreate, theAddExtension);
retVal.addAll(foundValues); retVal.addAll(foundValues);
} }
} }
return retVal; return retVal;
} }
/**
* Returns values stored in an element identified by its path. The list of values is of
* type {@link Object}.
*
* @param theResource The resource instance to be accessed. Must not be null.
* @param thePath The path for the element to be accessed.
* @return A list of values of type {@link Object}.
*/
public List<Object> getValues(IBaseResource theResource, String thePath) { public List<Object> getValues(IBaseResource theResource, String thePath) {
Class<Object> wantedClass = Object.class; Class<Object> wantedClass = Object.class;
return getValues(theResource, thePath, wantedClass); return getValues(theResource, thePath, wantedClass);
} }
/**
* Returns values stored in an element identified by its path. The list of values is of
* type {@link Object}.
*
* @param theResource The resource instance to be accessed. Must not be null.
* @param thePath The path for the element to be accessed.
* @param theCreate When set to <code>true</code>, the terser will create a null-valued element where none exists.
* @return A list of values of type {@link Object}.
*/
public List<Object> getValues(IBaseResource theResource, String thePath, boolean theCreate) {
Class<Object> wantedClass = Object.class;
return getValues(theResource, thePath, wantedClass, theCreate);
}
/**
* Returns values stored in an element identified by its path. The list of values is of
* type {@link Object}.
*
* @param theResource The resource instance to be accessed. Must not be null.
* @param thePath The path for the element to be accessed.
* @param theCreate When set to <code>true</code>, the terser will create a null-valued element where none exists.
* @param theAddExtension When set to <code>true</code>, the terser will add a null-valued extension where one or more such extensions already exist.
* @return A list of values of type {@link Object}.
*/
public List<Object> getValues(IBaseResource theResource, String thePath, boolean theCreate, boolean theAddExtension) {
Class<Object> wantedClass = Object.class;
return getValues(theResource, thePath, wantedClass, theCreate, theAddExtension);
}
/**
* Returns values stored in an element identified by its path. The list of values is of
* type <code>theWantedClass</code>.
*
* @param theResource The resource instance to be accessed. Must not be null.
* @param thePath The path for the element to be accessed.
* @param theWantedClass The desired class to be returned in a list.
* @param <T> Type declared by <code>theWantedClass</code>
* @return A list of values of type <code>theWantedClass</code>.
*/
public <T> List<T> getValues(IBaseResource theResource, String thePath, Class<T> theWantedClass) { public <T> List<T> getValues(IBaseResource theResource, String thePath, Class<T> theWantedClass) {
RuntimeResourceDefinition def = myContext.getResourceDefinition(theResource); RuntimeResourceDefinition def = myContext.getResourceDefinition(theResource);
List<String> parts = parsePath(def, thePath); List<String> parts = parsePath(def, thePath);
return getValues(def, theResource, parts, theWantedClass); return getValues(def, theResource, parts, theWantedClass);
} }
/**
* Returns values stored in an element identified by its path. The list of values is of
* type <code>theWantedClass</code>.
*
* @param theResource The resource instance to be accessed. Must not be null.
* @param thePath The path for the element to be accessed.
* @param theWantedClass The desired class to be returned in a list.
* @param theCreate When set to <code>true</code>, the terser will create a null-valued element where none exists.
* @param <T> Type declared by <code>theWantedClass</code>
* @return A list of values of type <code>theWantedClass</code>.
*/
public <T> List<T> getValues(IBaseResource theResource, String thePath, Class<T> theWantedClass, boolean theCreate) {
RuntimeResourceDefinition def = myContext.getResourceDefinition(theResource);
List<String> parts = parsePath(def, thePath);
return getValues(def, theResource, parts, theWantedClass, theCreate, false);
}
/**
* Returns values stored in an element identified by its path. The list of values is of
* type <code>theWantedClass</code>.
*
* @param theResource The resource instance to be accessed. Must not be null.
* @param thePath The path for the element to be accessed.
* @param theWantedClass The desired class to be returned in a list.
* @param theCreate When set to <code>true</code>, the terser will create a null-valued element where none exists.
* @param theAddExtension When set to <code>true</code>, the terser will add a null-valued extension where one or more such extensions already exist.
* @param <T> Type declared by <code>theWantedClass</code>
* @return A list of values of type <code>theWantedClass</code>.
*/
public <T> List<T> getValues(IBaseResource theResource, String thePath, Class<T> theWantedClass, boolean theCreate, boolean theAddExtension) {
RuntimeResourceDefinition def = myContext.getResourceDefinition(theResource);
List<String> parts = parsePath(def, thePath);
return getValues(def, theResource, parts, theWantedClass, theCreate, theAddExtension);
}
private List<String> parsePath(BaseRuntimeElementCompositeDefinition<?> theElementDef, String thePath) { private List<String> parsePath(BaseRuntimeElementCompositeDefinition<?> theElementDef, String thePath) {
List<String> parts = new ArrayList<>(); List<String> parts = new ArrayList<>();

View File

@ -25,6 +25,7 @@ import ca.uhn.fhir.jpa.dao.data.IForcedIdDao;
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamUriDao; import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamUriDao;
import ca.uhn.fhir.jpa.dao.data.IResourceSearchViewDao; import ca.uhn.fhir.jpa.dao.data.IResourceSearchViewDao;
import ca.uhn.fhir.jpa.dao.data.IResourceTagDao; import ca.uhn.fhir.jpa.dao.data.IResourceTagDao;
import ca.uhn.fhir.jpa.dao.index.ResourceIndexedSearchParams;
import ca.uhn.fhir.jpa.entity.*; import ca.uhn.fhir.jpa.entity.*;
import ca.uhn.fhir.jpa.search.JpaRuntimeSearchParam; import ca.uhn.fhir.jpa.search.JpaRuntimeSearchParam;
import ca.uhn.fhir.jpa.term.IHapiTerminologySvc; import ca.uhn.fhir.jpa.term.IHapiTerminologySvc;
@ -1496,7 +1497,7 @@ public class SearchBuilder implements ISearchBuilder {
} }
} }
Set<String> uniqueQueryStrings = BaseHapiFhirDao.extractCompositeStringUniquesValueChains(myResourceName, params); Set<String> uniqueQueryStrings = ResourceIndexedSearchParams.extractCompositeStringUniquesValueChains(myResourceName, params);
if (ourTrackHandlersForUnitTest) { if (ourTrackHandlersForUnitTest) {
ourLastHandlerParamsForUnitTest = theParams; ourLastHandlerParamsForUnitTest = theParams;
ourLastHandlerMechanismForUnitTest = HandlerTypeEnum.UNIQUE_INDEX; ourLastHandlerMechanismForUnitTest = HandlerTypeEnum.UNIQUE_INDEX;

View File

@ -0,0 +1,33 @@
package ca.uhn.fhir.jpa.dao.index;
import java.util.Map;
import java.util.Set;
import javax.persistence.EntityManager;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.dao.ISearchParamExtractor;
import ca.uhn.fhir.jpa.dao.ISearchParamRegistry;
import ca.uhn.fhir.jpa.dao.data.IForcedIdDao;
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedCompositeStringUniqueDao;
public interface IndexingSupport {
public DaoConfig getConfig();
public ISearchParamExtractor getSearchParamExtractor();
public ISearchParamRegistry getSearchParamRegistry();
public FhirContext getContext();
public EntityManager getEntityManager();
public <R extends IBaseResource> IFhirResourceDao<R> getDao(Class<R> theType);
public Map<Class<? extends IBaseResource>, IFhirResourceDao<?>> getResourceTypeToDao();
public boolean isLogicalReference(IIdType nextId);
public IForcedIdDao getForcedIdDao();
public <R extends IBaseResource> Set<Long> processMatchUrl(String theMatchUrl, Class<R> theResourceType);
public Long translateForcedIdToPid(String theResourceName, String theResourceId);
public String toResourceName(Class<? extends IBaseResource> theResourceType);
public IResourceIndexedCompositeStringUniqueDao getResourceIndexedCompositeStringUniqueDao();
}

View File

@ -0,0 +1,852 @@
package ca.uhn.fhir.jpa.dao.index;
import static org.apache.commons.lang3.StringUtils.compare;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import javax.persistence.EntityManager;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseBundle;
import org.hl7.fhir.instance.model.api.IBaseExtension;
import org.hl7.fhir.instance.model.api.IBaseReference;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r4.model.CanonicalType;
import org.hl7.fhir.r4.model.Reference;
import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.context.RuntimeSearchParam;
import ca.uhn.fhir.jpa.dao.BaseHapiFhirDao;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.dao.PathAndRef;
import ca.uhn.fhir.jpa.entity.BaseResourceIndexedSearchParam;
import ca.uhn.fhir.jpa.entity.ForcedId;
import ca.uhn.fhir.jpa.entity.ResourceIndexedCompositeStringUnique;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamCoords;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamDate;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamNumber;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamQuantity;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamString;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamToken;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamUri;
import ca.uhn.fhir.jpa.entity.ResourceLink;
import ca.uhn.fhir.jpa.entity.ResourceTable;
import ca.uhn.fhir.jpa.search.JpaRuntimeSearchParam;
import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import ca.uhn.fhir.util.FhirTerser;
import ca.uhn.fhir.util.UrlUtil;
public class ResourceIndexedSearchParams {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ResourceIndexedSearchParams.class);
// FIXME rename
private final IndexingSupport myIndexingService;
private final Collection<ResourceIndexedSearchParamString> stringParams;
private final Collection<ResourceIndexedSearchParamToken> tokenParams;
private final Collection<ResourceIndexedSearchParamNumber> numberParams;
private final Collection<ResourceIndexedSearchParamQuantity> quantityParams;
private final Collection<ResourceIndexedSearchParamDate> dateParams;
private final Collection<ResourceIndexedSearchParamUri> uriParams;
private final Collection<ResourceIndexedSearchParamCoords> coordsParams;
private final Collection<ResourceIndexedCompositeStringUnique> compositeStringUniques;
private final Collection<ResourceLink> links;
private Set<String> populatedResourceLinkParameters = Collections.emptySet();
public ResourceIndexedSearchParams(IndexingSupport indexingService, ResourceTable theEntity) {
this.myIndexingService = indexingService;
stringParams = new ArrayList<>();
if (theEntity.isParamsStringPopulated()) {
stringParams.addAll(theEntity.getParamsString());
}
tokenParams = new ArrayList<>();
if (theEntity.isParamsTokenPopulated()) {
tokenParams.addAll(theEntity.getParamsToken());
}
numberParams = new ArrayList<>();
if (theEntity.isParamsNumberPopulated()) {
numberParams.addAll(theEntity.getParamsNumber());
}
quantityParams = new ArrayList<>();
if (theEntity.isParamsQuantityPopulated()) {
quantityParams.addAll(theEntity.getParamsQuantity());
}
dateParams = new ArrayList<>();
if (theEntity.isParamsDatePopulated()) {
dateParams.addAll(theEntity.getParamsDate());
}
uriParams = new ArrayList<>();
if (theEntity.isParamsUriPopulated()) {
uriParams.addAll(theEntity.getParamsUri());
}
coordsParams = new ArrayList<>();
if (theEntity.isParamsCoordsPopulated()) {
coordsParams.addAll(theEntity.getParamsCoords());
}
links = new ArrayList<>();
if (theEntity.isHasLinks()) {
links.addAll(theEntity.getResourceLinks());
}
compositeStringUniques = new ArrayList<>();
if (theEntity.isParamsCompositeStringUniquePresent()) {
compositeStringUniques.addAll(theEntity.getParamsCompositeStringUnique());
}
}
public ResourceIndexedSearchParams(IndexingSupport indexingService) {
this.myIndexingService = indexingService;
stringParams = Collections.emptySet();
tokenParams = Collections.emptySet();
numberParams = Collections.emptySet();
quantityParams = Collections.emptySet();
dateParams = Collections.emptySet();
uriParams = Collections.emptySet();
coordsParams = Collections.emptySet();
links = Collections.emptySet();
compositeStringUniques = Collections.emptySet();
}
public ResourceIndexedSearchParams(IndexingSupport indexingService, Date theUpdateTime, ResourceTable theEntity, IBaseResource theResource, ResourceIndexedSearchParams existingParams) {
this.myIndexingService = indexingService;
stringParams = extractSearchParamStrings(theEntity, theResource);
numberParams = extractSearchParamNumber(theEntity, theResource);
quantityParams = extractSearchParamQuantity(theEntity, theResource);
dateParams = extractSearchParamDates(theEntity, theResource);
uriParams = extractSearchParamUri(theEntity, theResource);
coordsParams = extractSearchParamCoords(theEntity, theResource);
ourLog.trace("Storing date indexes: {}", dateParams);
tokenParams = new HashSet<>();
for (BaseResourceIndexedSearchParam next : extractSearchParamTokens(theEntity, theResource)) {
if (next instanceof ResourceIndexedSearchParamToken) {
tokenParams.add((ResourceIndexedSearchParamToken) next);
} else {
stringParams.add((ResourceIndexedSearchParamString) next);
}
}
Set<Entry<String, RuntimeSearchParam>> activeSearchParams = myIndexingService.getSearchParamRegistry().getActiveSearchParams(theEntity.getResourceType()).entrySet();
DaoConfig myConfig = indexingService.getConfig();
if (myConfig .getIndexMissingFields() == DaoConfig.IndexEnabledEnum.ENABLED) {
findMissingSearchParams(theEntity, activeSearchParams, RestSearchParameterTypeEnum.STRING, stringParams);
findMissingSearchParams(theEntity, activeSearchParams, RestSearchParameterTypeEnum.NUMBER, numberParams);
findMissingSearchParams(theEntity, activeSearchParams, RestSearchParameterTypeEnum.QUANTITY, quantityParams);
findMissingSearchParams(theEntity, activeSearchParams, RestSearchParameterTypeEnum.DATE, dateParams);
findMissingSearchParams(theEntity, activeSearchParams, RestSearchParameterTypeEnum.URI, uriParams);
findMissingSearchParams(theEntity, activeSearchParams, RestSearchParameterTypeEnum.TOKEN, tokenParams);
}
setUpdatedTime(stringParams, theUpdateTime);
setUpdatedTime(numberParams, theUpdateTime);
setUpdatedTime(quantityParams, theUpdateTime);
setUpdatedTime(dateParams, theUpdateTime);
setUpdatedTime(uriParams, theUpdateTime);
setUpdatedTime(coordsParams, theUpdateTime);
setUpdatedTime(tokenParams, theUpdateTime);
/*
* Handle references within the resource that are match URLs, for example references like "Patient?identifier=foo". These match URLs are resolved and replaced with the ID of the
* matching resource.
*/
if (myConfig.isAllowInlineMatchUrlReferences()) {
FhirTerser terser = myIndexingService.getContext().newTerser();
List<IBaseReference> allRefs = terser.getAllPopulatedChildElementsOfType(theResource, IBaseReference.class);
for (IBaseReference nextRef : allRefs) {
IIdType nextId = nextRef.getReferenceElement();
String nextIdText = nextId.getValue();
if (nextIdText == null) {
continue;
}
int qmIndex = nextIdText.indexOf('?');
if (qmIndex != -1) {
for (int i = qmIndex - 1; i >= 0; i--) {
if (nextIdText.charAt(i) == '/') {
if (i < nextIdText.length() - 1 && nextIdText.charAt(i + 1) == '?') {
// Just in case the URL is in the form Patient/?foo=bar
continue;
}
nextIdText = nextIdText.substring(i + 1);
break;
}
}
String resourceTypeString = nextIdText.substring(0, nextIdText.indexOf('?')).replace("/", "");
RuntimeResourceDefinition matchResourceDef = myIndexingService.getContext().getResourceDefinition(resourceTypeString);
if (matchResourceDef == null) {
String msg = myIndexingService.getContext().getLocalizer().getMessage(BaseHapiFhirDao.class, "invalidMatchUrlInvalidResourceType", nextId.getValue(), resourceTypeString);
throw new InvalidRequestException(msg);
}
Class<? extends IBaseResource> matchResourceType = matchResourceDef.getImplementingClass();
Set<Long> matches = myIndexingService.processMatchUrl(nextIdText, matchResourceType);
if (matches.isEmpty()) {
String msg = indexingService.getContext().getLocalizer().getMessage(BaseHapiFhirDao.class, "invalidMatchUrlNoMatches", nextId.getValue());
throw new ResourceNotFoundException(msg);
}
if (matches.size() > 1) {
String msg = indexingService.getContext().getLocalizer().getMessage(BaseHapiFhirDao.class, "invalidMatchUrlMultipleMatches", nextId.getValue());
throw new PreconditionFailedException(msg);
}
Long next = matches.iterator().next();
String newId = translatePidIdToForcedId(resourceTypeString, next);
ourLog.debug("Replacing inline match URL[{}] with ID[{}}", nextId.getValue(), newId);
nextRef.setReference(newId);
}
}
}
links = new HashSet<>();
populatedResourceLinkParameters = extractResourceLinks(theEntity, theResource, links, theUpdateTime);
/*
* If the existing resource already has links and those match links we still want, use them instead of removing them and re adding them
*/
for (Iterator<ResourceLink> existingLinkIter = existingParams.getResourceLinks().iterator(); existingLinkIter.hasNext(); ) {
ResourceLink nextExisting = existingLinkIter.next();
if (links.remove(nextExisting)) {
existingLinkIter.remove();
links.add(nextExisting);
}
}
/*
* Handle composites
*/
compositeStringUniques = extractCompositeStringUniques(theEntity, stringParams, tokenParams, numberParams, quantityParams, dateParams, uriParams, links);
}
public Collection<ResourceLink> getResourceLinks() {
return links;
}
protected Set<ResourceIndexedSearchParamCoords> extractSearchParamCoords(ResourceTable theEntity, IBaseResource theResource) {
return myIndexingService.getSearchParamExtractor().extractSearchParamCoords(theEntity, theResource);
}
protected Set<ResourceIndexedSearchParamDate> extractSearchParamDates(ResourceTable theEntity, IBaseResource theResource) {
return myIndexingService.getSearchParamExtractor().extractSearchParamDates(theEntity, theResource);
}
protected Set<ResourceIndexedSearchParamNumber> extractSearchParamNumber(ResourceTable theEntity, IBaseResource theResource) {
return myIndexingService.getSearchParamExtractor().extractSearchParamNumber(theEntity, theResource);
}
protected Set<ResourceIndexedSearchParamQuantity> extractSearchParamQuantity(ResourceTable theEntity, IBaseResource theResource) {
return myIndexingService.getSearchParamExtractor().extractSearchParamQuantity(theEntity, theResource);
}
protected Set<ResourceIndexedSearchParamString> extractSearchParamStrings(ResourceTable theEntity, IBaseResource theResource) {
return myIndexingService.getSearchParamExtractor().extractSearchParamStrings(theEntity, theResource);
}
protected Set<BaseResourceIndexedSearchParam> extractSearchParamTokens(ResourceTable theEntity, IBaseResource theResource) {
return myIndexingService.getSearchParamExtractor().extractSearchParamTokens(theEntity, theResource);
}
protected Set<ResourceIndexedSearchParamUri> extractSearchParamUri(ResourceTable theEntity, IBaseResource theResource) {
return myIndexingService.getSearchParamExtractor().extractSearchParamUri(theEntity, theResource);
}
@SuppressWarnings("unchecked")
private <RT extends BaseResourceIndexedSearchParam> void findMissingSearchParams(ResourceTable theEntity, Set<Entry<String, RuntimeSearchParam>> activeSearchParams, RestSearchParameterTypeEnum type,
Collection<RT> paramCollection) {
for (Entry<String, RuntimeSearchParam> nextEntry : activeSearchParams) {
String nextParamName = nextEntry.getKey();
if (nextEntry.getValue().getParamType() == type) {
boolean haveParam = false;
for (BaseResourceIndexedSearchParam nextParam : paramCollection) {
if (nextParam.getParamName().equals(nextParamName)) {
haveParam = true;
break;
}
}
if (!haveParam) {
BaseResourceIndexedSearchParam param;
switch (type) {
case DATE:
param = new ResourceIndexedSearchParamDate();
break;
case NUMBER:
param = new ResourceIndexedSearchParamNumber();
break;
case QUANTITY:
param = new ResourceIndexedSearchParamQuantity();
break;
case STRING:
param = new ResourceIndexedSearchParamString()
.setDaoConfig(myIndexingService.getConfig());
break;
case TOKEN:
param = new ResourceIndexedSearchParamToken();
break;
case URI:
param = new ResourceIndexedSearchParamUri();
break;
case COMPOSITE:
case HAS:
case REFERENCE:
default:
continue;
}
param.setResource(theEntity);
param.setMissing(true);
param.setParamName(nextParamName);
paramCollection.add((RT) param);
}
}
}
}
public void setParams(ResourceTable theEntity) {
theEntity.setParamsString(stringParams);
theEntity.setParamsStringPopulated(stringParams.isEmpty() == false);
theEntity.setParamsToken(tokenParams);
theEntity.setParamsTokenPopulated(tokenParams.isEmpty() == false);
theEntity.setParamsNumber(numberParams);
theEntity.setParamsNumberPopulated(numberParams.isEmpty() == false);
theEntity.setParamsQuantity(quantityParams);
theEntity.setParamsQuantityPopulated(quantityParams.isEmpty() == false);
theEntity.setParamsDate(dateParams);
theEntity.setParamsDatePopulated(dateParams.isEmpty() == false);
theEntity.setParamsUri(uriParams);
theEntity.setParamsUriPopulated(uriParams.isEmpty() == false);
theEntity.setParamsCoords(coordsParams);
theEntity.setParamsCoordsPopulated(coordsParams.isEmpty() == false);
theEntity.setParamsCompositeStringUniquePresent(compositeStringUniques.isEmpty() == false);
theEntity.setResourceLinks(links);
theEntity.setHasLinks(links.isEmpty() == false);
}
private Set<ResourceIndexedCompositeStringUnique> extractCompositeStringUniques(ResourceTable theEntity, Collection<ResourceIndexedSearchParamString> theStringParams, Collection<ResourceIndexedSearchParamToken> theTokenParams, Collection<ResourceIndexedSearchParamNumber> theNumberParams, Collection<ResourceIndexedSearchParamQuantity> theQuantityParams, Collection<ResourceIndexedSearchParamDate> theDateParams, Collection<ResourceIndexedSearchParamUri> theUriParams, Collection<ResourceLink> theLinks) {
Set<ResourceIndexedCompositeStringUnique> compositeStringUniques;
compositeStringUniques = new HashSet<>();
List<JpaRuntimeSearchParam> uniqueSearchParams = myIndexingService.getSearchParamRegistry().getActiveUniqueSearchParams(theEntity.getResourceType());
for (JpaRuntimeSearchParam next : uniqueSearchParams) {
List<List<String>> partsChoices = new ArrayList<>();
for (RuntimeSearchParam nextCompositeOf : next.getCompositeOf()) {
Collection<? extends BaseResourceIndexedSearchParam> paramsListForCompositePart = null;
Collection<ResourceLink> linksForCompositePart = null;
Collection<String> linksForCompositePartWantPaths = null;
switch (nextCompositeOf.getParamType()) {
case NUMBER:
paramsListForCompositePart = theNumberParams;
break;
case DATE:
paramsListForCompositePart = theDateParams;
break;
case STRING:
paramsListForCompositePart = theStringParams;
break;
case TOKEN:
paramsListForCompositePart = theTokenParams;
break;
case REFERENCE:
linksForCompositePart = theLinks;
linksForCompositePartWantPaths = new HashSet<>();
linksForCompositePartWantPaths.addAll(nextCompositeOf.getPathsSplit());
break;
case QUANTITY:
paramsListForCompositePart = theQuantityParams;
break;
case URI:
paramsListForCompositePart = theUriParams;
break;
case COMPOSITE:
case HAS:
break;
}
ArrayList<String> nextChoicesList = new ArrayList<>();
partsChoices.add(nextChoicesList);
String key = UrlUtil.escapeUrlParam(nextCompositeOf.getName());
if (paramsListForCompositePart != null) {
for (BaseResourceIndexedSearchParam nextParam : paramsListForCompositePart) {
if (nextParam.getParamName().equals(nextCompositeOf.getName())) {
IQueryParameterType nextParamAsClientParam = nextParam.toQueryParameterType();
String value = nextParamAsClientParam.getValueAsQueryToken(myIndexingService.getContext());
if (isNotBlank(value)) {
value = UrlUtil.escapeUrlParam(value);
nextChoicesList.add(key + "=" + value);
}
}
}
}
if (linksForCompositePart != null) {
for (ResourceLink nextLink : linksForCompositePart) {
if (linksForCompositePartWantPaths.contains(nextLink.getSourcePath())) {
String value = nextLink.getTargetResource().getIdDt().toUnqualifiedVersionless().getValue();
if (isNotBlank(value)) {
value = UrlUtil.escapeUrlParam(value);
nextChoicesList.add(key + "=" + value);
}
}
}
}
}
Set<String> queryStringsToPopulate = extractCompositeStringUniquesValueChains(theEntity.getResourceType(), partsChoices);
for (String nextQueryString : queryStringsToPopulate) {
if (isNotBlank(nextQueryString)) {
compositeStringUniques.add(new ResourceIndexedCompositeStringUnique(theEntity, nextQueryString));
}
}
}
return compositeStringUniques;
}
/**
* This method is used to create a set of all possible combinations of
* parameters across a set of search parameters. An example of why
* this is needed:
* <p>
* Let's say we have a unique index on (Patient:gender AND Patient:name).
* Then we pass in <code>SMITH, John</code> with a gender of <code>male</code>.
* </p>
* <p>
* In this case, because the name parameter matches both first and last name,
* we now need two unique indexes:
* <ul>
* <li>Patient?gender=male&amp;name=SMITH</li>
* <li>Patient?gender=male&amp;name=JOHN</li>
* </ul>
* </p>
* <p>
* So this recursive algorithm calculates those
* </p>
*
* @param theResourceType E.g. <code>Patient
* @param thePartsChoices E.g. <code>[[gender=male], [name=SMITH, name=JOHN]]</code>
*/
public static Set<String> extractCompositeStringUniquesValueChains(String
theResourceType, List<List<String>> thePartsChoices) {
for (List<String> next : thePartsChoices) {
next.removeIf(StringUtils::isBlank);
if (next.isEmpty()) {
return Collections.emptySet();
}
}
if (thePartsChoices.isEmpty()) {
return Collections.emptySet();
}
thePartsChoices.sort((o1, o2) -> {
String str1 = null;
String str2 = null;
if (o1.size() > 0) {
str1 = o1.get(0);
}
if (o2.size() > 0) {
str2 = o2.get(0);
}
return compare(str1, str2);
});
List<String> values = new ArrayList<>();
Set<String> queryStringsToPopulate = new HashSet<>();
extractCompositeStringUniquesValueChains(theResourceType, thePartsChoices, values, queryStringsToPopulate);
return queryStringsToPopulate;
}
private static void extractCompositeStringUniquesValueChains(String
theResourceType, List<List<String>> thePartsChoices, List<String> theValues, Set<String> theQueryStringsToPopulate) {
if (thePartsChoices.size() > 0) {
List<String> nextList = thePartsChoices.get(0);
Collections.sort(nextList);
for (String nextChoice : nextList) {
theValues.add(nextChoice);
extractCompositeStringUniquesValueChains(theResourceType, thePartsChoices.subList(1, thePartsChoices.size()), theValues, theQueryStringsToPopulate);
theValues.remove(theValues.size() - 1);
}
} else {
if (theValues.size() > 0) {
StringBuilder uniqueString = new StringBuilder();
uniqueString.append(theResourceType);
for (int i = 0; i < theValues.size(); i++) {
uniqueString.append(i == 0 ? "?" : "&");
uniqueString.append(theValues.get(i));
}
theQueryStringsToPopulate.add(uniqueString.toString());
}
}
}
/**
* @return Returns a set containing all of the parameter names that
* were found to have a value
*/
@SuppressWarnings("unchecked")
protected Set<String> extractResourceLinks(ResourceTable theEntity, IBaseResource theResource, Collection<ResourceLink> theLinks, Date theUpdateTime) {
HashSet<String> retVal = new HashSet<>();
String resourceType = theEntity.getResourceType();
/*
* For now we don't try to load any of the links in a bundle if it's the actual bundle we're storing..
*/
if (theResource instanceof IBaseBundle) {
return Collections.emptySet();
}
Map<String, RuntimeSearchParam> searchParams = myIndexingService.getSearchParamRegistry().getActiveSearchParams(myIndexingService.toResourceName(theResource.getClass()));
for (RuntimeSearchParam nextSpDef : searchParams.values()) {
if (nextSpDef.getParamType() != RestSearchParameterTypeEnum.REFERENCE) {
continue;
}
String nextPathsUnsplit = nextSpDef.getPath();
if (isBlank(nextPathsUnsplit)) {
continue;
}
boolean multiType = false;
if (nextPathsUnsplit.endsWith("[x]")) {
multiType = true;
}
List<PathAndRef> refs = myIndexingService.getSearchParamExtractor().extractResourceLinks(theResource, nextSpDef);
for (PathAndRef nextPathAndRef : refs) {
Object nextObject = nextPathAndRef.getRef();
/*
* A search parameter on an extension field that contains
* references should index those references
*/
if (nextObject instanceof IBaseExtension<?, ?>) {
nextObject = ((IBaseExtension<?, ?>) nextObject).getValue();
}
if (nextObject instanceof CanonicalType) {
nextObject = new Reference(((CanonicalType) nextObject).getValueAsString());
}
IIdType nextId;
if (nextObject instanceof IBaseReference) {
IBaseReference nextValue = (IBaseReference) nextObject;
if (nextValue.isEmpty()) {
continue;
}
nextId = nextValue.getReferenceElement();
/*
* This can only really happen if the DAO is being called
* programatically with a Bundle (not through the FHIR REST API)
* but Smile does this
*/
if (nextId.isEmpty() && nextValue.getResource() != null) {
nextId = nextValue.getResource().getIdElement();
}
if (nextId.isEmpty() || nextId.getValue().startsWith("#")) {
// This is a blank or contained resource reference
continue;
}
} else if (nextObject instanceof IBaseResource) {
nextId = ((IBaseResource) nextObject).getIdElement();
if (nextId == null || nextId.hasIdPart() == false) {
continue;
}
} else if (myIndexingService.getContext().getElementDefinition((Class<? extends IBase>) nextObject.getClass()).getName().equals("uri")) {
continue;
} else if (resourceType.equals("Consent") && nextPathAndRef.getPath().equals("Consent.source")) {
// Consent#source-identifier has a path that isn't typed - This is a one-off to deal with that
continue;
} else {
if (!multiType) {
if (nextSpDef.getName().equals("sourceuri")) {
continue; // TODO: disable this eventually - ConceptMap:sourceuri is of type reference but points to a URI
}
throw new ConfigurationException("Search param " + nextSpDef.getName() + " is of unexpected datatype: " + nextObject.getClass());
} else {
continue;
}
}
retVal.add(nextSpDef.getName());
if (myIndexingService.isLogicalReference(nextId)) {
ResourceLink resourceLink = new ResourceLink(nextPathAndRef.getPath(), theEntity, nextId, theUpdateTime);
if (theLinks.add(resourceLink)) {
ourLog.debug("Indexing remote resource reference URL: {}", nextId);
}
continue;
}
String baseUrl = nextId.getBaseUrl();
String typeString = nextId.getResourceType();
if (isBlank(typeString)) {
throw new InvalidRequestException("Invalid resource reference found at path[" + nextPathsUnsplit + "] - Does not contain resource type - " + nextId.getValue());
}
RuntimeResourceDefinition resourceDefinition;
try {
resourceDefinition = myIndexingService.getContext().getResourceDefinition(typeString);
} catch (DataFormatException e) {
throw new InvalidRequestException(
"Invalid resource reference found at path[" + nextPathsUnsplit + "] - Resource type is unknown or not supported on this server - " + nextId.getValue());
}
if (isNotBlank(baseUrl)) {
if (!myIndexingService.getConfig().getTreatBaseUrlsAsLocal().contains(baseUrl) && !myIndexingService.getConfig().isAllowExternalReferences()) {
String msg = myIndexingService.getContext().getLocalizer().getMessage(BaseHapiFhirDao.class, "externalReferenceNotAllowed", nextId.getValue());
throw new InvalidRequestException(msg);
} else {
ResourceLink resourceLink = new ResourceLink(nextPathAndRef.getPath(), theEntity, nextId, theUpdateTime);
if (theLinks.add(resourceLink)) {
ourLog.debug("Indexing remote resource reference URL: {}", nextId);
}
continue;
}
}
Class<? extends IBaseResource> type = resourceDefinition.getImplementingClass();
String id = nextId.getIdPart();
if (StringUtils.isBlank(id)) {
throw new InvalidRequestException("Invalid resource reference found at path[" + nextPathsUnsplit + "] - Does not contain resource ID - " + nextId.getValue());
}
IFhirResourceDao<?> dao = myIndexingService.getDao(type);
if (dao == null) {
StringBuilder b = new StringBuilder();
b.append("This server (version ");
b.append(myIndexingService.getContext().getVersion().getVersion());
b.append(") is not able to handle resources of type[");
b.append(nextId.getResourceType());
b.append("] - Valid resource types for this server: ");
b.append(myIndexingService.getResourceTypeToDao().keySet().toString());
throw new InvalidRequestException(b.toString());
}
Long valueOf;
try {
valueOf = myIndexingService.translateForcedIdToPid(typeString, id);
} catch (ResourceNotFoundException e) {
if (myIndexingService.getConfig().isEnforceReferentialIntegrityOnWrite() == false) {
continue;
}
RuntimeResourceDefinition missingResourceDef = myIndexingService.getContext().getResourceDefinition(type);
String resName = missingResourceDef.getName();
if (myIndexingService.getConfig().isAutoCreatePlaceholderReferenceTargets()) {
IBaseResource newResource = missingResourceDef.newInstance();
newResource.setId(resName + "/" + id);
IFhirResourceDao<IBaseResource> placeholderResourceDao = (IFhirResourceDao<IBaseResource>) myIndexingService.getDao(newResource.getClass());
ourLog.debug("Automatically creating empty placeholder resource: {}", newResource.getIdElement().getValue());
valueOf = placeholderResourceDao.update(newResource).getEntity().getId();
} else {
throw new InvalidRequestException("Resource " + resName + "/" + id + " not found, specified in path: " + nextPathsUnsplit);
}
}
ResourceTable target = myIndexingService.getEntityManager().find(ResourceTable.class, valueOf);
RuntimeResourceDefinition targetResourceDef = myIndexingService.getContext().getResourceDefinition(type);
if (target == null) {
String resName = targetResourceDef.getName();
throw new InvalidRequestException("Resource " + resName + "/" + id + " not found, specified in path: " + nextPathsUnsplit);
}
if (!typeString.equals(target.getResourceType())) {
throw new UnprocessableEntityException(
"Resource contains reference to " + nextId.getValue() + " but resource with ID " + nextId.getIdPart() + " is actually of type " + target.getResourceType());
}
if (target.getDeleted() != null) {
String resName = targetResourceDef.getName();
throw new InvalidRequestException("Resource " + resName + "/" + id + " is deleted, specified in path: " + nextPathsUnsplit);
}
if (nextSpDef.getTargets() != null && !nextSpDef.getTargets().contains(typeString)) {
continue;
}
ResourceLink resourceLink = new ResourceLink(nextPathAndRef.getPath(), theEntity, target, theUpdateTime);
theLinks.add(resourceLink);
}
}
theEntity.setHasLinks(theLinks.size() > 0);
return retVal;
}
private void setUpdatedTime(Collection<? extends BaseResourceIndexedSearchParam> theParams, Date theUpdateTime) {
for (BaseResourceIndexedSearchParam nextSearchParam : theParams) {
nextSearchParam.setUpdated(theUpdateTime);
}
}
private String translatePidIdToForcedId(String theResourceType, Long theId) {
ForcedId forcedId = myIndexingService.getForcedIdDao().findByResourcePid(theId);
if (forcedId != null) {
return forcedId.getResourceType() + '/' + forcedId.getForcedId();
} else {
return theResourceType + '/' + theId.toString();
}
}
public void removeCommon(ResourceTable theEntity, ResourceIndexedSearchParams existingParams) {
EntityManager myEntityManager = myIndexingService.getEntityManager();
calculateHashes(stringParams);
for (ResourceIndexedSearchParamString next : removeCommon(existingParams.stringParams, stringParams)) {
next.setDaoConfig(myIndexingService.getConfig());
myEntityManager .remove(next);
theEntity.getParamsString().remove(next);
}
for (ResourceIndexedSearchParamString next : removeCommon(stringParams, existingParams.stringParams)) {
myEntityManager.persist(next);
}
calculateHashes(tokenParams);
for (ResourceIndexedSearchParamToken next : removeCommon(existingParams.tokenParams, tokenParams)) {
myEntityManager.remove(next);
theEntity.getParamsToken().remove(next);
}
for (ResourceIndexedSearchParamToken next : removeCommon(tokenParams, existingParams.tokenParams)) {
myEntityManager.persist(next);
}
calculateHashes(numberParams);
for (ResourceIndexedSearchParamNumber next : removeCommon(existingParams.numberParams, numberParams)) {
myEntityManager.remove(next);
theEntity.getParamsNumber().remove(next);
}
for (ResourceIndexedSearchParamNumber next : removeCommon(numberParams, existingParams.numberParams)) {
myEntityManager.persist(next);
}
calculateHashes(quantityParams);
for (ResourceIndexedSearchParamQuantity next : removeCommon(existingParams.quantityParams, quantityParams)) {
myEntityManager.remove(next);
theEntity.getParamsQuantity().remove(next);
}
for (ResourceIndexedSearchParamQuantity next : removeCommon(quantityParams, existingParams.quantityParams)) {
myEntityManager.persist(next);
}
// Store date SP's
calculateHashes(dateParams);
for (ResourceIndexedSearchParamDate next : removeCommon(existingParams.dateParams, dateParams)) {
myEntityManager.remove(next);
theEntity.getParamsDate().remove(next);
}
for (ResourceIndexedSearchParamDate next : removeCommon(dateParams, existingParams.dateParams)) {
myEntityManager.persist(next);
}
// Store URI SP's
calculateHashes(uriParams);
for (ResourceIndexedSearchParamUri next : removeCommon(existingParams.uriParams, uriParams)) {
myEntityManager.remove(next);
theEntity.getParamsUri().remove(next);
}
for (ResourceIndexedSearchParamUri next : removeCommon(uriParams, existingParams.uriParams)) {
myEntityManager.persist(next);
}
// Store Coords SP's
calculateHashes(coordsParams);
for (ResourceIndexedSearchParamCoords next : removeCommon(existingParams.coordsParams, coordsParams)) {
myEntityManager.remove(next);
theEntity.getParamsCoords().remove(next);
}
for (ResourceIndexedSearchParamCoords next : removeCommon(coordsParams, existingParams.coordsParams)) {
myEntityManager.persist(next);
}
// Store resource links
for (ResourceLink next : removeCommon(existingParams.links, links)) {
myEntityManager.remove(next);
theEntity.getResourceLinks().remove(next);
}
for (ResourceLink next : removeCommon(links, existingParams.links)) {
myEntityManager.persist(next);
}
// make sure links are indexed
theEntity.setResourceLinks(links);
// Store composite string uniques
if (myIndexingService.getConfig().isUniqueIndexesEnabled()) {
for (ResourceIndexedCompositeStringUnique next : removeCommon(existingParams.compositeStringUniques, compositeStringUniques)) {
ourLog.debug("Removing unique index: {}", next);
myEntityManager.remove(next);
theEntity.getParamsCompositeStringUnique().remove(next);
}
for (ResourceIndexedCompositeStringUnique next : removeCommon(compositeStringUniques, existingParams.compositeStringUniques)) {
if (myIndexingService.getConfig().isUniqueIndexesCheckedBeforeSave()) {
ResourceIndexedCompositeStringUnique existing = myIndexingService.getResourceIndexedCompositeStringUniqueDao().findByQueryString(next.getIndexString());
if (existing != null) {
String msg = myIndexingService.getContext().getLocalizer().getMessage(BaseHapiFhirDao.class, "uniqueIndexConflictFailure", theEntity.getResourceType(), next.getIndexString(), existing.getResource().getIdDt().toUnqualifiedVersionless().getValue());
throw new PreconditionFailedException(msg);
}
}
ourLog.debug("Persisting unique index: {}", next);
myEntityManager.persist(next);
}
}
}
private void calculateHashes(Collection<? extends BaseResourceIndexedSearchParam> theStringParams) {
for (BaseResourceIndexedSearchParam next : theStringParams) {
next.calculateHashes();
}
}
private <T> Collection<T> removeCommon(Collection<T> theInput, Collection<T> theToRemove) {
assert theInput != theToRemove;
if (theInput.isEmpty()) {
return theInput;
}
ArrayList<T> retVal = new ArrayList<>(theInput);
retVal.removeAll(theToRemove);
return retVal;
}
public Set<String> getPopulatedResourceLinkParameters() {
return populatedResourceLinkParameters;
}
}

View File

@ -27,6 +27,8 @@ import ca.uhn.fhir.jpa.config.BaseConfig;
import ca.uhn.fhir.jpa.dao.IFhirResourceDao; import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.dao.SearchParameterMap; import ca.uhn.fhir.jpa.dao.SearchParameterMap;
import ca.uhn.fhir.jpa.provider.ServletSubRequestDetails; import ca.uhn.fhir.jpa.provider.ServletSubRequestDetails;
import ca.uhn.fhir.jpa.subscription.matcher.ISubscriptionMatcher;
import ca.uhn.fhir.jpa.subscription.matcher.SubscriptionMatcherDatabase;
import ca.uhn.fhir.jpa.util.JpaConstants; import ca.uhn.fhir.jpa.util.JpaConstants;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum; import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.api.server.IBundleProvider; import ca.uhn.fhir.rest.api.server.IBundleProvider;
@ -284,6 +286,7 @@ public abstract class BaseSubscriptionInterceptor<S extends IBaseResource> exten
public abstract Subscription.SubscriptionChannelType getChannelType(); public abstract Subscription.SubscriptionChannelType getChannelType();
// TODO KHS move out
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <R extends IBaseResource> IFhirResourceDao<R> getDao(Class<R> theType) { public <R extends IBaseResource> IFhirResourceDao<R> getDao(Class<R> theType) {
if (myResourceTypeToDao == null) { if (myResourceTypeToDao == null) {
@ -433,7 +436,8 @@ public abstract class BaseSubscriptionInterceptor<S extends IBaseResource> exten
protected void registerSubscriptionCheckingSubscriber() { protected void registerSubscriptionCheckingSubscriber() {
if (mySubscriptionCheckingSubscriber == null) { if (mySubscriptionCheckingSubscriber == null) {
mySubscriptionCheckingSubscriber = new SubscriptionCheckingSubscriber(getSubscriptionDao(), getChannelType(), this); ISubscriptionMatcher subscriptionMatcher = new SubscriptionMatcherDatabase(getSubscriptionDao(), this);
mySubscriptionCheckingSubscriber = new SubscriptionCheckingSubscriber(getSubscriptionDao(), getChannelType(), this, subscriptionMatcher );
} }
getProcessingChannel().subscribe(mySubscriptionCheckingSubscriber); getProcessingChannel().subscribe(mySubscriptionCheckingSubscriber);
} }

View File

@ -1,5 +1,17 @@
package ca.uhn.fhir.jpa.subscription; package ca.uhn.fhir.jpa.subscription;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r4.model.Subscription;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessagingException;
/*- /*-
* #%L * #%L
* HAPI FHIR JPA Server * HAPI FHIR JPA Server
@ -25,27 +37,20 @@ import ca.uhn.fhir.jpa.dao.BaseHapiFhirDao;
import ca.uhn.fhir.jpa.dao.IFhirResourceDao; import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.dao.SearchParameterMap; import ca.uhn.fhir.jpa.dao.SearchParameterMap;
import ca.uhn.fhir.jpa.provider.ServletSubRequestDetails; import ca.uhn.fhir.jpa.provider.ServletSubRequestDetails;
import ca.uhn.fhir.jpa.subscription.matcher.ISubscriptionMatcher;
import ca.uhn.fhir.rest.api.server.IBundleProvider; import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.api.server.RequestDetails;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r4.model.Subscription;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessagingException;
import java.util.List;
import static org.apache.commons.lang3.StringUtils.isNotBlank; import static org.apache.commons.lang3.StringUtils.isNotBlank;
public class SubscriptionCheckingSubscriber extends BaseSubscriptionSubscriber { public class SubscriptionCheckingSubscriber extends BaseSubscriptionSubscriber {
private Logger ourLog = LoggerFactory.getLogger(SubscriptionCheckingSubscriber.class); private Logger ourLog = LoggerFactory.getLogger(SubscriptionCheckingSubscriber.class);
public SubscriptionCheckingSubscriber(IFhirResourceDao theSubscriptionDao, Subscription.SubscriptionChannelType theChannelType, BaseSubscriptionInterceptor theSubscriptionInterceptor) { private final ISubscriptionMatcher mySubscriptionMatcher;
public SubscriptionCheckingSubscriber(IFhirResourceDao theSubscriptionDao, Subscription.SubscriptionChannelType theChannelType, BaseSubscriptionInterceptor theSubscriptionInterceptor, ISubscriptionMatcher theSubscriptionMatcher) {
super(theSubscriptionDao, theChannelType, theSubscriptionInterceptor); super(theSubscriptionDao, theChannelType, theSubscriptionInterceptor);
this.mySubscriptionMatcher = theSubscriptionMatcher;
} }
@Override @Override
@ -107,16 +112,7 @@ public class SubscriptionCheckingSubscriber extends BaseSubscriptionSubscriber {
continue; continue;
} }
// run the subscriptions query and look for matches, add the id as part of the criteria to avoid getting matches of previous resources rather than the recent resource if (!mySubscriptionMatcher.match(nextCriteriaString, msg)) {
String criteria = nextCriteriaString;
criteria += "&_id=" + resourceType + "/" + resourceId;
criteria = massageCriteria(criteria);
IBundleProvider results = performSearch(criteria);
ourLog.debug("Subscription check found {} results for query: {}", results.size(), criteria);
if (results.size() == 0) {
continue; continue;
} }

View File

@ -0,0 +1,7 @@
package ca.uhn.fhir.jpa.subscription.matcher;
import ca.uhn.fhir.jpa.subscription.ResourceModifiedMessage;
public interface ISubscriptionMatcher {
boolean match(String criteria, ResourceModifiedMessage msg);
}

View File

@ -0,0 +1,67 @@
package ca.uhn.fhir.jpa.subscription.matcher;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.jpa.dao.BaseHapiFhirDao;
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
import ca.uhn.fhir.jpa.provider.ServletSubRequestDetails;
import ca.uhn.fhir.jpa.subscription.BaseSubscriptionInterceptor;
import ca.uhn.fhir.jpa.subscription.ResourceModifiedMessage;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.api.server.RequestDetails;
public class SubscriptionMatcherDatabase implements ISubscriptionMatcher {
private Logger ourLog = LoggerFactory.getLogger(SubscriptionMatcherDatabase.class);
private final IFhirResourceDao<?> mySubscriptionDao;
private final BaseSubscriptionInterceptor mySubscriptionInterceptor;
public SubscriptionMatcherDatabase(IFhirResourceDao<?> theSubscriptionDao, BaseSubscriptionInterceptor theSubscriptionInterceptor) {
mySubscriptionDao = theSubscriptionDao;
mySubscriptionInterceptor = theSubscriptionInterceptor;
}
@Override
public boolean match(String criteria, ResourceModifiedMessage msg) {
IIdType id = msg.getId(getContext());
String resourceType = id.getResourceType();
String resourceId = id.getIdPart();
// run the subscriptions query and look for matches, add the id as part of the criteria to avoid getting matches of previous resources rather than the recent resource
criteria += "&_id=" + resourceType + "/" + resourceId;
IBundleProvider results = performSearch(criteria);
ourLog.debug("Subscription check found {} results for query: {}", results.size(), criteria);
return results.size() > 0;
}
/**
* Search based on a query criteria
*/
protected IBundleProvider performSearch(String theCriteria) {
RuntimeResourceDefinition responseResourceDef = mySubscriptionDao.validateCriteriaAndReturnResourceDefinition(theCriteria);
SearchParameterMap responseCriteriaUrl = BaseHapiFhirDao.translateMatchUrl(mySubscriptionDao, getContext(), theCriteria, responseResourceDef);
RequestDetails req = new ServletSubRequestDetails();
req.setSubRequest(true);
IFhirResourceDao<? extends IBaseResource> responseDao = mySubscriptionInterceptor.getDao(responseResourceDef.getImplementingClass());
responseCriteriaUrl.setLoadSynchronousUpTo(1);
IBundleProvider responseResults = responseDao.search(responseCriteriaUrl, req);
return responseResults;
}
public FhirContext getContext() {
return mySubscriptionDao.getContext();
}
}

View File

@ -0,0 +1,12 @@
package ca.uhn.fhir.jpa.subscription.matcher;
import ca.uhn.fhir.jpa.subscription.ResourceModifiedMessage;
public class SubscriptionMatcherInMemory implements ISubscriptionMatcher {
@Override
public boolean match(String criteria, ResourceModifiedMessage msg) {
// FIXME KHS implement
return true;
}
}

View File

@ -26,6 +26,7 @@ import org.junit.*;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.containsString;
@ -44,8 +45,8 @@ public class SubscriptionTriggeringDstu3Test extends BaseResourceProviderDstu3Te
private static RestfulServer ourListenerRestServer; private static RestfulServer ourListenerRestServer;
private static Server ourListenerServer; private static Server ourListenerServer;
private static String ourListenerServerBase; private static String ourListenerServerBase;
private static List<Observation> ourCreatedObservations = Lists.newArrayList(); private static List<Observation> ourCreatedObservations = Collections.synchronizedList(Lists.newArrayList());
private static List<Observation> ourUpdatedObservations = Lists.newArrayList(); private static List<Observation> ourUpdatedObservations = Collections.synchronizedList(Lists.newArrayList());
private static List<Patient> ourCreatedPatients = Lists.newArrayList(); private static List<Patient> ourCreatedPatients = Lists.newArrayList();
private static List<Patient> ourUpdatedPatients = Lists.newArrayList(); private static List<Patient> ourUpdatedPatients = Lists.newArrayList();
private static List<String> ourContentTypes = new ArrayList<>(); private static List<String> ourContentTypes = new ArrayList<>();

View File

@ -1,24 +1,5 @@
package ca.uhn.fhir.util; package ca.uhn.fhir.util;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseReference;
import org.junit.AfterClass;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import ca.uhn.fhir.context.BaseRuntimeChildDefinition; import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
import ca.uhn.fhir.context.BaseRuntimeElementDefinition; import ca.uhn.fhir.context.BaseRuntimeElementDefinition;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
@ -31,9 +12,26 @@ import ca.uhn.fhir.model.dstu2.resource.Bundle;
import ca.uhn.fhir.model.dstu2.resource.Observation; 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.primitive.BooleanDt;
import ca.uhn.fhir.model.primitive.MarkdownDt; import ca.uhn.fhir.model.primitive.MarkdownDt;
import ca.uhn.fhir.model.primitive.StringDt; import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.parser.DataFormatException; import ca.uhn.fhir.parser.DataFormatException;
import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseExtension;
import org.hl7.fhir.instance.model.api.IBaseReference;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
import org.junit.AfterClass;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.junit.Assert.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class FhirTerserDstu2Test { public class FhirTerserDstu2Test {
@ -180,6 +178,597 @@ public class FhirTerserDstu2Test {
assertEquals(1, refs.size()); assertEquals(1, refs.size());
assertSame(ref, refs.get(0)); assertSame(ref, refs.get(0));
} }
@Test
public void testGetValues() {
Patient p = new Patient();
p.setActive(true);
p.addUndeclaredExtension(false, "http://acme.org/extension", new StringDt("value"));
p.addUndeclaredExtension(false, "http://acme.org/otherExtension", new StringDt("otherValue"));
p.addUndeclaredExtension(true, "http://acme.org/modifierExtension", new StringDt("modifierValue"));
p.addUndeclaredExtension(false, "http://acme.org/parentExtension").addUndeclaredExtension(false, "http://acme.org/childExtension", new StringDt("nestedValue"));
System.out.println(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p));
List<Object> values = ourCtx.newTerser().getValues(p, "Patient.active");
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof IPrimitiveType);
assertTrue(values.get(0) instanceof BooleanDt);
assertTrue(((BooleanDt) values.get(0)).getValue());
values = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/extension')");
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof ExtensionDt);
assertEquals("http://acme.org/extension", ((ExtensionDt) values.get(0)).getUrl());
assertEquals("value", ((StringDt) ((ExtensionDt) values.get(0)).getValue()).getValueAsString());
values = ourCtx.newTerser().getValues(p, "Patient.modifierExtension('http://acme.org/modifierExtension')");
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof ExtensionDt);
assertEquals("http://acme.org/modifierExtension", ((ExtensionDt) values.get(0)).getUrl());
assertEquals("modifierValue", ((StringDt) ((ExtensionDt) values.get(0)).getValue()).getValueAsString());
values = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/parentExtension').extension('http://acme.org/childExtension')");
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof ExtensionDt);
assertEquals("http://acme.org/childExtension", ((ExtensionDt) values.get(0)).getUrl());
assertEquals("nestedValue", ((StringDt) ((ExtensionDt) values.get(0)).getValue()).getValueAsString());
}
@Test
public void testGetValuesAndModify() {
Patient p = new Patient();
p.setActive(true);
p.addUndeclaredExtension(false, "http://acme.org/extension", new StringDt("value"));
p.addUndeclaredExtension(false, "http://acme.org/otherExtension", new StringDt("otherValue"));
p.addUndeclaredExtension(true, "http://acme.org/modifierExtension", new StringDt("modifierValue"));
p.addUndeclaredExtension(false, "http://acme.org/parentExtension").addUndeclaredExtension(false, "http://acme.org/childExtension", new StringDt("nestedValue"));
System.out.println(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p));
List<Object> values = ourCtx.newTerser().getValues(p, "Patient.active");
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof IPrimitiveType);
assertTrue(values.get(0) instanceof BooleanDt);
assertTrue(((BooleanDt) values.get(0)).getValue());
((BooleanDt) values.get(0)).setValue(Boolean.FALSE);
System.out.println(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p));
values = ourCtx.newTerser().getValues(p, "Patient.active");
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof IPrimitiveType);
assertTrue(values.get(0) instanceof BooleanDt);
assertFalse(((BooleanDt) values.get(0)).getValue());
values = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/extension')");
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof ExtensionDt);
assertEquals("http://acme.org/extension", ((ExtensionDt) values.get(0)).getUrl());
assertEquals("value", ((StringDt) ((ExtensionDt) values.get(0)).getValue()).getValueAsString());
((ExtensionDt) values.get(0)).setValue(new StringDt("modifiedValue"));
System.out.println(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p));
values = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/extension')");
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof ExtensionDt);
assertEquals("http://acme.org/extension", ((ExtensionDt) values.get(0)).getUrl());
assertEquals("modifiedValue", ((StringDt) ((ExtensionDt) values.get(0)).getValue()).getValueAsString());
values = ourCtx.newTerser().getValues(p, "Patient.modifierExtension('http://acme.org/modifierExtension')");
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof ExtensionDt);
assertEquals("http://acme.org/modifierExtension", ((ExtensionDt) values.get(0)).getUrl());
assertEquals("modifierValue", ((StringDt) ((ExtensionDt) values.get(0)).getValue()).getValueAsString());
((ExtensionDt) values.get(0)).setValue(new StringDt("modifiedModifierValue"));
System.out.println(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p));
values = ourCtx.newTerser().getValues(p, "Patient.modifierExtension('http://acme.org/modifierExtension')");
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof ExtensionDt);
assertEquals("http://acme.org/modifierExtension", ((ExtensionDt) values.get(0)).getUrl());
assertEquals("modifiedModifierValue", ((StringDt) ((ExtensionDt) values.get(0)).getValue()).getValueAsString());
values = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/parentExtension').extension('http://acme.org/childExtension')");
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof ExtensionDt);
assertEquals("http://acme.org/childExtension", ((ExtensionDt) values.get(0)).getUrl());
assertEquals("nestedValue", ((StringDt) ((ExtensionDt) values.get(0)).getValue()).getValueAsString());
((ExtensionDt) values.get(0)).setValue(new StringDt("modifiedNestedValue"));
System.out.println(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p));
values = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/parentExtension').extension('http://acme.org/childExtension')");
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof ExtensionDt);
assertEquals("http://acme.org/childExtension", ((ExtensionDt) values.get(0)).getUrl());
assertEquals("modifiedNestedValue", ((StringDt) ((ExtensionDt) values.get(0)).getValue()).getValueAsString());
}
@Test
public void testGetValuesMultiple() {
Patient p = new Patient();
p.addUndeclaredExtension(false, "http://acme.org/extension", new StringDt("value1"));
p.addUndeclaredExtension(false, "http://acme.org/extension", new StringDt("value2"));
p.addUndeclaredExtension(false, "http://acme.org/otherExtension", new StringDt("otherValue"));
p.addUndeclaredExtension(true, "http://acme.org/modifierExtension", new StringDt("modifierValue1"));
p.addUndeclaredExtension(true, "http://acme.org/modifierExtension", new StringDt("modifierValue2"));
p.addUndeclaredExtension(false, "http://acme.org/parentExtension").addUndeclaredExtension(false, "http://acme.org/childExtension", new StringDt("nestedValue1"));
p.addUndeclaredExtension(false, "http://acme.org/parentExtension").addUndeclaredExtension(false, "http://acme.org/childExtension", new StringDt("nestedValue2"));
System.out.println(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p));
List<Object> values = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/extension')");
assertEquals(2, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof ExtensionDt);
assertEquals("http://acme.org/extension", ((ExtensionDt) values.get(0)).getUrl());
assertEquals("value1", ((StringDt) ((ExtensionDt) values.get(0)).getValue()).getValueAsString());
assertTrue(values.get(1) instanceof IBaseExtension);
assertTrue(values.get(1) instanceof ExtensionDt);
assertEquals("http://acme.org/extension", ((ExtensionDt) values.get(1)).getUrl());
assertEquals("value2", ((StringDt) ((ExtensionDt) values.get(1)).getValue()).getValueAsString());
values = ourCtx.newTerser().getValues(p, "Patient.modifierExtension('http://acme.org/modifierExtension')");
assertEquals(2, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof ExtensionDt);
assertEquals("http://acme.org/modifierExtension", ((ExtensionDt) values.get(0)).getUrl());
assertEquals("modifierValue1", ((StringDt) ((ExtensionDt) values.get(0)).getValue()).getValueAsString());
assertTrue(values.get(1) instanceof IBaseExtension);
assertTrue(values.get(1) instanceof ExtensionDt);
assertEquals("http://acme.org/modifierExtension", ((ExtensionDt) values.get(1)).getUrl());
assertEquals("modifierValue2", ((StringDt) ((ExtensionDt) values.get(1)).getValue()).getValueAsString());
values = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/parentExtension').extension('http://acme.org/childExtension')");
assertEquals(2, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof ExtensionDt);
assertEquals("http://acme.org/childExtension", ((ExtensionDt) values.get(0)).getUrl());
assertEquals("nestedValue1", ((StringDt) ((ExtensionDt) values.get(0)).getValue()).getValueAsString());
assertTrue(values.get(1) instanceof IBaseExtension);
assertTrue(values.get(1) instanceof ExtensionDt);
assertEquals("http://acme.org/childExtension", ((ExtensionDt) values.get(1)).getUrl());
assertEquals("nestedValue2", ((StringDt) ((ExtensionDt) values.get(1)).getValue()).getValueAsString());
}
@Test
public void testGetValuesWithWantedClass() {
Patient p = new Patient();
p.setActive(true);
p.addUndeclaredExtension(false, "http://acme.org/extension", new StringDt("value"));
p.addUndeclaredExtension(false, "http://acme.org/otherExtension", new StringDt("otherValue"));
p.addUndeclaredExtension(true, "http://acme.org/modifierExtension", new StringDt("modifierValue"));
p.addUndeclaredExtension(false, "http://acme.org/parentExtension").addUndeclaredExtension(false, "http://acme.org/childExtension", new StringDt("nestedValue"));
System.out.println(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p));
List<IPrimitiveType> values = ourCtx.newTerser().getValues(p, "Patient.active", IPrimitiveType.class);
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof BooleanDt);
assertTrue(((BooleanDt) values.get(0)).getValue());
List<ExtensionDt> extValues = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/extension')", ExtensionDt.class);
assertEquals(1, extValues.size());
assertTrue(extValues.get(0).getValue() instanceof StringDt);
assertEquals("http://acme.org/extension", extValues.get(0).getUrl());
assertEquals("value", ((StringDt) extValues.get(0).getValue()).getValueAsString());
extValues = ourCtx.newTerser().getValues(p, "Patient.modifierExtension('http://acme.org/modifierExtension')", ExtensionDt.class);
assertEquals(1, extValues.size());
assertTrue(extValues.get(0).getValue() instanceof StringDt);
assertEquals("http://acme.org/modifierExtension", extValues.get(0).getUrl());
assertEquals("modifierValue", ((StringDt) (extValues.get(0).getValue())).getValueAsString());
extValues = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/parentExtension').extension('http://acme.org/childExtension')", ExtensionDt.class);
assertEquals(1, extValues.size());
assertTrue(extValues.get(0).getValue() instanceof StringDt);
assertEquals("http://acme.org/childExtension", extValues.get(0).getUrl());
assertEquals("nestedValue", ((StringDt) extValues.get(0).getValue()).getValueAsString());
}
@Test
public void testGetValuesWithWantedClassAndModify() {
Patient p = new Patient();
p.setActive(true);
p.addUndeclaredExtension(false, "http://acme.org/extension", new StringDt("value"));
p.addUndeclaredExtension(false, "http://acme.org/otherExtension", new StringDt("otherValue"));
p.addUndeclaredExtension(true, "http://acme.org/modifierExtension", new StringDt("modifierValue"));
p.addUndeclaredExtension(false, "http://acme.org/parentExtension").addUndeclaredExtension(false, "http://acme.org/childExtension", new StringDt("nestedValue"));
System.out.println(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p));
List<IPrimitiveType> values = ourCtx.newTerser().getValues(p, "Patient.active", IPrimitiveType.class);
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof BooleanDt);
assertTrue(((BooleanDt) values.get(0)).getValue());
((BooleanDt) values.get(0)).setValue(Boolean.FALSE);
System.out.println(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p));
values = ourCtx.newTerser().getValues(p, "Patient.active", IPrimitiveType.class);
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof BooleanDt);
assertFalse(((BooleanDt) values.get(0)).getValue());
List<ExtensionDt> extValues = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/extension')", ExtensionDt.class);
assertEquals(1, extValues.size());
assertTrue(extValues.get(0).getValue() instanceof StringDt);
assertEquals("http://acme.org/extension", extValues.get(0).getUrl());
assertEquals("value", ((StringDt) (extValues.get(0).getValue())).getValueAsString());
extValues.get(0).setValue(new StringDt("modifiedValue"));
System.out.println(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p));
extValues = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/extension')", ExtensionDt.class);
assertEquals(1, extValues.size());
assertTrue(extValues.get(0).getValue() instanceof StringDt);
assertEquals("http://acme.org/extension", extValues.get(0).getUrl());
assertEquals("modifiedValue", ((StringDt) (extValues.get(0).getValue())).getValueAsString());
extValues = ourCtx.newTerser().getValues(p, "Patient.modifierExtension('http://acme.org/modifierExtension')", ExtensionDt.class);
assertEquals(1, extValues.size());
assertTrue(extValues.get(0).getValue() instanceof StringDt);
assertEquals("http://acme.org/modifierExtension", extValues.get(0).getUrl());
assertEquals("modifierValue", ((StringDt) (extValues.get(0).getValue())).getValueAsString());
extValues.get(0).setValue(new StringDt("modifiedModifierValue"));
System.out.println(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p));
extValues = ourCtx.newTerser().getValues(p, "Patient.modifierExtension('http://acme.org/modifierExtension')", ExtensionDt.class);
assertEquals(1, extValues.size());
assertTrue(extValues.get(0).getValue() instanceof StringDt);
assertEquals("http://acme.org/modifierExtension", extValues.get(0).getUrl());
assertEquals("modifiedModifierValue", ((StringDt) (extValues.get(0).getValue())).getValueAsString());
extValues = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/parentExtension').extension('http://acme.org/childExtension')", ExtensionDt.class);
assertEquals(1, extValues.size());
assertTrue(extValues.get(0).getValue() instanceof StringDt);
assertEquals("http://acme.org/childExtension", extValues.get(0).getUrl());
assertEquals("nestedValue", ((StringDt) extValues.get(0).getValue()).getValueAsString());
extValues.get(0).setValue(new StringDt("modifiedNestedValue"));
System.out.println(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p));
extValues = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/parentExtension').extension('http://acme.org/childExtension')", ExtensionDt.class);
assertEquals(1, extValues.size());
assertTrue(extValues.get(0).getValue() instanceof StringDt);
assertEquals("http://acme.org/childExtension", extValues.get(0).getUrl());
assertEquals("modifiedNestedValue", ((StringDt) extValues.get(0).getValue()).getValueAsString());
}
@Test
public void testGetValuesWithWantedClassAndTheCreate() {
Patient p = new Patient();
System.out.println(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p));
List<IPrimitiveType> values = ourCtx.newTerser().getValues(p, "Patient.active", IPrimitiveType.class, true);
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof BooleanDt);
assertNull(((BooleanDt) values.get(0)).getValue());
List<ExtensionDt> extValues = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/extension')", ExtensionDt.class, true);
assertEquals(1, extValues.size());
assertEquals("http://acme.org/extension", extValues.get(0).getUrl());
assertNull(extValues.get(0).getValue());
extValues = ourCtx.newTerser().getValues(p, "Patient.modifierExtension('http://acme.org/modifierExtension')", ExtensionDt.class, true);
assertEquals(1, extValues.size());
assertEquals("http://acme.org/modifierExtension", extValues.get(0).getUrl());
assertNull(extValues.get(0).getValue());
extValues = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/parentExtension').extension('http://acme.org/childExtension')", ExtensionDt.class, true);
assertEquals(1, extValues.size());
assertEquals("http://acme.org/childExtension", extValues.get(0).getUrl());
assertNull(extValues.get(0).getValue());
}
@Test
public void testGetValuesWithTheAddExtensionAndModify() {
Patient p = new Patient();
p.setActive(true);
p.addUndeclaredExtension(false, "http://acme.org/extension", new StringDt("value"));
p.addUndeclaredExtension(false, "http://acme.org/otherExtension", new StringDt("otherValue"));
p.addUndeclaredExtension(true, "http://acme.org/modifierExtension", new StringDt("modifierValue"));
p.addUndeclaredExtension(false, "http://acme.org/parentExtension").addUndeclaredExtension(false, "http://acme.org/childExtension", new StringDt("nestedValue"));
System.out.println(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p));
List<Object> values = ourCtx.newTerser().getValues(p, "Patient.active");
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof IPrimitiveType);
assertTrue(values.get(0) instanceof BooleanDt);
assertTrue(((BooleanDt) values.get(0)).getValue());
// No change.
values = ourCtx.newTerser().getValues(p, "Patient.active", false, true);
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof IPrimitiveType);
assertTrue(values.get(0) instanceof BooleanDt);
assertTrue(((BooleanDt) values.get(0)).getValue());
values = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/extension')");
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof ExtensionDt);
assertEquals("http://acme.org/extension", ((ExtensionDt) values.get(0)).getUrl());
assertEquals("value", ((StringDt) ((ExtensionDt) values.get(0)).getValue()).getValueAsString());
values = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/extension')", false, true);
assertEquals(2, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof ExtensionDt);
assertEquals("http://acme.org/extension", ((ExtensionDt) values.get(0)).getUrl());
assertEquals("value", ((StringDt) ((ExtensionDt) values.get(0)).getValue()).getValueAsString());
assertTrue(values.get(1) instanceof IBaseExtension);
assertTrue(values.get(1) instanceof ExtensionDt);
assertEquals("http://acme.org/extension", ((ExtensionDt) values.get(1)).getUrl());
assertNull(((ExtensionDt) values.get(1)).getValue());
((ExtensionDt) values.get(1)).setValue(new StringDt("addedValue"));
System.out.println(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p));
assertTrue(values.get(1) instanceof IBaseExtension);
assertTrue(values.get(1) instanceof ExtensionDt);
assertEquals("http://acme.org/extension", ((ExtensionDt) values.get(1)).getUrl());
assertEquals("addedValue", ((StringDt) ((ExtensionDt) values.get(1)).getValue()).getValueAsString());
values = ourCtx.newTerser().getValues(p, "Patient.modifierExtension('http://acme.org/modifierExtension')");
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof ExtensionDt);
assertEquals("http://acme.org/modifierExtension", ((ExtensionDt) values.get(0)).getUrl());
assertEquals("modifierValue", ((StringDt) ((ExtensionDt) values.get(0)).getValue()).getValueAsString());
values = ourCtx.newTerser().getValues(p, "Patient.modifierExtension('http://acme.org/modifierExtension')", false, true);
assertEquals(2, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof ExtensionDt);
assertEquals("http://acme.org/modifierExtension", ((ExtensionDt) values.get(0)).getUrl());
assertEquals("modifierValue", ((StringDt) ((ExtensionDt) values.get(0)).getValue()).getValueAsString());
assertTrue(values.get(1) instanceof IBaseExtension);
assertTrue(values.get(1) instanceof ExtensionDt);
assertEquals("http://acme.org/modifierExtension", ((ExtensionDt) values.get(1)).getUrl());
assertNull(((ExtensionDt) values.get(1)).getValue());
((ExtensionDt) values.get(1)).setValue(new StringDt("addedModifierValue"));
System.out.println(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p));
assertTrue(values.get(1) instanceof IBaseExtension);
assertTrue(values.get(1) instanceof ExtensionDt);
assertEquals("http://acme.org/modifierExtension", ((ExtensionDt) values.get(1)).getUrl());
assertEquals("addedModifierValue", ((StringDt) ((ExtensionDt) values.get(1)).getValue()).getValueAsString());
System.out.println(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p));
values = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/parentExtension').extension('http://acme.org/childExtension')");
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof ExtensionDt);
assertEquals("http://acme.org/childExtension", ((ExtensionDt) values.get(0)).getUrl());
assertEquals("nestedValue", ((StringDt) ((ExtensionDt) values.get(0)).getValue()).getValueAsString());
values = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/parentExtension').extension('http://acme.org/childExtension')", false, true);
assertEquals(2, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof ExtensionDt);
assertEquals("http://acme.org/childExtension", ((ExtensionDt) values.get(0)).getUrl());
assertEquals("nestedValue", ((StringDt) ((ExtensionDt) values.get(0)).getValue()).getValueAsString());
assertTrue(values.get(1) instanceof IBaseExtension);
assertTrue(values.get(1) instanceof ExtensionDt);
assertEquals("http://acme.org/childExtension", ((ExtensionDt) values.get(1)).getUrl());
assertNull(((ExtensionDt) values.get(1)).getValue());
((ExtensionDt) values.get(1)).setValue(new StringDt("addedNestedValue"));
System.out.println(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p));
assertTrue(values.get(1) instanceof IBaseExtension);
assertTrue(values.get(1) instanceof ExtensionDt);
assertEquals("http://acme.org/childExtension", ((ExtensionDt) values.get(1)).getUrl());
assertEquals("addedNestedValue", ((StringDt) ((ExtensionDt) values.get(1)).getValue()).getValueAsString());
}
@Test
public void testGetValuesWithTheCreate() {
Patient p = new Patient();
System.out.println(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p));
List<Object> values = ourCtx.newTerser().getValues(p, "Patient.active", true);
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof IPrimitiveType);
assertTrue(values.get(0) instanceof BooleanDt);
assertNull(((BooleanDt) values.get(0)).getValue());
values = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/extension')", true);
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof ExtensionDt);
assertEquals("http://acme.org/extension", ((ExtensionDt) values.get(0)).getUrl());
assertNull(((ExtensionDt) values.get(0)).getValue());
values = ourCtx.newTerser().getValues(p, "Patient.modifierExtension('http://acme.org/modifierExtension')", true);
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof ExtensionDt);
assertEquals("http://acme.org/modifierExtension", ((ExtensionDt) values.get(0)).getUrl());
assertNull(((ExtensionDt) values.get(0)).getValue());
values = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/parentExtension').extension('http://acme.org/childExtension')", true);
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof ExtensionDt);
assertEquals("http://acme.org/childExtension", ((ExtensionDt) values.get(0)).getUrl());
assertNull(((ExtensionDt) values.get(0)).getValue());
}
@Test
public void testGetValuesWithTheCreateAndTheAddExtensionAndModify() {
Patient p = new Patient();
p.setActive(true);
p.addUndeclaredExtension(false, "http://acme.org/extension", new StringDt("value"));
p.addUndeclaredExtension(false, "http://acme.org/otherExtension", new StringDt("otherValue"));
p.addUndeclaredExtension(true, "http://acme.org/modifierExtension", new StringDt("modifierValue"));
p.addUndeclaredExtension(false, "http://acme.org/parentExtension").addUndeclaredExtension(false, "http://acme.org/childExtension", new StringDt("nestedValue"));
System.out.println(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p));
List<Object> values = ourCtx.newTerser().getValues(p, "Patient.active");
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof IPrimitiveType);
assertTrue(values.get(0) instanceof BooleanDt);
assertTrue(((BooleanDt) values.get(0)).getValue());
// No change.
values = ourCtx.newTerser().getValues(p, "Patient.active", true, true);
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof IPrimitiveType);
assertTrue(values.get(0) instanceof BooleanDt);
assertTrue(((BooleanDt) values.get(0)).getValue());
values = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/extension')");
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof ExtensionDt);
assertEquals("http://acme.org/extension", ((ExtensionDt) values.get(0)).getUrl());
assertEquals("value", ((StringDt) ((ExtensionDt) values.get(0)).getValue()).getValueAsString());
values = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/extension')", true, true);
assertEquals(2, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof ExtensionDt);
assertEquals("http://acme.org/extension", ((ExtensionDt) values.get(0)).getUrl());
assertEquals("value", ((StringDt) ((ExtensionDt) values.get(0)).getValue()).getValueAsString());
assertTrue(values.get(1) instanceof IBaseExtension);
assertTrue(values.get(1) instanceof ExtensionDt);
assertEquals("http://acme.org/extension", ((ExtensionDt) values.get(1)).getUrl());
assertNull(((ExtensionDt) values.get(1)).getValue());
((ExtensionDt) values.get(1)).setValue(new StringDt("addedValue"));
System.out.println(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p));
assertTrue(values.get(1) instanceof IBaseExtension);
assertTrue(values.get(1) instanceof ExtensionDt);
assertEquals("http://acme.org/extension", ((ExtensionDt) values.get(1)).getUrl());
assertEquals("addedValue", ((StringDt) ((ExtensionDt) values.get(1)).getValue()).getValueAsString());
values = ourCtx.newTerser().getValues(p, "Patient.modifierExtension('http://acme.org/modifierExtension')");
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof ExtensionDt);
assertEquals("http://acme.org/modifierExtension", ((ExtensionDt) values.get(0)).getUrl());
assertEquals("modifierValue", ((StringDt) ((ExtensionDt) values.get(0)).getValue()).getValueAsString());
values = ourCtx.newTerser().getValues(p, "Patient.modifierExtension('http://acme.org/modifierExtension')", true, true);
assertEquals(2, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof ExtensionDt);
assertEquals("http://acme.org/modifierExtension", ((ExtensionDt) values.get(0)).getUrl());
assertEquals("modifierValue", ((StringDt) ((ExtensionDt) values.get(0)).getValue()).getValueAsString());
assertTrue(values.get(1) instanceof IBaseExtension);
assertTrue(values.get(1) instanceof ExtensionDt);
assertEquals("http://acme.org/modifierExtension", ((ExtensionDt) values.get(1)).getUrl());
assertNull(((ExtensionDt) values.get(1)).getValue());
((ExtensionDt) values.get(1)).setValue(new StringDt("addedModifierValue"));
System.out.println(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p));
assertTrue(values.get(1) instanceof IBaseExtension);
assertTrue(values.get(1) instanceof ExtensionDt);
assertEquals("http://acme.org/modifierExtension", ((ExtensionDt) values.get(1)).getUrl());
assertEquals("addedModifierValue", ((StringDt) ((ExtensionDt) values.get(1)).getValue()).getValueAsString());
values = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/parentExtension').extension('http://acme.org/childExtension')");
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof ExtensionDt);
assertEquals("http://acme.org/childExtension", ((ExtensionDt) values.get(0)).getUrl());
assertEquals("nestedValue", ((StringDt) ((ExtensionDt) values.get(0)).getValue()).getValueAsString());
values = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/parentExtension').extension('http://acme.org/childExtension')", true, true);
assertEquals(2, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof ExtensionDt);
assertEquals("http://acme.org/childExtension", ((ExtensionDt) values.get(0)).getUrl());
assertEquals("nestedValue", ((StringDt) ((ExtensionDt) values.get(0)).getValue()).getValueAsString());
assertTrue(values.get(1) instanceof IBaseExtension);
assertTrue(values.get(1) instanceof ExtensionDt);
assertEquals("http://acme.org/childExtension", ((ExtensionDt) values.get(1)).getUrl());
assertNull(((ExtensionDt) values.get(1)).getValue());
((ExtensionDt) values.get(1)).setValue(new StringDt("addedNestedValue"));
System.out.println(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p));
assertTrue(values.get(1) instanceof IBaseExtension);
assertTrue(values.get(1) instanceof ExtensionDt);
assertEquals("http://acme.org/childExtension", ((ExtensionDt) values.get(1)).getUrl());
assertEquals("addedNestedValue", ((StringDt) ((ExtensionDt) values.get(1)).getValue()).getValueAsString());
}
@Test
public void testGetValuesWithTheCreateAndNoOverwrite() {
Patient p = new Patient();
p.setActive(true);
p.addUndeclaredExtension(false, "http://acme.org/extension", new StringDt("value"));
p.addUndeclaredExtension(false, "http://acme.org/otherExtension", new StringDt("otherValue"));
p.addUndeclaredExtension(true, "http://acme.org/modifierExtension", new StringDt("modifierValue"));
p.addUndeclaredExtension(false, "http://acme.org/parentExtension").addUndeclaredExtension(false, "http://acme.org/childExtension", new StringDt("nestedValue"));
System.out.println(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p));
List<Object> values = ourCtx.newTerser().getValues(p, "Patient.active", true);
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof IPrimitiveType);
assertTrue(values.get(0) instanceof BooleanDt);
assertTrue(((BooleanDt) values.get(0)).getValue());
values = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/extension')", true);
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof ExtensionDt);
assertEquals("http://acme.org/extension", ((ExtensionDt) values.get(0)).getUrl());
assertEquals("value", ((StringDt) ((ExtensionDt) values.get(0)).getValue()).getValueAsString());
values = ourCtx.newTerser().getValues(p, "Patient.modifierExtension('http://acme.org/modifierExtension')", true);
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof ExtensionDt);
assertEquals("http://acme.org/modifierExtension", ((ExtensionDt) values.get(0)).getUrl());
assertEquals("modifierValue", ((StringDt) ((ExtensionDt) values.get(0)).getValue()).getValueAsString());
values = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/parentExtension').extension('http://acme.org/childExtension')", true);
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof ExtensionDt);
assertEquals("http://acme.org/childExtension", ((ExtensionDt) values.get(0)).getUrl());
assertEquals("nestedValue", ((StringDt) ((ExtensionDt) values.get(0)).getValue()).getValueAsString());
}
@Test @Test
public void testVisitWithModelVisitor2() { public void testVisitWithModelVisitor2() {

View File

@ -1,41 +1,27 @@
package ca.uhn.fhir.util; package ca.uhn.fhir.util;
import static org.hamcrest.Matchers.containsInAnyOrder; import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
import static org.junit.Assert.assertEquals; import ca.uhn.fhir.context.BaseRuntimeElementDefinition;
import static org.junit.Assert.assertSame; import ca.uhn.fhir.context.FhirContext;
import static org.junit.Assert.assertThat; import ca.uhn.fhir.parser.DataFormatException;
import static org.junit.Assert.assertTrue; import org.hl7.fhir.dstu3.model.*;
import static org.junit.Assert.fail; import org.hl7.fhir.dstu3.model.Patient.LinkType;
import static org.mockito.Mockito.mock; import org.hl7.fhir.instance.model.api.IBase;
import static org.mockito.Mockito.when; import org.hl7.fhir.instance.model.api.IBaseExtension;
import org.hl7.fhir.instance.model.api.IBaseReference;
import org.junit.AfterClass;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import java.lang.reflect.ParameterizedType; import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.hl7.fhir.dstu3.model.Bundle; import static org.hamcrest.Matchers.containsInAnyOrder;
import org.hl7.fhir.dstu3.model.Extension; import static org.junit.Assert.*;
import org.hl7.fhir.dstu3.model.Identifier; import static org.mockito.Mockito.mock;
import org.hl7.fhir.dstu3.model.MarkdownType; import static org.mockito.Mockito.when;
import org.hl7.fhir.dstu3.model.Money;
import org.hl7.fhir.dstu3.model.Observation;
import org.hl7.fhir.dstu3.model.Organization;
import org.hl7.fhir.dstu3.model.Patient;
import org.hl7.fhir.dstu3.model.Patient.LinkType;
import org.hl7.fhir.dstu3.model.Quantity;
import org.hl7.fhir.dstu3.model.Reference;
import org.hl7.fhir.dstu3.model.StringType;
import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseReference;
import org.junit.AfterClass;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
import ca.uhn.fhir.context.BaseRuntimeElementDefinition;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.parser.DataFormatException;
public class FhirTerserDstu3Test { public class FhirTerserDstu3Test {
@ -183,6 +169,683 @@ public class FhirTerserDstu3Test {
assertSame(ref, refs.get(0)); assertSame(ref, refs.get(0));
} }
@Test
public void testGetValues() {
Patient p = new Patient();
p.setActive(true);
p.addExtension()
.setUrl("http://acme.org/extension")
.setValue(new StringType("value"));
p.addExtension()
.setUrl("http://acme.org/otherExtension")
.setValue(new StringType("otherValue"));
p.addModifierExtension()
.setUrl("http://acme.org/modifierExtension")
.setValue(new StringType("modifierValue"));
p.addExtension()
.setUrl("http://acme.org/parentExtension")
.addExtension()
.setUrl("http://acme.org/childExtension")
.setValue(new StringType("nestedValue"));
System.out.println(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p));
List<Object> values = ourCtx.newTerser().getValues(p, "Patient.active");
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof PrimitiveType);
assertTrue(values.get(0) instanceof BooleanType);
assertTrue(((BooleanType) values.get(0)).booleanValue());
values = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/extension')");
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof Extension);
assertEquals("http://acme.org/extension", ((Extension) values.get(0)).getUrl());
assertEquals("value", ((StringType) ((Extension) values.get(0)).getValue()).getValueAsString());
values = ourCtx.newTerser().getValues(p, "Patient.modifierExtension('http://acme.org/modifierExtension')");
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof Extension);
assertEquals("http://acme.org/modifierExtension", ((Extension) values.get(0)).getUrl());
assertEquals("modifierValue", ((StringType) ((Extension) values.get(0)).getValue()).getValueAsString());
values = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/parentExtension').extension('http://acme.org/childExtension')");
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof Extension);
assertEquals("http://acme.org/childExtension", ((Extension) values.get(0)).getUrl());
assertEquals("nestedValue", ((StringType) ((Extension) values.get(0)).getValue()).getValueAsString());
}
@Test
public void testGetValuesAndModify() {
Patient p = new Patient();
p.setActive(true);
p.addExtension()
.setUrl("http://acme.org/extension")
.setValue(new StringType("value"));
p.addExtension()
.setUrl("http://acme.org/otherExtension")
.setValue(new StringType("otherValue"));
p.addModifierExtension()
.setUrl("http://acme.org/modifierExtension")
.setValue(new StringType("modifierValue"));
p.addExtension()
.setUrl("http://acme.org/parentExtension")
.addExtension()
.setUrl("http://acme.org/childExtension")
.setValue(new StringType("nestedValue"));
System.out.println(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p));
List<Object> values = ourCtx.newTerser().getValues(p, "Patient.active");
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof PrimitiveType);
assertTrue(values.get(0) instanceof BooleanType);
assertTrue(((BooleanType) values.get(0)).booleanValue());
((BooleanType) values.get(0)).setValue(Boolean.FALSE);
System.out.println(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p));
values = ourCtx.newTerser().getValues(p, "Patient.active");
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof PrimitiveType);
assertTrue(values.get(0) instanceof BooleanType);
assertFalse(((BooleanType) values.get(0)).booleanValue());
values = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/extension')");
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof Extension);
assertEquals("http://acme.org/extension", ((Extension) values.get(0)).getUrl());
assertEquals("value", ((StringType) ((Extension) values.get(0)).getValue()).getValueAsString());
((Extension) values.get(0)).setValue(new StringType("modifiedValue"));
System.out.println(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p));
values = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/extension')");
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof Extension);
assertEquals("http://acme.org/extension", ((Extension) values.get(0)).getUrl());
assertEquals("modifiedValue", ((StringType) ((Extension) values.get(0)).getValue()).getValueAsString());
values = ourCtx.newTerser().getValues(p, "Patient.modifierExtension('http://acme.org/modifierExtension')");
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof Extension);
assertEquals("http://acme.org/modifierExtension", ((Extension) values.get(0)).getUrl());
assertEquals("modifierValue", ((StringType) ((Extension) values.get(0)).getValue()).getValueAsString());
((Extension) values.get(0)).setValue(new StringType("modifiedModifierValue"));
System.out.println(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p));
values = ourCtx.newTerser().getValues(p, "Patient.modifierExtension('http://acme.org/modifierExtension')");
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof Extension);
assertEquals("http://acme.org/modifierExtension", ((Extension) values.get(0)).getUrl());
assertEquals("modifiedModifierValue", ((StringType) ((Extension) values.get(0)).getValue()).getValueAsString());
values = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/parentExtension').extension('http://acme.org/childExtension')");
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof Extension);
assertEquals("http://acme.org/childExtension", ((Extension) values.get(0)).getUrl());
assertEquals("nestedValue", ((StringType) ((Extension) values.get(0)).getValue()).getValueAsString());
((Extension) values.get(0)).setValue(new StringType("modifiedNestedValue"));
System.out.println(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p));
values = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/parentExtension').extension('http://acme.org/childExtension')");
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof Extension);
assertEquals("http://acme.org/childExtension", ((Extension) values.get(0)).getUrl());
assertEquals("modifiedNestedValue", ((StringType) ((Extension) values.get(0)).getValue()).getValueAsString());
}
@Test
public void testGetValuesMultiple() {
Patient p = new Patient();
p.addExtension()
.setUrl("http://acme.org/extension")
.setValue(new StringType("value1"));
p.addExtension()
.setUrl("http://acme.org/extension")
.setValue(new StringType("value2"));
p.addExtension()
.setUrl("http://acme.org/otherExtension")
.setValue(new StringType("otherValue"));
p.addModifierExtension()
.setUrl("http://acme.org/modifierExtension")
.setValue(new StringType("modifierValue1"));
p.addModifierExtension()
.setUrl("http://acme.org/modifierExtension")
.setValue(new StringType("modifierValue2"));
p.addExtension()
.setUrl("http://acme.org/parentExtension")
.addExtension()
.setUrl("http://acme.org/childExtension")
.setValue(new StringType("nestedValue1"));
p.addExtension()
.setUrl("http://acme.org/parentExtension")
.addExtension()
.setUrl("http://acme.org/childExtension")
.setValue(new StringType("nestedValue2"));
System.out.println(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p));
List<Object> values = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/extension')");
assertEquals(2, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof Extension);
assertEquals("http://acme.org/extension", ((Extension) values.get(0)).getUrl());
assertEquals("value1", ((StringType) ((Extension) values.get(0)).getValue()).getValueAsString());
assertTrue(values.get(1) instanceof IBaseExtension);
assertTrue(values.get(1) instanceof Extension);
assertEquals("http://acme.org/extension", ((Extension) values.get(1)).getUrl());
assertEquals("value2", ((StringType) ((Extension) values.get(1)).getValue()).getValueAsString());
values = ourCtx.newTerser().getValues(p, "Patient.modifierExtension('http://acme.org/modifierExtension')");
assertEquals(2, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof Extension);
assertEquals("http://acme.org/modifierExtension", ((Extension) values.get(0)).getUrl());
assertEquals("modifierValue1", ((StringType) ((Extension) values.get(0)).getValue()).getValueAsString());
assertTrue(values.get(1) instanceof IBaseExtension);
assertTrue(values.get(1) instanceof Extension);
assertEquals("http://acme.org/modifierExtension", ((Extension) values.get(1)).getUrl());
assertEquals("modifierValue2", ((StringType) ((Extension) values.get(1)).getValue()).getValueAsString());
values = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/parentExtension').extension('http://acme.org/childExtension')");
assertEquals(2, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof Extension);
assertEquals("http://acme.org/childExtension", ((Extension) values.get(0)).getUrl());
assertEquals("nestedValue1", ((StringType) ((Extension) values.get(0)).getValue()).getValueAsString());
assertTrue(values.get(1) instanceof IBaseExtension);
assertTrue(values.get(1) instanceof Extension);
assertEquals("http://acme.org/childExtension", ((Extension) values.get(1)).getUrl());
assertEquals("nestedValue2", ((StringType) ((Extension) values.get(1)).getValue()).getValueAsString());
}
@Test
public void testGetValuesWithWantedClass() {
Patient p = new Patient();
p.setActive(true);
p.addExtension()
.setUrl("http://acme.org/extension")
.setValue(new StringType("value"));
p.addExtension()
.setUrl("http://acme.org/otherExtension")
.setValue(new StringType("otherValue"));
p.addModifierExtension()
.setUrl("http://acme.org/modifierExtension")
.setValue(new StringType("modifierValue"));
p.addExtension()
.setUrl("http://acme.org/parentExtension")
.addExtension()
.setUrl("http://acme.org/childExtension")
.setValue(new StringType("nestedValue"));
System.out.println(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p));
List<PrimitiveType> values = ourCtx.newTerser().getValues(p, "Patient.active", PrimitiveType.class);
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof BooleanType);
assertTrue(((BooleanType) values.get(0)).booleanValue());
List<Extension> extValues = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/extension')", Extension.class);
assertEquals(1, extValues.size());
assertTrue(extValues.get(0).getValue() instanceof StringType);
assertEquals("http://acme.org/extension", extValues.get(0).getUrl());
assertEquals("value", ((StringType) (extValues.get(0).getValue())).getValueAsString());
extValues = ourCtx.newTerser().getValues(p, "Patient.modifierExtension('http://acme.org/modifierExtension')", Extension.class);
assertEquals(1, extValues.size());
assertTrue(extValues.get(0).getValue() instanceof StringType);
assertEquals("http://acme.org/modifierExtension", extValues.get(0).getUrl());
assertEquals("modifierValue", ((StringType) (extValues.get(0).getValue())).getValueAsString());
extValues = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/parentExtension').extension('http://acme.org/childExtension')", Extension.class);
assertEquals(1, extValues.size());
assertTrue(extValues.get(0).getValue() instanceof StringType);
assertEquals("http://acme.org/childExtension", extValues.get(0).getUrl());
assertEquals("nestedValue", ((StringType) extValues.get(0).getValue()).getValueAsString());
}
@Test
public void testGetValuesWithWantedClassAndModify() {
Patient p = new Patient();
p.setActive(true);
p.addExtension()
.setUrl("http://acme.org/extension")
.setValue(new StringType("value"));
p.addExtension()
.setUrl("http://acme.org/otherExtension")
.setValue(new StringType("otherValue"));
p.addModifierExtension()
.setUrl("http://acme.org/modifierExtension")
.setValue(new StringType("modifierValue"));
p.addExtension()
.setUrl("http://acme.org/parentExtension")
.addExtension()
.setUrl("http://acme.org/childExtension")
.setValue(new StringType("nestedValue"));
System.out.println(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p));
List<PrimitiveType> values = ourCtx.newTerser().getValues(p, "Patient.active", PrimitiveType.class);
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof BooleanType);
assertTrue(((BooleanType) values.get(0)).booleanValue());
((BooleanType) values.get(0)).setValue(Boolean.FALSE);
System.out.println(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p));
values = ourCtx.newTerser().getValues(p, "Patient.active", PrimitiveType.class);
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof BooleanType);
assertFalse(((BooleanType) values.get(0)).booleanValue());
List<Extension> extValues = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/extension')", Extension.class);
assertEquals(1, extValues.size());
assertTrue(extValues.get(0).getValue() instanceof StringType);
assertEquals("http://acme.org/extension", extValues.get(0).getUrl());
assertEquals("value", ((StringType) (extValues.get(0).getValue())).getValueAsString());
extValues.get(0).setValue(new StringType("modifiedValue"));
System.out.println(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p));
extValues = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/extension')", Extension.class);
assertEquals(1, extValues.size());
assertTrue(extValues.get(0).getValue() instanceof StringType);
assertEquals("http://acme.org/extension", extValues.get(0).getUrl());
assertEquals("modifiedValue", ((StringType) (extValues.get(0).getValue())).getValueAsString());
extValues = ourCtx.newTerser().getValues(p, "Patient.modifierExtension('http://acme.org/modifierExtension')", Extension.class);
assertEquals(1, extValues.size());
assertTrue(extValues.get(0).getValue() instanceof StringType);
assertEquals("http://acme.org/modifierExtension", extValues.get(0).getUrl());
assertEquals("modifierValue", ((StringType) (extValues.get(0).getValue())).getValueAsString());
extValues.get(0).setValue(new StringType("modifiedModifierValue"));
System.out.println(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p));
extValues = ourCtx.newTerser().getValues(p, "Patient.modifierExtension('http://acme.org/modifierExtension')", Extension.class);
assertEquals(1, extValues.size());
assertTrue(extValues.get(0).getValue() instanceof StringType);
assertEquals("http://acme.org/modifierExtension", extValues.get(0).getUrl());
assertEquals("modifiedModifierValue", ((StringType) (extValues.get(0).getValue())).getValueAsString());
extValues = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/parentExtension').extension('http://acme.org/childExtension')", Extension.class);
assertEquals(1, extValues.size());
assertTrue(extValues.get(0).getValue() instanceof StringType);
assertEquals("http://acme.org/childExtension", extValues.get(0).getUrl());
assertEquals("nestedValue", ((StringType) extValues.get(0).getValue()).getValueAsString());
extValues.get(0).setValue(new StringType("modifiedNestedValue"));
System.out.println(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p));
extValues = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/parentExtension').extension('http://acme.org/childExtension')", Extension.class);
assertEquals(1, extValues.size());
assertTrue(extValues.get(0).getValue() instanceof StringType);
assertEquals("http://acme.org/childExtension", extValues.get(0).getUrl());
assertEquals("modifiedNestedValue", ((StringType) extValues.get(0).getValue()).getValueAsString());
}
@Test
public void testGetValuesWithWantedClassAndTheCreate() {
Patient p = new Patient();
System.out.println(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p));
List<PrimitiveType> values = ourCtx.newTerser().getValues(p, "Patient.active", PrimitiveType.class, true);
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof BooleanType);
assertNull(((BooleanType) values.get(0)).getValue());
List<Extension> extValues = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/extension')", Extension.class, true);
assertEquals(1, extValues.size());
assertEquals("http://acme.org/extension", extValues.get(0).getUrl());
assertNull(extValues.get(0).getValue());
extValues = ourCtx.newTerser().getValues(p, "Patient.modifierExtension('http://acme.org/modifierExtension')", Extension.class, true);
assertEquals(1, extValues.size());
assertEquals("http://acme.org/modifierExtension", extValues.get(0).getUrl());
assertNull(extValues.get(0).getValue());
extValues = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/parentExtension').extension('http://acme.org/childExtension')", Extension.class, true);
assertEquals(1, extValues.size());
assertEquals("http://acme.org/childExtension", extValues.get(0).getUrl());
assertNull(extValues.get(0).getValue());
}
@Test
public void testGetValuesWithTheAddExtensionAndModify() {
Patient p = new Patient();
p.setActive(true);
p.addExtension()
.setUrl("http://acme.org/extension")
.setValue(new StringType("value"));
p.addExtension()
.setUrl("http://acme.org/otherExtension")
.setValue(new StringType("otherValue"));
p.addModifierExtension()
.setUrl("http://acme.org/modifierExtension")
.setValue(new StringType("modifierValue"));
p.addExtension()
.setUrl("http://acme.org/parentExtension")
.addExtension()
.setUrl("http://acme.org/childExtension")
.setValue(new StringType("nestedValue"));
System.out.println(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p));
List<Object> values = ourCtx.newTerser().getValues(p, "Patient.active");
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof PrimitiveType);
assertTrue(values.get(0) instanceof BooleanType);
assertTrue(((BooleanType) values.get(0)).booleanValue());
// No change.
values = ourCtx.newTerser().getValues(p, "Patient.active", false, true);
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof PrimitiveType);
assertTrue(values.get(0) instanceof BooleanType);
assertTrue(((BooleanType) values.get(0)).booleanValue());
values = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/extension')");
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof Extension);
assertEquals("http://acme.org/extension", ((Extension) values.get(0)).getUrl());
assertEquals("value", ((StringType) ((Extension) values.get(0)).getValue()).getValueAsString());
values = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/extension')", false, true);
assertEquals(2, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof Extension);
assertEquals("http://acme.org/extension", ((Extension) values.get(0)).getUrl());
assertEquals("value", ((StringType) ((Extension) values.get(0)).getValue()).getValueAsString());
assertTrue(values.get(1) instanceof IBaseExtension);
assertTrue(values.get(1) instanceof Extension);
assertEquals("http://acme.org/extension", ((Extension) values.get(1)).getUrl());
assertNull(((Extension) values.get(1)).getValue());
((Extension) values.get(1)).setValue(new StringType("addedValue"));
System.out.println(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p));
assertTrue(values.get(1) instanceof IBaseExtension);
assertTrue(values.get(1) instanceof Extension);
assertEquals("http://acme.org/extension", ((Extension) values.get(1)).getUrl());
assertEquals("addedValue", ((StringType) ((Extension) values.get(1)).getValue()).getValueAsString());
values = ourCtx.newTerser().getValues(p, "Patient.modifierExtension('http://acme.org/modifierExtension')");
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof Extension);
assertEquals("http://acme.org/modifierExtension", ((Extension) values.get(0)).getUrl());
assertEquals("modifierValue", ((StringType) ((Extension) values.get(0)).getValue()).getValueAsString());
values = ourCtx.newTerser().getValues(p, "Patient.modifierExtension('http://acme.org/modifierExtension')", false, true);
assertEquals(2, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof Extension);
assertEquals("http://acme.org/modifierExtension", ((Extension) values.get(0)).getUrl());
assertEquals("modifierValue", ((StringType) ((Extension) values.get(0)).getValue()).getValueAsString());
assertTrue(values.get(1) instanceof IBaseExtension);
assertTrue(values.get(1) instanceof Extension);
assertEquals("http://acme.org/modifierExtension", ((Extension) values.get(1)).getUrl());
assertNull(((Extension) values.get(1)).getValue());
((Extension) values.get(1)).setValue(new StringType("addedModifierValue"));
System.out.println(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p));
assertTrue(values.get(1) instanceof IBaseExtension);
assertTrue(values.get(1) instanceof Extension);
assertEquals("http://acme.org/modifierExtension", ((Extension) values.get(1)).getUrl());
assertEquals("addedModifierValue", ((StringType) ((Extension) values.get(1)).getValue()).getValueAsString());
System.out.println(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p));
values = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/parentExtension').extension('http://acme.org/childExtension')");
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof Extension);
assertEquals("http://acme.org/childExtension", ((Extension) values.get(0)).getUrl());
assertEquals("nestedValue", ((StringType) ((Extension) values.get(0)).getValue()).getValueAsString());
values = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/parentExtension').extension('http://acme.org/childExtension')", false, true);
assertEquals(2, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof Extension);
assertEquals("http://acme.org/childExtension", ((Extension) values.get(0)).getUrl());
assertEquals("nestedValue", ((StringType) ((Extension) values.get(0)).getValue()).getValueAsString());
assertTrue(values.get(1) instanceof IBaseExtension);
assertTrue(values.get(1) instanceof Extension);
assertEquals("http://acme.org/childExtension", ((Extension) values.get(1)).getUrl());
assertNull(((Extension) values.get(1)).getValue());
((Extension) values.get(1)).setValue(new StringType("addedNestedValue"));
System.out.println(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p));
assertTrue(values.get(1) instanceof IBaseExtension);
assertTrue(values.get(1) instanceof Extension);
assertEquals("http://acme.org/childExtension", ((Extension) values.get(1)).getUrl());
assertEquals("addedNestedValue", ((StringType) ((Extension) values.get(1)).getValue()).getValueAsString());
}
@Test
public void testGetValuesWithTheCreate() {
Patient p = new Patient();
List<Object> values = ourCtx.newTerser().getValues(p, "Patient.active", true);
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof PrimitiveType);
assertTrue(values.get(0) instanceof BooleanType);
assertNull(((BooleanType) values.get(0)).getValue());
values = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/extension')", true);
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof Extension);
assertEquals("http://acme.org/extension", ((Extension) values.get(0)).getUrl());
assertNull(((Extension) values.get(0)).getValue());
values = ourCtx.newTerser().getValues(p, "Patient.modifierExtension('http://acme.org/modifierExtension')", true);
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof Extension);
assertEquals("http://acme.org/modifierExtension", ((Extension) values.get(0)).getUrl());
assertNull(((Extension) values.get(0)).getValue());
values = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/parentExtension').extension('http://acme.org/childExtension')", true);
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof Extension);
assertEquals("http://acme.org/childExtension", ((Extension) values.get(0)).getUrl());
assertNull(((Extension) values.get(0)).getValue());
}
@Test
public void testGetValuesWithTheCreateAndTheAddExtensionAndModify() {
Patient p = new Patient();
p.setActive(true);
p.addExtension()
.setUrl("http://acme.org/extension")
.setValue(new StringType("value"));
p.addExtension()
.setUrl("http://acme.org/otherExtension")
.setValue(new StringType("otherValue"));
p.addModifierExtension()
.setUrl("http://acme.org/modifierExtension")
.setValue(new StringType("modifierValue"));
p.addExtension()
.setUrl("http://acme.org/parentExtension")
.addExtension()
.setUrl("http://acme.org/childExtension")
.setValue(new StringType("nestedValue"));
System.out.println(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p));
List<Object> values = ourCtx.newTerser().getValues(p, "Patient.active");
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof PrimitiveType);
assertTrue(values.get(0) instanceof BooleanType);
assertTrue(((BooleanType) values.get(0)).booleanValue());
// No change.
values = ourCtx.newTerser().getValues(p, "Patient.active", true, true);
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof PrimitiveType);
assertTrue(values.get(0) instanceof BooleanType);
assertTrue(((BooleanType) values.get(0)).booleanValue());
values = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/extension')");
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof Extension);
assertEquals("http://acme.org/extension", ((Extension) values.get(0)).getUrl());
assertEquals("value", ((StringType) ((Extension) values.get(0)).getValue()).getValueAsString());
values = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/extension')", true, true);
assertEquals(2, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof Extension);
assertEquals("http://acme.org/extension", ((Extension) values.get(0)).getUrl());
assertEquals("value", ((StringType) ((Extension) values.get(0)).getValue()).getValueAsString());
assertTrue(values.get(1) instanceof IBaseExtension);
assertTrue(values.get(1) instanceof Extension);
assertEquals("http://acme.org/extension", ((Extension) values.get(1)).getUrl());
assertNull(((Extension) values.get(1)).getValue());
((Extension) values.get(1)).setValue(new StringType("addedValue"));
System.out.println(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p));
assertTrue(values.get(1) instanceof IBaseExtension);
assertTrue(values.get(1) instanceof Extension);
assertEquals("http://acme.org/extension", ((Extension) values.get(1)).getUrl());
assertEquals("addedValue", ((StringType) ((Extension) values.get(1)).getValue()).getValueAsString());
values = ourCtx.newTerser().getValues(p, "Patient.modifierExtension('http://acme.org/modifierExtension')");
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof Extension);
assertEquals("http://acme.org/modifierExtension", ((Extension) values.get(0)).getUrl());
assertEquals("modifierValue", ((StringType) ((Extension) values.get(0)).getValue()).getValueAsString());
values = ourCtx.newTerser().getValues(p, "Patient.modifierExtension('http://acme.org/modifierExtension')", true, true);
assertEquals(2, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof Extension);
assertEquals("http://acme.org/modifierExtension", ((Extension) values.get(0)).getUrl());
assertEquals("modifierValue", ((StringType) ((Extension) values.get(0)).getValue()).getValueAsString());
assertTrue(values.get(1) instanceof IBaseExtension);
assertTrue(values.get(1) instanceof Extension);
assertEquals("http://acme.org/modifierExtension", ((Extension) values.get(1)).getUrl());
assertNull(((Extension) values.get(1)).getValue());
((Extension) values.get(1)).setValue(new StringType("addedModifierValue"));
System.out.println(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p));
assertTrue(values.get(1) instanceof IBaseExtension);
assertTrue(values.get(1) instanceof Extension);
assertEquals("http://acme.org/modifierExtension", ((Extension) values.get(1)).getUrl());
assertEquals("addedModifierValue", ((StringType) ((Extension) values.get(1)).getValue()).getValueAsString());
values = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/parentExtension').extension('http://acme.org/childExtension')");
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof Extension);
assertEquals("http://acme.org/childExtension", ((Extension) values.get(0)).getUrl());
assertEquals("nestedValue", ((StringType) ((Extension) values.get(0)).getValue()).getValueAsString());
values = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/parentExtension').extension('http://acme.org/childExtension')", true, true);
assertEquals(2, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof Extension);
assertEquals("http://acme.org/childExtension", ((Extension) values.get(0)).getUrl());
assertEquals("nestedValue", ((StringType) ((Extension) values.get(0)).getValue()).getValueAsString());
assertTrue(values.get(1) instanceof IBaseExtension);
assertTrue(values.get(1) instanceof Extension);
assertEquals("http://acme.org/childExtension", ((Extension) values.get(1)).getUrl());
assertNull(((Extension) values.get(1)).getValue());
((Extension) values.get(1)).setValue(new StringType("addedNestedValue"));
System.out.println(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p));
assertTrue(values.get(1) instanceof IBaseExtension);
assertTrue(values.get(1) instanceof Extension);
assertEquals("http://acme.org/childExtension", ((Extension) values.get(1)).getUrl());
assertEquals("addedNestedValue", ((StringType) ((Extension) values.get(1)).getValue()).getValueAsString());
}
@Test
public void testGetValuesWithTheCreateAndNoOverwrite() {
Patient p = new Patient();
p.setActive(true);
p.addExtension()
.setUrl("http://acme.org/extension")
.setValue(new StringType("value"));
p.addExtension()
.setUrl("http://acme.org/otherExtension")
.setValue(new StringType("otherValue"));
p.addModifierExtension()
.setUrl("http://acme.org/modifierExtension")
.setValue(new StringType("modifierValue"));
p.addExtension()
.setUrl("http://acme.org/parentExtension")
.addExtension()
.setUrl("http://acme.org/childExtension")
.setValue(new StringType("nestedValue"));
System.out.println(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p));
List<Object> values = ourCtx.newTerser().getValues(p, "Patient.active", true);
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof PrimitiveType);
assertTrue(values.get(0) instanceof BooleanType);
assertTrue(((BooleanType) values.get(0)).booleanValue());
values = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/extension')", true);
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof Extension);
assertEquals("http://acme.org/extension", ((Extension) values.get(0)).getUrl());
assertEquals("value", ((StringType) ((Extension) values.get(0)).getValue()).getValueAsString());
values = ourCtx.newTerser().getValues(p, "Patient.modifierExtension('http://acme.org/modifierExtension')", true);
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof Extension);
assertEquals("http://acme.org/modifierExtension", ((Extension) values.get(0)).getUrl());
assertEquals("modifierValue", ((StringType) ((Extension) values.get(0)).getValue()).getValueAsString());
values = ourCtx.newTerser().getValues(p, "Patient.extension('http://acme.org/parentExtension').extension('http://acme.org/childExtension')", true);
assertEquals(1, values.size());
assertTrue(values.get(0) instanceof IBaseExtension);
assertTrue(values.get(0) instanceof Extension);
assertEquals("http://acme.org/childExtension", ((Extension) values.get(0)).getUrl());
assertEquals("nestedValue", ((StringType) ((Extension) values.get(0)).getValue()).getValueAsString());
}
@Test @Test
public void testVisitWithModelVisitor2() { public void testVisitWithModelVisitor2() {
IModelVisitor2 visitor = mock(IModelVisitor2.class); IModelVisitor2 visitor = mock(IModelVisitor2.class);

View File

@ -116,6 +116,15 @@
<![CDATA[<a href="https://github.com/hapifhir/hapi-fhir-jpaserver-starter/blob/master/src/main/java/ca/uhn/fhir/jpa/demo/FhirServerConfig.java#L62">the example project</a>]]> <![CDATA[<a href="https://github.com/hapifhir/hapi-fhir-jpaserver-starter/blob/master/src/main/java/ca/uhn/fhir/jpa/demo/FhirServerConfig.java#L62">the example project</a>]]>
if they are not already. if they are not already.
</action> </action>
<action type="add">
The FhirTerser <![CDATA[<code>getValues(...)</code>]]> methods have been overloaded. The terser can now be
used to create a null-valued element where none exists. Additionally, the terser can now add a null-valued
extension where one or more such extensions already exist. These changes allow better population of FHIR
elements provided an arbitrary FHIR path.
</action>
<action type="fix">
The FhirTerser <![CDATA[<code>getValues(...)</code>]]> methods were not properly handling modifier
extensions for verions of FHIR prior to DSTU3. This has been corrected.
<action type="fix"> <action type="fix">
When updating resources in the JPA server, a bug caused index table entries to be refreshed When updating resources in the JPA server, a bug caused index table entries to be refreshed
sometimes even though the index value hadn't changed. This issue did not cause incorrect search sometimes even though the index value hadn't changed. This issue did not cause incorrect search