entity.rs 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. use convert_case::{Case, Casing};
  2. use quote::{format_ident, quote};
  3. pub fn derive(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {
  4. let input: syn::DeriveInput = syn::parse_macro_input!(tokens);
  5. let parts = if let syn::Data::Struct(syn::DataStruct {
  6. struct_token: _,
  7. fields: syn::Fields::Named(fields),
  8. semi_token: _,
  9. }) = input.data
  10. {
  11. fields
  12. .named
  13. .into_iter()
  14. .map(|f| (f.ident.unwrap(), f.ty, f.attrs))
  15. .collect::<Vec<_>>()
  16. } else {
  17. panic!("Can only derive Entity on data structs with named fields!");
  18. };
  19. let entity_ident = input.ident;
  20. let make_combined_name = |part: &(syn::Ident, syn::Type, _)| {
  21. format_ident!(
  22. "{}{}PartType",
  23. entity_ident,
  24. part.0.to_string().to_case(Case::UpperCamel)
  25. )
  26. };
  27. let make_part_list = |plist: &Vec<_>| match plist.len() {
  28. 0 => quote! { () },
  29. 1 => {
  30. let ty = make_combined_name(&plist.first().as_ref().unwrap());
  31. quote! { #ty }
  32. }
  33. _ => {
  34. let tys = plist.iter().map(|part| make_combined_name(&part));
  35. quote! { ( #(#tys),* ) }
  36. }
  37. };
  38. let vis = input.vis;
  39. let unique_ident = format_ident!("unique");
  40. // collect list of unique parts
  41. let unique_parts = parts
  42. .iter()
  43. .filter(|part| {
  44. part.2.iter().any(|attr| {
  45. attr.parse_meta()
  46. .map(|a| a.path().is_ident(&unique_ident))
  47. .unwrap_or(false)
  48. })
  49. })
  50. .cloned()
  51. .collect::<Vec<_>>();
  52. let part_defs = parts.iter().map(|part| {
  53. let part_combined_name = make_combined_name(&part);
  54. let part_base_name = &part.0.to_string();
  55. let part_type = &part.1;
  56. let unique = unique_parts.iter().any(|p| p.0 == part.0);
  57. quote! {
  58. #vis struct #part_combined_name;
  59. impl ::microrm::entity::EntityPart for #part_combined_name {
  60. type Datum = #part_type;
  61. type Entity = #entity_ident;
  62. fn part_name() -> &'static str {
  63. #part_base_name
  64. }
  65. fn unique() -> bool {
  66. #unique
  67. }
  68. }
  69. }
  70. });
  71. let part_visit = parts.iter().map(|part| {
  72. let part_combined_name = make_combined_name(&part);
  73. quote! {
  74. v.visit::<#part_combined_name>();
  75. }
  76. });
  77. let part_ref_visit = parts.iter().map(|part| {
  78. let part_combined_name = make_combined_name(&part);
  79. let field = &part.0;
  80. quote! {
  81. v.visit_datum::<#part_combined_name>(&self.#field);
  82. }
  83. });
  84. let part_names = parts.iter().map(|part| {
  85. let part_combined_name = make_combined_name(&part);
  86. let part_camel_name = format_ident!("{}", part.0.to_string().to_case(Case::UpperCamel));
  87. quote! {
  88. pub const #part_camel_name : #part_combined_name = #part_combined_name;
  89. }
  90. });
  91. let build_struct = parts
  92. .iter()
  93. .enumerate()
  94. .map(|(i, part)| {
  95. let ident = &part.0;
  96. match parts.len() {
  97. 1 => {
  98. quote! {
  99. #ident: values
  100. }
  101. }
  102. _ => {
  103. let idx = syn::Index::from(i);
  104. quote! {
  105. #ident: values. #idx
  106. }
  107. }
  108. }
  109. })
  110. .collect::<Vec<_>>();
  111. let parts_list = make_part_list(&parts);
  112. let uniques_list = make_part_list(&unique_parts);
  113. let entity_name = entity_ident.to_string().to_case(Case::Snake);
  114. let id_ident = format_ident!("{}ID", entity_ident);
  115. quote! {
  116. #(#part_defs)*
  117. impl #entity_ident {
  118. #(#part_names)*
  119. }
  120. #[derive(Clone, Copy, PartialEq, PartialOrd, Debug, Hash)]
  121. #vis struct #id_ident (i64);
  122. impl ::microrm::entity::EntityID for #id_ident {
  123. type Entity = #entity_ident;
  124. fn from_raw(raw: i64) -> Self { Self(raw) }
  125. fn into_raw(self) -> i64 { self.0 }
  126. }
  127. impl ::microrm::datum::Datum for #id_ident {
  128. fn sql_type() -> &'static str {
  129. <i64 as ::microrm::datum::Datum>::sql_type()
  130. }
  131. fn bind_to<'a>(&self, stmt: &mut ::microrm::sqlite::Statement<'a>, index: usize) {
  132. <i64 as ::microrm::datum::Datum>::bind_to(&self.0, stmt, index)
  133. }
  134. fn build_from<'a>(
  135. adata: ::microrm::schema::AssocData,
  136. stmt: &mut ::microrm::sqlite::Statement<'a>,
  137. index: usize,
  138. ) -> ::microrm::DBResult<(Self, usize)>
  139. where
  140. Self: Sized,
  141. {
  142. let raw = <i64 as ::microrm::datum::Datum>::build_from(adata, stmt, index)?;
  143. Ok((Self(raw.0), raw.1))
  144. }
  145. fn accept_discriminator(d: &mut impl ::microrm::schema::DatumDiscriminator) where Self: Sized {
  146. d.visit_entity_id::<#entity_ident>();
  147. }
  148. }
  149. impl ::microrm::entity::Entity for #entity_ident {
  150. type Parts = #parts_list;
  151. type Uniques = #uniques_list;
  152. type ID = #id_ident;
  153. fn build(values: <Self::Parts as ::microrm::entity::EntityPartList>::DatumList) -> Self {
  154. Self {
  155. #(#build_struct),*
  156. }
  157. }
  158. fn entity_name() -> &'static str { #entity_name }
  159. fn accept_part_visitor(v: &mut impl ::microrm::entity::EntityPartVisitor) {
  160. #(
  161. #part_visit
  162. );*
  163. }
  164. fn accept_part_visitor_ref(&self, v: &mut impl ::microrm::entity::EntityPartVisitor) {
  165. #(
  166. #part_ref_visit
  167. );*
  168. }
  169. }
  170. }
  171. .into()
  172. }