private ColumnPlanNode plan(NodeMatch match) { if(match.isJoined()) { throw new UnsupportedOperationException("TODO: Joins"); } switch (match.getType()) { case RECORD_ID: return new IdFetchOp(match.getFormClass().getId()); case FORM_ID: throw new UnsupportedOperationException("TODO: class"); default: throw new UnsupportedOperationException("type: " + match.getType()); case FIELD: return new ColumnFetchOp(match.getFieldNode().getDefiningFormClass().getId(), match.getFieldNode().getField()); } } }
public String getCalculation() { if(!isCalculated()) { throw new UnsupportedOperationException(getFieldComponent() + " is not a calculated field"); } CalculatedFieldType type = (CalculatedFieldType) fieldNode.getField().getType(); return type.getExpression(); }
public static NodeMatch forId(FormTree.Node parent, FormClass formClass) { List<List<FormTree.Node>> partitions = partitionOnJoins(parent); List<FormTree.Node> leaf = partitions.get(partitions.size() - 1); // Embedded records are not independent resources, and so // do not have their own ID. So the leaf field MUST be a reference field Preconditions.checkArgument(leaf.get(0).isReference()); NodeMatch match = new NodeMatch(); match.joins = joinsTo(partitions, Optional.<StatFunction>absent()); match.joins.add(new JoinNode(JoinType.REFERENCE, leaf.get(0).getDefiningFormClass().getId(), toExpr(leaf), formClass.getId())); match.formClass = formClass; match.type = Type.RECORD_ID; return match; }
public String getDescription() { if(match.isEnumBoolean()) { return match.getFieldNode().getField().getLabel() + " is " + match.getEnumItem().getLabel(); } else { return match.getFieldNode().getField().getLabel(); } }
if(match.isEnumBoolean()) { return BooleanType.INSTANCE; } else if(match.isCalculated()) { return findCalculatedFieldType(match.getFieldNode()); } else if (match.isRootId() || match.isFormLabel() || match.isId()) { return TextType.SIMPLE; } else { return match.getFieldNode().getType();
if(match.getJoins().size() == 1 && match.getJoins().get(0).getType() == JoinType.SUBFORM) { return addSubFormJoinedColumn(filterLevel, match); for (JoinNode joinNode : match.getJoins()) { links.add(addJoinLink(filterLevel, joinNode)); switch (match.getType()) { case FIELD: column = getDataColumn(filterLevel, match.getFormClass().getId(), match.getFieldComponent()); break; case RECORD_ID: column = addRecordIdColumn(filterLevel, match.getFormClass().getId()); break; default: throw new UnsupportedOperationException("type: " + match.getType());
public String getLabel() { // If this formula is just a field reference if(simpleReference && references.size() == 1) { NodeMatch ref = references.get(0).getMatch(); if(ref.isEnumBoolean()) { return ref.getEnumItem().getLabel(); } else if(ref.getType() == NodeMatch.Type.FIELD) { FormTree.Node field = ref.getFieldNode(); if (field.isRoot()) { return field.getField().getLabel(); } else { return field.getDefiningFormClass().getLabel() + " " + field.getField().getLabel(); } } } return formula; } }
/** * Adds a query to the batch for a column derived from a single node within the FormTree, along * with any necessary join structures required to join this column to the base table, if the column * is nested. * * @return a ColumnView Slot that can be used to retrieve the result after the batch * has finished executing. */ public Slot<ColumnView> addColumn(FilterLevel filterLevel, NodeMatch match) { if (match.isJoined()) { // requires join return addJoinedColumn(filterLevel, match); } else { // form label column, id column, simple root column or embedded form switch (match.getType()) { case FORM_NAME: return addConstantColumn(filterLevel, match.getFormClass(), match.getFormClass().getLabel()); case RECORD_ID: return addRecordIdColumn(filterLevel, match.getFormClass().getId()); case FORM_ID: return addConstantColumn(filterLevel, match.getFormClass(), match.getFormClass().getId().asString()); case FIELD: return getDataColumn(filterLevel, match.getFormClass().getId(), match.getFieldComponent()); default: throw new UnsupportedOperationException("Type: " + match.getType()); } } }
private Optional<ResourceId> findUniqueFieldReference(List<FieldReference> references, FormClass rootFormClass) { Set<ResourceId> rootFields = new HashSet<>(); for (FieldReference reference : references) { switch (reference.getMatch().getType()) { case RECORD_ID: findFormReferenceField(reference, rootFormClass).transform(rootFields::add); break; case FORM_ID: return Optional.absent(); case FIELD: rootFields.add(reference.getMatch().getFieldNode().getPath().getRoot()); break; } } if(rootFields.size() == 1) { return Optional.of(rootFields.iterator().next()); } else { return Optional.absent(); } }
private Slot<ColumnView> addSubFormJoinedColumn(FilterLevel filterLevel, NodeMatch match) { JoinNode node = match.getJoins().get(0); Slot<PrimaryKeyMap> primaryKey = addPrimaryKey(filterLevel, node.getLeftFormId()); Slot<ColumnView> parentColumn = addParentColumn(filterLevel, node.getRightFormId()); Slot<ColumnView> dataColumn = getDataColumn(filterLevel, match.getFormClass().getId(), match.getFieldComponent()); SubFormJoin join = new SubFormJoin(primaryKey, parentColumn); return new JoinedSubFormColumnViewSlot(Collections.singletonList(join), dataColumn, node.getAggregation().or(SumFunction.INSTANCE)); }
private Slot<ColumnView> addColumn(Collection<NodeMatch> nodes) { // Recursively expand any calculated fields List<Slot<ColumnView>> expandedNodes = Lists.newArrayList(); for (NodeMatch node : nodes) { switch (node.getType()) { case FORM_NAME: case RECORD_ID: case FORM_ID: expandedNodes.add(batch.addColumn(filterLevel, node)); break; case FIELD: if (node.isCalculated()) { expandedNodes.add(expandCalculatedField(node)); } else { expandedNodes.add(batch.addColumn(filterLevel, node)); } break; } } if(expandedNodes.isEmpty()) { return batch.addEmptyColumn(filterLevel, rootFormClass); } else if(expandedNodes.size() == 1) { return expandedNodes.get(0); } else { return new FunctionCallSlot(CoalesceFunction.INSTANCE, expandedNodes); } }
private Slot<ColumnView> expandCalculatedField(NodeMatch node) { try { Slot<ColumnView> calculation = evaluateExpression(node.getCalculation()); FormulaNode relevanceFormula = tryParseRelevance(node); if(relevanceFormula == null) { return calculation; } else { return new MemoizedSlot2<>(calculation, evaluateExpression(relevanceFormula), new BiFunction<ColumnView, ColumnView, ColumnView>() { @Override public ColumnView apply(ColumnView calculation, ColumnView relevance) { return new RelevanceViewMask(calculation, relevance); } }); } } catch (FormulaException e) { LOGGER.log(Level.WARNING, "Exception in calculated field " + node.getFormClass().getId() + "." + node.getFieldComponent() + " = " + node.getCalculation() + ": " + e.getMessage(), e); return batch.addEmptyColumn(filterLevel, node.getFormClass()); } }
matches.add(NodeMatch.forLabel(path.head(), tree.getRootFormClass())); matches.add(NodeMatch.forId(path.head(), tree.getRootFormClass())); matches.add(NodeMatch.forId(ColumnModel.RECORD_ID_SYMBOL, tree.getRootFormClass())); matches.add(NodeMatch.forField(field, currentAggregation())); } else if (field.getType() instanceof ReferenceType) { String symbol = path.head().toLowerCase(); if(symbol.equals("latitude") || symbol.equals("longitude")) { matches.add(NodeMatch.forFieldComponent(field, symbol));
private FormulaNode tryParseRelevance(NodeMatch node) { String formula = node.getFieldNode().getField().getRelevanceConditionExpression(); if(Strings.isNullOrEmpty(formula)) { return null; } try { return FormulaParser.parse(formula); } catch (FormulaException e) { LOGGER.info("Failed to parse relevance condition " + formula); return null; } }
private Optional<ResourceId> findFormReferenceField(FieldReference reference, FormClass rootFormClass) { for (FormField field : rootFormClass.getFields()) { if (!(field.getType() instanceof ReferenceType)) { continue; } ReferenceType refType = (ReferenceType) field.getType(); if (refType.getRange().contains(reference.getMatch().getFormClass().getId())) { return Optional.of(field.getId()); } } return Optional.absent(); }
@Test public void matchNodes() { TestingStorageProvider catalog = new TestingStorageProvider(); ClinicForm clinicForm = catalog.getClinicForm(); FormTree formTree = catalog.getFormTree(clinicForm.getFormId()); NodeMatcher nodeMatcher = new NodeMatcher(formTree); Collection<NodeMatch> nodeMatches = nodeMatcher.resolveSymbol(new SymbolNode("NUM_CONSULT")); assertThat(nodeMatches, hasSize(1)); NodeMatch nodeMatch = Iterables.getOnlyElement(nodeMatches); JoinNode joinNode = Iterables.getOnlyElement(nodeMatch.getJoins()); }
public static NodeMatch forLabel(String labelSymbol, FormClass formClass) { NodeMatch match = new NodeMatch(); match.formClass = formClass; if(labelSymbol.equals(ColumnModel.FORM_NAME_SYMBOL)) { match.type = Type.FORM_NAME; } else { throw new IllegalArgumentException(labelSymbol); } match.joins = Lists.newLinkedList(); return match; }
private java.util.Optional<NodeMatch> matchCoordinate(QueryPath queryPath, FormTree.Node field) { String symbol = queryPath.peek().toLowerCase(); if(symbol.equals("latitude") || symbol.equals("longitude")) { return java.util.Optional.of(NodeMatch.forFieldComponent(field, symbol)); } else { return java.util.Optional.empty(); } }
private void referencedFormIdMatches(List<NodeMatch> matches, QueryPath path, FormTree.Node field) { for (ResourceId referencedFormId : ((ReferenceType) field.getType()).getRange()) { Optional<FormClass> refFormClass = tree.getFormClassIfPresent(referencedFormId); if (!refFormClass.isPresent()) { continue; } if (path.matches(refFormClass.get())) { matches.add(NodeMatch.forId(field, refFormClass.get())); } } }
public static NodeMatch forFieldComponent(FormTree.Node fieldNode, String component) { NodeMatch match = forField(fieldNode, Optional.<StatFunction>absent()); match.fieldComponent = new FieldComponent(fieldNode.getFieldId(), component); return match; }