From 228f113dbf04b04396f504685c7590b9a239e5a9 Mon Sep 17 00:00:00 2001 From: JMARyA Date: Fri, 16 Aug 2024 20:38:16 +0200 Subject: [PATCH 01/10] add sort --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/model/mod.rs | 41 +++++++++++++++++++---------------------- 3 files changed, 21 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a71dde5..462ee37 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -698,7 +698,7 @@ dependencies = [ [[package]] name = "mongod" -version = "0.2.0" +version = "0.2.1" dependencies = [ "chrono", "futures", diff --git a/Cargo.toml b/Cargo.toml index d7418e1..119bf72 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mongod" -version = "0.2.0" +version = "0.2.1" edition = "2021" [features] diff --git a/src/model/mod.rs b/src/model/mod.rs index 90df8d3..0ceff52 100644 --- a/src/model/mod.rs +++ b/src/model/mod.rs @@ -8,7 +8,10 @@ use serde::de::DeserializeOwned; use serde_json::{Map, Value}; use valid::Validate; -use crate::{cache_read, cache_write, col, collect_results, get_mongo, id_of}; +#[cfg(feature = "cache")] +use crate::{cache_read, cache_write}; + +use crate::{col, collect_results, get_mongo, id_of}; pub mod historic; pub mod reference; @@ -215,7 +218,7 @@ pub trait Model: /// Get all `Model`s from the database #[must_use] fn find_all() -> impl std::future::Future>> { - Self::find(doc! {}, None) + Self::find(doc! {}, None, None) } /// Get all `Model`s partial from the database @@ -223,7 +226,7 @@ pub trait Model: fn find_all_partial( part: serde_json::Value, ) -> impl std::future::Future>> { - Self::find_partial(doc! {}, part, None) + Self::find_partial(doc! {}, part, None, None) } /// Get multiple `Model`s by using a filter from the database. Pass a `limit` parameter to limit the amount of `Model`s returned. @@ -231,17 +234,15 @@ pub trait Model: fn find( filter: mongodb::bson::Document, limit: Option, + sort: Option, ) -> impl std::future::Future>> { async move { let db = get_mongo!(); let collection = col!(db, Self::collection_name()); - let mut results = collection - .find( - filter, - limit.map(|x| FindOptions::builder().limit(x).build()), - ) - .await - .ok()?; + + let options = FindOptions::builder().limit(limit).sort(sort).build(); + + let mut results = collection.find(filter, options).await.ok()?; let docs = collect_results!(results); docs.into_iter() .map(|x| mongodb::bson::from_document(x).unwrap()) @@ -255,6 +256,7 @@ pub trait Model: filter: mongodb::bson::Document, mut part: serde_json::Value, limit: Option, + sort: Option, ) -> impl std::future::Future>> { async move { let db = get_mongo!(); @@ -262,18 +264,13 @@ pub trait Model: part.as_object_mut()?.insert("_id".into(), 1.into()); - let mut results = collection - .find( - filter, - Some( - FindOptions::builder() - .projection(Some(mongodb::bson::to_document(&part).unwrap())) - .limit(limit) - .build(), - ), - ) - .await - .ok()?; + let options = FindOptions::builder() + .limit(limit) + .sort(sort) + .projection(Some(mongodb::bson::to_document(&part).unwrap())) + .build(); + + let mut results = collection.find(filter, Some(options)).await.ok()?; let docs = collect_results!(results); docs.into_iter() .map(|x| mongodb::bson::from_document(x).unwrap()) From 05e09295a5cb121d35e19a437daa51b147567872 Mon Sep 17 00:00:00 2001 From: JMARyA Date: Wed, 28 Aug 2024 08:45:44 +0200 Subject: [PATCH 02/10] add unique + sort --- src/model/mod.rs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/model/mod.rs b/src/model/mod.rs index 0ceff52..7279058 100644 --- a/src/model/mod.rs +++ b/src/model/mod.rs @@ -250,6 +250,21 @@ pub trait Model: } } + /// Get unique values of a Models field + fn unique( + filter: mongodb::bson::Document, + field: &str, + ) -> impl std::future::Future> { + async move { + let db = get_mongo!(); + let collection = col!(db, Self::collection_name()); + let res = collection.distinct(field, filter, None).await.unwrap(); + res.into_iter() + .filter_map(|x| mongodb::bson::from_bson(x).ok()) + .collect() + } + } + /// Get multiple partial `Model`s by using a filter from the database. Pass a `limit` parameter to limit the amount of `Model`s returned. #[must_use] fn find_partial( @@ -330,3 +345,20 @@ pub trait Model: update: &mut mongodb::bson::Document, ) -> impl std::future::Future + Send; } + +/// Sorting Order +/// +/// # Example +/// ```ignore +/// let m = MyModel::find(doc! {}, None, Some(doc! { +/// "sort_key": Sort::Ascending +/// })).await.unwrap(); +/// ``` +#[repr(i8)] +#[derive(serde::Serialize, serde::Deserialize, Debug)] +pub enum Sort { + /// Sort in ascending order + Ascending = 1, + /// Sort in descending order + Descending = -1, +} From 9b56a434e7fe32ba2157d0b9f725a43c74a3971a Mon Sep 17 00:00:00 2001 From: JMARyA Date: Wed, 28 Aug 2024 08:50:38 +0200 Subject: [PATCH 03/10] fix --- src/lib.rs | 2 ++ src/model/mod.rs | 16 ++++++++++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index b0f1ee2..bf940e7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,8 +3,10 @@ pub use model::historic::Historic; pub use model::reference::*; pub use model::valid::Validate; pub use model::Model; +pub use model::Sort; pub use mongod_derive as derive; pub use mongodb; + #[cfg(feature = "cache")] pub mod cache; #[cfg(feature = "cache")] diff --git a/src/model/mod.rs b/src/model/mod.rs index 7279058..e0b850e 100644 --- a/src/model/mod.rs +++ b/src/model/mod.rs @@ -354,11 +354,19 @@ pub trait Model: /// "sort_key": Sort::Ascending /// })).await.unwrap(); /// ``` -#[repr(i8)] -#[derive(serde::Serialize, serde::Deserialize, Debug)] +#[derive(Debug)] pub enum Sort { /// Sort in ascending order - Ascending = 1, + Ascending, /// Sort in descending order - Descending = -1, + Descending, +} + +impl Into for Sort { + fn into(self) -> mongodb::bson::Bson { + match self { + Sort::Ascending => mongodb::bson::bson!(1), + Sort::Descending => mongodb::bson::bson!(-1), + } + } } From 9784c3cac65e5a1305e4f0e4ec769316eacced3c Mon Sep 17 00:00:00 2001 From: JMARyA Date: Fri, 30 Aug 2024 11:53:10 +0200 Subject: [PATCH 04/10] add api --- src/lib.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index bf940e7..b3fdaec 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -97,3 +97,20 @@ macro_rules! id_of { $crate::mongodb::bson::doc! { "_id": $id} }; } + +/// A trait to generate a Model API representation in JSON format. +pub trait ToAPI: Sized { + /// Generate public API JSON + fn api(&self) -> impl std::future::Future; +} + +/// Converts a slice of items implementing the `ToAPI` trait into a `Vec` of JSON values. +pub async fn vec_to_api(items: &[impl ToAPI]) -> Vec { + let mut ret = Vec::with_capacity(items.len()); + + for e in items { + ret.push(e.api().await); + } + + ret +} From d830e677baddd79839d199b0c58091ff2ec41209 Mon Sep 17 00:00:00 2001 From: JMARyA Date: Wed, 11 Sep 2024 11:09:38 +0200 Subject: [PATCH 05/10] builder update --- README.md | 31 ++++ mongod_derive/src/change_fields.rs | 213 ++++++++++++++++++++++++++++ mongod_derive/src/lib.rs | 165 +++++++++------------ mongod_derive/src/partial_fields.rs | 30 ++++ mongod_derive/src/types.rs | 42 ++++++ mongod_derive/src/update_fields.rs | 55 +++++++ src/model/historic.rs | 9 +- src/model/mod.rs | 15 +- 8 files changed, 461 insertions(+), 99 deletions(-) create mode 100644 mongod_derive/src/change_fields.rs create mode 100644 mongod_derive/src/partial_fields.rs create mode 100644 mongod_derive/src/types.rs create mode 100644 mongod_derive/src/update_fields.rs diff --git a/README.md b/README.md index 1a8cbc2..d24565f 100644 --- a/README.md +++ b/README.md @@ -105,3 +105,34 @@ let ms = MyStruct::get_partial("someid", &serde_json::json!({"other": 1})).await let myref = ms.other.unwrap(); // will be there let name = ms.name.unwrap() // will panic! ``` + +### Updating values +You can either update the values by passing a JSON object overwriting the current values or update the values using a builder pattern. + +```rust +[...] +struct MyStruct { + _id: String, + name: String, + age: u32, + other: Option, +} + +let mut a = MyStruct::get("someid").await.unwrap(); + +// JSON +a.update(serde_json::json!({"name": "bye"})).await.unwrap(); + +// Builder +let mut changes = a.change(); + +// Set fields +changes = changes.name("bye"); + +// There are type specific functions +// Increment age by 1 +changes = changes.age_increment(1); + +// Finalize +let changed_model: MyStruct = changes.update().await.unwrap(); +``` diff --git a/mongod_derive/src/change_fields.rs b/mongod_derive/src/change_fields.rs new file mode 100644 index 0000000..96894c3 --- /dev/null +++ b/mongod_derive/src/change_fields.rs @@ -0,0 +1,213 @@ +use quote::quote; +use syn::Field; + +use crate::{extract_inner_type, is_one_of_type, is_type}; + +/// Generate the ChangeBuilder field fns +pub fn builder_change_fields(field: &Field) -> proc_macro2::TokenStream { + let field_name = &field.ident.as_ref().unwrap(); + let field_type = &field.ty; + let field_name_str = field_name.to_string(); + + // Never update _id + if field_name_str == "_id" { + return quote! {}; + } + + let number_types = [ + "u8", "u16", "u32", "u64", "u128", "usize", "i8", "i16", "i32", "i64", "i128", "isize", + "f16", "f32", "f64", "f128", + ]; + + // Number type fn + if is_one_of_type(field_type, &number_types) { + let documentation = format!("Set the value of `{field_name}`"); + let inc_fn_name = syn::Ident::new(&format!("{}_increment", field_name), field_name.span()); + let doc_inc = format!("Increment value of `{field_name}` by `value`. Consecutive calls to this function will not add up, they overwrite the increment."); + + let mul_fn_name = syn::Ident::new(&format!("{}_multiply", field_name), field_name.span()); + let doc_mul = format!("Multiply value of `{field_name}` by `value`. Consecutive calls to this function will not add up, they overwrite the multiply."); + + return quote! { + #[doc = #documentation] + pub fn #field_name(mut self, value: #field_type)-> Self { + self.model.#field_name = value.into(); + + self.changeset.entry("$set".to_string()).or_insert(mongod::mongodb::bson::doc! {}.into()).as_document_mut().unwrap().insert( + #field_name_str.to_string(), + mongod::mongodb::bson::to_bson(&self.model.#field_name).unwrap(), + ); + + self + } + + #[doc = #doc_inc] + pub fn #inc_fn_name(mut self, value: #field_type) -> Self { + self.model.#field_name += value; + + self.changeset.entry("$inc".to_string()).or_insert(mongod::mongodb::bson::doc! {}.into()).as_document_mut().unwrap() + .insert( + #field_name_str.to_string(), + mongod::mongodb::bson::to_bson(&value).unwrap(), + ); + + self + } + + #[doc = #doc_mul] + pub fn #mul_fn_name(mut self, value: #field_type) -> Self { + self.model.#field_name *= value; + + self.changeset.entry("$mul".to_string()).or_insert(mongod::mongodb::bson::doc! {}.into()).as_document_mut().unwrap() + .insert( + #field_name_str.to_string(), + mongod::mongodb::bson::to_bson(&value).unwrap(), + ); + + self + } + }; + } + + if is_type(field_type, "Vec") { + let inner_field_type = extract_inner_type(field_type, "Vec").unwrap(); + + let push_fn_name = syn::Ident::new(&format!("{}_push", field_name), field_name.span()); + + let documentation = format!("Add a value to the Vec `{field_name}`"); + let documentation2 = format!("Set the value of `{field_name}`"); + + return quote! { + #[doc = #documentation] + pub fn #push_fn_name(mut self, value: T) -> Self where T: Into<#inner_field_type> + serde::Serialize { + let mut push = self.changeset.entry("$push".to_string()).or_insert(mongod::mongodb::bson::doc! {}.into()).as_document_mut().unwrap(); + + if push.contains_key(#field_name_str) { + let current = push.get_mut(#field_name_str.to_string()).unwrap(); + + if current.as_document().map(|x| !x.contains_key("$each")).unwrap_or(true) { + let each = mongod::mongodb::bson::doc! { + "$each": [current, mongod::mongodb::bson::to_bson(&value).unwrap()] + }; + + push.insert(#field_name_str.to_string(), each); + } else { + current.as_document_mut().unwrap().get_mut("$each").unwrap().as_array_mut().unwrap().push(mongod::mongodb::bson::to_bson(&value).unwrap()); + } + } else { + push.insert(#field_name_str.to_string(), mongod::mongodb::bson::to_bson(&value).unwrap()); + } + + self.model.#field_name.push(value.into()); + + self + } + + #[doc = #documentation2] + pub fn #field_name(mut self, value: T)-> Self where T: Into<#field_type> + serde::Serialize { + self.model.#field_name = value.into(); + + self.changeset.entry("$set".to_string()).or_insert(mongod::mongodb::bson::doc! {}.into()).as_document_mut().unwrap().insert( + #field_name_str.to_string(), + mongod::mongodb::bson::to_bson(&self.model.#field_name).unwrap(), + ); + + self + } + }; + } + + if is_type(field_type, "Historic") { + let inner_field_type = extract_inner_type(field_type, "Historic").unwrap(); + + let documentation = format!( + "Update the value of `{field_name}`. This change will be recorded by the `Historic`" + ); + + // Code for Historic + return quote! { + #[doc = #documentation] + pub fn #field_name(mut self, value: T) -> Self where T: Into<#inner_field_type> + serde::Serialize { + self.model.#field_name.update(value.into()); + + self.changeset.entry("$set".to_string()).or_insert(mongod::mongodb::bson::doc! {}.into()).as_document_mut().unwrap().insert( + #field_name_str.to_string(), + mongod::mongodb::bson::to_bson(&self.model.#field_name).unwrap(), + ); + + + self + } + }; + } + + if is_type(field_type, "Option") { + let inner_field_type = extract_inner_type(field_type, "Option").unwrap(); + + if is_type(inner_field_type, "Historic") { + let inner_field_type = extract_inner_type(inner_field_type, "Historic").unwrap(); + + let documentation = format!("Update the value of `{field_name}`. This change will be recorded by the `Historic`. If `{field_name}` is `None` a new `Historic` will be initialized."); + + // Code for Option> + return quote! { + #[doc = #documentation] + pub fn #field_name(mut self, value: T) -> Self where T: Into<#inner_field_type> + serde::Serialize { + if let Some(mut opt) = self.model.#field_name.as_mut() { + opt.update(value.into()); + } else { + self.model.#field_name = Some(mongod::Historic::new(value.into())); + } + + self.changeset.entry("$set".to_string()).or_insert(mongod::mongodb::bson::doc! {}.into()).as_document_mut().unwrap().insert( + #field_name_str.to_string(), + mongod::mongodb::bson::to_bson(&self.model.#field_name).unwrap(), + ); + + self + } + }; + } + + let documentation = format!("Set the value of `{field_name}`. If `Some(_)` it will be updated or removed if it is `None`"); + + return quote! { + #[doc = #documentation] + pub fn #field_name(mut self, value: Option<#inner_field_type>) -> Self { + let is_some = value.is_some(); + + self.model.#field_name = value.into(); + + if is_some { + self.changeset.entry("$set".to_string()).or_insert(mongod::mongodb::bson::doc! {}.into()).as_document_mut().unwrap().insert( + #field_name_str.to_string(), + mongod::mongodb::bson::to_bson(&self.model.#field_name).unwrap(), + ); + } else { + self.changeset.entry("$unset".to_string()).or_insert(mongod::mongodb::bson::doc! {}.into()).as_document_mut().unwrap().insert( + #field_name_str.to_string(), + mongod::mongodb::bson::to_bson("").unwrap(), + ); + } + + self + } + }; + } + + let documentation = format!("Set the value of `{field_name}`"); + // Code for T + quote! { + #[doc = #documentation] + pub fn #field_name(mut self, value: T)-> Self where T: Into<#field_type> + serde::Serialize { + self.model.#field_name = value.into(); + + self.changeset.entry("$set".to_string()).or_insert(mongod::mongodb::bson::doc! {}.into()).as_document_mut().unwrap().insert( + #field_name_str.to_string(), + mongod::mongodb::bson::to_bson(&self.model.#field_name).unwrap(), + ); + + self + } + } +} diff --git a/mongod_derive/src/lib.rs b/mongod_derive/src/lib.rs index 7264223..8cae41d 100644 --- a/mongod_derive/src/lib.rs +++ b/mongod_derive/src/lib.rs @@ -3,40 +3,18 @@ use case::CaseExt; use proc_macro::TokenStream; use quote::quote; -use syn::{parse_macro_input, Data, DeriveInput, Fields, Type, TypePath}; +use syn::{parse_macro_input, Data, DeriveInput, Fields}; -/// Get inner type. Example: Returns `T` for `Option`. -fn extract_inner_type<'a>(ty: &'a Type, parent: &'a str) -> Option<&'a Type> { - if let Type::Path(type_path) = ty { - if type_path.path.segments.len() == 1 { - let segment = &type_path.path.segments[0]; - if segment.ident == parent { - if let syn::PathArguments::AngleBracketed(ref args) = segment.arguments { - if args.args.len() == 1 { - if let syn::GenericArgument::Type(ref inner_type) = args.args[0] { - return Some(inner_type); - } - } - } - } - } - } - None -} - -fn type_path(ty: &syn::Type) -> TypePath { - if let syn::Type::Path(type_path) = ty { - return type_path.clone(); - } - unreachable!(); -} - -fn is_type(ty: &syn::Type, t: &str) -> bool { - let type_path = type_path(ty); - let id = type_path.path.segments.first().unwrap().ident.to_string(); - id == t -} +mod types; +use types::*; +mod partial_fields; +use partial_fields::partial_code_field; +mod update_fields; +use update_fields::update_code_field; +mod change_fields; +use change_fields::builder_change_fields; +/// #[derive(Model)] #[proc_macro_derive(Model)] pub fn model_derive(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); @@ -44,84 +22,37 @@ pub fn model_derive(input: TokenStream) -> TokenStream { let name = input.ident; let name_str = name.to_string().to_snake(); let partial_name = syn::Ident::new(&format!("Partial{}", name), name.span()); + let changebuilder_name = syn::Ident::new(&format!("Change{}", name), name.span()); + + let update_doc = "Commit the builder changes to DB"; // Generate code for each field let field_code = if let Data::Struct(data_struct) = input.data { match data_struct.fields { Fields::Named(fields_named) => { - let field_process_code: Vec<_> = fields_named.named.iter().map(|field| { - let field_name = &field.ident.as_ref().unwrap(); - let field_type = &field.ty; - let field_name_str = field_name.to_string(); + // Update code + let field_process_code: Vec<_> = + fields_named.named.iter().map(update_code_field).collect(); - if field_name_str == "_id" { - return quote! {}; - } + // Partial struct fields + let partial_struct: Vec<_> = + fields_named.named.iter().map(partial_code_field).collect(); - if is_type(field_type, "Historic") { - let inner_field_type = extract_inner_type(field_type, "Historic").unwrap(); - if is_type(inner_field_type, "Vec") { - return quote! { - mongod::update_historic_vec!(self, obj, #field_name_str, #field_name, update); - }; - } - - return quote! { - mongod::update_historic_str!(self, obj, #field_name_str, #field_name, update); - } - } - - if is_type(field_type, "Option") { - let inner_field_type = extract_inner_type(field_type, "Option").unwrap(); - - if is_type(inner_field_type, "Historic") { - let sub_inner_field_type = extract_inner_type(inner_field_type, "Historic").unwrap(); - if is_type(sub_inner_field_type, "Reference") { - return quote! { - mongod::update_historic_ref_option!(self, obj, #field_name_str, #field_name, update); - }; - } - } - - return quote! { - mongod::update_value_option!(self, obj, #field_name_str, #field_name, update, #inner_field_type); - }; - } - - quote! { - mongod::update_value!(self, obj, #field_name_str, #field_name, update, #field_type); - } - }).collect(); - - let partial_struct: Vec<_> = fields_named + // Builder functions + let builder_change_fields: Vec<_> = fields_named .named .iter() - .map(|field| { - let field_name = &field.ident.as_ref().unwrap(); - let field_type = &field.ty; - let field_name_str = field_name.to_string(); - - if field_name_str == "_id" { - return quote! { - pub _id: String, - }; - } - - if is_type(field_type, "Option") { - return quote! { - pub #field_name: #field_type, - }; - } - - quote! { - pub #field_name: Option<#field_type>, - } - }) + .map(builder_change_fields) .collect(); quote! { impl mongod::model::Model for #name { type Partial = #partial_name; + type ChangeBuilder = #changebuilder_name; + + fn change_builder(self) -> Self::ChangeBuilder { + #changebuilder_name::new(self) + } async fn update_values( &mut self, @@ -137,6 +68,47 @@ pub fn model_derive(input: TokenStream) -> TokenStream { #( #partial_struct )* } + #[derive(Debug)] + pub struct #changebuilder_name { + model: #name, + changeset: mongod::mongodb::bson::Document + } + + impl #changebuilder_name { + pub fn new(model: #name) -> Self { + Self { + model, + changeset: mongod::mongodb::bson::doc! {} + } + } + + #[doc = #update_doc] + pub async fn update(self) -> Result<#name, mongod::model::UpdateError> { + let db = mongod::get_mongo!(); + let collection = mongod::col!(db, <#name as mongod::Referencable>::collection_name()); + + if let Err(msg) = mongod::Validate::validate(&self.model).await { + return Err(mongod::model::UpdateError::Validation(msg)); + } + + let changeset = self.changeset; + + collection + .update_one( + mongod::id_of!(mongod::Referencable::id(&self.model)), + changeset, + None, + ) + .await + .map_err(mongod::model::UpdateError::Database)?; + + Ok(self.model) + } + + #( #builder_change_fields )* + + } + impl mongod::model::reference::Referencable for #partial_name { fn collection_name() -> &'static str { #name_str @@ -157,6 +129,7 @@ pub fn model_derive(input: TokenStream) -> TokenStream { TokenStream::from(field_code) } +/// #[derive(Referencable)] #[proc_macro_derive(Referencable)] pub fn referencable_derive(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); diff --git a/mongod_derive/src/partial_fields.rs b/mongod_derive/src/partial_fields.rs new file mode 100644 index 0000000..5234cb0 --- /dev/null +++ b/mongod_derive/src/partial_fields.rs @@ -0,0 +1,30 @@ +use quote::quote; +use syn::Field; + +use crate::is_type; + +/// Generate struct fields for Partial Model +pub fn partial_code_field(field: &Field) -> proc_macro2::TokenStream { + let field_name = &field.ident.as_ref().unwrap(); + let field_type = &field.ty; + let field_name_str = field_name.to_string(); + + // Keep _id + if field_name_str == "_id" { + return quote! { + pub _id: String, + }; + } + + // Leave Option alone + if is_type(field_type, "Option") { + return quote! { + pub #field_name: #field_type, + }; + } + + // Turn every field into Option + quote! { + pub #field_name: Option<#field_type>, + } +} diff --git a/mongod_derive/src/types.rs b/mongod_derive/src/types.rs new file mode 100644 index 0000000..f4bc087 --- /dev/null +++ b/mongod_derive/src/types.rs @@ -0,0 +1,42 @@ +use syn::{Type, TypePath}; + +/// Get inner type. Example: Returns `T` for `Option`. +pub fn extract_inner_type<'a>(ty: &'a Type, parent: &'a str) -> Option<&'a Type> { + if let Type::Path(type_path) = ty { + if type_path.path.segments.len() == 1 { + let segment = &type_path.path.segments[0]; + if segment.ident == parent { + if let syn::PathArguments::AngleBracketed(ref args) = segment.arguments { + if args.args.len() == 1 { + if let syn::GenericArgument::Type(ref inner_type) = args.args[0] { + return Some(inner_type); + } + } + } + } + } + } + None +} + +pub fn type_path(ty: &syn::Type) -> TypePath { + if let syn::Type::Path(type_path) = ty { + return type_path.clone(); + } + unreachable!(); +} + +pub fn is_one_of_type(ty: &syn::Type, t: &[&str]) -> bool { + for typ in t { + if is_type(ty, typ) { + return true; + } + } + false +} + +pub fn is_type(ty: &syn::Type, t: &str) -> bool { + let type_path = type_path(ty); + let id = type_path.path.segments.first().unwrap().ident.to_string(); + id == t +} diff --git a/mongod_derive/src/update_fields.rs b/mongod_derive/src/update_fields.rs new file mode 100644 index 0000000..f7bb9bd --- /dev/null +++ b/mongod_derive/src/update_fields.rs @@ -0,0 +1,55 @@ +use quote::quote; +use syn::Field; + +use crate::{extract_inner_type, is_type}; + +/// Generate code for the update fn of models +pub fn update_code_field(field: &Field) -> proc_macro2::TokenStream { + let field_name = &field.ident.as_ref().unwrap(); + let field_type = &field.ty; + let field_name_str = field_name.to_string(); + + // Never update _id + if field_name_str == "_id" { + return quote! {}; + } + + if is_type(field_type, "Historic") { + let inner_field_type = extract_inner_type(field_type, "Historic").unwrap(); + if is_type(inner_field_type, "Vec") { + // Custom code Historic> + return quote! { + mongod::update_historic_vec!(self, obj, #field_name_str, #field_name, update); + }; + } + + // Code for Historic + return quote! { + mongod::update_historic_str!(self, obj, #field_name_str, #field_name, update); + }; + } + + if is_type(field_type, "Option") { + let inner_field_type = extract_inner_type(field_type, "Option").unwrap(); + + if is_type(inner_field_type, "Historic") { + let sub_inner_field_type = extract_inner_type(inner_field_type, "Historic").unwrap(); + if is_type(sub_inner_field_type, "Reference") { + // Code for Option> + return quote! { + mongod::update_historic_ref_option!(self, obj, #field_name_str, #field_name, update); + }; + } + } + + // Code for Option + return quote! { + mongod::update_value_option!(self, obj, #field_name_str, #field_name, update, #inner_field_type); + }; + } + + // Code for T + quote! { + mongod::update_value!(self, obj, #field_name_str, #field_name, update, #field_type); + } +} diff --git a/src/model/historic.rs b/src/model/historic.rs index 85d8286..b9f5cc6 100644 --- a/src/model/historic.rs +++ b/src/model/historic.rs @@ -3,7 +3,7 @@ use std::{collections::HashMap, ops::Deref}; /// A struct to keep track of historical changes to a value. /// This struct represents a value that has a current state and a history of previous states. -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] pub struct Historic { /// The current value pub current: T, @@ -24,6 +24,13 @@ impl Historic { } } +impl Historic { + /// Create a new tracked value initialized with Default + pub fn new_default() -> Historic { + Self::new(T::default()) + } +} + impl Historic { /// Update the value. The change will be recorded. /// Will record a change even if the value is the same as the current one. diff --git a/src/model/mod.rs b/src/model/mod.rs index e0b850e..34896eb 100644 --- a/src/model/mod.rs +++ b/src/model/mod.rs @@ -18,8 +18,6 @@ pub mod reference; pub mod update; pub mod valid; -// todo : use mongodb projection to only get fields you actually use, maybe PartialModel shadow struct? - /// Error type when updating a model #[derive(Debug)] pub enum UpdateError { @@ -35,6 +33,7 @@ pub trait Model: Sized + Referencable + Validate + serde::Serialize + for<'a> serde::Deserialize<'a> { type Partial: DeserializeOwned; + type ChangeBuilder; /// Insert the `Model` into the database fn insert( @@ -293,6 +292,18 @@ pub trait Model: } } + fn change_builder(self) -> Self::ChangeBuilder; + + /// Update values of `Model` using a builder pattern + fn change(self) -> Self::ChangeBuilder { + #[cfg(feature = "cache")] + { + mongod::cache_write!().invalidate(Self::collection_name(), self.id()); + } + + self.change_builder() + } + /// Update values of `Model` into database fn update( &mut self, From 1e9efe4c12e600fd91400adb06f98c84caf11fef Mon Sep 17 00:00:00 2001 From: JMARyA Date: Wed, 11 Sep 2024 11:18:31 +0200 Subject: [PATCH 06/10] fix --- src/model/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/model/mod.rs b/src/model/mod.rs index 34896eb..57b8079 100644 --- a/src/model/mod.rs +++ b/src/model/mod.rs @@ -298,7 +298,7 @@ pub trait Model: fn change(self) -> Self::ChangeBuilder { #[cfg(feature = "cache")] { - mongod::cache_write!().invalidate(Self::collection_name(), self.id()); + cache_write!().invalidate(Self::collection_name(), self.id()); } self.change_builder() From f24e3f1e3cfff7e821faf4d1b76c409d8c647961 Mon Sep 17 00:00:00 2001 From: JMARyA Date: Wed, 11 Sep 2024 11:29:20 +0200 Subject: [PATCH 07/10] fix --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d24565f..b2dad84 100644 --- a/README.md +++ b/README.md @@ -11,9 +11,9 @@ You can derive the `Model` and `Referencable` traits for your struct. This will use serde::{Deserialize, Serialize}; use mongod::Validate; use mongod::Reference; -use mongod::derive::{Module, Referencable}; +use mongod::derive::{Model, Referencable}; -#[derive(Debug, Clone, Serialize, Deserialize, Module, Referencable)] +#[derive(Debug, Clone, Serialize, Deserialize, Model, Referencable)] struct MyStruct { _id: String, name: String, From 949340a7f28810768e408f4039dc1f1dc9cc1a82 Mon Sep 17 00:00:00 2001 From: JMARyA Date: Wed, 11 Sep 2024 16:08:58 +0200 Subject: [PATCH 08/10] fix --- Cargo.lock | 185 +++++++++++++++++++++++++++++------------------------ src/lib.rs | 2 +- 2 files changed, 104 insertions(+), 83 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 462ee37..8f0a366 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,18 +4,18 @@ version = 3 [[package]] name = "addr2line" -version = "0.22.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375" dependencies = [ "gimli", ] [[package]] -name = "adler" -version = "1.0.2" +name = "adler2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" [[package]] name = "ahash" @@ -56,13 +56,13 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.81" +version = "0.1.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" +checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.77", ] [[package]] @@ -73,17 +73,17 @@ checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "backtrace" -version = "0.3.73" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", "miniz_oxide", "object", "rustc-demangle", + "windows-targets 0.52.6", ] [[package]] @@ -159,10 +159,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] -name = "bytes" -version = "1.6.1" +name = "byteorder" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a12916984aab3fa6e39d655a33e09c0071eb36d6ab3aea5c2d78551f1df6d952" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" [[package]] name = "case" @@ -172,9 +178,12 @@ checksum = "fd6c0e7b807d60291f42f33f58480c0bfafe28ed08286446f45e463728cf9c1c" [[package]] name = "cc" -version = "1.1.6" +version = "1.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aba8f4e9906c7ce3c73463f62a7f0c65183ada1a2d47e397cc8810827f9694f" +checksum = "b62ac837cdb5cb22e10a256099b4fc502b1dfe560cb282963a974d7abd80e476" +dependencies = [ + "shlex", +] [[package]] name = "cfg-if" @@ -204,15 +213,15 @@ checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.12" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" dependencies = [ "libc", ] @@ -297,8 +306,8 @@ dependencies = [ "convert_case", "proc-macro2", "quote", - "rustc_version 0.4.0", - "syn 2.0.72", + "rustc_version 0.4.1", + "syn 2.0.77", ] [[package]] @@ -407,7 +416,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.77", ] [[package]] @@ -463,9 +472,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.29.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" +checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" [[package]] name = "hashbrown" @@ -563,9 +572,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.6" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" dependencies = [ "equivalent", "hashbrown", @@ -585,9 +594,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.9.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +checksum = "187674a687eed5fe42285b40c6291f9a01517d415fad1c3cbc6a9f778af7fcd4" [[package]] name = "itoa" @@ -597,9 +606,9 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "js-sys" -version = "0.3.69" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" dependencies = [ "wasm-bindgen", ] @@ -612,9 +621,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.155" +version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" [[package]] name = "linked-hash-map" @@ -677,18 +686,18 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "miniz_oxide" -version = "0.7.4" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" dependencies = [ - "adler", + "adler2", ] [[package]] name = "mio" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ "hermit-abi", "libc", @@ -785,9 +794,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.2" +version = "0.36.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f203fa8daa7bb185f760ae12bd8e097f63d17041dcdcaf675ac54cdf863170e" +checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" dependencies = [ "memchr", ] @@ -856,9 +865,12 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] [[package]] name = "proc-macro2" @@ -877,9 +889,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.36" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -931,9 +943,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.5" +version = "1.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick", "memchr", @@ -1000,9 +1012,9 @@ dependencies = [ [[package]] name = "rustc_version" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ "semver 1.0.23", ] @@ -1093,9 +1105,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.204" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] @@ -1111,23 +1123,24 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.204" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.77", ] [[package]] name = "serde_json" -version = "1.0.120" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" dependencies = [ "indexmap", "itoa", + "memchr", "ryu", "serde", ] @@ -1176,6 +1189,12 @@ dependencies = [ "digest", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signal-hook-registry" version = "1.4.2" @@ -1262,9 +1281,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.72" +version = "2.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" dependencies = [ "proc-macro2", "quote", @@ -1300,7 +1319,7 @@ checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.77", ] [[package]] @@ -1351,9 +1370,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.39.1" +version = "1.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d040ac2b29ab03b09d4129c2f5bbd012a3ac2f79d38ff506a4bf8dd34b0eac8a" +checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" dependencies = [ "backtrace", "bytes", @@ -1374,7 +1393,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.77", ] [[package]] @@ -1389,9 +1408,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.11" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" dependencies = [ "bytes", "futures-core", @@ -1471,9 +1490,9 @@ checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unicode-normalization" @@ -1486,9 +1505,9 @@ dependencies = [ [[package]] name = "unicode-properties" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4259d9d4425d9f0661581b804cb85fe66a4c631cadd8f490d1c13a35d5d9291" +checksum = "52ea75f83c0137a9b98608359a5f1af8144876eb67bcb1ce837368e906a9f524" [[package]] name = "untrusted" @@ -1519,9 +1538,9 @@ dependencies = [ [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "wasi" @@ -1531,34 +1550,35 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" dependencies = [ "cfg-if", + "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.77", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1566,22 +1586,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.77", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" [[package]] name = "webpki-roots" @@ -1790,6 +1810,7 @@ version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ + "byteorder", "zerocopy-derive", ] @@ -1801,5 +1822,5 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.77", ] diff --git a/src/lib.rs b/src/lib.rs index b3fdaec..a278970 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -57,7 +57,7 @@ macro_rules! get_mongo { if let Some(client) = $crate::MONGO_CLIENT.get() { client } else { - let client = mongodb::Client::with_uri_str(&std::env::var("DB_URI").unwrap()) + let client = $crate::mongodb::Client::with_uri_str(&std::env::var("DB_URI").unwrap()) .await .unwrap(); $crate::MONGO_CLIENT.set(client).unwrap(); From b0bae64efcfdc833c3b9e8508bf228c9299c1d21 Mon Sep 17 00:00:00 2001 From: JMARyA Date: Fri, 13 Sep 2024 14:00:28 +0200 Subject: [PATCH 09/10] update --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/model/reference.rs | 16 ++++++++-------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8f0a366..412d6cd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -707,7 +707,7 @@ dependencies = [ [[package]] name = "mongod" -version = "0.2.1" +version = "0.2.2" dependencies = [ "chrono", "futures", diff --git a/Cargo.toml b/Cargo.toml index 119bf72..06ccfea 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mongod" -version = "0.2.1" +version = "0.2.2" edition = "2021" [features] diff --git a/src/model/reference.rs b/src/model/reference.rs index f6e963e..e196942 100644 --- a/src/model/reference.rs +++ b/src/model/reference.rs @@ -10,9 +10,14 @@ use super::{valid::Validate, Model}; pub struct Reference(String); impl Reference { - /// Create a new reference from String - pub async fn new_raw(reference: &str) -> Option { - let r = Self(reference.to_string()); + /// Create a new reference from String without checks + pub fn new_raw(reference: &str) -> Self { + Self(reference.to_string()) + } + + /// Create a new reference + pub async fn new(model: &str, id: &str) -> Option { + let r = Self(format!("{model}::{id}")); if r.validate().await.is_ok() { Some(r) } else { @@ -20,11 +25,6 @@ impl Reference { } } - /// Create a new reference - pub async fn new(model: &str, id: &str) -> Option { - Self::new_raw(&format!("{model}::{id}")).await - } - /// Get just the ID of the referenced `Model` pub fn id(&self) -> &str { self.0.split_once("::").unwrap().1 From 58150002e60802d7b00fe0537e4a2e8c4e389a4a Mon Sep 17 00:00:00 2001 From: JMARyA Date: Fri, 13 Sep 2024 22:10:11 +0200 Subject: [PATCH 10/10] fix --- src/model/reference.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/model/reference.rs b/src/model/reference.rs index e196942..be33b3a 100644 --- a/src/model/reference.rs +++ b/src/model/reference.rs @@ -130,11 +130,11 @@ macro_rules! reference_of { ($model:ident, $id:ident) => {{ $model::get_partial($id, serde_json::json!({})) .await - .map(|x| x.reference()) + .map(|x| mongod::Referencable::reference(&x)) }}; ($model:ident, $id:literal) => {{ $model::get_partial($id, serde_json::json!({})) .await - .map(|x| x.reference()) + .map(|x| mongod::Referencable::reference(&x)) }}; }