Done first draft of strongly typed migrations

This commit is contained in:
Mikayla Maki 2022-11-10 15:29:29 -08:00
parent 4a00f0b062
commit c84201fc9f
18 changed files with 396 additions and 448 deletions

View file

@ -0,0 +1,39 @@
use crate::connection::Connection;
pub trait Domain: Send + Sync + Clone {
fn migrate(conn: &Connection) -> anyhow::Result<()>;
}
impl<D1: Domain, D2: Domain> Domain for (D1, D2) {
fn migrate(conn: &Connection) -> anyhow::Result<()> {
D1::migrate(conn)?;
D2::migrate(conn)
}
}
impl<D1: Domain, D2: Domain, D3: Domain> Domain for (D1, D2, D3) {
fn migrate(conn: &Connection) -> anyhow::Result<()> {
D1::migrate(conn)?;
D2::migrate(conn)?;
D3::migrate(conn)
}
}
impl<D1: Domain, D2: Domain, D3: Domain, D4: Domain> Domain for (D1, D2, D3, D4) {
fn migrate(conn: &Connection) -> anyhow::Result<()> {
D1::migrate(conn)?;
D2::migrate(conn)?;
D3::migrate(conn)?;
D4::migrate(conn)
}
}
impl<D1: Domain, D2: Domain, D3: Domain, D4: Domain, D5: Domain> Domain for (D1, D2, D3, D4, D5) {
fn migrate(conn: &Connection) -> anyhow::Result<()> {
D1::migrate(conn)?;
D2::migrate(conn)?;
D3::migrate(conn)?;
D4::migrate(conn)?;
D5::migrate(conn)
}
}

View file

@ -1,5 +1,6 @@
pub mod bindable;
pub mod connection;
pub mod domain;
pub mod migrations;
pub mod savepoint;
pub mod statement;

View file

@ -1,5 +1,5 @@
use anyhow::Result;
use indoc::{formatdoc, indoc};
use indoc::formatdoc;
use crate::connection::Connection;

View file

@ -1,26 +1,26 @@
use std::{ops::Deref, sync::Arc};
use std::{marker::PhantomData, ops::Deref, sync::Arc};
use connection::Connection;
use thread_local::ThreadLocal;
use crate::{connection, migrations::Migration};
use crate::{connection, domain::Domain};
pub struct ThreadSafeConnection {
pub struct ThreadSafeConnection<D: Domain> {
uri: Arc<str>,
persistent: bool,
initialize_query: Option<&'static str>,
migrations: Option<&'static [Migration]>,
connection: Arc<ThreadLocal<Connection>>,
_pd: PhantomData<D>,
}
impl ThreadSafeConnection {
impl<D: Domain> ThreadSafeConnection<D> {
pub fn new(uri: &str, persistent: bool) -> Self {
Self {
uri: Arc::from(uri),
persistent,
initialize_query: None,
migrations: None,
connection: Default::default(),
_pd: PhantomData,
}
}
@ -31,13 +31,6 @@ impl ThreadSafeConnection {
self
}
/// Migrations have to be run per connection because we fallback to memory
/// so this needs
pub fn with_migrations(mut self, migrations: &'static [Migration]) -> Self {
self.migrations = Some(migrations);
self
}
/// Opens a new db connection with the initialized file path. This is internal and only
/// called from the deref function.
/// If opening fails, the connection falls back to a shared memory connection
@ -50,21 +43,33 @@ impl ThreadSafeConnection {
fn open_shared_memory(&self) -> Connection {
Connection::open_memory(self.uri.as_ref())
}
// Open a new connection for the given domain, leaving this
// connection intact.
pub fn for_domain<D2: Domain>(&self) -> ThreadSafeConnection<D2> {
ThreadSafeConnection {
uri: self.uri.clone(),
persistent: self.persistent,
initialize_query: self.initialize_query,
connection: Default::default(),
_pd: PhantomData,
}
}
}
impl Clone for ThreadSafeConnection {
impl<D: Domain> Clone for ThreadSafeConnection<D> {
fn clone(&self) -> Self {
Self {
uri: self.uri.clone(),
persistent: self.persistent,
initialize_query: self.initialize_query.clone(),
migrations: self.migrations.clone(),
connection: self.connection.clone(),
_pd: PhantomData,
}
}
}
impl Deref for ThreadSafeConnection {
impl<D: Domain> Deref for ThreadSafeConnection<D> {
type Target = Connection;
fn deref(&self) -> &Self::Target {
@ -83,13 +88,7 @@ impl Deref for ThreadSafeConnection {
.unwrap();
}
if let Some(migrations) = self.migrations {
for migration in migrations {
migration
.run(&connection)
.expect(&format!("Migrations failed to execute: {:?}", migration));
}
}
D::migrate(&connection).expect("Migrations failed");
connection
})