hermit/src/db/mod.rs

127 lines
2.5 KiB
Rust

//! Database abstraction layer used by Hermit.
use crate::{ Id, Result };
use futures::prelude::*;
use sqlx::{Executor, pool::PoolConnection};
/// `const ()` but in Rust
fn void <T> (_: T) -> () { () }
type Database = sqlx::Postgres;
/// Specifies how to connect to the database.
pub struct Config {}
/// A database client.
///
/// Cloning this client is cheap.
#[derive(Clone)]
pub struct Client {
/// The internal connection pool.
pool: sqlx::Pool<Database>,
}
impl Client {
/// Attempt to connect to the database using the provided configuration.
pub async fn new (_: Config) -> Result<Client> {
todo!()
}
/// Fetch the data mapped to the given `key` from the database.
pub async fn get <T> (&self, key: T::Key) -> Result<Option<T>>
where
T: Get,
{
self.with_conn(|c| T::get(key, c))
.await
}
/// Perfom an insertion on the database.
pub async fn insert <T> (&mut self, data: T) -> Result<()>
where
T: Insert,
{
self.with_conn(|c| data.set(c))
.await
.map(void)
}
/// Delete something from the database.
pub async fn delete <T> (&mut self, key: T::Key) -> Result<()>
where
T: Delete,
{
self.with_conn(|c| T::del(key, c))
.await
}
/// Handles the getting-a-connection logic.
async fn with_conn <F, O, T> (&self, f: F) -> Result<T>
where
F: FnOnce (&mut PoolConnection<Database>) -> O,
O: Future<Output = Result<T>>,
{
use crate::err;
self.pool
.acquire()
.map_err(err)
.and_then(|mut c| {
f(&mut c)
})
.await
}
}
pub trait Object: Sized {
type Key: Eq;
fn key (&self) -> &Self::Key;
}
pub trait Insert: Object {
type Future: Future<Output = Result<Self::Key>>;
fn set <'e, E> (self, exec: E) -> Self::Future
where
E: Executor<'e>;
}
pub trait Delete: Object {
type Future: Future<Output = Result<()>>;
fn del <'e, E> (key: Self::Key, exec: E) -> Self::Future where E: Executor<'e>;
}
pub trait Get: Object {
type Future: Future<Output = Result<Option<Self>>>;
fn get <'e, E> (key: Self::Key, exec: E) -> Self::Future where E: Executor<'e>;
}
pub mod ops {
//! Database operations (queries and updates).
use super::*;
pub struct Following {
pub from: Id,
pub to: Id,
pub id: Id,
}
impl Object for Following {
type Key = Id;
fn key (&self) -> &Self::Key { &self.id }
}
impl Insert for Following {
type Future = future::BoxFuture<'static, Result<Id>>;
fn set <'e, E> (self, exec: E) -> Self::Future
where
E: Executor<'e>
{
todo!()
}
}
}