Skip to main content

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 Considerations

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

Build docs developers (and LLMs) love