sql_query 0.0.0

composible sql query builder, with support of binding into query buffer
Documentation
pub mod create_table_st;
pub(crate) mod create_table_st2;
#[cfg(test)]
pub mod debug_query;
pub mod debug_sql;
pub mod delete_st;
pub mod executable;
pub mod execute_no_cache;
pub mod expressions;
pub mod insert_many_st;
pub mod insert_one_st;
pub mod quick_query;
pub mod returning;
pub mod sanitize;
pub mod select_st;
pub mod string_query;
pub mod update_st;

pub mod macros {
    pub use query_macros::*;
}

pub mod prelude {
    pub use crate::create_table_st::constraints::exports::*;
    pub use crate::create_table_st::exports::*;
    pub use crate::execute_no_cache::ExecuteNoCache;
    pub use crate::expressions::exports::*;
    pub use crate::expressions::SelectHelpers2;
    use crate::sanitize::Sanitize;
    pub use crate::select_st::exports::*;
    pub use crate::select_st::joins::join_type;
    pub use crate::select_st::order_by;

    pub fn sanitize<T>(t: T) -> Sanitize<T> {
        Sanitize(t)
    }

    pub mod stmt {
        use crate::create_table_st::CreateTableSt;
        use crate::insert_one_st::InsertStOne;
        use crate::quick_query::QuickQuery;
        use crate::string_query::StringQuery;
        use crate::Query;
        use crate::SupportNamedBind;
        use sqlx::Database;
        use std::marker::PhantomData;

        pub use crate::insert_many_st::insert_many;

        pub fn insert_one<S>(
            from: &'static str,
        ) -> InsertStOne<S>
        where
            S: Database,
        {
            InsertStOne {
                input: Vec::new(),
                output: None,
                from,
                buffer: Default::default(),
                _pd: PhantomData,
                returning: (),
            }
        }

        pub fn create_table_if_not_exists<'q, S>(
            name: &'static str,
        ) -> CreateTableSt<S, QuickQuery<'q>>
        where
            QuickQuery<'q>: Query<S>,
        {
            CreateTableSt {
                header: "CREATE TABLE IF NOT EXISTS".to_string(),
                ident: (None, name.to_string()),
                columns: Vec::new(),
                foreign_keys: Vec::new(),
                ctx: Default::default(),
                _sqlx: Default::default(),
                verbatim: Default::default(),
            }
        }

        pub fn string_query<I>(
            query: String,
            input: I,
        ) -> StringQuery<I> {
            StringQuery { sql: query, input }
        }

        pub fn select<'q, S>(
            table: &'static str,
        ) -> crate::select_st::SelectSt<S, QuickQuery<'q>>
        where
            S: Database + SupportNamedBind,
        {
            crate::select_st::SelectSt {
                select_list: Default::default(),
                where_clause: Default::default(),
                joins: Default::default(),
                ctx: Default::default(),
                order_by: Default::default(),
                limit: Default::default(),
                shift: Default::default(),
                from: table,
                _sqlx: Default::default(),
            }
        }

        pub fn update<'q, S>(
            table: &'static str,
        ) -> crate::update_st::UpdateSt<S, QuickQuery<'q>, ()>
        where
            S: Database + SupportNamedBind,
        {
            crate::update_st::UpdateSt {
                sets: Default::default(),
                where_clause: Default::default(),
                ctx: Default::default(),
                table,
                returning: (),
                _sqlx: Default::default(),
            }
        }

        pub fn delete<'q, S>(
            table: &'static str,
        ) -> crate::delete_st::DeleteSt<S, QuickQuery<'q>>
        where
            S: Database + SupportNamedBind,
        {
            crate::delete_st::DeleteSt {
                where_clause: Default::default(),
                ctx: Default::default(),
                table,
                returning: (),
                _sqlx: Default::default(),
            }
        }
    }
}

pub mod from_row {
    use sqlx::{Database, FromRow};

    /// rely on Sqlx's `FromRow` trait to convert a row
    /// I put this on its own method because sometime
    /// I rely on more dynamic ways to convert a row
    /// and I want to keep sqlx's trait separate
    pub fn sqlx_from_row<T, S>(
    ) -> impl FnMut(S::Row) -> Result<T, sqlx::Error>
    where
        S: Database,
        for<'r> T: FromRow<'r, S::Row>,
    {
        |row| T::from_row(&row)
    }

    pub fn reflexive<S>(
    ) -> impl FnMut(S) -> Result<S, sqlx::Error> {
        |row| Ok(row)
    }
}

use sqlx::{database::HasArguments, Database, Postgres, Sqlite};

pub trait Query<S>: Sized {
    type SqlPart;
    type Context1: Default;
    type Context2: Default;
    #[deprecated = "in favor of ToSqlPart"]
    fn handle_where_item(
        _: impl WhereItem<S, Self> + 'static,
        _: &mut Self::Context1,
    ) -> Self::SqlPart {
        panic!("depricate in favor of ToSqlPart")
    }

    fn build_sql_part_back(
        ctx: &mut Self::Context2,
        from: Self::SqlPart,
    ) -> String;

    type Output;
    fn build_query(
        ctx1: Self::Context1,
        f: impl FnOnce(&mut Self::Context2) -> String,
    ) -> (String, Self::Output);
}

pub mod sql_part {
    use std::marker::PhantomData;

    use sqlx::Database;

    /// a given type can implement both WhereItem and Accept
    /// in order for rust to convert to SqlPart, it has to know
    /// which impl to target, here there are few new-type structs
    /// for each trait
    use crate::{
        create_table_st2::new_constraint_trait::Constraint,
        Accept, Query, WhereItem,
    };

    pub struct WhereItemToSqlPart<T>(pub T);
    pub struct AcceptToSqlPart<T>(pub T);
    pub struct ConstraintToSqlPart<T, Q>(
        pub T,
        pub PhantomData<Q>,
    );
    pub struct ColumnToSqlPart<T, Q>(pub T, pub PhantomData<Q>);

    /// a given type can implement both WhereItem and Accept
    /// in order for rust to convert to SqlPart, it has to know
    /// which impl to target, here there are few new-type structs
    /// for each trait
    /// this has blanket implementation for trivial queries:
    /// SqlPart = String, Context2 = ()
    pub trait ToSqlPart<Q: Query<S>, S> {
        fn to_sql_part(
            self,
            ctx: &mut Q::Context1,
        ) -> Q::SqlPart;
    }

    impl<Q, S, T> ToSqlPart<Q, S> for WhereItemToSqlPart<T>
    where
        S: Database,
        T: WhereItem<S, Q>,
        Q: Query<S, SqlPart = String, Context2 = ()>,
    {
        fn to_sql_part(
            self,
            ctx: &mut <Q as Query<S>>::Context1,
        ) -> <Q as Query<S>>::SqlPart
        where
            Q: Query<S>,
        {
            let item = self.0.where_item(ctx);
            item(&mut ())
        }
    }

    impl<'q, Q, S, T> ToSqlPart<Q, S> for ConstraintToSqlPart<T, Q>
    where
        S: Database,
        T: Constraint<S>,
        Q: Query<S, SqlPart = String, Context2 = ()>,
    {
        fn to_sql_part(
            self,
            ctx: &mut <Q as Query<S>>::Context1,
        ) -> <Q as Query<S>>::SqlPart
        where
            Q: Query<S>,
        {
            self.0.constraint::<Q>(ctx)(&mut ())
        }
    }

    impl<'q, Q, S, T> ToSqlPart<Q, S>
        for crate::sql_part::ColumnToSqlPart<T, Q>
    where
        S: Database,
        T: Constraint<S>,
        Q: Query<S, SqlPart = String, Context2 = ()>,
    {
        fn to_sql_part(
            self,
            ctx: &mut <Q as Query<S>>::Context1,
        ) -> <Q as Query<S>>::SqlPart
        where
            Q: Query<S>,
        {
            self.0.constraint::<Q>(ctx)(&mut ())
        }
    }
    impl<Q, S, T> ToSqlPart<Q, S> for AcceptToSqlPart<T>
    where
        Q: Accept<T, S>,
        Q: Query<S, SqlPart = String, Context2 = ()>,
    {
        fn to_sql_part(
            self,
            ctx: &mut <Q as Query<S>>::Context1,
        ) -> <Q as Query<S>>::SqlPart
        where
            Q: Query<S>,
        {
            <Q as Accept<T, S>>::accept(self.0, ctx)(&mut ())
        }
    }
}

pub trait HasQuery<S, Q: Query<S>> {
    fn _build(self) -> (String, Q::Output);
}

pub trait SupportNamedBind {}
pub trait SupportReturning {}

pub trait Accept<This, S>: Query<S> {
    fn accept(
        this: This,
        ctx1: &mut Self::Context1,
    ) -> impl FnOnce(&mut Self::Context2) -> String
           + 'static
           + Send
           + Sync;
}

pub trait SelectItem<S> {
    fn select_item(self) -> String;
}

pub trait WhereItem<S, Q: Query<S>> {
    fn where_item(
        self,
        ctx: &mut Q::Context1,
    ) -> impl FnOnce(&mut Q::Context2) -> String;
}

pub trait IntoMutArguments<'q, DB>
where
    Self: Sized,
    DB: Database,
{
    fn members_ord() -> &'static [&'static str];
    fn into_arguments(
        self,
        argument: &mut <DB as HasArguments<'q>>::Arguments,
    );
}

pub mod impl_into_mut_arguments_prelude {
    pub use super::IntoMutArguments;
    pub use sqlx::{
        database::HasArguments, Arguments, Database, Encode,
        Type,
    };
}

#[rustfmt::skip]
mod impl_consume_into_args_for_encode_types {
    use super::impl_into_mut_arguments_prelude::*;
    macro_rules! impls {
        ($([$ident:ident, $part:literal])*) => {
            #[allow(unused)]
            impl<'q, DB, $($ident,)*> IntoMutArguments<'q, DB> for ($($ident,)*)
            where
                DB: Database,
                $($ident: Encode<'q, DB> + Type<DB> + Send + 'q,)*
            {
                fn members_ord() -> &'static [&'static str] {
                    &[
                        $(
                            stringify!($part),
                        )*
                    ]
                }
                fn into_arguments(
                    self,
                    argument: &mut <DB as HasArguments<'q>>::Arguments,
                ) {
                    paste::paste! { $(
                        argument.add(self.$part);
                    )* }
                }
            }
        };
    }

    impls!();
    impls!([T0, 0]);
    impls!([T0, 0] [T1, 1]);
    impls!([T0, 0] [T1, 1] [T2, 2]);
    impls!([T0, 0] [T1, 1] [T2, 2] [T3, 3]);
    impls!([T0, 0] [T1, 1] [T2, 2] [T3, 3] [T4, 4]);
    impls!([T0, 0] [T1, 1] [T2, 2] [T3, 3] [T4, 4] [T5, 5]);
    impls!([T0, 0] [T1, 1] [T2, 2] [T3, 3] [T4, 4] [T5, 5] [T6, 6]);
    impls!([T0, 0] [T1, 1] [T2, 2] [T3, 3] [T4, 4] [T5, 5] [T6, 6] [T7, 7]);
    impls!([T0, 0] [T1, 1] [T2, 2] [T3, 3] [T4, 4] [T5, 5] [T6, 6] [T7, 7] [T8, 8]);
    impls!([T0, 0] [T1, 1] [T2, 2] [T3, 3] [T4, 4] [T5, 5] [T6, 6] [T7, 7] [T8, 8] [T9, 9]);
    impls!([T0, 0] [T1, 1] [T2, 2] [T3, 3] [T4, 4] [T5, 5] [T6, 6] [T7, 7] [T8, 8] [T9, 9] [T10, 10]);
    impls!([T0, 0] [T1, 1] [T2, 2] [T3, 3] [T4, 4] [T5, 5] [T6, 6] [T7, 7] [T8, 8] [T9, 9] [T10, 10] [T11, 11]);

}

mod impls {
    use super::*;
    impl SupportReturning for Sqlite {}
    impl SupportNamedBind for Sqlite {}

    impl SupportReturning for Postgres {}
    impl SupportNamedBind for Postgres {}
}