From 3bbedf5ab337d8c6d608ed0b24b9c656b0ee1004 Mon Sep 17 00:00:00 2001 From: metamuffin Date: Wed, 18 Feb 2026 13:24:44 +0100 Subject: dynamic typed db match values --- database/src/kv/binning.rs | 36 +++++++++++++++++++++++++++++++++--- database/src/kv/mod.rs | 3 +-- database/src/kv/tests.rs | 10 +++++----- database/src/lib.rs | 45 +++++++++++++++++++++++++++++++++++++++++++-- database/src/query_ser.rs | 21 ++++++++++++--------- 5 files changed, 94 insertions(+), 21 deletions(-) (limited to 'database') diff --git a/database/src/kv/binning.rs b/database/src/kv/binning.rs index 42e58fc..c41d6e9 100644 --- a/database/src/kv/binning.rs +++ b/database/src/kv/binning.rs @@ -4,7 +4,7 @@ Copyright (C) 2026 metamuffin */ -use crate::Filter; +use crate::{Filter, Value}; use jellyobject::{Object, Path}; /// Sorted list of components to bin objects by filtered values. @@ -88,8 +88,7 @@ impl Filter { Filter::Match(path, value) => { vec![vec![(BinningComponent::Match(path.to_owned()), { let mut co = Vec::new(); - co.extend((value.len() as u32).to_be_bytes()); - co.extend(value); + value.write_with_len(&mut co); co })]] } @@ -100,6 +99,37 @@ impl Filter { } } +impl Value { + pub fn write_with_len(&self, out: &mut Vec) { + match self { + Value::Tag(tag) => { + out.extend(4u32.to_be_bytes()); + out.extend(tag.0.to_be_bytes()); + } + Value::U32(x) => { + out.extend(4u32.to_be_bytes()); + out.extend(x.to_be_bytes()); + } + Value::U64(x) => { + out.extend(8u32.to_be_bytes()); + out.extend(x.to_be_bytes()); + } + Value::I64(x) => { + out.extend(8u32.to_be_bytes()); + out.extend(x.to_be_bytes()); + } + Value::String(s) => { + out.extend((s.len() as u32).to_be_bytes()); + out.extend(s.as_bytes()); + } + Value::Binary(s) => { + out.extend((s.len() as u32).to_be_bytes()); + out.extend(s); + } + } + } +} + #[cfg(test)] mod test { use jellyobject::{Path, Tag}; diff --git a/database/src/kv/mod.rs b/database/src/kv/mod.rs index f5dcc72..f90f07e 100644 --- a/database/src/kv/mod.rs +++ b/database/src/kv/mod.rs @@ -14,8 +14,6 @@ pub mod sort; #[cfg(test)] pub mod tests; -use std::borrow::Cow; - use crate::{ Database, Query, RowNum, Transaction, kv::{ @@ -29,6 +27,7 @@ use crate::{ use anyhow::{Result, anyhow}; use jellyobject::ObjectBuffer; use log::{debug, info}; +use std::borrow::Cow; pub type SubtreeNum = u32; diff --git a/database/src/kv/tests.rs b/database/src/kv/tests.rs index 5b587ed..85ee5d7 100644 --- a/database/src/kv/tests.rs +++ b/database/src/kv/tests.rs @@ -1,5 +1,5 @@ use crate::{ - Database, Filter, Query, Sort, + Database, Filter, Query, Sort, Value, test_shared::{AGE, NAME, new_alice, new_bob, new_charlie}, }; use anyhow::Result; @@ -67,7 +67,7 @@ pub fn query_match_int() -> Result<()> { })?; db.transaction(&mut |txn| { result = txn.query_single(Query { - filter: Filter::Match(Path(vec![AGE.0]), 35_u32.to_be_bytes().to_vec()), + filter: Filter::Match(Path(vec![AGE.0]), Value::U32(35)), sort: Sort::None, })?; Ok(()) @@ -94,7 +94,7 @@ pub fn query_match_str() -> Result<()> { })?; db.transaction(&mut |txn| { result = txn.query_single(Query { - filter: Filter::Match(Path(vec![NAME.0]), "Alice".as_bytes().to_vec()), + filter: Filter::Match(Path(vec![NAME.0]), "Alice".into()), sort: Sort::None, })?; Ok(()) @@ -113,7 +113,7 @@ pub fn query_match_str_after() -> Result<()> { db.transaction(&mut |txn| { result = txn.query_single(Query { - filter: Filter::Match(Path(vec![NAME.0]), "Alice".as_bytes().to_vec()), + filter: Filter::Match(Path(vec![NAME.0]), "Alice".into()), sort: Sort::None, })?; Ok(()) @@ -131,7 +131,7 @@ pub fn query_match_str_after() -> Result<()> { db.transaction(&mut |txn| { result = txn.query_single(Query { - filter: Filter::Match(Path(vec![NAME.0]), "Alice".as_bytes().to_vec()), + filter: Filter::Match(Path(vec![NAME.0]), "Alice".into()), sort: Sort::None, })?; Ok(()) diff --git a/database/src/lib.rs b/database/src/lib.rs index 9b76c58..ed9dc47 100644 --- a/database/src/lib.rs +++ b/database/src/lib.rs @@ -9,7 +9,7 @@ pub mod query_ser; pub mod test_shared; use anyhow::Result; -use jellyobject::{ObjectBuffer, Path}; +use jellyobject::{ObjectBuffer, Path, Tag}; pub type RowNum = u64; pub type RowIter = Box)>>>; @@ -74,6 +74,47 @@ pub enum Filter { True, All(Vec), Any(Vec), - Match(Path, Vec), + Match(Path, Value), Has(Path), } + +#[derive(Debug, Clone)] +pub enum Value { + Tag(Tag), + U32(u32), + U64(u64), + I64(i64), + String(String), + Binary(Vec), +} + +impl From<&str> for Value { + fn from(value: &str) -> Self { + Self::String(value.to_owned()) + } +} +impl From for Value { + fn from(value: String) -> Self { + Self::String(value) + } +} +impl From for Value { + fn from(value: u32) -> Self { + Self::U32(value) + } +} +impl From for Value { + fn from(value: u64) -> Self { + Self::U64(value) + } +} +impl From for Value { + fn from(value: i64) -> Self { + Self::I64(value) + } +} +impl From for Value { + fn from(value: Tag) -> Self { + Self::Tag(value) + } +} diff --git a/database/src/query_ser.rs b/database/src/query_ser.rs index d76dea7..de62a72 100644 --- a/database/src/query_ser.rs +++ b/database/src/query_ser.rs @@ -4,8 +4,8 @@ Copyright (C) 2026 metamuffin */ -use crate::{Filter, MultiBehaviour, Query, Sort, SortOrder}; -use jellyobject::{Path, Tag}; +use crate::{Filter, MultiBehaviour, Query, Sort, SortOrder, Value}; +use jellyobject::Path; impl Query { pub fn show(&self) -> String { @@ -40,11 +40,7 @@ impl Filter { .join(" OR ") ), Filter::Match(path, value) => { - format!( - "{} = {}", - show_path(path), - show_value(*path.0.last().unwrap(), value) - ) + format!("{} = {}", show_path(path), show_value(value)) } Filter::Has(path) => show_path(path), } @@ -85,6 +81,13 @@ fn show_path(path: &Path) -> String { .collect::>() .join(".") } -fn show_value(_tag: Tag, value: &[u8]) -> String { - format!("{value:?}") // TODO +fn show_value(value: &Value) -> String { + match value { + Value::Tag(tag) => format!("{tag}"), + Value::U32(x) => format!("{x}"), + Value::U64(x) => format!("{x}"), + Value::I64(x) => format!("{x}"), + Value::String(x) => format!("{x:?}"), + Value::Binary(x) => format!("{x:?}"), + } } -- cgit v1.3