127 lines
4.5 KiB
Rust
127 lines
4.5 KiB
Rust
use std::borrow::Borrow;
|
|
|
|
use heromodels_core::{Index, Model};
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
pub mod hero;
|
|
pub mod postgres;
|
|
|
|
pub trait Db {
|
|
/// Error type returned by database operations.
|
|
type Error: std::fmt::Debug;
|
|
|
|
/// Open the collection for a specific model. This method must create the collection if it does not exist.
|
|
fn collection<M: Model>(&self) -> Result<impl Collection<&str, M>, Error<Self::Error>>;
|
|
}
|
|
|
|
/// A collection stores a specific model under a specific key
|
|
pub trait Collection<K, V>
|
|
where
|
|
K: Serialize,
|
|
V: Serialize + for<'a> Deserialize<'a>,
|
|
{
|
|
/// Error type for database operations
|
|
type Error: std::fmt::Debug;
|
|
|
|
/// Get all items where the given index field is equal to key.
|
|
fn get<I, Q>(&self, key: &Q) -> Result<Vec<V>, Error<Self::Error>>
|
|
where
|
|
I: Index<Model = V>,
|
|
I::Key: Borrow<Q>,
|
|
Q: ToString + Serialize + core::fmt::Debug + Sync + ?Sized;
|
|
|
|
/// Get an object from its ID. This does not use an index lookup
|
|
fn get_by_id(&self, id: u32) -> Result<Option<V>, Error<Self::Error>>;
|
|
|
|
/// Store an item in the DB and return the assigned ID and the updated model.
|
|
///
|
|
/// # Important Notes
|
|
/// - This method does not modify the original model passed as an argument.
|
|
/// - For new models (with ID 0), an ID will be auto-generated by OurDB.
|
|
/// - The returned model will have the correct ID and should be used instead of the original model.
|
|
/// - The original model should not be used after calling this method, as it may have
|
|
/// an inconsistent state compared to what's in the database.
|
|
/// - ID 0 is reserved for new models and should not be used for existing models.
|
|
fn set(&self, value: &V) -> Result<(u32, V), Error<Self::Error>>;
|
|
|
|
/// Delete all items from the db with a given index.
|
|
fn delete<I, Q>(&self, key: &Q) -> Result<(), Error<Self::Error>>
|
|
where
|
|
I: Index<Model = V>,
|
|
I::Key: Borrow<Q>,
|
|
Q: ToString + Serialize + core::fmt::Debug + Sync + ?Sized;
|
|
|
|
/// Delete an object with a given ID
|
|
fn delete_by_id(&self, id: u32) -> Result<(), Error<Self::Error>>;
|
|
|
|
/// Get all objects from the collection
|
|
fn get_all(&self) -> Result<Vec<V>, Error<Self::Error>>;
|
|
|
|
/// Begin a transaction for this collection
|
|
fn begin_transaction(
|
|
&self,
|
|
) -> Result<Box<dyn Transaction<Error = Self::Error>>, Error<Self::Error>>;
|
|
}
|
|
|
|
/// Errors returned by the DB implementation
|
|
#[derive(Debug)]
|
|
pub enum Error<E> {
|
|
/// Error in the underlying database
|
|
DB(E),
|
|
/// Error decoding a stored model
|
|
Decode(bincode::error::DecodeError),
|
|
/// Error encoding a model for storage
|
|
Encode(bincode::error::EncodeError),
|
|
/// Invalid ID used (e.g., using ID 0 for an existing model)
|
|
InvalidId(String),
|
|
/// ID mismatch (e.g., expected ID 5 but got ID 6)
|
|
IdMismatch(String),
|
|
/// ID collision (e.g., trying to create a model with an ID that already exists)
|
|
IdCollision(String),
|
|
/// Type error (e.g., trying to get a model of the wrong type)
|
|
TypeError,
|
|
}
|
|
|
|
impl<E> From<bincode::error::DecodeError> for Error<E> {
|
|
fn from(value: bincode::error::DecodeError) -> Self {
|
|
Error::Decode(value)
|
|
}
|
|
}
|
|
|
|
impl<E> From<bincode::error::EncodeError> for Error<E> {
|
|
fn from(value: bincode::error::EncodeError) -> Self {
|
|
Error::Encode(value)
|
|
}
|
|
}
|
|
|
|
impl<E: std::fmt::Debug + std::fmt::Display> std::fmt::Display for Error<E> {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
match self {
|
|
Error::DB(e) => write!(f, "Database error: {}", e),
|
|
Error::Decode(e) => write!(f, "Failed to decode model: {}", e),
|
|
Error::Encode(e) => write!(f, "Failed to encode model: {}", e),
|
|
Error::InvalidId(s) => write!(f, "Invalid ID: {}", s),
|
|
Error::IdMismatch(s) => write!(f, "ID Mismatch: {}", s),
|
|
Error::IdCollision(s) => write!(f, "ID Collision: {}", s),
|
|
Error::TypeError => write!(f, "Type error"),
|
|
}
|
|
}
|
|
}
|
|
/// A transaction that can be committed or rolled back
|
|
pub trait Transaction {
|
|
/// Error type for transaction operations
|
|
type Error: std::fmt::Debug;
|
|
|
|
/// Begin a transaction
|
|
fn begin(&self) -> Result<(), Error<Self::Error>>;
|
|
|
|
/// Commit a transaction
|
|
fn commit(&self) -> Result<(), Error<Self::Error>>;
|
|
|
|
/// Roll back a transaction
|
|
fn rollback(&self) -> Result<(), Error<Self::Error>>;
|
|
|
|
/// Check if a transaction is active
|
|
fn is_active(&self) -> bool;
|
|
}
|