Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions lib/src/main/java/com/imsweb/staging/Staging.java
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,21 @@ public Set<String> getInputs(Schema schema, Map<String, String> context) {
return inputs;
}

/**
* Calculates the default value for an Input using supplied context. This may be based on "default" or "default_table".
* @param schema Schema
* @param key Input key
* @param context a Map containing the context
* @return the default value for the input or blank if there is none
*/
public String getInputDefault(Schema schema, String key, Map<String, String> context) {
Input input = schema.getInputMap().get(key);
if (input == null)
return "";

return _engine.getDefault(input, context, new Result(context));
}

/**
* Looks at a table path (and all jump tables within in) and returns a list of output keys that could be created.
* @param path a StagingTablePath
Expand Down
55 changes: 48 additions & 7 deletions lib/src/main/java/com/imsweb/staging/engine/DecisionEngine.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public class DecisionEngine {

// string to use for blank or null in error strings
public static final String _BLANK_OUTPUT = "<blank>";
private static final Pattern _TEMPLATE_REFERENCE = Pattern.compile("\\{\\{(.*?)\\}\\}");
private static final Pattern _TEMPLATE_REFERENCE = Pattern.compile("\\{\\{(.*?)}}");
private DataProvider _provider;

private static final String _CONTEXT_MISSING_MESSAGE = "Context must not be missing";
Expand Down Expand Up @@ -583,6 +583,49 @@ public Set<String> getOutputs(Schema schema) {
return outputs;
}

/**
* Calculates the default value for an Input using supplied context
* @param input Input definition
* @param context a Map containing the context
* @param result a Result object to store errors
* @return the default value for the input or blank if there is none
*/
public String getDefault(Input input, Map<String, String> context, Result result) {
String value = "";

if (input.getDefault() != null)
value = translateValue(input.getDefault(), context);
else if (input.getDefaultTable() != null) {
Table defaultTable = getProvider().getTable(input.getDefaultTable());
if (defaultTable == null) {
result.addError(new ErrorBuilder(Type.UNKNOWN_TABLE).message("Default table does not exist: " + input.getDefaultTable()).key(input.getKey()).build());
return value;
}

// look up default value from table
List<? extends Endpoint> endpoints = matchTable(defaultTable, context);
if (endpoints != null) {
value = endpoints.stream()
.filter(endpoint -> EndpointType.VALUE.equals(endpoint.getType()))
.filter(endpoint -> endpoint.getResultKey().equals(input.getKey()))
.map(endpoint -> translateValue(endpoint.getValue(), context))
.findFirst()
.orElse(null);
}

// if no match found, report the error
if (endpoints == null || value == null) {
result.addError(new ErrorBuilder(Type.MATCH_NOT_FOUND)
.message("Default table " + input.getDefaultTable() + " did not find a match")
.key(input.getKey())
.build());
return "";
}
}

return value;
}

/**
* Using the supplied context, process an schema. The results will be added to the context.
* @param schemaId an schema identifier
Expand Down Expand Up @@ -619,14 +662,12 @@ public Result process(Schema schema, Map<String, String> context) {

String value = context.get(input.getKey());

// if value not supplied, use the default and set it back into the context; if not supplied and no default, set the input the blank
if (value == null) {
value = (input.getDefault() != null ? translateValue(input.getDefault(), context) : "");
context.put(input.getKey(), value);
}
// if value not supplied, use the default or defaultTable and set it back into the context; if not supplied and no default, set the input the blank
if (value == null)
context.put(input.getKey(), getDefault(input, context, result));

// validate value against associated table, if supplied; if a value is not supplied, or blank, there is no need to validate it against the table
if (!value.isEmpty() && input.getTable() != null) {
if (value != null && !value.isEmpty() && input.getTable() != null) {
Table lookup = getProvider().getTable(input.getTable());

if (lookup == null) {
Expand Down
8 changes: 8 additions & 0 deletions lib/src/main/java/com/imsweb/staging/entities/Input.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,14 @@ public interface Input {
*/
String getDefault();

/**
* If supplied, a table lookup (using current context) will occur to determine
* the default value when it is not supplied. If both a default and a default table
* are specified, the default table will be ignored.
* @return A String representing the default value
*/
String getDefaultTable();

/**
* If supplied, the value of the field is verified to be contained in the table
* @return a String representing the lookup table name
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public class StagingSchemaInput implements Input {
private Integer _naaccrItem;
private String _naaccrXmlId;
private String _default;
private String _defaultTable;
private String _table;
private Boolean _usedForStaging;
private String _unit;
Expand Down Expand Up @@ -60,6 +61,7 @@ public StagingSchemaInput(StagingSchemaInput other) {
setNaaccrItem(other.getNaaccrItem());
setNaaccrXmlId(other.getNaaccrXmlId());
setDefault(other.getDefault());
setDefaultTable(other.getDefaultTable());
setTable(other.getTable());
if (other.getMetadata() != null)
setMetadata(new ArrayList<>(other.getMetadata()));
Expand Down Expand Up @@ -128,6 +130,16 @@ public void setDefault(String aDefault) {
_default = aDefault;
}

@Override
@JsonProperty("default_table")
public String getDefaultTable() {
return _defaultTable;
}

public void setDefaultTable(String defaultTable) {
_defaultTable = defaultTable;
}

@Override
@JsonProperty("table")
public String getTable() {
Expand Down Expand Up @@ -194,6 +206,7 @@ public boolean equals(Object o) {
Objects.equals(_naaccrItem, that._naaccrItem) &&
Objects.equals(_naaccrXmlId, that._naaccrXmlId) &&
Objects.equals(_default, that._default) &&
Objects.equals(_defaultTable, that._defaultTable) &&
Objects.equals(_table, that._table) &&
Objects.equals(_usedForStaging, that._usedForStaging) &&
Objects.equals(_unit, that._unit) &&
Expand All @@ -204,6 +217,6 @@ public boolean equals(Object o) {
@Override
public int hashCode() {
// do not include _parsedValues
return Objects.hash(_key, _name, _description, _naaccrItem, _naaccrXmlId, _default, _table, _usedForStaging, _unit, _decimalPlaces, _metadata);
return Objects.hash(_key, _name, _description, _naaccrItem, _naaccrXmlId, _default, _defaultTable, _table, _usedForStaging, _unit, _decimalPlaces, _metadata);
}
}
129 changes: 129 additions & 0 deletions lib/src/test/java/com/imsweb/staging/engine/DecisionEngineTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -1541,4 +1541,133 @@ void testMappingInputsWithReferenceInTable() {
assertEquals(new HashSet<>(Collections.singletonList("remapped1")), engine.getInputs(schema.getMappings().get(0).getTablePaths().get(0)));
}

@Test
void testDefaultTable() {
InMemoryDataProvider provider = new InMemoryDataProvider("default_table_testing", "1.0");

StagingTable table = new StagingTable("table_input1");
table.addColumnDefinition("input1", ColumnType.INPUT);
table.addColumnDefinition("description", ColumnType.DESCRIPTION);
table.addRawRow("000", "Alpha");
table.addRawRow("001", "Beta");
table.addRawRow("002", "Gamma");
provider.addTable(table);

table = new StagingTable("table_input2");
table.addColumnDefinition("input2", ColumnType.INPUT);
table.addColumnDefinition("description", ColumnType.DESCRIPTION);
table.addRawRow("900", "Zeta");
table.addRawRow("901", "Eta");
table.addRawRow("902", "Theta");
provider.addTable(table);

table = new StagingTable("table_input2_default");
table.addColumnDefinition("input1", ColumnType.INPUT);
table.addColumnDefinition("input2", ColumnType.ENDPOINT);
table.addRawRow("000", "VALUE:900");
table.addRawRow("*", "VALUE:902");
provider.addTable(table);

table = new StagingTable("table_mapping");
table.addColumnDefinition("input1", ColumnType.INPUT);
table.addColumnDefinition("input2", ColumnType.INPUT);
table.addColumnDefinition("output1", ColumnType.ENDPOINT);
table.addRawRow("000", "900", "VALUE:000-900");
table.addRawRow("000", "*", "VALUE:000-*");
table.addRawRow("001", "901", "VALUE:001-901");
table.addRawRow("001", "*", "VALUE:001-*");
table.addRawRow("002", "902", "VALUE:002-902");
provider.addTable(table);

StagingSchema schema = new StagingSchema("test_default_table");
schema.setSchemaSelectionTable("table_selection");
schema.setOnInvalidInput(Schema.StagingInputErrorHandler.FAIL);
schema.addInput(new StagingSchemaInput("input1", "input1", "table_input1"));
StagingSchemaInput input2 = new StagingSchemaInput("input2", "input2", "table_input2");
input2.setDefaultTable("table_input2_default");
schema.addInput(input2);

schema.addOutput(new StagingSchemaOutput("output1"));

schema.addMapping(new StagingMapping("m1", Collections.singletonList(new StagingTablePath("table_mapping"))));

provider.addSchema(schema);

DecisionEngine engine = new DecisionEngine(provider);

// test a case where the default_table make a successful lookup
Map<String, String> context = new HashMap<>();
context.put("input1", "000");
Result result = engine.process("test_default_table", context);

assertEquals(Type.STAGED, result.getType());
assertFalse(result.hasErrors());
assertEquals(1, result.getContext().size());
assertEquals("000-900", result.getContext().get("output1"));

// check same case with getDefault method
context = new HashMap<>();
context.put("input1", "000");
Result result1 = new Result(context);
assertEquals("900", engine.getDefault(input2, context, result1));
assertFalse(result1.hasErrors());

// test a case where there was a fallthrough match in the default table
context = new HashMap<>();
context.put("input1", "002");
result = engine.process("test_default_table", context);

assertEquals(Type.STAGED, result.getType());
assertFalse(result.hasErrors());
assertEquals(1, result.getContext().size());
assertEquals("002-902", result.getContext().get("output1"));

// check same case with getDefault method
context = new HashMap<>();
context.put("input1", "002");
result1 = new Result(context);
assertEquals("902", engine.getDefault(input2, context, result1));
assertFalse(result1.hasErrors());

// test a case where the default_table did not exist
schema.getInputs().stream().filter(i -> i.getDefaultTable() != null).forEach(i -> i.setDefaultTable("does_not_exist"));
context = new HashMap<>();
context.put("input1", "000");
result = engine.process("test_default_table", context);
assertEquals(Type.STAGED, result.getType());
assertEquals(1, result.getErrors().size());
assertEquals("input2", result.getErrors().get(0).getKey());
assertEquals("Default table does not exist: does_not_exist", result.getErrors().get(0).getMessage());

// check same case with getDefault method
context = new HashMap<>();
context.put("input1", "000");
result1 = new Result(context);
assertEquals("", engine.getDefault(input2, context, result1));
assertEquals(1, result1.getErrors().size());
assertEquals("input2", result1.getErrors().get(0).getKey());
assertEquals("Default table does not exist: does_not_exist", result1.getErrors().get(0).getMessage());

// test a case where the default table did not find a match
schema.getInputs().stream().filter(i -> i.getDefaultTable() != null).forEach(i -> i.setDefaultTable("table_input2_default"));
provider.getTable("table_input2_default").setRawRows(new ArrayList<>());
provider.initTable(provider.getTable("table_input2_default"));
context = new HashMap<>();
context.put("input1", "001");
result = engine.process("test_default_table", context);
assertEquals(Type.STAGED, result.getType());
assertEquals(1, result.getErrors().size());
assertEquals("input2", result.getErrors().get(0).getKey());
assertEquals("Default table table_input2_default did not find a match", result.getErrors().get(0).getMessage());

// check same case with getDefault method
context = new HashMap<>();
context.put("input1", "001");
result1 = new Result(context);
assertEquals("", engine.getDefault(input2, context, result1));
assertEquals(1, result1.getErrors().size());
assertEquals("input2", result.getErrors().get(0).getKey());
assertEquals("Default table table_input2_default did not find a match", result.getErrors().get(0).getMessage());
}

}
25 changes: 25 additions & 0 deletions lib/src/testFixtures/java/com/imsweb/staging/StagingTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,31 @@ public void testBasicInputs() {
}
}

@Test
public void testInputDefault() {
Map<String, String> context = new HashMap<>();

// error conditions
String schemaId = _STAGING.getSchemaIds().stream().findFirst().orElse(null);
assertNotNull(schemaId);
assertEquals("", _STAGING.getInputDefault(_STAGING.getSchema(schemaId), "i_do_not_exist", context));

for (String id : _STAGING.getSchemaIds()) {
Schema schema = _STAGING.getSchema(id);
for (Input input : schema.getInputs()) {
if (input.getDefault() != null && input.getDefaultTable() != null)
fail("In " + getAlgorithm() + ", schema " + schema.getId() + " and input " + input.getKey() + " there is a default and default_table. That is not allowed.");

if (input.getDefault() != null)
assertEquals(input.getDefault(), _STAGING.getInputDefault(schema, input.getKey(), context));
else if (input.getDefaultTable() != null)
assertFalse(_STAGING.getInputDefault(schema, input.getKey(), context).isEmpty());
else
assertTrue(_STAGING.getInputDefault(schema, input.getKey(), context).isEmpty());
}
}
}

@Test
public void testValidSite() {
assertFalse(_STAGING.isValidSite(null));
Expand Down