/* 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 */ use crate::{ backends::{ReadTransaction, WriteTransaction}, query::Query, sort::Index, }; use anyhow::{Result, anyhow}; use jellyobject::ObjectBuffer; pub type TableNum = u64; pub type RowNum = u64; pub struct Table { id: u32, pub(crate) indices: Vec>, } impl Table { pub fn new(id: u32) -> Self { Self { id, indices: Vec::new(), } } fn key(&self, row: RowNum) -> Vec { let mut key = Vec::new(); key.extend(self.id.to_be_bytes()); key.extend(row.to_be_bytes()); key } pub fn insert(&self, db: &mut dyn WriteTransaction, entry: ObjectBuffer) -> Result { 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), bytemuck::cast_slice(entry.0.as_slice()))?; let ob = entry.as_object(); for idx in &self.indices { idx.add(db, row, ob)?; } Ok(id_counter) } pub fn add_index(&mut self, index: T) -> T { self.indices.push(Box::new(index.clone())); index } pub fn get(&self, db: &dyn ReadTransaction, row: RowNum) -> Result> { Ok(db.get(&self.key(row))?.map(ObjectBuffer::from)) } pub fn remove(&self, db: &mut dyn WriteTransaction, row: RowNum) -> Result { let Some(entry) = self.get(db, row)? else { return Ok(false); }; let ob = entry.as_object(); for idx in &self.indices { idx.remove(db, row, ob)?; } db.del(&self.key(row))?; Ok(true) } pub fn update( &self, db: &mut dyn WriteTransaction, row: RowNum, entry: ObjectBuffer, ) -> Result<()> { let before = self.get(db, row)?.ok_or(anyhow!("row to update missing"))?; let before = before.as_object(); let after = entry.as_object(); db.set(&self.key(row), bytemuck::cast_slice(entry.0.as_slice()))?; for idx in &self.indices { if !idx.compare(before, after) { idx.remove(db, row, before)?; idx.add(db, row, after)?; } } Ok(()) } pub fn query( &self, db: &dyn ReadTransaction, query: Query, ) -> Box> { todo!() } pub fn query_single(&self, db: &dyn ReadTransaction, query: Query) -> Option { self.query(db, query).next() } }