feat: add type system encoding to text bytes
This commit is contained in:
parent
f47fd24232
commit
7773a2585e
2 changed files with 170 additions and 0 deletions
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::num::{ParseFloatError, ParseIntError};
|
||||||
|
use std::str::Utf8Error;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use crate::internals::row::ColumnPosition;
|
use crate::internals::row::ColumnPosition;
|
||||||
use crate::schema::{ColumnName, TableName};
|
use crate::schema::{ColumnName, TableName};
|
||||||
|
|
@ -25,3 +27,18 @@ pub enum Error {
|
||||||
#[error("table {0} cannot be indexed on column {1}")]
|
#[error("table {0} cannot be indexed on column {1}")]
|
||||||
AttemptToIndexNonIndexableColumn(TableName, ColumnName),
|
AttemptToIndexNonIndexableColumn(TableName, ColumnName),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum TypeConversionError {
|
||||||
|
#[error("failed to decode bytes to string")]
|
||||||
|
TextDecodeFailed(#[from] Utf8Error),
|
||||||
|
#[error("failed to parse float from text")]
|
||||||
|
NumberDecodeFailed(#[from] ParseFloatError),
|
||||||
|
#[error("failed to parse int from text")]
|
||||||
|
IntDecodeFailed(#[from] ParseIntError),
|
||||||
|
#[error("uknown type with oid {oid} and size {size}")]
|
||||||
|
UnknownType {
|
||||||
|
oid: i32,
|
||||||
|
size: i32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
use crate::error::TypeConversionError;
|
||||||
|
|
||||||
// ==============Types================
|
// ==============Types================
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum DbType {
|
pub enum DbType {
|
||||||
|
|
@ -39,4 +41,155 @@ impl Value {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn type_oid(&self) -> i32 {
|
||||||
|
match self {
|
||||||
|
Self::Number(_) => 701,
|
||||||
|
Self::Indexable(val) => match val {
|
||||||
|
IndexableValue::String(_) => 25,
|
||||||
|
IndexableValue::Int(_) => 23,
|
||||||
|
IndexableValue::Uuid(_) => 2950,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn type_size(&self) -> i32 {
|
||||||
|
match self {
|
||||||
|
Self::Number(_) => 8,
|
||||||
|
Self::Indexable(val) => match val {
|
||||||
|
IndexableValue::String(_) => -2, // null terminated string
|
||||||
|
IndexableValue::Int(_) => 8,
|
||||||
|
IndexableValue::Uuid(_) => 16,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_text_bytes(&self) -> Vec<u8> {
|
||||||
|
match self {
|
||||||
|
Self::Number(n) => format!("{n}").into_bytes(),
|
||||||
|
Self::Indexable(i) => match i {
|
||||||
|
IndexableValue::String(s) => format!("{s}\0").into_bytes(),
|
||||||
|
IndexableValue::Int(i) => format!("{i}").into_bytes(),
|
||||||
|
IndexableValue::Uuid(u) => format!("{u}").into_bytes(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_text_bytes(bytes: &[u8], type_oid: i32, type_size: i32) -> Result<Value, TypeConversionError> {
|
||||||
|
match (type_oid, type_size) {
|
||||||
|
(701, 8) => {
|
||||||
|
let s = std::str::from_utf8(bytes)?;
|
||||||
|
let n = s.parse::<f64>()?;
|
||||||
|
Ok(Value::Number(n))
|
||||||
|
}
|
||||||
|
(25, -2) => {
|
||||||
|
let s = std::str::from_utf8(bytes)?;
|
||||||
|
let s = &s[..s.len() - 1]; // remove null terminator
|
||||||
|
Ok(Value::Indexable(IndexableValue::String(s.to_string())))
|
||||||
|
}
|
||||||
|
(23, 8) => {
|
||||||
|
let s = std::str::from_utf8(bytes)?;
|
||||||
|
let n = s.parse::<u64>()?;
|
||||||
|
Ok(Value::Indexable(IndexableValue::Int(n)))
|
||||||
|
}
|
||||||
|
(2950, 16) => {
|
||||||
|
let s = std::str::from_utf8(bytes)?;
|
||||||
|
let n = s.parse::<Uuid>()?;
|
||||||
|
Ok(Value::Indexable(IndexableValue::Uuid(n)))
|
||||||
|
}
|
||||||
|
(oid, size) => Err(TypeConversionError::UnknownType { oid, size }),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod tests {
|
||||||
|
use crate::error::TypeConversionError::UnknownType;
|
||||||
|
use super::{Value, IndexableValue};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_encode_number() {
|
||||||
|
let value = Value::Number(123.456);
|
||||||
|
let oid = value.type_oid();
|
||||||
|
let size = value.type_size();
|
||||||
|
|
||||||
|
let bytes = value.as_text_bytes();
|
||||||
|
let from_bytes = Value::from_text_bytes(&bytes, oid, size).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(value, from_bytes);
|
||||||
|
|
||||||
|
assert_eq!(oid, 701);
|
||||||
|
assert_eq!(size, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_encode_string() {
|
||||||
|
let value = Value::Indexable(IndexableValue::String("hello".to_string()));
|
||||||
|
let oid = value.type_oid();
|
||||||
|
let size = value.type_size();
|
||||||
|
|
||||||
|
let bytes = value.as_text_bytes();
|
||||||
|
let from_bytes = Value::from_text_bytes(&bytes, oid, size).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(value, from_bytes);
|
||||||
|
|
||||||
|
assert_eq!(oid, 25);
|
||||||
|
assert_eq!(size, -2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_encode_string_utf8() {
|
||||||
|
let value = Value::Indexable(IndexableValue::String("#速度与激情9 早上好中国 现在我有冰激淋 我很喜欢冰激淋 但是《速度与激情9》比冰激淋 🍧🍦🍨".to_string()));
|
||||||
|
let oid = value.type_oid();
|
||||||
|
let size = value.type_size();
|
||||||
|
|
||||||
|
let bytes = value.as_text_bytes();
|
||||||
|
let from_bytes = Value::from_text_bytes(&bytes, oid, size).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(value, from_bytes);
|
||||||
|
|
||||||
|
assert_eq!(oid, 25);
|
||||||
|
assert_eq!(size, -2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_encode_int() {
|
||||||
|
let value = Value::Indexable(IndexableValue::Int(123));
|
||||||
|
let oid = value.type_oid();
|
||||||
|
let size = value.type_size();
|
||||||
|
|
||||||
|
let bytes = value.as_text_bytes();
|
||||||
|
let from_bytes = Value::from_text_bytes(&bytes, oid, size).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(value, from_bytes);
|
||||||
|
|
||||||
|
assert_eq!(oid, 23);
|
||||||
|
assert_eq!(size, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_encode_uuid() {
|
||||||
|
let value = Value::Indexable(IndexableValue::Uuid(123));
|
||||||
|
let oid = value.type_oid();
|
||||||
|
let size = value.type_size();
|
||||||
|
|
||||||
|
let bytes = value.as_text_bytes();
|
||||||
|
let from_bytes = Value::from_text_bytes(&bytes, oid, size).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(value, from_bytes);
|
||||||
|
|
||||||
|
assert_eq!(oid, 2950);
|
||||||
|
assert_eq!(size, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_mismatched_size() {
|
||||||
|
let value = Value::Indexable(IndexableValue::Uuid(123));
|
||||||
|
let oid = value.type_oid();
|
||||||
|
let size = 8;
|
||||||
|
|
||||||
|
let bytes = value.as_text_bytes();
|
||||||
|
let from_bytes = Value::from_text_bytes(&bytes, oid, size);
|
||||||
|
|
||||||
|
assert!(matches!(from_bytes, Err(UnknownType { oid: 2950, size: 8 })))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue