123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146 |
- use serde::de::Visitor;
- #[derive(Debug)]
- pub struct CreateDeserializer<'de> {
- column_names: Vec<String>,
- column_types: Vec<String>,
- column_name_stack: 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
- option unit unit_struct 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>>(self, v: V) -> Result<V::Value, Self::Error> {
- self.column_types.push("integer".to_owned());
- self.column_names.push(self.column_name_stack.pop().unwrap());
- v.visit_i32(0)
- }
- fn deserialize_i64<V: Visitor<'de>>(self, v: V) -> Result<V::Value, Self::Error> {
- self.column_types.push("integer".to_owned());
- self.column_names.push(self.column_name_stack.pop().unwrap());
- v.visit_i64(0)
- }
- fn deserialize_string<V: Visitor<'de>>(self, v: V) -> Result<V::Value, Self::Error> {
- self.column_types.push("varchar".to_owned());
- self.column_names.push(self.column_name_stack.pop().unwrap());
- v.visit_string("".to_owned())
- }
- fn deserialize_bytes<V: Visitor<'de>>(self, v: V) -> Result<V::Value, Self::Error> {
- self.column_types.push("blob".to_owned());
- self.column_names.push(self.column_name_stack.pop().unwrap());
- v.visit_bytes(&[])
- }
- fn deserialize_byte_buf<V: Visitor<'de>>(self, v: V) -> Result<V::Value, Self::Error> {
- self.column_types.push("blob".to_owned());
- self.column_names.push(self.column_name_stack.pop().unwrap());
- v.visit_bytes(&[])
- }
- fn deserialize_seq<V: Visitor<'de>>(
- self, v: V) -> Result<V::Value, Self::Error> {
- v.visit_seq(self)
- }
- fn deserialize_struct<V: Visitor<'de>>(
- self,
- name: &'static str,
- fields: &'static [&'static str],
- v: V,
- ) -> Result<V::Value, Self::Error> {
- self.column_name_stack.extend(fields.iter().map(|x| x.to_string()));
- v.visit_seq(self)
- }
- fn deserialize_newtype_struct<V: Visitor<'de>>(
- self,
- name: &'static str,
- v: V
- ) -> Result<V::Value, Self::Error> {
- unreachable!("microrm cannot store newtype structs")
- }
- }
- 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)
- }
- }
- pub fn sql_for<T: crate::model::Entity>() -> (String, String) {
- let mut cd = CreateDeserializer {
- column_names: Vec::new(),
- column_types: Vec::new(),
- column_name_stack: 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
- .iter()
- .zip(cd.column_types.iter())
- .map(|(n, t)| n.to_string() + " " + t)
- .collect::<Vec<_>>()
- .join(",")
- ),
- )
- }
- #[cfg(test)]
- mod test {
- #[derive(serde::Serialize, serde::Deserialize, crate::Entity)]
- struct Empty {}
- #[derive(serde::Serialize, serde::Deserialize, crate::Entity)]
- 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()
- )
- );
- }
- }
|