use crate::error::{CassandraError, CassandraResult};
use crate::pool::CassandraPool;
use crate::row::{FromRow, Row};
#[derive(Debug, Default)]
pub struct QueryResult {
pub rows: Vec<Row>,
pub applied: Option<bool>,
}
impl CassandraPool {
pub async fn query(&self, _cql: &str) -> CassandraResult<QueryResult> {
Err(CassandraError::Query(
"query() not yet wired to cdrs-tokio".into(),
))
}
pub async fn execute(&self, _cql: &str) -> CassandraResult<()> {
Err(CassandraError::Query(
"execute() not yet wired to cdrs-tokio".into(),
))
}
pub async fn query_one<T: FromRow>(&self, cql: &str) -> CassandraResult<T> {
let result = self.query(cql).await?;
let row = result
.rows
.into_iter()
.next()
.ok_or_else(|| CassandraError::Query("query_one: no rows returned".into()))?;
T::from_row(&row)
}
pub async fn query_many<T: FromRow>(&self, cql: &str) -> CassandraResult<Vec<T>> {
let result = self.query(cql).await?;
result.rows.iter().map(|row| T::from_row(row)).collect()
}
pub async fn execute_lwt(&self, cql: &str) -> CassandraResult<bool> {
let result = self.query(cql).await?;
Ok(result.applied.unwrap_or(false))
}
pub fn batch(&self) -> BatchBuilder<'_> {
BatchBuilder {
pool: self,
statements: Vec::new(),
}
}
}
pub struct BatchBuilder<'a> {
pool: &'a CassandraPool,
statements: Vec<String>,
}
impl<'a> BatchBuilder<'a> {
pub fn add_statement(mut self, cql: impl Into<String>) -> Self {
self.statements.push(cql.into());
self
}
pub async fn execute(self) -> CassandraResult<()> {
self.execute_logged().await
}
pub async fn execute_logged(self) -> CassandraResult<()> {
let _ = self.pool;
if self.statements.is_empty() {
return Err(CassandraError::Query("cannot execute empty batch".into()));
}
Err(CassandraError::Query(
"batch.execute_logged not yet wired to cdrs-tokio".into(),
))
}
pub async fn execute_unlogged(self) -> CassandraResult<()> {
let _ = self.pool;
if self.statements.is_empty() {
return Err(CassandraError::Query("cannot execute empty batch".into()));
}
Err(CassandraError::Query(
"batch.execute_unlogged not yet wired to cdrs-tokio".into(),
))
}
pub async fn execute_counter(self) -> CassandraResult<()> {
let _ = self.pool;
if self.statements.is_empty() {
return Err(CassandraError::Query("cannot execute empty batch".into()));
}
Err(CassandraError::Query(
"batch.execute_counter not yet wired to cdrs-tokio".into(),
))
}
pub fn len(&self) -> usize {
self.statements.len()
}
pub fn is_empty(&self) -> bool {
self.statements.is_empty()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::config::CassandraConfig;
#[tokio::test]
async fn test_query_without_connection_returns_error() {
let config = CassandraConfig::builder()
.known_nodes(["127.0.0.1:9042".to_string()])
.build();
let _ = config;
}
#[test]
fn test_batch_builder_add_increments_len() {
let stmts: Vec<String> = vec!["INSERT INTO t VALUES (1)".into()];
assert_eq!(stmts.len(), 1);
}
#[test]
fn test_query_result_default_is_empty() {
let r = QueryResult::default();
assert!(r.rows.is_empty());
assert!(r.applied.is_none());
}
}