#![cfg_attr(docsrs, feature(doc_cfg))]
#![doc(html_favicon_url = "https://nil.dev.br/favicon.png")]
#![feature(
const_clone,
const_cmp,
const_convert,
const_trait_impl,
derive_const,
str_as_str
)]
pub mod error;
mod r#impl;
mod migration;
pub mod model;
mod schema;
pub mod sql_types;
use crate::error::Result;
use crate::migration::run_pending_migrations;
use diesel::{SqliteConnection, sql_query};
use diesel_async::RunQueryDsl;
use diesel_async::pooled_connection::AsyncDieselConnectionManager;
use diesel_async::pooled_connection::deadpool::{Hook, HookError, Pool};
use diesel_async::sync_connection_wrapper::SyncConnectionWrapper;
use std::borrow::Cow;
type Conn = SyncConnectionWrapper<SqliteConnection>;
#[must_use]
#[derive(Clone)]
pub struct Database {
pool: Pool<Conn>,
}
impl Database {
pub fn new(url: &str) -> Result<Self> {
run_pending_migrations(url)?;
let manager = AsyncDieselConnectionManager::new(url);
let pool = Pool::builder(manager)
.max_size(4)
.post_create(Hook::async_fn(move |conn: &mut Conn, _| {
Box::pin(async move {
execute(conn, "PRAGMA journal_mode=WAL;").await?;
execute(conn, "PRAGMA synchronous=NORMAL;").await?;
execute(conn, "PRAGMA busy_timeout=5000;").await?;
execute(conn, "PRAGMA foreign_keys=ON;").await?;
Ok(())
})
}))
.build()?;
Ok(Self { pool })
}
}
#[doc(hidden)]
#[macro_export]
macro_rules! conn {
($database:expr) => {
&mut *$database.pool.get().await?
};
}
async fn execute(conn: &mut Conn, query: &str) -> Result<(), HookError> {
sql_query(query)
.execute(conn)
.await
.map_err(|err| HookError::Message(Cow::Owned(err.to_string())))?;
Ok(())
}