use crate::error::ScyllaxError;
use async_trait::async_trait;
use scylla::{
frame::value::{SerializeValuesError, SerializedValues},
prepared_statement::PreparedStatement,
Session, SessionBuilder,
};
#[allow(unused, dead_code, unused_variables)]
use std::{future::Future, pin::Pin};
type Result<T> = std::result::Result<T, ScyllaxError>;
type SerializedValuesResult = std::result::Result<SerializedValues, SerializeValuesError>;
struct UserEntity;
trait Query {
fn query() -> String;
fn bind(&self) -> SerializedValuesResult;
}
trait ReadQuery {
type Output;
}
trait WriteQuery {}
trait GetPreparedStatement<T: Query> {
fn get(&self) -> &PreparedStatement;
}
type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
#[async_trait]
trait QueryCollection {
async fn new(session: &Session) -> Result<Self>
where
Self: Sized;
fn get_prepared<T: Query>(&self) -> &PreparedStatement
where
Self: GetPreparedStatement<T>,
{
<Self as GetPreparedStatement<T>>::get(self)
}
}
struct UserByIdQuery {
id: i32,
}
impl Query for UserByIdQuery {
fn query() -> String {
"select * from users where id = :id".to_string()
}
fn bind(&self) -> SerializedValuesResult {
let mut values = SerializedValues::new();
values.add_named_value("id", &self.id)?;
Ok(values)
}
}
impl ReadQuery for UserByIdQuery {
type Output = UserEntity;
}
impl GetPreparedStatement<UserByIdQuery> for UserQueries {
fn get(&self) -> &PreparedStatement {
&self.user_by_id_query
}
}
struct UserByEmailQuery {
email: String,
}
impl Query for UserByEmailQuery {
fn query() -> String {
"select * from users_by_email where email = :email".to_string()
}
fn bind(&self) -> SerializedValuesResult {
let mut values = SerializedValues::with_capacity(1);
values.add_named_value("email", &self.email);
Ok(values)
}
}
impl ReadQuery for UserByEmailQuery {
type Output = UserEntity;
}
impl GetPreparedStatement<UserByEmailQuery> for UserQueries {
fn get(&self) -> &PreparedStatement {
&self.user_by_email_query
}
}
#[allow(nonstandard_style, non_snake_case)]
struct UserQueries {
user_by_id_query: PreparedStatement,
user_by_email_query: PreparedStatement,
}
#[async_trait]
impl QueryCollection for UserQueries {
async fn new(session: &Session) -> Result<Self> {
Ok(Self {
user_by_id_query: session.prepare(UserByIdQuery::query()).await?,
user_by_email_query: session.prepare(UserByEmailQuery::query()).await?,
})
}
}
struct Executor<T> {
session: Session,
queries: T,
}
impl<T: QueryCollection> Executor<T> {
async fn new(session: Session) -> Result<Self> {
let queries = T::new(&session).await?;
Ok(Self { session, queries })
}
async fn execute_read<Q>(&self, query: &Q) -> Result<Q::Output>
where
Q: Query + ReadQuery,
T: GetPreparedStatement<Q>,
{
let statement = self.queries.get_prepared::<Q>();
let variables = query.bind()?;
let result = self.session.execute(statement, variables).await?;
todo!("execute the query")
}
}
async fn test() -> Result<()> {
let session = SessionBuilder::new().build().await.unwrap();
let queries = Executor::<UserQueries>::new(session).await.unwrap();
let user = queries
.execute_read(&UserByEmailQuery {
email: "foo@bar.com".to_string(),
})
.await?;
Ok(())
}