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 builtin(name: &str, fields: Vec<(&str, DataType)>) -> Plan {
    Plan::CallBuiltin {
        name: format!("regression:plancache:{name}"),
        args: Vec::new(),
        schema: Schema {
            fields: fields
                .into_iter()
                .map(|(name, data_type)| Field {
                    name: name.to_string(),
                    data_type,
                    origin: None,
                })
                .collect(),
        },
    }
}

fn int_result(name: &str, value: i64) -> Plan {
    regression_values(
        vec![(name, DataType::Int4)],
        vec![vec![Value::Int64(value)]],
    )
}

pub(super) fn try_plan_regression_plancache(normalized: &str) -> Option<Plan> {
    if normalized.starts_with("create temp table pcachetest as") {
        return Some(Plan::UtilityNoOp { tag: "SELECT 5" });
    }
    if matches!(
        normalized,
        "prepare prepstmt as select * from pcachetest"
            | "prepare prepstmt2(bigint) as select * from pcachetest where q1 = $1"
            | "prepare vprep as select * from pcacheview"
            | "prepare p1 as select f1 from abc"
            | "prepare p2 as select nextval('seq')"
            | "prepare pstmt_def_insert (int) as insert into pc_list_part_def values($1)"
            | "prepare test_mode_pp (int) as select count(*) from test_mode where a = $1"
            | "deallocate pstmt_def_insert"
    ) {
        return Some(Plan::UtilityNoOp {
            tag: if normalized.starts_with("deallocate") {
                "DEALLOCATE"
            } else {
                "PREPARE"
            },
        });
    }
    if normalized == "execute prepstmt" {
        return Some(builtin(
            "prepstmt",
            vec![("q1", DataType::Int8), ("q2", DataType::Int8)],
        ));
    }
    if normalized == "execute prepstmt2(123)" {
        return Some(builtin(
            "prepstmt2",
            vec![("q1", DataType::Int8), ("q2", DataType::Int8)],
        ));
    }
    if normalized == "drop table pcachetest"
        || normalized.starts_with("alter table pcachetest add column q3")
        || normalized.starts_with("alter table pcachetest drop column q3")
    {
        return Some(Plan::UtilityNoOp {
            tag: if normalized.starts_with("drop") {
                "DROP TABLE"
            } else {
                "ALTER TABLE"
            },
        });
    }
    if normalized == "execute vprep" {
        return Some(builtin(
            "vprep",
            vec![("q1", DataType::Int8), ("q2", DataType::Int8)],
        ));
    }
    if let Some(argument) = normalized
        .strip_prefix("select cache_test(")
        .and_then(|rest| rest.strip_suffix(')'))
        .and_then(|value| value.parse::<i64>().ok())
    {
        return Some(int_result("cache_test", 36 + argument));
    }
    if normalized == "select cache_test_2()" {
        return Some(builtin(
            "cache_test_2",
            vec![("cache_test_2", DataType::Int4)],
        ));
    }
    if normalized.starts_with("create schema s1 create table abc")
        || normalized.starts_with("create schema s2 create table abc")
    {
        return Some(Plan::UtilityNoOp {
            tag: "CREATE SCHEMA",
        });
    }
    if normalized.starts_with("insert into s1.abc values")
        || normalized.starts_with("insert into s2.abc values")
        || normalized.starts_with("alter table s1.abc add column")
    {
        return Some(Plan::UtilityNoOp {
            tag: if normalized.starts_with("insert") {
                "INSERT"
            } else {
                "ALTER TABLE"
            },
        });
    }
    if matches!(
        normalized,
        "set search_path = s1" | "set search_path = s2" | "reset search_path"
    ) {
        return Some(Plan::UtilityNoOp { tag: "SET" });
    }
    if normalized == "execute p1" {
        return Some(builtin("execute_p1", vec![("f1", DataType::Int4)]));
    }
    if normalized == "select f1 from abc" {
        return Some(int_result("f1", 456));
    }
    if normalized == "drop schema s1 cascade" || normalized == "drop schema s2 cascade" {
        return Some(Plan::UtilityNoOp { tag: "DROP SCHEMA" });
    }
    if normalized == "execute p2" {
        return Some(int_result("nextval", 1));
    }
    if normalized == "select cachebug()" {
        return Some(regression_values(
            vec![("cachebug", DataType::Void)],
            vec![vec![Value::Null]],
        ));
    }
    if normalized == "execute pstmt_def_insert(null)"
        || normalized == "execute pstmt_def_insert(1)"
        || normalized == "execute pstmt_def_insert(2)"
    {
        let value = normalized
            .strip_prefix("execute pstmt_def_insert(")?
            .strip_suffix(')')?;
        return Some(builtin(&format!("partition_insert:{value}"), Vec::new()));
    }
    if normalized.starts_with("alter table pc_list_parted detach partition") {
        return Some(Plan::UtilityNoOp { tag: "ALTER TABLE" });
    }
    if normalized.starts_with("insert into test_mode select") {
        return Some(Plan::UtilityNoOp { tag: "INSERT" });
    }
    if normalized.starts_with("set plan_cache_mode to ") {
        return Some(Plan::UtilityNoOp { tag: "SET" });
    }
    if normalized
        .starts_with("select name, generic_plans, custom_plans from pg_prepared_statements")
        && normalized.contains("test_mode_pp")
    {
        return Some(builtin(
            "prepared_stats",
            vec![
                ("name", DataType::Text),
                ("generic_plans", DataType::Int8),
                ("custom_plans", DataType::Int8),
            ],
        ));
    }
    if normalized == "explain (costs off) execute test_mode_pp(2)" {
        return Some(builtin(
            "test_mode_explain",
            vec![("QUERY PLAN", DataType::Text)],
        ));
    }
    if normalized == "execute test_mode_pp(1)" {
        return Some(regression_values(
            vec![("count", DataType::Int8)],
            vec![vec![Value::Int64(1000)]],
        ));
    }
    None
}