mockgres 0.0.25

An in-memory database that replicates a reasonable subset of Postgres functionality to make unit tests that rely on a database to run.
Documentation
use super::*;

impl Db {
    pub fn rollback_transaction_changes(
        &mut self,
        changes: &TxnChanges,
        txid: TxId,
    ) -> anyhow::Result<()> {
        self.rollback_inserts(&changes.inserted, txid)?;
        self.rollback_xmax(&changes.updated_old, txid)?;
        Ok(())
    }

    fn rollback_inserts(&mut self, ptrs: &[RowPointer], txid: TxId) -> anyhow::Result<()> {
        for ptr in ptrs {
            let Some(meta) = self.table_meta_by_id(ptr.table_id).cloned() else {
                continue;
            };
            if let Some(mut table) = self.tables.remove(&ptr.table_id) {
                let mut removed_rows = Vec::new();
                if let Some(versions) = table.rows_by_key.get_mut(&ptr.key) {
                    versions.retain(|v| {
                        if v.xmin == txid {
                            removed_rows.push(v.data.clone());
                            false
                        } else {
                            true
                        }
                    });
                    if versions.is_empty() {
                        table.rows_by_key.remove(&ptr.key);
                    }
                }
                if !removed_rows.is_empty() {
                    let row_id = row_key_to_row_id(&ptr.key)?;
                    for row in removed_rows {
                        if let Some(pk_key) = build_primary_key_row_key(&meta, &row)?
                            && let Some(pk_map) = table.pk_map.as_mut()
                            && let Some(existing) = pk_map.get(&pk_key)
                            && *existing == row_id
                        {
                            pk_map.remove(&pk_key);
                        }
                        let fk_keys = meta
                            .foreign_keys
                            .iter()
                            .map(|fk| build_fk_parent_key(&row, fk))
                            .collect::<Vec<_>>();
                        remove_fk_rev_entries(&mut table, &meta, row_id, &fk_keys);
                        let unique_keys = build_unique_index_values(&meta, &row);
                        remove_unique_entries(&mut table, &unique_keys, row_id);
                    }
                }
                self.tables.insert(ptr.table_id, table);
            } else {
                return Err(sql_err(
                    "XX000",
                    format!("missing storage for table id {}", ptr.table_id),
                ));
            }
        }
        Ok(())
    }

    fn rollback_xmax(&mut self, ptrs: &[RowPointer], txid: TxId) -> anyhow::Result<()> {
        for ptr in ptrs {
            let Some(meta) = self.table_meta_by_id(ptr.table_id).cloned() else {
                continue;
            };
            if let Some(mut table) = self.tables.remove(&ptr.table_id) {
                let mut restored_rows = Vec::new();
                if let Some(versions) = table.rows_by_key.get_mut(&ptr.key) {
                    for version in versions.iter_mut() {
                        if version.xmax == Some(txid) {
                            version.xmax = None;
                            restored_rows.push(version.data.clone());
                        }
                    }
                }
                if !restored_rows.is_empty() {
                    let row_id = row_key_to_row_id(&ptr.key)?;
                    for row in restored_rows {
                        if let Some(pk_key) = build_primary_key_row_key(&meta, &row)?
                            && let Some(pk_map) = table.pk_map.as_mut()
                        {
                            pk_map.insert(pk_key, row_id);
                        }
                        let fk_keys = meta
                            .foreign_keys
                            .iter()
                            .map(|fk| build_fk_parent_key(&row, fk))
                            .collect::<Vec<_>>();
                        add_fk_rev_entries(&mut table, &meta, row_id, &fk_keys);
                        let unique_keys = build_unique_index_values(&meta, &row);
                        insert_unique_entries_owned(&mut table, unique_keys, row_id);
                    }
                }
                self.tables.insert(ptr.table_id, table);
            } else {
                return Err(sql_err(
                    "XX000",
                    format!("missing storage for table id {}", ptr.table_id),
                ));
            }
        }
        Ok(())
    }
}