1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
//! Procedural macro to automatically generate an `Sqlable` trait for the
//! provided struct that is compatible with an SQLite database.
//!
//! # How to use
//!
//! You write:
//! ```rust
//! # use derive_sql::*;
//! # use derive_sql_sqlite::DeriveSqlite;
//! #[derive(DeriveSqlite)]
//! pub struct Person {
//! name: String,
//! age: u32,
//! }
//! ```
//!
//! And you can use:
//! ```rust
//! # use derive_sql::*;
//! # use derive_sql_sqlite::DeriveSqlite;
//! # #[derive(DeriveSqlite)]
//! # pub struct Person {
//! # name: String,
//! # age: u32,
//! # }
//!
//! let connection = rusqlite::Connection::open_in_memory().unwrap();
//! let mut db: PersonSqlite = connection.into();
//!
//! // initialise
//! db.create_table().unwrap();
//!
//! // Insert entries
//! db.insert(Person {name: "Abi".to_string(), age: 31 }).unwrap();
//! db.insert(Person {name: "Bert".to_string(), age: 32 }).unwrap();
//! db.insert(Person {name: "Charlie".to_string(), age: 33 }).unwrap();
//!
//! // Query
//! let persons: Vec<Person> = db.select(Box::new(SimpleFilter::try_from(("age", 32)).unwrap())).unwrap();
//! assert!(persons[0].name.eq("Bert"));
//!
//! // Update
//! db.update(Box::new(SimpleFilter::try_from(("name", "Abi")).unwrap()), Person { name: "Abi".to_string(), age: 32 }).unwrap();
//!
//! // Delete
//! db.delete(Box::new(SimpleFilter::try_from(("name", "Abi")).unwrap())).unwrap();
//!
//! // Clear the table
//! db.delete_table().unwrap();
//! ```
//!
//! # Container attributes:
//! - `#[derive_sqlite(ident = ...)]` overwrite the name of the `rusqlite` wrapper from `{class}Sqlite`;
//! - `#[derive_sqlite(table_name = "...")]` specify the name of the table (default to the container name in lower case);
//!
//! # Field attributes:
//! - `#[derive_sqlite(is_primary_key = true)]` nominate that one of the field is a primary key. Only one primary key can be specified.
//! primary key fields are unique in the table.
//! - `#[derive_sqlite(on_insert = ...)]` nominate a function of the type `fn() -> {type}` with `{type}` corresponding to the type of the
//! field. The function is called when the item is inserted and the value returned by the function is assigned to the field before the
//! item is inserted. Typical use is to assign a creation date.
//! - `#[derive_sqlite(on_update = ...)]` nominate a function of the type `fn() -> {type}` with `{type}` corresponding to the type of the
//! field. The function is called when the item is updated and the value returned by the function is assigned to the field before the
//! item is updated. Typical use is to assign a last modified date.
//!
mod sqlite;
use attribute_derive::{Attribute};
#[derive(Attribute)]
#[attribute(ident = derive_sqlite)]
struct Attrs {
ident: Option<syn::Ident>,
table_name: Option<String>,
}
#[derive(Attribute)]
#[attribute(ident = derive_sqlite)]
struct FieldAttrs {
#[attribute(default = false)]
is_primary_key: bool,
on_insert: Option<syn::PatPath>,
on_update: Option<syn::PatPath>,
}
#[proc_macro_derive(DeriveSqlite, attributes(derive_sqlite))]
pub fn derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
syn::parse(input)
.and_then(|ast: syn::DeriveInput| {
Ok(sqlite::Sqlite::try_from(&ast)?.generate()?)
})
.unwrap_or_else(|e| e.into_compile_error())
.into()
}