CQL tuples are ordered sets of anonymous, typed fields. They can be used as a column type in tables, or a field type in user-defined types:
CREATE TABLE ks.collect_things ( pk int, ck1 text, ck2 text, v tuple<int, text, float>, PRIMARY KEY (pk, ck1, ck2) );
The driver maps tuple columns to the TupleValue class, which exposes getters and setters to access individual fields by index:
Row row = session.execute("SELECT v FROM ks.collect_things WHERE pk = 1").one(); TupleValue tupleValue = row.getTupleValue("v"); int field0 = tupleValue.getInt(0); String field1 = tupleValue.getString(1); Float field2 = tupleValue.getFloat(2);
Statements may contain tuples as bound values:
PreparedStatement ps = session.prepare( "INSERT INTO ks.collect_things (pk, ck1, ck2, v) VALUES (:pk, :ck1, :ck2, :v)");
To create a new tuple value, you must first have a reference to its TupleType. There are various ways to get it:
from the statement's metadata
TupleType tupleType = (TupleType) ps.getVariableDefinitions().get("v").getType();
from the driver's schema metadata:
TupleType tupleType = (TupleType) session .getMetadata() .getKeyspace("ks") .getTable("collect_things") .getColumn("v") .getType();
from another tuple value:
TupleType tupleType = tupleValue.getType();
or creating it from scratch:
TupleType tupleType = DataTypes.tupleOf(DataTypes.INT, DataTypes.TEXT, DataTypes.FLOAT);
Note that the resulting type is detached.
Once you have the type, call newValue()
and set the fields:
TupleValue tupleValue = tupleType.newValue().setInt(0, 1).setString(1, "hello").setFloat(2, 2.3f); // Or as a one-liner for convenience: TupleValue tupleValue = tupleType.newValue(1, "hello", 2.3f);
And bind your tuple value like any other type:
BoundStatement bs = ps.boundStatementBuilder() .setInt("pk", 1) .setString("ck1", "1") .setString("ck2", "1") .setTupleValue("v", tupleValue) .build(); session.execute(bs);
Tuples are also used for multi-column IN
restrictions (usually for tables with composite clustering keys):
PreparedStatement ps = session.prepare("SELECT * FROM ks.collect_things WHERE pk = 1 and (ck1, ck2) IN (:choice1, :choice2)"); TupleType tupleType = DataTypes.tupleOf(DataTypes.TEXT, DataTypes.TEXT); BoundStatement bs = ps.boundStatementBuilder() .setTupleValue("choice1", tupleType.newValue("a", "b")) .setTupleValue("choice2", tupleType.newValue("c", "d")) .build();
If you bind the whole list of choices as a single variable, a list of tuple values is expected:
PreparedStatement ps = // Note the absence of parentheses around ':choices' session.prepare("SELECT * FROM ks.collect_things WHERE pk = 1 and (ck1, ck2) IN :choices"); TupleType tupleType = DataTypes.tupleOf(DataTypes.TEXT, DataTypes.TEXT); List<TupleValue> choices = new ArrayList<>(); choices.add(tupleType.newValue("a", "b")); choices.add(tupleType.newValue("c", "d")); BoundStatement bs = ps.boundStatementBuilder().setList("choices", choices, TupleValue.class).build();