1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
|
/*
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::{
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<Box<dyn Index>>,
}
impl Table {
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, txn: &mut dyn WriteTransaction, entry: ObjectBuffer) -> Result<RowNum> {
let mut id_counter = txn
.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;
txn.set(&self.id.to_be_bytes(), &id_counter.to_be_bytes())?;
txn.set(&self.key(row), bytemuck::cast_slice(entry.0.as_slice()))?;
let ob = entry.as_object();
for idx in &self.indices {
idx.add(txn, row, ob)?;
}
Ok(id_counter)
}
pub fn add_index<T: Index + Clone + 'static>(&mut self, index: T) -> T {
self.indices.push(Box::new(index.clone()));
index
}
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 idx in &self.indices {
idx.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 idx in &self.indices {
if !idx.compare(before, after) {
idx.remove(txn, row, before)?;
idx.add(txn, row, after)?;
}
}
Ok(())
}
pub fn query(
&self,
txn: &dyn ReadTransaction,
query: Query,
) -> Box<dyn Iterator<Item = RowNum>> {
todo!()
}
pub fn query_single(&self, txn: &dyn ReadTransaction, query: Query) -> Option<RowNum> {
self.query(txn, query).next()
}
}
|