append_db_postgres 0.2.0

Support for PostgreSQL for append-db crate.
Documentation
pub mod backend;
pub mod update;

pub use update::{HasUpdateTag, VersionedState};
#[cfg(feature = "derive")]
pub use append_db_postgres_derive::*;

#[cfg(test)]
mod tests {
    use crate::backend::Postgres;
    use crate::update::{
        HasUpdateTag, VersionedState,
    };
    use append_db::backend::class::{SnapshotedUpdate, State, StateBackend};
    use append_db::db::AppendDb;
    use append_db_postgres_derive::*;
    use serde::{Deserialize, Serialize};
    use std::convert::Infallible;
    use std::ops::Deref;
    use crate as append_db_postgres;

    #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, VersionedState)]
    struct State0 {
        field: u64,
    }

    #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, VersionedState)]
    struct State1 {
        field: String
    }

    #[derive(Clone, Debug, PartialEq, HasUpdateTag)]
    enum Update1{
        Append(String),
        Set(String)
    }

    #[derive(Clone, Debug, PartialEq, HasUpdateTag)]
    enum Update0 {
        Add(u64),
        Set(u64),
    }

    impl State for State0 {
        type Update = Update0;
        type Err = Infallible;

        fn update(&mut self, upd: Update0) -> Result<(), Self::Err> {
            match upd {
                Update0::Add(v) => self.field += v,
                Update0::Set(v) => self.field = v,
            }
            Ok(())
        }
    }

    impl State for State1 {
        type Update = Update1;
        type Err = Infallible;

        const TABLE: &'static str = "updates2";

        fn update(&mut self, upd: Self::Update) -> Result<(), Self::Err> {
            match upd {
                Update1::Append(s) => self.field.push_str(s.as_str()),
                Update1::Set(s) => self.field = s,
            }
            Ok(())
        }
    }

    #[sqlx_database_tester::test(pool(variable = "pool", migrations = "./migrations"))]
    async fn postgres_init() {
        let state0 = State0 { field: 42 };
        let db = AppendDb::new(Postgres::new(pool), state0.clone());
        assert_eq!(db.get().await.deref(), &state0);
    }

    #[sqlx_database_tester::test(pool(variable = "pool", migrations = "./migrations"))]
    async fn two_tables_postgres_init() {
        let postgres = Postgres::new(pool);
        let state0 = State0 { field: 42 };
        let db = AppendDb::new(postgres.clone(), state0.clone());
        assert_eq!(db.get().await.deref(), &state0);

        let state1 = State1 {field: String::new()};
        let postgres1 = postgres.duplicate();
        let db = AppendDb::new(postgres1, state1.clone());
        assert_eq!(db.get().await.deref(), &state1);
    }    

    #[sqlx_database_tester::test(pool(variable = "pool", migrations = "./migrations"))]
    async fn postgres_updates() {
        let state0 = State0 { field: 42 };
        let mut db = AppendDb::new(Postgres::new(pool), state0.clone());
        db.update(Update0::Add(1)).await.expect("update");
        assert_eq!(db.get().await.deref().field, 43);
        db.update(Update0::Set(4)).await.expect("update");
        assert_eq!(db.get().await.deref().field, 4);
    }

    #[sqlx_database_tester::test(pool(variable = "pool", migrations = "./migrations"))]
    async fn two_tables_test_updates(){
        let postgres = Postgres::new(pool);
        let state0 = State0 { field: 42 };
        let mut db = AppendDb::new(postgres.clone(), state0.clone());
        db.update(Update0::Add(1)).await.expect("update");
        assert_eq!(db.get().await.deref().field, 43);
        db.update(Update0::Set(4)).await.expect("update");
        assert_eq!(db.get().await.deref().field, 4);

        let state1 = State1 {field: String::new()};
        let postgres1 = postgres.duplicate();
        let mut db1 = AppendDb::new(postgres1, state1.clone());
        db1.update(Update1::Append("Hello".to_string())).await.expect("update");
        assert_eq!(db1.get().await.deref().field, "Hello".to_string());
        db1.update(Update1::Set("Hello world!".to_string())).await.expect("update");
        assert_eq!(db1.get().await.deref().field, "Hello world!".to_string());        
    }     

    #[sqlx_database_tester::test(pool(variable = "pool", migrations = "./migrations"))]
    async fn postgres_snapshot() {
        let state0 = State0 { field: 42 };
        let mut db = AppendDb::new(Postgres::new(pool), state0.clone());
        db.update(Update0::Add(1)).await.expect("update");
        db.snapshot().await.expect("snapshot");

        let upds = db.backend.updates().await.expect("collected");
        assert_eq!(upds, vec![SnapshotedUpdate::Snapshot(State0 { field: 43 })])
    }

    #[sqlx_database_tester::test(pool(variable = "pool", migrations = "./migrations"))]
    async fn two_tables_postgres_snapshot() {
        let postgres0 = Postgres::new(pool);
        let state0 = State0 { field: 42 };
        let mut db = AppendDb::new(postgres0.clone(), state0.clone());
        db.update(Update0::Add(1)).await.expect("update");
        db.snapshot().await.expect("snapshot");

        let upds = db.backend.updates().await.expect("collected");
        assert_eq!(upds, vec![SnapshotedUpdate::Snapshot(State0 { field: 43 })]);

        let postgres1 = postgres0.duplicate();
        let state1 = State1 { field: "Hello".to_string() };
        let mut db1 = AppendDb::new(postgres1, state1.clone());
        db1.update(Update1::Append(" world!".to_string())).await.expect("update");
        db1.snapshot().await.expect("snapshot");
        let upds1 = db1.backend.updates().await.expect("collected");
        assert_eq!(upds1, vec![SnapshotedUpdate::Snapshot(State1 { field: "Hello world!".to_string() })]);
    }    

    #[sqlx_database_tester::test(pool(variable = "pool", migrations = "./migrations"))]
    async fn postgres_reconstruct() {
        let state0 = State0 { field: 42 };
        let mut db = AppendDb::new(Postgres::new(pool), state0.clone());
        db.update(Update0::Add(1)).await.expect("update");
        db.update(Update0::Set(4)).await.expect("update");

        db.load().await.expect("load");
        assert_eq!(db.get().await.deref().field, 4);
    }

    #[sqlx_database_tester::test(pool(variable = "pool", migrations = "./migrations"))]
    async fn two_tables_postgres_reconstruct() {
        let postgres = Postgres::new(pool);
        let state0 = State0 { field: 42 };
        let mut db = AppendDb::new(postgres.clone(), state0.clone());
        db.update(Update0::Add(1)).await.expect("update");
        db.update(Update0::Set(4)).await.expect("update");
        db.load().await.expect("load");
        assert_eq!(db.get().await.deref().field, 4);

        let state1 = State1 {field: String::new()};
        let postgres1 = postgres.duplicate();
        let mut db1 = AppendDb::new(postgres1, state1.clone());
        db1.update(Update1::Append("Hello".to_string())).await.expect("update");
        db1.update(Update1::Set("Hello world!".to_string())).await.expect("update");

        db1.load().await.expect("load");
        assert_eq!(db1.get().await.deref().field, "Hello world!".to_string());
    }    

    #[sqlx_database_tester::test(pool(variable = "pool", migrations = "./migrations"))]
    async fn postgres_reconstruct_snapshot() {
        let state0 = State0 { field: 42 };
        let mut db = AppendDb::new(Postgres::new(pool), state0.clone());
        db.update(Update0::Add(1)).await.expect("update");
        db.snapshot().await.expect("snapshot");
        db.update(Update0::Set(4)).await.expect("update");

        db.load().await.expect("load");
        assert_eq!(db.get().await.deref().field, 4);
    }

    #[sqlx_database_tester::test(pool(variable = "pool", migrations = "./migrations"))]
    async fn two_tables_postgres_reconstruct_snapshot() {
        let postgres = Postgres::new(pool);
        let state0 = State0 { field: 42 };
        let mut db = AppendDb::new(postgres.clone(), state0.clone());
        db.update(Update0::Add(1)).await.expect("update");
        db.snapshot().await.expect("snapshot");
        db.update(Update0::Set(4)).await.expect("update");

        db.load().await.expect("load");
        assert_eq!(db.get().await.deref().field, 4);

        let state1 = State1 {field: String::new()};
        let postgres1 = postgres.duplicate();
        let mut db1 = AppendDb::new(postgres1, state1.clone());

        db1.update(Update1::Append("Hello ') drop table updates2;".to_string())).await.expect("update");
        db1.snapshot().await.expect("snapshot");
        db1.update(Update1::Set("Hello world! ') drop table updates2;".to_string())).await.expect("update");

        db1.load().await.expect("load");
        assert_eq!(db1.get().await.deref().field, "Hello world! ') drop table updates2;".to_string());
    }
}