Rewritten diesel_crud to be more flexible
This commit is contained in:
parent
3318aacf7c
commit
17c81f4da1
1
.env
Normal file
1
.env
Normal file
@ -0,0 +1 @@
|
||||
DATABASE_URL="postgres://postgres:postgres@localhost:32768/postgres"
|
75
Cargo.lock
generated
75
Cargo.lock
generated
@ -55,7 +55,7 @@ checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.75",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -256,7 +256,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim 0.11.1",
|
||||
"syn",
|
||||
"syn 2.0.75",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -267,7 +267,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.75",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -320,7 +320,7 @@ dependencies = [
|
||||
"deluxe-macros",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"syn",
|
||||
"syn 2.0.75",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -333,7 +333,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim 0.10.0",
|
||||
"syn",
|
||||
"syn 2.0.75",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -348,7 +348,7 @@ dependencies = [
|
||||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.75",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -368,7 +368,7 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.75",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -406,7 +406,7 @@ dependencies = [
|
||||
"deluxe",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.75",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -430,7 +430,7 @@ dependencies = [
|
||||
"dsl_auto_type",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.75",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -439,7 +439,7 @@ version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "209c735641a413bc68c4923a9d6ad4bcb3ca306b794edaa7eb0b3228a99ffb25"
|
||||
dependencies = [
|
||||
"syn",
|
||||
"syn 2.0.75",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -453,6 +453,24 @@ dependencies = [
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dotenvy"
|
||||
version = "0.15.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b"
|
||||
|
||||
[[package]]
|
||||
name = "dotenvy_macro"
|
||||
version = "0.15.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb0235d912a8c749f4e0c9f18ca253b4c28cfefc1d2518096016d6e3230b6424"
|
||||
dependencies = [
|
||||
"dotenvy",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dsl_auto_type"
|
||||
version = "0.1.2"
|
||||
@ -464,7 +482,7 @@ dependencies = [
|
||||
"heck 0.5.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.75",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -533,7 +551,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.75",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -753,7 +771,7 @@ name = "into-response-derive"
|
||||
version = "1.1.0"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.75",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1017,7 +1035,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.75",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1143,7 +1161,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"regex",
|
||||
"syn",
|
||||
"syn 2.0.75",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1244,7 +1262,7 @@ checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.75",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1373,6 +1391,17 @@ version = "2.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
||||
|
||||
[[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 = "syn"
|
||||
version = "2.0.75"
|
||||
@ -1402,7 +1431,9 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"diesel",
|
||||
"diesel-async",
|
||||
"dotenvy_macro",
|
||||
"lib",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1422,7 +1453,7 @@ checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.75",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1474,7 +1505,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.75",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1608,7 +1639,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.75",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1731,7 +1762,7 @@ dependencies = [
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.75",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
@ -1753,7 +1784,7 @@ checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.75",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
@ -1916,5 +1947,5 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.75",
|
||||
]
|
||||
|
@ -45,7 +45,7 @@ serde = { version = "1.0", optional = true, features = ["derive"] }
|
||||
# Time
|
||||
chrono = { version = "0.4", optional = true, features = ["serde"] }
|
||||
# Utils
|
||||
derive_more = { version = "1.0", features = ["from", "constructor"] }
|
||||
derive_more = { workspace = true, features = ["from", "constructor"] }
|
||||
|
||||
[workspace.dependencies]
|
||||
syn = "2.0"
|
||||
@ -54,6 +54,7 @@ deluxe = "0.5"
|
||||
proc-macro2 = "1.0"
|
||||
diesel = "2.2"
|
||||
diesel-async = "0.5"
|
||||
derive_more = "1.0"
|
||||
|
||||
[features]
|
||||
axum = ["dep:axum", "dep:tower", "dep:tower-http", "dep:thiserror", "dep:tracing", "dep:tracing-subscriber", "dep:tokio"]
|
||||
|
73
crates/diesel_crud_derive/src/attributes.rs
Normal file
73
crates/diesel_crud_derive/src/attributes.rs
Normal file
@ -0,0 +1,73 @@
|
||||
use crate::common::PrimaryKey;
|
||||
use deluxe::{extract_attributes, ExtractAttributes};
|
||||
use proc_macro2::Ident;
|
||||
use quote::quote;
|
||||
use std::collections::HashMap;
|
||||
use syn::spanned::Spanned;
|
||||
use syn::{Data, DeriveInput, Expr, Path, Type};
|
||||
|
||||
#[derive(ExtractAttributes)]
|
||||
#[deluxe(attributes(diesel))]
|
||||
pub(crate) struct DieselStructAttributes {
|
||||
table_name: Option<Expr>,
|
||||
#[deluxe(rest)]
|
||||
_rest: HashMap<Path, Expr>,
|
||||
}
|
||||
|
||||
#[derive(ExtractAttributes)]
|
||||
#[deluxe(attributes(diesel_crud))]
|
||||
pub(crate) struct StructAttributes {
|
||||
table: Option<Expr>,
|
||||
#[deluxe(default)]
|
||||
insert: Option<Type>,
|
||||
#[deluxe(default)]
|
||||
update: Option<Type>,
|
||||
}
|
||||
|
||||
#[derive(ExtractAttributes)]
|
||||
#[deluxe(attributes(diesel_crud))]
|
||||
pub(crate) struct FieldAttributes(#[allow(unused)] Expr);
|
||||
|
||||
pub(crate) struct Attributes {
|
||||
pub struct_ident: Ident,
|
||||
pub table: Expr,
|
||||
pub insert: Type,
|
||||
pub update: Type,
|
||||
pub pk: Option<PrimaryKey>,
|
||||
}
|
||||
|
||||
pub(crate) fn extract_attrs(ast: &mut DeriveInput) -> deluxe::Result<Attributes> {
|
||||
let struct_attributes: StructAttributes = extract_attributes(ast)?;
|
||||
let diesel_attributes: DieselStructAttributes = extract_attributes(ast)?;
|
||||
Ok(Attributes {
|
||||
struct_ident: ast.ident.clone(),
|
||||
table: diesel_attributes.table_name.unwrap_or_else(|| {
|
||||
struct_attributes
|
||||
.table
|
||||
.expect("Table name should be provided on either diesel or diesel_crud attribute")
|
||||
}),
|
||||
insert: struct_attributes
|
||||
.insert
|
||||
.unwrap_or_else(|| Type::Verbatim(quote! { Self })),
|
||||
update: struct_attributes
|
||||
.update
|
||||
.unwrap_or_else(|| Type::Verbatim(quote! { Self })),
|
||||
pk: extract_field_attrs(ast).ok(),
|
||||
})
|
||||
}
|
||||
|
||||
fn extract_field_attrs(ast: &mut DeriveInput) -> deluxe::Result<PrimaryKey> {
|
||||
if let Data::Struct(data_struct) = &mut ast.data {
|
||||
for field in data_struct.fields.iter_mut() {
|
||||
if let Ok(FieldAttributes(_)) = extract_attributes(field) {
|
||||
return Ok(PrimaryKey {
|
||||
ident: field.ident.clone().unwrap(),
|
||||
ty: field.ty.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Err(deluxe::Error::new(ast.span(), "Expected a struct"));
|
||||
};
|
||||
Err(deluxe::Error::new(ast.span(), "Primary key not found"))
|
||||
}
|
@ -1,16 +1,10 @@
|
||||
use proc_macro2::Ident;
|
||||
use quote::quote;
|
||||
use syn::Type;
|
||||
|
||||
pub(crate) fn function_body(body: proc_macro2::TokenStream) -> proc_macro2::TokenStream {
|
||||
quote! {
|
||||
let connection = self.pool.get().await;
|
||||
match connection {
|
||||
Ok(mut connection) => {
|
||||
use diesel::associations::HasTable;
|
||||
#body
|
||||
}
|
||||
Err(error) => Err(lib::diesel_crud_trait::CrudError::PoolError(error.to_string())),
|
||||
}
|
||||
}
|
||||
pub(crate) struct PrimaryKey {
|
||||
pub ident: Ident,
|
||||
pub ty: Type,
|
||||
}
|
||||
|
||||
pub(crate) fn return_type(output: proc_macro2::TokenStream) -> proc_macro2::TokenStream {
|
||||
|
@ -1,49 +1,35 @@
|
||||
use crate::{common, StructAttributes};
|
||||
use proc_macro2::Ident;
|
||||
use crate::{common, Attributes};
|
||||
use quote::quote;
|
||||
use syn::Expr;
|
||||
|
||||
pub(crate) fn derive_diesel_crud_create_impl(
|
||||
StructAttributes {
|
||||
Attributes {
|
||||
struct_ident,
|
||||
table,
|
||||
entity,
|
||||
create,
|
||||
insert,
|
||||
..
|
||||
}: &StructAttributes,
|
||||
identifier: &Ident,
|
||||
}: &Attributes,
|
||||
) -> proc_macro2::TokenStream {
|
||||
let body = function_body(table);
|
||||
let return_type = common::return_type(quote! { Self::Entity });
|
||||
let return_type = common::return_type(quote! { Self });
|
||||
|
||||
quote! {
|
||||
#[automatically_derived]
|
||||
impl<'insertable, 'entity> lib::diesel_crud_trait::DieselCrudCreate<'insertable, 'entity, #table::table> for #identifier
|
||||
where
|
||||
'entity: 'insertable,
|
||||
{
|
||||
type Create = #create;
|
||||
type Entity = #entity;
|
||||
fn create<'a, 'b>(&'a self, create: &'insertable Self::Create) -> #return_type
|
||||
impl lib::diesel_crud_trait::DieselCrudCreate<#table::table> for #struct_ident {
|
||||
type Insert = #insert;
|
||||
fn create<'a, 'b>(insert: Self::Insert, conn: &'a mut diesel_async::AsyncPgConnection) -> #return_type
|
||||
where
|
||||
Self: Sync + 'a,
|
||||
Self: Sized + Sync + 'a,
|
||||
'a: 'b,
|
||||
'insertable: 'b
|
||||
{
|
||||
Box::pin(async move {
|
||||
#body
|
||||
use diesel::associations::HasTable;
|
||||
diesel_async::RunQueryDsl::get_result(
|
||||
diesel::dsl::insert_into(#table::table::table()).values(insert),
|
||||
conn
|
||||
)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn function_body(table: &Expr) -> proc_macro2::TokenStream {
|
||||
common::function_body(quote! {
|
||||
diesel_async::RunQueryDsl::get_result(
|
||||
diesel::dsl::insert_into(#table::table::table()).values(create),
|
||||
&mut connection
|
||||
)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
})
|
||||
}
|
||||
|
@ -1,55 +1,46 @@
|
||||
use crate::{common, StructAttributes};
|
||||
use proc_macro2::Ident;
|
||||
use quote::{quote, ToTokens};
|
||||
use syn::Expr;
|
||||
use crate::{common, Attributes, PrimaryKey};
|
||||
use quote::quote;
|
||||
|
||||
pub(crate) fn derive_diesel_crud_delete_impl(
|
||||
StructAttributes {
|
||||
Attributes {
|
||||
struct_ident,
|
||||
table,
|
||||
pk,
|
||||
pk_field,
|
||||
..
|
||||
}: &StructAttributes,
|
||||
identifier: &Ident,
|
||||
}: &Attributes,
|
||||
) -> proc_macro2::TokenStream {
|
||||
let body = function_body(
|
||||
table,
|
||||
pk_field
|
||||
.clone()
|
||||
.map(Expr::into_token_stream)
|
||||
.unwrap_or_else(|| quote! { id }),
|
||||
);
|
||||
let return_type = common::return_type(quote! { usize });
|
||||
if pk.is_none() {
|
||||
panic!("Please specify a primary key using #[diesel_crud(pk)]");
|
||||
}
|
||||
let PrimaryKey {
|
||||
ident: pk_ident,
|
||||
ty: pk_type,
|
||||
} = pk.as_ref().unwrap();
|
||||
let return_type = common::return_type(quote! { Self });
|
||||
|
||||
quote! {
|
||||
#[automatically_derived]
|
||||
impl lib::diesel_crud_trait::DieselCrudDelete for #identifier {
|
||||
type PK = #pk;
|
||||
fn delete<'a, 'pk, 'b>(&'a self, pk: &'pk Self::PK) -> #return_type
|
||||
impl lib::diesel_crud_trait::DieselCrudDelete for #struct_ident {
|
||||
type PK = #pk_type;
|
||||
fn delete<'a, 'b>(pk: Self::PK, conn: &'a mut diesel_async::AsyncPgConnection) -> #return_type
|
||||
where
|
||||
Self: Sync + 'a,
|
||||
Self: Sized + Sync + 'a,
|
||||
'a: 'b,
|
||||
'pk: 'b,
|
||||
{
|
||||
Box::pin(async move {
|
||||
#body
|
||||
use diesel::QueryDsl;
|
||||
use diesel::associations::HasTable;
|
||||
diesel_async::RunQueryDsl::get_result(
|
||||
diesel::delete(
|
||||
#table::table
|
||||
.filter(diesel::expression_methods::ExpressionMethods::eq(#table::#pk_ident, pk))
|
||||
),
|
||||
conn,
|
||||
)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn function_body(table: &Expr, pk_field: proc_macro2::TokenStream) -> proc_macro2::TokenStream {
|
||||
common::function_body(quote! {
|
||||
use diesel::QueryDsl;
|
||||
diesel_async::RunQueryDsl::execute(
|
||||
diesel::delete(
|
||||
#table::table
|
||||
.filter(diesel::expression_methods::ExpressionMethods::eq(#table::#pk_field, pk))
|
||||
),
|
||||
&mut connection,
|
||||
)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
})
|
||||
}
|
||||
|
@ -1,14 +1,16 @@
|
||||
extern crate proc_macro;
|
||||
|
||||
use crate::attributes::{extract_attrs, Attributes};
|
||||
use crate::common::PrimaryKey;
|
||||
use crate::create::derive_diesel_crud_create_impl;
|
||||
use crate::delete::derive_diesel_crud_delete_impl;
|
||||
use crate::list::derive_diesel_crud_list_impl;
|
||||
use crate::read::derive_diesel_crud_read_impl;
|
||||
use crate::update::derive_diesel_crud_update_impl;
|
||||
use deluxe::{extract_attributes, ExtractAttributes};
|
||||
use quote::quote;
|
||||
use syn::{parse_macro_input, DeriveInput, Expr, Type};
|
||||
use syn::{parse_macro_input, DeriveInput};
|
||||
|
||||
mod attributes;
|
||||
mod common;
|
||||
mod create;
|
||||
mod delete;
|
||||
@ -16,24 +18,6 @@ mod list;
|
||||
mod read;
|
||||
mod update;
|
||||
|
||||
#[derive(ExtractAttributes)]
|
||||
#[deluxe(attributes(diesel_crud))]
|
||||
pub(crate) struct StructAttributes {
|
||||
table: Expr,
|
||||
#[deluxe(default)]
|
||||
entity: Option<Type>,
|
||||
#[deluxe(default)]
|
||||
pk: Option<Type>,
|
||||
#[deluxe(default)]
|
||||
pk_field: Option<Expr>,
|
||||
#[deluxe(default)]
|
||||
create: Option<Type>, // TODO if None, use entity?
|
||||
#[deluxe(default)]
|
||||
update: Option<Type>, // TODO if None, use entity?
|
||||
}
|
||||
|
||||
// TODO get pool field automatically or by attribute
|
||||
|
||||
/// Derives 5 functions for CRUD operations
|
||||
/// 1. create
|
||||
/// 2. read
|
||||
@ -43,16 +27,19 @@ pub(crate) struct StructAttributes {
|
||||
#[proc_macro_derive(DieselCrud, attributes(diesel_crud))]
|
||||
pub fn derive_diesel_crud(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
let mut item = parse_macro_input!(item as DeriveInput);
|
||||
let struct_attributes = extract_attributes(&mut item).unwrap();
|
||||
let identifier = item.ident;
|
||||
let attrs = extract_attrs(&mut item).unwrap();
|
||||
|
||||
let create = derive_diesel_crud_create_impl(&struct_attributes, &identifier);
|
||||
let read = derive_diesel_crud_read_impl(&struct_attributes, &identifier);
|
||||
let update = derive_diesel_crud_update_impl(&struct_attributes, &identifier);
|
||||
let delete = derive_diesel_crud_delete_impl(&struct_attributes, &identifier);
|
||||
let list = derive_diesel_crud_list_impl(&struct_attributes, &identifier);
|
||||
let create = derive_diesel_crud_create_impl(&attrs);
|
||||
let read = derive_diesel_crud_read_impl(&attrs);
|
||||
let update = derive_diesel_crud_update_impl(&attrs);
|
||||
let delete = derive_diesel_crud_delete_impl(&attrs);
|
||||
let list = derive_diesel_crud_list_impl(&attrs);
|
||||
|
||||
let table = struct_attributes.table;
|
||||
let Attributes {
|
||||
table,
|
||||
struct_ident,
|
||||
..
|
||||
} = attrs;
|
||||
let expanded = quote! {
|
||||
#create
|
||||
#read
|
||||
@ -60,124 +47,119 @@ pub fn derive_diesel_crud(item: proc_macro::TokenStream) -> proc_macro::TokenStr
|
||||
#delete
|
||||
#list
|
||||
|
||||
impl<'insertable, 'entity> lib::diesel_crud_trait::DieselCrud<'insertable, 'entity, #table::table> for #identifier
|
||||
where
|
||||
'entity: 'insertable
|
||||
{}
|
||||
impl lib::diesel_crud_trait::DieselCrud<#table::table> for #struct_ident {}
|
||||
};
|
||||
expanded.into()
|
||||
}
|
||||
|
||||
/// Derives the create function for CRUD operations.
|
||||
/// Must be used on a struct with a field named `pool`, containing a `Pool<AsyncPgConnection>`.
|
||||
/// Must be used on a struct.
|
||||
/// # Struct Attributes
|
||||
/// - table: Ident - The schema struct for the table
|
||||
/// - result: Type - The resulting model
|
||||
/// - create: Type - The insertable model
|
||||
/// - table: Expr - The schema struct for the table (can be provided on either diesel or diesel_crud attribute)
|
||||
/// - insert: Type - The insertable model (Optional, defaults to `Self`)
|
||||
/// # Example
|
||||
/// ```ignore
|
||||
/// use diesel_async::{AsyncPgConnection, pooled_connection::deadpool::Pool};
|
||||
///
|
||||
/// #[derive(diesel_crud_derive::DieselCrudCreate)]
|
||||
/// #[diesel_crud(table = crate::schema::user, result = crate::models::User, create = crate::models::InsertUser)]
|
||||
/// struct TestServiceCreate {
|
||||
/// pool: Pool<AsyncPgConnection>,
|
||||
/// #[derive(Queryable, diesel_crud_derive::DieselCrudCreate)]
|
||||
/// #[diesel_crud(create = crate::models::InsertUser)]
|
||||
/// #[diesel(table_name = crate::schema::user)]
|
||||
/// struct User {
|
||||
/// #[diesel_crud(pk)]
|
||||
/// email: String,
|
||||
/// password: String,
|
||||
/// }
|
||||
/// ```
|
||||
#[proc_macro_derive(DieselCrudCreate, attributes(diesel_crud))]
|
||||
pub fn derive_diesel_crud_create(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
let mut item = syn::parse_macro_input!(item as DeriveInput);
|
||||
let struct_attributes = extract_attributes(&mut item).unwrap();
|
||||
derive_diesel_crud_create_impl(&struct_attributes, &item.ident).into()
|
||||
let attrs = extract_attrs(&mut item).unwrap();
|
||||
derive_diesel_crud_create_impl(&attrs).into()
|
||||
}
|
||||
|
||||
/// Derives the read function for CRUD operations.
|
||||
/// Must be used on a struct with a field named `pool`, containing a `Pool<AsyncPgConnection>`.
|
||||
/// Must be used on a struct with one field marked as the primary key.
|
||||
/// # Struct Attributes
|
||||
/// - table: Ident - The schema struct for the table
|
||||
/// - pk: Type - The primary key type
|
||||
/// - result: Type - The resulting model
|
||||
/// - pk_field (optional): Expr - The field to use as the primary key. Defaults to `id`
|
||||
/// - table: Expr - The schema struct for the table (can be provided on either diesel or diesel_crud attribute)
|
||||
/// # Field Attributes
|
||||
/// - pk: Ident - The primary key field (Only one field should be marked as the primary key)
|
||||
/// # Example
|
||||
/// ```ignore
|
||||
/// use diesel_async::{AsyncPgConnection, pooled_connection::deadpool::Pool};
|
||||
///
|
||||
/// #[derive(diesel_crud_derive::DieselCrudRead)]
|
||||
/// #[diesel_crud(table = crate::schema::user, result = crate::models::User, pk = String)]
|
||||
/// struct TestServiceRead {
|
||||
/// pool: Pool<AsyncPgConnection>,
|
||||
/// #[derive(Queryable, diesel_crud_derive::DieselCrudRead)]
|
||||
/// #[diesel(table_name = crate::schema::user)]
|
||||
/// struct User {
|
||||
/// #[diesel_crud(pk)]
|
||||
/// email: String,
|
||||
/// password: String,
|
||||
/// }
|
||||
/// ```
|
||||
#[proc_macro_derive(DieselCrudRead, attributes(diesel_crud))]
|
||||
pub fn derive_diesel_crud_read(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
let mut item = syn::parse_macro_input!(item as DeriveInput);
|
||||
let struct_attributes = extract_attributes(&mut item).unwrap();
|
||||
derive_diesel_crud_read_impl(&struct_attributes, &item.ident).into()
|
||||
let attrs = extract_attrs(&mut item).unwrap();
|
||||
derive_diesel_crud_read_impl(&attrs).into()
|
||||
}
|
||||
|
||||
/// Derives the update function for CRUD operations.
|
||||
/// Must be used on a struct with a field named `pool`, containing a `Pool<AsyncPgConnection>`.
|
||||
/// Must be used on a struct.
|
||||
/// # Struct Attributes
|
||||
/// - table: Ident - The schema struct for the table
|
||||
/// - update: Type - The update model
|
||||
/// - table: Expr - The schema struct for the table (can be provided on either diesel or diesel_crud attribute)
|
||||
/// - update: Type - The update model (Optional, defaults to `Self`)
|
||||
/// # Example
|
||||
/// ```ignore
|
||||
/// use diesel_async::{AsyncPgConnection, pooled_connection::deadpool::Pool};
|
||||
///
|
||||
/// #[derive(diesel_crud_derive::DieselCrudUpdate)]
|
||||
/// #[diesel_crud(table = crate::schema::user, update = crate::models::User)]
|
||||
/// struct TestServiceUpdate {
|
||||
/// pool: Pool<AsyncPgConnection>,
|
||||
/// #[derive(Queryable, diesel_crud_derive::DieselCrudUpdate)]
|
||||
/// #[diesel(table_name = crate::schema::user)]
|
||||
/// struct User {
|
||||
/// #[diesel_crud(pk)]
|
||||
/// email: String,
|
||||
/// password: String,
|
||||
/// }
|
||||
/// ```
|
||||
#[proc_macro_derive(DieselCrudUpdate, attributes(diesel_crud))]
|
||||
pub fn derive_diesel_crud_update(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
let mut item = syn::parse_macro_input!(item as DeriveInput);
|
||||
let struct_attributes = extract_attributes(&mut item).unwrap();
|
||||
derive_diesel_crud_update_impl(&struct_attributes, &item.ident).into()
|
||||
let attrs = extract_attrs(&mut item).unwrap();
|
||||
derive_diesel_crud_update_impl(&attrs).into()
|
||||
}
|
||||
|
||||
/// Derives the delete function for CRUD operations.
|
||||
/// Must be used on a struct with a field named `pool`, containing a `Pool<AsyncPgConnection>`.
|
||||
/// Must be used on a struct with a field marked as primary key.
|
||||
/// # Struct Attributes
|
||||
/// - table: Ident - The schema struct for the table
|
||||
/// - pk: Type - The primary key type
|
||||
/// - pk_field (optional): Expr - The field to use as the primary key. Defaults to `id`
|
||||
/// - table: Expr - The schema struct for the table (can be provided on either diesel or diesel_crud attribute)
|
||||
/// # Field Attributes
|
||||
/// - pk: Ident - The primary key field (Only one field should be marked as the primary key)
|
||||
/// # Example
|
||||
/// ```ignore
|
||||
/// use diesel_async::{AsyncPgConnection, pooled_connection::deadpool::Pool};
|
||||
///
|
||||
/// #[derive(diesel_crud_derive::DieselCrudDelete)]
|
||||
/// #[diesel_crud(table = crate::schema::user, pk = String)]
|
||||
/// struct TestServiceDelete {
|
||||
/// pool: Pool<AsyncPgConnection>,
|
||||
/// #[derive(Queryable, diesel_crud_derive::DieselCrudDelete)]
|
||||
/// #[diesel(table_name = crate::schema::user)]
|
||||
/// struct User {
|
||||
/// #[diesel_crud(pk)]
|
||||
/// email: String,
|
||||
/// password: String,
|
||||
/// }
|
||||
/// ```
|
||||
#[proc_macro_derive(DieselCrudDelete, attributes(diesel_crud))]
|
||||
pub fn derive_diesel_crud_delete(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
let mut item = syn::parse_macro_input!(item as DeriveInput);
|
||||
let struct_attributes = extract_attributes(&mut item).unwrap();
|
||||
derive_diesel_crud_delete_impl(&struct_attributes, &item.ident).into()
|
||||
let attrs = extract_attrs(&mut item).unwrap();
|
||||
derive_diesel_crud_delete_impl(&attrs).into()
|
||||
}
|
||||
|
||||
/// Derives the list function for CRUD operations.
|
||||
/// Must be used on a struct with a field named `pool`, containing a `Pool<AsyncPgConnection>`.
|
||||
/// Must be used on a struct.
|
||||
/// # Struct Attributes
|
||||
/// - table: Ident - The schema struct for the table
|
||||
/// - result: Type - The resulting model
|
||||
/// - table: Expr - The schema struct for the table (can be provided on either diesel or diesel_crud attribute)
|
||||
/// # Example
|
||||
/// ```ignore
|
||||
/// use diesel_async::{AsyncPgConnection, pooled_connection::deadpool::Pool};
|
||||
///
|
||||
/// #[derive(diesel_crud_derive::DieselCrudList)]
|
||||
/// #[diesel_crud(table = crate::schema::user, result = crate::models::User)]
|
||||
/// struct TestServiceList {
|
||||
/// pool: Pool<AsyncPgConnection>,
|
||||
/// #[derive(Queryable, diesel_crud_derive::DieselCrudList)]
|
||||
/// #[diesel(table_name = crate::schema::user)]
|
||||
/// struct User {
|
||||
/// #[diesel_crud(pk)]
|
||||
/// email: String,
|
||||
/// password: String,
|
||||
/// }
|
||||
/// ```
|
||||
#[proc_macro_derive(DieselCrudList, attributes(diesel_crud))]
|
||||
pub fn derive_diesel_crud_list(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
let mut item = syn::parse_macro_input!(item as DeriveInput);
|
||||
let struct_attributes = extract_attributes(&mut item).unwrap();
|
||||
derive_diesel_crud_list_impl(&struct_attributes, &item.ident).into()
|
||||
let attrs = extract_attrs(&mut item).unwrap();
|
||||
derive_diesel_crud_list_impl(&attrs).into()
|
||||
}
|
||||
|
@ -1,35 +1,28 @@
|
||||
use proc_macro2::Ident;
|
||||
use crate::{common, Attributes};
|
||||
use quote::quote;
|
||||
use syn::Expr;
|
||||
|
||||
use crate::{common, StructAttributes};
|
||||
|
||||
pub(crate) fn derive_diesel_crud_list_impl(
|
||||
StructAttributes { table, entity, .. }: &StructAttributes,
|
||||
identifier: &Ident,
|
||||
Attributes {
|
||||
struct_ident,
|
||||
table,
|
||||
..
|
||||
}: &Attributes,
|
||||
) -> proc_macro2::TokenStream {
|
||||
let body = function_body(table);
|
||||
let return_type = common::return_type(quote! { Vec<Self::Entity> });
|
||||
let return_type = common::return_type(quote! { Vec<Self> });
|
||||
|
||||
quote! {
|
||||
#[automatically_derived]
|
||||
impl lib::diesel_crud_trait::DieselCrudList for #identifier {
|
||||
type Entity = #entity;
|
||||
fn list<'a, 'b>(&'a self) -> #return_type
|
||||
impl lib::diesel_crud_trait::DieselCrudList for #struct_ident {
|
||||
fn list<'a, 'b>(conn: &'a mut diesel_async::AsyncPgConnection) -> #return_type
|
||||
where
|
||||
Self: Sync + 'a,
|
||||
Self: Sized + Sync + 'a,
|
||||
'a: 'b
|
||||
{
|
||||
Box::pin(async move {
|
||||
#body
|
||||
use diesel::associations::HasTable;
|
||||
diesel_async::RunQueryDsl::get_results(#table::table::table(), conn).await.map_err(Into::into)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn function_body(table: &Expr) -> proc_macro2::TokenStream {
|
||||
common::function_body(quote! {
|
||||
diesel_async::RunQueryDsl::get_results(#table::table::table(), &mut connection).await.map_err(Into::into)
|
||||
})
|
||||
}
|
||||
|
@ -1,38 +1,40 @@
|
||||
use proc_macro2::Ident;
|
||||
use crate::common::PrimaryKey;
|
||||
use crate::{common, Attributes};
|
||||
use quote::quote;
|
||||
use syn::Expr;
|
||||
|
||||
use crate::{common, StructAttributes};
|
||||
|
||||
pub(crate) fn derive_diesel_crud_read_impl(
|
||||
StructAttributes {
|
||||
table, entity, pk, ..
|
||||
}: &StructAttributes,
|
||||
identifier: &Ident,
|
||||
Attributes {
|
||||
struct_ident,
|
||||
table,
|
||||
pk,
|
||||
..
|
||||
}: &Attributes,
|
||||
) -> proc_macro2::TokenStream {
|
||||
let body = function_body(table);
|
||||
let return_type = common::return_type(quote! { Self::Entity });
|
||||
if pk.is_none() {
|
||||
panic!("Please specify a primary key using #[diesel_crud(pk)]");
|
||||
}
|
||||
let PrimaryKey { ty: pk_type, .. } = pk.as_ref().unwrap();
|
||||
let return_type = common::return_type(quote! { Self });
|
||||
|
||||
quote! {
|
||||
#[automatically_derived]
|
||||
impl lib::diesel_crud_trait::DieselCrudRead for #identifier {
|
||||
type PK = #pk;
|
||||
type Entity = #entity;
|
||||
fn read<'a, 'b>(&'a self, pk: Self::PK) -> #return_type
|
||||
impl lib::diesel_crud_trait::DieselCrudRead for #struct_ident {
|
||||
type PK = #pk_type;
|
||||
fn read<'a, 'b>(pk: Self::PK, conn: &'a mut diesel_async::AsyncPgConnection) -> #return_type
|
||||
where
|
||||
Self: Sync + 'a,
|
||||
Self: Sized + Sync + 'a,
|
||||
'a: 'b
|
||||
{
|
||||
Box::pin(async move {
|
||||
#body
|
||||
use diesel::associations::HasTable;
|
||||
diesel_async::RunQueryDsl::get_result(
|
||||
diesel::QueryDsl::find(#table::table::table(), pk),
|
||||
conn
|
||||
)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn function_body(table: &Expr) -> proc_macro2::TokenStream {
|
||||
common::function_body(quote! {
|
||||
diesel_async::RunQueryDsl::get_result(diesel::QueryDsl::find(#table::table::table(), pk), &mut connection).await.map_err(Into::into)
|
||||
})
|
||||
}
|
||||
|
@ -1,39 +1,35 @@
|
||||
use crate::{common, StructAttributes};
|
||||
use proc_macro2::Ident;
|
||||
use crate::{common, Attributes};
|
||||
use quote::quote;
|
||||
use syn::Expr;
|
||||
|
||||
pub(crate) fn derive_diesel_crud_update_impl(
|
||||
StructAttributes { table, update, .. }: &StructAttributes,
|
||||
identifier: &Ident,
|
||||
Attributes {
|
||||
struct_ident,
|
||||
table,
|
||||
update,
|
||||
..
|
||||
}: &Attributes,
|
||||
) -> proc_macro2::TokenStream {
|
||||
let body = function_body(table);
|
||||
let return_type = common::return_type(quote! { usize });
|
||||
let return_type = common::return_type(quote! { Self });
|
||||
|
||||
quote! {
|
||||
#[automatically_derived]
|
||||
impl lib::diesel_crud_trait::DieselCrudUpdate for #identifier {
|
||||
impl lib::diesel_crud_trait::DieselCrudUpdate for #struct_ident {
|
||||
type Update = #update;
|
||||
fn update<'a, 'b>(&'a self, update: Self::Update) -> #return_type
|
||||
fn update<'a, 'b>(update: Self::Update, conn: &'a mut diesel_async::AsyncPgConnection) -> #return_type
|
||||
where
|
||||
Self: Sync + 'a,
|
||||
Self: Sized + Sync + 'a,
|
||||
'a: 'b,
|
||||
{
|
||||
Box::pin(async move {
|
||||
#body
|
||||
use diesel::associations::HasTable;
|
||||
diesel_async::RunQueryDsl::get_result(
|
||||
diesel::dsl::update(#table::table::table()).set(update),
|
||||
conn,
|
||||
)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn function_body(table: &Expr) -> proc_macro2::TokenStream {
|
||||
common::function_body(quote! {
|
||||
diesel_async::RunQueryDsl::execute(
|
||||
diesel::dsl::update(#table::table::table()).set(update),
|
||||
&mut connection,
|
||||
)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
})
|
||||
}
|
||||
|
@ -1,18 +1,19 @@
|
||||
mod error;
|
||||
|
||||
pub use error::CrudError;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use diesel::{AsChangeset, Insertable};
|
||||
use diesel_async::AsyncPgConnection;
|
||||
pub use error::CrudError;
|
||||
|
||||
pub trait DieselCrud<'insertable, 'entity, Table>:
|
||||
DieselCrudCreate<'insertable, 'entity, Table>
|
||||
+ DieselCrudRead
|
||||
+ DieselCrudUpdate
|
||||
+ DieselCrudDelete
|
||||
+ DieselCrudList
|
||||
where
|
||||
'entity: 'insertable,
|
||||
/// Combines all CRUD operations into a single trait
|
||||
/// Includes:
|
||||
/// - Create
|
||||
/// - Read
|
||||
/// - Update
|
||||
/// - Delete
|
||||
/// - List
|
||||
pub trait DieselCrud<Table>:
|
||||
DieselCrudCreate<Table> + DieselCrudRead + DieselCrudUpdate + DieselCrudDelete + DieselCrudList
|
||||
{
|
||||
}
|
||||
|
||||
@ -21,20 +22,19 @@ where
|
||||
///
|
||||
/// Implementing the trait requires the `async_trait` macro.
|
||||
/// # Associations
|
||||
/// - `Create` - The type to insert
|
||||
/// - `Entity` - The type that will be returned
|
||||
/// - `Insert` - The type to insert, must implement `Insertable<Table>`
|
||||
/// # Parameters
|
||||
/// - `create` - The entity to insert
|
||||
/// - `insert` - The entity to insert
|
||||
/// - `conn` - The database connection
|
||||
/// # Returns
|
||||
/// A result containing the inserted entity or a `CrudError`
|
||||
#[async_trait]
|
||||
pub trait DieselCrudCreate<'insertable, 'entity, Table>
|
||||
pub trait DieselCrudCreate<Table>
|
||||
where
|
||||
'entity: 'insertable,
|
||||
Self: Sized,
|
||||
{
|
||||
type Create: Insertable<Table>;
|
||||
type Entity: 'entity;
|
||||
async fn create(&self, create: &'insertable Self::Create) -> Result<Self::Entity, CrudError>;
|
||||
type Insert: Insertable<Table>;
|
||||
async fn create(insert: Self::Insert, conn: &mut AsyncPgConnection) -> Result<Self, CrudError>;
|
||||
}
|
||||
|
||||
/// Gets an entity from the database
|
||||
@ -42,17 +42,19 @@ where
|
||||
/// Implementing the trait requires the `async_trait` macro.
|
||||
/// # Associations
|
||||
/// - `PK` - The primary key of the entity
|
||||
/// - `Entity` - The type that will be returned
|
||||
/// # Parameters
|
||||
/// - `pk` - The primary key of the entity
|
||||
/// - `conn` - The database connection
|
||||
/// # Returns
|
||||
/// A result containing the entity or a `CrudError`.
|
||||
/// If the entity is not found, the error should be `CrudError::NotFound`.
|
||||
#[async_trait]
|
||||
pub trait DieselCrudRead {
|
||||
pub trait DieselCrudRead
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
type PK;
|
||||
type Entity;
|
||||
async fn read(&self, pk: Self::PK) -> Result<Self::Entity, CrudError>;
|
||||
async fn read(pk: Self::PK, conn: &mut AsyncPgConnection) -> Result<Self, CrudError>;
|
||||
}
|
||||
|
||||
/// Updates an entity in the database
|
||||
@ -63,13 +65,17 @@ pub trait DieselCrudRead {
|
||||
/// - `Update` - The type to update
|
||||
/// # Parameters
|
||||
/// - `update` - The update to apply
|
||||
/// - `conn` - The database connection
|
||||
/// # Returns
|
||||
/// A result containing the number of rows updated or a `CrudError`.
|
||||
/// A result containing the old entry of the entity if successful or a `CrudError`.
|
||||
/// If the entity is not found, the error should be `CrudError::NotFound`.
|
||||
#[async_trait]
|
||||
pub trait DieselCrudUpdate {
|
||||
pub trait DieselCrudUpdate
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
type Update: AsChangeset;
|
||||
async fn update(&self, update: Self::Update) -> Result<usize, CrudError>;
|
||||
async fn update(update: Self::Update, conn: &mut AsyncPgConnection) -> Result<Self, CrudError>;
|
||||
}
|
||||
|
||||
/// Deletes an entity from the database
|
||||
@ -79,24 +85,30 @@ pub trait DieselCrudUpdate {
|
||||
/// - `PK` - The primary key of the entity
|
||||
/// # Parameters
|
||||
/// - `pk` - The primary key of the entity
|
||||
/// - `conn` - The database connection
|
||||
/// # Returns
|
||||
/// A result containing the number of rows deleted or a `CrudError`.
|
||||
/// A result containing the deleted entity or a `CrudError`.
|
||||
/// If the entity is not found, the error should be `CrudError::NotFound`.
|
||||
#[async_trait]
|
||||
pub trait DieselCrudDelete {
|
||||
pub trait DieselCrudDelete
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
type PK;
|
||||
async fn delete(&self, pk: &Self::PK) -> Result<usize, CrudError>;
|
||||
async fn delete(pk: Self::PK, conn: &mut AsyncPgConnection) -> Result<Self, CrudError>;
|
||||
}
|
||||
|
||||
/// Lists all entities in the table
|
||||
///
|
||||
/// Implementing the trait requires the `async_trait` macro.
|
||||
/// # Associations
|
||||
/// - `Entity` - The type that will be returned in a Vec
|
||||
/// # Parameters
|
||||
/// - `conn` - The database connection
|
||||
/// # Returns
|
||||
/// A result containing a Vec of entities or a `CrudError`.
|
||||
#[async_trait]
|
||||
pub trait DieselCrudList {
|
||||
type Entity;
|
||||
async fn list(&self) -> Result<Vec<Self::Entity>, CrudError>;
|
||||
pub trait DieselCrudList
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
async fn list(conn: &mut AsyncPgConnection) -> Result<Vec<Self>, CrudError>;
|
||||
}
|
||||
|
@ -10,3 +10,7 @@ homepage.workspace = true
|
||||
diesel = { workspace = true }
|
||||
diesel-async = { workspace = true }
|
||||
lib = { path = "../../../lib", features = ["diesel", "derive"] }
|
||||
|
||||
[dev-dependencies]
|
||||
tokio = { version = "1.39", features = ["macros"] }
|
||||
dotenvy_macro = "0.15"
|
||||
|
@ -1,11 +1,8 @@
|
||||
#![allow(unused)]
|
||||
use diesel::{AsChangeset, Insertable, Queryable, Selectable};
|
||||
use diesel_async::pooled_connection::deadpool::Pool;
|
||||
use diesel_async::pooled_connection::AsyncDieselConnectionManager;
|
||||
use diesel_async::AsyncPgConnection;
|
||||
use diesel_async::{AsyncConnection, AsyncPgConnection};
|
||||
use dotenvy_macro::dotenv;
|
||||
use lib::diesel_crud_derive::{
|
||||
DieselCrud, DieselCrudCreate, DieselCrudDelete, DieselCrudList, DieselCrudRead,
|
||||
DieselCrudUpdate,
|
||||
DieselCrudCreate, DieselCrudDelete, DieselCrudList, DieselCrudRead, DieselCrudUpdate,
|
||||
};
|
||||
use lib::diesel_crud_trait::DieselCrudCreate;
|
||||
|
||||
@ -16,67 +13,40 @@ diesel::table! {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Queryable, Selectable, Insertable, AsChangeset)]
|
||||
#[derive(
|
||||
Queryable,
|
||||
Selectable,
|
||||
Insertable,
|
||||
AsChangeset,
|
||||
DieselCrudCreate,
|
||||
DieselCrudDelete,
|
||||
DieselCrudList,
|
||||
DieselCrudRead,
|
||||
DieselCrudUpdate,
|
||||
)]
|
||||
#[diesel_crud(insert = InsertUser)]
|
||||
#[diesel(table_name = user)]
|
||||
struct User {
|
||||
#[diesel_crud(pk)]
|
||||
email: String,
|
||||
}
|
||||
|
||||
#[derive(Insertable)]
|
||||
#[derive(Clone, Insertable)]
|
||||
#[diesel(table_name = user)]
|
||||
struct InsertUser {
|
||||
email: String,
|
||||
}
|
||||
|
||||
#[derive(DieselCrud)]
|
||||
#[diesel_crud(table = user, entity = User, pk = String, pk_field = email, create = InsertUser, update = User)]
|
||||
struct TestService {
|
||||
pool: Pool<AsyncPgConnection>,
|
||||
}
|
||||
|
||||
#[derive(DieselCrudCreate, DieselCrudRead, DieselCrudUpdate, DieselCrudDelete, DieselCrudList)]
|
||||
#[diesel_crud(table = user, entity = User, pk = String, pk_field = email, create = InsertUser, update = User)]
|
||||
struct TestServiceSeparate {
|
||||
pool: Pool<AsyncPgConnection>,
|
||||
}
|
||||
|
||||
#[derive(DieselCrudCreate)]
|
||||
#[diesel_crud(table = user, entity = User, create = InsertUser)]
|
||||
struct TestServiceCreate {
|
||||
pool: Pool<AsyncPgConnection>,
|
||||
}
|
||||
|
||||
#[derive(DieselCrudRead)]
|
||||
#[diesel_crud(table = user, entity = User, pk = String)]
|
||||
struct TestServiceRead {
|
||||
pool: Pool<AsyncPgConnection>,
|
||||
}
|
||||
|
||||
#[derive(DieselCrudUpdate)]
|
||||
#[diesel_crud(table = user, update = User)]
|
||||
struct TestServiceUpdate {
|
||||
pool: Pool<AsyncPgConnection>,
|
||||
}
|
||||
|
||||
#[derive(DieselCrudDelete)]
|
||||
#[diesel_crud(table = user, pk = String, pk_field = email)]
|
||||
struct TestServiceDelete {
|
||||
pool: Pool<AsyncPgConnection>,
|
||||
}
|
||||
|
||||
#[derive(DieselCrudList)]
|
||||
#[diesel_crud(table = user, entity = User)]
|
||||
struct TestServiceList {
|
||||
pool: Pool<AsyncPgConnection>,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_insert_user() {
|
||||
let config = AsyncDieselConnectionManager::<AsyncPgConnection>::new("");
|
||||
let pool = Pool::builder(config).max_size(10).build().unwrap();
|
||||
|
||||
let service = TestServiceCreate { pool };
|
||||
service.create(&InsertUser {
|
||||
email: "test".to_string(),
|
||||
});
|
||||
#[tokio::test]
|
||||
async fn test_insert_user() {
|
||||
let database_url = dotenv!("DATABASE_URL");
|
||||
let mut conn = AsyncPgConnection::establish(database_url).await.unwrap();
|
||||
conn.begin_test_transaction().await.unwrap();
|
||||
let _user = User::create(
|
||||
InsertUser {
|
||||
email: "test".to_string(),
|
||||
},
|
||||
&mut conn,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ impl<T: Serialize> BaseResponse<T> {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO version should reference the version in caller's Cargo.toml
|
||||
#[macro_export]
|
||||
macro_rules! from {
|
||||
($body:expr) => {
|
||||
|
Loading…
x
Reference in New Issue
Block a user