package cassandra.cql.query; import cassandra.cql.RoutingKey; import cassandra.metadata.ColumnMetadata; import cassandra.metadata.TableMetadata; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; public class QueryBuilder implements QueryVisitor { private final List<ColumnMetadata> partitionKey; private final ByteBuffer[] routingKey; private final StringBuilder query; private List<Object> parameters; public QueryBuilder(TableMetadata table) { if (table != null) { partitionKey = table.getPartitionKey(); routingKey = new ByteBuffer[partitionKey.size()]; } else { partitionKey = null; routingKey = null; } query = new StringBuilder(); } public boolean hasRoutingKey() { if (routingKey == null || routingKey.length == 0) { return false; } for (ByteBuffer key : routingKey) { if (key == null) { return false; } } return true; } public RoutingKey routingKey() { if (!hasRoutingKey()) { return null; } return RoutingKey.copyFrom(routingKey); } public boolean hasParameters() { return parameters != null && !parameters.isEmpty(); } public List<Object> parameters() { return parameters; } public String build() { return query.toString(); } @Override public void visit(Trigger node) { // } @Override public void visit(Truncate node) { query.append("TRUNCATE "); if (node.hasKeyspace()) { query.append(node.keyspace).append("."); } query.append(node.table); } @Override public void visit(Select node) { query.append("SELECT "); if (node.hasSelectionClause()) { node.selectionClause().accept(this); } else { query.append("*"); } query.append(" FROM "); if (node.hasKeyspace()) { query.append(node.keyspace).append("."); } query.append(node.table); if (node.hasWhereClause()) { query.append(" WHERE "); node.whereClause().accept(this); } if (node.hasSort()) { node.sort().accept(this); } if (node.hasLimit()) { node.limit().accept(this); } if (node.isAllowFiltering()) { query.append(" ALLOW FILTERING"); } } @Override public void visit(Insert node) { query.append("INSERT INTO "); if (node.hasKeyspace()) { query.append(node.keyspace).append("."); } query.append(node.table); query.append("("); boolean first = true; for (String name : node.names()) { if (first) { first = false; } else { query.append(","); } query.append(name); } query.append(") VALUES ("); for (int i = 0; i < node.names().size(); i++) { if (i != 0) { query.append(","); } appendValue(node.names().get(i), node.values().get(i)); } query.append(")"); if (node.isIfNotExists()) { query.append(" IF NOT EXISTS"); } if (node.hasOptions()) { query.append(" USING "); node.options().accept(this); } } @Override public void visit(Update node) { query.append("UPDATE "); if (node.hasKeyspace()) { query.append(node.keyspace).append("."); } query.append(node.table); if (node.hasOptions()) { query.append(" USING "); node.options().accept(this); } query.append(" SET "); node.assignment().accept(this); if (node.hasWhereClause()) { query.append(" WHERE "); node.whereClause().accept(this); } if (node.hasConditions()) { query.append(" IF "); node.conditions().accept(this); } } @Override public void visit(Delete node) { query.append("DELETE "); if (node.hasSelectionClause()) { node.selectionClause().accept(this); } else { query.append("*"); } query.append(" FROM "); if (node.hasKeyspace()) { query.append(node.keyspace).append("."); } query.append(node.table); if (node.hasOptions()) { query.append(" USING "); node.options().accept(this); } if (node.hasWhereClause()) { query.append(" WHERE "); node.whereClause().accept(this); } } @Override public void visit(Batch node) { if (node.isCounterUpdate()) { query.append("BEGIN COUNTER BATCH"); } else { if (node.isLogged()) { query.append("BEGIN BATCH"); } else { query.append("BEGIN UNLOGGED BATCH"); } } if (node.hasOptions()) { query.append(" USING "); node.options().accept(this); } query.append(" "); for (Query each : node.queries()) { each.accept(this); query.append(";"); } query.append("APPLY BATCH;"); } @Override public void visit(Clause.And node) { boolean first = true; for (Clause each : node.clauses()) { if (first) { first = false; } else { query.append(" AND "); } each.accept(this); } } @Override public void visit(Clause.Selection node) { if (node.isDistinct()) { query.append(" DISTINCT "); } boolean first = true; for (Clause.Selection.Selector selector : node.selectors()) { if (first) { first = false; } else { query.append(","); } query.append(selector.name()); if (selector.hasValue()) { query.append("["); appendValue(selector.value()); query.append("]"); } } } @Override public void visit(Clause.Using node) { query.append(node.name()).append(" ?"); addParameter(node.value()); } @Override public void visit(Clause.Equal node) { query.append(node.name()).append("="); appendValue(node.name(), node.value()); } @Override public void visit(Clause.LessThan node) { query.append(node.name()).append("<"); appendValue(node.name(), node.value()); } @Override public void visit(Clause.LessThanEquals node) { query.append(node.name()).append("<="); appendValue(node.name(), node.value()); } @Override public void visit(Clause.GreaterThan node) { query.append(node.name()).append(">"); appendValue(node.name(), node.value()); } @Override public void visit(Clause.GreaterThanEquals node) { query.append(node.name()).append(">="); appendValue(node.name(), node.value()); } @Override public void visit(Clause.In node) { query.append(node.name()).append(" IN ("); boolean first = true; for (Object each : node.value()) { if (first) { first = false; appendValue(node.name(), each); } else { query.append(","); appendValue(each); } } query.append(")"); } @Override public void visit(Assignment.And node) { boolean first = true; for (Assignment each : node.assignments()) { if (first) { first = false; } else { query.append(","); } each.accept(this); } } @Override public void visit(Assignment.Increment node) { query.append(node.name()).append("=+?"); // TODO with func addParameter(node.value()); } @Override public void visit(Assignment.Decrement node) { query.append(node.name()).append("=-?"); // TODO with func addParameter(node.value()); } @Override public void visit(Assignment.Set node) { query.append(node.name()).append("="); appendValue(node.value()); } @Override public void visit(Assignment.CollectionAdd node) { query.append(node.name()).append("="); if (node.isPrepend()) { query.append("?+").append(node.name()); } else { query.append(node.name()).append("+?"); } addParameter(node.value()); } @Override public void visit(Assignment.CollectionRemove node) { query.append(node.name()).append("="); query.append(node.name()).append("-?"); addParameter(node.value()); } @Override public void visit(Assignment.ListSet node) { query.append(node.name()).append("[?]="); addParameter(node.index()); appendValue(node.value()); } @Override public void visit(Assignment.MapPut node) { query.append(node.name()); query.append("[?]="); addParameter(node.key()); appendValue(node.value()); } @Override public void visit(Assignment.MapPutAll node) { query.append(node.name()).append("="); query.append(node.name()).append("+"); appendValue(node.value()); } @Override public void visit(Sort node) { query.append(" ORDER BY "); boolean first = true; for (Order each : node.orders()) { if (first) { first = false; } else { query.append(","); } each.accept(this); } } @Override public void visit(Order.Ascending node) { query.append(node.name()); } @Override public void visit(Order.Descending node) { query.append(node.name()).append(" DESC"); } @Override public void visit(Limit node) { query.append(" LIMIT ?"); addParameter(node.count()); } private QueryBuilder appendValue(Object value) { return appendValue(null, value); } private QueryBuilder appendValue(String name, Object value) { if (value instanceof Function) { Function function = (Function)value; query.append(function.name()).append("("); if (function.hasParameters()) { boolean first = true; for (Object each : function.parameters()) { if (first) { first = false; } else { query.append(","); } query.append("?"); addParameter(each); } } query.append(")"); } else { query.append("?"); addParameter(name, value); } return this; } private QueryBuilder addParameter(Object value) { return addParameter(null, value); } private QueryBuilder addParameter(String name, Object value) { if (parameters == null) { parameters = new ArrayList<Object>(); } parameters.add(value); if (partitionKey != null && !partitionKey.isEmpty() && name != null && value != null) { for (int i = 0; i < partitionKey.size(); i++) { ColumnMetadata column = partitionKey.get(i); if (name.equals(column.getName())) { routingKey[i] = column.getCqlType().serialize(value); } } } return this; } }