From d4a941a7383442535547618f28dd3fdad0129447 Mon Sep 17 00:00:00 2001 From: Yuriy Dupyn <2153100+omedusyo@users.noreply.github.com> Date: Thu, 1 Feb 2024 15:50:19 +0100 Subject: [PATCH] Write new parser/formatters for Values/IndexableValues --- minisql/src/type_system.rs | 196 ++++++++++++++++++++++++++----------- 1 file changed, 140 insertions(+), 56 deletions(-) diff --git a/minisql/src/type_system.rs b/minisql/src/type_system.rs index 8e7b0a1..3113cd6 100644 --- a/minisql/src/type_system.rs +++ b/minisql/src/type_system.rs @@ -179,16 +179,134 @@ impl Value { } } +// ===formatting=== +fn db_type_to_string(type_: DbType) -> String { + match type_ { + DbType::String => format!("String()"), + DbType::Int => format!("Int()"), + DbType::Number => format!("Number()"), + DbType::Uuid => format!("Uuid()"), + DbType::Option(type_) => format!("Option({})", db_type_to_string(*type_)), + } +} + fn indexable_value_to_string(value: IndexableValue) -> String { match value { IndexableValue::String(s) => format!("String({s})"), IndexableValue::Int(i) => format!("Int({i})"), IndexableValue::Uuid(u) => format!("Uuid({u})"), - IndexableValue::Some(val) => todo!(), - IndexableValue::None(type_) => "None()".to_string(), + IndexableValue::Some(val) => format!("Some({})", indexable_value_to_string(*val)), + IndexableValue::None(_type_) => "None()".to_string(), } } +fn value_to_string(value: Value) -> String { + match value { + Value::Number(x) => format!("Number({x})"), + Value::String(s) => format!("String({s})"), + Value::Int(i) => format!("Int({i})"), + Value::Uuid(u) => format!("Uuid({u})"), + Value::Some(val) => format!("Some({})", value_to_string(*val)), + Value::None(_type_) => "None()".to_string(), + } +} + +// ===parsing=== +fn parse_db_type(str: &str) -> Result { + if !str.ends_with(')') { + return Err(format!("Invalid DbType: {}", str)); + } + + if str.starts_with("String(") { + Ok(DbType::String) + } else if str.starts_with("Int(") { + Ok(DbType::Int) + } else if str.starts_with("Number(") { + Ok(DbType::Number) + } else if str.starts_with("Uuid(") { + Ok(DbType::Uuid) + } else if str.starts_with("Option(") { + let s = &str[7..str.len() - 1]; + Ok(DbType::Option(Box::new(parse_db_type(s)?))) + } else { + Err(format!("Invalid DbType: {}", str)) + } +} + +fn parse_value(str: &str) -> Result { + if !str.ends_with(')') { + return Err(format!("Invalid IndexableValue: {}", str)); + } + + if str.starts_with("Number(") { + let s = str[7..str.len() - 1].to_string(); + let n = s + .parse::() + .map_err(|e| format!("Invalid Number: {}", e))?; + Ok(Value::Number(n)) + } else if str.starts_with("String(") { + let s = str[7..str.len() - 1].to_string(); + Ok(Value::String(s)) + } else if str.starts_with("Int(") { + let s = str[4..str.len() - 1].to_string(); + let i = s + .parse::() + .map_err(|e| format!("Invalid Int: {}", e))?; + Ok(Value::Int(i)) + } else if str.starts_with("Uuid(") { + let s = str[5..str.len() - 1].to_string(); + let u = s + .parse::() + .map_err(|e| format!("Invalid UUID: {}", e))?; + Ok(Value::Uuid(u)) + } else if str.starts_with("Some(") { + let s = str[5..str.len() - 1].to_string(); + let val: Value = parse_value(&s)?; + Ok(Value::Some(Box::new(val))) + } else if str.starts_with("None(") { + let s = str[5..str.len() - 1].to_string(); + let type_: DbType = TryFrom::try_from(s)?; + Ok(Value::None(type_)) + } else { + Err(format!("Invalid IndexableValue: {}", str)) + } +} + +fn parse_indexable_value(str: &str) -> Result { + if !str.ends_with(')') { + return Err(format!("Invalid IndexableValue: {}", str)); + } + + if str.starts_with("String(") { + let s = str[7..str.len() - 1].to_string(); + Ok(IndexableValue::String(s)) + } else if str.starts_with("Int(") { + let s = str[4..str.len() - 1].to_string(); + let i = s + .parse::() + .map_err(|e| format!("Invalid Int: {}", e))?; + Ok(IndexableValue::Int(i)) + } else if str.starts_with("Uuid(") { + let s = str[5..str.len() - 1].to_string(); + let u = s + .parse::() + .map_err(|e| format!("Invalid UUID: {}", e))?; + Ok(IndexableValue::Uuid(u)) + } else if str.starts_with("Some(") { + let s = str[5..str.len() - 1].to_string(); + let val: IndexableValue = parse_indexable_value(&s)?; + Ok(IndexableValue::Some(Box::new(val))) + } else if str.starts_with("None(") { + let s = str[5..str.len() - 1].to_string(); + let type_: DbType = parse_db_type(&s)?; + Ok(IndexableValue::None(type_)) + } else { + Err(format!("Invalid IndexableValue: {}", str)) + } +} + + + // Own string serialization so enums can be used as keys in maps impl From for String { fn from(value: IndexableValue) -> Self { @@ -196,71 +314,37 @@ impl From for String { } } -impl TryFrom for IndexableValue { - type Error = String; - fn try_from(value: String) -> Result { - if !value.ends_with(')') { - return Err(format!("Invalid IndexableValue: {}", value)); - } - - if value.starts_with("String(") { - let s = value[7..value.len() - 1].to_string(); - Ok(Self::String(s)) - } else if value.starts_with("Int(") { - let s = value[4..value.len() - 1].to_string(); - let i = s - .parse::() - .map_err(|e| format!("Invalid Int: {}", e))?; - Ok(Self::Int(i)) - } else if value.starts_with("Uuid(") { - let s = value[5..value.len() - 1].to_string(); - let u = s - .parse::() - .map_err(|e| format!("Invalid UUID: {}", e))?; - Ok(Self::Uuid(u)) - } else if value.starts_with("Some(") { - // TODO: This needs some recursion - todo!() - } else if value.starts_with("None(") { - todo!() - } else { - Err(format!("Invalid IndexableValue: {}", value)) - } +impl From for String { + fn from(type_: DbType) -> Self { + db_type_to_string(type_) } } +impl TryFrom for DbType { + type Error = String; + fn try_from(str: String) -> Result { + parse_db_type(&str) + } +} + +impl TryFrom for IndexableValue { + type Error = String; + fn try_from(str: String) -> Result { + parse_indexable_value(&str) + } +} + + impl From for String { fn from(value: Value) -> Self { - // match value { - // Value::Number(n) => format!("Number({n})"), - // Value::Indexable(i) => format!("Indexable({})", String::from(i)), - // } - todo!() + value_to_string(value) } } impl TryFrom for Value { type Error = String; fn try_from(value: String) -> Result { - if !value.ends_with(')') { - return Err(format!("Invalid Value: {}", value)); - } - - // if value.starts_with("Number(") { - // let s = value[7..value.len() - 1].to_string(); - // let n = s - // .parse::() - // .map_err(|e| format!("Invalid Number: {}", e))?; - // Ok(Self::Number(n)) - // } else if value.starts_with("Indexable(") { - // let s = value[10..value.len() - 1].to_string(); - // let i = IndexableValue::try_from(s)?; - // Ok(Self::Indexable(i)) - // } else { - // Err(format!("Invalid Value: {}", value)) - // } - - todo!() + parse_value(&value) } }