Overview
CqlValue is an enum that can represent any CQL value dynamically. It’s useful when the type is not known at compile time, for generic code, or for dynamic query building.
For better type safety and performance, prefer using statically-typed values (like i32, String) with DeserializeValue and SerializeValue traits.
Source: scylla-cql/src/value.rs (distributed across value types)
Enum Definition
pub enum CqlValue {
Ascii(String),
Boolean(bool),
Blob(Vec<u8>),
Counter(Counter),
Decimal(CqlDecimal),
Date(CqlDate),
Double(f64),
Duration(CqlDuration),
Empty,
Float(f32),
Int(i32),
BigInt(i64),
Text(String),
Timestamp(CqlTimestamp),
Inet(IpAddr),
List(Vec<CqlValue>),
Map(Vec<(CqlValue, CqlValue)>),
Set(Vec<CqlValue>),
UserDefinedType {
keyspace: String,
name: String,
fields: Vec<(String, Option<CqlValue>)>,
},
SmallInt(i16),
TinyInt(i8),
Time(CqlTime),
Timeuuid(CqlTimeuuid),
Tuple(Vec<Option<CqlValue>>),
Uuid(Uuid),
Varint(CqlVarint),
Vector(Vec<CqlValue>),
}
Variants
Simple Types
Ascii(String)
CQL ascii type - ASCII string.
let value = CqlValue::Ascii("hello".to_string());
Boolean(bool)
CQL boolean type.
let value = CqlValue::Boolean(true);
Blob(Vec<u8>)
CQL blob type - arbitrary binary data.
let value = CqlValue::Blob(vec![0x01, 0x02, 0x03]);
Int(i32)
CQL int type - 32-bit signed integer.
let value = CqlValue::Int(42);
BigInt(i64)
CQL bigint type - 64-bit signed integer.
let value = CqlValue::BigInt(9223372036854775807);
SmallInt(i16)
CQL smallint type - 16-bit signed integer.
let value = CqlValue::SmallInt(32767);
TinyInt(i8)
CQL tinyint type - 8-bit signed integer.
let value = CqlValue::TinyInt(127);
Float(f32)
CQL float type - 32-bit IEEE-754 floating point.
let value = CqlValue::Float(3.14);
Double(f64)
CQL double type - 64-bit IEEE-754 floating point.
let value = CqlValue::Double(2.718281828);
Text(String)
CQL text type - UTF-8 string.
let value = CqlValue::Text("Hello, World!".to_string());
Special Numeric Types
Counter(Counter)
CQL counter type.
use scylla::value::Counter;
let value = CqlValue::Counter(Counter(42));
Decimal(CqlDecimal)
CQL decimal type - arbitrary precision decimal.
use scylla::value::CqlDecimal;
let value = CqlValue::Decimal(
CqlDecimal::from_signed_be_bytes_slice_and_exponent(&[0x01, 0x02], 2)
);
Varint(CqlVarint)
CQL varint type - arbitrary precision integer.
use scylla::value::CqlVarint;
let value = CqlValue::Varint(
CqlVarint::from_signed_bytes_be_slice(&[0x01, 0x02, 0x03])
);
Date and Time Types
Date(CqlDate)
CQL date type - days since epoch.
use scylla::value::CqlDate;
let value = CqlValue::Date(CqlDate(2_u32.pow(31)));
Time(CqlTime)
CQL time type - nanoseconds since midnight.
use scylla::value::CqlTime;
let value = CqlValue::Time(CqlTime(3600_000_000_000));
Timestamp(CqlTimestamp)
CQL timestamp type - milliseconds since Unix epoch.
use scylla::value::CqlTimestamp;
let value = CqlValue::Timestamp(CqlTimestamp(1234567890000));
Duration(CqlDuration)
CQL duration type.
use scylla::value::CqlDuration;
let value = CqlValue::Duration(CqlDuration {
months: 1,
days: 2,
nanoseconds: 3_000_000_000,
});
UUID Types
Uuid(Uuid)
CQL uuid type.
use uuid::Uuid;
let value = CqlValue::Uuid(Uuid::new_v4());
Timeuuid(CqlTimeuuid)
CQL timeuuid type (UUID v1).
use scylla::value::CqlTimeuuid;
use uuid::Uuid;
let value = CqlValue::Timeuuid(CqlTimeuuid::from(Uuid::new_v1(/* ... */)));
Network Type
Inet(IpAddr)
CQL inet type - IPv4 or IPv6 address.
use std::net::IpAddr;
let value = CqlValue::Inet("127.0.0.1".parse::<IpAddr>()?);
Collection Types
List(Vec<CqlValue>)
CQL list type.
let value = CqlValue::List(vec![
CqlValue::Int(1),
CqlValue::Int(2),
CqlValue::Int(3),
]);
Set(Vec<CqlValue>)
CQL set type.
let value = CqlValue::Set(vec![
CqlValue::Text("tag1".to_string()),
CqlValue::Text("tag2".to_string()),
]);
Map(Vec<(CqlValue, CqlValue)>)
CQL map type.
let value = CqlValue::Map(vec![
(CqlValue::Text("key1".to_string()), CqlValue::Int(100)),
(CqlValue::Text("key2".to_string()), CqlValue::Int(200)),
]);
Vector(Vec<CqlValue>)
CQL vector type.
let value = CqlValue::Vector(vec![
CqlValue::Float(0.1),
CqlValue::Float(0.2),
CqlValue::Float(0.3),
]);
Complex Types
Tuple(Vec<Option<CqlValue>>)
CQL tuple type.
let value = CqlValue::Tuple(vec![
Some(CqlValue::Int(42)),
Some(CqlValue::Text("hello".to_string())),
None, // NULL element
]);
UserDefinedType
CQL user-defined type (UDT).
let value = CqlValue::UserDefinedType {
keyspace: "my_keyspace".to_string(),
name: "address".to_string(),
fields: vec![
("street".to_string(), Some(CqlValue::Text("123 Main St".to_string()))),
("city".to_string(), Some(CqlValue::Text("Springfield".to_string()))),
("zip".to_string(), Some(CqlValue::Int(12345))),
],
};
Special Value
Empty
Represents an empty value (0 bytes, distinct from NULL).
let value = CqlValue::Empty;
Trait Implementations
SerializeValue
impl SerializeValue for CqlValue
CqlValue can be serialized and used in queries.
use scylla::value::CqlValue;
let value = CqlValue::Int(42);
session.execute_unpaged(&prepared, (value,)).await?;
DeserializeValue
impl DeserializeValue for CqlValue
CqlValue can deserialize any CQL type.
let rows: Vec<(i32, CqlValue)> = session
.query_unpaged("SELECT id, data FROM table", &[])
.await?
.rows_typed::<(i32, CqlValue)>()?;
for (id, data) in rows {
match data {
CqlValue::Text(s) => println!("Text: {}", s),
CqlValue::Int(i) => println!("Int: {}", i),
_ => println!("Other type"),
}
}
Examples
Dynamic Query Building
use scylla::value::CqlValue;
use std::collections::HashMap;
fn build_filter(filters: HashMap<String, CqlValue>) -> (String, Vec<CqlValue>) {
let mut query = "SELECT * FROM users WHERE ".to_string();
let mut values = Vec::new();
for (i, (key, value)) in filters.into_iter().enumerate() {
if i > 0 {
query.push_str(" AND ");
}
query.push_str(&format!("{} = ?", key));
values.push(value);
}
(query, values)
}
let mut filters = HashMap::new();
filters.insert("id".to_string(), CqlValue::Int(42));
filters.insert("name".to_string(), CqlValue::Text("Alice".to_string()));
let (query, values) = build_filter(filters);
Heterogeneous Collection
let mixed_list = CqlValue::List(vec![
CqlValue::Int(42),
CqlValue::Text("hello".to_string()),
CqlValue::Boolean(true),
]);
// This would fail type checking in statically-typed approach
Converting from Strongly-Typed Values
use scylla::value::CqlValue;
// From primitives (need to construct CqlValue explicitly)
let int_val = CqlValue::Int(42);
let text_val = CqlValue::Text("hello".to_string());
// From collections
let list_val = CqlValue::List(
vec![1, 2, 3]
.into_iter()
.map(CqlValue::Int)
.collect()
);
Pattern Matching on Results
let rows: Vec<(String, CqlValue)> = session
.query_unpaged("SELECT name, value FROM settings", &[])
.await?
.rows_typed::<(String, CqlValue)>()?;
for (name, value) in rows {
match value {
CqlValue::Int(i) => println!("{} = {}", name, i),
CqlValue::Text(s) => println!("{} = {}", name, s),
CqlValue::Boolean(b) => println!("{} = {}", name, b),
_ => println!("{} has unknown type", name),
}
}
UDT with CqlValue
let address = CqlValue::UserDefinedType {
keyspace: "my_app".to_string(),
name: "address".to_string(),
fields: vec![
("street".to_string(), Some(CqlValue::Text("123 Main St".to_string()))),
("city".to_string(), Some(CqlValue::Text("Springfield".to_string()))),
("zip".to_string(), Some(CqlValue::Int(12345))),
("country".to_string(), None), // NULL field
],
};
session.execute_unpaged(
&prepared,
(1, "Alice", address)
).await?;
NULL Handling
// Option<CqlValue> for nullable columns
let rows: Vec<(i32, Option<CqlValue>)> = session
.query_unpaged("SELECT id, nullable_field FROM table", &[])
.await?
.rows_typed::<(i32, Option<CqlValue>)>()?;
for (id, value) in rows {
match value {
Some(v) => println!("ID {}: {:?}", id, v),
None => println!("ID {}: NULL", id),
}
}
Performance: CqlValue has overhead compared to statically-typed values:
- Larger memory footprint
- Runtime type checking
- Potential allocations for nested types
- No compile-time type safety
Use statically-typed values when possible for better performance.
When to Use CqlValue
✅ Good Use Cases:
- Generic database tools and utilities
- Dynamic query builders
- Schema introspection and migration tools
- Prototyping and experimentation
- Handling truly dynamic schemas
❌ Avoid When:
- Schema is known at compile time
- Performance is critical
- Type safety is important
- Working with large result sets
See Also