# ScyllaDB Rust Driver: How do I create a Vec of batch values?

**URL:** <https://forum.scylladb.com/t/scylladb-rust-driver-how-do-i-create-a-vec-of-batch-values/4484>\
**Category:** ScyllaDB\
**Tags:** data-model, rust-driver\
**Created:** [February 13, 2025, 4:27am UTC](https://forum.scylladb.com/t/scylladb-rust-driver-how-do-i-create-a-vec-of-batch-values/4484 "2025-02-13T04:27:29Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![Guy](https://sea2.discourse-cdn.com/flex016/user_avatar/forum.scylladb.com/guy/32/9_2.png) [@Guy](https://forum.scylladb.com/u/Guy)\
**Post date:** [February 13, 2025, 4:27am UTC](https://forum.scylladb.com/t/scylladb-rust-driver-how-do-i-create-a-vec-of-batch-values/4484/1 "2025-02-13T04:27:29Z")

</div>

> [@](#):
>
> [**Originally from the User Slack**](https://scylladb-users.slack.com/)
> 
> ![Terry_Davis](https://us1.discourse-cdn.com/flex016/uploads/scylladb/original/2X/3/310bc0d2a532ddb1e8121ab89661f17e26e36ea1.png) **@Terry\_Davis:** How can you create a Vec of batch values in v0.15 like you used to be able to do in scylla rust driver v0.14? The examples only show how to do it using a tuple with hardcoded values: [https://rust-driver.docs.scylladb.com/stable/queries/batch.html#batch-statement](https://rust-driver.docs.scylladb.com/stable/queries/batch.html#batch-statement)
> 
> ```auto
> #[derive(Debug, Deserialize, DeserializeRow, ValueList)]
> pub struct PlayerRow {
> pub id: i32,
> pub account_id: i32,
> }
> 
> fn generate_populate_queries(json_values: &JsonValues) -> (Batch, Vec<LegacySerializedValues>) {
> let mut batch = Batch::default();
> let mut batch_values: Vec<LegacySerializedValues> = Vec::new();
> 
> if let Some(players) = json_values.players.as_ref() {
> for player in players.iter() {
> batch.append_statement("INSERT INTO players (id, account_id) VALUES (?, ?)");
> batch_values.push(player.serialized().unwrap().into_owned());
> }
> }
> 
> // more values...
> 
> (batch, batch_values)
> }
> 
> ```
> 
> I can’t create something like `Vec<BatchValues>` or `Vec<dyn BatchValues>` or `Vec<Box<dyn BatchValues>>` or anything like that.
> 
> Do I have to type out every single field manually like this? `batch_values.push((player.id, player.account_id));` actually even that won’t work because tuples differ in shape.
> 
> ![Karol_Baryła](https://us1.discourse-cdn.com/flex016/uploads/scylladb/original/2X/e/e7789cf73c0ba650b837e4edcae775341e31755c.png) **@Karol\_Baryła:** 1. You should not use `LegacySerializedValues` - it is a not type safe remnant of previous serialization framework and will be removed in the next version. In your case you should probably use `Player` (or whatever is the type of `player` var).  
> 2. `fn generate_populate_queries(json_values: &JsonValues) -> (Batch, impl BatchValues)` should work.
> 
> ![Terry_Davis](https://us1.discourse-cdn.com/flex016/uploads/scylladb/original/2X/3/310bc0d2a532ddb1e8121ab89661f17e26e36ea1.png) **@Terry\_Davis:** 1. This is actually my objective to move away from `LegacySerializedValues` (0.14 -\> 0.15 update)  
> 2. The issue arises when I try to push another value of a different shape to `batch_values`
> 
> ```auto
> let mut batch_values: Vec<??> = Vec::new();
> 
> if let Some(players) = json_values.players.as_ref() {
> for player in players.iter() {
> batch.append_statement("INSERT INTO players (id, account_id) VALUES (?, ?)");
> batch_values.push(player);
> }
> }
> 
> if let Some(accounts) = json_values.accounts.as_ref() {
> for account in accounts.iter() {
> batch.append_statement("INSERT INTO accounts (id, hash, created_at) VALUES (?, ?, ?)");
> batch_values.push(account);
> }
> }
> 
> ```
> 
> error:
> 
> ```auto
> 46 | batch_values.push(*player);
> | ---- ^^^^^^^ expected `Account`, found `Player
> 
> ```
> 
> `Previously, the "polymorphism" was achieved thanks to`ValueList`, but now I don’t know how to type that vector.
> 
> ![Karol_Baryła](https://us1.discourse-cdn.com/flex016/uploads/scylladb/original/2X/e/e7789cf73c0ba650b837e4edcae775341e31755c.png) **@Karol\_Baryła:** This would be a great use case for “BoundStatement” which we currently lack, but will be added in the future.  
> For now you can:  
> • Use 2 batches instead of one, so that the type of values in the batch is constant.  
> • Box your values and use `Vec<Box<dyn SerializeRow>>`  
> I think you could also make your own enum, with variants for your types, and implement SerializeRow for it (and then use Vec\<YourEnum\>) but I’m not sure because I didn’t try to do this before. I can try in a week (I am going for a leave now), or maybe @Mikołaj\_Uzarski or @Wojciech\_Przytuła will be able to help.
> 
> ![Terry_Davis](https://us1.discourse-cdn.com/flex016/uploads/scylladb/original/2X/3/310bc0d2a532ddb1e8121ab89661f17e26e36ea1.png) **@Terry\_Davis:** The enum route will work for now. I had to implement the `BatchValues` trait which is required when calling `batch`. If someone has a better solution please lmk. This is horrid but works:
> 
> ```auto
> struct BatchValuesList(Vec<BatchItem>);
> 
> struct BatchValuesListIterator<'a> {
> values: std::slice::Iter<'a, BatchItem>,
> }
> 
> impl BatchValues for BatchValuesList {
> type BatchValuesIter<'r>
> = BatchValuesListIterator<'r>
> where
> Self: 'r;
> 
> fn batch_values_iter(&self) -> Self::BatchValuesIter<'_> {
> BatchValuesListIterator {
> values: self.0.iter(),
> }
> }
> }
> 
> #[derive(Clone)]
> enum BatchItem {
> PlayerRow(PlayerRow),
> AccountRow(AccountRow),
> }
> 
> impl SerializeRow for BatchItem {
> fn serialize(
> &self,
> ctx: &RowSerializationContext<'_>,
> writer: &mut RowWriter,
> ) -> Result<(), SerializationError> {
> match self {
> BatchItem::PlayerRow(val) => val.serialize(ctx, writer),
> BatchItem::AccountRow(val) => val.serialize(ctx, writer),
> }
> }
> 
> fn is_empty(&self) -> bool {
> false
> }
> }
> 
> impl<'bv> BatchValuesIterator<'bv> for BatchValuesListIterator<'bv> {
> fn serialize_next(
> &mut self,
> ctx: &RowSerializationContext<'_>,
> writer: &mut RowWriter,
> ) -> Option<Result<(), SerializationError>> {
> self.values.next().map(|value| value.serialize(ctx, writer))
> }
> 
> fn is_empty_next(&mut self) -> Option<bool> {
> self.values.next().map(|value| value.is_empty())
> }
> 
> fn skip_next(&mut self) -> Option<()> {
> self.values.next().map(|_| ())
> }
> }
> 
> fn generate_populate_queries(db_data: &DBData) -> (Batch, BatchValuesList) {
> let mut batch = Batch::default();
> let mut batch_values = Vec::new();
> 
> if let Some(players) = db_data.players.as_ref() {
> for player in players.iter() {
> batch.append_statement(INSERT_PLAYER_QUERY);
> batch_values.push(BatchItem::CostumeRow(player.clone()));
> }
> }
> 
> if let Some(accounts) = db_data.accounts.as_ref() {
> for account in accounts.iter() {
> batch.append_statement(INSERT_ACCOUNT_QUERY);
> batch_values.push(BatchItem::AccountRow(account.clone()));
> }
> }
> }
> 
> pub async fn persist_db_data(db_data: &DBData, db_manager: &Arc<DBManager>) {
> let (batch, batch_values) = generate_populate_queries(db_data);
> 
> db_manager
> .session
> .batch(&batch, batch_values)
> .await
> .unwrap();
> }
> 
> ```
> 
> ![Karol_Baryła](https://us1.discourse-cdn.com/flex016/uploads/scylladb/original/2X/e/e7789cf73c0ba650b837e4edcae775341e31755c.png) **@Karol\_Baryła:** Hi @Terry\_Davis, I’m back now so I can help again. There should be no need to implement `BatchValues` in your case - there is already an impl for `Vec<T: SerializeRow>`. I wrote a quick example of using enum for batch with multiple row types:
> 
> ```auto
> #[derive(SerializeRow)]
> struct CustomStructA {
> field_1: String,
> field_2: String,
> }
> 
> #[derive(SerializeRow)]
> struct CustomStructB {
> field_x: String,
> field_y: String,
> }
> 
> enum CustomBatchRow {
> A(CustomStructA),
> B(CustomStructB),
> }
> 
> impl SerializeRow for CustomBatchRow {
> fn serialize(
> &self,
> ctx: &scylla::serialize::row::RowSerializationContext<'_>,
> writer: &mut scylla::serialize::writers::RowWriter,
> ) -> std::result::Result<(), scylla::serialize::SerializationError> {
> match self {
> CustomBatchRow::A(s) => SerializeRow::serialize(s, ctx, writer),
> CustomBatchRow::B(s) => SerializeRow::serialize(s, ctx, writer),
> }
> }
> 
> fn is_empty(&self) -> bool {
> match self {
> CustomBatchRow::A(s) => SerializeRow::is_empty(s),
> CustomBatchRow::B(s) => SerializeRow::is_empty(s),
> }
> }
> }
> 
> fn generate_populate_queries(
> a_rows: impl Iterator<Item = CustomStructA>,
> b_rows: impl Iterator<Item = CustomStructB>,
> ) -> (Batch, Vec<CustomBatchRow>) {
> let mut batch = Batch::default();
> let mut batch_values: Vec<CustomBatchRow> = Vec::new();
> 
> for a_row_values in a_rows {
> batch.append_statement("INSERT INTO table_A (field_1, field_2) VALUES (?, ?)");
> batch_values.push(CustomBatchRow::A(a_row_values));
> }
> 
> for b_row_values in b_rows {
> batch.append_statement("INSERT INTO table_B (field_x, field_y) VALUES (?, ?)");
> batch_values.push(CustomBatchRow::B(b_row_values));
> }
> 
> // more values...
> 
> (batch, batch_values)
> }
> 
> async fn execute_batch(s: &Session) {
> let (batch, values) = generate_populate_queries(vec![].into_iter(), vec![].into_iter());
> let result = s.batch(&batch, &values).await.unwrap();
> }
> 
> ```
