Implement TableMeta proc_macro
This commit is contained in:
parent
0d3a89caeb
commit
771be89260
101
persmgr_derive/Cargo.lock
generated
Normal file
101
persmgr_derive/Cargo.lock
generated
Normal file
|
@ -0,0 +1,101 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.13.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"darling_macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_core"
|
||||
version = "0.13.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610"
|
||||
dependencies = [
|
||||
"fnv",
|
||||
"ident_case",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_macro"
|
||||
version = "0.13.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "ident_case"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||
|
||||
[[package]]
|
||||
name = "persmgr_derive"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"darling",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.101"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.109"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d"
|
13
persmgr_derive/Cargo.toml
Normal file
13
persmgr_derive/Cargo.toml
Normal file
|
@ -0,0 +1,13 @@
|
|||
[package]
|
||||
name = "persmgr_derive"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
quote = "1"
|
||||
proc-macro2 = "1"
|
||||
syn = { version = "1", features = ["full"] }
|
||||
darling = "0.13"
|
109
persmgr_derive/src/lib.rs
Normal file
109
persmgr_derive/src/lib.rs
Normal file
|
@ -0,0 +1,109 @@
|
|||
use darling::FromDeriveInput;
|
||||
use proc_macro::{self, TokenStream};
|
||||
use quote::quote;
|
||||
use syn::{Data, DeriveInput, Expr, Fields, Type, parse_macro_input};
|
||||
|
||||
#[derive(FromDeriveInput, Default)]
|
||||
#[darling(default, attributes(meta))]
|
||||
struct Opts {
|
||||
table: String,
|
||||
key_t: Option<Expr>,
|
||||
}
|
||||
|
||||
#[proc_macro_derive(TableMeta, attributes(meta))]
|
||||
pub fn derive_table_meta(input: TokenStream) -> TokenStream {
|
||||
let input = parse_macro_input!(input);
|
||||
let opts = Opts::from_derive_input(&input)
|
||||
.expect("Expected attribute #[meta(table=\"users\", key_t=i32)]");
|
||||
|
||||
let mut struct_items = Vec::new();
|
||||
|
||||
if let Data::Struct(data) = &input.data {
|
||||
if let Fields::Named(fields) = &data.fields {
|
||||
for field in &fields.named {
|
||||
let ident = field.ident.as_ref().unwrap();
|
||||
let s = ident.to_string();
|
||||
if s.as_str() == "id" || s.as_str() == "created_at" {
|
||||
continue;
|
||||
}
|
||||
let mut should_deref = false;
|
||||
if let Type::Path(tp) = &field.ty {
|
||||
if tp.path.segments.first().unwrap().ident == "ForeignKey" {
|
||||
should_deref = true;
|
||||
}
|
||||
}
|
||||
|
||||
struct_items.push((ident, should_deref));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let ident = input.ident;
|
||||
let table_name = opts.table;
|
||||
let key_t = opts
|
||||
.key_t
|
||||
.unwrap_or_else(|| syn::parse_str::<Expr>("i64").unwrap());
|
||||
|
||||
// dbg!(&table_name);
|
||||
//dbg!(&key_t);
|
||||
|
||||
let mut query = format!("UPDATE {table_name} SET ");
|
||||
let mut query_args = quote!(self.id);
|
||||
let mut i = 2;
|
||||
let mut modified_update = false;
|
||||
for (item, should_deref) in &struct_items {
|
||||
let s = item.to_string();
|
||||
//dbg!(&s);
|
||||
|
||||
if s.as_str() == "modified_at" {
|
||||
modified_update = true;
|
||||
}
|
||||
|
||||
if i != 2 {
|
||||
query.push_str(", ");
|
||||
}
|
||||
query.push_str(s.as_str());
|
||||
query.push_str(&format!(" = ${i} "));
|
||||
i += 1;
|
||||
|
||||
let deref = if *should_deref { quote!(*) } else { quote!() };
|
||||
|
||||
query_args = quote! {
|
||||
#query_args, #deref self.#item
|
||||
};
|
||||
}
|
||||
query.push_str("WHERE id = $1 RETURNING *");
|
||||
|
||||
let mut modified_at = quote! {};
|
||||
|
||||
if modified_update {
|
||||
modified_at = quote! {
|
||||
self.modified_at = time::OffsetDateTime::now_utc().unix_timestamp();
|
||||
}
|
||||
}
|
||||
|
||||
let output = quote! {
|
||||
impl TableMeta for #ident {
|
||||
type PrimaryKey = #key_t;
|
||||
const TABLE: &'static str = #table_name;
|
||||
}
|
||||
|
||||
impl #ident {
|
||||
pub async fn update(&mut self, pool: &crate::db::CurrPool) -> anyhow::Result<Self> {
|
||||
#modified_at
|
||||
let session = sqlx::query_as!(
|
||||
#ident,
|
||||
#query,
|
||||
#query_args
|
||||
)
|
||||
.fetch_one(pool)
|
||||
.await?;
|
||||
Ok(session)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
eprintln!("{}", output.to_string());
|
||||
|
||||
output.into()
|
||||
}
|
Loading…
Reference in New Issue
Block a user