Change how count is calculated when expanding value sets

This commit is contained in:
Grahame Grieve 2024-06-18 19:44:22 +10:00
parent b97065338d
commit 2612fa1e63
2 changed files with 33 additions and 29 deletions

View File

@ -187,7 +187,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
private ValueSetExpansionContainsComponent addCode(WorkingContext wc, String system, String code, String display, String dispLang, ValueSetExpansionContainsComponent parent, List<ConceptDefinitionDesignationComponent> designations, Parameters expParams, private ValueSetExpansionContainsComponent addCode(WorkingContext wc, String system, String code, String display, String dispLang, ValueSetExpansionContainsComponent parent, List<ConceptDefinitionDesignationComponent> designations, Parameters expParams,
boolean isAbstract, boolean inactive, List<ValueSet> filters, boolean noInactive, boolean deprecated, List<ValueSetExpansionPropertyComponent> vsProp, boolean isAbstract, boolean inactive, List<ValueSet> filters, boolean noInactive, boolean deprecated, List<ValueSetExpansionPropertyComponent> vsProp,
List<ConceptPropertyComponent> csProps, CodeSystem cs, List<org.hl7.fhir.r5.model.ValueSet.ConceptPropertyComponent> expProps, List<Extension> csExtList, List<Extension> vsExtList, ValueSetExpansionComponent exp, boolean countToTotal) throws ETooCostly { List<ConceptPropertyComponent> csProps, CodeSystem cs, List<org.hl7.fhir.r5.model.ValueSet.ConceptPropertyComponent> expProps, List<Extension> csExtList, List<Extension> vsExtList, ValueSetExpansionComponent exp) throws ETooCostly {
opContext.deadCheck(); opContext.deadCheck();
if (filters != null && !filters.isEmpty() && !filterContainsCode(filters, system, code, exp)) if (filters != null && !filters.isEmpty() && !filterContainsCode(filters, system, code, exp))
@ -326,9 +326,6 @@ public class ValueSetExpander extends ValueSetProcessBase {
} else { } else {
wc.getCodes().add(n); wc.getCodes().add(n);
wc.getMap().put(s, n); wc.getMap().put(s, n);
if (countToTotal) {
wc.incTotal();
}
// if (wc == dwc && wc.getTotal() > maxExpansionSize) { // if (wc == dwc && wc.getTotal() > maxExpansionSize) {
// if (wc.getOffset()+wc.getCount() > 0 && wc.getTotal() > wc.getOffset()+wc.getCount()) { // if (wc.getOffset()+wc.getCount() > 0 && wc.getTotal() > wc.getOffset()+wc.getCount()) {
// wc.setTotal(-1); // wc.setTotal(-1);
@ -449,19 +446,19 @@ public class ValueSetExpander extends ValueSetProcessBase {
return null; return null;
} }
private void addCodeAndDescendents(WorkingContext wc, ValueSetExpansionContainsComponent focus, ValueSetExpansionContainsComponent parent, Parameters expParams, List<ValueSet> filters, boolean noInactive, List<ValueSetExpansionPropertyComponent> vsProps, ValueSet vsSrc, ValueSetExpansionComponent exp, boolean countToTotal) throws FHIRException, ETooCostly { private void addCodeAndDescendents(WorkingContext wc, ValueSetExpansionContainsComponent focus, ValueSetExpansionContainsComponent parent, Parameters expParams, List<ValueSet> filters, boolean noInactive, List<ValueSetExpansionPropertyComponent> vsProps, ValueSet vsSrc, ValueSetExpansionComponent exp) throws FHIRException, ETooCostly {
opContext.deadCheck(); opContext.deadCheck();
focus.checkNoModifiers("Expansion.contains", "expanding"); focus.checkNoModifiers("Expansion.contains", "expanding");
ValueSetExpansionContainsComponent np = null; ValueSetExpansionContainsComponent np = null;
for (String code : getCodesForConcept(focus, expParams)) { for (String code : getCodesForConcept(focus, expParams)) {
ValueSetExpansionContainsComponent t = addCode(wc, focus.getSystem(), code, focus.getDisplay(), vsSrc.getLanguage(), parent, ValueSetExpansionContainsComponent t = addCode(wc, focus.getSystem(), code, focus.getDisplay(), vsSrc.getLanguage(), parent,
convert(focus.getDesignation()), expParams, focus.getAbstract(), focus.getInactive(), filters, noInactive, false, vsProps, makeCSProps(focus.getExtensionString(ToolingExtensions.EXT_DEFINITION), null), null, focus.getProperty(), null, focus.getExtension(), exp, countToTotal); convert(focus.getDesignation()), expParams, focus.getAbstract(), focus.getInactive(), filters, noInactive, false, vsProps, makeCSProps(focus.getExtensionString(ToolingExtensions.EXT_DEFINITION), null), null, focus.getProperty(), null, focus.getExtension(), exp);
if (np == null) { if (np == null) {
np = t; np = t;
} }
} }
for (ValueSetExpansionContainsComponent c : focus.getContains()) for (ValueSetExpansionContainsComponent c : focus.getContains())
addCodeAndDescendents(wc, c, np, expParams, filters, noInactive, vsProps, vsSrc, exp, countToTotal); addCodeAndDescendents(wc, c, np, expParams, filters, noInactive, vsProps, vsSrc, exp);
} }
private List<ConceptPropertyComponent> makeCSProps(String definition, List<ConceptPropertyComponent> list) { private List<ConceptPropertyComponent> makeCSProps(String definition, List<ConceptPropertyComponent> list) {
@ -512,7 +509,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
boolean dep = CodeSystemUtilities.isDeprecated(cs, def, false); boolean dep = CodeSystemUtilities.isDeprecated(cs, def, false);
if ((includeAbstract || !abs) && filterFunc.includeConcept(cs, def) && passesOtherFilters(otherFilters, cs, def.getCode())) { if ((includeAbstract || !abs) && filterFunc.includeConcept(cs, def) && passesOtherFilters(otherFilters, cs, def.getCode())) {
for (String code : getCodesForConcept(def, expParams)) { for (String code : getCodesForConcept(def, expParams)) {
ValueSetExpansionContainsComponent t = addCode(wc, system, code, def.getDisplay(), cs.getLanguage(), parent, def.getDesignation(), expParams, abs, inc, filters, noInactive, dep, vsProps, makeCSProps(def.getDefinition(), def.getProperty()), cs, null, def.getExtension(), null, exp, true); ValueSetExpansionContainsComponent t = addCode(wc, system, code, def.getDisplay(), cs.getLanguage(), parent, def.getDesignation(), expParams, abs, inc, filters, noInactive, dep, vsProps, makeCSProps(def.getDefinition(), def.getProperty()), cs, null, def.getExtension(), null, exp);
if (np == null) { if (np == null) {
np = t; np = t;
} }
@ -761,11 +758,11 @@ public class ValueSetExpander extends ValueSetProcessBase {
// nothing - we intended to trap this here // nothing - we intended to trap this here
} }
if (dwc.getTotal() > maxExpansionSize && dwc.getOffsetParam() + dwc.getCountParam() == 0) { if (dwc.getCount() > maxExpansionSize && dwc.getOffsetParam() + dwc.getCountParam() == 0) {
if (dwc.isNoTotal()) { if (dwc.isNoTotal()) {
throw failCostly(context.formatMessage(I18nConstants.VALUESET_TOO_COSTLY, focus.getVersionedUrl(), ">" + MessageFormat.format("{0,number,#}", maxExpansionSize))); throw failCostly(context.formatMessage(I18nConstants.VALUESET_TOO_COSTLY, focus.getVersionedUrl(), ">" + MessageFormat.format("{0,number,#}", maxExpansionSize)));
} else { } else {
throw failCostly(context.formatMessage(I18nConstants.VALUESET_TOO_COSTLY_COUNT, focus.getVersionedUrl(), ">" + MessageFormat.format("{0,number,#}", maxExpansionSize), MessageFormat.format("{0,number,#}", dwc.getTotal()))); throw failCostly(context.formatMessage(I18nConstants.VALUESET_TOO_COSTLY_COUNT, focus.getVersionedUrl(), ">" + MessageFormat.format("{0,number,#}", maxExpansionSize), MessageFormat.format("{0,number,#}", dwc.getCount())));
} }
} else if (dwc.isCanBeHierarchy() && ((dwc.getCountParam() == 0) || dwc.getCountParam() > dwc.getCodes().size())) { } else if (dwc.isCanBeHierarchy() && ((dwc.getCountParam() == 0) || dwc.getCountParam() > dwc.getCodes().size())) {
for (ValueSetExpansionContainsComponent c : dwc.getRoots()) { for (ValueSetExpansionContainsComponent c : dwc.getRoots()) {
@ -793,7 +790,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
focus.getExpansion().setOffset(dwc.getOffsetParam()); focus.getExpansion().setOffset(dwc.getOffsetParam());
} }
if (!dwc.isNoTotal()) { if (!dwc.isNoTotal()) {
focus.getExpansion().setTotal(dwc.getTotal()); focus.getExpansion().setTotal(dwc.getStatedTotal());
} }
if (!requiredSupplements.isEmpty()) { if (!requiredSupplements.isEmpty()) {
return new ValueSetExpansionOutcome(context.formatMessagePlural(requiredSupplements.size(), I18nConstants.VALUESET_SUPPLEMENT_MISSING, CommaSeparatedStringBuilder.build(requiredSupplements)), TerminologyServiceErrorClass.BUSINESS_RULE, allErrors, false); return new ValueSetExpansionOutcome(context.formatMessagePlural(requiredSupplements.size(), I18nConstants.VALUESET_SUPPLEMENT_MISSING, CommaSeparatedStringBuilder.build(requiredSupplements)), TerminologyServiceErrorClass.BUSINESS_RULE, allErrors, false);
@ -975,7 +972,6 @@ public class ValueSetExpander extends ValueSetProcessBase {
if (!wc.getMap().containsKey(s) && !wc.getExcludeKeys().contains(s)) { if (!wc.getMap().containsKey(s) && !wc.getExcludeKeys().contains(s)) {
wc.getCodes().add(n); wc.getCodes().add(n);
wc.getMap().put(s, n); wc.getMap().put(s, n);
wc.incTotal();
} }
copyExpansion(wc, cc.getContains()); copyExpansion(wc, cc.getContains());
} }
@ -995,7 +991,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
for (ValueSetExpansionContainsComponent c : list) { for (ValueSetExpansionContainsComponent c : list) {
c.checkNoModifiers("Imported Expansion in Code System", "expanding"); c.checkNoModifiers("Imported Expansion in Code System", "expanding");
ValueSetExpansionContainsComponent np = addCode(dwc, c.getSystem(), c.getCode(), c.getDisplay(), vsSrc.getLanguage(), parent, null, expParams, c.getAbstract(), c.getInactive(), ValueSetExpansionContainsComponent np = addCode(dwc, c.getSystem(), c.getCode(), c.getDisplay(), vsSrc.getLanguage(), parent, null, expParams, c.getAbstract(), c.getInactive(),
filter, noInactive, false, vsProps, makeCSProps(c.getExtensionString(ToolingExtensions.EXT_DEFINITION), null), null, c.getProperty(), null, c.getExtension(), exp, false); filter, noInactive, false, vsProps, makeCSProps(c.getExtensionString(ToolingExtensions.EXT_DEFINITION), null), null, c.getProperty(), null, c.getExtension(), exp);
if (np != null) { if (np != null) {
count++; count++;
} }
@ -1015,12 +1011,11 @@ public class ValueSetExpander extends ValueSetProcessBase {
if (!inc.hasSystem()) { if (!inc.hasSystem()) {
if (imports.isEmpty()) // though this is not supposed to be the case if (imports.isEmpty()) // though this is not supposed to be the case
return; return;
dwc.resetTotal();
ValueSet base = imports.get(0); ValueSet base = imports.get(0);
checkCanonical(exp, base, focus); checkCanonical(exp, base, focus);
imports.remove(0); imports.remove(0);
base.checkNoModifiers("Imported ValueSet", "expanding"); base.checkNoModifiers("Imported ValueSet", "expanding");
dwc.incTotal(copyImportContains(base.getExpansion().getContains(), null, expParams, imports, noInactive, base.getExpansion().getProperty(), base, exp)); copyImportContains(base.getExpansion().getContains(), null, expParams, imports, noInactive, base.getExpansion().getProperty(), base, exp);
} else { } else {
CodeSystem cs = context.fetchSupplementedCodeSystem(inc.getSystem()); CodeSystem cs = context.fetchSupplementedCodeSystem(inc.getSystem());
if (ValueSetUtilities.isServerSide(inc.getSystem()) || (cs == null || (cs.getContent() != CodeSystemContentMode.COMPLETE && cs.getContent() != CodeSystemContentMode.FRAGMENT))) { if (ValueSetUtilities.isServerSide(inc.getSystem()) || (cs == null || (cs.getContent() != CodeSystemContentMode.COMPLETE && cs.getContent() != CodeSystemContentMode.FRAGMENT))) {
@ -1056,7 +1051,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
} }
} }
if (vs.getExpansion().hasTotal()) { if (vs.getExpansion().hasTotal()) {
dwc.incTotal(vs.getExpansion().getTotal()); // 0 for now... dwc.incExtraCount(!vs.getExpansion().getTotal());
} else { } else {
dwc.setNoTotal(true); dwc.setNoTotal(true);
} }
@ -1073,7 +1068,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
} }
} }
for (ValueSetExpansionContainsComponent cc : vs.getExpansion().getContains()) { for (ValueSetExpansionContainsComponent cc : vs.getExpansion().getContains()) {
addCodeAndDescendents(dwc, cc, null, expParams, imports, noInactive, vsProps, vs, exp, !vs.getExpansion().hasTotal()); addCodeAndDescendents(dwc, cc, null, expParams, imports, noInactive, vsProps, vs, exp);
} }
} }
@ -1138,7 +1133,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
inactive = CodeSystemUtilities.isInactive(cs, def); inactive = CodeSystemUtilities.isInactive(cs, def);
isAbstract = CodeSystemUtilities.isNotSelectable(cs, def); isAbstract = CodeSystemUtilities.isNotSelectable(cs, def);
addCode(dwc, inc.getSystem(), c.getCode(), !Utilities.noString(c.getDisplay()) ? c.getDisplay() : def.getDisplay(), c.hasDisplay() ? vsSrc.getLanguage() : cs.getLanguage(), null, mergeDesignations(def, convertDesignations(c.getDesignation())), addCode(dwc, inc.getSystem(), c.getCode(), !Utilities.noString(c.getDisplay()) ? c.getDisplay() : def.getDisplay(), c.hasDisplay() ? vsSrc.getLanguage() : cs.getLanguage(), null, mergeDesignations(def, convertDesignations(c.getDesignation())),
expParams, isAbstract, inactive, imports, noInactive, false, exp.getProperty(), makeCSProps(def.getDefinition(), def.getProperty()), cs, null, def.getExtension(), c.getExtension(), exp, true); expParams, isAbstract, inactive, imports, noInactive, false, exp.getProperty(), makeCSProps(def.getDefinition(), def.getProperty()), cs, null, def.getExtension(), c.getExtension(), exp);
} }
} }
} }
@ -1222,7 +1217,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
excludeCode(wc, inc.getSystem(), code); excludeCode(wc, inc.getSystem(), code);
} else { } else {
addCode(wc, inc.getSystem(), code, def.getDisplay(), cs.getLanguage(), null, def.getDesignation(), expParams, CodeSystemUtilities.isNotSelectable(cs, def), CodeSystemUtilities.isInactive(cs, def), addCode(wc, inc.getSystem(), code, def.getDisplay(), cs.getLanguage(), null, def.getDesignation(), expParams, CodeSystemUtilities.isNotSelectable(cs, def), CodeSystemUtilities.isInactive(cs, def),
imports, noInactive, false, exp.getProperty(), makeCSProps(def.getDefinition(), def.getProperty()), cs, null, def.getExtension(), null, exp, true); imports, noInactive, false, exp.getProperty(), makeCSProps(def.getDefinition(), def.getProperty()), cs, null, def.getExtension(), null, exp);
} }
} }
} }

View File

@ -21,7 +21,8 @@ class WorkingContext {
private boolean canBeHierarchy = true; private boolean canBeHierarchy = true;
private Integer offsetParam; private Integer offsetParam;
private Integer countParam; // allowed count. Because of internal processing, we allow more private Integer countParam; // allowed count. Because of internal processing, we allow more
private int total; // running count. This might be more than actually seen if we call out to an external server and only get the first 1000 codes
private int extraCount; // running count. This might be more than actually seen if we call out to an external server and only get the first 1000 codes
private boolean noTotal; // we lost count of the correct total private boolean noTotal; // we lost count of the correct total
public List<ValueSetExpansionContainsComponent> getCodes() { public List<ValueSetExpansionContainsComponent> getCodes() {
@ -80,16 +81,20 @@ class WorkingContext {
this.countParam = countParam; this.countParam = countParam;
} }
public int getTotal() { public int getExtraCount() {
return total; return extraCount;
} }
public void incTotal() { public void incExtraCount() {
total++; extraCount++;
} }
public void incTotal(int amount) { public void incExtraCount(int amount) {
total += amount; extraCount += amount;
}
public void resetExtraCount() {
extraCount = 0;
} }
public boolean isNoTotal() { public boolean isNoTotal() {
@ -100,8 +105,12 @@ class WorkingContext {
this.noTotal = noTotal; this.noTotal = noTotal;
} }
public void resetTotal() { public int getCount() {
total = 0; return codes.size();
}
public int getStatedTotal() {
return codes.size() + extraCount;
} }
} }