aboutsummaryrefslogtreecommitdiff
path: root/database
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2026-02-05 20:31:55 +0100
committermetamuffin <metamuffin@disroot.org>2026-02-05 20:31:55 +0100
commit65ca3f3450d0067668111f6e13cc3089768c9efe (patch)
tree89dceed4f711d25ff2763e18a4be7e1a59e79507 /database
parent1af0468788c0a592a76398206e6c7479384853ec (diff)
downloadjellything-65ca3f3450d0067668111f6e13cc3089768c9efe.tar
jellything-65ca3f3450d0067668111f6e13cc3089768c9efe.tar.bz2
jellything-65ca3f3450d0067668111f6e13cc3089768c9efe.tar.zst
remove read/write distinction for kv transactions; traitify database
Diffstat (limited to 'database')
-rw-r--r--database/src/filter/binning.rs52
-rw-r--r--database/src/kv/binning.rs (renamed from database/src/filter/mod.rs)59
-rw-r--r--database/src/kv/counters.rs (renamed from database/src/counters.rs)14
-rw-r--r--database/src/kv/mod.rs217
-rw-r--r--database/src/kv/prefix_iterator.rs (renamed from database/src/prefix_iterator.rs)0
-rw-r--r--database/src/kv/sort/mod.rs (renamed from database/src/sort/mod.rs)14
-rw-r--r--database/src/kv/sort/none.rs50
-rw-r--r--database/src/kv/sort/value.rs (renamed from database/src/sort/value.rs)51
-rw-r--r--database/src/lib.rs71
-rw-r--r--database/src/query.rs51
-rw-r--r--database/src/sort/none.rs53
-rw-r--r--database/src/table.rs184
12 files changed, 413 insertions, 403 deletions
diff --git a/database/src/filter/binning.rs b/database/src/filter/binning.rs
deleted file mode 100644
index 3265e1a..0000000
--- a/database/src/filter/binning.rs
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- This file is part of jellything (https://codeberg.org/metamuffin/jellything)
- which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
- Copyright (C) 2026 metamuffin <metamuffin.org>
-*/
-
-use jellyobject::{Object, Path};
-
-/// Sorted list of components to bin objects by filterable values.
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct Binning(Vec<BinningComponent>);
-
-#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
-pub enum BinningComponent {
- Has(Path),
- Match(Path),
-}
-
-impl Binning {
- pub fn new(mut comps: Vec<BinningComponent>) -> Self {
- comps.sort();
- Self(comps)
- }
- pub fn apply(&self, ob: Object<'_>, keys: &mut Vec<Vec<u8>>) {
- for f in &self.0 {
- f.apply(ob, keys);
- }
- }
-}
-impl BinningComponent {
- pub fn apply(&self, ob: Object<'_>, keys: &mut Vec<Vec<u8>>) {
- match self {
- BinningComponent::Has(path) => {
- let has = path.get_matching_value(ob).is_some();
- for co in keys {
- co.push(has as u8)
- }
- }
- BinningComponent::Match(path) => {
- let mut new_out = Vec::new();
- for value in path.get_matching_values(ob) {
- for mut co in keys.clone() {
- co.extend((co.len() as u32).to_be_bytes());
- co.extend(value);
- new_out.push(co);
- }
- }
- *keys = new_out;
- }
- }
- }
-}
diff --git a/database/src/filter/mod.rs b/database/src/kv/binning.rs
index c40e4c0..7bec294 100644
--- a/database/src/filter/mod.rs
+++ b/database/src/kv/binning.rs
@@ -3,12 +3,55 @@
which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
Copyright (C) 2026 metamuffin <metamuffin.org>
*/
-pub mod binning;
-use crate::{
- filter::binning::{Binning, BinningComponent},
- query::Filter,
-};
+use jellyobject::{Object, Path};
+
+use crate::Filter;
+
+/// Sorted list of components to bin objects by filterable values.
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct Binning(Vec<BinningComponent>);
+
+#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+pub enum BinningComponent {
+ Has(Path),
+ Match(Path),
+}
+
+impl Binning {
+ pub fn new(mut comps: Vec<BinningComponent>) -> Self {
+ comps.sort();
+ Self(comps)
+ }
+ pub fn apply(&self, ob: Object<'_>, keys: &mut Vec<Vec<u8>>) {
+ for f in &self.0 {
+ f.apply(ob, keys);
+ }
+ }
+}
+impl BinningComponent {
+ pub fn apply(&self, ob: Object<'_>, keys: &mut Vec<Vec<u8>>) {
+ match self {
+ BinningComponent::Has(path) => {
+ let has = path.get_matching_value(ob).is_some();
+ for co in keys {
+ co.push(has as u8)
+ }
+ }
+ BinningComponent::Match(path) => {
+ let mut new_out = Vec::new();
+ for value in path.get_matching_values(ob) {
+ for mut co in keys.clone() {
+ co.extend((co.len() as u32).to_be_bytes());
+ co.extend(value);
+ new_out.push(co);
+ }
+ }
+ *keys = new_out;
+ }
+ }
+ }
+}
impl Filter {
pub fn get_bins(&self) -> Vec<Binning> {
@@ -40,12 +83,10 @@ impl Filter {
#[cfg(test)]
mod test {
- use crate::{
- filter::binning::{Binning, BinningComponent},
- query::Filter,
- };
use jellyobject::{Path, Tag};
+ use crate::{Filter, kv::binning::{Binning, BinningComponent}};
+
#[test]
fn all() {
let f = Filter::All(vec![
diff --git a/database/src/counters.rs b/database/src/kv/counters.rs
index 17e2de8..fae7b42 100644
--- a/database/src/counters.rs
+++ b/database/src/kv/counters.rs
@@ -4,12 +4,10 @@
Copyright (C) 2026 metamuffin <metamuffin.org>
*/
use crate::{
- filter::binning::Binning,
- query::Query,
- table::{RowNum, TableNum},
+ Query, RowNum,
+ kv::{self, TableNum, binning::Binning},
};
use anyhow::Result;
-use jellykv::{ReadTransaction, WriteTransaction};
use jellyobject::Object;
use std::collections::HashMap;
@@ -17,7 +15,7 @@ pub(crate) struct Counters(pub HashMap<Binning, TableNum>);
impl Counters {
pub fn update(
&self,
- txn: &mut dyn WriteTransaction,
+ txn: &mut dyn jellykv::Transaction,
ob: Object<'_>,
remove: bool,
) -> Result<()> {
@@ -37,7 +35,7 @@ impl Counters {
}
Ok(())
}
- pub fn count(&self, txn: &dyn ReadTransaction, query: &Query) -> Result<Option<u64>> {
+ pub fn count(&self, txn: &dyn jellykv::Transaction, query: &Query) -> Result<Option<u64>> {
let mut total = 0;
for binning in query.filter.get_bins() {
let Some(b) = self.0.get(&binning) else {
@@ -49,10 +47,10 @@ impl Counters {
}
}
-pub fn write_counter(txn: &mut dyn WriteTransaction, t: TableNum, value: u64) -> Result<()> {
+pub fn write_counter(txn: &mut dyn jellykv::Transaction, t: TableNum, value: u64) -> Result<()> {
txn.set(&t.to_be_bytes(), &value.to_be_bytes())
}
-pub fn read_counter(txn: &dyn ReadTransaction, t: TableNum) -> Result<u64> {
+pub fn read_counter(txn: &dyn jellykv::Transaction, t: TableNum) -> Result<u64> {
Ok(txn
.get(&t.to_be_bytes())?
.map(|k| k.as_slice().try_into().map(RowNum::from_be_bytes).ok())
diff --git a/database/src/kv/mod.rs b/database/src/kv/mod.rs
new file mode 100644
index 0000000..b4bd000
--- /dev/null
+++ b/database/src/kv/mod.rs
@@ -0,0 +1,217 @@
+/*
+ This file is part of jellything (https://codeberg.org/metamuffin/jellything)
+ which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
+ Copyright (C) 2026 metamuffin <metamuffin.org>
+*/
+
+pub mod binning;
+pub mod counters;
+pub mod prefix_iterator;
+pub mod sort;
+
+use crate::{
+ Database, Query, RowIter, RowNum, Transaction,
+ kv::{binning::Binning, sort::SortKey},
+};
+use anyhow::Result;
+use jellyobject::ObjectBuffer;
+
+pub type IndexKey = (Binning, SortKey);
+pub type TableNum = u32;
+
+impl<T: jellykv::Store> Database for T {
+ fn transaction(&self, f: &mut dyn FnMut(&mut dyn Transaction) -> Result<()>) -> Result<()> {
+ todo!()
+ }
+}
+
+impl<T: jellykv::Transaction> Transaction for T {
+ fn insert(&self, entry: ObjectBuffer) -> Result<RowNum> {
+ todo!()
+ }
+
+ fn get(&self, row: RowNum) -> Result<Option<ObjectBuffer>> {
+ todo!()
+ }
+
+ fn remove(&self, row: RowNum) -> Result<()> {
+ todo!()
+ }
+
+ fn update(&self, row: RowNum, entry: ObjectBuffer) -> Result<()> {
+ todo!()
+ }
+
+ fn query(&self, query: Query) -> Result<RowIter> {
+ todo!()
+ }
+
+ fn query_single(&self, query: Query) -> Result<Option<RowNum>> {
+ todo!()
+ }
+
+ fn count(&self, query: Query) -> Result<u64> {
+ todo!()
+ }
+}
+
+// pub struct Table {
+// id: TableNum,
+// pub(crate) counters: HashMap<Binning, TableNum>,
+// pub(crate) indices: HashMap<IndexKey, TableNum>,
+// }
+// impl Table {
+// pub fn new(id: u32) -> Self {
+// Self {
+// id,
+// counters: HashMap::new(),
+// indices: HashMap::new(),
+// }
+// }
+// fn key(&self, row: RowNum) -> Vec<u8> {
+// let mut key = Vec::new();
+// key.extend(self.id.to_be_bytes());
+// key.extend(row.to_be_bytes());
+// key
+// }
+// pub fn iter(&self, txn: &dyn ReadTransaction) -> Result<impl Iterator<Item = Result<RowNum>>> {
+// Ok(PrefixIterator {
+// inner: txn.iter(&self.id.to_be_bytes(), false)?,
+// prefix: self.id.to_be_bytes().to_vec().into(),
+// }
+// .map(|r| r.map(|r| RowNum::from_be_bytes(r.try_into().unwrap()))))
+// }
+// pub fn insert(&self, txn: &mut dyn WriteTransaction, entry: ObjectBuffer) -> Result<RowNum> {
+// let mut id_counter = read_counter(txn, self.id)?;
+// let row = id_counter;
+// id_counter += 1;
+// write_counter(txn, self.id, id_counter)?;
+
+// txn.set(&self.key(row), bytemuck::cast_slice(entry.0.as_slice()))?;
+
+// let ob = entry.as_object();
+// // for idx in self.indices.values() {
+// // idx.add(txn, row, ob)?;
+// // }
+
+// Ok(row)
+// }
+// pub fn get(&self, txn: &dyn ReadTransaction, row: RowNum) -> Result<Option<ObjectBuffer>> {
+// Ok(txn.get(&self.key(row))?.map(ObjectBuffer::from))
+// }
+// pub fn remove(&self, db: &mut dyn WriteTransaction, row: RowNum) -> Result<bool> {
+// let Some(entry) = self.get(db, row)? else {
+// return Ok(false);
+// };
+// let ob = entry.as_object();
+// // for index in self.indices.values() {
+// // index.remove(db, row, ob)?;
+// // }
+// db.del(&self.key(row))?;
+// Ok(true)
+// }
+// pub fn update(
+// &self,
+// txn: &mut dyn WriteTransaction,
+// row: RowNum,
+// entry: ObjectBuffer,
+// ) -> Result<()> {
+// let before = self
+// .get(txn, row)?
+// .ok_or(anyhow!("row to update missing"))?;
+// let before = before.as_object();
+// let after = entry.as_object();
+
+// txn.set(&self.key(row), bytemuck::cast_slice(entry.0.as_slice()))?;
+
+// // for index in self.indices.values() {
+// // if !index.compare(before, after) {
+// // index.remove(txn, row, before)?;
+// // index.add(txn, row, after)?;
+// // }
+// // }
+
+// Ok(())
+// }
+// pub fn query(&self, txn: &dyn ReadTransaction, query: Query) -> Result<RowIter> {
+// // query
+// // .filter
+// // .get_bins()
+// // .into_iter()
+// // .flat_map(|b| {
+// // let ikey = (b, query.sort.key());
+// // self.indices.get(&ikey)
+// // })
+// // .map(|i| i.query(txn, &query.sort))
+// todo!()
+// }
+// pub fn query_single(&self, txn: &dyn ReadTransaction, query: Query) -> Result<Option<RowNum>> {
+// self.query(txn, query)?.next().transpose()
+// }
+// pub fn count(&self, txn: &dyn ReadTransaction, query: Query) -> Result<u64> {
+// let mut total = 0;
+// for b in query.filter.get_bins() {
+// if let Some(&c) = self.counters.get(&b) {
+// total += read_counter(txn, c)?;
+// }
+// }
+// Ok(total)
+// }
+// }
+
+// #[cfg(test)]
+// mod test {
+// use {
+// table::Table,
+// test_shared::{NAME, new_bob},
+// };
+// use anyhow::Result;
+// use jellykv::Database;
+
+// #[test]
+// pub fn insert_get() -> Result<()> {
+// let db = jellykv::memory::new();
+// let table = Table::new(5);
+
+// let mut bob_row = 0;
+// db.write_transaction(&mut |txn| {
+// bob_row = table.insert(txn, new_bob())?;
+// Ok(())
+// })?;
+
+// let mut bob = None;
+// db.read_transaction(&mut |txn| {
+// bob = table.get(txn, bob_row)?;
+// Ok(())
+// })?;
+
+// assert_eq!(bob.unwrap().as_object().get(NAME).unwrap(), "Bob");
+// Ok(())
+// }
+
+// #[test]
+// pub fn update() -> Result<()> {
+// let db = jellykv::memory::new();
+// let table = Table::new(5);
+
+// let mut bob_row = 0;
+// let mut bob = None;
+
+// db.write_transaction(&mut |txn| {
+// bob_row = table.insert(txn, new_bob())?;
+// Ok(())
+// })?;
+// db.write_transaction(&mut |txn| {
+// let better_bob = new_bob().as_object().insert(NAME, "Better Bob");
+// table.update(txn, bob_row, better_bob)?;
+// Ok(())
+// })?;
+// db.read_transaction(&mut |txn| {
+// bob = table.get(txn, bob_row)?;
+// Ok(())
+// })?;
+
+// assert_eq!(bob.unwrap().as_object().get(NAME).unwrap(), "Better Bob");
+// Ok(())
+// }
+// }
diff --git a/database/src/prefix_iterator.rs b/database/src/kv/prefix_iterator.rs
index 9a73558..9a73558 100644
--- a/database/src/prefix_iterator.rs
+++ b/database/src/kv/prefix_iterator.rs
diff --git a/database/src/sort/mod.rs b/database/src/kv/sort/mod.rs
index 58d8eff..403ba73 100644
--- a/database/src/sort/mod.rs
+++ b/database/src/kv/sort/mod.rs
@@ -4,13 +4,9 @@
Copyright (C) 2026 metamuffin <metamuffin.org>
*/
-use crate::{
- query::{MultiBehaviour, Sort},
- table::IndexKey,
-};
-use anyhow::Result;
-use jellykv::WriteTransaction;
-use jellyobject::{Object, Path};
+use jellyobject::Path;
+
+use crate::{MultiBehaviour, Sort};
pub mod none;
pub mod value;
@@ -31,7 +27,3 @@ impl Sort {
}
}
}
-
-pub fn index_add(txn: &mut dyn WriteTransaction, ik: &IndexKey, ob: &Object) -> Result<()> {
-
-}
diff --git a/database/src/kv/sort/none.rs b/database/src/kv/sort/none.rs
new file mode 100644
index 0000000..b4d5db2
--- /dev/null
+++ b/database/src/kv/sort/none.rs
@@ -0,0 +1,50 @@
+/*
+ This file is part of jellything (https://codeberg.org/metamuffin/jellything)
+ which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
+ Copyright (C) 2026 metamuffin <metamuffin.org>
+*/
+
+use crate::{
+ RowNum,
+ kv::{TableNum, binning::Binning},
+};
+use jellyobject::Object;
+
+pub struct UnsortedIndex {
+ id: TableNum,
+ binning: Binning,
+}
+
+impl UnsortedIndex {
+ pub fn new(id: TableNum, binning: Binning) -> Self {
+ Self { id, binning }
+ }
+ fn keys(&self, id: RowNum, ob: Object) -> Vec<Vec<u8>> {
+ let mut keys = vec![self.id.to_be_bytes().to_vec()];
+ self.binning.apply(ob, &mut keys);
+ for k in &mut keys {
+ k.extend(id.to_ne_bytes());
+ }
+ keys
+ }
+}
+// impl Index for UnsortedIndex {
+// fn add(&self, db: &mut dyn WriteTransaction, id: RowNum, ob: Object) -> Result<()> {
+// for key in self.keys(id, ob) {
+// db.set(&key, &[])?;
+// }
+// Ok(())
+// }
+// fn remove(&self, db: &mut dyn WriteTransaction, id: RowNum, ob: Object) -> Result<()> {
+// for key in self.keys(id, ob) {
+// db.del(&key)?;
+// }
+// Ok(())
+// }
+// fn compare(&self, before: Object, after: Object) -> bool {
+// self.keys(0, before) == self.keys(0, after)
+// }
+// fn query(&self, txn: &mut dyn ReadTransaction, _sort: &Sort) -> Result<RowIter> {
+// todo!()
+// }
+// }
diff --git a/database/src/sort/value.rs b/database/src/kv/sort/value.rs
index 6e42fd7..0d4ceb7 100644
--- a/database/src/sort/value.rs
+++ b/database/src/kv/sort/value.rs
@@ -4,15 +4,12 @@
Copyright (C) 2026 metamuffin <metamuffin.org>
*/
+use jellyobject::Object;
+
use crate::{
- filter::binning::Binning,
- query::{MultiBehaviour, Sort, ValueSort},
- sort::Index,
- table::{RowIter, RowNum, TableNum},
+ MultiBehaviour, RowNum, ValueSort,
+ kv::{TableNum, binning::Binning},
};
-use anyhow::Result;
-use jellykv::{ReadTransaction, WriteTransaction};
-use jellyobject::Object;
pub struct ValueIndex {
id: TableNum,
@@ -34,26 +31,26 @@ impl ValueIndex {
keys
}
}
-impl Index for ValueIndex {
- fn add(&self, db: &mut dyn WriteTransaction, id: RowNum, ob: Object) -> Result<()> {
- for key in self.keys(id, ob) {
- db.set(&key, &[])?;
- }
- Ok(())
- }
- fn remove(&self, db: &mut dyn WriteTransaction, id: RowNum, ob: Object) -> Result<()> {
- for key in self.keys(id, ob) {
- db.del(&key)?;
- }
- Ok(())
- }
- fn compare(&self, before: Object, after: Object) -> bool {
- self.keys(0, before) == self.keys(0, after)
- }
- fn query(&self, txn: &mut dyn ReadTransaction, sort: &Sort) -> Result<RowIter> {
- todo!()
- }
-}
+// impl Index for ValueIndex {
+// fn add(&self, db: &mut dyn WriteTransaction, id: RowNum, ob: Object) -> Result<()> {
+// for key in self.keys(id, ob) {
+// db.set(&key, &[])?;
+// }
+// Ok(())
+// }
+// fn remove(&self, db: &mut dyn WriteTransaction, id: RowNum, ob: Object) -> Result<()> {
+// for key in self.keys(id, ob) {
+// db.del(&key)?;
+// }
+// Ok(())
+// }
+// fn compare(&self, before: Object, after: Object) -> bool {
+// self.keys(0, before) == self.keys(0, after)
+// }
+// fn query(&self, txn: &mut dyn ReadTransaction, sort: &Sort) -> Result<RowIter> {
+// todo!()
+// }
+// }
impl ValueSort {
fn apply(&self, ob: Object, keys: &mut Vec<Vec<u8>>) {
match self.multi {
diff --git a/database/src/lib.rs b/database/src/lib.rs
index 00e6905..f6f3fa9 100644
--- a/database/src/lib.rs
+++ b/database/src/lib.rs
@@ -3,15 +3,70 @@
which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
Copyright (C) 2026 metamuffin <metamuffin.org>
*/
-pub mod filter;
-pub mod prefix_iterator;
-pub mod query;
-pub mod sort;
-pub mod table;
+pub mod kv;
#[cfg(test)]
pub mod test_shared;
-pub mod counters;
-pub type Pad32 = u32;
+use anyhow::Result;
+use jellyobject::{ObjectBuffer, Path};
-pub use jellykv as kv;
+pub type RowNum = u64;
+pub type RowIter = Box<dyn Iterator<Item = Result<RowNum>>>;
+
+pub trait Database {
+ fn transaction(&self, f: &mut dyn FnMut(&mut dyn Transaction) -> Result<()>) -> Result<()>;
+}
+
+pub trait Transaction {
+ fn insert(&self, entry: ObjectBuffer) -> Result<RowNum>;
+ fn get(&self, row: RowNum) -> Result<Option<ObjectBuffer>>;
+ fn remove(&self, row: RowNum) -> Result<()>;
+ fn update(&self, row: RowNum, entry: ObjectBuffer) -> Result<()>;
+ fn query(&self, query: Query) -> Result<RowIter>;
+ fn query_single(&self, query: Query) -> Result<Option<RowNum>>;
+ fn count(&self, query: Query) -> Result<u64>;
+}
+
+#[derive(Default)]
+pub struct Query {
+ pub filter: Filter,
+ pub sort: Sort,
+}
+
+#[derive(Default)]
+pub enum Sort {
+ #[default]
+ None,
+ Value(ValueSort),
+ TextSearch(Path, String),
+}
+
+pub struct ValueSort {
+ pub order: SortOrder,
+ pub path: Path,
+ pub multi: MultiBehaviour,
+ pub offset: Option<Vec<u8>>,
+}
+
+#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
+pub enum MultiBehaviour {
+ First,
+ ForEach,
+ Max,
+ Min,
+ Count,
+}
+pub enum SortOrder {
+ Ascending,
+ Descending,
+}
+
+#[derive(Debug, Clone, Default)]
+pub enum Filter {
+ #[default]
+ True,
+ All(Vec<Filter>),
+ Any(Vec<Filter>),
+ Match(Path, Vec<u8>),
+ Has(Path),
+}
diff --git a/database/src/query.rs b/database/src/query.rs
deleted file mode 100644
index 002a872..0000000
--- a/database/src/query.rs
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- This file is part of jellything (https://codeberg.org/metamuffin/jellything)
- which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
- Copyright (C) 2026 metamuffin <metamuffin.org>
-*/
-
-use jellyobject::Path;
-
-#[derive(Default)]
-pub struct Query {
- pub filter: Filter,
- pub sort: Sort,
-}
-
-#[derive(Default)]
-pub enum Sort {
- #[default]
- None,
- Value(ValueSort),
- TextSearch(Path, String),
-}
-
-pub struct ValueSort {
- pub order: SortOrder,
- pub path: Path,
- pub multi: MultiBehaviour,
- pub offset: Option<Vec<u8>>,
-}
-
-#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
-pub enum MultiBehaviour {
- First,
- ForEach,
- Max,
- Min,
- Count,
-}
-pub enum SortOrder {
- Ascending,
- Descending,
-}
-
-#[derive(Debug, Clone, Default)]
-pub enum Filter {
- #[default]
- True,
- All(Vec<Filter>),
- Any(Vec<Filter>),
- Match(Path, Vec<u8>),
- Has(Path),
-}
diff --git a/database/src/sort/none.rs b/database/src/sort/none.rs
deleted file mode 100644
index efaa7f8..0000000
--- a/database/src/sort/none.rs
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- This file is part of jellything (https://codeberg.org/metamuffin/jellything)
- which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
- Copyright (C) 2026 metamuffin <metamuffin.org>
-*/
-
-use crate::{
- filter::binning::Binning,
- query::Sort,
- table::{RowIter, RowNum, TableNum},
-};
-use anyhow::Result;
-use jellykv::{ReadTransaction, WriteTransaction};
-use jellyobject::Object;
-
-pub struct UnsortedIndex {
- id: TableNum,
- binning: Binning,
-}
-
-impl UnsortedIndex {
- pub fn new(id: TableNum, binning: Binning) -> Self {
- Self { id, binning }
- }
- fn keys(&self, id: RowNum, ob: Object) -> Vec<Vec<u8>> {
- let mut keys = vec![self.id.to_be_bytes().to_vec()];
- self.binning.apply(ob, &mut keys);
- for k in &mut keys {
- k.extend(id.to_ne_bytes());
- }
- keys
- }
-}
-impl Index for UnsortedIndex {
- fn add(&self, db: &mut dyn WriteTransaction, id: RowNum, ob: Object) -> Result<()> {
- for key in self.keys(id, ob) {
- db.set(&key, &[])?;
- }
- Ok(())
- }
- fn remove(&self, db: &mut dyn WriteTransaction, id: RowNum, ob: Object) -> Result<()> {
- for key in self.keys(id, ob) {
- db.del(&key)?;
- }
- Ok(())
- }
- fn compare(&self, before: Object, after: Object) -> bool {
- self.keys(0, before) == self.keys(0, after)
- }
- fn query(&self, txn: &mut dyn ReadTransaction, _sort: &Sort) -> Result<RowIter> {
- todo!()
- }
-}
diff --git a/database/src/table.rs b/database/src/table.rs
deleted file mode 100644
index ee8d66b..0000000
--- a/database/src/table.rs
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- This file is part of jellything (https://codeberg.org/metamuffin/jellything)
- which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
- Copyright (C) 2026 metamuffin <metamuffin.org>
-*/
-
-use crate::{
- counters::{read_counter, write_counter},
- filter::binning::Binning,
- prefix_iterator::PrefixIterator,
- query::Query,
- sort::{Index, SortKey},
-};
-use anyhow::{Result, anyhow};
-use jellykv::{ReadTransaction, WriteTransaction};
-use jellyobject::ObjectBuffer;
-use std::collections::HashMap;
-
-pub type TableNum = u32;
-pub type RowNum = u64;
-
-pub type RowIter = Box<dyn Iterator<Item = Result<RowNum>>>;
-pub type IndexKey = (Binning, SortKey);
-
-pub struct Table {
- id: TableNum,
- pub(crate) counters: HashMap<Binning, TableNum>,
- pub(crate) indices: HashMap<IndexKey, TableNum>,
-}
-impl Table {
- pub fn new(id: u32) -> Self {
- Self {
- id,
- counters: HashMap::new(),
- indices: HashMap::new(),
- }
- }
- fn key(&self, row: RowNum) -> Vec<u8> {
- let mut key = Vec::new();
- key.extend(self.id.to_be_bytes());
- key.extend(row.to_be_bytes());
- key
- }
- pub fn iter(&self, txn: &dyn ReadTransaction) -> Result<impl Iterator<Item = Result<RowNum>>> {
- Ok(PrefixIterator {
- inner: txn.iter(&self.id.to_be_bytes(), false)?,
- prefix: self.id.to_be_bytes().to_vec().into(),
- }
- .map(|r| r.map(|r| RowNum::from_be_bytes(r.try_into().unwrap()))))
- }
- pub fn insert(&self, txn: &mut dyn WriteTransaction, entry: ObjectBuffer) -> Result<RowNum> {
- let mut id_counter = read_counter(txn, self.id)?;
- let row = id_counter;
- id_counter += 1;
- write_counter(txn, self.id, id_counter)?;
-
- txn.set(&self.key(row), bytemuck::cast_slice(entry.0.as_slice()))?;
-
- let ob = entry.as_object();
- for idx in self.indices.values() {
- idx.add(txn, row, ob)?;
- }
-
- Ok(row)
- }
- pub fn get(&self, txn: &dyn ReadTransaction, row: RowNum) -> Result<Option<ObjectBuffer>> {
- Ok(txn.get(&self.key(row))?.map(ObjectBuffer::from))
- }
- pub fn remove(&self, db: &mut dyn WriteTransaction, row: RowNum) -> Result<bool> {
- let Some(entry) = self.get(db, row)? else {
- return Ok(false);
- };
- let ob = entry.as_object();
- for index in self.indices.values() {
- index.remove(db, row, ob)?;
- }
- db.del(&self.key(row))?;
- Ok(true)
- }
- pub fn update(
- &self,
- txn: &mut dyn WriteTransaction,
- row: RowNum,
- entry: ObjectBuffer,
- ) -> Result<()> {
- let before = self
- .get(txn, row)?
- .ok_or(anyhow!("row to update missing"))?;
- let before = before.as_object();
- let after = entry.as_object();
-
- txn.set(&self.key(row), bytemuck::cast_slice(entry.0.as_slice()))?;
-
- for index in self.indices.values() {
- if !index.compare(before, after) {
- index.remove(txn, row, before)?;
- index.add(txn, row, after)?;
- }
- }
-
- Ok(())
- }
- pub fn query(&self, txn: &dyn ReadTransaction, query: Query) -> Result<RowIter> {
- // query
- // .filter
- // .get_bins()
- // .into_iter()
- // .flat_map(|b| {
- // let ikey = (b, query.sort.key());
- // self.indices.get(&ikey)
- // })
- // .map(|i| i.query(txn, &query.sort))
- todo!()
- }
- pub fn query_single(&self, txn: &dyn ReadTransaction, query: Query) -> Result<Option<RowNum>> {
- self.query(txn, query)?.next().transpose()
- }
- pub fn count(&self, txn: &dyn ReadTransaction, query: Query) -> Result<u64> {
- let mut total = 0;
- for b in query.filter.get_bins() {
- if let Some(&c) = self.counters.get(&b) {
- total += read_counter(txn, c)?;
- }
- }
- Ok(total)
- }
-}
-
-#[cfg(test)]
-mod test {
- use crate::{
- table::Table,
- test_shared::{NAME, new_bob},
- };
- use anyhow::Result;
- use jellykv::Database;
-
- #[test]
- pub fn insert_get() -> Result<()> {
- let db = jellykv::memory::new();
- let table = Table::new(5);
-
- let mut bob_row = 0;
- db.write_transaction(&mut |txn| {
- bob_row = table.insert(txn, new_bob())?;
- Ok(())
- })?;
-
- let mut bob = None;
- db.read_transaction(&mut |txn| {
- bob = table.get(txn, bob_row)?;
- Ok(())
- })?;
-
- assert_eq!(bob.unwrap().as_object().get(NAME).unwrap(), "Bob");
- Ok(())
- }
-
- #[test]
- pub fn update() -> Result<()> {
- let db = jellykv::memory::new();
- let table = Table::new(5);
-
- let mut bob_row = 0;
- let mut bob = None;
-
- db.write_transaction(&mut |txn| {
- bob_row = table.insert(txn, new_bob())?;
- Ok(())
- })?;
- db.write_transaction(&mut |txn| {
- let better_bob = new_bob().as_object().insert(NAME, "Better Bob");
- table.update(txn, bob_row, better_bob)?;
- Ok(())
- })?;
- db.read_transaction(&mut |txn| {
- bob = table.get(txn, bob_row)?;
- Ok(())
- })?;
-
- assert_eq!(bob.unwrap().as_object().get(NAME).unwrap(), "Better Bob");
- Ok(())
- }
-}