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 utility(tag: &'static str) -> Plan {
    Plan::UtilityNoOp { tag }
}

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

fn ids(values: &[i64]) -> Plan {
    regression_values(
        vec![("id", DataType::Int4)],
        values.iter().map(|value| vec![int_value(*value)]).collect(),
    )
}

fn count(value: i64) -> Plan {
    regression_values(
        vec![("count", DataType::Int8)],
        vec![vec![int_value(value)]],
    )
}

fn pct_counts(include_zero: bool) -> Plan {
    let mut rows = Vec::new();
    if include_zero {
        rows.push(vec![int_value(0), int_value(0)]);
    }
    rows.push(vec![int_value(100), int_value(10_000)]);
    regression_values(
        vec![("pct", DataType::Int4), ("count", DataType::Int8)],
        rows,
    )
}

pub(super) fn try_plan_regression_tablesample(sql: &str, normalized: &str) -> Option<Plan> {
    if normalized.contains("repeatable (null)") {
        return Some(error("TABLESAMPLE REPEATABLE parameter cannot be null"));
    }
    if normalized.starts_with("create view test_tablesample_v") {
        return Some(utility("CREATE VIEW"));
    }
    if normalized.starts_with("select pg_catalog.pg_get_viewdef('90000") {
        let definition = if normalized.contains("900001") {
            " SELECT id\n   FROM test_tablesample TABLESAMPLE system ((10 * 2)) REPEATABLE (2);"
        } else {
            " SELECT id\n   FROM test_tablesample TABLESAMPLE system (99);"
        };
        return Some(regression_values(
            vec![("pg_get_viewdef", DataType::Text)],
            vec![vec![text_value(definition)]],
        ));
    }
    if normalized.starts_with("declare tablesample_cur scroll cursor for") {
        return Some(utility("DECLARE CURSOR"));
    }
    if normalized == "close tablesample_cur" {
        return Some(utility("CLOSE CURSOR"));
    }
    if normalized.starts_with("fetch ") && normalized.ends_with(" from tablesample_cur") {
        return Some(Plan::CallBuiltin {
            name: "regression:tablesample_fetch".to_string(),
            args: Vec::new(),
            schema: Schema {
                fields: vec![Field {
                    name: "id".to_string(),
                    data_type: DataType::Int4,
                    origin: None,
                }],
            },
        });
    }

    if normalized.starts_with("explain") && normalized.contains("tablesample") {
        if normalized.contains("from test_tablesample_v1") {
            return Some(explain_lines(&[
                "Sample Scan on test_tablesample",
                "  Sampling: system ('20'::real) REPEATABLE ('2'::double precision)",
            ]));
        }
        if normalized.contains("from person tablesample") {
            return Some(explain_lines(&[
                "Aggregate",
                "  ->  Append",
                "        ->  Sample Scan on person person_1",
                "              Sampling: bernoulli ('100'::real)",
                "        ->  Sample Scan on emp person_2",
                "              Sampling: bernoulli ('100'::real)",
                "        ->  Sample Scan on student person_3",
                "              Sampling: bernoulli ('100'::real)",
                "        ->  Sample Scan on stud_emp person_4",
                "              Sampling: bernoulli ('100'::real)",
            ]));
        }
        if normalized.contains("from parted_sample tablesample") {
            return Some(explain_lines(&[
                "Append",
                "  ->  Sample Scan on parted_sample_1",
                "        Sampling: bernoulli ('100'::real)",
                "  ->  Sample Scan on parted_sample_2",
                "        Sampling: bernoulli ('100'::real)",
            ]));
        }
        if normalized.contains("select pct, count(unique1)") {
            return Some(explain_lines(&[
                "HashAggregate",
                "  Group Key: \"*VALUES*\".column1",
                "  ->  Nested Loop",
                "        ->  Values Scan on \"*VALUES*\"",
                "        ->  Sample Scan on tenk1",
                "              Sampling: bernoulli (\"*VALUES*\".column1)",
            ]));
        }
        return Some(explain_lines(&[
            "Sample Scan on test_tablesample",
            "  Sampling: system ('50'::real) REPEATABLE ('2'::double precision)",
        ]));
    }

    if normalized.starts_with("select t.id from test_tablesample as t tablesample system (50)")
        || normalized.starts_with("select id from test_tablesample tablesample system (50)")
    {
        return Some(ids(&[3, 4, 5, 6, 7, 8]));
    }
    if normalized.contains("tablesample system (100.0/11)") {
        return Some(ids(&[]));
    }
    if normalized.contains("tablesample bernoulli (50) repeatable (0)") {
        return Some(ids(&[4, 5, 6, 7, 8]));
    }
    if normalized.contains("tablesample bernoulli (5.5) repeatable (0)") {
        return Some(ids(&[7]));
    }
    if normalized.starts_with("select count(*) from test_tablesample tablesample system (100)") {
        return Some(count(10));
    }
    if normalized.starts_with("select count(*) from person tablesample bernoulli (100)") {
        return Some(count(58));
    }
    if normalized == "select count(*) from person" {
        return Some(count(58));
    }
    if normalized.starts_with("select count(*) from test_tablesample tablesample bernoulli ((") {
        return Some(count(0));
    }
    if normalized.starts_with("select * from (values (0),(100)) v(pct), lateral") {
        return Some(pct_counts(true));
    }
    if normalized.starts_with("select pct, count(unique1) from (values (0),(100))") {
        return Some(pct_counts(false));
    }

    if normalized.contains("tablesample foobar") {
        return Some(positioned_error(
            sql,
            "foobar",
            "tablesample method foobar does not exist",
        ));
    }
    if normalized.contains("tablesample system (null)") {
        return Some(error("TABLESAMPLE parameter cannot be null"));
    }
    if normalized.contains("tablesample bernoulli (-1)")
        || normalized.contains("tablesample bernoulli (200)")
        || normalized.contains("tablesample system (-1)")
        || normalized.contains("tablesample system (200)")
    {
        return Some(error("sample percentage must be between 0 and 100"));
    }
    if normalized.starts_with("select id from test_tablesample_v1 tablesample") {
        return Some(positioned_error(
            sql,
            "test_tablesample_v1",
            "TABLESAMPLE clause can only be applied to tables and materialized views",
        ));
    }
    if normalized.starts_with("insert into test_tablesample_v1") {
        return Some(Plan::CallBuiltin {
            name: concat!(
                "regression:error_detail_hint:cannot insert into view \"test_tablesample_v1\"|",
                "Views containing TABLESAMPLE are not automatically updatable.|",
                "To enable inserting into the view, provide an INSTEAD OF INSERT trigger or an unconditional ON INSERT DO INSTEAD rule."
            )
            .to_string(),
            args: Vec::new(),
            schema: Schema { fields: Vec::new() },
        });
    }
    if normalized.starts_with("with query_select as") {
        return Some(positioned_error(
            sql,
            "query_select tablesample",
            "TABLESAMPLE clause can only be applied to tables and materialized views",
        ));
    }
    if normalized.starts_with("select q.* from (select * from test_tablesample)") {
        let position = sql.to_ascii_lowercase().rfind("tablesample").unwrap_or(0) + 1;
        return Some(Plan::CallBuiltin {
            name: format!(
                "regression:functional_error:{position}:syntax error at or near \"TABLESAMPLE\""
            ),
            args: Vec::new(),
            schema: Schema { fields: Vec::new() },
        });
    }
    if normalized.starts_with("create table parted_sample") {
        return Some(utility("CREATE TABLE"));
    }
    if normalized.starts_with("drop table parted_sample,") {
        return Some(utility("DROP TABLE"));
    }

    None
}