This commit is contained in:
Yuriy Dupyn 2024-02-01 17:14:50 +01:00
parent ae4061980e
commit af5490e2dc

View file

@ -28,7 +28,6 @@ pub enum Value {
None(DbType),
}
#[derive(Debug, Eq, Clone, PartialEq, Serialize, Deserialize)]
#[serde(try_from = "String", into = "String")]
pub enum IndexableValue {
@ -91,6 +90,37 @@ impl DbType {
}
}
fn to_json_key_string(self) -> String {
match self {
DbType::String => format!("String()"),
DbType::Int => format!("Int()"),
DbType::Number => format!("Number()"),
DbType::Uuid => format!("Uuid()"),
DbType::Option(type_) => format!("Option({})", type_.to_json_key_string()),
}
}
fn parse_json_key_string(str: &str) -> Result<DbType, String> {
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(Self::parse_json_key_string(s)?)))
} else {
Err(format!("Invalid DbType: {}", str))
}
}
pub fn type_oid(&self) -> i32 {
// match self {
// Self::String => 25,
@ -135,6 +165,58 @@ impl Value {
}
}
fn to_json_key_string(self) -> String {
match self {
Self::Number(x) => format!("Number({x})"),
Self::String(s) => format!("String({s})"),
Self::Int(i) => format!("Int({i})"),
Self::Uuid(u) => format!("Uuid({u})"),
Self::Some(val) => format!("Some({})", val.to_json_key_string()),
Self::None(_type_) => "None()".to_string(),
}
}
// We don't really need this, since only indexable values are keys in maps. It is here for consistency.
fn parse_json_key_string(str: &str) -> Result<Self, String> {
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::<f64>()
.map_err(|e| format!("Invalid Number: {}", e))?;
Ok(Self::Number(n))
} else if str.starts_with("String(") {
let s = str[7..str.len() - 1].to_string();
Ok(Self::String(s))
} else if str.starts_with("Int(") {
let s = str[4..str.len() - 1].to_string();
let i = s
.parse::<u64>()
.map_err(|e| format!("Invalid Int: {}", e))?;
Ok(Self::Int(i))
} else if str.starts_with("Uuid(") {
let s = str[5..str.len() - 1].to_string();
let u = s
.parse::<u64>()
.map_err(|e| format!("Invalid UUID: {}", e))?;
Ok(Self::Uuid(u))
} else if str.starts_with("Some(") {
let s = str[5..str.len() - 1].to_string();
let val: Value = Self::parse_json_key_string(&s)?;
Ok(Self::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))
}
}
pub fn as_text_bytes(&self) -> Vec<u8> {
// match self {
// Self::Number(n) => format!("{n}").into_bytes(),
@ -179,171 +261,105 @@ 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_)),
impl IndexableValue {
fn to_value(self) -> Value {
match self {
IndexableValue::String(str) => Value::String(str),
IndexableValue::Int(n) => Value::Int(n),
IndexableValue::Uuid(id) => Value::Uuid(id),
IndexableValue::Some(indexable_value) => Value::Some(Box::new(indexable_value.to_value())),
IndexableValue::None(type_) => Value::None(type_),
}
}
fn to_json_key_string(self) -> String {
match self {
IndexableValue::String(s) => format!("String({s})"),
IndexableValue::Int(i) => format!("Int({i})"),
IndexableValue::Uuid(u) => format!("Uuid({u})"),
IndexableValue::Some(val) => format!("Some({})", val.to_json_key_string()),
IndexableValue::None(_type_) => "None()".to_string(),
}
}
fn parse_json_key_string(str: &str) -> Result<Self, String> {
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::<u64>()
.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::<u64>()
.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 = Self::parse_json_key_string(&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 = DbType::parse_json_key_string(&s)?;
Ok(IndexableValue::None(type_))
} else {
Err(format!("Invalid IndexableValue: {}", str))
}
}
}
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) => format!("Some({})", indexable_value_to_string(*val)),
IndexableValue::None(_type_) => "None()".to_string(),
impl From<IndexableValue> for Value {
fn from(indexable_value: IndexableValue) -> Self {
indexable_value.to_value()
}
}
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<DbType, String> {
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<Value, String> {
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::<f64>()
.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::<u64>()
.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::<u64>()
.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<IndexableValue, String> {
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::<u64>()
.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::<u64>()
.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<IndexableValue> for String {
fn from(value: IndexableValue) -> Self {
indexable_value_to_string(value)
value.to_json_key_string()
}
}
impl From<DbType> for String {
fn from(type_: DbType) -> Self {
db_type_to_string(type_)
type_.to_json_key_string()
}
}
impl TryFrom<String> for DbType {
type Error = String;
fn try_from(str: String) -> Result<Self, Self::Error> {
parse_db_type(&str)
Self::parse_json_key_string(&str)
}
}
impl TryFrom<String> for IndexableValue {
type Error = String;
fn try_from(str: String) -> Result<Self, Self::Error> {
parse_indexable_value(&str)
Self::parse_json_key_string(&str)
}
}
impl From<Value> for String {
fn from(value: Value) -> Self {
value_to_string(value)
value.to_json_key_string()
}
}
impl TryFrom<String> for Value {
type Error = String;
fn try_from(value: String) -> Result<Self, Self::Error> {
parse_value(&value)
Value::parse_json_key_string(&value)
}
}