@Override public ColumnPlanNode visitSymbol(SymbolNode symbolNode) { NodeMatcher nodeMatcher = new NodeMatcher(formTree); Collection<NodeMatch> nodeMatches = nodeMatcher.resolveSymbol(symbolNode); return plan(nodeMatches); }
@Override public ColumnPlanNode visitCompoundExpr(CompoundExpr compoundExpr) { NodeMatcher nodeMatcher = new NodeMatcher(formTree); Collection<NodeMatch> nodeMatches = nodeMatcher.resolveCompoundExpr(compoundExpr); return plan(nodeMatches); } });
private Collection<String> resolve(String exprString) { FormTree tree = tree(); symbolTable = new NodeMatcher(tree); FormulaNode expr = FormulaParser.parse(exprString); Collection<NodeMatch> matches; if(expr instanceof SymbolNode) { matches = symbolTable.resolveSymbol((SymbolNode) expr); } else if(expr instanceof CompoundExpr) { matches = symbolTable.resolveCompoundExpr((CompoundExpr) expr); } else { throw new IllegalArgumentException(exprString); } // Create a string that we can match against easily List<String> strings = Lists.newArrayList(); for (NodeMatch match : matches) { strings.add(match.toDebugString()); } System.out.println("Resolved " + exprString + " => " + strings); return strings; }
@Override public Slot<ColumnView> visitFunctionCall(final FunctionCallNode call) { if(call.getFunction() instanceof ColumnFunction) { if(call.getArguments().isEmpty()) { return createNullaryFunctionCall(call); } else { return createFunctionCall(call); } } else if(call.getFunction() instanceof BoundingBoxFunction) { FormulaNode geometry = call.getArgument(0); Collection<NodeMatch> nodes; if(geometry instanceof SymbolNode) { nodes = resolver.resolveSymbol(((SymbolNode) geometry)); } else if(geometry instanceof CompoundExpr) { nodes = resolver.resolveCompoundExpr((CompoundExpr) geometry); } else { throw new QuerySyntaxException("Function " + call.getFunction().getId() + " can only be applied" + " to an argument of type GeoArea."); } return addColumn(nodes.stream().map(n -> n.withComponent(call.getFunction().getId())).collect(Collectors.toList())); } else { throw new UnsupportedOperationException("TODO: " + call.getFunction().getId()); } }
private Collection<NodeMatch> matchReferenceField(QueryPath queryPath, Iterable<FormTree.Node> fields) { List<Collection<NodeMatch>> matches = Lists.newArrayList(); for (FormTree.Node field : fields) { if(field.getType() instanceof ReferenceType) { Collection<NodeMatch> result = unionMatches(queryPath, field); if (!result.isEmpty()) { matches.add(result); } } else if(field.getType() instanceof EnumType) { Optional<NodeMatch> result = matchEnum(queryPath, field); if(result.isPresent()) { matches.add(Collections.singleton(result.get())); } } else if(field.getType() instanceof GeoPointType) { matchCoordinate(queryPath, field).ifPresent(match -> { matches.add(Collections.singleton(match)); }); } } if(matches.size() > 0) { return matches.get(0); } // If no results, check search at the next level List<FormTree.Node> children = childrenOf(fields); if(children.isEmpty()) { return Collections.emptyList(); } else { return matchReferenceField(queryPath, children); } }
public FormulaValidator(FormTree formTree) { this.formTree = formTree; this.nodeMatcher = new NodeMatcher(formTree); }
@Override public Slot<ColumnView> visitSymbol(SymbolNode symbolNode) { // Check for recursion: are we in the process of evaluating // this symbol? Trying to do so again will lead to an infinite // loop and a StackOverflowException. if(evaluationStack.contains(symbolNode)) { return batch.addEmptyColumn(filterLevel, rootFormClass); } evaluationStack.push(symbolNode); try { Collection<NodeMatch> nodes = resolver.resolveSymbol(symbolNode); LOGGER.finer(symbolNode + " matched to " + nodes); return addColumn(nodes); } catch (AmbiguousSymbolException | SymbolNotFoundException e) { // Ambiguous or unknown symbols should result in an empty column, not full failure LOGGER.log(Level.WARNING, e.getMessage(), e); return batch.addEmptyColumn(filterLevel, rootFormClass); } finally { evaluationStack.pop(); } }
matches.add(NodeMatch.forField(field, currentAggregation())); } else if (field.getType() instanceof ReferenceType) { referencedFormIdMatches(matches, path, field); } else if(field.getType() instanceof GeoPointType) { String symbol = path.head().toLowerCase(); List<FormTree.Node> children = childrenOf(fields); if(children.isEmpty()) { return Collections.emptyList(); } else { return matchTerminal(path, children);
@Override public Slot<ColumnView> visitCompoundExpr(CompoundExpr compoundExpr) { return addColumn(resolver.resolveCompoundExpr(compoundExpr)); }
private FunctionCallSlot createFunctionCall(final FunctionCallNode call) { resolver.enterFunction(call.getFunction()); try { final List<Slot<ColumnView>> argumentSlots = Lists.newArrayList(); for (FormulaNode argument : call.getArguments()) { argumentSlots.add(argument.accept(this)); } return new FunctionCallSlot((ColumnFunction)call.getFunction(), argumentSlots); } finally { resolver.exitFunction(call.getFunction()); } }
try { if (formulaNode instanceof SymbolNode) { matches = nodeMatcher.resolveSymbol((SymbolNode) formulaNode); } else if (formulaNode instanceof CompoundExpr) { matches = nodeMatcher.resolveCompoundExpr((CompoundExpr) formulaNode); } else { throw new IllegalArgumentException();
public QueryEvaluator(FilterLevel filterLevel, FormTree formTree, FormScanBatch batch) { this.filterLevel = filterLevel; this.tree = formTree; this.resolver = new NodeMatcher(formTree); this.rootFormClass = tree.getRootFormClass(); this.batch = batch; }
@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()); }