diff --git a/docs/queries.md b/docs/queries.md index 0f7620fc3..c5a35f8f9 100644 --- a/docs/queries.md +++ b/docs/queries.md @@ -98,18 +98,36 @@ The `DbKey` is an alias of `DbValue` and the value itself is an enum of valid ty ```Rust pub enum DbValue { Bytes(Vec), - Int(i64), - Uint(u64), - Float(DbFloat), + I64(i64), + U64(u64), + F64(DbF64), String(String), - VecInt(Vec), - VecUint(Vec), - VecFloat(Vec), + VecI64(Vec), + VecU64(Vec), + VecF64(Vec), VecString(Vec), } ``` -Note the `DbFloat` type (i.e. `pub struct DbFloat(f64)`) which is a convenient wrapper of `f64` to provide opinionated implementation of some of the operations that are not floating type friendly like comparisons. In `agdb` the float type is using [`total_cmp` standard library function](https://doc.rust-lang.org/std/primitive.f64.html#method.total_cmp). Please see its documentation for important details about possible limits or issues on certain platforms. +Note the `DbF64` type (i.e. `pub struct DbF64(f64)`) which is a convenient wrapper of `f64` to provide opinionated implementation of some of the operations that are not floating type friendly like comparisons. In `agdb` the float type is using [`total_cmp` standard library function](https://doc.rust-lang.org/std/primitive.f64.html#method.total_cmp). Please see its documentation for important details about possible limits or issues on certain platforms. + +The enum variants can be conveniently accessed through methods named after each variant: + +```Rust +fn bytes(&self) -> Result<&Vec, DbError>; +fn to_f64(&self) -> Result; +fn to_i64(&self) -> Result; +fn to_u64(&self) -> Result; +fn to_string(&self) -> String; +fn string(&self) -> Result<&String, DbError>; +fn vec_f64(&self) -> Result<&Vec, DbError>; +fn vec_i64(&self) -> Result<&Vec, DbError>; +fn vec_u64(&self) -> Result<&Vec, DbError>; +fn vec_string(&self) -> Result<&Vec, DbError>; + +``` + +The numerical variants (`I64`, `U64`, `DbF64`) will attempt loss-less conversions where possible. To avoid copies all other variants return `&` where conversions are not possible even if they could be done in theory. The special case is `to_string()` provided by the `Display` trait. It converts any values into string (it also copies the `String` variant) and performs possibly lossy conversion from `Bytes` to UTF-8 string. # QueryError @@ -461,7 +479,7 @@ Selects elements identified by `ids` [`QueryIds`](#queryids--queryid) or search The result will contain: - number of returned elements -- list of elements with only keys and default (empty `Int(0)` values) +- list of elements with only keys and default (empty `I64(0)` values) ### Select key count diff --git a/src/agdb/db.rs b/src/agdb/db.rs index 4f2f8de28..e0269a127 100644 --- a/src/agdb/db.rs +++ b/src/agdb/db.rs @@ -5,7 +5,7 @@ pub mod db_key; pub mod db_key_value; pub mod db_value; -mod db_float; +mod db_f64; mod db_search_handlers; mod db_value_index; diff --git a/src/agdb/db/db_float.rs b/src/agdb/db/db_f64.rs similarity index 64% rename from src/agdb/db/db_float.rs rename to src/agdb/db/db_f64.rs index 624aa8406..986e3e26f 100644 --- a/src/agdb/db/db_float.rs +++ b/src/agdb/db/db_f64.rs @@ -11,56 +11,57 @@ use std::hash::Hasher; /// [docs](https://doc.rust-lang.org/std/primitive.f64.html#method.total_cmp) /// to understand how it handles NaNs and other edge cases /// of floating point numbers. -#[derive(Clone, Debug)] -pub struct DbFloat(f64); +#[derive(Clone, Copy, Debug)] +pub struct DbF64(f64); -impl DbFloat { +impl DbF64 { + #[allow(clippy::wrong_self_convention)] pub fn to_f64(&self) -> f64 { self.0 } } -impl Eq for DbFloat {} +impl Eq for DbF64 {} -impl Hash for DbFloat { +impl Hash for DbF64 { fn hash(&self, state: &mut H) { self.0.to_bits().hash(state) } } -impl Ord for DbFloat { +impl Ord for DbF64 { fn cmp(&self, other: &Self) -> Ordering { self.0.total_cmp(&other.0) } } -impl PartialEq for DbFloat { +impl PartialEq for DbF64 { fn eq(&self, other: &Self) -> bool { self.0.total_cmp(&other.0) == Ordering::Equal } } -impl PartialOrd for DbFloat { +impl PartialOrd for DbF64 { fn partial_cmp(&self, other: &Self) -> Option { Some(self.0.total_cmp(&other.0)) } } -impl From for DbFloat { +impl From for DbF64 { fn from(value: f32) -> Self { - DbFloat(value.into()) + DbF64(value.into()) } } -impl From for DbFloat { +impl From for DbF64 { fn from(value: f64) -> Self { - DbFloat(value) + DbF64(value) } } -impl Serialize for DbFloat { +impl Serialize for DbF64 { fn deserialize(bytes: &[u8]) -> Result { - Ok(DbFloat::from(f64::deserialize(bytes)?)) + Ok(DbF64::from(f64::deserialize(bytes)?)) } fn serialize(&self) -> Vec { @@ -72,7 +73,7 @@ impl Serialize for DbFloat { } } -impl StableHash for DbFloat { +impl StableHash for DbF64 { fn stable_hash(&self) -> u64 { self.0.to_bits().stable_hash() } @@ -85,85 +86,86 @@ mod tests { use std::collections::HashSet; #[test] + #[allow(clippy::clone_on_copy)] fn derived_from_clone() { - let float = DbFloat::from(1.0_f64); + let float = DbF64::from(1.0_f64); let _other = float.clone(); let _other2 = float; } #[test] fn derived_from_debug() { - format!("{:?}", DbFloat::from(1.0_f64)); + format!("{:?}", DbF64::from(1.0_f64)); } #[test] fn derived_from_eq() { - let float = DbFloat::from(1.0_f64); - let other = DbFloat::from(1.0_f64); + let float = DbF64::from(1.0_f64); + let other = DbF64::from(1.0_f64); assert_eq!(float, other); } #[test] fn derived_from_hash() { - let mut set = HashSet::::new(); - set.insert(DbFloat::from(1.0_f64)); + let mut set = HashSet::::new(); + set.insert(DbF64::from(1.0_f64)); } #[test] fn derived_from_ord() { - assert_eq!(DbFloat::from(1.0).cmp(&DbFloat::from(1.0)), Ordering::Equal); + assert_eq!(DbF64::from(1.0).cmp(&DbF64::from(1.0)), Ordering::Equal); } #[test] fn derived_from_partial_ord() { let mut vec = vec![ - DbFloat::from(1.1_f64), - DbFloat::from(1.3_f64), - DbFloat::from(-3.333_f64), + DbF64::from(1.1_f64), + DbF64::from(1.3_f64), + DbF64::from(-3.333_f64), ]; vec.sort(); assert_eq!( vec, vec![ - DbFloat::from(-3.333_f64), - DbFloat::from(1.1_f64), - DbFloat::from(1.3_f64) + DbF64::from(-3.333_f64), + DbF64::from(1.1_f64), + DbF64::from(1.3_f64) ] ); } #[test] fn from_f32() { - let _ = DbFloat::from(1.0_f32); + let _ = DbF64::from(1.0_f32); } #[test] fn from_f64() { - let _ = DbFloat::from(1.0_f64); + let _ = DbF64::from(1.0_f64); } #[test] fn serialize() { - let float = DbFloat::from(0.1_f64 + 0.2_f64); + let float = DbF64::from(0.1_f64 + 0.2_f64); let bytes = float.serialize(); assert_eq!(bytes.len() as u64, float.serialized_size()); - let actual = DbFloat::deserialize(&bytes).unwrap(); + let actual = DbF64::deserialize(&bytes).unwrap(); assert_eq!(float, actual); } #[test] fn stable_hash() { - let hash = DbFloat::from(1.0_f64).stable_hash(); + let hash = DbF64::from(1.0_f64).stable_hash(); assert_ne!(hash, 0); } #[test] fn to_f64() { - let _to_f64 = DbFloat::from(1.0_f64).to_f64(); + let _to_f64 = DbF64::from(1.0_f64).to_f64(); } } diff --git a/src/agdb/db/db_key_value.rs b/src/agdb/db/db_key_value.rs index cfa603524..f8a530004 100644 --- a/src/agdb/db/db_key_value.rs +++ b/src/agdb/db/db_key_value.rs @@ -78,8 +78,8 @@ mod tests { format!( "{:?}", DbKeyValue { - key: DbKey::Int(0), - value: DbKey::Int(0) + key: DbKey::I64(0), + value: DbKey::I64(0) } ); } @@ -87,12 +87,12 @@ mod tests { fn derived_from_partial_eq() { assert_eq!( DbKeyValue { - key: DbKey::Int(0), - value: DbKey::Int(0) + key: DbKey::I64(0), + value: DbKey::I64(0) }, DbKeyValue { - key: DbKey::Int(0), - value: DbKey::Int(0) + key: DbKey::I64(0), + value: DbKey::I64(0) } ); } diff --git a/src/agdb/db/db_value.rs b/src/agdb/db/db_value.rs index 1e4e03579..8ea1ed9c2 100644 --- a/src/agdb/db/db_value.rs +++ b/src/agdb/db/db_value.rs @@ -1,5 +1,5 @@ use super::db_error::DbError; -use super::db_float::DbFloat; +use super::db_f64::DbF64; use super::db_value_index::DbValueIndex; use crate::storage::Storage; use crate::storage::StorageIndex; @@ -24,41 +24,188 @@ pub enum DbValue { Bytes(Vec), /// 64-bit wide signed integer - Int(i64), + I64(i64), /// 64-bit wide unsigned integer - Uint(u64), + U64(u64), /// 64-bit floating point number - Float(DbFloat), + F64(DbF64), /// UTF-8 string String(String), /// List of 64-bit wide signed integers - VecInt(Vec), + VecI64(Vec), /// List of 64-bit wide unsigned integers - VecUint(Vec), + VecU64(Vec), /// List of 64-bit floating point numbers - VecFloat(Vec), + VecF64(Vec), /// List of UTF-8 strings VecString(Vec), } pub(crate) const BYTES_META_VALUE: u8 = 1_u8; -pub(crate) const INT_META_VALUE: u8 = 2_u8; -pub(crate) const UINT_META_VALUE: u8 = 3_u8; -pub(crate) const FLOAT_META_VALUE: u8 = 4_u8; +pub(crate) const I64_META_VALUE: u8 = 2_u8; +pub(crate) const U64_META_VALUE: u8 = 3_u8; +pub(crate) const F64_META_VALUE: u8 = 4_u8; pub(crate) const STRING_META_VALUE: u8 = 5_u8; -pub(crate) const VEC_INT_META_VALUE: u8 = 6_u8; -pub(crate) const VEC_UINT_META_VALUE: u8 = 7_u8; -pub(crate) const VEC_FLOAT_META_VALUE: u8 = 8_u8; +pub(crate) const VEC_I64_META_VALUE: u8 = 6_u8; +pub(crate) const VEC_U64_META_VALUE: u8 = 7_u8; +pub(crate) const VEC_F64_META_VALUE: u8 = 8_u8; pub(crate) const VEC_STRING_META_VALUE: u8 = 9_u8; impl DbValue { + /// Returns `&Vec` or an error if the value is + /// of a different type. + pub fn bytes(&self) -> Result<&Vec, DbError> { + match self { + DbValue::Bytes(v) => Ok(v), + DbValue::I64(_) => Self::type_error("i64", "bytes"), + DbValue::U64(_) => Self::type_error("u64", "bytes"), + DbValue::F64(_) => Self::type_error("f64", "bytes"), + DbValue::String(_) => Self::type_error("string", "bytes"), + DbValue::VecI64(_) => Self::type_error("vec", "bytes"), + DbValue::VecU64(_) => Self::type_error("vec", "bytes"), + DbValue::VecF64(_) => Self::type_error("vec", "bytes"), + DbValue::VecString(_) => Self::type_error("vec", "bytes"), + } + } + + /// Returns `&String` or an error if the value is + /// of a different type. + pub fn string(&self) -> Result<&String, DbError> { + match self { + DbValue::Bytes(_) => Self::type_error("bytes", "string"), + DbValue::I64(_) => Self::type_error("i64", "string"), + DbValue::U64(_) => Self::type_error("u64", "string"), + DbValue::F64(_) => Self::type_error("f64", "string"), + DbValue::String(v) => Ok(v), + DbValue::VecI64(_) => Self::type_error("vec", "string"), + DbValue::VecU64(_) => Self::type_error("vec", "string"), + DbValue::VecF64(_) => Self::type_error("vec", "string"), + DbValue::VecString(_) => Self::type_error("vec", "string"), + } + } + + /// Returns `DbF64` possibly converted from `i64` or `u64` + /// or na error if the conversion failed or the value is of + /// a different type. + pub fn to_f64(&self) -> Result { + match self { + DbValue::Bytes(_) => Self::type_error("bytes", "f64"), + DbValue::I64(v) => Ok(DbF64::from(f64::from(i32::try_from(*v)?))), + DbValue::U64(v) => Ok(DbF64::from(f64::from(u32::try_from(*v)?))), + DbValue::F64(v) => Ok(*v), + DbValue::String(_) => Self::type_error("string", "f64"), + DbValue::VecI64(_) => Self::type_error("vec", "f64"), + DbValue::VecU64(_) => Self::type_error("vec", "f64"), + DbValue::VecF64(_) => Self::type_error("vec", "f64"), + DbValue::VecString(_) => Self::type_error("vec", "f64"), + } + } + + /// Returns `i64` possibly converted from `u64` + /// or na error if the conversion failed or the value is of + /// a different type. + pub fn to_i64(&self) -> Result { + match self { + DbValue::Bytes(_) => Self::type_error("bytes", "i64"), + DbValue::I64(v) => Ok(*v), + DbValue::U64(v) => Ok(i64::try_from(*v)?), + DbValue::F64(_) => Self::type_error("f64", "i64"), + DbValue::String(_) => Self::type_error("string", "i64"), + DbValue::VecI64(_) => Self::type_error("vec", "i64"), + DbValue::VecU64(_) => Self::type_error("vec", "i64"), + DbValue::VecF64(_) => Self::type_error("vec", "i64"), + DbValue::VecString(_) => Self::type_error("vec", "i64"), + } + } + + /// Returns `u64` possibly converted from `i64` + /// or na error if the conversion failed or the value is of + /// a different type. + pub fn to_u64(&self) -> Result { + match self { + DbValue::Bytes(_) => Self::type_error("bytes", "u64"), + DbValue::I64(v) => Ok(u64::try_from(*v)?), + DbValue::U64(v) => Ok(*v), + DbValue::F64(_) => Self::type_error("f64", "u64"), + DbValue::String(_) => Self::type_error("string", "u64"), + DbValue::VecI64(_) => Self::type_error("vec", "u64"), + DbValue::VecU64(_) => Self::type_error("vec", "u64"), + DbValue::VecF64(_) => Self::type_error("vec", "u64"), + DbValue::VecString(_) => Self::type_error("vec", "u64"), + } + } + + /// Returns `&Vec` or an error if the value is + /// of a different type. + pub fn vec_f64(&self) -> Result<&Vec, DbError> { + match self { + DbValue::Bytes(_) => Self::type_error("bytes", "vec"), + DbValue::I64(_) => Self::type_error("i64", "vec"), + DbValue::U64(_) => Self::type_error("u64", "vec"), + DbValue::F64(_) => Self::type_error("f64", "vec"), + DbValue::String(_) => Self::type_error("string", "vec"), + DbValue::VecI64(_) => Self::type_error("vec", "vec"), + DbValue::VecU64(_) => Self::type_error("vec", "vec"), + DbValue::VecF64(v) => Ok(v), + DbValue::VecString(_) => Self::type_error("vec", "vec"), + } + } + + /// Returns `&Vec` or an error if the value is + /// of a different type. + pub fn vec_i64(&self) -> Result<&Vec, DbError> { + match self { + DbValue::Bytes(_) => Self::type_error("bytes", "vec"), + DbValue::I64(_) => Self::type_error("i64", "vec"), + DbValue::U64(_) => Self::type_error("u64", "vec"), + DbValue::F64(_) => Self::type_error("f64", "vec"), + DbValue::String(_) => Self::type_error("string", "vec"), + DbValue::VecI64(v) => Ok(v), + DbValue::VecU64(_) => Self::type_error("vec", "vec"), + DbValue::VecF64(_) => Self::type_error("vec", "vec"), + DbValue::VecString(_) => Self::type_error("vec", "vec"), + } + } + + /// Returns `&Vec` or an error if the value is + /// of a different type. + pub fn vec_u64(&self) -> Result<&Vec, DbError> { + match self { + DbValue::Bytes(_) => Self::type_error("bytes", "vec"), + DbValue::I64(_) => Self::type_error("i64", "vec"), + DbValue::U64(_) => Self::type_error("u64", "vec"), + DbValue::F64(_) => Self::type_error("f64", "vec"), + DbValue::String(_) => Self::type_error("string", "vec"), + DbValue::VecI64(_) => Self::type_error("vec", "vec"), + DbValue::VecU64(v) => Ok(v), + DbValue::VecF64(_) => Self::type_error("vec", "vec"), + DbValue::VecString(_) => Self::type_error("vec", "vec"), + } + } + + /// Returns `&Vec` or an error if the value is + /// of a different type. + pub fn vec_string(&self) -> Result<&Vec, DbError> { + match self { + DbValue::Bytes(_) => Self::type_error("bytes", "vec"), + DbValue::I64(_) => Self::type_error("i64", "vec"), + DbValue::U64(_) => Self::type_error("u64", "vec"), + DbValue::F64(_) => Self::type_error("f64", "vec"), + DbValue::String(_) => Self::type_error("string", "vec"), + DbValue::VecI64(_) => Self::type_error("vec", "vec"), + DbValue::VecU64(_) => Self::type_error("vec", "vec"), + DbValue::VecF64(_) => Self::type_error("vec", "vec"), + DbValue::VecString(v) => Ok(v), + } + } + pub(crate) fn load_db_value( value_index: DbValueIndex, storage: &mut S, @@ -71,20 +218,20 @@ impl DbValue { DbValue::Bytes(storage.value_as_bytes(StorageIndex(value_index.index()))?) } } - INT_META_VALUE => { + I64_META_VALUE => { let mut bytes = [0_u8; 8]; bytes.copy_from_slice(value_index.value()); - DbValue::Int(i64::from_le_bytes(bytes)) + DbValue::I64(i64::from_le_bytes(bytes)) } - UINT_META_VALUE => { + U64_META_VALUE => { let mut bytes = [0_u8; 8]; bytes.copy_from_slice(value_index.value()); - DbValue::Uint(u64::from_le_bytes(bytes)) + DbValue::U64(u64::from_le_bytes(bytes)) } - FLOAT_META_VALUE => { + F64_META_VALUE => { let mut bytes = [0_u8; 8]; bytes.copy_from_slice(value_index.value()); - DbValue::Float(DbFloat::from(f64::from_le_bytes(bytes))) + DbValue::F64(DbF64::from(f64::from_le_bytes(bytes))) } STRING_META_VALUE => { if value_index.is_value() { @@ -93,14 +240,14 @@ impl DbValue { DbValue::String(storage.value::(StorageIndex(value_index.index()))?) } } - VEC_INT_META_VALUE => { - DbValue::VecInt(storage.value::>(StorageIndex(value_index.index()))?) + VEC_I64_META_VALUE => { + DbValue::VecI64(storage.value::>(StorageIndex(value_index.index()))?) } - VEC_UINT_META_VALUE => { - DbValue::VecUint(storage.value::>(StorageIndex(value_index.index()))?) + VEC_U64_META_VALUE => { + DbValue::VecU64(storage.value::>(StorageIndex(value_index.index()))?) } - VEC_FLOAT_META_VALUE => { - DbValue::VecFloat(storage.value::>(StorageIndex(value_index.index()))?) + VEC_F64_META_VALUE => { + DbValue::VecF64(storage.value::>(StorageIndex(value_index.index()))?) } VEC_STRING_META_VALUE => { DbValue::VecString(storage.value::>(StorageIndex(value_index.index()))?) @@ -122,16 +269,16 @@ impl DbValue { index.set_index(storage.insert_bytes(v)?.0); } } - DbValue::Int(v) => { - index.set_type(INT_META_VALUE); + DbValue::I64(v) => { + index.set_type(I64_META_VALUE); index.set_value(&v.to_le_bytes()); } - DbValue::Uint(v) => { - index.set_type(UINT_META_VALUE); + DbValue::U64(v) => { + index.set_type(U64_META_VALUE); index.set_value(&v.to_le_bytes()); } - DbValue::Float(v) => { - index.set_type(FLOAT_META_VALUE); + DbValue::F64(v) => { + index.set_type(F64_META_VALUE); index.set_value(&v.to_f64().to_le_bytes()); } DbValue::String(v) => { @@ -141,16 +288,16 @@ impl DbValue { index.set_index(storage.insert(v)?.0); } } - DbValue::VecInt(v) => { - index.set_type(VEC_INT_META_VALUE); + DbValue::VecI64(v) => { + index.set_type(VEC_I64_META_VALUE); index.set_index(storage.insert(v)?.0); } - DbValue::VecUint(v) => { - index.set_type(VEC_UINT_META_VALUE); + DbValue::VecU64(v) => { + index.set_type(VEC_U64_META_VALUE); index.set_index(storage.insert(v)?.0); } - DbValue::VecFloat(v) => { - index.set_type(VEC_FLOAT_META_VALUE); + DbValue::VecF64(v) => { + index.set_type(VEC_F64_META_VALUE); index.set_index(storage.insert(v)?.0); } DbValue::VecString(v) => { @@ -161,53 +308,59 @@ impl DbValue { Ok(index) } + + fn type_error(from: &str, to: &str) -> Result { + Err(DbError::from(format!( + "Type mismatch. Cannot convert '{from}' to '{to}'." + ))) + } } impl Default for DbValue { fn default() -> Self { - Self::Int(0) + Self::I64(0) } } impl From for DbValue { fn from(value: f32) -> Self { - DbValue::Float(value.into()) + DbValue::F64(value.into()) } } impl From for DbValue { fn from(value: f64) -> Self { - DbValue::Float(value.into()) + DbValue::F64(value.into()) } } -impl From for DbValue { - fn from(value: DbFloat) -> Self { - DbValue::Float(value) +impl From for DbValue { + fn from(value: DbF64) -> Self { + DbValue::F64(value) } } impl From for DbValue { fn from(value: i32) -> Self { - DbValue::Int(value.into()) + DbValue::I64(value.into()) } } impl From for DbValue { fn from(value: i64) -> Self { - DbValue::Int(value) + DbValue::I64(value) } } impl From for DbValue { fn from(value: u32) -> Self { - DbValue::Uint(value.into()) + DbValue::U64(value.into()) } } impl From for DbValue { fn from(value: u64) -> Self { - DbValue::Uint(value) + DbValue::U64(value) } } @@ -231,43 +384,43 @@ impl From<&str> for DbValue { impl From> for DbValue { fn from(value: Vec) -> Self { - DbValue::VecFloat(value.iter().map(|i| (*i).into()).collect()) + DbValue::VecF64(value.iter().map(|i| (*i).into()).collect()) } } impl From> for DbValue { fn from(value: Vec) -> Self { - DbValue::VecFloat(value.iter().map(|i| (*i).into()).collect()) + DbValue::VecF64(value.iter().map(|i| (*i).into()).collect()) } } -impl From> for DbValue { - fn from(value: Vec) -> Self { - DbValue::VecFloat(value) +impl From> for DbValue { + fn from(value: Vec) -> Self { + DbValue::VecF64(value) } } impl From> for DbValue { fn from(value: Vec) -> Self { - DbValue::VecInt(value.iter().map(|i| *i as i64).collect()) + DbValue::VecI64(value.iter().map(|i| *i as i64).collect()) } } impl From> for DbValue { fn from(value: Vec) -> Self { - DbValue::VecInt(value) + DbValue::VecI64(value) } } impl From> for DbValue { fn from(value: Vec) -> Self { - DbValue::VecUint(value.iter().map(|i| *i as u64).collect()) + DbValue::VecU64(value.iter().map(|i| *i as u64).collect()) } } impl From> for DbValue { fn from(value: Vec) -> Self { - DbValue::VecUint(value) + DbValue::VecU64(value) } } @@ -293,11 +446,11 @@ impl Display for DbValue { fn fmt(&self, f: &mut Formatter<'_>) -> DisplayResult { match self { DbValue::Bytes(v) => write!(f, "{}", String::from_utf8_lossy(v)), - DbValue::Int(v) => write!(f, "{}", v), - DbValue::Uint(v) => write!(f, "{}", v), - DbValue::Float(v) => write!(f, "{}", v.to_f64()), + DbValue::I64(v) => write!(f, "{}", v), + DbValue::U64(v) => write!(f, "{}", v), + DbValue::F64(v) => write!(f, "{}", v.to_f64()), DbValue::String(v) => write!(f, "{}", v), - DbValue::VecInt(v) => write!( + DbValue::VecI64(v) => write!( f, "[{}]", v.iter() @@ -305,7 +458,7 @@ impl Display for DbValue { .collect::>() .join(", ") ), - DbValue::VecUint(v) => write!( + DbValue::VecU64(v) => write!( f, "[{}]", v.iter() @@ -313,7 +466,7 @@ impl Display for DbValue { .collect::>() .join(", ") ), - DbValue::VecFloat(v) => write!( + DbValue::VecF64(v) => write!( f, "[{}]", v.iter() @@ -330,13 +483,13 @@ impl StableHash for DbValue { fn stable_hash(&self) -> u64 { match self { DbValue::Bytes(value) => value.stable_hash(), - DbValue::Int(value) => value.stable_hash(), - DbValue::Uint(value) => value.stable_hash(), - DbValue::Float(value) => value.stable_hash(), + DbValue::I64(value) => value.stable_hash(), + DbValue::U64(value) => value.stable_hash(), + DbValue::F64(value) => value.stable_hash(), DbValue::String(value) => value.stable_hash(), - DbValue::VecInt(value) => value.stable_hash(), - DbValue::VecUint(value) => value.stable_hash(), - DbValue::VecFloat(value) => value.stable_hash(), + DbValue::VecI64(value) => value.stable_hash(), + DbValue::VecU64(value) => value.stable_hash(), + DbValue::VecF64(value) => value.stable_hash(), DbValue::VecString(value) => value.stable_hash(), } } @@ -436,42 +589,36 @@ mod tests { DbValue::from(Vec::::new()), DbValue::Bytes { .. } )); - assert!(matches!(DbValue::from(1_i32), DbValue::Int { .. })); - assert!(matches!(DbValue::from(1_i64), DbValue::Int { .. })); - assert!(matches!(DbValue::from(1_u32), DbValue::Uint { .. })); - assert!(matches!(DbValue::from(1_u64), DbValue::Uint { .. })); - assert!(matches!(DbValue::from(1.0_f32), DbValue::Float { .. })); - assert!(matches!(DbValue::from(1.0_f64), DbValue::Float { .. })); + assert!(matches!(DbValue::from(1_i32), DbValue::I64 { .. })); + assert!(matches!(DbValue::from(1_i64), DbValue::I64 { .. })); + assert!(matches!(DbValue::from(1_u32), DbValue::U64 { .. })); + assert!(matches!(DbValue::from(1_u64), DbValue::U64 { .. })); + assert!(matches!(DbValue::from(1.0_f32), DbValue::F64 { .. })); + assert!(matches!(DbValue::from(1.0_f64), DbValue::F64 { .. })); assert!(matches!( - DbValue::from(DbFloat::from(1.0_f64)), - DbValue::Float { .. } + DbValue::from(DbF64::from(1.0_f64)), + DbValue::F64 { .. } )); assert!(matches!(DbValue::from(""), DbValue::String { .. })); assert!(matches!( DbValue::from(String::new()), DbValue::String { .. } )); - assert!(matches!(DbValue::from(vec![1_i32]), DbValue::VecInt { .. })); - assert!(matches!(DbValue::from(vec![1_i64]), DbValue::VecInt { .. })); - assert!(matches!( - DbValue::from(vec![1_u32]), - DbValue::VecUint { .. } - )); - assert!(matches!( - DbValue::from(vec![1_u64]), - DbValue::VecUint { .. } - )); + assert!(matches!(DbValue::from(vec![1_i32]), DbValue::VecI64 { .. })); + assert!(matches!(DbValue::from(vec![1_i64]), DbValue::VecI64 { .. })); + assert!(matches!(DbValue::from(vec![1_u32]), DbValue::VecU64 { .. })); + assert!(matches!(DbValue::from(vec![1_u64]), DbValue::VecU64 { .. })); assert!(matches!( DbValue::from(vec![1.0_f32]), - DbValue::VecFloat { .. } + DbValue::VecF64 { .. } )); assert!(matches!( DbValue::from(vec![1.0_f64]), - DbValue::VecFloat { .. } + DbValue::VecF64 { .. } )); assert!(matches!( - DbValue::from(vec![DbFloat::from(1.0_f64)]), - DbValue::VecFloat { .. } + DbValue::from(vec![DbF64::from(1.0_f64)]), + DbValue::VecF64 { .. } )); assert!(matches!(DbValue::from(vec![""]), DbValue::VecString { .. })); assert!(matches!( @@ -501,4 +648,504 @@ mod tests { let _ = DbValue::load_db_value(DbValueIndex::new(), &mut storage); } + + #[test] + fn to_u64() { + assert_eq!(DbValue::from(1_u64).to_u64().unwrap(), 1_u64); + assert_eq!(DbValue::from(1_i64).to_u64().unwrap(), 1_u64); + assert_eq!( + DbValue::from(-1_i64).to_u64(), + Err(DbError::from( + "out of range integral type conversion attempted" + )) + ); + assert_eq!( + DbValue::from(vec![0_u8; 1]).to_u64(), + Err(DbError::from( + "Type mismatch. Cannot convert 'bytes' to 'u64'." + )) + ); + assert_eq!( + DbValue::from(1.1).to_u64(), + Err(DbError::from( + "Type mismatch. Cannot convert 'f64' to 'u64'." + )) + ); + assert_eq!( + DbValue::from("").to_u64(), + Err(DbError::from( + "Type mismatch. Cannot convert 'string' to 'u64'." + )) + ); + assert_eq!( + DbValue::from(vec![0_u64]).to_u64(), + Err(DbError::from( + "Type mismatch. Cannot convert 'vec' to 'u64'." + )) + ); + assert_eq!( + DbValue::from(vec![0_i64]).to_u64(), + Err(DbError::from( + "Type mismatch. Cannot convert 'vec' to 'u64'." + )) + ); + assert_eq!( + DbValue::from(vec![1.1]).to_u64(), + Err(DbError::from( + "Type mismatch. Cannot convert 'vec' to 'u64'." + )) + ); + assert_eq!( + DbValue::from(vec![""]).to_u64(), + Err(DbError::from( + "Type mismatch. Cannot convert 'vec' to 'u64'." + )) + ); + } + + #[test] + fn to_i64() { + assert_eq!(DbValue::from(-1_i64).to_i64().unwrap(), -1_i64); + assert_eq!(DbValue::from(1_u64).to_i64().unwrap(), 1_i64); + assert_eq!( + DbValue::from(u64::MAX).to_i64(), + Err(DbError::from( + "out of range integral type conversion attempted" + )) + ); + assert_eq!( + DbValue::from(vec![0_u8; 1]).to_i64(), + Err(DbError::from( + "Type mismatch. Cannot convert 'bytes' to 'i64'." + )) + ); + assert_eq!( + DbValue::from(1.1).to_i64(), + Err(DbError::from( + "Type mismatch. Cannot convert 'f64' to 'i64'." + )) + ); + assert_eq!( + DbValue::from("").to_i64(), + Err(DbError::from( + "Type mismatch. Cannot convert 'string' to 'i64'." + )) + ); + assert_eq!( + DbValue::from(vec![0_u64]).to_i64(), + Err(DbError::from( + "Type mismatch. Cannot convert 'vec' to 'i64'." + )) + ); + assert_eq!( + DbValue::from(vec![0_i64]).to_i64(), + Err(DbError::from( + "Type mismatch. Cannot convert 'vec' to 'i64'." + )) + ); + assert_eq!( + DbValue::from(vec![1.1]).to_i64(), + Err(DbError::from( + "Type mismatch. Cannot convert 'vec' to 'i64'." + )) + ); + assert_eq!( + DbValue::from(vec![""]).to_i64(), + Err(DbError::from( + "Type mismatch. Cannot convert 'vec' to 'i64'." + )) + ); + } + + #[test] + fn to_f64() { + assert_eq!( + DbValue::from(1.1_f64).to_f64().unwrap(), + DbF64::from(1.1_f64) + ); + assert_eq!( + DbValue::from(-1_i64).to_f64().unwrap(), + DbF64::from(-1.0_f64) + ); + assert_eq!(DbValue::from(1_i64).to_f64().unwrap(), DbF64::from(1.0_f64)); + assert_eq!(DbValue::from(1_u64).to_f64().unwrap(), DbF64::from(1.0_f64)); + assert_eq!( + DbValue::from(i64::MAX).to_f64(), + Err(DbError::from( + "out of range integral type conversion attempted" + )) + ); + assert_eq!( + DbValue::from(u64::MAX).to_f64(), + Err(DbError::from( + "out of range integral type conversion attempted" + )) + ); + assert_eq!( + DbValue::from(vec![0_u8; 1]).to_f64(), + Err(DbError::from( + "Type mismatch. Cannot convert 'bytes' to 'f64'." + )) + ); + assert_eq!( + DbValue::from("").to_f64(), + Err(DbError::from( + "Type mismatch. Cannot convert 'string' to 'f64'." + )) + ); + assert_eq!( + DbValue::from(vec![0_u64]).to_f64(), + Err(DbError::from( + "Type mismatch. Cannot convert 'vec' to 'f64'." + )) + ); + assert_eq!( + DbValue::from(vec![0_i64]).to_f64(), + Err(DbError::from( + "Type mismatch. Cannot convert 'vec' to 'f64'." + )) + ); + assert_eq!( + DbValue::from(vec![1.1]).to_f64(), + Err(DbError::from( + "Type mismatch. Cannot convert 'vec' to 'f64'." + )) + ); + assert_eq!( + DbValue::from(vec![""]).to_f64(), + Err(DbError::from( + "Type mismatch. Cannot convert 'vec' to 'f64'." + )) + ); + } + + #[test] + fn vec_i64() { + assert_eq!( + DbValue::from(vec![-1_i64]).vec_i64().unwrap(), + &vec![-1_i64] + ); + assert_eq!( + DbValue::from(-1_i64).vec_i64(), + Err(DbError::from( + "Type mismatch. Cannot convert 'i64' to 'vec'." + )) + ); + assert_eq!( + DbValue::from(1_u64).vec_i64(), + Err(DbError::from( + "Type mismatch. Cannot convert 'u64' to 'vec'." + )) + ); + assert_eq!( + DbValue::from(vec![1_u64]).vec_i64(), + Err(DbError::from( + "Type mismatch. Cannot convert 'vec' to 'vec'." + )) + ); + assert_eq!( + DbValue::from(1.1).vec_i64(), + Err(DbError::from( + "Type mismatch. Cannot convert 'f64' to 'vec'." + )) + ); + assert_eq!( + DbValue::from(vec![0_u8; 1]).vec_i64(), + Err(DbError::from( + "Type mismatch. Cannot convert 'bytes' to 'vec'." + )) + ); + assert_eq!( + DbValue::from("").vec_i64(), + Err(DbError::from( + "Type mismatch. Cannot convert 'string' to 'vec'." + )) + ); + assert_eq!( + DbValue::from(vec![1.1]).vec_i64(), + Err(DbError::from( + "Type mismatch. Cannot convert 'vec' to 'vec'." + )) + ); + assert_eq!( + DbValue::from(vec![""]).vec_i64(), + Err(DbError::from( + "Type mismatch. Cannot convert 'vec' to 'vec'." + )) + ); + } + + #[test] + fn vec_u64() { + assert_eq!(DbValue::from(vec![1_u64]).vec_u64().unwrap(), &vec![1_u64]); + assert_eq!( + DbValue::from(-1_i64).vec_u64(), + Err(DbError::from( + "Type mismatch. Cannot convert 'i64' to 'vec'." + )) + ); + assert_eq!( + DbValue::from(1_u64).vec_u64(), + Err(DbError::from( + "Type mismatch. Cannot convert 'u64' to 'vec'." + )) + ); + assert_eq!( + DbValue::from(vec![-1_i64]).vec_u64(), + Err(DbError::from( + "Type mismatch. Cannot convert 'vec' to 'vec'." + )) + ); + assert_eq!( + DbValue::from(1.1).vec_u64(), + Err(DbError::from( + "Type mismatch. Cannot convert 'f64' to 'vec'." + )) + ); + assert_eq!( + DbValue::from(vec![0_u8; 1]).vec_u64(), + Err(DbError::from( + "Type mismatch. Cannot convert 'bytes' to 'vec'." + )) + ); + assert_eq!( + DbValue::from("").vec_u64(), + Err(DbError::from( + "Type mismatch. Cannot convert 'string' to 'vec'." + )) + ); + assert_eq!( + DbValue::from(vec![1.1]).vec_u64(), + Err(DbError::from( + "Type mismatch. Cannot convert 'vec' to 'vec'." + )) + ); + assert_eq!( + DbValue::from(vec![""]).vec_u64(), + Err(DbError::from( + "Type mismatch. Cannot convert 'vec' to 'vec'." + )) + ); + } + + #[test] + fn vec_f64() { + assert_eq!( + DbValue::from(vec![1.1]).vec_f64().unwrap(), + &vec![DbF64::from(1.1_f64)] + ); + assert_eq!( + DbValue::from(-1_i64).vec_f64(), + Err(DbError::from( + "Type mismatch. Cannot convert 'i64' to 'vec'." + )) + ); + assert_eq!( + DbValue::from(1_u64).vec_f64(), + Err(DbError::from( + "Type mismatch. Cannot convert 'u64' to 'vec'." + )) + ); + assert_eq!( + DbValue::from(vec![-1_i64]).vec_f64(), + Err(DbError::from( + "Type mismatch. Cannot convert 'vec' to 'vec'." + )) + ); + assert_eq!( + DbValue::from(vec![1_u64]).vec_f64(), + Err(DbError::from( + "Type mismatch. Cannot convert 'vec' to 'vec'." + )) + ); + assert_eq!( + DbValue::from(1.1).vec_f64(), + Err(DbError::from( + "Type mismatch. Cannot convert 'f64' to 'vec'." + )) + ); + assert_eq!( + DbValue::from(vec![0_u8; 1]).vec_f64(), + Err(DbError::from( + "Type mismatch. Cannot convert 'bytes' to 'vec'." + )) + ); + assert_eq!( + DbValue::from("").vec_f64(), + Err(DbError::from( + "Type mismatch. Cannot convert 'string' to 'vec'." + )) + ); + assert_eq!( + DbValue::from(vec![""]).vec_f64(), + Err(DbError::from( + "Type mismatch. Cannot convert 'vec' to 'vec'." + )) + ); + } + + #[test] + fn vec_string() { + assert_eq!( + DbValue::from(vec![""]).vec_string().unwrap(), + &vec!["".to_string()] + ); + assert_eq!( + DbValue::from(-1_i64).vec_string(), + Err(DbError::from( + "Type mismatch. Cannot convert 'i64' to 'vec'." + )) + ); + assert_eq!( + DbValue::from(1_u64).vec_string(), + Err(DbError::from( + "Type mismatch. Cannot convert 'u64' to 'vec'." + )) + ); + assert_eq!( + DbValue::from(vec![-1_i64]).vec_string(), + Err(DbError::from( + "Type mismatch. Cannot convert 'vec' to 'vec'." + )) + ); + assert_eq!( + DbValue::from(vec![1_u64]).vec_string(), + Err(DbError::from( + "Type mismatch. Cannot convert 'vec' to 'vec'." + )) + ); + assert_eq!( + DbValue::from(1.1).vec_string(), + Err(DbError::from( + "Type mismatch. Cannot convert 'f64' to 'vec'." + )) + ); + assert_eq!( + DbValue::from(vec![1.1]).vec_string(), + Err(DbError::from( + "Type mismatch. Cannot convert 'vec' to 'vec'." + )) + ); + assert_eq!( + DbValue::from(vec![0_u8; 1]).vec_string(), + Err(DbError::from( + "Type mismatch. Cannot convert 'bytes' to 'vec'." + )) + ); + assert_eq!( + DbValue::from("").vec_string(), + Err(DbError::from( + "Type mismatch. Cannot convert 'string' to 'vec'." + )) + ); + } + + #[test] + fn bytes() { + assert_eq!(DbValue::from(vec![1_u8]).bytes().unwrap(), &vec![1_u8]); + assert_eq!( + DbValue::from(-1_i64).bytes(), + Err(DbError::from( + "Type mismatch. Cannot convert 'i64' to 'bytes'." + )) + ); + assert_eq!( + DbValue::from(1_u64).bytes(), + Err(DbError::from( + "Type mismatch. Cannot convert 'u64' to 'bytes'." + )) + ); + assert_eq!( + DbValue::from(vec![-1_i64]).bytes(), + Err(DbError::from( + "Type mismatch. Cannot convert 'vec' to 'bytes'." + )) + ); + assert_eq!( + DbValue::from(vec![1_u64]).bytes(), + Err(DbError::from( + "Type mismatch. Cannot convert 'vec' to 'bytes'." + )) + ); + assert_eq!( + DbValue::from(1.1).bytes(), + Err(DbError::from( + "Type mismatch. Cannot convert 'f64' to 'bytes'." + )) + ); + assert_eq!( + DbValue::from(vec![1.1]).bytes(), + Err(DbError::from( + "Type mismatch. Cannot convert 'vec' to 'bytes'." + )) + ); + assert_eq!( + DbValue::from("").bytes(), + Err(DbError::from( + "Type mismatch. Cannot convert 'string' to 'bytes'." + )) + ); + assert_eq!( + DbValue::from(vec![""]).bytes(), + Err(DbError::from( + "Type mismatch. Cannot convert 'vec' to 'bytes'." + )) + ); + } + + #[test] + fn string() { + assert_eq!( + DbValue::from("hello").string().unwrap(), + &"hello".to_string() + ); + assert_eq!( + DbValue::from(vec![1_u8]).string(), + Err(DbError::from( + "Type mismatch. Cannot convert 'bytes' to 'string'." + )) + ); + assert_eq!( + DbValue::from(-1_i64).string(), + Err(DbError::from( + "Type mismatch. Cannot convert 'i64' to 'string'." + )) + ); + assert_eq!( + DbValue::from(1_u64).string(), + Err(DbError::from( + "Type mismatch. Cannot convert 'u64' to 'string'." + )) + ); + assert_eq!( + DbValue::from(vec![-1_i64]).string(), + Err(DbError::from( + "Type mismatch. Cannot convert 'vec' to 'string'." + )) + ); + assert_eq!( + DbValue::from(vec![1_u64]).string(), + Err(DbError::from( + "Type mismatch. Cannot convert 'vec' to 'string'." + )) + ); + assert_eq!( + DbValue::from(1.1).string(), + Err(DbError::from( + "Type mismatch. Cannot convert 'f64' to 'string'." + )) + ); + assert_eq!( + DbValue::from(vec![1.1]).string(), + Err(DbError::from( + "Type mismatch. Cannot convert 'vec' to 'string'." + )) + ); + assert_eq!( + DbValue::from(vec![""]).string(), + Err(DbError::from( + "Type mismatch. Cannot convert 'vec' to 'string'." + )) + ); + } } diff --git a/src/agdb/query/query_condition.rs b/src/agdb/query/query_condition.rs index 4c1983b07..653a0d4da 100644 --- a/src/agdb/query/query_condition.rs +++ b/src/agdb/query/query_condition.rs @@ -217,16 +217,16 @@ impl Comparison { (DbValue::String(left), DbValue::VecString(right)) => { right.iter().all(|x| left.contains(x)) } - (DbValue::VecInt(left), DbValue::Int(right)) => left.contains(right), - (DbValue::VecInt(left), DbValue::VecInt(right)) => { + (DbValue::VecI64(left), DbValue::I64(right)) => left.contains(right), + (DbValue::VecI64(left), DbValue::VecI64(right)) => { right.iter().all(|x| left.contains(x)) } - (DbValue::VecUint(left), DbValue::Uint(right)) => left.contains(right), - (DbValue::VecUint(left), DbValue::VecUint(right)) => { + (DbValue::VecU64(left), DbValue::U64(right)) => left.contains(right), + (DbValue::VecU64(left), DbValue::VecU64(right)) => { right.iter().all(|x| left.contains(x)) } - (DbValue::VecFloat(left), DbValue::Float(right)) => left.contains(right), - (DbValue::VecFloat(left), DbValue::VecFloat(right)) => { + (DbValue::VecF64(left), DbValue::F64(right)) => left.contains(right), + (DbValue::VecF64(left), DbValue::VecF64(right)) => { right.iter().all(|x| left.contains(x)) } (DbValue::VecString(left), DbValue::String(right)) => left.contains(right), @@ -254,7 +254,7 @@ mod tests { } ); - format!("{:?}", Comparison::Equal(DbValue::Int(0))); + format!("{:?}", Comparison::Equal(DbValue::I64(0))); format!("{:?}", CountComparison::Equal(0)); } @@ -270,7 +270,7 @@ mod tests { let right = left.clone(); assert_eq!(left, right); - let left = Comparison::Equal(DbValue::Int(0)); + let left = Comparison::Equal(DbValue::I64(0)); let right = left.clone(); assert_eq!(left, right); @@ -295,8 +295,8 @@ mod tests { ); assert_eq!( - Comparison::Equal(DbValue::Int(0)), - Comparison::Equal(DbValue::Int(0)) + Comparison::Equal(DbValue::I64(0)), + Comparison::Equal(DbValue::I64(0)) ); assert_eq!(CountComparison::Equal(0), CountComparison::Equal(0));