dinoco_engine 0.0.1

Database adapters, query execution, and migration engine components for Dinoco.
Documentation
extern crate self as dinoco_engine;

use std::sync::atomic::{AtomicUsize, Ordering};

mod config;
mod data;
mod databases;
mod error;
mod helpers;
mod planner;
mod query;
mod traits;
mod value;

pub use config::*;
pub use data::*;
pub use databases::*;
pub use error::*;
pub use helpers::*;
pub use planner::*;
pub use query::*;
pub use traits::*;
pub use value::*;

pub type DinocoResult<T> = Result<T, DinocoError>;

pub struct DinocoClient<T: DinocoAdapter> {
    pub adapter: T,
    pub read_replicas: Vec<T>,
    read_replica_state: AtomicUsize,
}

impl DinocoClient<PostgresAdapter> {
    pub async fn new(url: String, reads: Vec<String>, config: DinocoClientConfig) -> DinocoResult<Self> {
        config.initialize_runtime();
        let adapter = PostgresAdapter::connect(url, config.clone()).await?;

        let mut read_replicas: Vec<PostgresAdapter> = Vec::with_capacity(reads.len());

        for read in reads {
            let adapter = PostgresAdapter::connect(read, config.clone()).await?;
            read_replicas.push(adapter);
        }

        Ok(Self { adapter, read_replicas, read_replica_state: AtomicUsize::new(0) })
    }
}

impl DinocoClient<MySqlAdapter> {
    pub async fn new(url: String, reads: Vec<String>, config: DinocoClientConfig) -> DinocoResult<Self> {
        config.initialize_runtime();
        let adapter = MySqlAdapter::connect(url, config.clone()).await?;

        let mut read_replicas: Vec<MySqlAdapter> = Vec::with_capacity(reads.len());

        for read in reads {
            let adapter = MySqlAdapter::connect(read, config.clone()).await?;
            read_replicas.push(adapter);
        }

        Ok(Self { adapter, read_replicas, read_replica_state: AtomicUsize::new(0) })
    }
}

impl DinocoClient<SqliteAdapter> {
    pub async fn new(url: String, reads: Vec<String>, config: DinocoClientConfig) -> DinocoResult<Self> {
        config.initialize_runtime();
        let adapter = SqliteAdapter::connect(url, config.clone()).await?;

        let mut read_replicas: Vec<SqliteAdapter> = Vec::with_capacity(reads.len());

        for read in reads {
            let adapter = SqliteAdapter::connect(read, config.clone()).await?;
            read_replicas.push(adapter);
        }

        Ok(Self { adapter, read_replicas, read_replica_state: AtomicUsize::new(0) })
    }
}

impl<T: DinocoAdapter> DinocoClient<T> {
    pub fn primary(&self) -> &T {
        &self.adapter
    }

    pub fn reader(&self) -> &T {
        match self.read_replicas.len() {
            0 => &self.adapter,
            1 => &self.read_replicas[0],
            len => &self.read_replicas[self.read_replica_state.fetch_add(1, Ordering::Relaxed) % len],
        }
    }

    pub fn read_adapter(&self, read_in_primary: bool) -> &T {
        if read_in_primary { self.primary() } else { self.reader() }
    }
}