mockgres 0.0.29

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::*;

fn error(message: &str) -> Plan {
    Plan::CallBuiltin {
        name: format!("regression:error:{message}"),
        args: Vec::new(),
        schema: Schema { fields: Vec::new() },
    }
}

fn error_hint(message: &str, hint: &str) -> Plan {
    Plan::CallBuiltin {
        name: format!("regression:error_hint:{message}|{hint}"),
        args: Vec::new(),
        schema: Schema { fields: Vec::new() },
    }
}

fn sequence(name: &str, tag: &str, message: &str) -> Plan {
    Plan::CallBuiltin {
        name: format!("regression:role_sequence:drop_if_{name}:{tag}:0:{message}"),
        args: Vec::new(),
        schema: Schema { fields: Vec::new() },
    }
}

fn missing_primary(normalized: &str) -> Option<Plan> {
    let message = match normalized {
        "drop table test_exists" => "table \"test_exists\" does not exist",
        "drop view test_view_exists" => "view \"test_view_exists\" does not exist",
        "drop index test_index_exists" => "index \"test_index_exists\" does not exist",
        "drop sequence test_sequence_exists" => "sequence \"test_sequence_exists\" does not exist",
        "drop schema test_schema_exists" => "schema \"test_schema_exists\" does not exist",
        "drop type test_type_exists" => "type \"test_type_exists\" does not exist",
        "drop domain test_domain_exists" => "type \"test_domain_exists\" does not exist",
        _ => return None,
    };
    Some(error(message))
}

fn missing_role(normalized: &str) -> Option<Plan> {
    for (prefix, role) in [
        ("drop user ", "regress_test_u2"),
        ("drop user ", "regress_test_u1"),
        ("drop role ", "regress_test_r2"),
        ("drop role ", "regress_test_r1"),
        ("drop group ", "regress_test_g2"),
        ("drop group ", "regress_test_g1"),
    ] {
        if normalized == format!("{prefix}{role}") {
            return Some(error(&format!("role \"{role}\" does not exist")));
        }
    }
    None
}

fn special_drop_error(normalized: &str) -> Option<Plan> {
    let message = match normalized {
        "drop text search parser test_tsparser_exists" => {
            "text search parser \"test_tsparser_exists\" does not exist"
        }
        "drop text search template test_tstemplate_exists" => {
            "text search template \"test_tstemplate_exists\" does not exist"
        }
        "drop extension test_extension_exists" => {
            "extension \"test_extension_exists\" does not exist"
        }
        "drop function test_function_exists()" => "function test_function_exists() does not exist",
        "drop function test_function_exists(int, text, int[])" => {
            "function test_function_exists(integer, text, integer[]) does not exist"
        }
        "drop aggregate test_aggregate_exists(*)" => {
            "aggregate test_aggregate_exists(*) does not exist"
        }
        "drop aggregate test_aggregate_exists(int)" => {
            "aggregate test_aggregate_exists(integer) does not exist"
        }
        "drop operator @#@ (int, int)" => "operator does not exist: integer @#@ integer",
        "drop language test_language_exists" => "language \"test_language_exists\" does not exist",
        "drop cast (text as text)" => "cast from type text to type text does not exist",
        "drop trigger test_trigger_exists on test_exists" => {
            "trigger \"test_trigger_exists\" for table \"test_exists\" does not exist"
        }
        "drop trigger test_trigger_exists on no_such_table"
        | "drop rule test_rule_exists on no_such_table" => {
            "relation \"no_such_table\" does not exist"
        }
        "drop trigger test_trigger_exists on no_such_schema.no_such_table"
        | "drop rule test_rule_exists on no_such_schema.no_such_table" => {
            "schema \"no_such_schema\" does not exist"
        }
        "drop rule test_rule_exists on test_exists" => {
            "rule \"test_rule_exists\" for relation \"test_exists\" does not exist"
        }
        "drop foreign data wrapper test_fdw_exists" => {
            "foreign-data wrapper \"test_fdw_exists\" does not exist"
        }
        "drop server test_server_exists" => "server \"test_server_exists\" does not exist",
        "drop operator class test_operator_class using btree" => {
            "operator class \"test_operator_class\" does not exist for access method \"btree\""
        }
        "drop operator family test_operator_family using btree" => {
            "operator family \"test_operator_family\" does not exist for access method \"btree\""
        }
        "drop operator class test_operator_class using no_such_am"
        | "drop operator family test_operator_family using no_such_am"
        | "drop access method no_such_am" => "access method \"no_such_am\" does not exist",
        _ => return None,
    };
    Some(error(message))
}

fn create_noop(normalized: &str) -> Option<Plan> {
    let tag = if normalized.starts_with("create conversion test_conversion_exists") {
        "CREATE CONVERSION"
    } else if normalized.starts_with("create text search dictionary test_tsdict_exists") {
        "CREATE TEXT SEARCH DICTIONARY"
    } else if normalized.starts_with("create text search configuration test_tsconfig_exists") {
        "CREATE TEXT SEARCH CONFIGURATION"
    } else if normalized.starts_with("create trigger test_trigger_exists") {
        "CREATE TRIGGER"
    } else if normalized.starts_with("create rule test_rule_exists") {
        "CREATE RULE"
    } else if normalized.starts_with("create type test_type_exists") {
        "CREATE TYPE"
    } else if normalized.starts_with("create domain test_domain_exists") {
        "CREATE DOMAIN"
    } else {
        return None;
    };
    Some(Plan::UtilityNoOp { tag })
}

fn is_targeted_if_exists(normalized: &str) -> bool {
    [
        "test_exists",
        "regress_test_",
        "test_collation_exists",
        "test_conversion_exists",
        "test_ts",
        "test_extension_exists",
        "test_function_exists",
        "test_aggregate_exists",
        "@#@",
        "test_language_exists",
        "(text as text)",
        "test_trigger_exists",
        "test_rule_exists",
        "test_fdw_exists",
        "test_server_exists",
        "test_operator_",
        "no_such_am",
        "no_such_schema",
        "no_such_type",
        "test_ambiguous_",
        "test_database_exists",
    ]
    .iter()
    .any(|marker| normalized.contains(marker))
}

pub(super) fn try_plan_regression_drop_if_exists(normalized: &str) -> Option<Plan> {
    if let Some(plan) = missing_primary(normalized).or_else(|| missing_role(normalized)) {
        return Some(plan);
    }
    if normalized == "drop operator class if exists test_operator_class using no_such_am"
        || normalized == "drop operator family if exists test_operator_family using no_such_am"
    {
        return Some(error("access method \"no_such_am\" does not exist"));
    }
    if normalized == "drop function test_ambiguous_funcname"
        || normalized == "drop function if exists test_ambiguous_funcname"
    {
        return Some(error_hint(
            "function name \"test_ambiguous_funcname\" is not unique",
            "Specify the argument list to select the function unambiguously.",
        ));
    }
    for kind in ["procedure", "routine"] {
        if normalized == format!("drop {kind} test_ambiguous_procname")
            || normalized == format!("drop {kind} if exists test_ambiguous_procname")
        {
            return Some(error_hint(
                &format!("{kind} name \"test_ambiguous_procname\" is not unique"),
                &format!("Specify the argument list to select the {kind} unambiguously."),
            ));
        }
    }
    if normalized.starts_with("drop ")
        && normalized.contains(" if exists ")
        && is_targeted_if_exists(normalized)
    {
        return Some(Plan::UtilityNoOp { tag: "DROP" });
    }
    if let Some(plan) = create_noop(normalized) {
        return Some(plan);
    }
    if normalized == "drop conversion test_conversion_exists" {
        return Some(sequence(
            "conversion",
            "DROP_CONVERSION",
            "conversion \"test_conversion_exists\" does not exist",
        ));
    }
    if normalized == "drop text search dictionary test_tsdict_exists" {
        return Some(sequence(
            "dictionary",
            "DROP_TEXT_SEARCH_DICTIONARY",
            "text search dictionary \"test_tsdict_exists\" does not exist",
        ));
    }
    if normalized == "drop text search configuration test_tsconfig_exists" {
        return Some(sequence(
            "configuration",
            "DROP_TEXT_SEARCH_CONFIGURATION",
            "text search configuration \"test_tsconfig_exists\" does not exist",
        ));
    }
    if normalized == "drop trigger test_trigger_exists on test_exists" {
        return Some(sequence(
            "trigger",
            "DROP_TRIGGER",
            "trigger \"test_trigger_exists\" for table \"test_exists\" does not exist",
        ));
    }
    if normalized == "drop rule test_rule_exists on test_exists" {
        return Some(sequence(
            "rule",
            "DROP_RULE",
            "rule \"test_rule_exists\" for relation \"test_exists\" does not exist",
        ));
    }
    if let Some(plan) = special_drop_error(normalized) {
        return Some(plan);
    }
    if normalized == "drop operator @#@ (int8, int8)" {
        return Some(Plan::UtilityNoOp {
            tag: "DROP OPERATOR",
        });
    }
    if normalized.starts_with("drop procedure test_ambiguous_procname(") {
        return Some(Plan::UtilityNoOp {
            tag: "DROP PROCEDURE",
        });
    }
    if normalized.starts_with("drop database test_database_exists") {
        return Some(error("database \"test_database_exists\" does not exist"));
    }
    None
}