Skip to content

Commit

Permalink
Merge pull request hapifhir#1798 from hapifhir/2024-11-gg-pe-code-gen-2
Browse files Browse the repository at this point in the history
2024 11 gg pe code gen 2
  • Loading branch information
grahamegrieve authored Nov 7, 2024
2 parents c060518 + 6775a09 commit 3dd7203
Show file tree
Hide file tree
Showing 65 changed files with 10,662 additions and 693 deletions.
17 changes: 15 additions & 2 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,20 @@
## Validator Changes

* no changes
* Fix issue where valdiator not retaining extension context when checking constraint expressions in profiles
* Validate min-length when found in extension
* Correct bug parsing json-property-key values with meant validation failed
* Fix problem validating json-property-key value pairs
* Fix special case r5 loading of terminology to fix validation error on ExampleScenario
* Improve handling of JSON format errors

## Other code changes

* no changes
* More work on code generation for profiles
* Render min-length extension on profiles
* Clone SQL on FHIR engine to R4, and update FHIRPath engine based on R5 current code
* Update SQL on FHIR engine to allow push as well as pull
* Change R5 tx server to use http://tx.fhir.org/r5 (instead of /r4)
* Update output from tx-tester to include release ready statement
* Fix rendering of Logical Models for polymorphic elements, and rendering target profiles with versions
* Render contained resources in List resource
* #1790 - Fix versionFromCanonical returns system instead and systemFromCanonical returns version
Original file line number Diff line number Diff line change
Expand Up @@ -3621,11 +3621,35 @@ private TypeDetails evaluateFunctionType(ExecutionTypeContext context, TypeDetai
ExpressionNode p = exp.getParameters().get(0);
if (p.getKind() == Kind.Constant && p.getConstant() != null) {
String url = exp.getParameters().get(0).getConstant().primitiveValue();
ExtensionDefinition ed = findExtensionDefinition(focus, url);
if (ed != null) {
return new TypeDetails(CollectionStatus.ORDERED, new ProfiledType(ed.sd.getUrl()));
if (!Utilities.isAbsoluteUrl(url) && focus.hasType("Extension")) {
TypeDetails res = new TypeDetails(CollectionStatus.ORDERED);
List<String> profiles = focus.getProfiles("Extension");
if (profiles != null) {
for (String pt : profiles) {
String extn = pt.contains("#") ? pt.substring(0, pt.indexOf("#")) : pt;
String subExtn = pt.contains("#") ? pt.substring(0, pt.indexOf("#")) : null;
StructureDefinition sd = worker.fetchResource(StructureDefinition.class, extn);
if (sd != null) {
String id = subExtn == null ? "Extension.extension:"+url : subExtn+".extension:"+url;
ElementDefinition ed = sd.getSnapshot().getElementById(id);
if (ed != null) {
res.addType("Extension", sd.getUrl()+"#"+id);
}
}
}
}
if (res.isEmpty()) {
typeWarnings.add(new IssueMessage(worker.formatMessage(I18nConstants.FHIRPATH_UNKNOWN_EXTENSION, url), I18nConstants.FHIRPATH_UNKNOWN_EXTENSION));
} else {
return res;
}
} else {
typeWarnings.add(new IssueMessage(worker.formatMessage(I18nConstants.FHIRPATH_UNKNOWN_EXTENSION, url), I18nConstants.FHIRPATH_UNKNOWN_EXTENSION));
ExtensionDefinition ed = findExtensionDefinition(focus, url);
if (ed != null) {
return new TypeDetails(CollectionStatus.ORDERED, new ProfiledType(ed.sd.getUrl()));
} else {
typeWarnings.add(new IssueMessage(worker.formatMessage(I18nConstants.FHIRPATH_UNKNOWN_EXTENSION, url), I18nConstants.FHIRPATH_UNKNOWN_EXTENSION));
}
}
return new TypeDetails(CollectionStatus.SINGLETON, "Extension");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -593,5 +593,17 @@ public void setChoice(boolean b) {
public boolean isChoice() {
return choice;
}
public boolean isEmpty() {
return types.isEmpty();
}
public List<String> getProfiles(String t) {
t = ProfiledType.ns(t);
for (ProfiledType pt : types) {
if (t.equals(pt.uri)) {
return pt.getProfiles();
}
}
return new ArrayList<String>();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWIS

import org.apache.commons.lang3.NotImplementedException;
import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r4.conformance.ProfileUtilities;
import org.hl7.fhir.r4.context.ContextUtilities;
import org.hl7.fhir.r4.context.IWorkerContext;
import org.hl7.fhir.r4.fhirpath.FHIRPathEngine;
import org.hl7.fhir.r4.model.Base;
Expand All @@ -44,10 +46,14 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWIS
import org.hl7.fhir.r4.model.ElementDefinition.ElementDefinitionSlicingDiscriminatorComponent;
import org.hl7.fhir.r4.model.ElementDefinition.SlicingRules;
import org.hl7.fhir.r4.model.ElementDefinition.TypeRefComponent;
import org.hl7.fhir.r4.model.Enumerations.BindingStrength;
import org.hl7.fhir.r4.model.Resource;
import org.hl7.fhir.r4.model.ResourceFactory;
import org.hl7.fhir.r4.model.StructureDefinition;
import org.hl7.fhir.r4.model.StructureDefinition.TypeDerivationRule;
import org.hl7.fhir.r4.model.ValueSet;
import org.hl7.fhir.r4.model.ValueSet.ValueSetExpansionContainsComponent;
import org.hl7.fhir.r4.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
import org.hl7.fhir.utilities.Utilities;

Expand Down Expand Up @@ -110,6 +116,7 @@ public enum PEElementPropertiesPolicy {

private IWorkerContext context;
private ProfileUtilities pu;
private ContextUtilities cu;
private PEElementPropertiesPolicy elementProps;
private boolean fixedPropsDefault;
private FHIRPathEngine fpe;
Expand All @@ -124,6 +131,7 @@ public PEBuilder(IWorkerContext context, PEElementPropertiesPolicy elementProps,
this.elementProps = elementProps;
this.fixedPropsDefault = fixedPropsDefault;
pu = new ProfileUtilities(context, null, null);
cu = new ContextUtilities(context);
fpe = new FHIRPathEngine(context, pu);
}

Expand Down Expand Up @@ -338,6 +346,9 @@ protected List<PEDefinition> listChildren(boolean allFixed, PEDefinition parent,
List<PEDefinition> res = new ArrayList<>();
if (list.size() == 0) {
profile = context.fetchResource(StructureDefinition.class, url);
if (profile == null) {
throw new FHIRException("Unable to resolve profile "+url);
}
list = pu.getChildList(profile, profile.getSnapshot().getElementFirstRep());
}
if (list.size() > 0) {
Expand Down Expand Up @@ -574,20 +585,42 @@ public String makeSliceExpression(StructureDefinition profile, ElementDefinition
throw new DefinitionException("The discriminator type 'type' is not supported by the PEBuilder");
case VALUE:
String path = d.getPath();
if (path.contains(".")) {
throw new DefinitionException("The discriminator path '"+path+"' is not supported by the PEBuilder");
}
ElementDefinition ed = getChildElement(profile, definition, path);
if (ed == null) {
throw new DefinitionException("The discriminator path '"+path+"' could not be resolved by the PEBuilder");
}
if (!ed.hasFixed()) {
throw new DefinitionException("The discriminator path '"+path+"' has no fixed value - this is not supported by the PEBuilder");
}
if (!ed.getFixed().isPrimitive()) {
throw new DefinitionException("The discriminator path '"+path+"' has a fixed value that is not a primitive ("+ed.getFixed().fhirType()+") - this is not supported by the PEBuilder");
// three things possible:
// fixed, pattern, or binding
if (ed.hasFixed()) {
if (!ed.getFixed().isPrimitive()) {
throw new DefinitionException("The discriminator path '"+path+"' has a fixed value that is not a primitive ("+ed.getFixed().fhirType()+") - this is not supported by the PEBuilder");
}
b.append(path+" = '"+ed.getFixed().primitiveValue()+"'");
} else if (ed.hasPattern()) {
throw new DefinitionException("The discriminator path '"+path+"' has a pattern on the element '"+ed.getId()+"' - this is not supported by the PEBuilder");
} else if (ed.hasBinding()) {
if (ed.getBinding().getStrength() != BindingStrength.REQUIRED) {
throw new DefinitionException("The discriminator path '"+path+"' has a binding on the element '"+ed.getId()+"' but the strength is not required - this is not supported by the PEBuilder");
} else {
ValueSet vs = context.fetchResource(ValueSet.class, ed.getBinding().getValueSet());
if (vs == null) {
throw new DefinitionException("The discriminator path '"+path+"' has a binding on the element '"+ed.getId()+"' but the valueSet '"+ed.getBinding().getValueSet()+"' is not known - this is not supported by the PEBuilder");
}
ValueSetExpansionOutcome exp = context.expandVS(vs, true, false);
if (exp.isOk()) {
CommaSeparatedStringBuilder bs = new CommaSeparatedStringBuilder(" | ");
for (ValueSetExpansionContainsComponent cc : exp.getValueset().getExpansion().getContains()) {
bs.append("'"+cc.getCode()+"'");
}
b.append(path+" in ("+bs.toString()+")");
} else {
throw new DefinitionException("The discriminator path '"+path+"' has a binding on the element '"+ed.getId()+"' but the valueSet '"+ed.getBinding().getValueSet()+"' could not be expanded: "+exp.getError());
}
}
} else {
throw new DefinitionException("The discriminator path '"+path+"' has no fixed or pattern value or a binding on the element '"+ed.getId()+"' - this is not supported by the PEBuilder");

}
b.append(path+" = '"+ed.getFixed().primitiveValue()+"'");
break;
case NULL:
throw new DefinitionException("The discriminator type 'null' is not supported by the PEBuilder");
Expand All @@ -599,20 +632,33 @@ public String makeSliceExpression(StructureDefinition profile, ElementDefinition
}

private ElementDefinition getChildElement(StructureDefinition profile, ElementDefinition definition, String path) {
List<ElementDefinition> elements = pu.getChildList(profile, definition);
if (elements.size() == 0) {
profile = definition.getTypeFirstRep().hasProfile() ? context.fetchResource(StructureDefinition.class, definition.getTypeFirstRep().getProfile().get(0).asStringValue()) :
context.fetchTypeDefinition(definition.getTypeFirstRep().getWorkingCode());
elements = pu.getChildList(profile, profile.getSnapshot().getElementFirstRep());
}
return getByName(elements, path);
String head = path.contains(".") ? path.substring(0, path.indexOf(".")) : path;
String tail = path.contains(".") ? path.substring(path.indexOf(".")+1) : null;
ElementDefinition focus = definition;

do {
List<ElementDefinition> elements = pu.getChildList(profile, focus);
if (elements.size() == 0) {
profile = focus.getTypeFirstRep().hasProfile() ? context.fetchResource(StructureDefinition.class, focus.getTypeFirstRep().getProfile().get(0).asStringValue()) :
context.fetchTypeDefinition(focus.getTypeFirstRep().getWorkingCode());
elements = pu.getChildList(profile, profile.getSnapshot().getElementFirstRep());
}
focus = getByName(elements, head);
if (tail != null) {
head = tail.contains(".") ? tail.substring(0, tail.indexOf(".")) : tail;
tail = tail.contains(".") ? tail.substring(tail.indexOf(".")+1) : null;
} else {
head = null;
}
} while (head != null && focus != null);
return focus;
}

public List<Base> exec(Resource resource, Base data, String fhirpath) {
return fpe.evaluate(this, resource, resource, data, fhirpath);
}

public boolean isResource(String name) {
return context.getResourceNamesAsSet().contains(name);
return cu.isResource(name);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -299,10 +299,16 @@ public IWorkerContext getContext() {
}

public Base addChild(String name, Type value) {
PEDefinition child = byName(definition.children(), name);
Base b = data.setProperty(child.schemaName(), value);
return b;
}
PEDefinition child = byName(definition.children(), name);
Base b = data.setProperty(child.schemaName(), value);
return b;
}

public Base addChild(String name, Resource value) {
PEDefinition child = byName(definition.children(), name);
Base b = data.setProperty(child.schemaName(), value);
return b;
}

public Base addChild(String name, BackboneElement value) {
PEDefinition child = byName(definition.children(), name);
Expand Down
Loading

0 comments on commit 3dd7203

Please sign in to comment.