127 lines
2.5 KiB
Rust
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!()
|
|
}
|
|
}
|
|
}
|