sqlm-postgres 0.1.0

`sql!` macro to write compile-time checked database queries similar to how `format!` works
Documentation
use postgres_types::{FromSql, ToSql};
use sqlm_postgres::{sql, FromRow, SqlType};

#[derive(Debug, Default, PartialEq, Eq)]
struct Id(i64);

#[derive(Debug, PartialEq, Eq, FromRow)]
struct User {
    id: Id,
    name: String,
}

impl SqlType for Id {
    type Type = i64;
}

impl<'a> FromSql<'a> for Id {
    fn from_sql(
        ty: &postgres_types::Type,
        raw: &'a [u8],
    ) -> Result<Self, Box<dyn std::error::Error + Sync + Send>> {
        Ok(Id(i64::from_sql(ty, raw)?))
    }

    fn accepts(ty: &postgres_types::Type) -> bool {
        <i64 as FromSql<'_>>::accepts(ty)
    }
}

impl ToSql for Id {
    fn to_sql(
        &self,
        ty: &postgres_types::Type,
        out: &mut postgres_types::private::BytesMut,
    ) -> Result<postgres_types::IsNull, Box<dyn std::error::Error + Sync + Send>>
    where
        Self: Sized,
    {
        i64::to_sql(&self.0, ty, out)
    }

    fn accepts(ty: &postgres_types::Type) -> bool
    where
        Self: Sized,
    {
        <i64 as FromSql<'_>>::accepts(ty)
    }

    fn to_sql_checked(
        &self,
        ty: &postgres_types::Type,
        out: &mut postgres_types::private::BytesMut,
    ) -> Result<postgres_types::IsNull, Box<dyn std::error::Error + Sync + Send>> {
        i64::to_sql_checked(&self.0, ty, out)
    }
}

#[tokio::test]
async fn test() {
    let id: Id = sql!("SELECT id FROM users WHERE id = 1").await.unwrap();
    assert_eq!(id, Id(1));
}

#[tokio::test]
async fn test_option() {
    let role: Option<Id> = sql!("SELECT id FROM users WHERE id = 1").await.unwrap();
    assert_eq!(role, Some(Id(1)));
    let role: Option<Id> = sql!("SELECT id FROM users WHERE id = -1").await.unwrap();
    assert_eq!(role, None);
}

#[tokio::test]
async fn test_vec() {
    let role: Vec<Id> = sql!(r#"SELECT ARRAY[4, 2]::BIGINT[]"#).await.unwrap();
    assert_eq!(role, vec![Id(4), Id(2)]);
}

#[tokio::test]
async fn test_property() {
    let users: User = sql!("SELECT id, name FROM users WHERE id = 1")
        .await
        .unwrap();
    assert_eq!(
        users,
        User {
            id: Id(1),
            name: "first".to_string()
        }
    );
}

#[tokio::test]
async fn test_option_property() {
    #[derive(Debug, PartialEq, Eq, FromRow)]
    struct User {
        id: Option<Id>,
        name: String,
    }
    let user: User = sql!("SELECT id, name FROM users WHERE id = 1")
        .await
        .unwrap();
    assert_eq!(
        user,
        User {
            id: Some(Id(1)),
            name: "first".to_string()
        }
    );
}

#[tokio::test]
async fn test_property_option() {
    let users: Option<User> = sql!("SELECT id, name FROM users WHERE id = 1")
        .await
        .unwrap();
    assert_eq!(
        users,
        Some(User {
            id: Id(1),
            name: "first".to_string()
        })
    );
}

#[tokio::test]
async fn test_vec_property() {
    #[derive(Debug, PartialEq, Eq, FromRow)]
    struct User {
        ids: Vec<Id>,
        name: String,
    }
    let user: User = sql!("SELECT ARRAY[4, 2]::BIGINT[] AS ids, '' AS name")
        .await
        .unwrap();
    assert_eq!(
        user,
        User {
            ids: vec![Id(4), Id(2)],
            name: String::new()
        }
    );
}

#[tokio::test]
async fn test_property_vec() {
    let users: Vec<User> = sql!("SELECT id, name FROM users").await.unwrap();
    assert_eq!(
        users,
        vec![
            User {
                id: Id(1),
                name: "first".to_string()
            },
            User {
                id: Id(2),
                name: String::new()
            }
        ]
    );
}

#[tokio::test]
async fn test_param() {
    let id = Id(1);
    let users: Vec<User> = sql!("SELECT id, name FROM users WHERE id = {id}")
        .await
        .unwrap();
    assert_eq!(
        users,
        vec![User {
            id: Id(1),
            name: "first".to_string()
        }]
    );
}

#[tokio::test]
async fn test_vec_param() {
    let ids = vec![Id(1), Id(2)];
    let users: Vec<User> = sql!("SELECT id, name FROM users WHERE id = ANY({ids})")
        .await
        .unwrap();
    assert_eq!(
        users,
        vec![
            User {
                id: Id(1),
                name: "first".to_string()
            },
            User {
                id: Id(2),
                name: String::new()
            }
        ]
    );
}