|
@@ -1,19 +1,31 @@
|
|
use serde::de::Visitor;
|
|
use serde::de::Visitor;
|
|
|
|
|
|
|
|
+use std::rc::Rc;
|
|
|
|
+use std::cell::Cell;
|
|
|
|
+
|
|
#[derive(Debug)]
|
|
#[derive(Debug)]
|
|
pub struct CreateDeserializer<'de> {
|
|
pub struct CreateDeserializer<'de> {
|
|
- column_names: Vec<String>,
|
|
|
|
- column_types: Vec<String>,
|
|
|
|
- column_name_stack: Vec<String>,
|
|
|
|
|
|
+ struct_visited: bool,
|
|
|
|
+ column_names: Vec<&'static str>,
|
|
|
|
+ column_types: Vec<&'static str>,
|
|
|
|
+ column_name_stack: Vec<&'static str>,
|
|
|
|
+ expected_length: Rc<Cell<usize>>,
|
|
_de: std::marker::PhantomData<&'de u8>,
|
|
_de: std::marker::PhantomData<&'de u8>,
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+impl<'de> CreateDeserializer<'de> {
|
|
|
|
+ fn integral_type(&mut self) {
|
|
|
|
+ self.column_types.push("integer");
|
|
|
|
+ self.column_names.push(self.column_name_stack.pop().unwrap());
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
impl<'de, 'a> serde::de::Deserializer<'de> for &'a mut CreateDeserializer<'de> {
|
|
impl<'de, 'a> serde::de::Deserializer<'de> for &'a mut CreateDeserializer<'de> {
|
|
type Error = super::ModelError;
|
|
type Error = super::ModelError;
|
|
|
|
|
|
// we (ab)use the forward_to_deserialize_any! macro to stub out the types we don't care about
|
|
// we (ab)use the forward_to_deserialize_any! macro to stub out the types we don't care about
|
|
serde::forward_to_deserialize_any! {
|
|
serde::forward_to_deserialize_any! {
|
|
- bool i8 i16 i128 u8 u16 u32 u64 u128 f32 f64 char str
|
|
|
|
|
|
+ bool i128 u64 u128 f32 f64 char str
|
|
option unit unit_struct tuple
|
|
option unit unit_struct tuple
|
|
tuple_struct map enum identifier ignored_any
|
|
tuple_struct map enum identifier ignored_any
|
|
}
|
|
}
|
|
@@ -22,32 +34,55 @@ impl<'de, 'a> serde::de::Deserializer<'de> for &'a mut CreateDeserializer<'de> {
|
|
todo!()
|
|
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_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> {
|
|
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());
|
|
|
|
|
|
+ self.integral_type();
|
|
v.visit_i32(0)
|
|
v.visit_i32(0)
|
|
}
|
|
}
|
|
|
|
|
|
fn deserialize_i64<V: Visitor<'de>>(self, v: V) -> Result<V::Value, Self::Error> {
|
|
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());
|
|
|
|
|
|
+ self.integral_type();
|
|
v.visit_i64(0)
|
|
v.visit_i64(0)
|
|
}
|
|
}
|
|
|
|
|
|
fn deserialize_string<V: Visitor<'de>>(self, v: V) -> Result<V::Value, Self::Error> {
|
|
fn deserialize_string<V: Visitor<'de>>(self, v: V) -> Result<V::Value, Self::Error> {
|
|
- self.column_types.push("varchar".to_owned());
|
|
|
|
|
|
+ self.column_types.push("text");
|
|
self.column_names.push(self.column_name_stack.pop().unwrap());
|
|
self.column_names.push(self.column_name_stack.pop().unwrap());
|
|
v.visit_string("".to_owned())
|
|
v.visit_string("".to_owned())
|
|
}
|
|
}
|
|
|
|
|
|
fn deserialize_bytes<V: Visitor<'de>>(self, v: V) -> Result<V::Value, Self::Error> {
|
|
fn deserialize_bytes<V: Visitor<'de>>(self, v: V) -> Result<V::Value, Self::Error> {
|
|
- self.column_types.push("blob".to_owned());
|
|
|
|
|
|
+ self.column_types.push("blob");
|
|
self.column_names.push(self.column_name_stack.pop().unwrap());
|
|
self.column_names.push(self.column_name_stack.pop().unwrap());
|
|
v.visit_bytes(&[])
|
|
v.visit_bytes(&[])
|
|
}
|
|
}
|
|
|
|
|
|
fn deserialize_byte_buf<V: Visitor<'de>>(self, v: V) -> Result<V::Value, Self::Error> {
|
|
fn deserialize_byte_buf<V: Visitor<'de>>(self, v: V) -> Result<V::Value, Self::Error> {
|
|
- self.column_types.push("blob".to_owned());
|
|
|
|
|
|
+ self.column_types.push("blob");
|
|
self.column_names.push(self.column_name_stack.pop().unwrap());
|
|
self.column_names.push(self.column_name_stack.pop().unwrap());
|
|
v.visit_bytes(&[])
|
|
v.visit_bytes(&[])
|
|
}
|
|
}
|
|
@@ -60,15 +95,22 @@ impl<'de, 'a> serde::de::Deserializer<'de> for &'a mut CreateDeserializer<'de> {
|
|
|
|
|
|
fn deserialize_struct<V: Visitor<'de>>(
|
|
fn deserialize_struct<V: Visitor<'de>>(
|
|
self,
|
|
self,
|
|
- name: &'static str,
|
|
|
|
|
|
+ _name: &'static str,
|
|
fields: &'static [&'static str],
|
|
fields: &'static [&'static str],
|
|
v: V,
|
|
v: V,
|
|
) -> Result<V::Value, Self::Error> {
|
|
) -> Result<V::Value, Self::Error> {
|
|
- // we may not have a prefix if this is the root struct
|
|
|
|
- // but if we do, it means we're serializing a sub-structure
|
|
|
|
- let prefix = self.column_name_stack.pop().map(|x| x + "_").unwrap_or("".to_string());
|
|
|
|
- self.column_name_stack.extend(fields.iter().map(|x| prefix.clone() + x).rev());
|
|
|
|
- v.visit_seq(self)
|
|
|
|
|
|
+ if self.struct_visited {
|
|
|
|
+ let elength = self.expected_length.clone();
|
|
|
|
+ let old_elength = elength.get();
|
|
|
|
+ println!("nested deserialize_struct invoked!");
|
|
|
|
+ todo!();
|
|
|
|
+ }
|
|
|
|
+ else {
|
|
|
|
+ self.column_name_stack.extend(fields.iter().rev());
|
|
|
|
+ self.expected_length.set(fields.len());
|
|
|
|
+ let ret = v.visit_seq(self);
|
|
|
|
+ ret
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
fn deserialize_newtype_struct<V: Visitor<'de>>(
|
|
fn deserialize_newtype_struct<V: Visitor<'de>>(
|
|
@@ -76,7 +118,14 @@ impl<'de, 'a> serde::de::Deserializer<'de> for &'a mut CreateDeserializer<'de> {
|
|
name: &'static str,
|
|
name: &'static str,
|
|
v: V
|
|
v: V
|
|
) -> Result<V::Value, Self::Error> {
|
|
) -> Result<V::Value, Self::Error> {
|
|
- unreachable!("microrm cannot store newtype structs")
|
|
|
|
|
|
+ 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
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -87,15 +136,26 @@ impl<'de> serde::de::SeqAccess<'de> for CreateDeserializer<'de> {
|
|
&mut self,
|
|
&mut self,
|
|
seed: T,
|
|
seed: T,
|
|
) -> Result<Option<T::Value>, Self::Error> {
|
|
) -> 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)
|
|
seed.deserialize(self).map(Some)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
pub fn sql_for<T: crate::model::Entity>() -> (String, String) {
|
|
pub fn sql_for<T: crate::model::Entity>() -> (String, String) {
|
|
|
|
+
|
|
|
|
+ let mut elength = Rc::new(Cell::new(0));
|
|
|
|
+
|
|
let mut cd = CreateDeserializer {
|
|
let mut cd = CreateDeserializer {
|
|
|
|
+ struct_visited: false,
|
|
column_names: Vec::new(),
|
|
column_names: Vec::new(),
|
|
column_types: Vec::new(),
|
|
column_types: Vec::new(),
|
|
column_name_stack: Vec::new(),
|
|
column_name_stack: Vec::new(),
|
|
|
|
+ expected_length: elength,
|
|
_de: std::marker::PhantomData {},
|
|
_de: std::marker::PhantomData {},
|
|
};
|
|
};
|
|
|
|
|
|
@@ -121,6 +181,8 @@ pub fn sql_for<T: crate::model::Entity>() -> (String, String) {
|
|
|
|
|
|
#[cfg(test)]
|
|
#[cfg(test)]
|
|
mod test {
|
|
mod test {
|
|
|
|
+ use serde::Deserialize;
|
|
|
|
+
|
|
#[derive(serde::Serialize, serde::Deserialize, crate::Entity)]
|
|
#[derive(serde::Serialize, serde::Deserialize, crate::Entity)]
|
|
#[microrm_internal]
|
|
#[microrm_internal]
|
|
pub struct Empty {}
|
|
pub struct Empty {}
|
|
@@ -131,6 +193,12 @@ mod test {
|
|
e: i32,
|
|
e: i32,
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ #[derive(serde::Serialize, serde::Deserialize, crate::Entity)]
|
|
|
|
+ #[microrm_internal]
|
|
|
|
+ pub struct Reference {
|
|
|
|
+ e: SingleID,
|
|
|
|
+ }
|
|
|
|
+
|
|
#[test]
|
|
#[test]
|
|
fn example_sql_for() {
|
|
fn example_sql_for() {
|
|
assert_eq!(
|
|
assert_eq!(
|
|
@@ -147,5 +215,48 @@ mod test {
|
|
r#"CREATE TABLE "single" ("e" integer)"#.to_owned()
|
|
r#"CREATE TABLE "single" ("e" integer)"#.to_owned()
|
|
)
|
|
)
|
|
);
|
|
);
|
|
|
|
+
|
|
|
|
+ assert_eq!(
|
|
|
|
+ super::sql_for::<Reference>(),
|
|
|
|
+ (
|
|
|
|
+ r#"DROP TABLE IF EXISTS "reference""#.to_owned(),
|
|
|
|
+ r#"CREATE TABLE "reference" ("e" integer)"#.to_owned()
|
|
|
|
+ )
|
|
|
|
+ );
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ #[derive(serde::Serialize, serde::Deserialize, crate::Modelable)]
|
|
|
|
+ #[microrm_internal]
|
|
|
|
+ pub struct Unit(u8);
|
|
|
|
+ #[derive(serde::Serialize, serde::Deserialize, crate::Entity)]
|
|
|
|
+ #[microrm_internal]
|
|
|
|
+ pub struct UnitNewtype {
|
|
|
|
+ newtype: Unit,
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ #[test]
|
|
|
|
+ fn unit_newtype_struct() {
|
|
|
|
+ assert_eq!(
|
|
|
|
+ super::sql_for::<UnitNewtype>(),
|
|
|
|
+ (
|
|
|
|
+ r#"DROP TABLE IF EXISTS "unit_newtype""#.to_owned(),
|
|
|
|
+ r#"CREATE TABLE "unit_newtype" ("newtype" integer)"#.to_owned()
|
|
|
|
+ )
|
|
|
|
+ );
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ #[derive(serde::Serialize, serde::Deserialize, crate::Modelable)]
|
|
|
|
+ #[microrm_internal]
|
|
|
|
+ pub struct NonUnit(u8,u8);
|
|
|
|
+ #[derive(serde::Serialize, serde::Deserialize, crate::Entity)]
|
|
|
|
+ #[microrm_internal]
|
|
|
|
+ pub struct NonUnitNewtype {
|
|
|
|
+ newtype: NonUnit,
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ #[test]
|
|
|
|
+ #[should_panic]
|
|
|
|
+ fn nonunit_newtype_struct() {
|
|
|
|
+ super::sql_for::<NonUnitNewtype>();
|
|
}
|
|
}
|
|
}
|
|
}
|