Overview
The BatchValues trait provides an iterator-like interface for supplying values to batch statements. Each element in the batch can have its own set of bound values.
Most users will use built-in implementations like tuples, slices, or iterators rather than implementing this trait directly.
Source: scylla-cql/src/serialize/batch.rs:10
Trait Definition
pub trait BatchValues {
type BatchValuesIter<'r>: BatchValuesIterator<'r>
where
Self: 'r;
fn batch_values_iter(&self) -> Self::BatchValuesIter<'_>;
}
BatchValuesIterator
An iterator-like interface for accessing values in a batch.
pub trait BatchValuesIterator<'bv> {
fn serialize_next(
&mut self,
ctx: &RowSerializationContext<'_>,
writer: &mut RowWriter,
) -> Option<Result<(), SerializationError>>;
fn is_empty_next(&mut self) -> Option<bool>;
fn skip_next(&mut self) -> Option<()>;
fn count(mut self) -> usize
where
Self: Sized;
}
Built-in Implementations
Slices
impl<T: SerializeRow> BatchValues for [T]
Each element in the slice provides values for one statement in the batch.
Example:
let values = [
(1, "Alice"),
(2, "Bob"),
(3, "Charlie"),
];
session.batch(&batch, values).await?;
Vectors
impl<T: SerializeRow> BatchValues for Vec<T>
Example:
let values = vec![
(1, "Alice"),
(2, "Bob"),
];
session.batch(&batch, values).await?;
Single-Element Tuple
impl<T0: SerializeRow> BatchValues for (T0,)
Provides values for a batch with exactly one statement.
Example:
let values = ((42, "Alice"),);
session.batch(&batch, values).await?;
Multiple-Element Tuples
impl<T0: SerializeRow, T1: SerializeRow> BatchValues for (T0, T1)
impl<T0: SerializeRow, T1: SerializeRow, T2: SerializeRow> BatchValues for (T0, T1, T2)
// ... up to 16 elements
Each tuple element provides values for one statement.
Example:
// Batch with 3 statements
let values = (
(1, "Alice"), // Values for first statement
(2, "Bob"), // Values for second statement
(3, "Charlie"), // Values for third statement
);
session.batch(&batch, values).await?;
References
impl<T: BatchValues + ?Sized> BatchValues for &T
BatchValuesFromIterator
A type that implements BatchValues from an iterator over SerializeRow types.
pub struct BatchValuesFromIterator<'sr, IT> {
// ... internal fields
}
Methods
new
Creates a new BatchValuesFromIterator.
pub fn new(into_iter: impl IntoIterator<IntoIter = IT>) -> Self
where
IT: Iterator<Item = &'sr SR> + Clone,
SR: SerializeRow + 'sr,
Example:
use scylla::serialize::batch::BatchValuesFromIterator;
let users = vec![
User { id: 1, name: "Alice".to_string() },
User { id: 2, name: "Bob".to_string() },
];
let values = BatchValuesFromIterator::new(users.iter());
session.batch(&batch, values).await?;
Usage Patterns
Homogeneous Batch Values
All statements in the batch take the same type of values.
let mut batch = Batch::new(BatchType::Logged);
let prepared = session.prepare("INSERT INTO users (id, name) VALUES (?, ?)").await?;
// Add same statement multiple times
batch.append_statement(&prepared);
batch.append_statement(&prepared);
batch.append_statement(&prepared);
// Provide values for each
let values = [
(1, "Alice"),
(2, "Bob"),
(3, "Charlie"),
];
session.batch(&batch, values).await?;
Heterogeneous Batch Values
Statements in the batch take different types of values.
let mut batch = Batch::new(BatchType::Logged);
let insert_user = session.prepare("INSERT INTO users (id, name) VALUES (?, ?)").await?;
let insert_log = session.prepare("INSERT INTO logs (timestamp, message) VALUES (?, ?)").await?;
batch.append_statement(&insert_user);
batch.append_statement(&insert_log);
// Tuple with different types for each statement
let values = (
(1, "Alice"), // For insert_user
(1234567890i64, "User created"), // For insert_log
);
session.batch(&batch, values).await?;
Empty Values
For statements with no bind markers.
let mut batch = Batch::new(BatchType::Logged);
batch.append_statement("INSERT INTO logs (message) VALUES ('Started')");
batch.append_statement("INSERT INTO logs (message) VALUES ('Finished')");
// Empty tuple for each statement
let values = ((), ());
session.batch(&batch, values).await?;
Mixed Empty and Non-Empty
let mut batch = Batch::new(BatchType::Logged);
let prepared = session.prepare("INSERT INTO users (id, name) VALUES (?, ?)").await?;
batch.append_statement(&prepared);
batch.append_statement("INSERT INTO logs (message) VALUES ('Done')");
// First has values, second is empty
let values = (
(1, "Alice"),
(),
);
session.batch(&batch, values).await?;
Iterator-based Values
use scylla::serialize::batch::BatchValuesFromIterator;
#[derive(SerializeRow)]
struct User {
id: i32,
name: String,
}
let users = vec![
User { id: 1, name: "Alice".to_string() },
User { id: 2, name: "Bob".to_string() },
User { id: 3, name: "Charlie".to_string() },
];
// Create batch with same prepared statement for each user
let mut batch = Batch::new(BatchType::Logged);
let prepared = session.prepare("INSERT INTO users (id, name) VALUES (?, ?)").await?;
for _ in 0..users.len() {
batch.append_statement(&prepared);
}
// Use iterator to provide values
let values = BatchValuesFromIterator::new(users.iter());
session.batch(&batch, values).await?;
Examples
Basic Batch with Tuple Values
use scylla::statement::batch::{Batch, BatchType};
let mut batch = Batch::new(BatchType::Logged);
let prepared = session
.prepare("INSERT INTO users (id, name, email) VALUES (?, ?, ?)")
.await?;
batch.append_statement(&prepared);
batch.append_statement(&prepared);
// Tuple of tuples - each inner tuple is values for one statement
let values = (
(1, "Alice", "[email protected]"),
(2, "Bob", "[email protected]"),
);
session.batch(&batch, values).await?;
Batch with Slices
let values = [
(1, "Alice", "[email protected]"),
(2, "Bob", "[email protected]"),
(3, "Charlie", "[email protected]"),
];
session.batch(&batch, &values[..]).await?;
Batch with Vectors
let mut values = Vec::new();
for i in 1..=100 {
values.push((i, format!("User {}", i), format!("user{}@example.com", i)));
}
session.batch(&batch, values).await?;
Batch with Structs
use scylla::macros::SerializeRow;
#[derive(SerializeRow)]
struct UserInsert {
id: i32,
name: String,
email: String,
}
let users = vec![
UserInsert {
id: 1,
name: "Alice".to_string(),
email: "[email protected]".to_string(),
},
UserInsert {
id: 2,
name: "Bob".to_string(),
email: "[email protected]".to_string(),
},
];
let mut batch = Batch::new(BatchType::Logged);
let prepared = session
.prepare("INSERT INTO users (id, name, email) VALUES (?, ?, ?)")
.await?;
for _ in 0..users.len() {
batch.append_statement(&prepared);
}
session.batch(&batch, users).await?;
Large Batch with Iterator
use scylla::serialize::batch::BatchValuesFromIterator;
// Generate large number of inserts
let data: Vec<_> = (1..=10000)
.map(|i| (i, format!("User {}", i)))
.collect();
let mut batch = Batch::new(BatchType::Unlogged);
let prepared = session
.prepare("INSERT INTO users (id, name) VALUES (?, ?)")
.await?;
for _ in 0..data.len() {
batch.append_statement(&prepared);
}
let values = BatchValuesFromIterator::new(data.iter());
session.batch(&batch, values).await?;
Best Practices
- Use slices or vectors for homogeneous batch values
- Use tuples when statements need different value types
- Use iterators for large batches to avoid allocating all values upfront
- Keep batches small - aim for under 1000 statements
- Match value count to statement count - mismatches will cause errors
The number of value sets must exactly match the number of statements in the batch. Extra values or missing values will cause serialization errors.
See Also