Merge branch 'index-serialization' into 'main'
Index serialization See merge request x433485/minisql!25
This commit is contained in:
commit
597c52caa0
2 changed files with 102 additions and 1 deletions
File diff suppressed because one or more lines are too long
|
|
@ -17,6 +17,7 @@ pub type Uuid = u64;
|
||||||
// I would rather have non-nullable values by default,
|
// I would rather have non-nullable values by default,
|
||||||
// and something like an explicit Option type for nulls.
|
// and something like an explicit Option type for nulls.
|
||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
|
#[serde(try_from = "String", into = "String")]
|
||||||
pub enum Value {
|
pub enum Value {
|
||||||
Number(f64), // TODO: Can't put floats as keys in maps, since they don't implement Eq. What to
|
Number(f64), // TODO: Can't put floats as keys in maps, since they don't implement Eq. What to
|
||||||
// do?
|
// do?
|
||||||
|
|
@ -24,6 +25,7 @@ pub enum Value {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Ord, Eq, Clone, PartialOrd, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Ord, Eq, Clone, PartialOrd, PartialEq, Serialize, Deserialize)]
|
||||||
|
#[serde(try_from = "String", into = "String")]
|
||||||
pub enum IndexableValue {
|
pub enum IndexableValue {
|
||||||
String(String),
|
String(String),
|
||||||
Int(u64),
|
Int(u64),
|
||||||
|
|
@ -113,10 +115,88 @@ impl Value {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Own string serialization so enums can be used as keys in maps
|
||||||
|
impl From<IndexableValue> for String {
|
||||||
|
fn from(value: IndexableValue) -> Self {
|
||||||
|
match value {
|
||||||
|
IndexableValue::String(s) => format!("String({s})"),
|
||||||
|
IndexableValue::Int(i) => format!("Int({i})"),
|
||||||
|
IndexableValue::Uuid(u) => format!("Uuid({u})"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<String> for IndexableValue {
|
||||||
|
type Error = String;
|
||||||
|
fn try_from(value: String) -> Result<Self, Self::Error> {
|
||||||
|
if !value.ends_with(')') {
|
||||||
|
return Err(format!("Invalid IndexableValue: {}", value));
|
||||||
|
}
|
||||||
|
|
||||||
|
if value.starts_with("String(") {
|
||||||
|
let s = value[7..value.len() - 1].to_string();
|
||||||
|
return Ok(Self::String(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
if value.starts_with("Int(") {
|
||||||
|
let s = value[4..value.len() - 1].to_string();
|
||||||
|
let i = s
|
||||||
|
.parse::<u64>()
|
||||||
|
.map_err(|e| format!("Invalid Int: {}", e))?;
|
||||||
|
return Ok(Self::Int(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
if value.starts_with("Uuid(") {
|
||||||
|
let s = value[5..value.len() - 1].to_string();
|
||||||
|
let u = s
|
||||||
|
.parse::<u64>()
|
||||||
|
.map_err(|e| format!("Invalid UUID: {}", e))?;
|
||||||
|
return Ok(Self::Uuid(u));
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(format!("Invalid IndexableValue: {}", value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Value> for String {
|
||||||
|
fn from(value: Value) -> Self {
|
||||||
|
match value {
|
||||||
|
Value::Number(n) => format!("Number({n})"),
|
||||||
|
Value::Indexable(i) => format!("Indexable({})", String::from(i)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<String> for Value {
|
||||||
|
type Error = String;
|
||||||
|
fn try_from(value: String) -> Result<Self, Self::Error> {
|
||||||
|
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::<f64>()
|
||||||
|
.map_err(|e| format!("Invalid Number: {}", e))?;
|
||||||
|
return Ok(Self::Number(n));
|
||||||
|
}
|
||||||
|
|
||||||
|
if value.starts_with("Indexable(") {
|
||||||
|
let s = value[10..value.len() - 1].to_string();
|
||||||
|
let i = IndexableValue::try_from(s)?;
|
||||||
|
return Ok(Self::Indexable(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(format!("Invalid Value: {}", value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{IndexableValue, Value};
|
use super::{IndexableValue, Value};
|
||||||
use crate::error::TypeConversionError::UnknownType;
|
use crate::error::TypeConversionError::UnknownType;
|
||||||
|
use crate::type_system::Value::{Indexable, Number};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_encode_number() {
|
fn test_encode_number() {
|
||||||
|
|
@ -213,4 +293,25 @@ mod tests {
|
||||||
Err(UnknownType { oid: 2950, size: 8 })
|
Err(UnknownType { oid: 2950, size: 8 })
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_value_stringification() {
|
||||||
|
let pairs = vec![
|
||||||
|
(Number(1.0), "Number(1)"),
|
||||||
|
(
|
||||||
|
Indexable(IndexableValue::String("hello".to_string())),
|
||||||
|
"Indexable(String(hello))",
|
||||||
|
),
|
||||||
|
(Indexable(IndexableValue::Int(123)), "Indexable(Int(123))"),
|
||||||
|
(Indexable(IndexableValue::Uuid(123)), "Indexable(Uuid(123))"),
|
||||||
|
];
|
||||||
|
|
||||||
|
for (value, string) in pairs {
|
||||||
|
let serialized = String::from(value.clone());
|
||||||
|
assert_eq!(serialized, string);
|
||||||
|
|
||||||
|
let deserialized = Value::try_from(serialized);
|
||||||
|
assert_eq!(deserialized, Ok(value));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue