//! Database connection implementations using enum-based approach instead of trait objects

use super::{DatabasePool, DatabaseRow as DatabaseRowTrait, DatabaseType, PostgresRow, SqliteRow};
use anyhow::Result;
use chrono::{DateTime, Utc};
use sqlx::{PgPool, SqlitePool};
use uuid::Uuid;

/// Database connection enum that wraps concrete database implementations
#[derive(Debug, Clone)]
pub enum DatabaseConnection {
    PostgreSQL(PostgreSQLConnection),
    SQLite(SQLiteConnection),
}

impl DatabaseConnection {
    /// Create a new database connection from a pool
    pub fn from_pool(pool: &DatabasePool) -> Self {
        match pool {
            DatabasePool::PostgreSQL(pg_pool) => {
                Self::PostgreSQL(PostgreSQLConnection::new(pg_pool.clone()))
            }
            DatabasePool::SQLite(sqlite_pool) => {
                Self::SQLite(SQLiteConnection::new(sqlite_pool.clone()))
            }
        }
    }

    /// Get the database type
    pub fn database_type(&self) -> DatabaseType {
        match self {
            Self::PostgreSQL(_) => DatabaseType::PostgreSQL,
            Self::SQLite(_) => DatabaseType::SQLite,
        }
    }

    /// Execute a query that doesn't return rows
    pub async fn execute(&self, query: &str, params: &[DatabaseParam]) -> Result<u64> {
        match self {
            Self::PostgreSQL(conn) => conn.execute(query, params).await,
            Self::SQLite(conn) => conn.execute(query, params).await,
        }
    }

    /// Fetch exactly one row
    pub async fn fetch_one(&self, query: &str, params: &[DatabaseParam]) -> Result<DatabaseRow> {
        match self {
            Self::PostgreSQL(conn) => {
                let row = conn.fetch_one(query, params).await?;
                Ok(DatabaseRow::PostgreSQL(row))
            }
            Self::SQLite(conn) => {
                let row = conn.fetch_one(query, params).await?;
                Ok(DatabaseRow::SQLite(row))
            }
        }
    }

    /// Fetch zero or one row
    pub async fn fetch_optional(
        &self,
        query: &str,
        params: &[DatabaseParam],
    ) -> Result<Option<DatabaseRow>> {
        match self {
            Self::PostgreSQL(conn) => {
                let row = conn.fetch_optional(query, params).await?;
                Ok(row.map(DatabaseRow::PostgreSQL))
            }
            Self::SQLite(conn) => {
                let row = conn.fetch_optional(query, params).await?;
                Ok(row.map(DatabaseRow::SQLite))
            }
        }
    }

    /// Fetch all rows
    pub async fn fetch_all(
        &self,
        query: &str,
        params: &[DatabaseParam],
    ) -> Result<Vec<DatabaseRow>> {
        match self {
            Self::PostgreSQL(conn) => {
                let rows = conn.fetch_all(query, params).await?;
                Ok(rows.into_iter().map(DatabaseRow::PostgreSQL).collect())
            }
            Self::SQLite(conn) => {
                let rows = conn.fetch_all(query, params).await?;
                Ok(rows.into_iter().map(DatabaseRow::SQLite).collect())
            }
        }
    }
}

/// Database row enum that wraps concrete row implementations
#[derive(Debug)]
pub enum DatabaseRow {
    PostgreSQL(PostgresRow),
    SQLite(SqliteRow),
}

impl std::fmt::Debug for SqliteRow {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("SqliteRow").finish()
    }
}

impl DatabaseRow {
    pub fn get_string(&self, column: &str) -> Result<String> {
        match self {
            Self::PostgreSQL(row) => <PostgresRow as DatabaseRowTrait>::get_string(row, column),
            Self::SQLite(row) => <SqliteRow as DatabaseRowTrait>::get_string(row, column),
        }
    }

    pub fn get_optional_string(&self, column: &str) -> Result<Option<String>> {
        match self {
            Self::PostgreSQL(row) => {
                <PostgresRow as DatabaseRowTrait>::get_optional_string(row, column)
            }
            Self::SQLite(row) => <SqliteRow as DatabaseRowTrait>::get_optional_string(row, column),
        }
    }

    pub fn get_i32(&self, column: &str) -> Result<i32> {
        match self {
            Self::PostgreSQL(row) => <PostgresRow as DatabaseRowTrait>::get_i32(row, column),
            Self::SQLite(row) => <SqliteRow as DatabaseRowTrait>::get_i32(row, column),
        }
    }

    pub fn get_optional_i32(&self, column: &str) -> Result<Option<i32>> {
        match self {
            Self::PostgreSQL(row) => {
                <PostgresRow as DatabaseRowTrait>::get_optional_i32(row, column)
            }
            Self::SQLite(row) => <SqliteRow as DatabaseRowTrait>::get_optional_i32(row, column),
        }
    }

    pub fn get_i64(&self, column: &str) -> Result<i64> {
        match self {
            Self::PostgreSQL(row) => <PostgresRow as DatabaseRowTrait>::get_i64(row, column),
            Self::SQLite(row) => <SqliteRow as DatabaseRowTrait>::get_i64(row, column),
        }
    }

    pub fn get_optional_i64(&self, column: &str) -> Result<Option<i64>> {
        match self {
            Self::PostgreSQL(row) => {
                <PostgresRow as DatabaseRowTrait>::get_optional_i64(row, column)
            }
            Self::SQLite(row) => <SqliteRow as DatabaseRowTrait>::get_optional_i64(row, column),
        }
    }

    pub fn get_bool(&self, column: &str) -> Result<bool> {
        match self {
            Self::PostgreSQL(row) => <PostgresRow as DatabaseRowTrait>::get_bool(row, column),
            Self::SQLite(row) => <SqliteRow as DatabaseRowTrait>::get_bool(row, column),
        }
    }

    pub fn get_optional_bool(&self, column: &str) -> Result<Option<bool>> {
        match self {
            Self::PostgreSQL(row) => {
                <PostgresRow as DatabaseRowTrait>::get_optional_bool(row, column)
            }
            Self::SQLite(row) => <SqliteRow as DatabaseRowTrait>::get_optional_bool(row, column),
        }
    }

    pub fn get_bytes(&self, column: &str) -> Result<Vec<u8>> {
        match self {
            Self::PostgreSQL(row) => <PostgresRow as DatabaseRowTrait>::get_bytes(row, column),
            Self::SQLite(row) => <SqliteRow as DatabaseRowTrait>::get_bytes(row, column),
        }
    }

    pub fn get_optional_bytes(&self, column: &str) -> Result<Option<Vec<u8>>> {
        match self {
            Self::PostgreSQL(row) => {
                <PostgresRow as DatabaseRowTrait>::get_optional_bytes(row, column)
            }
            Self::SQLite(row) => <SqliteRow as DatabaseRowTrait>::get_optional_bytes(row, column),
        }
    }

    #[cfg(feature = "uuid")]
    pub fn get_uuid(&self, column: &str) -> Result<Uuid> {
        match self {
            Self::PostgreSQL(row) => <PostgresRow as DatabaseRowTrait>::get_uuid(row, column),
            Self::SQLite(row) => <SqliteRow as DatabaseRowTrait>::get_uuid(row, column),
        }
    }

    #[cfg(feature = "uuid")]
    pub fn get_optional_uuid(&self, column: &str) -> Result<Option<Uuid>> {
        match self {
            Self::PostgreSQL(row) => {
                <PostgresRow as DatabaseRowTrait>::get_optional_uuid(row, column)
            }
            Self::SQLite(row) => <SqliteRow as DatabaseRowTrait>::get_optional_uuid(row, column),
        }
    }

    pub fn get_datetime(&self, column: &str) -> Result<DateTime<Utc>> {
        match self {
            Self::PostgreSQL(row) => <PostgresRow as DatabaseRowTrait>::get_datetime(row, column),
            Self::SQLite(row) => <SqliteRow as DatabaseRowTrait>::get_datetime(row, column),
        }
    }

    pub fn get_optional_datetime(&self, column: &str) -> Result<Option<DateTime<Utc>>> {
        match self {
            Self::PostgreSQL(row) => {
                <PostgresRow as DatabaseRowTrait>::get_optional_datetime(row, column)
            }
            Self::SQLite(row) => {
                <SqliteRow as DatabaseRowTrait>::get_optional_datetime(row, column)
            }
        }
    }
}

/// Database parameter enum for query parameters
#[derive(Debug, Clone)]
pub enum DatabaseParam {
    String(String),
    I32(i32),
    I64(i64),
    Bool(bool),
    Bytes(Vec<u8>),
    #[cfg(feature = "uuid")]
    Uuid(Uuid),
    DateTime(DateTime<Utc>),
    OptionalString(Option<String>),
    OptionalI32(Option<i32>),
    OptionalI64(Option<i64>),
    OptionalBool(Option<bool>),
    OptionalBytes(Option<Vec<u8>>),
    #[cfg(feature = "uuid")]
    OptionalUuid(Option<Uuid>),
    OptionalDateTime(Option<DateTime<Utc>>),
}

impl From<String> for DatabaseParam {
    fn from(value: String) -> Self {
        Self::String(value)
    }
}

impl From<&str> for DatabaseParam {
    fn from(value: &str) -> Self {
        Self::String(value.to_string())
    }
}

impl From<i32> for DatabaseParam {
    fn from(value: i32) -> Self {
        Self::I32(value)
    }
}

impl From<i64> for DatabaseParam {
    fn from(value: i64) -> Self {
        Self::I64(value)
    }
}

impl From<bool> for DatabaseParam {
    fn from(value: bool) -> Self {
        Self::Bool(value)
    }
}

impl From<Vec<u8>> for DatabaseParam {
    fn from(value: Vec<u8>) -> Self {
        Self::Bytes(value)
    }
}

#[cfg(feature = "uuid")]
impl From<Uuid> for DatabaseParam {
    fn from(value: Uuid) -> Self {
        Self::Uuid(value)
    }
}

impl From<DateTime<Utc>> for DatabaseParam {
    fn from(value: DateTime<Utc>) -> Self {
        Self::DateTime(value)
    }
}

impl From<Option<String>> for DatabaseParam {
    fn from(value: Option<String>) -> Self {
        Self::OptionalString(value)
    }
}

impl From<Option<i32>> for DatabaseParam {
    fn from(value: Option<i32>) -> Self {
        Self::OptionalI32(value)
    }
}

impl From<Option<i64>> for DatabaseParam {
    fn from(value: Option<i64>) -> Self {
        Self::OptionalI64(value)
    }
}

impl From<Option<bool>> for DatabaseParam {
    fn from(value: Option<bool>) -> Self {
        Self::OptionalBool(value)
    }
}

impl From<Option<Vec<u8>>> for DatabaseParam {
    fn from(value: Option<Vec<u8>>) -> Self {
        Self::OptionalBytes(value)
    }
}

#[cfg(feature = "uuid")]
impl From<Option<Uuid>> for DatabaseParam {
    fn from(value: Option<Uuid>) -> Self {
        Self::OptionalUuid(value)
    }
}

impl From<Option<DateTime<Utc>>> for DatabaseParam {
    fn from(value: Option<DateTime<Utc>>) -> Self {
        Self::OptionalDateTime(value)
    }
}

/// PostgreSQL database connection implementation
#[derive(Debug, Clone)]
pub struct PostgreSQLConnection {
    pool: PgPool,
}

impl PostgreSQLConnection {
    pub fn new(pool: PgPool) -> Self {
        Self { pool }
    }

    pub async fn execute(&self, query: &str, params: &[DatabaseParam]) -> Result<u64> {
        let mut sqlx_query = sqlx::query(query);

        for param in params {
            match param {
                DatabaseParam::String(s) => sqlx_query = sqlx_query.bind(s),
                DatabaseParam::I32(i) => sqlx_query = sqlx_query.bind(i),
                DatabaseParam::I64(i) => sqlx_query = sqlx_query.bind(i),
                DatabaseParam::Bool(b) => sqlx_query = sqlx_query.bind(b),
                DatabaseParam::Bytes(bytes) => sqlx_query = sqlx_query.bind(bytes),
                #[cfg(feature = "uuid")]
                DatabaseParam::Uuid(uuid) => sqlx_query = sqlx_query.bind(uuid),
                DatabaseParam::DateTime(dt) => sqlx_query = sqlx_query.bind(dt),
                DatabaseParam::OptionalString(s) => sqlx_query = sqlx_query.bind(s),
                DatabaseParam::OptionalI32(i) => sqlx_query = sqlx_query.bind(i),
                DatabaseParam::OptionalI64(i) => sqlx_query = sqlx_query.bind(i),
                DatabaseParam::OptionalBool(b) => sqlx_query = sqlx_query.bind(b),
                DatabaseParam::OptionalBytes(bytes) => sqlx_query = sqlx_query.bind(bytes),
                #[cfg(feature = "uuid")]
                DatabaseParam::OptionalUuid(uuid) => sqlx_query = sqlx_query.bind(uuid),
                DatabaseParam::OptionalDateTime(dt) => sqlx_query = sqlx_query.bind(dt),
            }
        }

        let result = sqlx_query.execute(&self.pool).await?;
        Ok(result.rows_affected())
    }

    pub async fn fetch_one(&self, query: &str, params: &[DatabaseParam]) -> Result<PostgresRow> {
        let mut sqlx_query = sqlx::query(query);

        for param in params {
            match param {
                DatabaseParam::String(s) => sqlx_query = sqlx_query.bind(s),
                DatabaseParam::I32(i) => sqlx_query = sqlx_query.bind(i),
                DatabaseParam::I64(i) => sqlx_query = sqlx_query.bind(i),
                DatabaseParam::Bool(b) => sqlx_query = sqlx_query.bind(b),
                DatabaseParam::Bytes(bytes) => sqlx_query = sqlx_query.bind(bytes),
                #[cfg(feature = "uuid")]
                DatabaseParam::Uuid(uuid) => sqlx_query = sqlx_query.bind(uuid),
                DatabaseParam::DateTime(dt) => sqlx_query = sqlx_query.bind(dt),
                DatabaseParam::OptionalString(s) => sqlx_query = sqlx_query.bind(s),
                DatabaseParam::OptionalI32(i) => sqlx_query = sqlx_query.bind(i),
                DatabaseParam::OptionalI64(i) => sqlx_query = sqlx_query.bind(i),
                DatabaseParam::OptionalBool(b) => sqlx_query = sqlx_query.bind(b),
                DatabaseParam::OptionalBytes(bytes) => sqlx_query = sqlx_query.bind(bytes),
                #[cfg(feature = "uuid")]
                DatabaseParam::OptionalUuid(uuid) => sqlx_query = sqlx_query.bind(uuid),
                DatabaseParam::OptionalDateTime(dt) => sqlx_query = sqlx_query.bind(dt),
            }
        }

        let row = sqlx_query.fetch_one(&self.pool).await?;
        Ok(PostgresRow(row))
    }

    pub async fn fetch_optional(
        &self,
        query: &str,
        params: &[DatabaseParam],
    ) -> Result<Option<PostgresRow>> {
        let mut sqlx_query = sqlx::query(query);

        for param in params {
            match param {
                DatabaseParam::String(s) => sqlx_query = sqlx_query.bind(s),
                DatabaseParam::I32(i) => sqlx_query = sqlx_query.bind(i),
                DatabaseParam::I64(i) => sqlx_query = sqlx_query.bind(i),
                DatabaseParam::Bool(b) => sqlx_query = sqlx_query.bind(b),
                DatabaseParam::Bytes(bytes) => sqlx_query = sqlx_query.bind(bytes),
                #[cfg(feature = "uuid")]
                DatabaseParam::Uuid(uuid) => sqlx_query = sqlx_query.bind(uuid),
                DatabaseParam::DateTime(dt) => sqlx_query = sqlx_query.bind(dt),
                DatabaseParam::OptionalString(s) => sqlx_query = sqlx_query.bind(s),
                DatabaseParam::OptionalI32(i) => sqlx_query = sqlx_query.bind(i),
                DatabaseParam::OptionalI64(i) => sqlx_query = sqlx_query.bind(i),
                DatabaseParam::OptionalBool(b) => sqlx_query = sqlx_query.bind(b),
                DatabaseParam::OptionalBytes(bytes) => sqlx_query = sqlx_query.bind(bytes),
                #[cfg(feature = "uuid")]
                DatabaseParam::OptionalUuid(uuid) => sqlx_query = sqlx_query.bind(uuid),
                DatabaseParam::OptionalDateTime(dt) => sqlx_query = sqlx_query.bind(dt),
            }
        }

        let row = sqlx_query.fetch_optional(&self.pool).await?;
        Ok(row.map(PostgresRow))
    }

    pub async fn fetch_all(
        &self,
        query: &str,
        params: &[DatabaseParam],
    ) -> Result<Vec<PostgresRow>> {
        let mut sqlx_query = sqlx::query(query);

        for param in params {
            match param {
                DatabaseParam::String(s) => sqlx_query = sqlx_query.bind(s),
                DatabaseParam::I32(i) => sqlx_query = sqlx_query.bind(i),
                DatabaseParam::I64(i) => sqlx_query = sqlx_query.bind(i),
                DatabaseParam::Bool(b) => sqlx_query = sqlx_query.bind(b),
                DatabaseParam::Bytes(bytes) => sqlx_query = sqlx_query.bind(bytes),
                #[cfg(feature = "uuid")]
                DatabaseParam::Uuid(uuid) => sqlx_query = sqlx_query.bind(uuid),
                DatabaseParam::DateTime(dt) => sqlx_query = sqlx_query.bind(dt),
                DatabaseParam::OptionalString(s) => sqlx_query = sqlx_query.bind(s),
                DatabaseParam::OptionalI32(i) => sqlx_query = sqlx_query.bind(i),
                DatabaseParam::OptionalI64(i) => sqlx_query = sqlx_query.bind(i),
                DatabaseParam::OptionalBool(b) => sqlx_query = sqlx_query.bind(b),
                DatabaseParam::OptionalBytes(bytes) => sqlx_query = sqlx_query.bind(bytes),
                #[cfg(feature = "uuid")]
                DatabaseParam::OptionalUuid(uuid) => sqlx_query = sqlx_query.bind(uuid),
                DatabaseParam::OptionalDateTime(dt) => sqlx_query = sqlx_query.bind(dt),
            }
        }

        let rows = sqlx_query.fetch_all(&self.pool).await?;
        Ok(rows.into_iter().map(PostgresRow).collect())
    }
}

/// SQLite database connection implementation
#[derive(Debug, Clone)]
pub struct SQLiteConnection {
    pool: SqlitePool,
}

impl SQLiteConnection {
    pub fn new(pool: SqlitePool) -> Self {
        Self { pool }
    }

    pub async fn execute(&self, query: &str, params: &[DatabaseParam]) -> Result<u64> {
        let mut sqlx_query = sqlx::query(query);

        for param in params {
            match param {
                DatabaseParam::String(s) => sqlx_query = sqlx_query.bind(s),
                DatabaseParam::I32(i) => sqlx_query = sqlx_query.bind(i),
                DatabaseParam::I64(i) => sqlx_query = sqlx_query.bind(i),
                DatabaseParam::Bool(b) => sqlx_query = sqlx_query.bind(b),
                DatabaseParam::Bytes(bytes) => sqlx_query = sqlx_query.bind(bytes),
                #[cfg(feature = "uuid")]
                DatabaseParam::Uuid(uuid) => sqlx_query = sqlx_query.bind(uuid.to_string()),
                DatabaseParam::DateTime(dt) => sqlx_query = sqlx_query.bind(dt.to_rfc3339()),
                DatabaseParam::OptionalString(s) => sqlx_query = sqlx_query.bind(s),
                DatabaseParam::OptionalI32(i) => sqlx_query = sqlx_query.bind(i),
                DatabaseParam::OptionalI64(i) => sqlx_query = sqlx_query.bind(i),
                DatabaseParam::OptionalBool(b) => sqlx_query = sqlx_query.bind(b),
                DatabaseParam::OptionalBytes(bytes) => sqlx_query = sqlx_query.bind(bytes),
                #[cfg(feature = "uuid")]
                DatabaseParam::OptionalUuid(uuid) => {
                    sqlx_query = sqlx_query.bind(uuid.map(|u| u.to_string()))
                }
                DatabaseParam::OptionalDateTime(dt) => {
                    sqlx_query = sqlx_query.bind(dt.map(|d| d.to_rfc3339()))
                }
            }
        }

        let result = sqlx_query.execute(&self.pool).await?;
        Ok(result.rows_affected())
    }

    pub async fn fetch_one(&self, query: &str, params: &[DatabaseParam]) -> Result<SqliteRow> {
        let mut sqlx_query = sqlx::query(query);

        for param in params {
            match param {
                DatabaseParam::String(s) => sqlx_query = sqlx_query.bind(s),
                DatabaseParam::I32(i) => sqlx_query = sqlx_query.bind(i),
                DatabaseParam::I64(i) => sqlx_query = sqlx_query.bind(i),
                DatabaseParam::Bool(b) => sqlx_query = sqlx_query.bind(b),
                DatabaseParam::Bytes(bytes) => sqlx_query = sqlx_query.bind(bytes),
                #[cfg(feature = "uuid")]
                DatabaseParam::Uuid(uuid) => sqlx_query = sqlx_query.bind(uuid.to_string()),
                DatabaseParam::DateTime(dt) => sqlx_query = sqlx_query.bind(dt.to_rfc3339()),
                DatabaseParam::OptionalString(s) => sqlx_query = sqlx_query.bind(s),
                DatabaseParam::OptionalI32(i) => sqlx_query = sqlx_query.bind(i),
                DatabaseParam::OptionalI64(i) => sqlx_query = sqlx_query.bind(i),
                DatabaseParam::OptionalBool(b) => sqlx_query = sqlx_query.bind(b),
                DatabaseParam::OptionalBytes(bytes) => sqlx_query = sqlx_query.bind(bytes),
                #[cfg(feature = "uuid")]
                DatabaseParam::OptionalUuid(uuid) => {
                    sqlx_query = sqlx_query.bind(uuid.map(|u| u.to_string()))
                }
                DatabaseParam::OptionalDateTime(dt) => {
                    sqlx_query = sqlx_query.bind(dt.map(|d| d.to_rfc3339()))
                }
            }
        }

        let row = sqlx_query.fetch_one(&self.pool).await?;
        Ok(SqliteRow(row))
    }

    pub async fn fetch_optional(
        &self,
        query: &str,
        params: &[DatabaseParam],
    ) -> Result<Option<SqliteRow>> {
        let mut sqlx_query = sqlx::query(query);

        for param in params {
            match param {
                DatabaseParam::String(s) => sqlx_query = sqlx_query.bind(s),
                DatabaseParam::I32(i) => sqlx_query = sqlx_query.bind(i),
                DatabaseParam::I64(i) => sqlx_query = sqlx_query.bind(i),
                DatabaseParam::Bool(b) => sqlx_query = sqlx_query.bind(b),
                DatabaseParam::Bytes(bytes) => sqlx_query = sqlx_query.bind(bytes),
                #[cfg(feature = "uuid")]
                DatabaseParam::Uuid(uuid) => sqlx_query = sqlx_query.bind(uuid.to_string()),
                DatabaseParam::DateTime(dt) => sqlx_query = sqlx_query.bind(dt.to_rfc3339()),
                DatabaseParam::OptionalString(s) => sqlx_query = sqlx_query.bind(s),
                DatabaseParam::OptionalI32(i) => sqlx_query = sqlx_query.bind(i),
                DatabaseParam::OptionalI64(i) => sqlx_query = sqlx_query.bind(i),
                DatabaseParam::OptionalBool(b) => sqlx_query = sqlx_query.bind(b),
                DatabaseParam::OptionalBytes(bytes) => sqlx_query = sqlx_query.bind(bytes),
                #[cfg(feature = "uuid")]
                DatabaseParam::OptionalUuid(uuid) => {
                    sqlx_query = sqlx_query.bind(uuid.map(|u| u.to_string()))
                }
                DatabaseParam::OptionalDateTime(dt) => {
                    sqlx_query = sqlx_query.bind(dt.map(|d| d.to_rfc3339()))
                }
            }
        }

        let row = sqlx_query.fetch_optional(&self.pool).await?;
        Ok(row.map(SqliteRow))
    }

    pub async fn fetch_all(&self, query: &str, params: &[DatabaseParam]) -> Result<Vec<SqliteRow>> {
        let mut sqlx_query = sqlx::query(query);

        for param in params {
            match param {
                DatabaseParam::String(s) => sqlx_query = sqlx_query.bind(s),
                DatabaseParam::I32(i) => sqlx_query = sqlx_query.bind(i),
                DatabaseParam::I64(i) => sqlx_query = sqlx_query.bind(i),
                DatabaseParam::Bool(b) => sqlx_query = sqlx_query.bind(b),
                DatabaseParam::Bytes(bytes) => sqlx_query = sqlx_query.bind(bytes),
                #[cfg(feature = "uuid")]
                DatabaseParam::Uuid(uuid) => sqlx_query = sqlx_query.bind(uuid.to_string()),
                DatabaseParam::DateTime(dt) => sqlx_query = sqlx_query.bind(dt.to_rfc3339()),
                DatabaseParam::OptionalString(s) => sqlx_query = sqlx_query.bind(s),
                DatabaseParam::OptionalI32(i) => sqlx_query = sqlx_query.bind(i),
                DatabaseParam::OptionalI64(i) => sqlx_query = sqlx_query.bind(i),
                DatabaseParam::OptionalBool(b) => sqlx_query = sqlx_query.bind(b),
                DatabaseParam::OptionalBytes(bytes) => sqlx_query = sqlx_query.bind(bytes),
                #[cfg(feature = "uuid")]
                DatabaseParam::OptionalUuid(uuid) => {
                    sqlx_query = sqlx_query.bind(uuid.map(|u| u.to_string()))
                }
                DatabaseParam::OptionalDateTime(dt) => {
                    sqlx_query = sqlx_query.bind(dt.map(|d| d.to_rfc3339()))
                }
            }
        }

        let rows = sqlx_query.fetch_all(&self.pool).await?;
        Ok(rows.into_iter().map(SqliteRow).collect())
    }
}
