|
@@ -0,0 +1,94 @@
|
|
|
+use serde::de::Visitor;
|
|
|
+
|
|
|
+#[derive(Debug)]
|
|
|
+pub struct CreateDeserializer<'de> {
|
|
|
+ table_name: Option<&'static str>,
|
|
|
+ column_names: Option<&'static [&'static str]>,
|
|
|
+ column_types: Vec<String>,
|
|
|
+ _de: std::marker::PhantomData<&'de u8>
|
|
|
+}
|
|
|
+
|
|
|
+impl<'de, 'a> serde::de::Deserializer<'de> for &'a mut CreateDeserializer<'de> {
|
|
|
+ type Error = super::ModelError;
|
|
|
+
|
|
|
+ // we (ab)use the forward_to_deserialize_any! macro to stub out the types we don't care about
|
|
|
+ serde::forward_to_deserialize_any! {
|
|
|
+ bool i8 i16 i128 u8 u16 u32 u64 u128 f32 f64 char str
|
|
|
+ bytes byte_buf option unit unit_struct newtype_struct seq tuple
|
|
|
+ tuple_struct map enum identifier ignored_any
|
|
|
+ }
|
|
|
+
|
|
|
+ fn deserialize_any<V: Visitor<'de>>(self, _v: V) -> Result<V::Value, Self::Error> {
|
|
|
+ todo!()
|
|
|
+ }
|
|
|
+
|
|
|
+ fn deserialize_i32<V: Visitor<'de>>(mut self, v: V) -> Result<V::Value, Self::Error> {
|
|
|
+ self.column_types.push("integer".to_owned());
|
|
|
+ v.visit_i32(0)
|
|
|
+ }
|
|
|
+
|
|
|
+ fn deserialize_i64<V: Visitor<'de>>(mut self, v: V) -> Result<V::Value, Self::Error> {
|
|
|
+ self.column_types.push("integer".to_owned());
|
|
|
+ v.visit_i64(0)
|
|
|
+ }
|
|
|
+
|
|
|
+ fn deserialize_string<V: Visitor<'de>>(mut self, v: V) -> Result<V::Value, Self::Error> {
|
|
|
+ self.column_types.push("varchar".to_owned());
|
|
|
+ v.visit_string("".to_owned())
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ fn deserialize_struct<V: Visitor<'de>>(self, name: &'static str, fields: &'static [&'static str], v: V) -> Result<V::Value, Self::Error> {
|
|
|
+ self.table_name = Some(name);
|
|
|
+ self.column_names = Some(fields);
|
|
|
+ v.visit_seq(self)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl<'de> serde::de::SeqAccess<'de> for CreateDeserializer<'de> {
|
|
|
+ type Error = super::ModelError;
|
|
|
+
|
|
|
+ fn next_element_seed<T: serde::de::DeserializeSeed<'de>>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error> {
|
|
|
+ seed.deserialize(self).map(Some)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// trait SQLFor: crate::model::Entity
|
|
|
+
|
|
|
+pub fn sql_for<'de, T: crate::model::EntityColumn + crate::model::Entity + serde::de::Deserialize<'de>>() -> (String,String) {
|
|
|
+ let mut cd = CreateDeserializer { table_name: None, column_names: None, column_types: Vec::new(), _de: std::marker::PhantomData{} };
|
|
|
+
|
|
|
+ T::deserialize(&mut cd).expect("SQL creation failed!");
|
|
|
+
|
|
|
+ (
|
|
|
+ format!("DROP TABLE IF EXISTS {}", <T as crate::model::Entity>::table_name()),
|
|
|
+ format!("CREATE TABLE {} ({})",
|
|
|
+ <T as crate::model::Entity>::table_name(),
|
|
|
+ cd.column_names.unwrap().iter().zip(cd.column_types.iter())
|
|
|
+ .map(|(n,t)| n.to_string() + " " + t).collect::<Vec<_>>().join(",")
|
|
|
+ )
|
|
|
+ )
|
|
|
+}
|
|
|
+
|
|
|
+#[cfg(test)]
|
|
|
+mod test {
|
|
|
+ #[derive(serde::Deserialize,crate::Model)]
|
|
|
+ struct Empty {}
|
|
|
+
|
|
|
+ #[derive(serde::Deserialize,crate::Model)]
|
|
|
+ struct Single {
|
|
|
+ e: i32
|
|
|
+ }
|
|
|
+
|
|
|
+ #[test]
|
|
|
+ fn example_sql_for() {
|
|
|
+ assert_eq!(
|
|
|
+ super::sql_for::<Empty>(),
|
|
|
+ ("DROP TABLE IF EXISTS empty".to_owned(), "CREATE TABLE empty ()".to_owned())
|
|
|
+ );
|
|
|
+ assert_eq!(
|
|
|
+ super::sql_for::<Single>(),
|
|
|
+ ("DROP TABLE IF EXISTS single".to_owned(), "CREATE TABLE single (e integer)".to_owned())
|
|
|
+ );
|
|
|
+ }
|
|
|
+}
|