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
|
## 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
|
## 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>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>org.hl7.fhir.core</artifactId>
|
<artifactId>org.hl7.fhir.core</artifactId>
|
||||||
<version>6.3.24-SNAPSHOT</version>
|
<version>6.3.26-SNAPSHOT</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>org.hl7.fhir.core</artifactId>
|
<artifactId>org.hl7.fhir.core</artifactId>
|
||||||
<version>6.3.24-SNAPSHOT</version>
|
<version>6.3.26-SNAPSHOT</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>org.hl7.fhir.core</artifactId>
|
<artifactId>org.hl7.fhir.core</artifactId>
|
||||||
<version>6.3.24-SNAPSHOT</version>
|
<version>6.3.26-SNAPSHOT</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>org.hl7.fhir.core</artifactId>
|
<artifactId>org.hl7.fhir.core</artifactId>
|
||||||
<version>6.3.24-SNAPSHOT</version>
|
<version>6.3.26-SNAPSHOT</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>org.hl7.fhir.core</artifactId>
|
<artifactId>org.hl7.fhir.core</artifactId>
|
||||||
<version>6.3.24-SNAPSHOT</version>
|
<version>6.3.26-SNAPSHOT</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>org.hl7.fhir.core</artifactId>
|
<artifactId>org.hl7.fhir.core</artifactId>
|
||||||
<version>6.3.24-SNAPSHOT</version>
|
<version>6.3.26-SNAPSHOT</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>org.hl7.fhir.core</artifactId>
|
<artifactId>org.hl7.fhir.core</artifactId>
|
||||||
<version>6.3.24-SNAPSHOT</version>
|
<version>6.3.26-SNAPSHOT</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -289,7 +289,7 @@ public class ProfilePathProcessor {
|
||||||
start++;
|
start++;
|
||||||
} else {
|
} else {
|
||||||
// we're just going to accept the differential slicing at face value
|
// 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()));
|
outcome.setPath(profileUtilities.fixedPathDest(getContextPathTarget(), outcome.getPath(), getRedirector(), getContextPathSource()));
|
||||||
profileUtilities.updateFromBase(outcome, currentBase, getSourceStructureDefinition().getUrl());
|
profileUtilities.updateFromBase(outcome, currentBase, getSourceStructureDefinition().getUrl());
|
||||||
|
|
||||||
|
@ -667,14 +667,14 @@ public class ProfilePathProcessor {
|
||||||
// some of what's in currentBase overrides template
|
// some of what's in currentBase overrides template
|
||||||
template = profileUtilities.fillOutFromBase(template, currentBase);
|
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()));
|
outcome.setPath(profileUtilities.fixedPathDest(getContextPathTarget(), outcome.getPath(), getRedirector(), getContextPathSource()));
|
||||||
|
|
||||||
res = outcome;
|
res = outcome;
|
||||||
profileUtilities.updateFromBase(outcome, currentBase, getSourceStructureDefinition().getUrl());
|
profileUtilities.updateFromBase(outcome, currentBase, getSourceStructureDefinition().getUrl());
|
||||||
if (diffMatches.get(0).hasSliceName()) {
|
if (diffMatches.get(0).hasSliceName()) {
|
||||||
template = currentBase.copy();
|
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()));
|
template.setPath(profileUtilities.fixedPathDest(getContextPathTarget(), template.getPath(), getRedirector(), getContextPathSource()));
|
||||||
|
|
||||||
checkToSeeIfSlicingExists(diffMatches.get(0), template);
|
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) {
|
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()));
|
outcome.setPath(profileUtilities.fixedPathDest(getContextPathTarget(), outcome.getPath(), getRedirector(), getContextPathSource()));
|
||||||
profileUtilities.updateFromBase(outcome, currentBase, getSourceStructureDefinition().getUrl());
|
profileUtilities.updateFromBase(outcome, currentBase, getSourceStructureDefinition().getUrl());
|
||||||
profileUtilities.updateConstraintSources(outcome, getSourceStructureDefinition().getUrl());
|
profileUtilities.updateConstraintSources(outcome, getSourceStructureDefinition().getUrl());
|
||||||
profileUtilities.checkExtensions(outcome);
|
profileUtilities.checkExtensions(outcome);
|
||||||
profileUtilities.updateFromObligationProfiles(outcome);
|
profileUtilities.updateFromObligationProfiles(outcome);
|
||||||
profileUtilities.updateURLs(url, webUrl, outcome);
|
profileUtilities.updateURLs(url, webUrl, outcome, true);
|
||||||
profileUtilities.markDerived(outcome);
|
profileUtilities.markDerived(outcome);
|
||||||
if (cursors.resultPathBase == null)
|
if (cursors.resultPathBase == null)
|
||||||
cursors.resultPathBase = outcome.getPath();
|
cursors.resultPathBase = outcome.getPath();
|
||||||
|
@ -1033,7 +1033,7 @@ public class ProfilePathProcessor {
|
||||||
if (!currentBase.isChoice() && !profileUtilities.ruleMatches(dSlice.getRules(), bSlice.getRules()))
|
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));
|
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()));
|
outcome.setPath(profileUtilities.fixedPathDest(getContextPathTarget(), outcome.getPath(), getRedirector(), getContextPathSource()));
|
||||||
profileUtilities.updateFromBase(outcome, currentBase, getSourceStructureDefinition().getUrl());
|
profileUtilities.updateFromBase(outcome, currentBase, getSourceStructureDefinition().getUrl());
|
||||||
if (diffMatches.get(0).hasSlicing() || !diffMatches.get(0).hasSliceName()) {
|
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
|
// We need to copy children of the backbone element before we start messing around with slices
|
||||||
int newBaseLimit = profileUtilities.findEndOfElement(cursors.base, cursors.baseCursor);
|
int newBaseLimit = profileUtilities.findEndOfElement(cursors.base, cursors.baseCursor);
|
||||||
for (int i = cursors.baseCursor + 1; i <= newBaseLimit; i++) {
|
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()));
|
outcome.setPath(profileUtilities.fixedPathDest(getContextPathTarget(), outcome.getPath(), getRedirector(), getContextPathSource()));
|
||||||
debugCheck(outcome);
|
debugCheck(outcome);
|
||||||
getResult().getElement().add(outcome);
|
getResult().getElement().add(outcome);
|
||||||
|
@ -1106,7 +1106,7 @@ public class ProfilePathProcessor {
|
||||||
List<ElementDefinition> baseMatches = profileUtilities.getSiblings(cursors.base.getElement(), currentBase);
|
List<ElementDefinition> baseMatches = profileUtilities.getSiblings(cursors.base.getElement(), currentBase);
|
||||||
for (ElementDefinition baseItem : baseMatches) {
|
for (ElementDefinition baseItem : baseMatches) {
|
||||||
cursors.baseCursor = cursors.base.getElement().indexOf(baseItem);
|
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());
|
profileUtilities.updateFromBase(outcome, currentBase, getSourceStructureDefinition().getUrl());
|
||||||
outcome.setPath(profileUtilities.fixedPathDest(getContextPathTarget(), outcome.getPath(), getRedirector(), getContextPathSource()));
|
outcome.setPath(profileUtilities.fixedPathDest(getContextPathTarget(), outcome.getPath(), getRedirector(), getContextPathSource()));
|
||||||
outcome.setSlicing(null);
|
outcome.setSlicing(null);
|
||||||
|
@ -1139,7 +1139,7 @@ public class ProfilePathProcessor {
|
||||||
cursors.baseCursor++;
|
cursors.baseCursor++;
|
||||||
// just copy any children on the base
|
// 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)) {
|
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()));
|
outcome.setPath(profileUtilities.fixedPathDest(getContextPathTarget(), outcome.getPath(), getRedirector(), getContextPathSource()));
|
||||||
if (!outcome.getPath().startsWith(cursors.resultPathBase))
|
if (!outcome.getPath().startsWith(cursors.resultPathBase))
|
||||||
throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.ADDING_WRONG_PATH));
|
throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.ADDING_WRONG_PATH));
|
||||||
|
@ -1166,7 +1166,7 @@ public class ProfilePathProcessor {
|
||||||
for (ElementDefinition baseItem : baseMatches)
|
for (ElementDefinition baseItem : baseMatches)
|
||||||
if (baseItem.getSliceName().equals(diffItem.getSliceName()))
|
if (baseItem.getSliceName().equals(diffItem.getSliceName()))
|
||||||
throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.NAMED_ITEMS_ARE_OUT_OF_ORDER_IN_THE_SLICE));
|
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 = updateURLs(url, diffItem.copy());
|
||||||
outcome.setPath(profileUtilities.fixedPathDest(getContextPathTarget(), outcome.getPath(), getRedirector(), getContextPathSource()));
|
outcome.setPath(profileUtilities.fixedPathDest(getContextPathTarget(), outcome.getPath(), getRedirector(), getContextPathSource()));
|
||||||
profileUtilities.updateFromBase(outcome, currentBase, getSourceStructureDefinition().getUrl());
|
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) {
|
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)) {
|
if (profileUtilities.hasInnerDiffMatches(getDifferential(), path, cursors.diffCursor, getDiffLimit(), cursors.base.getElement(), true)) {
|
||||||
// so we just copy it in
|
// 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()));
|
outcome.setPath(profileUtilities.fixedPathDest(getContextPathTarget(), outcome.getPath(), getRedirector(), getContextPathSource()));
|
||||||
profileUtilities.updateFromBase(outcome, currentBase, getSourceStructureDefinition().getUrl());
|
profileUtilities.updateFromBase(outcome, currentBase, getSourceStructureDefinition().getUrl());
|
||||||
profileUtilities.markDerived(outcome);
|
profileUtilities.markDerived(outcome);
|
||||||
|
@ -1457,7 +1457,7 @@ public class ProfilePathProcessor {
|
||||||
// the differential doesn't say anything about this item
|
// the differential doesn't say anything about this item
|
||||||
// copy across the currentbase, and all of its children and siblings
|
// 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)) {
|
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()));
|
outcome.setPath(profileUtilities.fixedPathDest(getContextPathTarget(), outcome.getPath(), getRedirector(), getContextPathSource()));
|
||||||
if (!outcome.getPath().startsWith(cursors.resultPathBase))
|
if (!outcome.getPath().startsWith(cursors.resultPathBase))
|
||||||
throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.ADDING_WRONG_PATH_IN_PROFILE___VS_, getProfileName(), outcome.getPath(), 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) {
|
if (existing != null) {
|
||||||
updateFromDefinition(existing, e, profileName, false, url, base, derived, "StructureDefinition.differential.element["+i+"]", mappingDetails);
|
updateFromDefinition(existing, e, profileName, false, url, base, derived, "StructureDefinition.differential.element["+i+"]", mappingDetails);
|
||||||
} else {
|
} else {
|
||||||
ElementDefinition outcome = updateURLs(url, webUrl, e.copy());
|
ElementDefinition outcome = updateURLs(url, webUrl, e.copy(), true);
|
||||||
e.setUserData(UD_GENERATED_IN_SNAPSHOT, outcome);
|
e.setUserData(UD_GENERATED_IN_SNAPSHOT, outcome);
|
||||||
derived.getSnapshot().addElement(outcome);
|
derived.getSnapshot().addElement(outcome);
|
||||||
if (walksInto(diff.getElement(), e)) {
|
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);
|
// don't do this. should already be in snapshot ... addInheritedElementsForSpecialization(snapshot, focus, sd.getBaseDefinition(), path, url, weburl);
|
||||||
for (ElementDefinition ed : sd.getSnapshot().getElement()) {
|
for (ElementDefinition ed : sd.getSnapshot().getElement()) {
|
||||||
if (ed.getPath().contains(".")) {
|
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));
|
outcome.setPath(outcome.getPath().replace(sd.getTypeName(), path));
|
||||||
snapshot.getElement().add(outcome);
|
snapshot.getElement().add(outcome);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1548,7 +1548,6 @@ public class ProfileUtilities {
|
||||||
protected void removeStatusExtensions(ElementDefinition outcome) {
|
protected void removeStatusExtensions(ElementDefinition outcome) {
|
||||||
outcome.removeExtension(ToolingExtensions.EXT_FMM_LEVEL);
|
outcome.removeExtension(ToolingExtensions.EXT_FMM_LEVEL);
|
||||||
outcome.removeExtension(ToolingExtensions.EXT_FMM_SUPPORT);
|
outcome.removeExtension(ToolingExtensions.EXT_FMM_SUPPORT);
|
||||||
outcome.removeExtension(ToolingExtensions.EXT_FMM_DERIVED);
|
|
||||||
outcome.removeExtension(ToolingExtensions.EXT_STANDARDS_STATUS);
|
outcome.removeExtension(ToolingExtensions.EXT_STANDARDS_STATUS);
|
||||||
outcome.removeExtension(ToolingExtensions.EXT_NORMATIVE_VERSION);
|
outcome.removeExtension(ToolingExtensions.EXT_NORMATIVE_VERSION);
|
||||||
outcome.removeExtension(ToolingExtensions.EXT_WORKGROUP);
|
outcome.removeExtension(ToolingExtensions.EXT_WORKGROUP);
|
||||||
|
@ -1911,7 +1910,7 @@ public class ProfileUtilities {
|
||||||
* @param element - the Element to update
|
* @param element - the Element to update
|
||||||
* @return - the updated Element
|
* @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) {
|
if (element != null) {
|
||||||
ElementDefinition defn = element;
|
ElementDefinition defn = element;
|
||||||
if (defn.hasBinding() && defn.getBinding().hasValueSet() && defn.getBinding().getValueSet().startsWith("#"))
|
if (defn.hasBinding() && defn.getBinding().hasValueSet() && defn.getBinding().getValueSet().startsWith("#"))
|
||||||
|
@ -1929,24 +1928,24 @@ public class ProfileUtilities {
|
||||||
if (webUrl != null) {
|
if (webUrl != null) {
|
||||||
// also, must touch up the markdown
|
// also, must touch up the markdown
|
||||||
if (element.hasDefinition()) {
|
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()) {
|
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()) {
|
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()) {
|
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()) {
|
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()) {
|
for (Extension ext : element.getExtension()) {
|
||||||
if (ext.hasValueMarkdownType()) {
|
if (ext.hasValueMarkdownType()) {
|
||||||
MarkdownType md = ext.getValueMarkdownType();
|
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) {
|
if (elist.size() == 2) {
|
||||||
dest.getExtension().remove(elist.get(1));
|
dest.getExtension().remove(elist.get(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
updateExtensionsFromDefinition(dest, source);
|
updateExtensionsFromDefinition(dest, source);
|
||||||
|
|
||||||
for (ElementDefinition ed : obligationProfileElements) {
|
for (ElementDefinition ed : obligationProfileElements) {
|
||||||
|
@ -2423,6 +2421,9 @@ public class ProfileUtilities {
|
||||||
if (e.hasDefinition()) {
|
if (e.hasDefinition()) {
|
||||||
base.setDefinition(processRelativeUrls(e.getDefinition(), webroot, context.getSpecUrl(), context.getResourceNames(), masterSourceFileNames, localFileNames, true));
|
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());
|
base.setShort(e.getShort());
|
||||||
if (e.hasCommentElement())
|
if (e.hasCommentElement())
|
||||||
base.setCommentElement(e.getCommentElement());
|
base.setCommentElement(e.getCommentElement());
|
||||||
|
@ -2466,9 +2467,9 @@ public class ProfileUtilities {
|
||||||
if (derived.hasDefinitionElement()) {
|
if (derived.hasDefinitionElement()) {
|
||||||
if (derived.getDefinition().startsWith("..."))
|
if (derived.getDefinition().startsWith("..."))
|
||||||
base.setDefinition(Utilities.appendDerivedTextToBase(base.getDefinition(), derived.getDefinition()));
|
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());
|
base.setDefinitionElement(derived.getDefinitionElement().copy());
|
||||||
else if (trimDifferential)
|
} else if (trimDifferential)
|
||||||
derived.setDefinitionElement(null);
|
derived.setDefinitionElement(null);
|
||||||
else if (derived.hasDefinitionElement())
|
else if (derived.hasDefinitionElement())
|
||||||
derived.getDefinitionElement().setUserData(UD_DERIVATION_EQUALS, true);
|
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));
|
throw new Error(formatMessage(I18nConstants.NO_VALUE_SET_IN_URL));
|
||||||
}
|
}
|
||||||
for (ConceptSetComponent inc : vs.getCompose().getInclude()) {
|
for (ConceptSetComponent inc : vs.getCompose().getInclude()) {
|
||||||
codeSystemsUsed.add(inc.getSystem());
|
if (inc.hasSystem()) {
|
||||||
|
codeSystemsUsed.add(inc.getSystem());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (ConceptSetComponent inc : vs.getCompose().getExclude()) {
|
for (ConceptSetComponent inc : vs.getCompose().getExclude()) {
|
||||||
codeSystemsUsed.add(inc.getSystem());
|
if (inc.hasSystem()) {
|
||||||
|
codeSystemsUsed.add(inc.getSystem());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CacheToken cacheToken = txCache.generateExpandToken(vs, hierarchical);
|
CacheToken cacheToken = txCache.generateExpandToken(vs, hierarchical);
|
||||||
|
|
|
@ -366,7 +366,11 @@ public class ContextUtilities implements ProfileKnowledgeProvider {
|
||||||
public StructureDefinition fetchByJsonName(String key) {
|
public StructureDefinition fetchByJsonName(String key) {
|
||||||
for (StructureDefinition sd : context.fetchResourcesByType(StructureDefinition.class)) {
|
for (StructureDefinition sd : context.fetchResourcesByType(StructureDefinition.class)) {
|
||||||
ElementDefinition ed = sd.getSnapshot().getElementFirstRep();
|
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))) {
|
key.equals(ToolingExtensions.readStringExtension(ed, ToolingExtensions.EXT_JSON_NAME, ToolingExtensions.EXT_JSON_NAME_DEPRECATED))) {
|
||||||
return sd;
|
return sd;
|
||||||
}
|
}
|
||||||
|
|
|
@ -187,7 +187,7 @@ public class FHIRLexer {
|
||||||
cursor++;
|
cursor++;
|
||||||
} else
|
} else
|
||||||
while (cursor < source.length() && ((source.charAt(cursor) >= 'A' && source.charAt(cursor) <= 'Z') || (source.charAt(cursor) >= 'a' && source.charAt(cursor) <= 'z') ||
|
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++;
|
cursor++;
|
||||||
current = source.substring(currentStart, cursor);
|
current = source.substring(currentStart, cursor);
|
||||||
} else if (ch == '/') {
|
} 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);
|
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
|
* 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"))) {
|
if ((focus.hasType("date") || focus.hasType("datetime") || focus.hasType("instant"))) {
|
||||||
return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Decimal, TypeDetails.FP_DateTime);
|
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")) {
|
} else if (focus.hasType("decimal") || focus.hasType("integer")) {
|
||||||
return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Decimal);
|
return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Decimal);
|
||||||
} else {
|
} else {
|
||||||
|
@ -6351,7 +6372,7 @@ public class FHIRPathEngine {
|
||||||
}
|
}
|
||||||
result.addTypes(worker.getResourceNames());
|
result.addTypes(worker.getResourceNames());
|
||||||
} else {
|
} else {
|
||||||
pt = new ProfiledType(t.getCode());
|
pt = new ProfiledType(t.getWorkingCode());
|
||||||
}
|
}
|
||||||
if (pt != null) {
|
if (pt != null) {
|
||||||
if (t.hasProfile()) {
|
if (t.hasProfile()) {
|
||||||
|
|
|
@ -3431,7 +3431,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
|
||||||
sdMapCache.put(url, sdCache);
|
sdMapCache.put(url, sdCache);
|
||||||
String webroot = sd.getUserString("webroot");
|
String webroot = sd.getUserString("webroot");
|
||||||
for (ElementDefinition e : sd.getSnapshot().getElement()) {
|
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);
|
sdCache.put(e.getId(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -754,16 +754,7 @@ public class ValueSetRenderer extends TerminologyRenderer {
|
||||||
if (ref == null) {
|
if (ref == null) {
|
||||||
ref = (String) cs.getWebPath();
|
ref = (String) cs.getWebPath();
|
||||||
}
|
}
|
||||||
if (ref == null && cs.hasUserData("webroot")) {
|
return ref == null ? null : ref.replace("\\", "/");
|
||||||
ref = (String) cs.getUserData("webroot");
|
|
||||||
}
|
|
||||||
if (ref == null) {
|
|
||||||
return "?ngen-14?.html";
|
|
||||||
}
|
|
||||||
if (!ref.contains(".html")) {
|
|
||||||
ref = ref + ".html";
|
|
||||||
}
|
|
||||||
return ref.replace("\\", "/");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void scanForDesignations(ValueSetExpansionContainsComponent c, List<String> langs, Map<String, String> designations) {
|
private void scanForDesignations(ValueSetExpansionContainsComponent c, List<String> langs, Map<String, String> designations) {
|
||||||
|
@ -922,14 +913,18 @@ public class ValueSetRenderer extends TerminologyRenderer {
|
||||||
td.addText(code);
|
td.addText(code);
|
||||||
} else {
|
} else {
|
||||||
String href = context.fixReference(getCsRef(e));
|
String href = context.fixReference(getCsRef(e));
|
||||||
if (href.contains("#"))
|
if (href == null) {
|
||||||
href = href + "-"+Utilities.nmtokenize(code);
|
td.code().tx(code);
|
||||||
else
|
} else {
|
||||||
href = href + "#"+e.getId()+"-"+Utilities.nmtokenize(code);
|
if (href.contains("#"))
|
||||||
if (isAbstract)
|
href = href + "-"+Utilities.nmtokenize(code);
|
||||||
td.ah(context.prefixLocalHref(href)).setAttribute("title", context.formatPhrase(RenderingContext.VS_ABSTRACT_CODE_HINT)).i().addText(code);
|
else
|
||||||
else
|
href = href + "#"+e.getId()+"-"+Utilities.nmtokenize(code);
|
||||||
td.ah(context.prefixLocalHref(href)).addText(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())+" ");
|
wli.tx(f.getProperty()+" "+describe(f.getOp())+" ");
|
||||||
if (e != null && codeExistsInValueSet(e, f.getValue())) {
|
if (e != null && codeExistsInValueSet(e, f.getValue())) {
|
||||||
String href = getContext().fixReference(getCsRef(e));
|
String href = getContext().fixReference(getCsRef(e));
|
||||||
if (href.contains("#"))
|
if (href == null) {
|
||||||
href = href + "-"+Utilities.nmtokenize(f.getValue());
|
wli.code().tx(f.getValue());
|
||||||
else
|
} else {
|
||||||
href = href + "#"+e.getId()+"-"+Utilities.nmtokenize(f.getValue());
|
if (href.contains("#"))
|
||||||
wli.ah(context.prefixLocalHref(href)).addText(f.getValue());
|
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()) {
|
} else if (inc.hasSystem()) {
|
||||||
wli.addText(f.getValue());
|
wli.addText(f.getValue());
|
||||||
ValidationResult vr = getContext().getWorker().validateCode(getContext().getTerminologyServiceOptions(), inc.getSystem(), inc.getVersion(), f.getValue(), null);
|
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) {
|
public String fixReference(String ref) {
|
||||||
|
if (ref == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
if (!Utilities.isAbsoluteUrl(ref)) {
|
if (!Utilities.isAbsoluteUrl(ref)) {
|
||||||
return (localPrefix == null ? "" : localPrefix)+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());
|
excludeCodes(wc, importValueSetForExclude(wc, imp.getValue(), exp, expParams, false, vs).getExpansion());
|
||||||
}
|
}
|
||||||
|
|
||||||
CodeSystem cs = context.fetchSupplementedCodeSystem(exc.getSystem());
|
if (exc.hasSystem()) {
|
||||||
if ((cs == null || cs.getContent() != CodeSystemContentMode.COMPLETE) && context.supportsSystem(exc.getSystem(), opContext.getOptions().getFhirVersion())) {
|
CodeSystem cs = context.fetchSupplementedCodeSystem(exc.getSystem());
|
||||||
ValueSetExpansionOutcome vse = context.expandVS(exc, false, false);
|
if ((cs == null || cs.getContent() != CodeSystemContentMode.COMPLETE) && context.supportsSystem(exc.getSystem(), opContext.getOptions().getFhirVersion())) {
|
||||||
ValueSet valueset = vse.getValueset();
|
ValueSetExpansionOutcome vse = context.expandVS(exc, false, false);
|
||||||
if (valueset == null)
|
ValueSet valueset = vse.getValueset();
|
||||||
throw failTSE("Error Expanding ValueSet: "+vse.getError());
|
if (valueset == null)
|
||||||
excludeCodes(wc, valueset.getExpansion());
|
throw failTSE("Error Expanding ValueSet: "+vse.getError());
|
||||||
return;
|
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);
|
|
||||||
}
|
}
|
||||||
List<WorkingContext> filters = new ArrayList<>();
|
|
||||||
for (int i = 1; i < exc.getFilter().size(); i++) {
|
for (ConceptReferenceComponent c : exc.getConcept()) {
|
||||||
WorkingContext wc1 = new WorkingContext();
|
excludeCode(wc, exc.getSystem(), c.getCode());
|
||||||
filters.add(wc1);
|
}
|
||||||
processFilter(exc, exp, expParams, null, cs, false, exc.getFilter().get(i), wc1, null, true);
|
|
||||||
|
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();
|
expParams = makeDefaultExpansion();
|
||||||
altCodeParams.seeParameters(expParams);
|
altCodeParams.seeParameters(expParams);
|
||||||
altCodeParams.seeValueSet(source);
|
altCodeParams.seeValueSet(source);
|
||||||
|
|
||||||
source.checkNoModifiers("ValueSet", "expanding");
|
source.checkNoModifiers("ValueSet", "expanding");
|
||||||
focus = source.copy();
|
focus = source.copy();
|
||||||
focus.setIdBase(null);
|
focus.setIdBase(null);
|
||||||
|
|
|
@ -125,10 +125,8 @@ public class ValueSetValidator extends ValueSetProcessBase {
|
||||||
public String getMessage() {
|
public String getMessage() {
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private ValueSet valueset;
|
private ValueSet valueset;
|
||||||
private Map<String, ValueSetValidator> inner = new HashMap<>();
|
private Map<String, ValueSetValidator> inner = new HashMap<>();
|
||||||
private ValidationOptions options;
|
private ValidationOptions options;
|
||||||
|
|
|
@ -103,7 +103,7 @@ public class Runner implements IEvaluationContext {
|
||||||
for (JsonObject w : vd.getJsonObjects("where")) {
|
for (JsonObject w : vd.getJsonObjects("where")) {
|
||||||
String expr = w.asString("path");
|
String expr = w.asString("path");
|
||||||
ExpressionNode node = fpe.parse(expr);
|
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) {
|
if (!pass) {
|
||||||
ok = false;
|
ok = false;
|
||||||
break;
|
break;
|
||||||
|
@ -114,7 +114,7 @@ public class Runner implements IEvaluationContext {
|
||||||
rows.add(new ArrayList<Cell>());
|
rows.add(new ArrayList<Cell>());
|
||||||
|
|
||||||
for (JsonObject select : vd.getJsonObjects("select")) {
|
for (JsonObject select : vd.getJsonObjects("select")) {
|
||||||
executeSelect(select, b, rows);
|
executeSelect(vd, select, b, rows);
|
||||||
}
|
}
|
||||||
for (List<Cell> row : rows) {
|
for (List<Cell> row : rows) {
|
||||||
storage.addRow(store, row);
|
storage.addRow(store, row);
|
||||||
|
@ -124,14 +124,14 @@ public class Runner implements IEvaluationContext {
|
||||||
storage.finish(store);
|
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<>();
|
List<Base> focus = new ArrayList<>();
|
||||||
|
|
||||||
if (select.has("forEach")) {
|
if (select.has("forEach")) {
|
||||||
focus.addAll(executeForEach(select, b));
|
focus.addAll(executeForEach(vd, select, b));
|
||||||
} else if (select.has("forEachOrNull")) {
|
} else if (select.has("forEachOrNull")) {
|
||||||
|
|
||||||
focus.addAll(executeForEachOrNull(select, b));
|
focus.addAll(executeForEachOrNull(vd, select, b));
|
||||||
if (focus.isEmpty()) {
|
if (focus.isEmpty()) {
|
||||||
List<Column> columns = (List<Column>) select.getUserData("columns");
|
List<Column> columns = (List<Column>) select.getUserData("columns");
|
||||||
for (List<Cell> row : rows) {
|
for (List<Cell> row : rows) {
|
||||||
|
@ -159,20 +159,20 @@ public class Runner implements IEvaluationContext {
|
||||||
List<List<Cell>> rowsToAdd = cloneRows(tempRows);
|
List<List<Cell>> rowsToAdd = cloneRows(tempRows);
|
||||||
|
|
||||||
for (JsonObject column : select.getJsonObjects("column")) {
|
for (JsonObject column : select.getJsonObjects("column")) {
|
||||||
executeColumn(column, f, rowsToAdd);
|
executeColumn(vd, column, f, rowsToAdd);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (JsonObject sub : select.getJsonObjects("select")) {
|
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);
|
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()) {
|
if (unionList.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -183,7 +183,7 @@ public class Runner implements IEvaluationContext {
|
||||||
for (JsonObject union : unionList) {
|
for (JsonObject union : unionList) {
|
||||||
List<List<Cell>> tempRows = new ArrayList<>();
|
List<List<Cell>> tempRows = new ArrayList<>();
|
||||||
tempRows.addAll(sourceRows);
|
tempRows.addAll(sourceRows);
|
||||||
executeSelect(union, b, tempRows);
|
executeSelect(vd, union, b, tempRows);
|
||||||
rows.addAll(tempRows);
|
rows.addAll(tempRows);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -204,25 +204,25 @@ public class Runner implements IEvaluationContext {
|
||||||
return list;
|
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");
|
ExpressionNode n = (ExpressionNode) focus.getUserData("forEach");
|
||||||
List<Base> result = new ArrayList<>();
|
List<Base> result = new ArrayList<>();
|
||||||
result.addAll(fpe.evaluate(b, n));
|
result.addAll(fpe.evaluate(vd, b, n));
|
||||||
return result;
|
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");
|
ExpressionNode n = (ExpressionNode) focus.getUserData("forEachOrNull");
|
||||||
List<Base> result = new ArrayList<>();
|
List<Base> result = new ArrayList<>();
|
||||||
result.addAll(fpe.evaluate(b, n));
|
result.addAll(fpe.evaluate(vd, b, n));
|
||||||
return result;
|
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");
|
ExpressionNode n = (ExpressionNode) column.getUserData("path");
|
||||||
List<Base> bl2 = new ArrayList<>();
|
List<Base> bl2 = new ArrayList<>();
|
||||||
if (b != null) {
|
if (b != null) {
|
||||||
bl2.addAll(fpe.evaluate(b, n));
|
bl2.addAll(fpe.evaluate(vd, b, n));
|
||||||
}
|
}
|
||||||
Column col = (Column) column.getUserData("column");
|
Column col = (Column) column.getUserData("column");
|
||||||
if (col == null) {
|
if (col == null) {
|
||||||
|
@ -344,14 +344,43 @@ public class Runner implements IEvaluationContext {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Base> resolveConstant(FHIRPathEngine engine, Object appContext, String name, boolean beforeContext, boolean explicitConstant) throws PathEngineException {
|
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
|
@Override
|
||||||
public TypeDetails resolveConstantType(FHIRPathEngine engine, Object appContext, String name, boolean explicitConstant) throws PathEngineException {
|
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
|
@Override
|
||||||
public boolean log(String argument, List<Base> focus) {
|
public boolean log(String argument, List<Base> focus) {
|
||||||
throw new Error("Not implemented yet: log");
|
throw new Error("Not implemented yet: log");
|
||||||
|
|
|
@ -2,6 +2,7 @@ package org.hl7.fhir.r5.utils.sql;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.hl7.fhir.exceptions.FHIRException;
|
||||||
import org.hl7.fhir.r5.model.Base;
|
import org.hl7.fhir.r5.model.Base;
|
||||||
import org.hl7.fhir.utilities.json.model.JsonArray;
|
import org.hl7.fhir.utilities.json.model.JsonArray;
|
||||||
import org.hl7.fhir.utilities.json.model.JsonBoolean;
|
import org.hl7.fhir.utilities.json.model.JsonBoolean;
|
||||||
|
@ -33,16 +34,16 @@ public class StorageJson implements Storage {
|
||||||
JsonObject row = new JsonObject();
|
JsonObject row = new JsonObject();
|
||||||
rows.add(row);
|
rows.add(row);
|
||||||
for (Cell cell : cells) {
|
for (Cell cell : cells) {
|
||||||
if (cell.getValues().size() == 0) {
|
if (cell.getColumn().isColl() || cell.getValues().size() > 1) {
|
||||||
row.add(cell.getColumn().getName(), new JsonNull());
|
|
||||||
} else if (cell.getValues().size() == 1) {
|
|
||||||
row.add(cell.getColumn().getName(), makeJsonNode(cell.getValues().get(0)));
|
|
||||||
} else {
|
|
||||||
JsonArray arr = new JsonArray();
|
JsonArray arr = new JsonArray();
|
||||||
row.add(cell.getColumn().getName(), arr);
|
row.add(cell.getColumn().getName(), arr);
|
||||||
for (Value value : cell.getValues()) {
|
for (Value value : cell.getValues()) {
|
||||||
arr.add(makeJsonNode(value));
|
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
|
@Override
|
||||||
public String getKeyForSourceResource(Base res) {
|
public String getKeyForSourceResource(Base res) {
|
||||||
return res.getIdBase();
|
return res.fhirType()+"/"+res.getIdBase();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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.ExpressionNode;
|
||||||
import org.hl7.fhir.r5.fhirpath.FHIRPathEngine;
|
import org.hl7.fhir.r5.fhirpath.FHIRPathEngine;
|
||||||
import org.hl7.fhir.r5.fhirpath.TypeDetails;
|
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.ExpressionNode.CollectionStatus;
|
||||||
import org.hl7.fhir.r5.fhirpath.FHIRPathEngine.IssueMessage;
|
import org.hl7.fhir.r5.fhirpath.FHIRPathEngine.IssueMessage;
|
||||||
import org.hl7.fhir.utilities.Utilities;
|
import org.hl7.fhir.utilities.Utilities;
|
||||||
|
@ -99,7 +120,7 @@ public class Validator {
|
||||||
i = 0;
|
i = 0;
|
||||||
if (checkAllObjects(path, viewDefinition, "where")) {
|
if (checkAllObjects(path, viewDefinition, "where")) {
|
||||||
for (JsonObject where : viewDefinition.getJsonObjects("where")) {
|
for (JsonObject where : viewDefinition.getJsonObjects("where")) {
|
||||||
checkWhere(path+".where["+i+"]", where);
|
checkWhere(viewDefinition, path+".where["+i+"]", where);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -108,7 +129,7 @@ public class Validator {
|
||||||
i = 0;
|
i = 0;
|
||||||
if (checkAllObjects(path, viewDefinition, "select")) {
|
if (checkAllObjects(path, viewDefinition, "select")) {
|
||||||
for (JsonObject select : viewDefinition.getJsonObjects("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++;
|
i++;
|
||||||
}
|
}
|
||||||
if (i == 0) {
|
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<>();
|
List<Column> columns = new ArrayList<>();
|
||||||
select.setUserData("columns", columns);
|
select.setUserData("columns", columns);
|
||||||
checkProperties(select, path, "column", "select", "forEach", "forEachOrNull", "unionAll");
|
checkProperties(select, path, "column", "select", "forEach", "forEachOrNull", "unionAll");
|
||||||
|
|
||||||
if (select.has("forEach")) {
|
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")) {
|
} 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) {
|
if (t != null) {
|
||||||
|
@ -142,7 +163,7 @@ public class Validator {
|
||||||
if (!(e instanceof JsonObject)) {
|
if (!(e instanceof JsonObject)) {
|
||||||
error(path+".column["+i+"]", a, "column["+i+"] is a "+e.type().toName()+" not an object", IssueType.INVALID);
|
error(path+".column["+i+"]", a, "column["+i+"] is a "+e.type().toName()+" not an object", IssueType.INVALID);
|
||||||
} else {
|
} 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)) {
|
if (!(e instanceof JsonObject)) {
|
||||||
error(path+".select["+i+"]", e, "select["+i+"] is not an object", IssueType.INVALID);
|
error(path+".select["+i+"]", e, "select["+i+"] is not an object", IssueType.INVALID);
|
||||||
} else {
|
} else {
|
||||||
columns.addAll(checkSelect(path+".select["+i+"]", (JsonObject) e, t));
|
columns.addAll(checkSelect(vd, path+".select["+i+"]", (JsonObject) e, t));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (select.has("unionAll")) {
|
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()) {
|
if (columns.isEmpty()) {
|
||||||
error(path, select, "The select has no columns or selects", IssueType.REQUIRED);
|
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");
|
JsonElement a = focus.get("unionAll");
|
||||||
if (!(a instanceof JsonArray)) {
|
if (!(a instanceof JsonArray)) {
|
||||||
error(path+".unionAll", a, "union is not an array", IssueType.INVALID);
|
error(path+".unionAll", a, "union is not an array", IssueType.INVALID);
|
||||||
|
@ -203,7 +224,7 @@ public class Validator {
|
||||||
if (!(e instanceof JsonObject)) {
|
if (!(e instanceof JsonObject)) {
|
||||||
error(path+".unionAll["+i+"]", e, "unionAll["+i+"] is not an object", IssueType.INVALID);
|
error(path+".unionAll["+i+"]", e, "unionAll["+i+"] is not an object", IssueType.INVALID);
|
||||||
} else {
|
} else {
|
||||||
unionColumns.add(checkSelect(path+".unionAll["+i+"]", (JsonObject) e, t));
|
unionColumns.add(checkSelect(vd, path+".unionAll["+i+"]", (JsonObject) e, t));
|
||||||
}
|
}
|
||||||
i++;
|
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");
|
checkProperties(column, path, "path", "name", "description", "collection", "type", "tag");
|
||||||
|
|
||||||
if (!column.has("path")) {
|
if (!column.has("path")) {
|
||||||
|
@ -260,7 +281,7 @@ public class Validator {
|
||||||
try {
|
try {
|
||||||
node = fpe.parse(expr);
|
node = fpe.parse(expr);
|
||||||
column.setUserData("path", node);
|
column.setUserData("path", node);
|
||||||
td = fpe.checkOnTypes(null, resourceName, t, node, warnings);
|
td = fpe.checkOnTypes(vd, resourceName, t, node, warnings);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
error(path, expression, e.getMessage(), IssueType.INVALID);
|
error(path, expression, e.getMessage(), IssueType.INVALID);
|
||||||
}
|
}
|
||||||
|
@ -296,25 +317,31 @@ public class Validator {
|
||||||
// ok, name is sorted!
|
// ok, name is sorted!
|
||||||
if (columnName != null) {
|
if (columnName != null) {
|
||||||
column.setUserData("name", columnName);
|
column.setUserData("name", columnName);
|
||||||
boolean isColl = (td.getCollectionStatus() != CollectionStatus.SINGLETON);
|
boolean isColl = false;
|
||||||
if (column.has("collection")) {
|
if (column.has("collection")) {
|
||||||
JsonElement collectionJ = column.get("collection");
|
JsonElement collectionJ = column.get("collection");
|
||||||
if (!(collectionJ instanceof JsonBoolean)) {
|
if (!(collectionJ instanceof JsonBoolean)) {
|
||||||
error(path+".collection", collectionJ, "collection is not a boolean", IssueType.INVALID);
|
error(path+".collection", collectionJ, "collection is not a boolean", IssueType.INVALID);
|
||||||
} else {
|
} else {
|
||||||
boolean collection = collectionJ.asJsonBoolean().asBoolean();
|
boolean collection = collectionJ.asJsonBoolean().asBoolean();
|
||||||
if (!collection && isColl) {
|
if (collection) {
|
||||||
isColl = false;
|
isColl = true;
|
||||||
warning(path, column, "collection is false, but the path statement(s) might return multiple values for the column '"+columnName+"' some inputs");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isColl) {
|
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) {
|
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");
|
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) {
|
} 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");
|
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<>();
|
Set<String> types = new HashSet<>();
|
||||||
if (node.isNullSet()) {
|
if (node.isNullSet()) {
|
||||||
|
@ -330,7 +357,7 @@ public class Validator {
|
||||||
if (typeJ instanceof JsonString) {
|
if (typeJ instanceof JsonString) {
|
||||||
String type = typeJ.asString();
|
String type = typeJ.asString();
|
||||||
if (!td.hasType(type)) {
|
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 {
|
} else {
|
||||||
types.clear();
|
types.clear();
|
||||||
types.add(simpleType(type));
|
types.add(simpleType(type));
|
||||||
|
@ -377,6 +404,8 @@ public class Validator {
|
||||||
case "integer": return ColumnKind.Integer;
|
case "integer": return ColumnKind.Integer;
|
||||||
case "decimal": return ColumnKind.Decimal;
|
case "decimal": return ColumnKind.Decimal;
|
||||||
case "string": return ColumnKind.String;
|
case "string": return ColumnKind.String;
|
||||||
|
case "id": return ColumnKind.String;
|
||||||
|
case "code": return ColumnKind.String;
|
||||||
case "base64Binary": return ColumnKind.Binary;
|
case "base64Binary": return ColumnKind.Binary;
|
||||||
case "time": return ColumnKind.Time;
|
case "time": return ColumnKind.Time;
|
||||||
default: return ColumnKind.Complex;
|
default: return ColumnKind.Complex;
|
||||||
|
@ -384,7 +413,7 @@ public class Validator {
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isSimpleType(String type) {
|
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) {
|
private String simpleType(String type) {
|
||||||
|
@ -413,7 +442,7 @@ public class Validator {
|
||||||
return type;
|
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)) {
|
if (!(expression instanceof JsonString)) {
|
||||||
error(path+".forEach", expression, "forEach is not a string", IssueType.INVALID);
|
error(path+".forEach", expression, "forEach is not a string", IssueType.INVALID);
|
||||||
return null;
|
return null;
|
||||||
|
@ -425,7 +454,7 @@ public class Validator {
|
||||||
try {
|
try {
|
||||||
ExpressionNode n = fpe.parse(expr);
|
ExpressionNode n = fpe.parse(expr);
|
||||||
focus.setUserData("forEach", n);
|
focus.setUserData("forEach", n);
|
||||||
td = fpe.checkOnTypes(null, resourceName, t, n, warnings);
|
td = fpe.checkOnTypes(vd, resourceName, t, n, warnings);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
error(path, expression, e.getMessage(), IssueType.INVALID);
|
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)) {
|
if (!(expression instanceof JsonString)) {
|
||||||
error(path+".forEachOrNull", expression, "forEachOrNull is not a string", IssueType.INVALID);
|
error(path+".forEachOrNull", expression, "forEachOrNull is not a string", IssueType.INVALID);
|
||||||
return null;
|
return null;
|
||||||
|
@ -450,7 +479,7 @@ public class Validator {
|
||||||
try {
|
try {
|
||||||
ExpressionNode n = fpe.parse(expr);
|
ExpressionNode n = fpe.parse(expr);
|
||||||
focus.setUserData("forEachOrNull", n);
|
focus.setUserData("forEachOrNull", n);
|
||||||
td = fpe.checkOnTypes(null, resourceName, t, n, warnings);
|
td = fpe.checkOnTypes(vd, resourceName, t, n, warnings);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
error(path, expression, e.getMessage(), IssueType.INVALID);
|
error(path, expression, e.getMessage(), IssueType.INVALID);
|
||||||
}
|
}
|
||||||
|
@ -477,69 +506,79 @@ public class Validator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (constant.has("valueBase64Binary")) {
|
if (constant.has("valueBase64Binary")) {
|
||||||
checkIsString(path, constant, "valueBase64Binary");
|
checkIsString(path, constant, "valueBase64Binary", new Base64BinaryType());
|
||||||
} else if (constant.has("valueBoolean")) {
|
} else if (constant.has("valueBoolean")) {
|
||||||
checkIsBoolean(path, constant, "valueBoolean");
|
checkIsBoolean(path, constant, "valueBoolean", new BooleanType());
|
||||||
} else if (constant.has("valueCanonical")) {
|
} else if (constant.has("valueCanonical")) {
|
||||||
checkIsString(path, constant, "valueCanonical");
|
checkIsString(path, constant, "valueCanonical", new CanonicalType());
|
||||||
} else if (constant.has("valueCode")) {
|
} else if (constant.has("valueCode")) {
|
||||||
checkIsString(path, constant, "valueCode");
|
checkIsString(path, constant, "valueCode", new CodeType());
|
||||||
} else if (constant.has("valueDate")) {
|
} else if (constant.has("valueDate")) {
|
||||||
checkIsString(path, constant, "valueDate");
|
checkIsString(path, constant, "valueDate", new DateType());
|
||||||
} else if (constant.has("valueDateTime")) {
|
} else if (constant.has("valueDateTime")) {
|
||||||
checkIsString(path, constant, "valueDateTime");
|
checkIsString(path, constant, "valueDateTime", new DateTimeType());
|
||||||
} else if (constant.has("valueDecimal")) {
|
} else if (constant.has("valueDecimal")) {
|
||||||
checkIsNumber(path, constant, "valueDecimal");
|
checkIsNumber(path, constant, "valueDecimal", new DecimalType());
|
||||||
} else if (constant.has("valueId")) {
|
} else if (constant.has("valueId")) {
|
||||||
checkIsString(path, constant, "valueId");
|
checkIsString(path, constant, "valueId", new IdType());
|
||||||
} else if (constant.has("valueInstant")) {
|
} else if (constant.has("valueInstant")) {
|
||||||
checkIsString(path, constant, "valueInstant");
|
checkIsString(path, constant, "valueInstant", new InstantType());
|
||||||
} else if (constant.has("valueInteger")) {
|
} else if (constant.has("valueInteger")) {
|
||||||
checkIsNumber(path, constant, "valueInteger");
|
checkIsNumber(path, constant, "valueInteger", new IntegerType());
|
||||||
} else if (constant.has("valueInteger64")) {
|
} else if (constant.has("valueInteger64")) {
|
||||||
checkIsNumber(path, constant, "valueInteger64");
|
checkIsNumber(path, constant, "valueInteger64", new Integer64Type());
|
||||||
} else if (constant.has("valueOid")) {
|
} else if (constant.has("valueOid")) {
|
||||||
checkIsString(path, constant, "valueOid");
|
checkIsString(path, constant, "valueOid", new OidType());
|
||||||
} else if (constant.has("valueString")) {
|
} else if (constant.has("valueString")) {
|
||||||
checkIsString(path, constant, "valueString");
|
checkIsString(path, constant, "valueString", new StringType());
|
||||||
} else if (constant.has("valuePositiveInt")) {
|
} else if (constant.has("valuePositiveInt")) {
|
||||||
checkIsNumber(path, constant, "valuePositiveInt");
|
checkIsNumber(path, constant, "valuePositiveInt", new PositiveIntType());
|
||||||
} else if (constant.has("valueTime")) {
|
} else if (constant.has("valueTime")) {
|
||||||
checkIsString(path, constant, "valueTime");
|
checkIsString(path, constant, "valueTime", new TimeType());
|
||||||
} else if (constant.has("valueUnsignedInt")) {
|
} else if (constant.has("valueUnsignedInt")) {
|
||||||
checkIsNumber(path, constant, "valueUnsignedInt");
|
checkIsNumber(path, constant, "valueUnsignedInt", new UnsignedIntType());
|
||||||
} else if (constant.has("valueUri")) {
|
} else if (constant.has("valueUri")) {
|
||||||
checkIsString(path, constant, "valueUri");
|
checkIsString(path, constant, "valueUri", new UriType());
|
||||||
} else if (constant.has("valueUrl")) {
|
} else if (constant.has("valueUrl")) {
|
||||||
checkIsString(path, constant, "valueUrl");
|
checkIsString(path, constant, "valueUrl", new UrlType());
|
||||||
} else if (constant.has("valueUuid")) {
|
} else if (constant.has("valueUuid")) {
|
||||||
checkIsString(path, constant, "valueUuid");
|
checkIsString(path, constant, "valueUuid", new UuidType());
|
||||||
} else {
|
} else {
|
||||||
error(path, constant, "No value found", IssueType.REQUIRED);
|
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);
|
JsonElement j = constant.get(name);
|
||||||
if (!(j instanceof JsonString)) {
|
if (!(j instanceof JsonString)) {
|
||||||
error(path+"."+name, j, name+" must be a string", IssueType.INVALID);
|
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);
|
JsonElement j = constant.get(name);
|
||||||
if (!(j instanceof JsonBoolean)) {
|
if (!(j instanceof JsonBoolean)) {
|
||||||
error(path+"."+name, j, name+" must be a boolean", IssueType.INVALID);
|
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);
|
JsonElement j = constant.get(name);
|
||||||
if (!(j instanceof JsonNumber)) {
|
if (!(j instanceof JsonNumber)) {
|
||||||
error(path+"."+name, j, name+" must be a number", IssueType.INVALID);
|
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");
|
checkProperties(where, path, "path", "description");
|
||||||
|
|
||||||
String expr = where.asString("path");
|
String expr = where.asString("path");
|
||||||
|
@ -553,7 +592,7 @@ public class Validator {
|
||||||
try {
|
try {
|
||||||
ExpressionNode n = fpe.parse(expr);
|
ExpressionNode n = fpe.parse(expr);
|
||||||
where.setUserData("path", n);
|
where.setUserData("path", n);
|
||||||
td = fpe.checkOnTypes(null, resourceName, types, n, warnings);
|
td = fpe.checkOnTypes(vd, resourceName, types, n, warnings);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
error(path, where.get("path"), e.getMessage(), IssueType.INVALID);
|
error(path, where.get("path"), e.getMessage(), IssueType.INVALID);
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,23 +83,21 @@ public class SQLOnFhirTests {
|
||||||
this.resources = resources;
|
this.resources = resources;
|
||||||
this.testCase = testCase;
|
this.testCase = testCase;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Stream<Arguments> data() throws ParserConfigurationException, SAXException, IOException {
|
public static Stream<Arguments> data() throws ParserConfigurationException, SAXException, IOException {
|
||||||
List<Arguments> objects = new ArrayList<>();
|
List<Arguments> objects = new ArrayList<>();
|
||||||
File dir = ManagedFileAccess.file("/Users/grahamegrieve/work/sql-on-fhir-v2/tests/content");
|
JsonArray testFiles = (JsonArray) JsonParser.parse(TestingUtilities.loadTestResourceStream("sql-on-fhir", "manifest.json"));
|
||||||
for (File f : dir.listFiles()) {
|
|
||||||
if (f.getName().endsWith(".json")) {
|
for (String s : testFiles.asStrings()) {
|
||||||
JsonObject json = JsonParser.parseObject(f);
|
JsonObject json = JsonParser.parseObject(TestingUtilities.loadTestResourceStream("sql-on-fhir", s));
|
||||||
String name1 = f.getName().replace(".json", "");
|
String name1 = s.replace(".json", "");
|
||||||
List<JsonObject> resources = json.getJsonObjects("resources");
|
List<JsonObject> resources = json.getJsonObjects("resources");
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (JsonObject test : json.getJsonObjects("tests")) {
|
for (JsonObject test : json.getJsonObjects("tests")) {
|
||||||
String name2 = test.asString("title");
|
String name2 = test.asString("title");
|
||||||
objects.add(Arguments.of(name1+":"+name2, new TestDetails(name1+":"+name2, "$.tests["+i+"]", resources, test)));
|
objects.add(Arguments.of(name1+":"+name2, new TestDetails(name1+":"+name2, "$.tests["+i+"]", resources, test)));
|
||||||
i++;
|
i++;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return objects.stream();
|
return objects.stream();
|
||||||
|
@ -110,7 +108,6 @@ public class SQLOnFhirTests {
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
@ParameterizedTest(name = "{index}: file {0}")
|
@ParameterizedTest(name = "{index}: file {0}")
|
||||||
@MethodSource("data")
|
@MethodSource("data")
|
||||||
@Disabled
|
|
||||||
public void test(String name, TestDetails test) throws FileNotFoundException, IOException, FHIRException, org.hl7.fhir.exceptions.FHIRException, UcumException {
|
public void test(String name, TestDetails test) throws FileNotFoundException, IOException, FHIRException, org.hl7.fhir.exceptions.FHIRException, UcumException {
|
||||||
this.details = test;
|
this.details = test;
|
||||||
Runner runner = new Runner();
|
Runner runner = new Runner();
|
||||||
|
@ -137,8 +134,8 @@ public class SQLOnFhirTests {
|
||||||
rows.add("rows", results);
|
rows.add("rows", results);
|
||||||
JsonObject exp = new JsonObject();
|
JsonObject exp = new JsonObject();
|
||||||
exp.add("rows", test.testCase.getJsonArray("expect"));
|
exp.add("rows", test.testCase.getJsonArray("expect"));
|
||||||
sortResults(exp);
|
// sortResults(exp);
|
||||||
sortResults(rows);
|
// sortResults(rows);
|
||||||
String expS = JsonParser.compose(exp, true);
|
String expS = JsonParser.compose(exp, true);
|
||||||
String rowS = JsonParser.compose(rows, true);
|
String rowS = JsonParser.compose(rows, true);
|
||||||
String c = CompareUtilities.checkJsonSrcIsSame(name, expS, rowS, null);
|
String c = CompareUtilities.checkJsonSrcIsSame(name, expS, rowS, null);
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>org.hl7.fhir.core</artifactId>
|
<artifactId>org.hl7.fhir.core</artifactId>
|
||||||
<version>6.3.24-SNAPSHOT</version>
|
<version>6.3.26-SNAPSHOT</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>org.hl7.fhir.core</artifactId>
|
<artifactId>org.hl7.fhir.core</artifactId>
|
||||||
<version>6.3.24-SNAPSHOT</version>
|
<version>6.3.26-SNAPSHOT</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -1491,7 +1491,7 @@ public class Utilities {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean startsWithInList(String s, Collection<String> list) {
|
public static boolean startsWithInList(String s, Collection<String> list) {
|
||||||
if (s == null) {
|
if (s == null || list == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (String l : list) {
|
for (String l : list) {
|
||||||
|
@ -1819,9 +1819,14 @@ public class Utilities {
|
||||||
|
|
||||||
private static Object applyDatePrecision(String v, int precision) {
|
private static Object applyDatePrecision(String v, int precision) {
|
||||||
switch (precision) {
|
switch (precision) {
|
||||||
case 4: return v.substring(0, 4);
|
case 4:
|
||||||
case 6: return v.substring(0, 7);
|
return v.substring(0, 4);
|
||||||
case 8: return v.substring(0, 10);
|
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 14: return v.substring(0, 17);
|
||||||
case 17: return v;
|
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());
|
Utilities.createDirectory(cacheFolder.getAbsolutePath());
|
||||||
createIniFile();
|
createIniFile();
|
||||||
} else {
|
} else {
|
||||||
if (!isCacheFolderValid()) {
|
if (!iniFileExists()) {
|
||||||
|
createIniFile();
|
||||||
|
}
|
||||||
|
if (!isIniFileCurrentVersion()) {
|
||||||
clearCache();
|
clearCache();
|
||||||
createIniFile();
|
createIniFile();
|
||||||
} else {
|
|
||||||
deleteOldTempDirectories();
|
|
||||||
}
|
}
|
||||||
|
deleteOldTempDirectories();
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isCacheFolderValid() throws IOException {
|
private boolean iniFileExists() throws IOException {
|
||||||
String iniPath = getPackagesIniPath();
|
String iniPath = getPackagesIniPath();
|
||||||
File iniFile = ManagedFileAccess.file(iniPath);
|
File iniFile = ManagedFileAccess.file(iniPath);
|
||||||
if (!(iniFile.exists())) {
|
return iniFile.exists();
|
||||||
return false;
|
}
|
||||||
}
|
|
||||||
|
private boolean isIniFileCurrentVersion() throws IOException {
|
||||||
|
String iniPath = getPackagesIniPath();
|
||||||
IniFile ini = new IniFile(iniPath);
|
IniFile ini = new IniFile(iniPath);
|
||||||
String v = ini.getStringProperty("cache", "version");
|
String version = ini.getStringProperty("cache", "version");
|
||||||
return CACHE_VERSION.equals(v);
|
return CACHE_VERSION.equals(version);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void deleteOldTempDirectories() throws IOException {
|
private void deleteOldTempDirectories() throws IOException {
|
||||||
|
|
|
@ -237,9 +237,11 @@ public class NpmPackage {
|
||||||
public List<String> listFiles() {
|
public List<String> listFiles() {
|
||||||
List<String> res = new ArrayList<>();
|
List<String> res = new ArrayList<>();
|
||||||
if (folder != null) {
|
if (folder != null) {
|
||||||
for (File f : folder.listFiles()) {
|
if (folder.exists()) {
|
||||||
if (!f.isDirectory() && !Utilities.existsInList(f.getName(), "package.json", ".index.json", ".index.db", ".oids.json", ".oids.db")) {
|
for (File f : folder.listFiles()) {
|
||||||
res.add(f.getName());
|
if (!f.isDirectory() && !Utilities.existsInList(f.getName(), "package.json", ".index.json", ".index.db", ".oids.json", ".oids.db")) {
|
||||||
|
res.add(f.getName());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} 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 {
|
public void indexFolder(String desc, NpmPackageFolder folder) throws FileNotFoundException, IOException {
|
||||||
List<String> remove = new ArrayList<>();
|
List<String> remove = new ArrayList<>();
|
||||||
NpmPackageIndexBuilder indexer = new NpmPackageIndexBuilder();
|
NpmPackageIndexBuilder indexer = new NpmPackageIndexBuilder();
|
||||||
|
|
|
@ -31,18 +31,19 @@ public class PackageHacker {
|
||||||
|
|
||||||
public static void main(String[] args) throws FileNotFoundException, IOException {
|
public static void main(String[] args) throws FileNotFoundException, IOException {
|
||||||
// new PackageHacker().massEdit(new File("/Users/grahamegrieve/web/hl7.org/fhir"));
|
// 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.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.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.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.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-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.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.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.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.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-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 {
|
// 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);
|
File f = ManagedFileAccess.file(name);
|
||||||
if (!f.exists())
|
if (!f.exists())
|
||||||
throw new Error("Unable to find "+f.getAbsolutePath());
|
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("Altering Package "+f.getAbsolutePath());
|
||||||
System.out.println(nice(pck.getNpm()));
|
System.out.println(nice(pck.getNpm()));
|
||||||
|
|
||||||
if (change(pck.getNpm())) {
|
if (change(pck.getNpm(), path)) {
|
||||||
|
|
||||||
System.out.println("Revised Package");
|
System.out.println("Revised Package");
|
||||||
System.out.println("=======================");
|
System.out.println("=======================");
|
||||||
System.out.println(nice(pck.getNpm()));
|
System.out.println(nice(pck.getNpm()));
|
||||||
System.out.println("=======================");
|
System.out.println("=======================");
|
||||||
// System.out.print("save? y/n: ");
|
System.out.print("save? y/n: ");
|
||||||
// int r = System.in.read();
|
int r = System.in.read();
|
||||||
// if (r == 'y') {
|
if (r == 'y') {
|
||||||
f.renameTo(ManagedFileAccess.file(Utilities.changeFileExt(name, ".tgz.bak")));
|
f.renameTo(ManagedFileAccess.file(Utilities.changeFileExt(name, ".tgz.bak")));
|
||||||
FileOutputStream fso = ManagedFileAccess.outStream(f);
|
FileOutputStream fso = ManagedFileAccess.outStream(f);
|
||||||
try {
|
try {
|
||||||
|
@ -123,7 +124,7 @@ public class PackageHacker {
|
||||||
} finally {
|
} finally {
|
||||||
fso.close();
|
fso.close();
|
||||||
}
|
}
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,13 +143,15 @@ public class PackageHacker {
|
||||||
return JsonParser.compose(json, true);
|
return JsonParser.compose(json, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean change(JsonObject npm) throws FileNotFoundException, IOException {
|
private boolean change(JsonObject npm, String path) throws FileNotFoundException, IOException {
|
||||||
// fixVersions(npm, ver);
|
npm.remove("url");
|
||||||
if (npm.has("notForPublication")) {
|
npm.add("url", path);
|
||||||
npm.remove("notForPublication");
|
return true;
|
||||||
return true;
|
// if (npm.has("notForPublication")) {
|
||||||
}
|
// npm.remove("notForPublication");
|
||||||
return false;
|
// return true;
|
||||||
|
// }
|
||||||
|
// return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fixVersionInContent(Map<String, byte[]> content) {
|
private void fixVersionInContent(Map<String, byte[]> content) {
|
||||||
|
|
|
@ -1,22 +1,25 @@
|
||||||
package org.hl7.fhir.utilities.npm;
|
package org.hl7.fhir.utilities.npm;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
|
import java.io.FileWriter;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
import java.util.UUID;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
import org.hl7.fhir.utilities.IniFile;
|
||||||
import org.hl7.fhir.utilities.filesystem.ManagedFileAccess;
|
import org.hl7.fhir.utilities.filesystem.ManagedFileAccess;
|
||||||
import org.junit.jupiter.api.RepeatedTest;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.condition.DisabledOnOs;
|
import org.junit.jupiter.api.condition.DisabledOnOs;
|
||||||
import org.junit.jupiter.api.condition.EnabledOnOs;
|
import org.junit.jupiter.api.condition.EnabledOnOs;
|
||||||
|
@ -100,7 +103,6 @@ public class FilesystemPackageManagerTests {
|
||||||
@DisabledOnOs(OS.WINDOWS)
|
@DisabledOnOs(OS.WINDOWS)
|
||||||
public void testSystemCacheDirectory() throws IOException {
|
public void testSystemCacheDirectory() throws IOException {
|
||||||
File folder = new FilesystemPackageCacheManager.Builder().withSystemCacheFolder().getCacheFolder();
|
File folder = new FilesystemPackageCacheManager.Builder().withSystemCacheFolder().getCacheFolder();
|
||||||
|
|
||||||
assertEquals( "/var/lib/.fhir/packages", folder.getAbsolutePath());
|
assertEquals( "/var/lib/.fhir/packages", folder.getAbsolutePath());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,6 +126,118 @@ public class FilesystemPackageManagerTests {
|
||||||
return params.stream();
|
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")
|
@MethodSource("packageCacheMultiThreadTestParams")
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
public void packageCacheMultiThreadTest(final int threadTotal, final int packageCacheManagerTotal) throws IOException {
|
public void packageCacheMultiThreadTest(final int threadTotal, final int packageCacheManagerTotal) throws IOException {
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>org.hl7.fhir.core</artifactId>
|
<artifactId>org.hl7.fhir.core</artifactId>
|
||||||
<version>6.3.24-SNAPSHOT</version>
|
<version>6.3.26-SNAPSHOT</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>org.hl7.fhir.core</artifactId>
|
<artifactId>org.hl7.fhir.core</artifactId>
|
||||||
<version>6.3.24-SNAPSHOT</version>
|
<version>6.3.26-SNAPSHOT</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
@ -119,37 +119,6 @@
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</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 -->
|
<!-- OkHttpDependency -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.squareup.okhttp3</groupId>
|
<groupId>com.squareup.okhttp3</groupId>
|
||||||
|
|
|
@ -226,6 +226,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
|
||||||
@Getter @Setter private boolean allowDoubleQuotesInFHIRPath;
|
@Getter @Setter private boolean allowDoubleQuotesInFHIRPath;
|
||||||
@Getter @Setter private boolean checkIPSCodes;
|
@Getter @Setter private boolean checkIPSCodes;
|
||||||
@Getter @Setter private BestPracticeWarningLevel bestPracticeLevel;
|
@Getter @Setter private BestPracticeWarningLevel bestPracticeLevel;
|
||||||
|
@Getter @Setter private boolean unknownCodeSystemsCauseErrors;
|
||||||
@Getter @Setter private Locale locale;
|
@Getter @Setter private Locale locale;
|
||||||
@Getter @Setter private List<ImplementationGuide> igs = new ArrayList<>();
|
@Getter @Setter private List<ImplementationGuide> igs = new ArrayList<>();
|
||||||
@Getter @Setter private List<String> extensionDomains = new ArrayList<>();
|
@Getter @Setter private List<String> extensionDomains = new ArrayList<>();
|
||||||
|
@ -289,6 +290,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
|
||||||
fhirPathEngine = other.fhirPathEngine;
|
fhirPathEngine = other.fhirPathEngine;
|
||||||
igLoader = other.igLoader;
|
igLoader = other.igLoader;
|
||||||
jurisdiction = other.jurisdiction;
|
jurisdiction = other.jurisdiction;
|
||||||
|
unknownCodeSystemsCauseErrors = other.unknownCodeSystemsCauseErrors;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -906,6 +908,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
|
||||||
if (policyAdvisor != null) {
|
if (policyAdvisor != null) {
|
||||||
validator.setPolicyAdvisor(policyAdvisor);
|
validator.setPolicyAdvisor(policyAdvisor);
|
||||||
}
|
}
|
||||||
|
validator.setUnknownCodeSystemsCauseErrors(unknownCodeSystemsCauseErrors);
|
||||||
return validator;
|
return validator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -163,6 +163,9 @@ public class CliContext {
|
||||||
@JsonProperty("bestPracticeLevel")
|
@JsonProperty("bestPracticeLevel")
|
||||||
private BestPracticeWarningLevel bestPracticeLevel = BestPracticeWarningLevel.Warning;
|
private BestPracticeWarningLevel bestPracticeLevel = BestPracticeWarningLevel.Warning;
|
||||||
|
|
||||||
|
@JsonProperty("unknownCodeSystemsCauseErrors")
|
||||||
|
private boolean unknownCodeSystemsCauseErrors;
|
||||||
|
|
||||||
@JsonProperty("baseEngine")
|
@JsonProperty("baseEngine")
|
||||||
public String getBaseEngine() {
|
public String getBaseEngine() {
|
||||||
return baseEngine;
|
return baseEngine;
|
||||||
|
@ -832,6 +835,7 @@ public class CliContext {
|
||||||
Objects.equals(watchMode, that.watchMode) &&
|
Objects.equals(watchMode, that.watchMode) &&
|
||||||
Objects.equals(bestPracticeLevel, that.bestPracticeLevel) &&
|
Objects.equals(bestPracticeLevel, that.bestPracticeLevel) &&
|
||||||
Objects.equals(watchScanDelay, that.watchScanDelay) &&
|
Objects.equals(watchScanDelay, that.watchScanDelay) &&
|
||||||
|
Objects.equals(unknownCodeSystemsCauseErrors, that.unknownCodeSystemsCauseErrors) &&
|
||||||
Objects.equals(watchSettleTime, that.watchSettleTime) ;
|
Objects.equals(watchSettleTime, that.watchSettleTime) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -839,8 +843,8 @@ public class CliContext {
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hash(baseEngine, doNative, extensions, hintAboutNonMustSupport, recursive, doDebug, assumeValidRestReferences, canDoNative, noInternalCaching,
|
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,
|
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,
|
targetVer, igs, questionnaireMode, level, profiles, sources, inputs, mode, locale, locations, crumbTrails, forPublication, showTimes, allowExampleUrls, outputStyle, jurisdiction, noUnicodeBiDiControlChars,
|
||||||
htmlInMarkdownCheck, allowDoubleQuotesInFHIRPath, checkIPSCodes);
|
watchMode, watchScanDelay, watchSettleTime, bestPracticeLevel, unknownCodeSystemsCauseErrors, htmlInMarkdownCheck, allowDoubleQuotesInFHIRPath, checkIPSCodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -899,6 +903,7 @@ public class CliContext {
|
||||||
", bestPracticeLevel=" + bestPracticeLevel +
|
", bestPracticeLevel=" + bestPracticeLevel +
|
||||||
", watchSettleTime=" + watchSettleTime +
|
", watchSettleTime=" + watchSettleTime +
|
||||||
", watchScanDelay=" + watchScanDelay +
|
", watchScanDelay=" + watchScanDelay +
|
||||||
|
", unknownCodeSystemsCauseErrors=" + unknownCodeSystemsCauseErrors +
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -956,4 +961,17 @@ public class CliContext {
|
||||||
return this;
|
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.getBundleValidationRules().addAll(cliContext.getBundleValidationRules());
|
||||||
validationEngine.setJurisdiction(CodeSystemUtilities.readCoding(cliContext.getJurisdiction()));
|
validationEngine.setJurisdiction(CodeSystemUtilities.readCoding(cliContext.getJurisdiction()));
|
||||||
|
validationEngine.setUnknownCodeSystemsCauseErrors(cliContext.isUnknownCodeSystemsCauseErrors());
|
||||||
TerminologyCache.setNoCaching(cliContext.isNoInternalCaching());
|
TerminologyCache.setNoCaching(cliContext.isNoInternalCaching());
|
||||||
validationEngine.prepare(); // generate any missing snapshots
|
validationEngine.prepare(); // generate any missing snapshots
|
||||||
System.out.println(" go (" + timeTracker.milestone() + ")");
|
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 DISABLE_DEFAULT_RESOURCE_FETCHER = "-disable-default-resource-fetcher";
|
||||||
public static final String CHECK_IPS_CODES = "-check-ips-codes";
|
public static final String CHECK_IPS_CODES = "-check-ips-codes";
|
||||||
public static final String BEST_PRACTICE = "-best-practice";
|
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";
|
public static final String RUN_TESTS = "-run-tests";
|
||||||
|
|
||||||
|
@ -320,6 +319,8 @@ public class Params {
|
||||||
cliContext.setCrumbTrails(true);
|
cliContext.setCrumbTrails(true);
|
||||||
} else if (args[i].equals(FOR_PUBLICATION)) {
|
} else if (args[i].equals(FOR_PUBLICATION)) {
|
||||||
cliContext.setForPublication(true);
|
cliContext.setForPublication(true);
|
||||||
|
} else if (args[i].equals(UNKNOWN_CODESYSTEMS_CAUSE_ERROR)) {
|
||||||
|
cliContext.setUnknownCodeSystemsCauseErrors(true);
|
||||||
} else if (args[i].equals(VERBOSE)) {
|
} else if (args[i].equals(VERBOSE)) {
|
||||||
cliContext.setCrumbTrails(true);
|
cliContext.setCrumbTrails(true);
|
||||||
} else if (args[i].equals(ALLOW_EXAMPLE_URLS)) {
|
} 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.NotImplementedException;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.fhir.ucum.Decimal;
|
import org.fhir.ucum.Decimal;
|
||||||
import org.hl7.elm.r1.Code;
|
|
||||||
import org.hl7.fhir.exceptions.DefinitionException;
|
import org.hl7.fhir.exceptions.DefinitionException;
|
||||||
import org.hl7.fhir.exceptions.FHIRException;
|
import org.hl7.fhir.exceptions.FHIRException;
|
||||||
import org.hl7.fhir.exceptions.PathEngineException;
|
import org.hl7.fhir.exceptions.PathEngineException;
|
||||||
|
@ -598,6 +598,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
private boolean example ;
|
private boolean example ;
|
||||||
private IDigitalSignatureServices signatureServices;
|
private IDigitalSignatureServices signatureServices;
|
||||||
private ContextUtilities cu;
|
private ContextUtilities cu;
|
||||||
|
private boolean unknownCodeSystemsCauseErrors;
|
||||||
|
|
||||||
public InstanceValidator(@Nonnull IWorkerContext theContext, @Nonnull IEvaluationContext hostServices, @Nonnull XVerExtensionManager xverManager) {
|
public InstanceValidator(@Nonnull IWorkerContext theContext, @Nonnull IEvaluationContext hostServices, @Nonnull XVerExtensionManager xverManager) {
|
||||||
super(theContext, xverManager, false);
|
super(theContext, xverManager, false);
|
||||||
|
@ -1125,7 +1126,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
timeTracker.tx(t, "vc "+system+"#"+code+" '"+display+"'");
|
timeTracker.tx(t, "vc "+system+"#"+code+" '"+display+"'");
|
||||||
if (s == null)
|
if (s == null)
|
||||||
return true;
|
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.isOk()) {
|
||||||
if (s.getMessage() != null && !s.messageIsInIssues()) {
|
if (s.getMessage() != null && !s.messageIsInIssues()) {
|
||||||
|
@ -1381,7 +1382,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
if (cc.hasCoding()) {
|
if (cc.hasCoding()) {
|
||||||
long t = System.nanoTime();
|
long t = System.nanoTime();
|
||||||
ValidationResult vr = checkCodeOnServer(stack, null, cc);
|
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());
|
timeTracker.tx(t, "vc " + cc.toString());
|
||||||
}
|
}
|
||||||
} catch (CheckCodeOnServerException e) {
|
} catch (CheckCodeOnServerException e) {
|
||||||
|
@ -1465,7 +1466,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
} else {
|
} else {
|
||||||
checked.set(true);
|
checked.set(true);
|
||||||
ValidationResult vr = checkCodeOnServer(stack, valueset, cc);
|
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()) {
|
if (!vr.isOk()) {
|
||||||
bindingsOk = false;
|
bindingsOk = false;
|
||||||
if (vr.getErrorClass() != null && vr.getErrorClass() == TerminologyServiceErrorClass.NOSERVICE) {
|
if (vr.getErrorClass() != null && vr.getErrorClass() == TerminologyServiceErrorClass.NOSERVICE) {
|
||||||
|
@ -1533,33 +1534,34 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
return checkDisp;
|
return checkDisp;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String notFoundSeverityNoteForBinding(BindingStrength strength) {
|
// private String notFoundSeverityNoteForBinding(BindingStrength strength, Set<String> systems) {
|
||||||
if (strength == BindingStrength.REQUIRED) {
|
// if (strength == BindingStrength.REQUIRED &&
|
||||||
return "error because this is a required binding";
|
// (Utilities.listValueStartsWith("http://hl7.org/fhir", systems) || Utilities.listValueStartsWith("http://terminology.hl7.org", systems))) {
|
||||||
} else {
|
// return "error because this is a required binding to an HL7 code system";
|
||||||
return null;
|
// } 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;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
/**
|
private boolean processTxIssues(List<ValidationMessage> errors, ValidationResult vr, Element element, String path, boolean ignoreCantInfer, String vsurl, BindingStrength bs) {
|
||||||
* 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) {
|
|
||||||
boolean ok = true;
|
boolean ok = true;
|
||||||
if (vr != null) {
|
if (vr != null) {
|
||||||
for (OperationOutcomeIssueComponent iss : vr.getIssues()) {
|
for (OperationOutcomeIssueComponent iss : vr.getIssues()) {
|
||||||
|
@ -1568,11 +1570,34 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
&& !(ignoreCantInfer || iss.getDetails().hasCoding("http://hl7.org/fhir/tools/CodeSystem/tx-issue-type", "cannot-infer"))) {
|
&& !(ignoreCantInfer || iss.getDetails().hasCoding("http://hl7.org/fhir/tools/CodeSystem/tx-issue-type", "cannot-infer"))) {
|
||||||
OperationOutcomeIssueComponent i = iss.copy();
|
OperationOutcomeIssueComponent i = iss.copy();
|
||||||
if (i.getDetails().hasCoding("http://hl7.org/fhir/tools/CodeSystem/tx-issue-type", "not-found")) {
|
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))) {
|
String msg = iss.getDetails().getText();
|
||||||
i.setSeverity(notFoundLevel);
|
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) {
|
if (notFoundLevel != null && i.getSeverity().isHigherThan(notFoundLevel)) { // && (vsurl != null && i.getDetails().getText().contains(vsurl))) {
|
||||||
i.getDetails().setText(i.getDetails().getText()+" ("+notFoundNote+")");
|
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")) {
|
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;
|
boolean ok = true;
|
||||||
if (isNotBlank(nextCoding.getCode()) && isNotBlank(nextCoding.getSystem()) && context.supportsSystem(nextCoding.getSystem(), baseOptions.getFhirVersion())) {
|
if (isNotBlank(nextCoding.getCode()) && isNotBlank(nextCoding.getSystem()) && context.supportsSystem(nextCoding.getSystem(), baseOptions.getFhirVersion())) {
|
||||||
ValidationResult vr = checkCodeOnServer(stack, valueset, nextCoding);
|
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() != null && !vr.messageIsInIssues()) {
|
||||||
if (vr.getSeverity() == IssueSeverity.INFORMATION) {
|
if (vr.getSeverity() == IssueSeverity.INFORMATION) {
|
||||||
|
@ -1721,7 +1746,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
if (strength == BindingStrength.REQUIRED) {
|
if (strength == BindingStrength.REQUIRED) {
|
||||||
removeTrackedMessagesForLocation(errors, element, path);
|
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+"'");
|
timeTracker.tx(t, "vc "+system+"#"+code+" '"+display+"'");
|
||||||
if (vr != null && !vr.isOk()) {
|
if (vr != null && !vr.isOk()) {
|
||||||
if (vr.IsNoService())
|
if (vr.IsNoService())
|
||||||
|
@ -1766,6 +1791,21 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
return ok;
|
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) {
|
private boolean convertCDACodeToCodeableConcept(List<ValidationMessage> errors, String path, Element element, StructureDefinition logical, CodeableConcept cc) {
|
||||||
boolean ok = true;
|
boolean ok = true;
|
||||||
cc.setText(element.getNamedChildValue("originalText", false));
|
cc.setText(element.getNamedChildValue("originalText", false));
|
||||||
|
@ -1851,7 +1891,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
try {
|
try {
|
||||||
long t = System.nanoTime();
|
long t = System.nanoTime();
|
||||||
ValidationResult vr = checkCodeOnServer(stack, valueset, cc);
|
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());
|
timeTracker.tx(t, "vc "+cc.toString());
|
||||||
if (!vr.isOk()) {
|
if (!vr.isOk()) {
|
||||||
if (vr.getErrorClass() != null && vr.getErrorClass().isInfrastructure())
|
if (vr.getErrorClass() != null && vr.getErrorClass().isInfrastructure())
|
||||||
|
@ -1890,7 +1930,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
try {
|
try {
|
||||||
long t = System.nanoTime();
|
long t = System.nanoTime();
|
||||||
ValidationResult vr = checkCodeOnServer(stack, valueset, c);
|
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()+"'");
|
timeTracker.tx(t, "vc "+c.getSystem()+"#"+c.getCode()+" '"+c.getDisplay()+"'");
|
||||||
if (!vr.isOk()) {
|
if (!vr.isOk()) {
|
||||||
|
@ -1921,7 +1961,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
try {
|
try {
|
||||||
long t = System.nanoTime();
|
long t = System.nanoTime();
|
||||||
ValidationResult vr = checkCodeOnServer(stack, valueset, value, baseOptions);
|
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);
|
timeTracker.tx(t, "vc "+value);
|
||||||
if (!vr.isOk()) {
|
if (!vr.isOk()) {
|
||||||
if (vr.getErrorClass() != null && vr.getErrorClass().isInfrastructure())
|
if (vr.getErrorClass() != null && vr.getErrorClass().isInfrastructure())
|
||||||
|
@ -2045,7 +2085,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
checked.set(true);
|
checked.set(true);
|
||||||
vr = checkCodeOnServer(stack, valueset, c);
|
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()+"'");
|
timeTracker.tx(t, "vc "+c.getSystem()+"#"+c.getCode()+" '"+c.getDisplay()+"'");
|
||||||
if (strength == BindingStrength.REQUIRED) {
|
if (strength == BindingStrength.REQUIRED) {
|
||||||
|
@ -3510,7 +3550,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
}
|
}
|
||||||
vr = checkCodeOnServer(stack, vs, value, options);
|
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+"");
|
timeTracker.tx(t, "vc "+value+"");
|
||||||
if (binding.getStrength() == BindingStrength.REQUIRED) {
|
if (binding.getStrength() == BindingStrength.REQUIRED) {
|
||||||
|
@ -7791,4 +7831,14 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
this.fetcher = value;
|
this.fetcher = value;
|
||||||
return this;
|
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
|
// 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()")) {
|
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
|
// R5 ballot
|
||||||
|
|
|
@ -8,10 +8,10 @@ import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.hl7.fhir.ParametersParameter;
|
|
||||||
import org.hl7.fhir.r5.formats.IParser.OutputStyle;
|
import org.hl7.fhir.r5.formats.IParser.OutputStyle;
|
||||||
import org.hl7.fhir.r5.formats.JsonParser;
|
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.Extension;
|
||||||
import org.hl7.fhir.r5.model.OperationOutcome;
|
import org.hl7.fhir.r5.model.OperationOutcome;
|
||||||
import org.hl7.fhir.r5.model.OperationOutcome.OperationOutcomeIssueComponent;
|
import org.hl7.fhir.r5.model.OperationOutcome.OperationOutcomeIssueComponent;
|
||||||
|
|
|
@ -247,9 +247,9 @@ public class ValidationEngineTests {
|
||||||
Assertions.assertTrue(checkOutcomes("testObs102", op,
|
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.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.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 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);
|
verifyNoTerminologyRequests(logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -265,8 +265,8 @@ public class ValidationEngineTests {
|
||||||
System.out.println(" .. load USCore");
|
System.out.println(" .. load USCore");
|
||||||
OperationOutcome op = ve.validate(FhirFormat.XML, TestingUtilities.loadTestResourceStream("validator", "observation301.xml"), null);
|
OperationOutcome op = ve.validate(FhirFormat.XML, TestingUtilities.loadTestResourceStream("validator", "observation301.xml"), null);
|
||||||
Assertions.assertTrue(checkOutcomes("test301", op,
|
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\n"+
|
||||||
"Observation null warning/invalid: Best Practice Recommendation: In general, all observations should have a performer"));
|
"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);
|
verifyNoTerminologyRequests(logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
4
pom.xml
4
pom.xml
|
@ -14,14 +14,14 @@
|
||||||
HAPI FHIR
|
HAPI FHIR
|
||||||
-->
|
-->
|
||||||
<artifactId>org.hl7.fhir.core</artifactId>
|
<artifactId>org.hl7.fhir.core</artifactId>
|
||||||
<version>6.3.24-SNAPSHOT</version>
|
<version>6.3.26-SNAPSHOT</version>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<commons_compress_version>1.26.0</commons_compress_version>
|
<commons_compress_version>1.26.0</commons_compress_version>
|
||||||
<guava_version>32.0.1-jre</guava_version>
|
<guava_version>32.0.1-jre</guava_version>
|
||||||
<hapi_fhir_version>6.4.1</hapi_fhir_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>
|
<jackson_version>2.17.0</jackson_version>
|
||||||
<junit_jupiter_version>5.9.2</junit_jupiter_version>
|
<junit_jupiter_version>5.9.2</junit_jupiter_version>
|
||||||
<junit_platform_launcher_version>1.8.2</junit_platform_launcher_version>
|
<junit_platform_launcher_version>1.8.2</junit_platform_launcher_version>
|
||||||
|
|
Loading…
Reference in New Issue