## Tuples

[CQL tuples][cql_doc] 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](../udts/):

```
CREATE TABLE ks.collect_things (
  pk int,
  ck1 text,
  ck2 text,
  v tuple<int, text, float>,
  PRIMARY KEY (pk, ck1, ck2)
);
```

### Fetching tuples from results

The driver maps tuple columns to the [TupleValue] class, which exposes getters and setters to access
individual fields by index:

```java
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);
```

### Using tuples as parameters

Statements may contain tuples as bound values:

```java
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

    ```java
    TupleType tupleType = (TupleType) ps.getVariableDefinitions().get("v").getType();
    ```

* from the driver's [schema metadata](../metadata/schema/):

    ```java
    TupleType tupleType =
        (TupleType)
            session
                .getMetadata()
                .getKeyspace("ks")
                .getTable("collect_things")
                .getColumn("v")
                .getType();
    ```

* from another tuple value:

    ```java
    TupleType tupleType = tupleValue.getType();
    ``` 
  
* or creating it from scratch:

    ```java
    TupleType tupleType = DataTypes.tupleOf(DataTypes.INT, DataTypes.TEXT, DataTypes.FLOAT);
    ```

    Note that the resulting type is [detached](../detachable_types).
  
Once you have the type, call `newValue()` and set the fields:

```java
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:

```java
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):

```java
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:

```java
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();
```

[cql_doc]: https://docs.datastax.com/en/cql/3.3/cql/cql_reference/tupleType.html

[TupleType]:  https://docs.datastax.com/en/drivers/java/4.0/com/datastax/oss/driver/api/core/type/TupleType.html
[TupleValue]: https://docs.datastax.com/en/drivers/java/4.0/com/datastax/oss/driver/api/core/data/TupleValue.html
