package com.wizecommerce.hecuba.datastax; import java.net.InetAddress; import java.util.*; import org.apache.commons.lang3.builder.ToStringBuilder; import com.datastax.driver.core.ColumnDefinitions.Definition; import com.datastax.driver.core.*; import com.google.common.base.Objects; import com.wizecommerce.hecuba.AbstractCassandraResultSet; public class DataStaxCassandraResultSet<K> extends AbstractCassandraResultSet<K, String> { private ResultSet rs; private Iterator<Row> rowIterator; private DataType keyType; private String keyColumn; private DataType columnType; private Map<String, DataType> valueTypes = new HashMap<>(); private Map<String, Object> currentRow = new LinkedHashMap<>(); private Map<String, Object> nextRow = new LinkedHashMap<>(); private K currentKey; private K nextKey; private long durationNanos; public DataStaxCassandraResultSet(ResultSet rs, DataType keyType, DataType columnType, Map<String, DataType> valueTypes, long durationNanos) { this.rs = rs; this.rowIterator = rs.iterator(); this.durationNanos = durationNanos; this.keyType = keyType; this.columnType = columnType; this.valueTypes = valueTypes; this.keyColumn = getKeyColumn(); extractRow(); } private String getKeyColumn() { // TODO: Ideally we'd use ColumnDefinitions.contains...but it's throwing out of bounds exception for (Definition definition : rs.getColumnDefinitions()) { for (String keyColumn : new String[] { "KEY", "key" }) { if (keyColumn.equals(definition.getName())) { return keyColumn; } } } throw new RuntimeException("Can't determine key column from metadata"); } @SuppressWarnings("unchecked") private void extractRow() { while (rowIterator.hasNext()) { Row row = rowIterator.next(); K key = (K) getValue(row, keyColumn, keyType); if (currentKey == null) { currentKey = key; } String column = getValue(row, "column1", columnType).toString(); DataType valueType = null; if (valueTypes != null) { valueType = valueTypes.get(column); if (valueType == null) { valueType = valueTypes.get("*"); } } Object value = getValue(row, "value", valueType); if (Objects.equal(key, currentKey)) { currentRow.put(column, value); } else { nextRow.put(column, value); nextKey = key; break; } } } private Object getValue(Row row, String column, DataType dataType) { if (dataType == null) { return row.getString(column); } switch (dataType.getName()) { case ASCII: case VARCHAR: case TEXT: return row.getString(column); case BIGINT: case COUNTER: return row.getLong(column); case BLOB: return row.getBytes(column); case BOOLEAN: return row.getBool(column); case DECIMAL: return row.getDecimal(column); case DOUBLE: return row.getDouble(column); case FLOAT: return row.getFloat(column); case INET: return row.getInet(column); case TIMESTAMP: case INT: return row.getInt(column); case TIMEUUID: case UUID: return row.getUUID(column); case VARINT: return row.getVarint(column); case CUSTOM: return row.getBytesUnsafe(column); default: throw new RuntimeException("Unhandled DataType: " + dataType); } } public boolean hasNext() { return nextKey != null; } public void next() { currentKey = nextKey; currentRow = nextRow; nextKey = null; nextRow = new LinkedHashMap<>(); extractRow(); } @Override public boolean hasNextResult() { return hasNext(); } @Override public void nextResult() { next(); } @Override public String getHost() { ExecutionInfo executionInfo = rs.getExecutionInfo(); Host queriedHost = executionInfo.getQueriedHost(); InetAddress address = queriedHost.getAddress(); return address.getCanonicalHostName(); } @Override public long getExecutionLatency() { return durationNanos; } @Override public K getKey() { return currentKey; } @Override public UUID getUUID(String columnName) { return (UUID) currentRow.get(columnName); } @Override public String getString(String columnName) { Object value = currentRow.get(columnName); if (value == null) { return null; } String result = value.toString(); if ("null".equalsIgnoreCase(result)) { result = null; } return result; } @Override public byte[] getByteArray(String columnName) { String value = getString(columnName); if (value != null) { return value.getBytes(); } return null; } @Override public Collection<String> getColumnNames() { return currentRow.keySet(); } @Override public boolean hasResults() { return !currentRow.isEmpty(); } @Override public String toString() { return new ToStringBuilder(this).append("key", currentKey).append("currentRow", currentRow).append("hasNextResult", hasNextResult()).toString(); } }