@Override public void meet(Count node) throws RuntimeException { builder.append("COUNT("); if (node.isDistinct()) { builder.append("DISTINCT "); } if (node.getArg() == null) { // this is a weird special case where we need to expand to all variables selected in the query // wrapped // by the group; we cannot simply use "*" because the concept of variables is a different one // in SQL, // so instead we construct an ARRAY of the bindings of all variables List<String> countVariables = new ArrayList<>(); for (SQLVariable v : parent.getVariables().values()) { if (v.getProjectionType() == ValueType.NONE) { Preconditions.checkState( v.getExpressions().size() > 0, "no expressions available for variable"); countVariables.add(v.getExpressions().get(0)); } } builder.append("ARRAY["); Joiner.on(',').appendTo(builder, countVariables); builder.append("]"); } else { optypes.push(ValueType.NODE); node.getArg().visit(this); optypes.pop(); } builder.append(")"); }
@Override public void meet(Var node) throws RuntimeException { // distinguish between the case where the variable is plain and the variable is bound SQLVariable sv = parent.getVariables().get(node.getName()); if (sv == null) { builder.append("NULL"); } else if (sv.getBindings().size() > 0) { // in case the variable is actually an alias for an expression, we evaluate that expression // instead, effectively replacing the // variable occurrence with its value sv.getBindings().get(0).visit(this); } else { String var = sv.getAlias(); if (sv.getProjectionType() != ValueType.NODE && sv.getProjectionType() != ValueType.NONE) { // in case the variable represents a constructed or bound value instead of a node, we need // to // use the SQL expression as value; SQL should take care of proper casting... // TODO: explicit casting needed? builder.append(sv.getExpressions().get(0)); } else { // in case the variable represents an entry from the NODES table (i.e. has been bound to a // node // in the database, we take the NODES alias and resolve to the correct column according to // the // operator type switch (optypes.peek()) { case STRING: Preconditions.checkState(var != null, "no alias available for variable"); builder.append(var).append(".svalue"); break; case INT: Preconditions.checkState(var != null, "no alias available for variable"); builder.append(var).append(".ivalue"); break; case DECIMAL: case DOUBLE: Preconditions.checkState(var != null, "no alias available for variable"); builder.append(var).append(".dvalue"); break; case BOOL: Preconditions.checkState(var != null, "no alias available for variable"); builder.append(var).append(".bvalue"); break; case DATE: Preconditions.checkState(var != null, "no alias available for variable"); builder.append(var).append(".tvalue"); break; case TZDATE: Preconditions.checkState(var != null, "no alias available for variable"); builder.append(parent.getDialect().getDateTimeTZ(var)); break; case URI: Preconditions.checkState(var != null, "no alias available for variable"); builder.append(var).append(".svalue"); break; case TERM: case NODE: if (sv.getExpressions().size() > 0) { // this allows us to avoid joins with the nodes table for simple expressions that only // need the ID builder.append(sv.getExpressions().get(0)); } else { Preconditions.checkState(var != null, "no alias available for variable"); builder.append(var).append(".id"); } break; } } } }