sqly 0.5.0

A lightweight macro system on top of sqlx
Documentation
use sqly::derive::*;

/*

Applicable attributes will be passed through, specialized
versions exist to specify only specific operations. These
can be used together, overriding each other where needed.

Additionally, the identifier, visibility and derives of the
generated structs can be specified. However, custom
attributes can currently not be added to generated structs.

*/

#[derive(Table, Debug, Clone)]
#[sqly(
	delete = C35Delete, // derive struct with specific ident
	insert = C35Insert, // derive struct with specific ident
	select = C35Select, // derive struct with specific ident
	update = C35Update, // derive struct with specific ident
	query_derive(Debug, Default), // add Debug and Default to all structs
	delete_derive(Clone, Copy), select_derive(Clone, Copy), // add Clone and Copy to delete and select
	delete_visibility( ), update_visibility = pub(super), // delete is private, update is pub(super), the rest is pub
	insert_returning = { id }, returning = Self, // insert returns the id, delete and update return Self
	update_filter = "archived = FALSE", // only update rows which have not been archived
	update_dynamic, update_optional, // update is dynamic and all values are optional
)]
#[sqly(table = "c35")]
pub struct C35Table {
    // filter on id for delete and update, do not insert (will be generated by SQL)
    #[sqly(key, skip = select, insert)]
    id: i32,
    // select on archived, do not insert or update (needs a different query)
    #[sqly(key = select, skip = insert, update)]
    archived: bool,

    // many repetitive fields, justifying the complicated attribute setup, they only need to be specified once
    // (delete and select do not use these fields, these queries might be better off as separate derives)
    one: i32,
    two: i32,
    // ...
}

// the generated structs look something like this:
/**
```
#[derive(::sqly::Delete, Debug, Default, Clone, Copy)]
#[sqly(table = C35Table, returning = C35Table)]
struct C35Delete {
    id: i32,
}
#[derive(::sqly::Select, Debug, Default, Clone, Copy)]
#[sqly(table = C35Table)]
pub struct C35Select {
    archived: bool,
}
#[derive(::sqly::Insert, Debug, Default)]
#[sqly(table = C35Table, returning = { id })]
pub struct C35Insert {
    one: i32,
    two: i32,
    // ...
}
#[derive(::sqly::Update, Debug, Default)]
#[sqly(table = C35Table, returning = C35Table)]
#[sqly(dynamic, filter = "archived = FALSE")]
pub(super) struct C35Update {
    #[sqly(key)]
    id: i32,
    #[sqly(optional)]
    one: Option<i32>,
    #[sqly(optional)]
    two: Option<i32>,
    // ...
}
```
*/
mod c35 {}

#[test]
fn c35_multi_tasking() {
    let obj = C35Delete::default();
    let (sql, args) = obj.delete_sql();
    assert_eq!(
        sql,
        r#"
DELETE FROM c35 AS "self"
WHERE
	"id" = $1
RETURNING
	"self"."id",
	"self"."archived",
	"self"."one",
	"self"."two"
	"#
        .trim_ascii()
    );

    let obj = C35Select::default();
    let (sql, args) = obj.select_sql();
    assert_eq!(
        sql,
        r#"
SELECT
	"self"."id",
	"self"."archived",
	"self"."one",
	"self"."two"
FROM c35 AS "self"
WHERE
	"self"."archived" = $1
	"#
        .trim_ascii()
    );

    let obj = C35Insert::default();
    let (sql, args) = obj.insert_sql();
    assert_eq!(
        sql,
        r#"
INSERT INTO c35 AS "self" (
	"one",
	"two"
) VALUES (
	$1,
	$2
)
RETURNING
	"self"."id"
	"#
        .trim_ascii()
    );

    let mut obj = C35Update::default();
    assert!(obj.update_sql().is_none());
    obj.one = Some(1);
    obj.two = Some(2);
    let (sql, args) = obj.update_sql().unwrap();
    assert_eq!(
        sql,
        r#"
UPDATE c35 AS "self"
SET
	"one" = $1,
	"two" = $2
WHERE
	(archived = FALSE) AND
	"id" = $3
RETURNING
	"self"."id",
	"self"."archived",
	"self"."one",
	"self"."two"
	"#
        .trim_ascii()
    );
}