Type-safe, sortable key encoding that supports multiple data types while preserving lexicographic ordering. Tuples provide a structured way to encode keys and values for FoundationDB.
Create tuples from various data sources.
/**
* Create tuple from variable arguments.
*
* Parameters:
* - items: Object... - Items to include in tuple
*
* Returns:
* Tuple - New tuple containing items
*/
static Tuple Tuple.from(Object... items);
/**
* Create tuple from iterable collection.
*
* Parameters:
* - items: Iterable<?> - Items to include in tuple
*
* Returns:
* Tuple - New tuple containing items
*/
static Tuple Tuple.fromItems(Iterable<?> items);
/**
* Create tuple from list.
*
* Parameters:
* - items: List<?> - Items to include in tuple
*
* Returns:
* Tuple - New tuple containing items
*/
static Tuple Tuple.fromList(List<?> items);
/**
* Create tuple from stream.
*
* Parameters:
* - items: Stream<?> - Items to include in tuple
*
* Returns:
* Tuple - New tuple containing items
*/
static Tuple Tuple.fromStream(Stream<?> items);
/**
* Unpack tuple from byte array.
*
* Parameters:
* - bytes: byte[] - Packed tuple data
*
* Returns:
* Tuple - Unpacked tuple
*/
static Tuple Tuple.fromBytes(byte[] bytes);
/**
* Unpack tuple from byte array with offset.
*
* Parameters:
* - bytes: byte[] - Packed tuple data
* - offset: int - Starting offset in array
* - length: int - Number of bytes to read
*
* Returns:
* Tuple - Unpacked tuple
*/
static Tuple Tuple.fromBytes(byte[] bytes, int offset, int length);Usage examples:
import com.apple.foundationdb.tuple.Tuple;
import java.util.UUID;
// Create from multiple items
Tuple tuple1 = Tuple.from("user", 1001, "Alice");
// Create from collection
List<Object> items = Arrays.asList("key", 42, true);
Tuple tuple2 = Tuple.fromItems(items);
// Unpack from bytes
byte[] packed = tuple1.pack();
Tuple unpacked = Tuple.fromBytes(packed);
// Empty tuple
Tuple empty = Tuple.from();Build tuples by adding typed elements (returns new tuple).
/**
* Add untyped object to tuple.
* Returns new tuple with object appended.
*
* Parameters:
* - o: Object - Object to add
*
* Returns:
* Tuple - New tuple with object appended
*/
Tuple Tuple.addObject(Object o);
/**
* Add string to tuple.
*
* Parameters:
* - s: String - String to add
*
* Returns:
* Tuple - New tuple with string appended
*/
Tuple Tuple.add(String s);
/**
* Add long integer to tuple.
*
* Parameters:
* - l: long - Long to add
*
* Returns:
* Tuple - New tuple with long appended
*/
Tuple Tuple.add(long l);
/**
* Add byte array to tuple.
*
* Parameters:
* - b: byte[] - Bytes to add
*
* Returns:
* Tuple - New tuple with bytes appended
*/
Tuple Tuple.add(byte[] b);
/**
* Add boolean to tuple.
*
* Parameters:
* - b: boolean - Boolean to add
*
* Returns:
* Tuple - New tuple with boolean appended
*/
Tuple Tuple.add(boolean b);
/**
* Add UUID to tuple.
*
* Parameters:
* - uuid: UUID - UUID to add
*
* Returns:
* Tuple - New tuple with UUID appended
*/
Tuple Tuple.add(UUID uuid);
/**
* Add nested tuple to tuple.
*
* Parameters:
* - tuple: Tuple - Nested tuple to add
*
* Returns:
* Tuple - New tuple with nested tuple appended
*/
Tuple Tuple.add(Tuple tuple);
/**
* Add list to tuple (stored as nested structure).
*
* Parameters:
* - list: List<?> - List to add
*
* Returns:
* Tuple - New tuple with list appended
*/
Tuple Tuple.add(List<?> list);
/**
* Add big integer to tuple.
*
* Parameters:
* - bigInt: BigInteger - Big integer to add
*
* Returns:
* Tuple - New tuple with big integer appended
*/
Tuple Tuple.add(BigInteger bigInt);
/**
* Add double to tuple.
*
* Parameters:
* - d: double - Double to add
*
* Returns:
* Tuple - New tuple with double appended
*/
Tuple Tuple.add(double d);
/**
* Add float to tuple.
*
* Parameters:
* - f: float - Float to add
*
* Returns:
* Tuple - New tuple with float appended
*/
Tuple Tuple.add(float f);
/**
* Add versionstamp to tuple.
*
* Parameters:
* - v: Versionstamp - Versionstamp to add
*
* Returns:
* Tuple - New tuple with versionstamp appended
*/
Tuple Tuple.add(Versionstamp v);
/**
* Add byte array slice to tuple.
*
* Parameters:
* - b: byte[] - Source byte array
* - offset: int - Starting offset in source array
* - length: int - Number of bytes to copy
*
* Returns:
* Tuple - New tuple with byte slice appended
*/
Tuple Tuple.add(byte[] b, int offset, int length);
/**
* Add all elements from list to tuple.
* Elements are added individually (not as nested list).
*
* Parameters:
* - o: List<?> - List of elements to add
*
* Returns:
* Tuple - New tuple with all list elements appended
*/
Tuple Tuple.addAll(List<?> o);
/**
* Add all elements from another tuple.
* Elements are added individually (not as nested tuple).
*
* Parameters:
* - other: Tuple - Tuple whose elements to add
*
* Returns:
* Tuple - New tuple with all other tuple's elements appended
*/
Tuple Tuple.addAll(Tuple other);Usage examples:
// Build tuple incrementally
Tuple base = Tuple.from("users");
Tuple withId = base.add(1001L);
Tuple complete = withId.add("profile").add("email");
// Chain multiple additions
Tuple tuple = Tuple.from()
.add("order")
.add(12345L)
.add(new UUID(1, 2))
.add(99.99)
.add(true);
// Add various types
Tuple mixed = Tuple.from("data")
.add(42L)
.add("text")
.add(new byte[]{1, 2, 3})
.add(3.14)
.add(BigInteger.valueOf(1000000000000L));
// Nested tuples
Tuple inner = Tuple.from("inner", 1);
Tuple outer = Tuple.from("outer").add(inner);
// Add null
Tuple withNull = Tuple.from("key", null, "value");Extract typed elements from tuple by index.
/**
* Get untyped object at index.
*
* Parameters:
* - index: int - Zero-based index
*
* Returns:
* Object - Object at index
*/
Object Tuple.get(int index);
/**
* Get string at index.
*
* Parameters:
* - index: int - Zero-based index
*
* Returns:
* String - String at index, or null
*/
String Tuple.getString(int index);
/**
* Get long at index.
*
* Parameters:
* - index: int - Zero-based index
*
* Returns:
* long - Long value at index
*
* Throws:
* IllegalArgumentException - If value is null or not a number
*/
long Tuple.getLong(int index);
/**
* Get byte array at index.
*
* Parameters:
* - index: int - Zero-based index
*
* Returns:
* byte[] - Byte array at index, or null
*/
byte[] Tuple.getBytes(int index);
/**
* Get boolean at index.
*
* Parameters:
* - index: int - Zero-based index
*
* Returns:
* boolean - Boolean value at index
*
* Throws:
* IllegalArgumentException - If value is null or not a boolean
*/
boolean Tuple.getBoolean(int index);
/**
* Get UUID at index.
*
* Parameters:
* - index: int - Zero-based index
*
* Returns:
* UUID - UUID at index, or null
*/
UUID Tuple.getUUID(int index);
/**
* Get nested tuple at index.
*
* Parameters:
* - index: int - Zero-based index
*
* Returns:
* Tuple - Nested tuple at index, or null
*/
Tuple Tuple.getNestedTuple(int index);
/**
* Get nested list at index.
*
* Parameters:
* - index: int - Zero-based index
*
* Returns:
* List<Object> - Nested list at index, or null
*/
List<Object> Tuple.getNestedList(int index);
/**
* Get big integer at index.
*
* Parameters:
* - index: int - Zero-based index
*
* Returns:
* BigInteger - Big integer at index
*
* Throws:
* IllegalArgumentException - If value is null or not a number
*/
BigInteger Tuple.getBigInteger(int index);
/**
* Get double at index.
*
* Parameters:
* - index: int - Zero-based index
*
* Returns:
* double - Double value at index
*
* Throws:
* IllegalArgumentException - If value is null or not a number
*/
double Tuple.getDouble(int index);
/**
* Get float at index.
*
* Parameters:
* - index: int - Zero-based index
*
* Returns:
* float - Float value at index
*
* Throws:
* IllegalArgumentException - If value is null or not a number
*/
float Tuple.getFloat(int index);
/**
* Get number at index (any numeric type).
*
* Parameters:
* - index: int - Zero-based index
*
* Returns:
* Number - Number at index
*
* Throws:
* IllegalArgumentException - If value is null or not a number
*/
Number Tuple.getNumber(int index);
/**
* Get versionstamp at index.
*
* Parameters:
* - index: int - Zero-based index
*
* Returns:
* Versionstamp - Versionstamp at index, or null
*/
Versionstamp Tuple.getVersionstamp(int index);Usage examples:
// Extract elements
Tuple tuple = Tuple.from("user", 1001, "Alice", true, 3.14);
String type = tuple.getString(0); // "user"
long id = tuple.getLong(1); // 1001
String name = tuple.getString(2); // "Alice"
boolean active = tuple.getBoolean(3); // true
double score = tuple.getDouble(4); // 3.14
// Handle nulls
Tuple withNull = Tuple.from("key", null);
String value = withNull.getString(1); // null
// long num = withNull.getLong(1); // Throws exception
// Nested structures
Tuple nested = Tuple.from("outer", Tuple.from("inner", 42));
Tuple inner = nested.getNestedTuple(1);
long value = inner.getLong(1); // 42
// Get as generic object
Object obj = tuple.get(0); // Returns String "user"Convert tuples to and from byte arrays for storage.
/**
* Pack tuple to byte array.
* Result can be used as FDB key or value.
*
* Returns:
* byte[] - Packed tuple bytes
*/
byte[] Tuple.pack();
/**
* Pack tuple with prefix prepended.
*
* Parameters:
* - prefix: byte[] - Prefix to prepend to packed tuple
*
* Returns:
* byte[] - Prefix + packed tuple bytes
*/
byte[] Tuple.pack(byte[] prefix);
/**
* Pack tuple directly into ByteBuffer.
* Does not store packed representation internally.
*
* Parameters:
* - dest: ByteBuffer - Destination buffer for packed tuple
*
* Throws:
* IllegalArgumentException - If tuple contains incomplete versionstamps
*/
void Tuple.packInto(ByteBuffer dest);
/**
* Pack tuple containing incomplete versionstamp.
* Used with SET_VERSIONSTAMPED_KEY or SET_VERSIONSTAMPED_VALUE.
*
* Returns:
* byte[] - Packed tuple with versionstamp placeholder
*
* Throws:
* IllegalArgumentException - If tuple has no incomplete versionstamp
*/
byte[] Tuple.packWithVersionstamp();
/**
* Pack tuple with versionstamp and prefix.
*
* Parameters:
* - prefix: byte[] - Prefix to prepend
*
* Returns:
* byte[] - Prefix + packed tuple with versionstamp placeholder
*/
byte[] Tuple.packWithVersionstamp(byte[] prefix);Usage examples:
// Pack for storage
Tuple tuple = Tuple.from("user", 1001);
byte[] key = tuple.pack();
db.run(tr -> {
tr.set(key, "user data".getBytes());
return null;
});
// Unpack from storage
byte[] storedKey = db.run(tr -> {
return tr.get(key).join();
});
Tuple unpacked = Tuple.fromBytes(key);
// Pack with prefix
byte[] prefix = "app:".getBytes();
byte[] keyWithPrefix = tuple.pack(prefix);
// Pack with versionstamp
Tuple timestamped = Tuple.from("log", Versionstamp.incomplete());
byte[] versionstampedKey = timestamped.packWithVersionstamp();
db.run(tr -> {
tr.mutate(MutationType.SET_VERSIONSTAMPED_KEY,
versionstampedKey, "log entry".getBytes());
return null;
});Query tuple properties and metadata.
/**
* Get number of elements in tuple.
*
* Returns:
* int - Number of elements
*/
int Tuple.size();
/**
* Check if tuple is empty.
*
* Returns:
* boolean - True if tuple has no elements
*/
boolean Tuple.isEmpty();
/**
* Get all elements as list.
*
* Returns:
* List<Object> - List containing all tuple elements
*/
List<Object> Tuple.getItems();
/**
* Check if tuple contains incomplete versionstamp.
*
* Returns:
* boolean - True if tuple has incomplete versionstamp
*/
boolean Tuple.hasIncompleteVersionstamp();
/**
* Get size of packed tuple in bytes.
*
* Returns:
* int - Size in bytes when packed
*/
int Tuple.getPackedSize();
/**
* Get range covering all keys with this tuple as prefix.
*
* Returns:
* Range - Range from tuple to next possible tuple
*/
Range Tuple.range();
/**
* Iterate over tuple elements.
*
* Returns:
* Iterator<Object> - Iterator over elements
*/
Iterator<Object> Tuple.iterator();
/**
* Create new tuple without first element.
*
* Returns:
* Tuple - New tuple with first element removed
*
* Throws:
* IllegalStateException - If tuple is empty
*/
Tuple Tuple.popFront();
/**
* Create new tuple without last element.
*
* Returns:
* Tuple - New tuple with last element removed
*
* Throws:
* IllegalStateException - If tuple is empty
*/
Tuple Tuple.popBack();Usage examples:
Tuple tuple = Tuple.from("user", 1001, "Alice");
// Query properties
int size = tuple.size(); // 3
boolean empty = tuple.isEmpty(); // false
List<Object> items = tuple.getItems();
// Check versionstamp
Tuple vstamped = Tuple.from("log", Versionstamp.incomplete());
boolean hasVS = vstamped.hasIncompleteVersionstamp(); // true
// Get packed size
int packedSize = tuple.getPackedSize();
System.out.println("Packed size: " + packedSize + " bytes");
// Get range for prefix
Tuple prefix = Tuple.from("users");
Range range = prefix.range();
db.read(tr -> {
for (KeyValue kv : tr.getRange(range)) {
Tuple key = Tuple.fromBytes(kv.getKey());
// Process keys with "users" prefix
}
return null;
});
// Iterate over elements
for (Object item : tuple) {
System.out.println(item);
}Compare tuples lexicographically.
/**
* Compare tuples lexicographically.
* Matches sort order of packed tuples.
*
* Parameters:
* - other: Tuple - Tuple to compare to
*
* Returns:
* int - Negative if less, 0 if equal, positive if greater
*/
int Tuple.compareTo(Tuple other);
/**
* Check equality with another object.
*
* Parameters:
* - o: Object - Object to compare
*
* Returns:
* boolean - True if equal
*/
boolean Tuple.equals(Object o);
/**
* Get hash code.
*
* Returns:
* int - Hash code
*/
int Tuple.hashCode();
/**
* Get human-readable string representation.
*
* Returns:
* String - String representation
*/
String Tuple.toString();Usage examples:
Tuple t1 = Tuple.from("a", 1);
Tuple t2 = Tuple.from("a", 2);
Tuple t3 = Tuple.from("b", 1);
// Compare
int cmp1 = t1.compareTo(t2); // Negative (t1 < t2)
int cmp2 = t2.compareTo(t1); // Positive (t2 > t1)
int cmp3 = t1.compareTo(t1); // 0 (equal)
// Equality
boolean eq1 = t1.equals(t2); // false
boolean eq2 = t1.equals(Tuple.from("a", 1)); // true
// Sort tuples
List<Tuple> tuples = Arrays.asList(t3, t1, t2);
Collections.sort(tuples); // [t1, t2, t3]
// Use in maps/sets
Map<Tuple, String> map = new HashMap<>();
map.put(t1, "value1");
map.put(t2, "value2");Versionstamps provide transaction commit version timestamps.
/**
* Create complete versionstamp from 12 bytes.
*
* Parameters:
* - data: byte[] - 12-byte versionstamp
*
* Returns:
* Versionstamp - Complete versionstamp
*/
static Versionstamp Versionstamp.complete(byte[] data);
/**
* Create complete versionstamp from data at offset.
*
* Parameters:
* - data: byte[] - Byte array containing versionstamp
* - offset: int - Offset of 12-byte versionstamp
*
* Returns:
* Versionstamp - Complete versionstamp
*/
static Versionstamp Versionstamp.complete(byte[] data, int offset);
/**
* Create incomplete versionstamp with default user version (0).
* Used as placeholder for transaction commit version.
*
* Returns:
* Versionstamp - Incomplete versionstamp
*/
static Versionstamp Versionstamp.incomplete();
/**
* Create incomplete versionstamp with user version.
*
* Parameters:
* - userVersion: int - 16-bit user version (0-65535)
*
* Returns:
* Versionstamp - Incomplete versionstamp with user version
*/
static Versionstamp Versionstamp.incomplete(int userVersion);
/**
* Create versionstamp from bytes (auto-detect complete/incomplete).
*
* Parameters:
* - data: byte[] - 12-byte versionstamp
*
* Returns:
* Versionstamp - Versionstamp
*/
static Versionstamp Versionstamp.fromBytes(byte[] data);/**
* Get 12-byte versionstamp representation.
*
* Returns:
* byte[] - 12-byte array (10 bytes version + 2 bytes user version)
*/
byte[] Versionstamp.getBytes();
/**
* Get 10-byte transaction version portion.
*
* Returns:
* byte[] - 10-byte transaction version
*/
byte[] Versionstamp.getTransactionVersion();
/**
* Get 16-bit user version.
*
* Returns:
* int - User version (0-65535)
*/
int Versionstamp.getUserVersion();
/**
* Check if versionstamp is complete.
*
* Returns:
* boolean - True if complete, false if placeholder
*/
boolean Versionstamp.isComplete();
/**
* Compare versionstamps.
*
* Parameters:
* - other: Versionstamp - Versionstamp to compare
*
* Returns:
* int - Negative if less, 0 if equal, positive if greater
*/
int Versionstamp.compareTo(Versionstamp other);
/**
* Check equality.
*
* Parameters:
* - o: Object - Object to compare
*
* Returns:
* boolean - True if equal
*/
boolean Versionstamp.equals(Object o);
/**
* Get hash code.
*
* Returns:
* int - Hash code
*/
int Versionstamp.hashCode();
/**
* Get string representation.
*
* Returns:
* String - Human-readable representation
*/
String Versionstamp.toString();Usage examples:
import com.apple.foundationdb.tuple.Versionstamp;
// Create incomplete versionstamp for commit-time assignment
Versionstamp incomplete = Versionstamp.incomplete();
Tuple logKey = Tuple.from("log", incomplete);
db.run(tr -> {
byte[] key = logKey.packWithVersionstamp();
tr.mutate(MutationType.SET_VERSIONSTAMPED_KEY, key, "entry".getBytes());
return null;
});
// Create with user version for ordering within same transaction
for (int i = 0; i < 10; i++) {
Versionstamp vs = Versionstamp.incomplete(i);
Tuple key = Tuple.from("events", vs);
// Each key gets same transaction version but different user version
}
// Read complete versionstamp after commit
db.run(tr -> {
tr.mutate(MutationType.SET_VERSIONSTAMPED_KEY,
logKey.packWithVersionstamp(), "data".getBytes());
tr.commit().join();
byte[] vstampBytes = tr.getVersionstamp().join();
Versionstamp committed = Versionstamp.complete(vstampBytes);
System.out.println("Committed at: " + committed);
return null;
});class Tuple implements Comparable<Tuple>, Iterable<Object> {
// All methods documented above
}
class Versionstamp implements Comparable<Versionstamp> {
Versionstamp(byte[] bytes);
Versionstamp(byte[] transactionVersion, int userVersion);
// All methods documented above
}Tuples support the following types with proper ordering: