|
@@ -1,173 +1,5 @@
|
|
|
-use serde::de::Visitor;
|
|
|
-
|
|
|
-use std::cell::Cell;
|
|
|
-use std::rc::Rc;
|
|
|
-
|
|
|
-struct EmptySequence {}
|
|
|
-
|
|
|
-impl<'de> serde::de::SeqAccess<'de> for EmptySequence {
|
|
|
- type Error = super::ModelError;
|
|
|
-
|
|
|
- fn next_element_seed<T: serde::de::DeserializeSeed<'de>>(
|
|
|
- &mut self,
|
|
|
- _seed: T,
|
|
|
- ) -> Result<Option<T::Value>, Self::Error> {
|
|
|
- Ok(None)
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-#[derive(Debug)]
|
|
|
-pub struct CreateDeserializer<'de> {
|
|
|
- struct_visited: bool,
|
|
|
- column_types: Vec<&'static str>,
|
|
|
- expected_length: Rc<Cell<usize>>,
|
|
|
- _de: std::marker::PhantomData<&'de u8>,
|
|
|
-}
|
|
|
-
|
|
|
-impl<'de> CreateDeserializer<'de> {
|
|
|
- fn integral_type(&mut self) {
|
|
|
- self.column_types.push("integer");
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-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 i128 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_u8<V: Visitor<'de>>(self, v: V) -> Result<V::Value, Self::Error> {
|
|
|
- self.integral_type();
|
|
|
- v.visit_u8(0)
|
|
|
- }
|
|
|
-
|
|
|
- fn deserialize_u16<V: Visitor<'de>>(self, v: V) -> Result<V::Value, Self::Error> {
|
|
|
- self.integral_type();
|
|
|
- v.visit_u16(0)
|
|
|
- }
|
|
|
-
|
|
|
- fn deserialize_u32<V: Visitor<'de>>(self, v: V) -> Result<V::Value, Self::Error> {
|
|
|
- self.integral_type();
|
|
|
- v.visit_u32(0)
|
|
|
- }
|
|
|
-
|
|
|
- fn deserialize_u64<V: Visitor<'de>>(self, v: V) -> Result<V::Value, Self::Error> {
|
|
|
- self.integral_type();
|
|
|
- v.visit_u64(0)
|
|
|
- }
|
|
|
-
|
|
|
- fn deserialize_i8<V: Visitor<'de>>(self, v: V) -> Result<V::Value, Self::Error> {
|
|
|
- self.integral_type();
|
|
|
- v.visit_i8(0)
|
|
|
- }
|
|
|
-
|
|
|
- fn deserialize_i16<V: Visitor<'de>>(self, v: V) -> Result<V::Value, Self::Error> {
|
|
|
- self.integral_type();
|
|
|
- v.visit_i16(0)
|
|
|
- }
|
|
|
-
|
|
|
- fn deserialize_i32<V: Visitor<'de>>(self, v: V) -> Result<V::Value, Self::Error> {
|
|
|
- self.integral_type();
|
|
|
- v.visit_i32(0)
|
|
|
- }
|
|
|
-
|
|
|
- fn deserialize_i64<V: Visitor<'de>>(self, v: V) -> Result<V::Value, Self::Error> {
|
|
|
- self.integral_type();
|
|
|
- v.visit_i64(0)
|
|
|
- }
|
|
|
-
|
|
|
- fn deserialize_string<V: Visitor<'de>>(self, v: V) -> Result<V::Value, Self::Error> {
|
|
|
- self.column_types.push("text");
|
|
|
- v.visit_string("".to_owned())
|
|
|
- }
|
|
|
-
|
|
|
- fn deserialize_bytes<V: Visitor<'de>>(self, v: V) -> Result<V::Value, Self::Error> {
|
|
|
- self.column_types.push("blob");
|
|
|
- v.visit_bytes(&[])
|
|
|
- }
|
|
|
-
|
|
|
- fn deserialize_byte_buf<V: Visitor<'de>>(self, v: V) -> Result<V::Value, Self::Error> {
|
|
|
- self.column_types.push("blob");
|
|
|
- v.visit_bytes(&[])
|
|
|
- }
|
|
|
-
|
|
|
- fn deserialize_seq<V: Visitor<'de>>(self, v: V) -> Result<V::Value, Self::Error> {
|
|
|
- // we store sequences as JSON-encoded strings, so...
|
|
|
- self.column_types.push("text");
|
|
|
- let es = EmptySequence {};
|
|
|
- v.visit_seq(es)
|
|
|
- }
|
|
|
-
|
|
|
- fn deserialize_struct<V: Visitor<'de>>(
|
|
|
- self,
|
|
|
- _name: &'static str,
|
|
|
- fields: &'static [&'static str],
|
|
|
- v: V,
|
|
|
- ) -> Result<V::Value, Self::Error> {
|
|
|
- if self.struct_visited {
|
|
|
- panic!("Nested structs not allowed!");
|
|
|
- } else {
|
|
|
- self.struct_visited = true;
|
|
|
- self.expected_length.set(fields.len());
|
|
|
- v.visit_seq(self)
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- fn deserialize_newtype_struct<V: Visitor<'de>>(
|
|
|
- self,
|
|
|
- _name: &'static str,
|
|
|
- v: V,
|
|
|
- ) -> Result<V::Value, Self::Error> {
|
|
|
- let elength = self.expected_length.clone();
|
|
|
- let old_elength = elength.get();
|
|
|
- elength.set(1);
|
|
|
- let ret = v.visit_seq(self);
|
|
|
-
|
|
|
- elength.set(old_elength);
|
|
|
-
|
|
|
- ret
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-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> {
|
|
|
- if self.expected_length.get() == 0 {
|
|
|
- return Err(Self::Error::CreateError);
|
|
|
- }
|
|
|
-
|
|
|
- self.expected_length.set(self.expected_length.get() - 1);
|
|
|
-
|
|
|
- seed.deserialize(self).map(Some)
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
pub fn sql_for_table<T: crate::model::Entity>() -> (String, String) {
|
|
|
- let elength = Rc::new(Cell::new(0));
|
|
|
-
|
|
|
- let mut cd = CreateDeserializer {
|
|
|
- struct_visited: false,
|
|
|
- column_types: Vec::new(),
|
|
|
- expected_length: elength,
|
|
|
- _de: std::marker::PhantomData {},
|
|
|
- };
|
|
|
-
|
|
|
- T::deserialize(&mut cd).expect("SQL creation failed!");
|
|
|
-
|
|
|
- // +1 to account for id column that is included in column_count
|
|
|
- assert_eq!(T::column_count(), cd.column_types.len() + 1);
|
|
|
+ let types = T::column_types();
|
|
|
|
|
|
let mut columns = vec!["id integer primary key".to_owned()];
|
|
|
|
|
@@ -190,7 +22,7 @@ pub fn sql_for_table<T: crate::model::Entity>() -> (String, String) {
|
|
|
columns.push(format!(
|
|
|
"\"{}\" {}{}",
|
|
|
T::name(col),
|
|
|
- cd.column_types[i - 1],
|
|
|
+ types[i],
|
|
|
fk.last().unwrap_or_else(|| "".to_string())
|
|
|
));
|
|
|
}
|
|
@@ -364,11 +196,32 @@ mod test {
|
|
|
#[test]
|
|
|
fn test_vec() {
|
|
|
assert_eq!(
|
|
|
- super::sql_for_table::<VecTest>(),
|
|
|
- (
|
|
|
- r#"DROP TABLE IF EXISTS "vec_test""#.to_owned(),
|
|
|
- r#"CREATE TABLE IF NOT EXISTS "vec_test" (id integer primary key,"e" integer,"test" text)"#.to_owned()
|
|
|
- )
|
|
|
+ super::sql_for_table::<VecTest>().1,
|
|
|
+ r#"CREATE TABLE IF NOT EXISTS "vec_test" (id integer primary key,"e" integer,"test" blob)"#.to_owned()
|
|
|
);
|
|
|
}
|
|
|
+
|
|
|
+ #[derive(crate::Modelable, serde::Deserialize, serde::Serialize)]
|
|
|
+ #[microrm_internal]
|
|
|
+ pub enum TestEnum {
|
|
|
+ A,
|
|
|
+ B,
|
|
|
+ C
|
|
|
+ }
|
|
|
+
|
|
|
+ #[derive(serde::Serialize, serde::Deserialize, crate::Entity)]
|
|
|
+ #[microrm_internal]
|
|
|
+ pub struct EnumContainer {
|
|
|
+ before: usize,
|
|
|
+ e: TestEnum,
|
|
|
+ after: usize
|
|
|
+ }
|
|
|
+
|
|
|
+ #[test]
|
|
|
+ fn test_enum() {
|
|
|
+ assert_eq!(
|
|
|
+ super::sql_for_table::<EnumContainer>().1,
|
|
|
+ r#"CREATE TABLE IF NOT EXISTS "enum_container" (id integer primary key,"before" integer,"e" blob,"after" integer)"#.to_owned()
|
|
|
+ )
|
|
|
+ }
|
|
|
}
|