Parcourir la source

Add Value derive macro.

Kestrel il y a 1 mois
Parent
commit
f9cddd32b6
3 fichiers modifiés avec 41 ajouts et 1 suppressions
  1. 7 0
      microrm-macros/src/lib.rs
  2. 26 0
      microrm-macros/src/value.rs
  3. 8 1
      microrm/src/schema/datum.rs

+ 7 - 0
microrm-macros/src/lib.rs

@@ -5,6 +5,7 @@ use proc_macro::TokenStream;
 mod database;
 mod entity;
 mod index;
+mod value;
 
 /// `Entity` trait derivation procedural macro.
 ///
@@ -83,3 +84,9 @@ pub fn derive_database(tokens: TokenStream) -> TokenStream {
 pub fn index_cols(tokens: TokenStream) -> TokenStream {
     index::index_cols(tokens)
 }
+
+/// Value specification
+#[proc_macro_derive(Value)]
+pub fn value(tokens: TokenStream) -> TokenStream {
+    value::derive(tokens)
+}

+ 26 - 0
microrm-macros/src/value.rs

@@ -0,0 +1,26 @@
+use quote::quote;
+
+pub fn derive(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {
+    let input: syn::DeriveInput = syn::parse_macro_input!(tokens);
+
+    let ident = input.ident;
+
+    quote!{
+        impl ::microrm::schema::datum::DatumProxy for #ident {}
+        impl ::microrm::schema::datum::ConcreteDatum for #ident {}
+        impl ::microrm::schema::datum::Datum for #ident {
+            fn sql_type() -> &'static str {
+                <::microrm::Serialized< #ident > as ::microrm::schema::datum::Datum>::sql_type()
+            }
+            fn bind_to(&self, stmt: &mut ::microrm::db::StatementContext, index: i32) {
+                self.clone().into_serialized().bind_to(stmt, index)
+            }
+            fn build_from(rdata: ::microrm::schema::relation::RelationData, stmt: &mut ::microrm::db::StatementRow, index: &mut i32) -> ::microrm::DBResult<Self>
+            where
+                Self: Sized,
+            {
+                <::microrm::Serialized< #ident > as ::microrm::schema::datum::Datum>::build_from(rdata, stmt, index).map(::microrm::Serialized::wrapped)
+            }
+        }
+    }.into()
+}

+ 8 - 1
microrm/src/schema/datum.rs

@@ -2,6 +2,7 @@ use crate::{
     db::{StatementContext, StatementRow},
     schema::entity::{Entity, EntityVisitor},
     schema::relation::{Relation, RelationData, RelationDomain, RelationMap, RelationRange},
+    schema::{Serializable, Serialized},
     DBResult,
 };
 
@@ -137,12 +138,18 @@ pub trait DatumVisitor {
 /// Note that this is abstracted across [`ConcreteDatum`] and not [`Datum`]; this is to avoid
 /// issues with [`StringQuery`] -- which is not concrete -- having two implementations of
 /// `QueryEquivalent<StringQuery>`: one from the reflexive implementation and one from (2) above.
-pub trait QueryEquivalent<T: ConcreteDatum>: Datum {}
+pub trait QueryEquivalent<T>: Datum {}
 
 // Every type is query-equivalent to itself.
 impl<T: ConcreteDatum> QueryEquivalent<T> for T {}
 // Every reference type is query-equivalent to the non-referenced type.
 impl<'l, T: ConcreteDatum> QueryEquivalent<T> for &'l T {}
+// Any type is query-equivalent to the serialized type.
+impl<T: 'static + DatumProxy + Datum + Serializable> QueryEquivalent<Serialized<T>> for T {}
+
+/// Used as a marker trait for types that on their own, are not [`Datum`]s, but can be turned into
+/// one in a query-equivalent fashion.
+pub trait DatumProxy: Serializable {}
 
 /// Used if you wish to use sqlite's built-in string equivalence for a query.
 #[derive(Clone, Debug)]