Repository: libsql/libsql
File: libsql/src/hrana/mod.rs (Rust)

Code before:
where
    T: HttpSend,
{
    stream: HranaStream<T>,
    inner: Stmt,
}

impl<T> Statement<T>
where
    T: HttpSend,
{
    pub(crate) fn new(stream: HranaStream<T>, sql: String, want_rows: bool) -> Self {
        let inner = Stmt::new(sql, want_rows);
        Statement { stream, inner }
    }

    pub async fn execute(&mut self, params: &Params) -> crate::Result<usize> {
        let mut stmt = self.inner.clone();
        bind_params(params.clone(), &mut stmt);

        let result = self.stream.execute(stmt).await?;
        Ok(result.affected_row_count as usize)
    }

    pub(crate) async fn query_raw(
        &mut self,
        params: &Params,
    ) -> crate::Result<HranaRows<T::Stream>> {
        let mut stmt = self.inner.clone();
        bind_params(params.clone(), &mut stmt);

        let cursor = self.stream.cursor(Batch::single(stmt)).await?;
        let rows = HranaRows::from_cursor(cursor).await?;

        Ok(rows)
    }
}
impl<T> Statement<T>
where
    T: HttpSend,
    <T as HttpSend>::Stream: Send + Sync + 'static,
{
    pub async fn query(&mut self, params: &Params) -> crate::Result<super::Rows> {
        let rows = self.query_raw(params).await?;
        Ok(super::Rows {
            inner: Box::new(rows),
        })
    }
}

pub struct HranaRows<S> {

Review comment (performance):
I think the issue is with the API for execute_batch. It shouldn't take a coma separated list of statements, but something that implement something like `IntoIterator<Item = Into<Query>>`. Query could be implemented for `(String, Params)`, so that parameters can be bound to each statement in the batch

Code after:
where
    T: HttpSend,
{
    stream: HranaStream<T>,
    inner: Stmt,
}

impl<T> Statement<T>
where
    T: HttpSend,
{
    pub(crate) fn new(stream: HranaStream<T>, sql: String, want_rows: bool) -> crate::Result<Self> {
        // in SQLite when a multiple statements are glued together into one string, only the first one is
        // executed and then a handle to continue execution is returned. However Hrana API doesn't allow
        // passing multi-statement strings, so we just pick first one.
        let mut parse = crate::parser::Statement::parse(&sql);
        match parse.next() {
            None => Err(crate::Error::Misuse(
                "no SQL statement provided".to_string(),
            )),
            Some(Err(e)) => Err(e.into()),
            Some(Ok(stmt)) => {
                let inner = Stmt::new(stmt.stmt, want_rows);
                Ok(Statement { stream, inner })
            }
        }
    }

    pub async fn execute(&mut self, params: &Params) -> crate::Result<usize> {
        let mut stmt = self.inner.clone();
        bind_params(params.clone(), &mut stmt);

        let result = self.stream.execute(stmt).await?;
        Ok(result.affected_row_count as usize)
    }

    pub(crate) async fn query_raw(
        &mut self,
        params: &Params,
    ) -> crate::Result<HranaRows<T::Stream>> {
        let mut stmt = self.inner.clone();
        bind_params(params.clone(), &mut stmt);

        let cursor = self.stream.cursor(Batch::single(stmt)).await?;
        let rows = HranaRows::from_cursor(cursor).await?;

        Ok(rows)
    }
}
impl<T> Statement<T>
where