use rusqlite::types::Value;
use crate::sqlite::codec::{DbValue, ToSqlValue};
#[derive(Debug, Clone, PartialEq)]
pub struct InList(Vec<Value>);
impl InList {
pub fn from_i64s(items: impl IntoIterator<Item = i64>) -> Self {
Self(items.into_iter().map(Value::Integer).collect())
}
pub fn from_blobs<'a>(items: impl IntoIterator<Item = &'a [u8]>) -> Self {
Self(items.into_iter().map(|bytes| Value::Blob(bytes.to_vec())).collect())
}
pub fn from_values<T: ToSqlValue>(items: impl IntoIterator<Item = T>) -> Self {
let mut values = Vec::new();
for item in items {
match item.to_sql_value() {
DbValue::Single(value) => values.push(value),
DbValue::Array(nested) => values.extend(nested.iter().cloned()),
}
}
Self(values)
}
}
impl ToSqlValue for InList {
fn to_sql_value(&self) -> DbValue {
DbValue::array(self.0.clone())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn in_list_i64_collects_integer_values() {
assert_eq!(InList::from_i64s([1]).0, vec![Value::Integer(1)]);
assert_eq!(
InList::from_i64s([1, 2, 3]).0,
vec![Value::Integer(1), Value::Integer(2), Value::Integer(3)]
);
assert_eq!(InList::from_i64s(std::iter::empty()).0, Vec::<Value>::new());
}
#[test]
fn in_list_values_bind_each_key_through_its_codec() {
use miden_protocol::Word;
use miden_protocol::block::BlockNumber;
use miden_protocol::utils::serde::Serializable;
let word = Word::from([1_u32, 2, 3, 4]);
assert_eq!(InList::from_values([word]).0, vec![Value::Blob(word.to_bytes())]);
assert_eq!(InList::from_values([BlockNumber::from(7_u32)]).0, vec![Value::Integer(7)]);
assert_eq!(InList::from_values(std::iter::empty::<u32>()).0, Vec::<Value>::new());
}
#[test]
fn in_list_blob_collects_blob_values() {
assert_eq!(
InList::from_blobs([[0x0a, 0xff].as_slice()]).0,
vec![Value::Blob(vec![0x0a, 0xff])]
);
assert_eq!(
InList::from_blobs([[0x01].as_slice(), [0x02].as_slice()]).0,
vec![Value::Blob(vec![0x01]), Value::Blob(vec![0x02])]
);
}
}