diff options
| author | metamuffin <metamuffin@disroot.org> | 2025-12-16 04:30:42 +0100 |
|---|---|---|
| committer | metamuffin <metamuffin@disroot.org> | 2025-12-16 04:30:42 +0100 |
| commit | fc7f3ae8e39a0398ceba7b9c44f58679c01a98da (patch) | |
| tree | 77eef4d5e5ccb733b15ac4039e0a966f88ee8380 /database | |
| parent | 0e48299889c3c2b81bf351ffe5da71e0bcd4c22a (diff) | |
| download | jellything-fc7f3ae8e39a0398ceba7b9c44f58679c01a98da.tar jellything-fc7f3ae8e39a0398ceba7b9c44f58679c01a98da.tar.bz2 jellything-fc7f3ae8e39a0398ceba7b9c44f58679c01a98da.tar.zst | |
tables
Diffstat (limited to 'database')
| -rw-r--r-- | database/src/backends/memory.rs | 2 | ||||
| -rw-r--r-- | database/src/backends/mod.rs | 13 | ||||
| -rw-r--r-- | database/src/backends/rocksdb.rs | 2 | ||||
| -rw-r--r-- | database/src/indices/mod.rs | 6 | ||||
| -rw-r--r-- | database/src/indices/order.rs | 16 | ||||
| -rw-r--r-- | database/src/lib.rs | 42 | ||||
| -rw-r--r-- | database/src/table.rs | 64 | ||||
| -rw-r--r-- | database/src/transaction.rs | 42 |
8 files changed, 128 insertions, 59 deletions
diff --git a/database/src/backends/memory.rs b/database/src/backends/memory.rs index 2f19ce6..f1952a3 100644 --- a/database/src/backends/memory.rs +++ b/database/src/backends/memory.rs @@ -20,7 +20,7 @@ impl KV for Memory { self.0.write().unwrap().insert(key.to_vec(), value.to_vec()); Ok(()) } - fn get<'a>(&'a self, key: &[u8]) -> Result<Option<Vec<u8>>> { + fn get(&self, key: &[u8]) -> Result<Option<Vec<u8>>> { Ok(self.0.read().unwrap().get(key).cloned()) } fn del(&self, key: &[u8]) -> Result<()> { diff --git a/database/src/backends/mod.rs b/database/src/backends/mod.rs index b6d3770..814cc50 100644 --- a/database/src/backends/mod.rs +++ b/database/src/backends/mod.rs @@ -8,7 +8,9 @@ pub mod memory; pub mod redb; pub mod rocksdb; -use anyhow::Result; +use crate::backends::{memory::Memory, redb::Redb, rocksdb::Rocksdb}; +use anyhow::{Result, bail}; +use std::{path::Path, sync::Arc}; pub trait KV { fn set(&self, key: &[u8], value: &[u8]) -> Result<()>; @@ -17,3 +19,12 @@ pub trait KV { fn next(&self, key: &[u8]) -> Result<Option<Vec<u8>>>; fn prev(&self, key: &[u8]) -> Result<Option<Vec<u8>>>; } + +pub fn create_backend(driver: &str, path: &Path) -> Result<Arc<dyn KV>> { + Ok(match driver { + "rocksdb" => Arc::new(Rocksdb::new(path)?), + "redb" => Arc::new(Redb::new(path)?), + "memory" => Arc::new(Memory::new()), + _ => bail!("unknown db driver"), + }) +} diff --git a/database/src/backends/rocksdb.rs b/database/src/backends/rocksdb.rs index f4ed55b..31229a9 100644 --- a/database/src/backends/rocksdb.rs +++ b/database/src/backends/rocksdb.rs @@ -25,7 +25,7 @@ impl KV for Rocksdb { fn set(&self, key: &[u8], value: &[u8]) -> Result<()> { Ok(self.db.put(key, value)?) } - fn get<'a>(&'a self, key: &[u8]) -> Result<Option<Vec<u8>>> { + fn get(&self, key: &[u8]) -> Result<Option<Vec<u8>>> { Ok(self.db.get(key)?) } fn del(&self, key: &[u8]) -> Result<()> { diff --git a/database/src/indices/mod.rs b/database/src/indices/mod.rs index 48e91a9..5856254 100644 --- a/database/src/indices/mod.rs +++ b/database/src/indices/mod.rs @@ -4,14 +4,14 @@ Copyright (C) 2025 metamuffin <metamuffin.org> */ -use crate::backends::KV; +use crate::{backends::KV, table::RowNum}; use anyhow::Result; pub mod order; pub trait Index<T> { - fn add(&self, db: &dyn KV, id: u64, val: &T) -> Result<()>; - fn remove(&self, db: &dyn KV, id: u64, val: &T) -> Result<()>; + fn add(&self, db: &dyn KV, row: RowNum, val: &T) -> Result<()>; + fn remove(&self, db: &dyn KV, row: RowNum, val: &T) -> Result<()>; fn compare(&self, before: &T, after: &T) -> bool { let _ = (before, after); true diff --git a/database/src/indices/order.rs b/database/src/indices/order.rs index 852342d..04fb975 100644 --- a/database/src/indices/order.rs +++ b/database/src/indices/order.rs @@ -4,27 +4,17 @@ Copyright (C) 2025 metamuffin <metamuffin.org> */ -use crate::{Table, backends::KV, indices::Index}; +use crate::{backends::KV, indices::Index, table::Table}; use anyhow::Result; -use std::sync::Arc; pub struct OrderIndex<T> { id: u32, value: fn(&T) -> [u8; 8], - db: Arc<dyn KV>, } impl<T: 'static> OrderIndex<T> { pub fn new(table: &mut Table<T>, id: u32, value: fn(&T) -> [u8; 8]) -> Self { - table.indices.push(Box::new(Self { - id, - value, - db: table.db.clone(), - })); - Self { - id, - value, - db: table.db.clone(), - } + table.indices.push(Box::new(Self { id, value })); + Self { id, value } } fn key(&self, id: u64, val: &T) -> Vec<u8> { let mut key = Vec::new(); diff --git a/database/src/lib.rs b/database/src/lib.rs index 828761e..7618fe7 100644 --- a/database/src/lib.rs +++ b/database/src/lib.rs @@ -4,45 +4,7 @@ Copyright (C) 2025 metamuffin <metamuffin.org> */ -use anyhow::{Result, bail}; - -use crate::{ - backends::{KV, memory::Memory, redb::Redb, rocksdb::Rocksdb}, - indices::Index, -}; -use std::{path::Path, sync::Arc}; - pub mod backends; pub mod indices; - -pub struct Database { - storage: Arc<dyn KV>, -} - -impl Database { - pub fn new(driver: &str, path: &Path) -> Result<Self> { - Ok(Self { - storage: match driver { - "rocksdb" => Arc::new(Rocksdb::new(path)?), - "redb" => Arc::new(Redb::new(path)?), - "memory" => Arc::new(Memory::new()), - _ => bail!("unknown db driver"), - }, - }) - } -} - -pub struct Table<T> { - id: u32, - indices: Vec<Box<dyn Index<T>>>, - db: Arc<dyn KV>, -} -impl<T> Table<T> { - pub fn new(db: &Database, id: u32) -> Self { - Self { - id, - indices: Vec::new(), - db: db.storage.clone(), - } - } -} +pub mod table; +pub mod transaction; diff --git a/database/src/table.rs b/database/src/table.rs new file mode 100644 index 0000000..8c6b724 --- /dev/null +++ b/database/src/table.rs @@ -0,0 +1,64 @@ +/* + 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) 2025 metamuffin <metamuffin.org> +*/ + +use crate::{backends::KV, indices::Index}; +use anyhow::Result; +use serde::{Serialize, de::DeserializeOwned}; + +pub type RowNum = u64; + +pub struct Table<T> { + id: u32, + pub(crate) indices: Vec<Box<dyn Index<T>>>, +} +impl<T: Serialize + DeserializeOwned> Table<T> { + pub fn new(id: u32) -> Self { + Self { + id, + indices: Vec::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 insert(&self, db: &dyn KV, entry: T) -> Result<RowNum> { + let mut id_counter = db + .get(&self.id.to_be_bytes())? + .map(|k| k.as_slice().try_into().map(RowNum::from_be_bytes).ok()) + .flatten() + .unwrap_or(0); + let row = id_counter; + id_counter += 1; + db.set(&self.id.to_be_bytes(), &id_counter.to_be_bytes())?; + + db.set(&self.key(row), &serde_json::to_vec(&entry)?)?; + + for idx in &self.indices { + idx.add(db, row, &entry)?; + } + + Ok(id_counter) + } + pub fn get(&self, db: &dyn KV, row: RowNum) -> Result<Option<T>> { + Ok(db + .get(&self.key(row))? + .map(|v| serde_json::from_slice(&v)) + .transpose()?) + } + pub fn remove(&self, db: &dyn KV, row: RowNum) -> Result<bool> { + let Some(entry) = self.get(db, row)? else { + return Ok(false); + }; + for idx in &self.indices { + idx.remove(db, row, &entry)?; + } + db.del(&self.key(row))?; + Ok(true) + } +} diff --git a/database/src/transaction.rs b/database/src/transaction.rs new file mode 100644 index 0000000..c0e89b7 --- /dev/null +++ b/database/src/transaction.rs @@ -0,0 +1,42 @@ +/* + 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) 2025 metamuffin <metamuffin.org> +*/ + +use crate::backends::KV; +use anyhow::Result; +use std::sync::Arc; + +pub struct TransactionController { + db: Arc<dyn KV>, +} +impl TransactionController { + pub fn transact(&self, tx: impl Fn(&mut Transaction) -> Result<()>) -> Result<()> { + tx(&mut Transaction { + db: self.db.clone(), + })?; + Ok(()) + } +} + +pub struct Transaction { + db: Arc<dyn KV>, +} +impl KV for Transaction { + fn set(&self, key: &[u8], value: &[u8]) -> Result<()> { + self.db.set(key, value) + } + fn get(&self, key: &[u8]) -> Result<Option<Vec<u8>>> { + self.db.get(key) + } + fn del(&self, key: &[u8]) -> Result<()> { + self.db.del(key) + } + fn next(&self, key: &[u8]) -> Result<Option<Vec<u8>>> { + self.db.next(key) + } + fn prev(&self, key: &[u8]) -> Result<Option<Vec<u8>>> { + self.db.prev(key) + } +} |