diff --git a/src/ir/relation.rs b/src/ir/relation.rs index 4a3ae7ca55d2f4f29d73ed406ea586ae0d19d258..462f8a4fe2d5885702fcd4d709d0a68128dbc074 100644 --- a/src/ir/relation.rs +++ b/src/ir/relation.rs @@ -1,14 +1,16 @@ //! Relation module. use std::collections::{HashMap, HashSet}; +use std::fmt::Formatter; -use super::distribution::Key; +use serde::{Deserialize, Deserializer, Serialize}; +use serde::de::{Error, MapAccess, Visitor}; use serde::ser::{Serialize as SerSerialize, SerializeMap, Serializer}; -use serde::{Deserialize, Serialize}; use tarantool::hlua::{self, LuaRead}; use crate::errors::QueryPlannerError; +use super::distribution::Key; use super::value::Value; /// Supported column types. @@ -39,7 +41,7 @@ impl Type { } /// Relation column. -#[derive(LuaRead, Deserialize, PartialEq, Debug, Eq, Clone)] +#[derive(LuaRead, PartialEq, Debug, Eq, Clone)] pub struct Column { /// Column name. pub name: String, @@ -50,8 +52,8 @@ pub struct Column { /// Msgpack serializer for column impl SerSerialize for Column { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> - where - S: Serializer, + where + S: Serializer, { let mut map = serializer.serialize_map(Some(2))?; map.serialize_entry("name", &self.name)?; @@ -67,6 +69,46 @@ impl SerSerialize for Column { } } +struct ColumnVisitor; + +impl<'de> Visitor<'de> for ColumnVisitor { + type Value = Column; + + fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result { + formatter.write_str("column parsing failed") + } + + fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error> where A: MapAccess<'de> { + let mut column_name = String::new(); + let mut column_type = String::new(); + while let Some((key, value)) = map.next_entry::<String, String>()? { + match key.as_str() { + "name" => column_name.push_str(&value), + "type" => column_type.push_str(&value.to_lowercase()), + _ => return Err(Error::custom("invalid column param")) + } + } + + match column_type.as_str() { + "boolean" => Ok(Column::new(&column_name, Type::Boolean)), + "number" => Ok(Column::new(&column_name, Type::Number)), + "string" => Ok(Column::new(&column_name, Type::String)), + "integer" => Ok(Column::new(&column_name, Type::Integer)), + "unsigned" => Ok(Column::new(&column_name, Type::Unsigned)), + _ => Err(Error::custom("unsupported column type")), + } + } +} + +impl<'de> Deserialize<'de> for Column { + fn deserialize<D>(deserializer: D) -> Result<Column, D::Error> + where + D: Deserializer<'de>, + { + deserializer.deserialize_map(ColumnVisitor) + } +} + impl Column { /// Column constructor. #[must_use] diff --git a/src/ir/relation/tests.rs b/src/ir/relation/tests.rs index 9f7e4052580129caef6e8b840b53bb1436283318..5647457c0d08ad9901c4630b59b93143168836a5 100644 --- a/src/ir/relation/tests.rs +++ b/src/ir/relation/tests.rs @@ -28,7 +28,7 @@ fn table_seg() { ], &["b", "a"], ) - .unwrap(); + .unwrap(); if let Table::Segment { key, .. } = &t { assert_eq!(2, key.positions.len()); assert_eq!(0, key.positions[1]); @@ -55,7 +55,7 @@ fn table_seg_duplicate_columns() { ], &["b", "a"], ) - .unwrap_err(), + .unwrap_err(), QueryPlannerError::DuplicateColumn ); } @@ -73,7 +73,7 @@ fn table_seg_wrong_key() { ], &["a", "e"], ) - .unwrap_err(), + .unwrap_err(), QueryPlannerError::InvalidShardingKey ); } @@ -92,7 +92,7 @@ fn table_seg_serialized() { ], &["a", "d"], ) - .unwrap(); + .unwrap(); let path = Path::new("") .join("tests") .join("artifactory") @@ -185,7 +185,7 @@ fn column_msgpack_serialize() { assert_eq!( vec![ 0x82, 0xA4, 0x6E, 0x61, 0x6D, 0x65, 0xA4, 0x6E, 0x61, 0x6D, 0x65, 0xA4, 0x74, 0x79, - 0x70, 0x65, 0xA6, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67 + 0x70, 0x65, 0xA6, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, ], rmp_serde::to_vec(&c).unwrap() ); @@ -229,3 +229,21 @@ fn column_msgpack_serialize() { rmp_serde::to_vec(&c).unwrap() ) } + +#[test] +fn table_converting() { + let t = Table::new_seg( + "t", + vec![ + Column::new("a", Type::Boolean), + Column::new("b", Type::Number), + Column::new("c", Type::String), + Column::new("d", Type::String), + ], + &["b", "a"], + ) + .unwrap(); + + let s = serde_yaml::to_string(&t).unwrap(); + Table::seg_from_yaml(&s).unwrap(); +} \ No newline at end of file