Merge remote-tracking branch 'origin/master' into do-20240830-maven-compiler-update
This commit is contained in:
commit
9fb7c83e40
|
@ -1,7 +1,18 @@
|
|||
## Validator Changes
|
||||
|
||||
* no changes
|
||||
* Fix expression for con-3 properly (fix validation problem on some condition resources)
|
||||
* Fix FHIRPath bug using wrong type on simple elements when checking FHIRPath types
|
||||
* FHIRPath: Allow _ in constant names (per FHIRPath spec)
|
||||
* Fix value set rendering creating wrong references
|
||||
* Fix bug processing value set includes / excludes that are just value sets (no system value)
|
||||
* Alter processing of unknown code systems per discussion at ,https://chat.fhir.org/#narrow/stream/179252-IG-creation/topic/Don't.20error.20when.20you.20can't.20find.20code.20system and implement unknown-codesystems-cause-errors
|
||||
* Improve message for when elements are out of order in profile differentials
|
||||
|
||||
|
||||
## Other code changes
|
||||
|
||||
* no changes
|
||||
* fix problem where profile rendering had spurious 'slices for' nodes everywhere
|
||||
* Update SQL-On-FHIR implementation for latest cases, and clone test cases to general test care repository
|
||||
* Fix problem generating value set spreadsheets
|
||||
* fix concurrent modification error processing language translations
|
||||
* Check for null fetcher processing ConceptMaps (#1728)
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>org.hl7.fhir.core</artifactId>
|
||||
<version>6.3.24-SNAPSHOT</version>
|
||||
<version>6.3.26-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>org.hl7.fhir.core</artifactId>
|
||||
<version>6.3.24-SNAPSHOT</version>
|
||||
<version>6.3.26-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>org.hl7.fhir.core</artifactId>
|
||||
<version>6.3.24-SNAPSHOT</version>
|
||||
<version>6.3.26-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>org.hl7.fhir.core</artifactId>
|
||||
<version>6.3.24-SNAPSHOT</version>
|
||||
<version>6.3.26-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>org.hl7.fhir.core</artifactId>
|
||||
<version>6.3.24-SNAPSHOT</version>
|
||||
<version>6.3.26-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>org.hl7.fhir.core</artifactId>
|
||||
<version>6.3.24-SNAPSHOT</version>
|
||||
<version>6.3.26-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>org.hl7.fhir.core</artifactId>
|
||||
<version>6.3.24-SNAPSHOT</version>
|
||||
<version>6.3.26-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -289,7 +289,7 @@ public class ProfilePathProcessor {
|
|||
start++;
|
||||
} else {
|
||||
// we're just going to accept the differential slicing at face value
|
||||
ElementDefinition outcome = profileUtilities.updateURLs(getUrl(), getWebUrl(), currentBase.copy());
|
||||
ElementDefinition outcome = profileUtilities.updateURLs(getUrl(), getWebUrl(), currentBase.copy(), true);
|
||||
outcome.setPath(profileUtilities.fixedPathDest(getContextPathTarget(), outcome.getPath(), getRedirector(), getContextPathSource()));
|
||||
profileUtilities.updateFromBase(outcome, currentBase, getSourceStructureDefinition().getUrl());
|
||||
|
||||
|
@ -667,14 +667,14 @@ public class ProfilePathProcessor {
|
|||
// some of what's in currentBase overrides template
|
||||
template = profileUtilities.fillOutFromBase(template, currentBase);
|
||||
|
||||
ElementDefinition outcome = profileUtilities.updateURLs(getUrl(), getWebUrl(), template);
|
||||
ElementDefinition outcome = profileUtilities.updateURLs(getUrl(), getWebUrl(), template, true);
|
||||
outcome.setPath(profileUtilities.fixedPathDest(getContextPathTarget(), outcome.getPath(), getRedirector(), getContextPathSource()));
|
||||
|
||||
res = outcome;
|
||||
profileUtilities.updateFromBase(outcome, currentBase, getSourceStructureDefinition().getUrl());
|
||||
if (diffMatches.get(0).hasSliceName()) {
|
||||
template = currentBase.copy();
|
||||
template = profileUtilities.updateURLs(getUrl(), getWebUrl(), template);
|
||||
template = profileUtilities.updateURLs(getUrl(), getWebUrl(), template, true);
|
||||
template.setPath(profileUtilities.fixedPathDest(getContextPathTarget(), template.getPath(), getRedirector(), getContextPathSource()));
|
||||
|
||||
checkToSeeIfSlicingExists(diffMatches.get(0), template);
|
||||
|
@ -866,13 +866,13 @@ public class ProfilePathProcessor {
|
|||
|
||||
|
||||
private void processSimplePathWithEmptyDiffMatches(ElementDefinition currentBase, String currentBasePath, List<ElementDefinition> diffMatches, ProfilePathProcessorState cursors, MappingAssistant mapHelper) {
|
||||
ElementDefinition outcome = profileUtilities.updateURLs(getUrl(), getWebUrl(), currentBase.copy());
|
||||
ElementDefinition outcome = profileUtilities.updateURLs(getUrl(), getWebUrl(), currentBase.copy(), true);
|
||||
outcome.setPath(profileUtilities.fixedPathDest(getContextPathTarget(), outcome.getPath(), getRedirector(), getContextPathSource()));
|
||||
profileUtilities.updateFromBase(outcome, currentBase, getSourceStructureDefinition().getUrl());
|
||||
profileUtilities.updateConstraintSources(outcome, getSourceStructureDefinition().getUrl());
|
||||
profileUtilities.checkExtensions(outcome);
|
||||
profileUtilities.updateFromObligationProfiles(outcome);
|
||||
profileUtilities.updateURLs(url, webUrl, outcome);
|
||||
profileUtilities.updateURLs(url, webUrl, outcome, true);
|
||||
profileUtilities.markDerived(outcome);
|
||||
if (cursors.resultPathBase == null)
|
||||
cursors.resultPathBase = outcome.getPath();
|
||||
|
@ -1033,7 +1033,7 @@ public class ProfilePathProcessor {
|
|||
if (!currentBase.isChoice() && !profileUtilities.ruleMatches(dSlice.getRules(), bSlice.getRules()))
|
||||
throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.SLICING_RULES_ON_DIFFERENTIAL__DO_NOT_MATCH_THOSE_ON_BASE___RULE___, profileUtilities.summarizeSlicing(dSlice), profileUtilities.summarizeSlicing(bSlice), path, cursors.contextName));
|
||||
}
|
||||
ElementDefinition outcome = profileUtilities.updateURLs(getUrl(), getWebUrl(), currentBase.copy());
|
||||
ElementDefinition outcome = profileUtilities.updateURLs(getUrl(), getWebUrl(), currentBase.copy(), true);
|
||||
outcome.setPath(profileUtilities.fixedPathDest(getContextPathTarget(), outcome.getPath(), getRedirector(), getContextPathSource()));
|
||||
profileUtilities.updateFromBase(outcome, currentBase, getSourceStructureDefinition().getUrl());
|
||||
if (diffMatches.get(0).hasSlicing() || !diffMatches.get(0).hasSliceName()) {
|
||||
|
@ -1095,7 +1095,7 @@ public class ProfilePathProcessor {
|
|||
// We need to copy children of the backbone element before we start messing around with slices
|
||||
int newBaseLimit = profileUtilities.findEndOfElement(cursors.base, cursors.baseCursor);
|
||||
for (int i = cursors.baseCursor + 1; i <= newBaseLimit; i++) {
|
||||
outcome = profileUtilities.updateURLs(getUrl(), getWebUrl(), cursors.base.getElement().get(i).copy());
|
||||
outcome = profileUtilities.updateURLs(getUrl(), getWebUrl(), cursors.base.getElement().get(i).copy(), true);
|
||||
outcome.setPath(profileUtilities.fixedPathDest(getContextPathTarget(), outcome.getPath(), getRedirector(), getContextPathSource()));
|
||||
debugCheck(outcome);
|
||||
getResult().getElement().add(outcome);
|
||||
|
@ -1106,7 +1106,7 @@ public class ProfilePathProcessor {
|
|||
List<ElementDefinition> baseMatches = profileUtilities.getSiblings(cursors.base.getElement(), currentBase);
|
||||
for (ElementDefinition baseItem : baseMatches) {
|
||||
cursors.baseCursor = cursors.base.getElement().indexOf(baseItem);
|
||||
outcome = profileUtilities.updateURLs(getUrl(), getWebUrl(), baseItem.copy());
|
||||
outcome = profileUtilities.updateURLs(getUrl(), getWebUrl(), baseItem.copy(), true);
|
||||
profileUtilities.updateFromBase(outcome, currentBase, getSourceStructureDefinition().getUrl());
|
||||
outcome.setPath(profileUtilities.fixedPathDest(getContextPathTarget(), outcome.getPath(), getRedirector(), getContextPathSource()));
|
||||
outcome.setSlicing(null);
|
||||
|
@ -1139,7 +1139,7 @@ public class ProfilePathProcessor {
|
|||
cursors.baseCursor++;
|
||||
// just copy any children on the base
|
||||
while (cursors.baseCursor < cursors.base.getElement().size() && cursors.base.getElement().get(cursors.baseCursor).getPath().startsWith(path) && !cursors.base.getElement().get(cursors.baseCursor).getPath().equals(path)) {
|
||||
outcome = profileUtilities.updateURLs(getUrl(), getWebUrl(), cursors.base.getElement().get(cursors.baseCursor).copy());
|
||||
outcome = profileUtilities.updateURLs(getUrl(), getWebUrl(), cursors.base.getElement().get(cursors.baseCursor).copy(), true);
|
||||
outcome.setPath(profileUtilities.fixedPathDest(getContextPathTarget(), outcome.getPath(), getRedirector(), getContextPathSource()));
|
||||
if (!outcome.getPath().startsWith(cursors.resultPathBase))
|
||||
throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.ADDING_WRONG_PATH));
|
||||
|
@ -1166,7 +1166,7 @@ public class ProfilePathProcessor {
|
|||
for (ElementDefinition baseItem : baseMatches)
|
||||
if (baseItem.getSliceName().equals(diffItem.getSliceName()))
|
||||
throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.NAMED_ITEMS_ARE_OUT_OF_ORDER_IN_THE_SLICE));
|
||||
outcome = profileUtilities.updateURLs(getUrl(), getWebUrl(), currentBase.copy());
|
||||
outcome = profileUtilities.updateURLs(getUrl(), getWebUrl(), currentBase.copy(), true);
|
||||
// outcome = updateURLs(url, diffItem.copy());
|
||||
outcome.setPath(profileUtilities.fixedPathDest(getContextPathTarget(), outcome.getPath(), getRedirector(), getContextPathSource()));
|
||||
profileUtilities.updateFromBase(outcome, currentBase, getSourceStructureDefinition().getUrl());
|
||||
|
@ -1409,7 +1409,7 @@ public class ProfilePathProcessor {
|
|||
private void processPathWithSlicedBaseAndEmptyDiffMatches(ElementDefinition currentBase, String currentBasePath, List<ElementDefinition> diffMatches, ProfilePathProcessorState cursors, String path, MappingAssistant mapHelper) {
|
||||
if (profileUtilities.hasInnerDiffMatches(getDifferential(), path, cursors.diffCursor, getDiffLimit(), cursors.base.getElement(), true)) {
|
||||
// so we just copy it in
|
||||
ElementDefinition outcome = profileUtilities.updateURLs(getUrl(), getWebUrl(), currentBase.copy());
|
||||
ElementDefinition outcome = profileUtilities.updateURLs(getUrl(), getWebUrl(), currentBase.copy(), true);
|
||||
outcome.setPath(profileUtilities.fixedPathDest(getContextPathTarget(), outcome.getPath(), getRedirector(), getContextPathSource()));
|
||||
profileUtilities.updateFromBase(outcome, currentBase, getSourceStructureDefinition().getUrl());
|
||||
profileUtilities.markDerived(outcome);
|
||||
|
@ -1457,7 +1457,7 @@ public class ProfilePathProcessor {
|
|||
// the differential doesn't say anything about this item
|
||||
// copy across the currentbase, and all of its children and siblings
|
||||
while (cursors.baseCursor < cursors.base.getElement().size() && cursors.base.getElement().get(cursors.baseCursor).getPath().startsWith(path)) {
|
||||
ElementDefinition outcome = profileUtilities.updateURLs(getUrl(), getWebUrl(), cursors.base.getElement().get(cursors.baseCursor).copy());
|
||||
ElementDefinition outcome = profileUtilities.updateURLs(getUrl(), getWebUrl(), cursors.base.getElement().get(cursors.baseCursor).copy(), true);
|
||||
outcome.setPath(profileUtilities.fixedPathDest(getContextPathTarget(), outcome.getPath(), getRedirector(), getContextPathSource()));
|
||||
if (!outcome.getPath().startsWith(cursors.resultPathBase))
|
||||
throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.ADDING_WRONG_PATH_IN_PROFILE___VS_, getProfileName(), outcome.getPath(), cursors.resultPathBase));
|
||||
|
|
|
@ -739,7 +739,7 @@ public class ProfileUtilities {
|
|||
if (existing != null) {
|
||||
updateFromDefinition(existing, e, profileName, false, url, base, derived, "StructureDefinition.differential.element["+i+"]", mappingDetails);
|
||||
} else {
|
||||
ElementDefinition outcome = updateURLs(url, webUrl, e.copy());
|
||||
ElementDefinition outcome = updateURLs(url, webUrl, e.copy(), true);
|
||||
e.setUserData(UD_GENERATED_IN_SNAPSHOT, outcome);
|
||||
derived.getSnapshot().addElement(outcome);
|
||||
if (walksInto(diff.getElement(), e)) {
|
||||
|
@ -1042,7 +1042,7 @@ public class ProfileUtilities {
|
|||
// don't do this. should already be in snapshot ... addInheritedElementsForSpecialization(snapshot, focus, sd.getBaseDefinition(), path, url, weburl);
|
||||
for (ElementDefinition ed : sd.getSnapshot().getElement()) {
|
||||
if (ed.getPath().contains(".")) {
|
||||
ElementDefinition outcome = updateURLs(url, weburl, ed.copy());
|
||||
ElementDefinition outcome = updateURLs(url, weburl, ed.copy(), true);
|
||||
outcome.setPath(outcome.getPath().replace(sd.getTypeName(), path));
|
||||
snapshot.getElement().add(outcome);
|
||||
} else {
|
||||
|
@ -1548,7 +1548,6 @@ public class ProfileUtilities {
|
|||
protected void removeStatusExtensions(ElementDefinition outcome) {
|
||||
outcome.removeExtension(ToolingExtensions.EXT_FMM_LEVEL);
|
||||
outcome.removeExtension(ToolingExtensions.EXT_FMM_SUPPORT);
|
||||
outcome.removeExtension(ToolingExtensions.EXT_FMM_DERIVED);
|
||||
outcome.removeExtension(ToolingExtensions.EXT_STANDARDS_STATUS);
|
||||
outcome.removeExtension(ToolingExtensions.EXT_NORMATIVE_VERSION);
|
||||
outcome.removeExtension(ToolingExtensions.EXT_WORKGROUP);
|
||||
|
@ -1911,7 +1910,7 @@ public class ProfileUtilities {
|
|||
* @param element - the Element to update
|
||||
* @return - the updated Element
|
||||
*/
|
||||
public ElementDefinition updateURLs(String url, String webUrl, ElementDefinition element) {
|
||||
public ElementDefinition updateURLs(String url, String webUrl, ElementDefinition element, boolean processRelatives) {
|
||||
if (element != null) {
|
||||
ElementDefinition defn = element;
|
||||
if (defn.hasBinding() && defn.getBinding().hasValueSet() && defn.getBinding().getValueSet().startsWith("#"))
|
||||
|
@ -1929,24 +1928,24 @@ public class ProfileUtilities {
|
|||
if (webUrl != null) {
|
||||
// also, must touch up the markdown
|
||||
if (element.hasDefinition()) {
|
||||
element.setDefinition(processRelativeUrls(element.getDefinition(), webUrl, context.getSpecUrl(), context.getResourceNames(), masterSourceFileNames, localFileNames, false));
|
||||
element.setDefinition(processRelativeUrls(element.getDefinition(), webUrl, context.getSpecUrl(), context.getResourceNames(), masterSourceFileNames, localFileNames, processRelatives));
|
||||
}
|
||||
if (element.hasComment()) {
|
||||
element.setComment(processRelativeUrls(element.getComment(), webUrl, context.getSpecUrl(), context.getResourceNames(), masterSourceFileNames, localFileNames, false));
|
||||
element.setComment(processRelativeUrls(element.getComment(), webUrl, context.getSpecUrl(), context.getResourceNames(), masterSourceFileNames, localFileNames, processRelatives));
|
||||
}
|
||||
if (element.hasRequirements()) {
|
||||
element.setRequirements(processRelativeUrls(element.getRequirements(), webUrl, context.getSpecUrl(), context.getResourceNames(), masterSourceFileNames, localFileNames, false));
|
||||
element.setRequirements(processRelativeUrls(element.getRequirements(), webUrl, context.getSpecUrl(), context.getResourceNames(), masterSourceFileNames, localFileNames, processRelatives));
|
||||
}
|
||||
if (element.hasMeaningWhenMissing()) {
|
||||
element.setMeaningWhenMissing(processRelativeUrls(element.getMeaningWhenMissing(), webUrl, context.getSpecUrl(), context.getResourceNames(), masterSourceFileNames, localFileNames, false));
|
||||
element.setMeaningWhenMissing(processRelativeUrls(element.getMeaningWhenMissing(), webUrl, context.getSpecUrl(), context.getResourceNames(), masterSourceFileNames, localFileNames, processRelatives));
|
||||
}
|
||||
if (element.hasBinding() && element.getBinding().hasDescription()) {
|
||||
element.getBinding().setDescription(processRelativeUrls(element.getBinding().getDescription(), webUrl, context.getSpecUrl(), context.getResourceNames(), masterSourceFileNames, localFileNames, false));
|
||||
element.getBinding().setDescription(processRelativeUrls(element.getBinding().getDescription(), webUrl, context.getSpecUrl(), context.getResourceNames(), masterSourceFileNames, localFileNames, processRelatives));
|
||||
}
|
||||
for (Extension ext : element.getExtension()) {
|
||||
if (ext.hasValueMarkdownType()) {
|
||||
MarkdownType md = ext.getValueMarkdownType();
|
||||
md.setValue(processRelativeUrls(md.getValue(), webUrl, context.getSpecUrl(), context.getResourceNames(), masterSourceFileNames, localFileNames, false));
|
||||
md.setValue(processRelativeUrls(md.getValue(), webUrl, context.getSpecUrl(), context.getResourceNames(), masterSourceFileNames, localFileNames, processRelatives));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2371,7 +2370,6 @@ public class ProfileUtilities {
|
|||
if (elist.size() == 2) {
|
||||
dest.getExtension().remove(elist.get(1));
|
||||
}
|
||||
|
||||
updateExtensionsFromDefinition(dest, source);
|
||||
|
||||
for (ElementDefinition ed : obligationProfileElements) {
|
||||
|
@ -2423,6 +2421,9 @@ public class ProfileUtilities {
|
|||
if (e.hasDefinition()) {
|
||||
base.setDefinition(processRelativeUrls(e.getDefinition(), webroot, context.getSpecUrl(), context.getResourceNames(), masterSourceFileNames, localFileNames, true));
|
||||
}
|
||||
if (e.getBinding().hasDescription()) {
|
||||
base.getBinding().setDescription(processRelativeUrls(e.getBinding().getDescription(), webroot, context.getSpecUrl(), context.getResourceNames(), masterSourceFileNames, localFileNames, true));
|
||||
}
|
||||
base.setShort(e.getShort());
|
||||
if (e.hasCommentElement())
|
||||
base.setCommentElement(e.getCommentElement());
|
||||
|
@ -2466,9 +2467,9 @@ public class ProfileUtilities {
|
|||
if (derived.hasDefinitionElement()) {
|
||||
if (derived.getDefinition().startsWith("..."))
|
||||
base.setDefinition(Utilities.appendDerivedTextToBase(base.getDefinition(), derived.getDefinition()));
|
||||
else if (!Base.compareDeep(derived.getDefinitionElement(), base.getDefinitionElement(), false))
|
||||
else if (!Base.compareDeep(derived.getDefinitionElement(), base.getDefinitionElement(), false)) {
|
||||
base.setDefinitionElement(derived.getDefinitionElement().copy());
|
||||
else if (trimDifferential)
|
||||
} else if (trimDifferential)
|
||||
derived.setDefinitionElement(null);
|
||||
else if (derived.hasDefinitionElement())
|
||||
derived.getDefinitionElement().setUserData(UD_DERIVATION_EQUALS, true);
|
||||
|
|
|
@ -934,10 +934,14 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
throw new Error(formatMessage(I18nConstants.NO_VALUE_SET_IN_URL));
|
||||
}
|
||||
for (ConceptSetComponent inc : vs.getCompose().getInclude()) {
|
||||
codeSystemsUsed.add(inc.getSystem());
|
||||
if (inc.hasSystem()) {
|
||||
codeSystemsUsed.add(inc.getSystem());
|
||||
}
|
||||
}
|
||||
for (ConceptSetComponent inc : vs.getCompose().getExclude()) {
|
||||
codeSystemsUsed.add(inc.getSystem());
|
||||
if (inc.hasSystem()) {
|
||||
codeSystemsUsed.add(inc.getSystem());
|
||||
}
|
||||
}
|
||||
|
||||
CacheToken cacheToken = txCache.generateExpandToken(vs, hierarchical);
|
||||
|
|
|
@ -366,7 +366,11 @@ public class ContextUtilities implements ProfileKnowledgeProvider {
|
|||
public StructureDefinition fetchByJsonName(String key) {
|
||||
for (StructureDefinition sd : context.fetchResourcesByType(StructureDefinition.class)) {
|
||||
ElementDefinition ed = sd.getSnapshot().getElementFirstRep();
|
||||
if (sd.getKind() == StructureDefinitionKind.LOGICAL && ed != null && ed.hasExtension(ToolingExtensions.EXT_JSON_NAME, ToolingExtensions.EXT_JSON_NAME_DEPRECATED) &&
|
||||
if (/*sd.getKind() == StructureDefinitionKind.LOGICAL && */
|
||||
// this is turned off because it's valid to use a FHIR type directly in
|
||||
// an extension of this kind, and that can't be a logical model. Any profile on
|
||||
// a type is acceptable as long as it has the json name on it
|
||||
ed != null && ed.hasExtension(ToolingExtensions.EXT_JSON_NAME, ToolingExtensions.EXT_JSON_NAME_DEPRECATED) &&
|
||||
key.equals(ToolingExtensions.readStringExtension(ed, ToolingExtensions.EXT_JSON_NAME, ToolingExtensions.EXT_JSON_NAME_DEPRECATED))) {
|
||||
return sd;
|
||||
}
|
||||
|
|
|
@ -187,7 +187,7 @@ public class FHIRLexer {
|
|||
cursor++;
|
||||
} else
|
||||
while (cursor < source.length() && ((source.charAt(cursor) >= 'A' && source.charAt(cursor) <= 'Z') || (source.charAt(cursor) >= 'a' && source.charAt(cursor) <= 'z') ||
|
||||
(source.charAt(cursor) >= '0' && source.charAt(cursor) <= '9') || source.charAt(cursor) == ':' || source.charAt(cursor) == '-'))
|
||||
(source.charAt(cursor) >= '0' && source.charAt(cursor) <= '9') || source.charAt(cursor) == ':' || source.charAt(cursor) == '-' || source.charAt(cursor) == '_'))
|
||||
cursor++;
|
||||
current = source.substring(currentStart, cursor);
|
||||
} else if (ch == '/') {
|
||||
|
|
|
@ -773,6 +773,25 @@ public class FHIRPathEngine {
|
|||
return execute(new ExecutionContext(null, base != null && base.isResource() ? base : null, base != null && base.isResource() ? base : null, base, base), list, ExpressionNode, true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* evaluate a path and return the matching elements
|
||||
*
|
||||
* @param base - the object against which the path is being evaluated
|
||||
* @param ExpressionNode - the parsed ExpressionNode statement to use
|
||||
* @return
|
||||
* @throws FHIRException
|
||||
* @
|
||||
*/
|
||||
public List<Base> evaluate(Object appContext, Base base, ExpressionNode ExpressionNode) throws FHIRException {
|
||||
List<Base> list = new ArrayList<Base>();
|
||||
if (base != null) {
|
||||
list.add(base);
|
||||
}
|
||||
log = new StringBuilder();
|
||||
return execute(new ExecutionContext(appContext, base != null && base.isResource() ? base : null, base != null && base.isResource() ? base : null, base, base), list, ExpressionNode, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* evaluate a path and return the matching elements
|
||||
*
|
||||
|
@ -3741,6 +3760,8 @@ public class FHIRPathEngine {
|
|||
}
|
||||
if ((focus.hasType("date") || focus.hasType("datetime") || focus.hasType("instant"))) {
|
||||
return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Decimal, TypeDetails.FP_DateTime);
|
||||
} else if ((focus.hasType("time"))) {
|
||||
return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Time, TypeDetails.FP_Time);
|
||||
} else if (focus.hasType("decimal") || focus.hasType("integer")) {
|
||||
return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Decimal);
|
||||
} else {
|
||||
|
@ -6351,7 +6372,7 @@ public class FHIRPathEngine {
|
|||
}
|
||||
result.addTypes(worker.getResourceNames());
|
||||
} else {
|
||||
pt = new ProfiledType(t.getCode());
|
||||
pt = new ProfiledType(t.getWorkingCode());
|
||||
}
|
||||
if (pt != null) {
|
||||
if (t.hasProfile()) {
|
||||
|
|
|
@ -3431,7 +3431,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
|
|||
sdMapCache.put(url, sdCache);
|
||||
String webroot = sd.getUserString("webroot");
|
||||
for (ElementDefinition e : sd.getSnapshot().getElement()) {
|
||||
context.getProfileUtilities().updateURLs(sd.getUrl(), webroot, e);
|
||||
context.getProfileUtilities().updateURLs(sd.getUrl(), webroot, e, false);
|
||||
sdCache.put(e.getId(), e);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -754,16 +754,7 @@ public class ValueSetRenderer extends TerminologyRenderer {
|
|||
if (ref == null) {
|
||||
ref = (String) cs.getWebPath();
|
||||
}
|
||||
if (ref == null && cs.hasUserData("webroot")) {
|
||||
ref = (String) cs.getUserData("webroot");
|
||||
}
|
||||
if (ref == null) {
|
||||
return "?ngen-14?.html";
|
||||
}
|
||||
if (!ref.contains(".html")) {
|
||||
ref = ref + ".html";
|
||||
}
|
||||
return ref.replace("\\", "/");
|
||||
return ref == null ? null : ref.replace("\\", "/");
|
||||
}
|
||||
|
||||
private void scanForDesignations(ValueSetExpansionContainsComponent c, List<String> langs, Map<String, String> designations) {
|
||||
|
@ -922,14 +913,18 @@ public class ValueSetRenderer extends TerminologyRenderer {
|
|||
td.addText(code);
|
||||
} else {
|
||||
String href = context.fixReference(getCsRef(e));
|
||||
if (href.contains("#"))
|
||||
href = href + "-"+Utilities.nmtokenize(code);
|
||||
else
|
||||
href = href + "#"+e.getId()+"-"+Utilities.nmtokenize(code);
|
||||
if (isAbstract)
|
||||
td.ah(context.prefixLocalHref(href)).setAttribute("title", context.formatPhrase(RenderingContext.VS_ABSTRACT_CODE_HINT)).i().addText(code);
|
||||
else
|
||||
td.ah(context.prefixLocalHref(href)).addText(code);
|
||||
if (href == null) {
|
||||
td.code().tx(code);
|
||||
} else {
|
||||
if (href.contains("#"))
|
||||
href = href + "-"+Utilities.nmtokenize(code);
|
||||
else
|
||||
href = href + "#"+e.getId()+"-"+Utilities.nmtokenize(code);
|
||||
if (isAbstract)
|
||||
td.ah(context.prefixLocalHref(href)).setAttribute("title", context.formatPhrase(RenderingContext.VS_ABSTRACT_CODE_HINT)).i().addText(code);
|
||||
else
|
||||
td.ah(context.prefixLocalHref(href)).addText(code);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1247,11 +1242,15 @@ public class ValueSetRenderer extends TerminologyRenderer {
|
|||
wli.tx(f.getProperty()+" "+describe(f.getOp())+" ");
|
||||
if (e != null && codeExistsInValueSet(e, f.getValue())) {
|
||||
String href = getContext().fixReference(getCsRef(e));
|
||||
if (href.contains("#"))
|
||||
href = href + "-"+Utilities.nmtokenize(f.getValue());
|
||||
else
|
||||
href = href + "#"+e.getId()+"-"+Utilities.nmtokenize(f.getValue());
|
||||
wli.ah(context.prefixLocalHref(href)).addText(f.getValue());
|
||||
if (href == null) {
|
||||
wli.code().tx(f.getValue());
|
||||
} else {
|
||||
if (href.contains("#"))
|
||||
href = href + "-"+Utilities.nmtokenize(f.getValue());
|
||||
else
|
||||
href = href + "#"+e.getId()+"-"+Utilities.nmtokenize(f.getValue());
|
||||
wli.ah(context.prefixLocalHref(href)).addText(f.getValue());
|
||||
}
|
||||
} else if (inc.hasSystem()) {
|
||||
wli.addText(f.getValue());
|
||||
ValidationResult vr = getContext().getWorker().validateCode(getContext().getTerminologyServiceOptions(), inc.getSystem(), inc.getVersion(), f.getValue(), null);
|
||||
|
|
|
@ -554,6 +554,9 @@ public class RenderingContext extends RenderingI18nContext {
|
|||
}
|
||||
|
||||
public String fixReference(String ref) {
|
||||
if (ref == null) {
|
||||
return null;
|
||||
}
|
||||
if (!Utilities.isAbsoluteUrl(ref)) {
|
||||
return (localPrefix == null ? "" : localPrefix)+ref;
|
||||
}
|
||||
|
|
|
@ -606,33 +606,35 @@ public class ValueSetExpander extends ValueSetProcessBase {
|
|||
excludeCodes(wc, importValueSetForExclude(wc, imp.getValue(), exp, expParams, false, vs).getExpansion());
|
||||
}
|
||||
|
||||
CodeSystem cs = context.fetchSupplementedCodeSystem(exc.getSystem());
|
||||
if ((cs == null || cs.getContent() != CodeSystemContentMode.COMPLETE) && context.supportsSystem(exc.getSystem(), opContext.getOptions().getFhirVersion())) {
|
||||
ValueSetExpansionOutcome vse = context.expandVS(exc, false, false);
|
||||
ValueSet valueset = vse.getValueset();
|
||||
if (valueset == null)
|
||||
throw failTSE("Error Expanding ValueSet: "+vse.getError());
|
||||
excludeCodes(wc, valueset.getExpansion());
|
||||
return;
|
||||
}
|
||||
|
||||
for (ConceptReferenceComponent c : exc.getConcept()) {
|
||||
excludeCode(wc, exc.getSystem(), c.getCode());
|
||||
}
|
||||
|
||||
if (exc.getFilter().size() > 0) {
|
||||
if (cs.getContent() == CodeSystemContentMode.FRAGMENT) {
|
||||
addFragmentWarning(exp, cs);
|
||||
if (exc.hasSystem()) {
|
||||
CodeSystem cs = context.fetchSupplementedCodeSystem(exc.getSystem());
|
||||
if ((cs == null || cs.getContent() != CodeSystemContentMode.COMPLETE) && context.supportsSystem(exc.getSystem(), opContext.getOptions().getFhirVersion())) {
|
||||
ValueSetExpansionOutcome vse = context.expandVS(exc, false, false);
|
||||
ValueSet valueset = vse.getValueset();
|
||||
if (valueset == null)
|
||||
throw failTSE("Error Expanding ValueSet: "+vse.getError());
|
||||
excludeCodes(wc, valueset.getExpansion());
|
||||
return;
|
||||
}
|
||||
List<WorkingContext> filters = new ArrayList<>();
|
||||
for (int i = 1; i < exc.getFilter().size(); i++) {
|
||||
WorkingContext wc1 = new WorkingContext();
|
||||
filters.add(wc1);
|
||||
processFilter(exc, exp, expParams, null, cs, false, exc.getFilter().get(i), wc1, null, true);
|
||||
|
||||
for (ConceptReferenceComponent c : exc.getConcept()) {
|
||||
excludeCode(wc, exc.getSystem(), c.getCode());
|
||||
}
|
||||
|
||||
if (exc.getFilter().size() > 0) {
|
||||
if (cs.getContent() == CodeSystemContentMode.FRAGMENT) {
|
||||
addFragmentWarning(exp, cs);
|
||||
}
|
||||
List<WorkingContext> filters = new ArrayList<>();
|
||||
for (int i = 1; i < exc.getFilter().size(); i++) {
|
||||
WorkingContext wc1 = new WorkingContext();
|
||||
filters.add(wc1);
|
||||
processFilter(exc, exp, expParams, null, cs, false, exc.getFilter().get(i), wc1, null, true);
|
||||
}
|
||||
ConceptSetFilterComponent fc = exc.getFilter().get(0);
|
||||
WorkingContext wc1 = dwc;
|
||||
processFilter(exc, exp, expParams, null, cs, false, fc, wc1, filters, true);
|
||||
}
|
||||
ConceptSetFilterComponent fc = exc.getFilter().get(0);
|
||||
WorkingContext wc1 = dwc;
|
||||
processFilter(exc, exp, expParams, null, cs, false, fc, wc1, filters, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -728,7 +730,6 @@ public class ValueSetExpander extends ValueSetProcessBase {
|
|||
expParams = makeDefaultExpansion();
|
||||
altCodeParams.seeParameters(expParams);
|
||||
altCodeParams.seeValueSet(source);
|
||||
|
||||
source.checkNoModifiers("ValueSet", "expanding");
|
||||
focus = source.copy();
|
||||
focus.setIdBase(null);
|
||||
|
|
|
@ -124,11 +124,9 @@ public class ValueSetValidator extends ValueSetProcessBase {
|
|||
}
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private ValueSet valueset;
|
||||
private Map<String, ValueSetValidator> inner = new HashMap<>();
|
||||
private ValidationOptions options;
|
||||
|
|
|
@ -103,7 +103,7 @@ public class Runner implements IEvaluationContext {
|
|||
for (JsonObject w : vd.getJsonObjects("where")) {
|
||||
String expr = w.asString("path");
|
||||
ExpressionNode node = fpe.parse(expr);
|
||||
boolean pass = fpe.evaluateToBoolean(null, b, b, b, node);
|
||||
boolean pass = fpe.evaluateToBoolean(vd, b, b, b, node);
|
||||
if (!pass) {
|
||||
ok = false;
|
||||
break;
|
||||
|
@ -114,7 +114,7 @@ public class Runner implements IEvaluationContext {
|
|||
rows.add(new ArrayList<Cell>());
|
||||
|
||||
for (JsonObject select : vd.getJsonObjects("select")) {
|
||||
executeSelect(select, b, rows);
|
||||
executeSelect(vd, select, b, rows);
|
||||
}
|
||||
for (List<Cell> row : rows) {
|
||||
storage.addRow(store, row);
|
||||
|
@ -124,14 +124,14 @@ public class Runner implements IEvaluationContext {
|
|||
storage.finish(store);
|
||||
}
|
||||
|
||||
private void executeSelect(JsonObject select, Base b, List<List<Cell>> rows) {
|
||||
private void executeSelect(JsonObject vd, JsonObject select, Base b, List<List<Cell>> rows) {
|
||||
List<Base> focus = new ArrayList<>();
|
||||
|
||||
if (select.has("forEach")) {
|
||||
focus.addAll(executeForEach(select, b));
|
||||
focus.addAll(executeForEach(vd, select, b));
|
||||
} else if (select.has("forEachOrNull")) {
|
||||
|
||||
focus.addAll(executeForEachOrNull(select, b));
|
||||
focus.addAll(executeForEachOrNull(vd, select, b));
|
||||
if (focus.isEmpty()) {
|
||||
List<Column> columns = (List<Column>) select.getUserData("columns");
|
||||
for (List<Cell> row : rows) {
|
||||
|
@ -159,20 +159,20 @@ public class Runner implements IEvaluationContext {
|
|||
List<List<Cell>> rowsToAdd = cloneRows(tempRows);
|
||||
|
||||
for (JsonObject column : select.getJsonObjects("column")) {
|
||||
executeColumn(column, f, rowsToAdd);
|
||||
executeColumn(vd, column, f, rowsToAdd);
|
||||
}
|
||||
|
||||
for (JsonObject sub : select.getJsonObjects("select")) {
|
||||
executeSelect(sub, f, rowsToAdd);
|
||||
executeSelect(vd, sub, f, rowsToAdd);
|
||||
}
|
||||
|
||||
executeUnionAll(select.getJsonObjects("unionAll"), f, rowsToAdd);
|
||||
executeUnionAll(vd, select.getJsonObjects("unionAll"), f, rowsToAdd);
|
||||
|
||||
rows.addAll(rowsToAdd);
|
||||
}
|
||||
}
|
||||
|
||||
private void executeUnionAll(List<JsonObject> unionList, Base b, List<List<Cell>> rows) {
|
||||
private void executeUnionAll(JsonObject vd, List<JsonObject> unionList, Base b, List<List<Cell>> rows) {
|
||||
if (unionList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
@ -183,7 +183,7 @@ public class Runner implements IEvaluationContext {
|
|||
for (JsonObject union : unionList) {
|
||||
List<List<Cell>> tempRows = new ArrayList<>();
|
||||
tempRows.addAll(sourceRows);
|
||||
executeSelect(union, b, tempRows);
|
||||
executeSelect(vd, union, b, tempRows);
|
||||
rows.addAll(tempRows);
|
||||
}
|
||||
}
|
||||
|
@ -204,25 +204,25 @@ public class Runner implements IEvaluationContext {
|
|||
return list;
|
||||
}
|
||||
|
||||
private List<Base> executeForEach(JsonObject focus, Base b) {
|
||||
private List<Base> executeForEach(JsonObject vd, JsonObject focus, Base b) {
|
||||
ExpressionNode n = (ExpressionNode) focus.getUserData("forEach");
|
||||
List<Base> result = new ArrayList<>();
|
||||
result.addAll(fpe.evaluate(b, n));
|
||||
result.addAll(fpe.evaluate(vd, b, n));
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<Base> executeForEachOrNull(JsonObject focus, Base b) {
|
||||
private List<Base> executeForEachOrNull(JsonObject vd, JsonObject focus, Base b) {
|
||||
ExpressionNode n = (ExpressionNode) focus.getUserData("forEachOrNull");
|
||||
List<Base> result = new ArrayList<>();
|
||||
result.addAll(fpe.evaluate(b, n));
|
||||
result.addAll(fpe.evaluate(vd, b, n));
|
||||
return result;
|
||||
}
|
||||
|
||||
private void executeColumn(JsonObject column, Base b, List<List<Cell>> rows) {
|
||||
private void executeColumn(JsonObject vd, JsonObject column, Base b, List<List<Cell>> rows) {
|
||||
ExpressionNode n = (ExpressionNode) column.getUserData("path");
|
||||
List<Base> bl2 = new ArrayList<>();
|
||||
if (b != null) {
|
||||
bl2.addAll(fpe.evaluate(b, n));
|
||||
bl2.addAll(fpe.evaluate(vd, b, n));
|
||||
}
|
||||
Column col = (Column) column.getUserData("column");
|
||||
if (col == null) {
|
||||
|
@ -344,14 +344,43 @@ public class Runner implements IEvaluationContext {
|
|||
|
||||
@Override
|
||||
public List<Base> resolveConstant(FHIRPathEngine engine, Object appContext, String name, boolean beforeContext, boolean explicitConstant) throws PathEngineException {
|
||||
throw new Error("Not implemented yet: resolveConstant");
|
||||
List<Base> list = new ArrayList<Base>();
|
||||
if (explicitConstant) {
|
||||
JsonObject vd = (JsonObject) appContext;
|
||||
JsonObject constant = findConstant(vd, name);
|
||||
if (constant != null) {
|
||||
Base b = (Base) constant.getUserData("value");
|
||||
if (b != null) {
|
||||
list.add(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeDetails resolveConstantType(FHIRPathEngine engine, Object appContext, String name, boolean explicitConstant) throws PathEngineException {
|
||||
throw new Error("Not implemented yet: resolveConstantType");
|
||||
if (explicitConstant) {
|
||||
JsonObject vd = (JsonObject) appContext;
|
||||
JsonObject constant = findConstant(vd, name.substring(1));
|
||||
if (constant != null) {
|
||||
Base b = (Base) constant.getUserData("value");
|
||||
if (b != null) {
|
||||
return new TypeDetails(CollectionStatus.SINGLETON, b.fhirType());
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private JsonObject findConstant(JsonObject vd, String name) {
|
||||
for (JsonObject o : vd.getJsonObjects("constant")) {
|
||||
if (name.equals(o.asString("name"))) {
|
||||
return o;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public boolean log(String argument, List<Base> focus) {
|
||||
throw new Error("Not implemented yet: log");
|
||||
|
|
|
@ -2,6 +2,7 @@ package org.hl7.fhir.r5.utils.sql;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.r5.model.Base;
|
||||
import org.hl7.fhir.utilities.json.model.JsonArray;
|
||||
import org.hl7.fhir.utilities.json.model.JsonBoolean;
|
||||
|
@ -33,16 +34,16 @@ public class StorageJson implements Storage {
|
|||
JsonObject row = new JsonObject();
|
||||
rows.add(row);
|
||||
for (Cell cell : cells) {
|
||||
if (cell.getValues().size() == 0) {
|
||||
row.add(cell.getColumn().getName(), new JsonNull());
|
||||
} else if (cell.getValues().size() == 1) {
|
||||
row.add(cell.getColumn().getName(), makeJsonNode(cell.getValues().get(0)));
|
||||
} else {
|
||||
if (cell.getColumn().isColl() || cell.getValues().size() > 1) {
|
||||
JsonArray arr = new JsonArray();
|
||||
row.add(cell.getColumn().getName(), arr);
|
||||
row.add(cell.getColumn().getName(), arr);
|
||||
for (Value value : cell.getValues()) {
|
||||
arr.add(makeJsonNode(value));
|
||||
}
|
||||
}
|
||||
} else if (cell.getValues().size() == 0) {
|
||||
row.add(cell.getColumn().getName(), new JsonNull());
|
||||
} else {
|
||||
row.add(cell.getColumn().getName(), makeJsonNode(cell.getValues().get(0)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -87,7 +88,7 @@ public class StorageJson implements Storage {
|
|||
|
||||
@Override
|
||||
public String getKeyForSourceResource(Base res) {
|
||||
return res.getIdBase();
|
||||
return res.fhirType()+"/"+res.getIdBase();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -11,6 +11,27 @@ import org.hl7.fhir.r5.context.IWorkerContext;
|
|||
import org.hl7.fhir.r5.fhirpath.ExpressionNode;
|
||||
import org.hl7.fhir.r5.fhirpath.FHIRPathEngine;
|
||||
import org.hl7.fhir.r5.fhirpath.TypeDetails;
|
||||
import org.hl7.fhir.r5.formats.JsonParser;
|
||||
import org.hl7.fhir.r5.model.Base64BinaryType;
|
||||
import org.hl7.fhir.r5.model.BooleanType;
|
||||
import org.hl7.fhir.r5.model.CanonicalType;
|
||||
import org.hl7.fhir.r5.model.CodeType;
|
||||
import org.hl7.fhir.r5.model.DateTimeType;
|
||||
import org.hl7.fhir.r5.model.DateType;
|
||||
import org.hl7.fhir.r5.model.DecimalType;
|
||||
import org.hl7.fhir.r5.model.IdType;
|
||||
import org.hl7.fhir.r5.model.InstantType;
|
||||
import org.hl7.fhir.r5.model.Integer64Type;
|
||||
import org.hl7.fhir.r5.model.IntegerType;
|
||||
import org.hl7.fhir.r5.model.OidType;
|
||||
import org.hl7.fhir.r5.model.PositiveIntType;
|
||||
import org.hl7.fhir.r5.model.PrimitiveType;
|
||||
import org.hl7.fhir.r5.model.StringType;
|
||||
import org.hl7.fhir.r5.model.TimeType;
|
||||
import org.hl7.fhir.r5.model.UnsignedIntType;
|
||||
import org.hl7.fhir.r5.model.UriType;
|
||||
import org.hl7.fhir.r5.model.UrlType;
|
||||
import org.hl7.fhir.r5.model.UuidType;
|
||||
import org.hl7.fhir.r5.fhirpath.ExpressionNode.CollectionStatus;
|
||||
import org.hl7.fhir.r5.fhirpath.FHIRPathEngine.IssueMessage;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
|
@ -99,7 +120,7 @@ public class Validator {
|
|||
i = 0;
|
||||
if (checkAllObjects(path, viewDefinition, "where")) {
|
||||
for (JsonObject where : viewDefinition.getJsonObjects("where")) {
|
||||
checkWhere(path+".where["+i+"]", where);
|
||||
checkWhere(viewDefinition, path+".where["+i+"]", where);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
@ -108,7 +129,7 @@ public class Validator {
|
|||
i = 0;
|
||||
if (checkAllObjects(path, viewDefinition, "select")) {
|
||||
for (JsonObject select : viewDefinition.getJsonObjects("select")) {
|
||||
columns.addAll(checkSelect(path+".select["+i+"]", select, t));
|
||||
columns.addAll(checkSelect(viewDefinition, path+".select["+i+"]", select, t));
|
||||
i++;
|
||||
}
|
||||
if (i == 0) {
|
||||
|
@ -119,15 +140,15 @@ public class Validator {
|
|||
}
|
||||
}
|
||||
|
||||
private List<Column> checkSelect(String path, JsonObject select, TypeDetails t) {
|
||||
private List<Column> checkSelect(JsonObject vd, String path, JsonObject select, TypeDetails t) {
|
||||
List<Column> columns = new ArrayList<>();
|
||||
select.setUserData("columns", columns);
|
||||
checkProperties(select, path, "column", "select", "forEach", "forEachOrNull", "unionAll");
|
||||
|
||||
if (select.has("forEach")) {
|
||||
t = checkForEach(path, select, select.get("forEach"), t);
|
||||
t = checkForEach(vd, path, select, select.get("forEach"), t);
|
||||
} else if (select.has("forEachOrNull")) {
|
||||
t = checkForEachOrNull(path, select, select.get("forEachOrNull"), t);
|
||||
t = checkForEachOrNull(vd, path, select, select.get("forEachOrNull"), t);
|
||||
}
|
||||
|
||||
if (t != null) {
|
||||
|
@ -142,7 +163,7 @@ public class Validator {
|
|||
if (!(e instanceof JsonObject)) {
|
||||
error(path+".column["+i+"]", a, "column["+i+"] is a "+e.type().toName()+" not an object", IssueType.INVALID);
|
||||
} else {
|
||||
columns.add(checkColumn(path+".column["+i+"]", (JsonObject) e, t));
|
||||
columns.add(checkColumn(vd, path+".column["+i+"]", (JsonObject) e, t));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -158,14 +179,14 @@ public class Validator {
|
|||
if (!(e instanceof JsonObject)) {
|
||||
error(path+".select["+i+"]", e, "select["+i+"] is not an object", IssueType.INVALID);
|
||||
} else {
|
||||
columns.addAll(checkSelect(path+".select["+i+"]", (JsonObject) e, t));
|
||||
columns.addAll(checkSelect(vd, path+".select["+i+"]", (JsonObject) e, t));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (select.has("unionAll")) {
|
||||
columns.addAll(checkUnion(path, select, select.get("unionAll"), t));
|
||||
columns.addAll(checkUnion(vd, path, select, select.get("unionAll"), t));
|
||||
}
|
||||
if (columns.isEmpty()) {
|
||||
error(path, select, "The select has no columns or selects", IssueType.REQUIRED);
|
||||
|
@ -191,7 +212,7 @@ public class Validator {
|
|||
}
|
||||
}
|
||||
|
||||
private List<Column> checkUnion(String path, JsonObject focus, JsonElement expression, TypeDetails t) {
|
||||
private List<Column> checkUnion(JsonObject vd, String path, JsonObject focus, JsonElement expression, TypeDetails t) {
|
||||
JsonElement a = focus.get("unionAll");
|
||||
if (!(a instanceof JsonArray)) {
|
||||
error(path+".unionAll", a, "union is not an array", IssueType.INVALID);
|
||||
|
@ -203,7 +224,7 @@ public class Validator {
|
|||
if (!(e instanceof JsonObject)) {
|
||||
error(path+".unionAll["+i+"]", e, "unionAll["+i+"] is not an object", IssueType.INVALID);
|
||||
} else {
|
||||
unionColumns.add(checkSelect(path+".unionAll["+i+"]", (JsonObject) e, t));
|
||||
unionColumns.add(checkSelect(vd, path+".unionAll["+i+"]", (JsonObject) e, t));
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
@ -242,7 +263,7 @@ public class Validator {
|
|||
}
|
||||
}
|
||||
|
||||
private Column checkColumn(String path, JsonObject column, TypeDetails t) {
|
||||
private Column checkColumn(JsonObject vd, String path, JsonObject column, TypeDetails t) {
|
||||
checkProperties(column, path, "path", "name", "description", "collection", "type", "tag");
|
||||
|
||||
if (!column.has("path")) {
|
||||
|
@ -260,7 +281,7 @@ public class Validator {
|
|||
try {
|
||||
node = fpe.parse(expr);
|
||||
column.setUserData("path", node);
|
||||
td = fpe.checkOnTypes(null, resourceName, t, node, warnings);
|
||||
td = fpe.checkOnTypes(vd, resourceName, t, node, warnings);
|
||||
} catch (Exception e) {
|
||||
error(path, expression, e.getMessage(), IssueType.INVALID);
|
||||
}
|
||||
|
@ -296,25 +317,31 @@ public class Validator {
|
|||
// ok, name is sorted!
|
||||
if (columnName != null) {
|
||||
column.setUserData("name", columnName);
|
||||
boolean isColl = (td.getCollectionStatus() != CollectionStatus.SINGLETON);
|
||||
boolean isColl = false;
|
||||
if (column.has("collection")) {
|
||||
JsonElement collectionJ = column.get("collection");
|
||||
if (!(collectionJ instanceof JsonBoolean)) {
|
||||
error(path+".collection", collectionJ, "collection is not a boolean", IssueType.INVALID);
|
||||
} else {
|
||||
boolean collection = collectionJ.asJsonBoolean().asBoolean();
|
||||
if (!collection && isColl) {
|
||||
isColl = false;
|
||||
warning(path, column, "collection is false, but the path statement(s) might return multiple values for the column '"+columnName+"' some inputs");
|
||||
if (collection) {
|
||||
isColl = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isColl) {
|
||||
if (td.getCollectionStatus() == CollectionStatus.SINGLETON) {
|
||||
hint(path, column, "collection is true, but the path statement(s) can only return single values for the column '"+columnName+"'");
|
||||
}
|
||||
} else {
|
||||
if (arrays == null) {
|
||||
warning(path, expression, "The column '"+columnName+"' appears to be a collection based on it's path. Collections are not supported in all execution contexts");
|
||||
} else if (!arrays) {
|
||||
warning(path, expression, "The column '"+columnName+"' appears to be a collection based on it's path, but this is not allowed in the current execution context");
|
||||
}
|
||||
if (td.getCollectionStatus() != CollectionStatus.SINGLETON) {
|
||||
warning(path, column, "collection is not true, but the path statement(s) might return multiple values for the column '"+columnName+"' for some inputs");
|
||||
}
|
||||
}
|
||||
Set<String> types = new HashSet<>();
|
||||
if (node.isNullSet()) {
|
||||
|
@ -330,7 +357,7 @@ public class Validator {
|
|||
if (typeJ instanceof JsonString) {
|
||||
String type = typeJ.asString();
|
||||
if (!td.hasType(type)) {
|
||||
error(path+".type", typeJ, "The path expression does not return a value of the type '"+type, IssueType.VALUE);
|
||||
error(path+".type", typeJ, "The path expression does not return a value of the type '"+type+"' - found "+td.describe(), IssueType.VALUE);
|
||||
} else {
|
||||
types.clear();
|
||||
types.add(simpleType(type));
|
||||
|
@ -377,6 +404,8 @@ public class Validator {
|
|||
case "integer": return ColumnKind.Integer;
|
||||
case "decimal": return ColumnKind.Decimal;
|
||||
case "string": return ColumnKind.String;
|
||||
case "id": return ColumnKind.String;
|
||||
case "code": return ColumnKind.String;
|
||||
case "base64Binary": return ColumnKind.Binary;
|
||||
case "time": return ColumnKind.Time;
|
||||
default: return ColumnKind.Complex;
|
||||
|
@ -384,7 +413,7 @@ public class Validator {
|
|||
}
|
||||
|
||||
private boolean isSimpleType(String type) {
|
||||
return Utilities.existsInList(type, "dateTime", "boolean", "integer", "decimal", "string", "base64Binary");
|
||||
return Utilities.existsInList(type, "dateTime", "boolean", "integer", "decimal", "string", "base64Binary", "id", "code", "date", "time");
|
||||
}
|
||||
|
||||
private String simpleType(String type) {
|
||||
|
@ -413,7 +442,7 @@ public class Validator {
|
|||
return type;
|
||||
}
|
||||
|
||||
private TypeDetails checkForEach(String path, JsonObject focus, JsonElement expression, TypeDetails t) {
|
||||
private TypeDetails checkForEach(JsonObject vd, String path, JsonObject focus, JsonElement expression, TypeDetails t) {
|
||||
if (!(expression instanceof JsonString)) {
|
||||
error(path+".forEach", expression, "forEach is not a string", IssueType.INVALID);
|
||||
return null;
|
||||
|
@ -425,7 +454,7 @@ public class Validator {
|
|||
try {
|
||||
ExpressionNode n = fpe.parse(expr);
|
||||
focus.setUserData("forEach", n);
|
||||
td = fpe.checkOnTypes(null, resourceName, t, n, warnings);
|
||||
td = fpe.checkOnTypes(vd, resourceName, t, n, warnings);
|
||||
} catch (Exception e) {
|
||||
error(path, expression, e.getMessage(), IssueType.INVALID);
|
||||
}
|
||||
|
@ -438,7 +467,7 @@ public class Validator {
|
|||
}
|
||||
}
|
||||
|
||||
private TypeDetails checkForEachOrNull(String path, JsonObject focus, JsonElement expression, TypeDetails t) {
|
||||
private TypeDetails checkForEachOrNull(JsonObject vd, String path, JsonObject focus, JsonElement expression, TypeDetails t) {
|
||||
if (!(expression instanceof JsonString)) {
|
||||
error(path+".forEachOrNull", expression, "forEachOrNull is not a string", IssueType.INVALID);
|
||||
return null;
|
||||
|
@ -450,7 +479,7 @@ public class Validator {
|
|||
try {
|
||||
ExpressionNode n = fpe.parse(expr);
|
||||
focus.setUserData("forEachOrNull", n);
|
||||
td = fpe.checkOnTypes(null, resourceName, t, n, warnings);
|
||||
td = fpe.checkOnTypes(vd, resourceName, t, n, warnings);
|
||||
} catch (Exception e) {
|
||||
error(path, expression, e.getMessage(), IssueType.INVALID);
|
||||
}
|
||||
|
@ -477,69 +506,79 @@ public class Validator {
|
|||
}
|
||||
}
|
||||
if (constant.has("valueBase64Binary")) {
|
||||
checkIsString(path, constant, "valueBase64Binary");
|
||||
checkIsString(path, constant, "valueBase64Binary", new Base64BinaryType());
|
||||
} else if (constant.has("valueBoolean")) {
|
||||
checkIsBoolean(path, constant, "valueBoolean");
|
||||
checkIsBoolean(path, constant, "valueBoolean", new BooleanType());
|
||||
} else if (constant.has("valueCanonical")) {
|
||||
checkIsString(path, constant, "valueCanonical");
|
||||
checkIsString(path, constant, "valueCanonical", new CanonicalType());
|
||||
} else if (constant.has("valueCode")) {
|
||||
checkIsString(path, constant, "valueCode");
|
||||
checkIsString(path, constant, "valueCode", new CodeType());
|
||||
} else if (constant.has("valueDate")) {
|
||||
checkIsString(path, constant, "valueDate");
|
||||
checkIsString(path, constant, "valueDate", new DateType());
|
||||
} else if (constant.has("valueDateTime")) {
|
||||
checkIsString(path, constant, "valueDateTime");
|
||||
checkIsString(path, constant, "valueDateTime", new DateTimeType());
|
||||
} else if (constant.has("valueDecimal")) {
|
||||
checkIsNumber(path, constant, "valueDecimal");
|
||||
checkIsNumber(path, constant, "valueDecimal", new DecimalType());
|
||||
} else if (constant.has("valueId")) {
|
||||
checkIsString(path, constant, "valueId");
|
||||
checkIsString(path, constant, "valueId", new IdType());
|
||||
} else if (constant.has("valueInstant")) {
|
||||
checkIsString(path, constant, "valueInstant");
|
||||
checkIsString(path, constant, "valueInstant", new InstantType());
|
||||
} else if (constant.has("valueInteger")) {
|
||||
checkIsNumber(path, constant, "valueInteger");
|
||||
checkIsNumber(path, constant, "valueInteger", new IntegerType());
|
||||
} else if (constant.has("valueInteger64")) {
|
||||
checkIsNumber(path, constant, "valueInteger64");
|
||||
checkIsNumber(path, constant, "valueInteger64", new Integer64Type());
|
||||
} else if (constant.has("valueOid")) {
|
||||
checkIsString(path, constant, "valueOid");
|
||||
checkIsString(path, constant, "valueOid", new OidType());
|
||||
} else if (constant.has("valueString")) {
|
||||
checkIsString(path, constant, "valueString");
|
||||
checkIsString(path, constant, "valueString", new StringType());
|
||||
} else if (constant.has("valuePositiveInt")) {
|
||||
checkIsNumber(path, constant, "valuePositiveInt");
|
||||
checkIsNumber(path, constant, "valuePositiveInt", new PositiveIntType());
|
||||
} else if (constant.has("valueTime")) {
|
||||
checkIsString(path, constant, "valueTime");
|
||||
checkIsString(path, constant, "valueTime", new TimeType());
|
||||
} else if (constant.has("valueUnsignedInt")) {
|
||||
checkIsNumber(path, constant, "valueUnsignedInt");
|
||||
checkIsNumber(path, constant, "valueUnsignedInt", new UnsignedIntType());
|
||||
} else if (constant.has("valueUri")) {
|
||||
checkIsString(path, constant, "valueUri");
|
||||
checkIsString(path, constant, "valueUri", new UriType());
|
||||
} else if (constant.has("valueUrl")) {
|
||||
checkIsString(path, constant, "valueUrl");
|
||||
checkIsString(path, constant, "valueUrl", new UrlType());
|
||||
} else if (constant.has("valueUuid")) {
|
||||
checkIsString(path, constant, "valueUuid");
|
||||
checkIsString(path, constant, "valueUuid", new UuidType());
|
||||
} else {
|
||||
error(path, constant, "No value found", IssueType.REQUIRED);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkIsString(String path, JsonObject constant, String name) {
|
||||
private void checkIsString(String path, JsonObject constant, String name, PrimitiveType<?> value) {
|
||||
JsonElement j = constant.get(name);
|
||||
if (!(j instanceof JsonString)) {
|
||||
error(path+"."+name, j, name+" must be a string", IssueType.INVALID);
|
||||
} else {
|
||||
value.setValueAsString(j.asString());
|
||||
constant.setUserData("value", value);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkIsBoolean(String path, JsonObject constant, String name) {
|
||||
private void checkIsBoolean(String path, JsonObject constant, String name, PrimitiveType<?> value) {
|
||||
JsonElement j = constant.get(name);
|
||||
if (!(j instanceof JsonBoolean)) {
|
||||
error(path+"."+name, j, name+" must be a boolean", IssueType.INVALID);
|
||||
} else {
|
||||
value.setValueAsString(j.asString());
|
||||
constant.setUserData("value", value);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkIsNumber(String path, JsonObject constant, String name) {
|
||||
private void checkIsNumber(String path, JsonObject constant, String name, PrimitiveType<?> value) {
|
||||
JsonElement j = constant.get(name);
|
||||
if (!(j instanceof JsonNumber)) {
|
||||
error(path+"."+name, j, name+" must be a number", IssueType.INVALID);
|
||||
} else {
|
||||
value.setValueAsString(j.asString());
|
||||
constant.setUserData("value", value);
|
||||
}
|
||||
}
|
||||
private void checkWhere(String path, JsonObject where) {
|
||||
|
||||
private void checkWhere(JsonObject vd, String path, JsonObject where) {
|
||||
checkProperties(where, path, "path", "description");
|
||||
|
||||
String expr = where.asString("path");
|
||||
|
@ -553,7 +592,7 @@ public class Validator {
|
|||
try {
|
||||
ExpressionNode n = fpe.parse(expr);
|
||||
where.setUserData("path", n);
|
||||
td = fpe.checkOnTypes(null, resourceName, types, n, warnings);
|
||||
td = fpe.checkOnTypes(vd, resourceName, types, n, warnings);
|
||||
} catch (Exception e) {
|
||||
error(path, where.get("path"), e.getMessage(), IssueType.INVALID);
|
||||
}
|
||||
|
|
|
@ -83,23 +83,21 @@ public class SQLOnFhirTests {
|
|||
this.resources = resources;
|
||||
this.testCase = testCase;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static Stream<Arguments> data() throws ParserConfigurationException, SAXException, IOException {
|
||||
List<Arguments> objects = new ArrayList<>();
|
||||
File dir = ManagedFileAccess.file("/Users/grahamegrieve/work/sql-on-fhir-v2/tests/content");
|
||||
for (File f : dir.listFiles()) {
|
||||
if (f.getName().endsWith(".json")) {
|
||||
JsonObject json = JsonParser.parseObject(f);
|
||||
String name1 = f.getName().replace(".json", "");
|
||||
List<JsonObject> resources = json.getJsonObjects("resources");
|
||||
int i = 0;
|
||||
for (JsonObject test : json.getJsonObjects("tests")) {
|
||||
String name2 = test.asString("title");
|
||||
objects.add(Arguments.of(name1+":"+name2, new TestDetails(name1+":"+name2, "$.tests["+i+"]", resources, test)));
|
||||
i++;
|
||||
}
|
||||
JsonArray testFiles = (JsonArray) JsonParser.parse(TestingUtilities.loadTestResourceStream("sql-on-fhir", "manifest.json"));
|
||||
|
||||
for (String s : testFiles.asStrings()) {
|
||||
JsonObject json = JsonParser.parseObject(TestingUtilities.loadTestResourceStream("sql-on-fhir", s));
|
||||
String name1 = s.replace(".json", "");
|
||||
List<JsonObject> resources = json.getJsonObjects("resources");
|
||||
int i = 0;
|
||||
for (JsonObject test : json.getJsonObjects("tests")) {
|
||||
String name2 = test.asString("title");
|
||||
objects.add(Arguments.of(name1+":"+name2, new TestDetails(name1+":"+name2, "$.tests["+i+"]", resources, test)));
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return objects.stream();
|
||||
|
@ -110,7 +108,6 @@ public class SQLOnFhirTests {
|
|||
@SuppressWarnings("deprecation")
|
||||
@ParameterizedTest(name = "{index}: file {0}")
|
||||
@MethodSource("data")
|
||||
@Disabled
|
||||
public void test(String name, TestDetails test) throws FileNotFoundException, IOException, FHIRException, org.hl7.fhir.exceptions.FHIRException, UcumException {
|
||||
this.details = test;
|
||||
Runner runner = new Runner();
|
||||
|
@ -137,8 +134,8 @@ public class SQLOnFhirTests {
|
|||
rows.add("rows", results);
|
||||
JsonObject exp = new JsonObject();
|
||||
exp.add("rows", test.testCase.getJsonArray("expect"));
|
||||
sortResults(exp);
|
||||
sortResults(rows);
|
||||
// sortResults(exp);
|
||||
// sortResults(rows);
|
||||
String expS = JsonParser.compose(exp, true);
|
||||
String rowS = JsonParser.compose(rows, true);
|
||||
String c = CompareUtilities.checkJsonSrcIsSame(name, expS, rowS, null);
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>org.hl7.fhir.core</artifactId>
|
||||
<version>6.3.24-SNAPSHOT</version>
|
||||
<version>6.3.26-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>org.hl7.fhir.core</artifactId>
|
||||
<version>6.3.24-SNAPSHOT</version>
|
||||
<version>6.3.26-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -1491,7 +1491,7 @@ public class Utilities {
|
|||
}
|
||||
|
||||
public static boolean startsWithInList(String s, Collection<String> list) {
|
||||
if (s == null) {
|
||||
if (s == null || list == null) {
|
||||
return false;
|
||||
}
|
||||
for (String l : list) {
|
||||
|
@ -1819,9 +1819,14 @@ public class Utilities {
|
|||
|
||||
private static Object applyDatePrecision(String v, int precision) {
|
||||
switch (precision) {
|
||||
case 4: return v.substring(0, 4);
|
||||
case 6: return v.substring(0, 7);
|
||||
case 8: return v.substring(0, 10);
|
||||
case 4:
|
||||
return v.substring(0, 4);
|
||||
case 6:
|
||||
case 7:
|
||||
return v.substring(0, 7);
|
||||
case 8:
|
||||
case 10:
|
||||
return v.substring(0, 10);
|
||||
case 14: return v.substring(0, 17);
|
||||
case 17: return v;
|
||||
}
|
||||
|
@ -2304,4 +2309,16 @@ public class Utilities {
|
|||
}
|
||||
}
|
||||
|
||||
public static boolean listValueStartsWith(String s, Set<String> list) {
|
||||
if (s == null || list == null) {
|
||||
return false;
|
||||
}
|
||||
for (String l : list) {
|
||||
if (l.startsWith(s)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -210,26 +210,30 @@ public class FilesystemPackageCacheManager extends BasePackageCacheManager imple
|
|||
Utilities.createDirectory(cacheFolder.getAbsolutePath());
|
||||
createIniFile();
|
||||
} else {
|
||||
if (!isCacheFolderValid()) {
|
||||
if (!iniFileExists()) {
|
||||
createIniFile();
|
||||
}
|
||||
if (!isIniFileCurrentVersion()) {
|
||||
clearCache();
|
||||
createIniFile();
|
||||
} else {
|
||||
deleteOldTempDirectories();
|
||||
}
|
||||
deleteOldTempDirectories();
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
private boolean isCacheFolderValid() throws IOException {
|
||||
private boolean iniFileExists() throws IOException {
|
||||
String iniPath = getPackagesIniPath();
|
||||
File iniFile = ManagedFileAccess.file(iniPath);
|
||||
if (!(iniFile.exists())) {
|
||||
return false;
|
||||
}
|
||||
return iniFile.exists();
|
||||
}
|
||||
|
||||
private boolean isIniFileCurrentVersion() throws IOException {
|
||||
String iniPath = getPackagesIniPath();
|
||||
IniFile ini = new IniFile(iniPath);
|
||||
String v = ini.getStringProperty("cache", "version");
|
||||
return CACHE_VERSION.equals(v);
|
||||
String version = ini.getStringProperty("cache", "version");
|
||||
return CACHE_VERSION.equals(version);
|
||||
}
|
||||
|
||||
private void deleteOldTempDirectories() throws IOException {
|
||||
|
|
|
@ -237,9 +237,11 @@ public class NpmPackage {
|
|||
public List<String> listFiles() {
|
||||
List<String> res = new ArrayList<>();
|
||||
if (folder != null) {
|
||||
for (File f : folder.listFiles()) {
|
||||
if (!f.isDirectory() && !Utilities.existsInList(f.getName(), "package.json", ".index.json", ".index.db", ".oids.json", ".oids.db")) {
|
||||
res.add(f.getName());
|
||||
if (folder.exists()) {
|
||||
for (File f : folder.listFiles()) {
|
||||
if (!f.isDirectory() && !Utilities.existsInList(f.getName(), "package.json", ".index.json", ".index.db", ".oids.json", ".oids.db")) {
|
||||
res.add(f.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -648,7 +650,17 @@ public class NpmPackage {
|
|||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create a package .index.json file for a package folder.
|
||||
* <p>
|
||||
* See <a href="https://hl7.org/fhir/packages.html#2.1.10.4">the FHIR specification</a> for details on .index.json
|
||||
* format and usage.
|
||||
*
|
||||
* @param desc
|
||||
* @param folder
|
||||
* @throws FileNotFoundException
|
||||
* @throws IOException
|
||||
*/
|
||||
public void indexFolder(String desc, NpmPackageFolder folder) throws FileNotFoundException, IOException {
|
||||
List<String> remove = new ArrayList<>();
|
||||
NpmPackageIndexBuilder indexer = new NpmPackageIndexBuilder();
|
||||
|
|
|
@ -31,18 +31,19 @@ public class PackageHacker {
|
|||
|
||||
public static void main(String[] args) throws FileNotFoundException, IOException {
|
||||
// new PackageHacker().massEdit(new File("/Users/grahamegrieve/web/hl7.org/fhir"));
|
||||
new PackageHacker().edit("/Users/grahamegrieve/web/hl7.org/fhir/6.0.0-ballot1/hl7.fhir.r6.core.tgz");
|
||||
new PackageHacker().edit("/Users/grahamegrieve/web/hl7.org/fhir/6.0.0-ballot1/hl7.fhir.r6.corexml.tgz");
|
||||
new PackageHacker().edit("/Users/grahamegrieve/web/hl7.org/fhir/6.0.0-ballot1/hl7.fhir.r6.examples.tgz");
|
||||
new PackageHacker().edit("/Users/grahamegrieve/web/hl7.org/fhir/6.0.0-ballot1/hl7.fhir.r6.expansions.tgz");
|
||||
new PackageHacker().edit("/Users/grahamegrieve/web/hl7.org/fhir/6.0.0-ballot1/hl7.fhir.r6.search.tgz");
|
||||
new PackageHacker().edit("/Users/grahamegrieve/web/hl7.org/fhir/6.0.0-ballot2/hl7.fhir.r6.core.tgz");
|
||||
new PackageHacker().edit("/Users/grahamegrieve/web/hl7.org/fhir/6.0.0-ballot2/hl7.fhir.r6.corexml.tgz");
|
||||
new PackageHacker().edit("/Users/grahamegrieve/web/hl7.org/fhir/6.0.0-ballot2/hl7.fhir.r6.examples.tgz");
|
||||
new PackageHacker().edit("/Users/grahamegrieve/web/hl7.org/fhir/6.0.0-ballot2/hl7.fhir.r6.expansions.tgz");
|
||||
new PackageHacker().edit("/Users/grahamegrieve/web/hl7.org/fhir/6.0.0-ballot2/hl7.fhir.r6.search.tgz");
|
||||
// new PackageHacker().edit("/Users/grahamegrieve/web/hl7.org/fhir/6.0.0-ballot1/hl7.fhir.r6.core.tgz");
|
||||
// new PackageHacker().edit("/Users/grahamegrieve/web/hl7.org/fhir/6.0.0-ballot1/hl7.fhir.r6.corexml.tgz");
|
||||
// new PackageHacker().edit("/Users/grahamegrieve/web/hl7.org/fhir/6.0.0-ballot1/hl7.fhir.r6.examples.tgz");
|
||||
// new PackageHacker().edit("/Users/grahamegrieve/web/hl7.org/fhir/6.0.0-ballot1/hl7.fhir.r6.expansions.tgz");
|
||||
// new PackageHacker().edit("/Users/grahamegrieve/web/hl7.org/fhir/6.0.0-ballot1/hl7.fhir.r6.search.tgz");
|
||||
// new PackageHacker().edit("/Users/grahamegrieve/web/hl7.org/fhir/6.0.0-ballot2/hl7.fhir.r6.core.tgz");
|
||||
// new PackageHacker().edit("/Users/grahamegrieve/web/hl7.org/fhir/6.0.0-ballot2/hl7.fhir.r6.corexml.tgz");
|
||||
// new PackageHacker().edit("/Users/grahamegrieve/web/hl7.org/fhir/6.0.0-ballot2/hl7.fhir.r6.examples.tgz");
|
||||
// new PackageHacker().edit("/Users/grahamegrieve/web/hl7.org/fhir/6.0.0-ballot2/hl7.fhir.r6.expansions.tgz");
|
||||
// new PackageHacker().edit("/Users/grahamegrieve/web/hl7.org/fhir/6.0.0-ballot2/hl7.fhir.r6.search.tgz");
|
||||
|
||||
// new PackageHacker().edit(args[0]);
|
||||
// new PackageHacker().edit("/Users/grahamegrieve/web/hl7.org/fhir/us/core/v311/package.tgz", "http://hl7.org/fhir/us/core/STU3.1.1");
|
||||
new PackageHacker().edit("/Users/grahamegrieve/web/hl7.org/fhir/us/core/v700/package.tgz", "http://hl7.org/fhir/us/core/STU7");
|
||||
}
|
||||
|
||||
// private void massEdit(File dir) throws IOException {
|
||||
|
@ -91,7 +92,7 @@ public class PackageHacker {
|
|||
// }
|
||||
// }
|
||||
|
||||
private void edit(String name) throws FileNotFoundException, IOException {
|
||||
private void edit(String name, String path) throws FileNotFoundException, IOException {
|
||||
File f = ManagedFileAccess.file(name);
|
||||
if (!f.exists())
|
||||
throw new Error("Unable to find "+f.getAbsolutePath());
|
||||
|
@ -107,15 +108,15 @@ public class PackageHacker {
|
|||
System.out.println("Altering Package "+f.getAbsolutePath());
|
||||
System.out.println(nice(pck.getNpm()));
|
||||
|
||||
if (change(pck.getNpm())) {
|
||||
if (change(pck.getNpm(), path)) {
|
||||
|
||||
System.out.println("Revised Package");
|
||||
System.out.println("=======================");
|
||||
System.out.println(nice(pck.getNpm()));
|
||||
System.out.println("=======================");
|
||||
// System.out.print("save? y/n: ");
|
||||
// int r = System.in.read();
|
||||
// if (r == 'y') {
|
||||
System.out.print("save? y/n: ");
|
||||
int r = System.in.read();
|
||||
if (r == 'y') {
|
||||
f.renameTo(ManagedFileAccess.file(Utilities.changeFileExt(name, ".tgz.bak")));
|
||||
FileOutputStream fso = ManagedFileAccess.outStream(f);
|
||||
try {
|
||||
|
@ -123,7 +124,7 @@ public class PackageHacker {
|
|||
} finally {
|
||||
fso.close();
|
||||
}
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -142,13 +143,15 @@ public class PackageHacker {
|
|||
return JsonParser.compose(json, true);
|
||||
}
|
||||
|
||||
private boolean change(JsonObject npm) throws FileNotFoundException, IOException {
|
||||
// fixVersions(npm, ver);
|
||||
if (npm.has("notForPublication")) {
|
||||
npm.remove("notForPublication");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
private boolean change(JsonObject npm, String path) throws FileNotFoundException, IOException {
|
||||
npm.remove("url");
|
||||
npm.add("url", path);
|
||||
return true;
|
||||
// if (npm.has("notForPublication")) {
|
||||
// npm.remove("notForPublication");
|
||||
// return true;
|
||||
// }
|
||||
// return false;
|
||||
}
|
||||
|
||||
private void fixVersionInContent(Map<String, byte[]> content) {
|
||||
|
|
|
@ -1,22 +1,25 @@
|
|||
package org.hl7.fhir.utilities.npm;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import org.hl7.fhir.utilities.IniFile;
|
||||
import org.hl7.fhir.utilities.filesystem.ManagedFileAccess;
|
||||
import org.junit.jupiter.api.RepeatedTest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.DisabledOnOs;
|
||||
import org.junit.jupiter.api.condition.EnabledOnOs;
|
||||
|
@ -100,7 +103,6 @@ public class FilesystemPackageManagerTests {
|
|||
@DisabledOnOs(OS.WINDOWS)
|
||||
public void testSystemCacheDirectory() throws IOException {
|
||||
File folder = new FilesystemPackageCacheManager.Builder().withSystemCacheFolder().getCacheFolder();
|
||||
|
||||
assertEquals( "/var/lib/.fhir/packages", folder.getAbsolutePath());
|
||||
}
|
||||
|
||||
|
@ -124,6 +126,118 @@ public class FilesystemPackageManagerTests {
|
|||
return params.stream();
|
||||
}
|
||||
|
||||
private void createDummyTemp(File cacheDirectory, String lowerCase) throws IOException {
|
||||
createDummyPackage(cacheDirectory, lowerCase);
|
||||
}
|
||||
|
||||
private void createDummyPackage(File cacheDirectory, String packageName, String packageVersion) throws IOException {
|
||||
String directoryName = packageName + "#" + packageVersion;
|
||||
createDummyPackage(cacheDirectory, directoryName);
|
||||
}
|
||||
|
||||
private static void createDummyPackage(File cacheDirectory, String directoryName) throws IOException {
|
||||
File packageDirectory = ManagedFileAccess.file(cacheDirectory.getAbsolutePath(), directoryName);
|
||||
packageDirectory.mkdirs();
|
||||
|
||||
File dummyContentFile = ManagedFileAccess.file(packageDirectory.getAbsolutePath(), "dummy.txt");
|
||||
FileWriter wr = new FileWriter(dummyContentFile);
|
||||
wr.write("Ain't nobody here but us chickens");
|
||||
wr.flush();
|
||||
wr.close();
|
||||
}
|
||||
|
||||
private void assertThatDummyTempExists(File cacheDirectory, String dummyTempPackage) throws IOException {
|
||||
File dummyTempDirectory = ManagedFileAccess.file(cacheDirectory.getAbsolutePath(), dummyTempPackage);
|
||||
assertThat(dummyTempDirectory).exists();
|
||||
|
||||
File dummyContentFile = ManagedFileAccess.file(dummyTempDirectory.getAbsolutePath(), "dummy.txt");
|
||||
assertThat(dummyContentFile).exists();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreatesIniIfDoesntExistAndCacheStaysIntact() throws IOException {
|
||||
File cacheDirectory = ManagedFileAccess.fromPath(Files.createTempDirectory("fpcm-multithreadingTest"));
|
||||
File cacheIni = ManagedFileAccess.file(cacheDirectory.getAbsolutePath(), "packages.ini");
|
||||
|
||||
createDummyPackage(cacheDirectory, "example.fhir.uv.myig", "1.2.3");
|
||||
|
||||
String dummyTempPackage = UUID.randomUUID().toString().toLowerCase();
|
||||
createDummyTemp(cacheDirectory, dummyTempPackage);
|
||||
assertThatDummyTempExists(cacheDirectory, dummyTempPackage);
|
||||
|
||||
assertThat(cacheIni).doesNotExist();
|
||||
FilesystemPackageCacheManager filesystemPackageCacheManager = new FilesystemPackageCacheManager.Builder().withCacheFolder(cacheDirectory.getAbsolutePath()).build();
|
||||
assertInitializedTestCacheIsValid(cacheDirectory, true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testClearsCacheIfVersionIsWrong() throws IOException {
|
||||
File cacheDirectory = ManagedFileAccess.fromPath(Files.createTempDirectory("fpcm-multithreadingTest"));
|
||||
File cacheIni = ManagedFileAccess.file(cacheDirectory.getAbsolutePath(), "packages.ini");
|
||||
|
||||
createDummyPackage(cacheDirectory, "example.fhir.uv.myig", "1.2.3");
|
||||
String dummyTempPackage = UUID.randomUUID().toString().toLowerCase();
|
||||
createDummyTemp(cacheDirectory, dummyTempPackage);
|
||||
assertThatDummyTempExists(cacheDirectory, dummyTempPackage);
|
||||
|
||||
|
||||
IniFile ini = new IniFile(cacheIni.getAbsolutePath());
|
||||
ini.setStringProperty("cache", "version", "2", null);
|
||||
ini.save();
|
||||
|
||||
assertThat(cacheIni).exists();
|
||||
FilesystemPackageCacheManager filesystemPackageCacheManager = new FilesystemPackageCacheManager.Builder().withCacheFolder(cacheDirectory.getAbsolutePath()).build();
|
||||
assertInitializedTestCacheIsValid(cacheDirectory, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCacheStaysIntactIfVersionIsTheSame() throws IOException {
|
||||
File cacheDirectory = ManagedFileAccess.fromPath(Files.createTempDirectory("fpcm-multithreadingTest"));
|
||||
File cacheIni = ManagedFileAccess.file(cacheDirectory.getAbsolutePath(), "packages.ini");
|
||||
|
||||
createDummyPackage(cacheDirectory, "example.fhir.uv.myig", "1.2.3");
|
||||
String dummyTempPackage = UUID.randomUUID().toString().toLowerCase();
|
||||
createDummyTemp(cacheDirectory, dummyTempPackage);
|
||||
assertThatDummyTempExists(cacheDirectory, dummyTempPackage);
|
||||
|
||||
|
||||
IniFile ini = new IniFile(cacheIni.getAbsolutePath());
|
||||
ini.setStringProperty("cache", "version", "3", null);
|
||||
ini.save();
|
||||
|
||||
assertThat(cacheIni).exists();
|
||||
FilesystemPackageCacheManager filesystemPackageCacheManager = new FilesystemPackageCacheManager.Builder().withCacheFolder(cacheDirectory.getAbsolutePath()).build();
|
||||
assertInitializedTestCacheIsValid(cacheDirectory, true);
|
||||
}
|
||||
|
||||
private void assertInitializedTestCacheIsValid(File cacheDirectory, boolean dummyPackageShouldExist) throws IOException {
|
||||
assertThat(cacheDirectory).exists();
|
||||
File iniFile = ManagedFileAccess.file(cacheDirectory.getAbsolutePath(), "packages.ini");
|
||||
assertThat(ManagedFileAccess.file(cacheDirectory.getAbsolutePath(), "packages.ini")).exists();
|
||||
IniFile ini = new IniFile(iniFile.getAbsolutePath());
|
||||
String version = ini.getStringProperty("cache", "version");
|
||||
assertThat(version).isEqualTo("3");
|
||||
|
||||
File[] files = cacheDirectory.listFiles();
|
||||
if (dummyPackageShouldExist) {
|
||||
// Check that only packages.ini and our dummy package are in the cache. Our previous temp should be deleted.
|
||||
assertThat(files).hasSize(2); // packages.ini and example.fhir.uv.myig#1.2.3 (directory)
|
||||
|
||||
File dummyPackage = ManagedFileAccess.file(cacheDirectory.getAbsolutePath(), "example.fhir.uv.myig#1.2.3");
|
||||
assertThat(dummyPackage).exists();
|
||||
|
||||
File dummyContentFile = ManagedFileAccess.file(dummyPackage.getAbsolutePath(), "dummy.txt");
|
||||
assertThat(dummyContentFile).exists();
|
||||
} else {
|
||||
// Check that only packages.ini is in the cache.
|
||||
assertThat(files).hasSize(1);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@MethodSource("packageCacheMultiThreadTestParams")
|
||||
@ParameterizedTest
|
||||
public void packageCacheMultiThreadTest(final int threadTotal, final int packageCacheManagerTotal) throws IOException {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>org.hl7.fhir.core</artifactId>
|
||||
<version>6.3.24-SNAPSHOT</version>
|
||||
<version>6.3.26-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>org.hl7.fhir.core</artifactId>
|
||||
<version>6.3.24-SNAPSHOT</version>
|
||||
<version>6.3.26-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
@ -119,37 +119,6 @@
|
|||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- CQL-to-ELM -->
|
||||
<dependency>
|
||||
<groupId>info.cqframework</groupId>
|
||||
<artifactId>cql</artifactId>
|
||||
<version>${info_cqframework_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>info.cqframework</groupId>
|
||||
<artifactId>model</artifactId>
|
||||
<version>${info_cqframework_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>info.cqframework</groupId>
|
||||
<artifactId>elm</artifactId>
|
||||
<version>${info_cqframework_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>info.cqframework</groupId>
|
||||
<artifactId>cql-to-elm</artifactId>
|
||||
<version>${info_cqframework_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>info.cqframework</groupId>
|
||||
<artifactId>quick</artifactId>
|
||||
<version>${info_cqframework_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>info.cqframework</groupId>
|
||||
<artifactId>qdm</artifactId>
|
||||
<version>${info_cqframework_version}</version>
|
||||
</dependency>
|
||||
<!-- OkHttpDependency -->
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
|
|
|
@ -226,6 +226,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
|
|||
@Getter @Setter private boolean allowDoubleQuotesInFHIRPath;
|
||||
@Getter @Setter private boolean checkIPSCodes;
|
||||
@Getter @Setter private BestPracticeWarningLevel bestPracticeLevel;
|
||||
@Getter @Setter private boolean unknownCodeSystemsCauseErrors;
|
||||
@Getter @Setter private Locale locale;
|
||||
@Getter @Setter private List<ImplementationGuide> igs = new ArrayList<>();
|
||||
@Getter @Setter private List<String> extensionDomains = new ArrayList<>();
|
||||
|
@ -289,6 +290,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
|
|||
fhirPathEngine = other.fhirPathEngine;
|
||||
igLoader = other.igLoader;
|
||||
jurisdiction = other.jurisdiction;
|
||||
unknownCodeSystemsCauseErrors = other.unknownCodeSystemsCauseErrors;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -906,6 +908,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
|
|||
if (policyAdvisor != null) {
|
||||
validator.setPolicyAdvisor(policyAdvisor);
|
||||
}
|
||||
validator.setUnknownCodeSystemsCauseErrors(unknownCodeSystemsCauseErrors);
|
||||
return validator;
|
||||
}
|
||||
|
||||
|
|
|
@ -163,6 +163,9 @@ public class CliContext {
|
|||
@JsonProperty("bestPracticeLevel")
|
||||
private BestPracticeWarningLevel bestPracticeLevel = BestPracticeWarningLevel.Warning;
|
||||
|
||||
@JsonProperty("unknownCodeSystemsCauseErrors")
|
||||
private boolean unknownCodeSystemsCauseErrors;
|
||||
|
||||
@JsonProperty("baseEngine")
|
||||
public String getBaseEngine() {
|
||||
return baseEngine;
|
||||
|
@ -832,6 +835,7 @@ public class CliContext {
|
|||
Objects.equals(watchMode, that.watchMode) &&
|
||||
Objects.equals(bestPracticeLevel, that.bestPracticeLevel) &&
|
||||
Objects.equals(watchScanDelay, that.watchScanDelay) &&
|
||||
Objects.equals(unknownCodeSystemsCauseErrors, that.unknownCodeSystemsCauseErrors) &&
|
||||
Objects.equals(watchSettleTime, that.watchSettleTime) ;
|
||||
}
|
||||
|
||||
|
@ -839,8 +843,8 @@ public class CliContext {
|
|||
public int hashCode() {
|
||||
return Objects.hash(baseEngine, doNative, extensions, hintAboutNonMustSupport, recursive, doDebug, assumeValidRestReferences, canDoNative, noInternalCaching,
|
||||
noExtensibleBindingMessages, noInvariants, displayWarnings, wantInvariantsInMessages, map, output, outputSuffix, htmlOutput, txServer, sv, txLog, txCache, mapLog, lang, srcLang, tgtLang, fhirpath, snomedCT,
|
||||
targetVer, igs, questionnaireMode, level, profiles, sources, inputs, mode, locale, locations, crumbTrails, forPublication, showTimes, allowExampleUrls, outputStyle, jurisdiction, noUnicodeBiDiControlChars, watchMode, watchScanDelay, watchSettleTime, bestPracticeLevel,
|
||||
htmlInMarkdownCheck, allowDoubleQuotesInFHIRPath, checkIPSCodes);
|
||||
targetVer, igs, questionnaireMode, level, profiles, sources, inputs, mode, locale, locations, crumbTrails, forPublication, showTimes, allowExampleUrls, outputStyle, jurisdiction, noUnicodeBiDiControlChars,
|
||||
watchMode, watchScanDelay, watchSettleTime, bestPracticeLevel, unknownCodeSystemsCauseErrors, htmlInMarkdownCheck, allowDoubleQuotesInFHIRPath, checkIPSCodes);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -899,6 +903,7 @@ public class CliContext {
|
|||
", bestPracticeLevel=" + bestPracticeLevel +
|
||||
", watchSettleTime=" + watchSettleTime +
|
||||
", watchScanDelay=" + watchScanDelay +
|
||||
", unknownCodeSystemsCauseErrors=" + unknownCodeSystemsCauseErrors +
|
||||
'}';
|
||||
}
|
||||
|
||||
|
@ -956,4 +961,17 @@ public class CliContext {
|
|||
return this;
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("unknownCodeSystemsCauseErrors")
|
||||
public boolean isUnknownCodeSystemsCauseErrors() {
|
||||
return unknownCodeSystemsCauseErrors;
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("unknownCodeSystemsCauseErrors")
|
||||
public void setUnknownCodeSystemsCauseErrors(boolean unknownCodeSystemsCauseErrors) {
|
||||
this.unknownCodeSystemsCauseErrors = unknownCodeSystemsCauseErrors;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -581,6 +581,7 @@ public class ValidationService {
|
|||
}
|
||||
validationEngine.getBundleValidationRules().addAll(cliContext.getBundleValidationRules());
|
||||
validationEngine.setJurisdiction(CodeSystemUtilities.readCoding(cliContext.getJurisdiction()));
|
||||
validationEngine.setUnknownCodeSystemsCauseErrors(cliContext.isUnknownCodeSystemsCauseErrors());
|
||||
TerminologyCache.setNoCaching(cliContext.isNoInternalCaching());
|
||||
validationEngine.prepare(); // generate any missing snapshots
|
||||
System.out.println(" go (" + timeTracker.milestone() + ")");
|
||||
|
|
|
@ -94,8 +94,7 @@ public class Params {
|
|||
public static final String DISABLE_DEFAULT_RESOURCE_FETCHER = "-disable-default-resource-fetcher";
|
||||
public static final String CHECK_IPS_CODES = "-check-ips-codes";
|
||||
public static final String BEST_PRACTICE = "-best-practice";
|
||||
|
||||
|
||||
public static final String UNKNOWN_CODESYSTEMS_CAUSE_ERROR = "-unknown-codesystems-cause-errors";
|
||||
|
||||
public static final String RUN_TESTS = "-run-tests";
|
||||
|
||||
|
@ -320,6 +319,8 @@ public class Params {
|
|||
cliContext.setCrumbTrails(true);
|
||||
} else if (args[i].equals(FOR_PUBLICATION)) {
|
||||
cliContext.setForPublication(true);
|
||||
} else if (args[i].equals(UNKNOWN_CODESYSTEMS_CAUSE_ERROR)) {
|
||||
cliContext.setUnknownCodeSystemsCauseErrors(true);
|
||||
} else if (args[i].equals(VERBOSE)) {
|
||||
cliContext.setCrumbTrails(true);
|
||||
} else if (args[i].equals(ALLOW_EXAMPLE_URLS)) {
|
||||
|
|
|
@ -46,7 +46,7 @@ import javax.annotation.Nonnull;
|
|||
import org.apache.commons.lang3.NotImplementedException;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.fhir.ucum.Decimal;
|
||||
import org.hl7.elm.r1.Code;
|
||||
|
||||
import org.hl7.fhir.exceptions.DefinitionException;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.exceptions.PathEngineException;
|
||||
|
@ -598,6 +598,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
private boolean example ;
|
||||
private IDigitalSignatureServices signatureServices;
|
||||
private ContextUtilities cu;
|
||||
private boolean unknownCodeSystemsCauseErrors;
|
||||
|
||||
public InstanceValidator(@Nonnull IWorkerContext theContext, @Nonnull IEvaluationContext hostServices, @Nonnull XVerExtensionManager xverManager) {
|
||||
super(theContext, xverManager, false);
|
||||
|
@ -1125,7 +1126,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
timeTracker.tx(t, "vc "+system+"#"+code+" '"+display+"'");
|
||||
if (s == null)
|
||||
return true;
|
||||
ok = processTxIssues(errors, s, element, path, null, "no binding on code", false, null) & ok;
|
||||
ok = processTxIssues(errors, s, element, path, false, null, null) & ok;
|
||||
|
||||
if (s.isOk()) {
|
||||
if (s.getMessage() != null && !s.messageIsInIssues()) {
|
||||
|
@ -1381,7 +1382,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
if (cc.hasCoding()) {
|
||||
long t = System.nanoTime();
|
||||
ValidationResult vr = checkCodeOnServer(stack, null, cc);
|
||||
bh.see(processTxIssues(errors, vr, element, path, org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.INFORMATION, null, false, null));
|
||||
bh.see(processTxIssues(errors, vr, element, path, false, null, null));
|
||||
timeTracker.tx(t, "vc " + cc.toString());
|
||||
}
|
||||
} catch (CheckCodeOnServerException e) {
|
||||
|
@ -1465,7 +1466,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
} else {
|
||||
checked.set(true);
|
||||
ValidationResult vr = checkCodeOnServer(stack, valueset, cc);
|
||||
bh.see(processTxIssues(errors, vr, element, path, notFoundSeverityForBinding(strength), notFoundSeverityNoteForBinding(strength), false, vsRef));
|
||||
bh.see(processTxIssues(errors, vr, element, path, false, vsRef, strength));
|
||||
if (!vr.isOk()) {
|
||||
bindingsOk = false;
|
||||
if (vr.getErrorClass() != null && vr.getErrorClass() == TerminologyServiceErrorClass.NOSERVICE) {
|
||||
|
@ -1533,33 +1534,34 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
return checkDisp;
|
||||
}
|
||||
|
||||
private String notFoundSeverityNoteForBinding(BindingStrength strength) {
|
||||
if (strength == BindingStrength.REQUIRED) {
|
||||
return "error because this is a required binding";
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
// private String notFoundSeverityNoteForBinding(BindingStrength strength, Set<String> systems) {
|
||||
// if (strength == BindingStrength.REQUIRED &&
|
||||
// (Utilities.listValueStartsWith("http://hl7.org/fhir", systems) || Utilities.listValueStartsWith("http://terminology.hl7.org", systems))) {
|
||||
// return "error because this is a required binding to an HL7 code system";
|
||||
// } else {
|
||||
// return null;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * The terminology server will report an error for an unknown code system or version, or a dependent valueset
|
||||
// *
|
||||
// * but we only care for validation if the binding strength is strong enough.
|
||||
// * @param binding
|
||||
// * @return
|
||||
// */
|
||||
// private org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity notFoundSeverityForBinding(BindingStrength strength, String systems) {
|
||||
// if (strength == BindingStrength.REQUIRED &&
|
||||
// (Utilities.listValueStartsWith("http://hl7.org/fhir", systems) || Utilities.listValueStartsWith("http://terminology.hl7.org", systems))) {
|
||||
// return org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.ERROR;
|
||||
// } else if (strength == BindingStrength.REQUIRED || strength == BindingStrength.EXTENSIBLE) {
|
||||
// return org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.WARNING;
|
||||
// } else {
|
||||
// return org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.INFORMATION;
|
||||
// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* The terminology server will report an error for an unknown code system or version, or a dependent valueset
|
||||
*
|
||||
* but we only care for validation if the binding strength is strong enough.
|
||||
* @param binding
|
||||
* @return
|
||||
*/
|
||||
private org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity notFoundSeverityForBinding(BindingStrength strength) {
|
||||
if (strength == BindingStrength.REQUIRED) {
|
||||
return org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.ERROR;
|
||||
} else if (strength == BindingStrength.EXTENSIBLE) {
|
||||
return org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.WARNING;
|
||||
} else {
|
||||
return org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.INFORMATION;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean processTxIssues(List<ValidationMessage> errors, ValidationResult vr, Element element, String path,
|
||||
org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity notFoundLevel, String notFoundNote, boolean ignoreCantInfer, String vsurl) {
|
||||
private boolean processTxIssues(List<ValidationMessage> errors, ValidationResult vr, Element element, String path, boolean ignoreCantInfer, String vsurl, BindingStrength bs) {
|
||||
boolean ok = true;
|
||||
if (vr != null) {
|
||||
for (OperationOutcomeIssueComponent iss : vr.getIssues()) {
|
||||
|
@ -1567,12 +1569,35 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
&& !iss.getDetails().hasCoding("http://hl7.org/fhir/tools/CodeSystem/tx-issue-type", "this-code-not-in-vs")
|
||||
&& !(ignoreCantInfer || iss.getDetails().hasCoding("http://hl7.org/fhir/tools/CodeSystem/tx-issue-type", "cannot-infer"))) {
|
||||
OperationOutcomeIssueComponent i = iss.copy();
|
||||
if (i.getDetails().hasCoding("http://hl7.org/fhir/tools/CodeSystem/tx-issue-type", "not-found")) {
|
||||
if (notFoundLevel != null && i.getSeverity().isHigherThan(notFoundLevel) || (vsurl != null && i.getDetails().getText().contains(vsurl))) {
|
||||
i.setSeverity(notFoundLevel);
|
||||
if (i.getDetails().hasCoding("http://hl7.org/fhir/tools/CodeSystem/tx-issue-type", "not-found")) {
|
||||
String msg = iss.getDetails().getText();
|
||||
boolean isHL7 = msg == null ? false : msg.contains("http://hl7.org/fhir") || msg.contains("http://terminology.hl7.org");
|
||||
org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity notFoundLevel = null;
|
||||
String notFoundNote = null;
|
||||
if (bs == null) {
|
||||
notFoundLevel = org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.WARNING;
|
||||
notFoundNote = null; // "binding=null";
|
||||
} else if (bs == BindingStrength.REQUIRED && isHL7) {
|
||||
notFoundLevel = org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.ERROR;
|
||||
notFoundNote = "error because this is a required binding to an HL7 code system";
|
||||
} else if (bs == BindingStrength.REQUIRED && unknownCodeSystemsCauseErrors) {
|
||||
notFoundLevel = org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.ERROR;
|
||||
notFoundNote = "error because this is a required binding";
|
||||
} else if (bs == BindingStrength.REQUIRED) {
|
||||
notFoundLevel = org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.WARNING;
|
||||
notFoundNote = null; // "binding=required";
|
||||
} else if (bs == BindingStrength.EXTENSIBLE) {
|
||||
notFoundLevel = org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.WARNING;
|
||||
notFoundNote = null; // "binding=extensible";
|
||||
} else {
|
||||
notFoundLevel = org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.WARNING;
|
||||
notFoundNote = null; // "binding="+bs.toCode();
|
||||
}
|
||||
if (notFoundNote != null) {
|
||||
i.getDetails().setText(i.getDetails().getText()+" ("+notFoundNote+")");
|
||||
if (notFoundLevel != null && i.getSeverity().isHigherThan(notFoundLevel)) { // && (vsurl != null && i.getDetails().getText().contains(vsurl))) {
|
||||
i.setSeverity(notFoundLevel);
|
||||
if (notFoundNote != null) {
|
||||
i.getDetails().setText(i.getDetails().getText()+" ("+notFoundNote+")");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (baseOptions.isDisplayWarningMode() && i.getSeverity() == org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.ERROR && i.getDetails().hasCoding("http://hl7.org/fhir/tools/CodeSystem/tx-issue-type", "invalid-display")) {
|
||||
|
@ -1592,7 +1617,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
boolean ok = true;
|
||||
if (isNotBlank(nextCoding.getCode()) && isNotBlank(nextCoding.getSystem()) && context.supportsSystem(nextCoding.getSystem(), baseOptions.getFhirVersion())) {
|
||||
ValidationResult vr = checkCodeOnServer(stack, valueset, nextCoding);
|
||||
ok = processTxIssues(errors, vr, element, path, null, "ex-checkBindings", false, null) && ok;
|
||||
ok = processTxIssues(errors, vr, element, path, false, null, null) && ok;
|
||||
|
||||
if (vr.getSeverity() != null && !vr.messageIsInIssues()) {
|
||||
if (vr.getSeverity() == IssueSeverity.INFORMATION) {
|
||||
|
@ -1721,7 +1746,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
if (strength == BindingStrength.REQUIRED) {
|
||||
removeTrackedMessagesForLocation(errors, element, path);
|
||||
}
|
||||
ok = processTxIssues(errors, vr, element, path, notFoundSeverityForBinding(strength), notFoundSeverityNoteForBinding(strength), false, vsRef) && ok;
|
||||
ok = processTxIssues(errors, vr, element, path, false, vsRef, strength) && ok;
|
||||
timeTracker.tx(t, "vc "+system+"#"+code+" '"+display+"'");
|
||||
if (vr != null && !vr.isOk()) {
|
||||
if (vr.IsNoService())
|
||||
|
@ -1766,6 +1791,21 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
return ok;
|
||||
}
|
||||
|
||||
private Set<String> getUnknownSystems(ValidationResult vr) {
|
||||
if (vr == null) {
|
||||
return null;
|
||||
}
|
||||
if (vr.getUnknownSystems() != null && !vr.getUnknownSystems().isEmpty()) {
|
||||
return vr.getUnknownSystems();
|
||||
}
|
||||
if (vr.getSystem() != null) {
|
||||
Set<String> set = new HashSet<String>();
|
||||
set.add(vr.getSystem());
|
||||
return set;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean convertCDACodeToCodeableConcept(List<ValidationMessage> errors, String path, Element element, StructureDefinition logical, CodeableConcept cc) {
|
||||
boolean ok = true;
|
||||
cc.setText(element.getNamedChildValue("originalText", false));
|
||||
|
@ -1851,7 +1891,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
try {
|
||||
long t = System.nanoTime();
|
||||
ValidationResult vr = checkCodeOnServer(stack, valueset, cc);
|
||||
ok = processTxIssues(errors, vr, element, path, null, "ex-checkMaxValueSet", false, maxVSUrl) && ok;
|
||||
ok = processTxIssues(errors, vr, element, path, false, maxVSUrl, null) && ok;
|
||||
timeTracker.tx(t, "vc "+cc.toString());
|
||||
if (!vr.isOk()) {
|
||||
if (vr.getErrorClass() != null && vr.getErrorClass().isInfrastructure())
|
||||
|
@ -1890,7 +1930,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
try {
|
||||
long t = System.nanoTime();
|
||||
ValidationResult vr = checkCodeOnServer(stack, valueset, c);
|
||||
ok = processTxIssues(errors, vr, element, path, null, "ex-checkMaxValueSet-2", false, maxVSUrl) && ok;
|
||||
ok = processTxIssues(errors, vr, element, path, false, maxVSUrl, null) && ok;
|
||||
|
||||
timeTracker.tx(t, "vc "+c.getSystem()+"#"+c.getCode()+" '"+c.getDisplay()+"'");
|
||||
if (!vr.isOk()) {
|
||||
|
@ -1921,7 +1961,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
try {
|
||||
long t = System.nanoTime();
|
||||
ValidationResult vr = checkCodeOnServer(stack, valueset, value, baseOptions);
|
||||
ok = processTxIssues(errors, vr, element, path, null, "ex-checkMaxValueSet-3", false, maxVSUrl) && ok;
|
||||
ok = processTxIssues(errors, vr, element, path, false, maxVSUrl, null) && ok;
|
||||
timeTracker.tx(t, "vc "+value);
|
||||
if (!vr.isOk()) {
|
||||
if (vr.getErrorClass() != null && vr.getErrorClass().isInfrastructure())
|
||||
|
@ -2045,7 +2085,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
checked.set(true);
|
||||
vr = checkCodeOnServer(stack, valueset, c);
|
||||
}
|
||||
ok = processTxIssues(errors, vr, element, path, notFoundSeverityForBinding(strength), notFoundSeverityNoteForBinding(strength), strength == BindingStrength.EXTENSIBLE, vsRef) && ok;
|
||||
ok = processTxIssues(errors, vr, element, path, strength == BindingStrength.EXTENSIBLE, vsRef, strength) && ok;
|
||||
|
||||
timeTracker.tx(t, "vc "+c.getSystem()+"#"+c.getCode()+" '"+c.getDisplay()+"'");
|
||||
if (strength == BindingStrength.REQUIRED) {
|
||||
|
@ -3510,7 +3550,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
}
|
||||
vr = checkCodeOnServer(stack, vs, value, options);
|
||||
}
|
||||
ok = processTxIssues(errors, vr, element, path, notFoundSeverityForBinding(binding.getStrength()), notFoundSeverityNoteForBinding(binding.getStrength()), binding.getStrength() != BindingStrength.REQUIRED, binding.getValueSet()) && ok;
|
||||
ok = processTxIssues(errors, vr, element, path, binding.getStrength() != BindingStrength.REQUIRED, binding.getValueSet(), binding.getStrength()) && ok;
|
||||
|
||||
timeTracker.tx(t, "vc "+value+"");
|
||||
if (binding.getStrength() == BindingStrength.REQUIRED) {
|
||||
|
@ -7791,4 +7831,14 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
this.fetcher = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isUnknownCodeSystemsCauseErrors() {
|
||||
return unknownCodeSystemsCauseErrors;
|
||||
}
|
||||
|
||||
public void setUnknownCodeSystemsCauseErrors(boolean unknownCodeSystemsCauseErrors) {
|
||||
this.unknownCodeSystemsCauseErrors = unknownCodeSystemsCauseErrors;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -61,7 +61,7 @@ public class FHIRPathExpressionFixer {
|
|||
}
|
||||
// con-3 in R4
|
||||
if (expr.equals("clinicalStatus.exists() or verificationStatus.coding.where(system='http://terminology.hl7.org/CodeSystem/condition-ver-status' and code = 'entered-in-error').exists() or category.select($this='problem-list-item').empty()")) {
|
||||
return "clinicalStatus.exists() or verificationStatus.coding.where(system='http://terminology.hl7.org/CodeSystem/condition-ver-status' and code = 'entered-in-error').exists() or category.coding.exists(system='http://terminology.hl7.org/CodeSystem/condition-category' and code ='problem-list-item').empty()";
|
||||
return "(verificationStatus.coding.where(system='http://terminology.hl7.org/CodeSystem/condition-ver-status' and code = 'entered-in-error').exists() and category.coding.exists(system='http://terminology.hl7.org/CodeSystem/condition-category' and code ='problem-list-item').empty()) implies (clinicalStatus.exists())";
|
||||
}
|
||||
|
||||
// R5 ballot
|
||||
|
|
|
@ -8,10 +8,10 @@ import java.util.Collections;
|
|||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import org.hl7.fhir.ParametersParameter;
|
||||
|
||||
import org.hl7.fhir.r5.formats.IParser.OutputStyle;
|
||||
import org.hl7.fhir.r5.formats.JsonParser;
|
||||
import org.hl7.fhir.r5.model.Base;
|
||||
|
||||
import org.hl7.fhir.r5.model.Extension;
|
||||
import org.hl7.fhir.r5.model.OperationOutcome;
|
||||
import org.hl7.fhir.r5.model.OperationOutcome.OperationOutcomeIssueComponent;
|
||||
|
|
|
@ -247,9 +247,9 @@ public class ValidationEngineTests {
|
|||
Assertions.assertTrue(checkOutcomes("testObs102", op,
|
||||
"Observation.text.div null error/invalid: Wrong namespace on the XHTML ('null', should be 'http://www.w3.org/1999/xhtml')\n"+
|
||||
"Observation.category null information/business-rule: Reference to experimental CodeSystem http://hl7.org/fhir/observation-category\n"+
|
||||
"Observation.code.coding[2].system null information/not-found: A definition for CodeSystem 'http://acme.org/devices/clinical-codes' could not be found, so the code cannot be validated\n"+
|
||||
"Observation null warning/invalid: Best Practice Recommendation: In general, all observations should have a performer\n"+
|
||||
"Observation null warning/invalid: Best Practice Recommendation: In general, all observations should have an effective[x] ()"));
|
||||
"Observation null warning/invalid: Best Practice Recommendation: In general, all observations should have an effective[x] ()\n"+
|
||||
"Observation.code.coding[2].system null warning/not-found: A definition for CodeSystem 'http://acme.org/devices/clinical-codes' could not be found, so the code cannot be validated"));
|
||||
verifyNoTerminologyRequests(logger);
|
||||
}
|
||||
|
||||
|
@ -265,8 +265,8 @@ public class ValidationEngineTests {
|
|||
System.out.println(" .. load USCore");
|
||||
OperationOutcome op = ve.validate(FhirFormat.XML, TestingUtilities.loadTestResourceStream("validator", "observation301.xml"), null);
|
||||
Assertions.assertTrue(checkOutcomes("test301", op,
|
||||
"Observation.code.coding[3].system null information/not-found: A definition for CodeSystem 'http://acme.org/devices/clinical-codes' could not be found, so the code cannot be validated\n"+
|
||||
"Observation null warning/invalid: Best Practice Recommendation: In general, all observations should have a performer"));
|
||||
"Observation null warning/invalid: Best Practice Recommendation: In general, all observations should have a performer\n"+
|
||||
"Observation.code.coding[3].system null warning/not-found: A definition for CodeSystem 'http://acme.org/devices/clinical-codes' could not be found, so the code cannot be validated"));
|
||||
verifyNoTerminologyRequests(logger);
|
||||
}
|
||||
|
||||
|
|
4
pom.xml
4
pom.xml
|
@ -14,14 +14,14 @@
|
|||
HAPI FHIR
|
||||
-->
|
||||
<artifactId>org.hl7.fhir.core</artifactId>
|
||||
<version>6.3.24-SNAPSHOT</version>
|
||||
<version>6.3.26-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<properties>
|
||||
<commons_compress_version>1.26.0</commons_compress_version>
|
||||
<guava_version>32.0.1-jre</guava_version>
|
||||
<hapi_fhir_version>6.4.1</hapi_fhir_version>
|
||||
<validator_test_case_version>1.5.21-SNAPSHOT</validator_test_case_version>
|
||||
<validator_test_case_version>1.5.22-SNAPSHOT</validator_test_case_version>
|
||||
<jackson_version>2.17.0</jackson_version>
|
||||
<junit_jupiter_version>5.9.2</junit_jupiter_version>
|
||||
<junit_platform_launcher_version>1.8.2</junit_platform_launcher_version>
|
||||
|
|
Loading…
Reference in New Issue