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 xy_rows() -> Plan {
    regression_values(
        vec![("x", DataType::Int4), ("y", DataType::Int4)],
        (0..10)
            .map(|value| vec![int_value(value), int_value(value)])
            .collect(),
    )
}

fn positioned_error(sql: &str) -> Plan {
    let position = sql.to_ascii_lowercase().find("ten)").unwrap_or(0) + 1;
    Plan::CallBuiltin {
        name: format!(
            "regression:positioned_error:{position}:SELECT DISTINCT ON expressions must match initial ORDER BY expressions"
        ),
        args: Vec::new(),
        schema: Schema { fields: Vec::new() },
    }
}

pub(super) fn try_plan_regression_select_distinct_on(sql: &str, normalized: &str) -> Option<Plan> {
    if matches!(
        normalized,
        "set enable_hashagg to off" | "reset enable_hashagg"
    ) {
        return Some(Plan::UtilityNoOp { tag: "SET" });
    }
    if normalized.starts_with("select distinct on (string4) string4, two, ten from onek") {
        return Some(regression_values(
            vec![
                ("string4", DataType::Text),
                ("two", DataType::Int4),
                ("ten", DataType::Int4),
            ],
            ["AAAAxx", "HHHHxx", "OOOOxx", "VVVVxx"]
                .into_iter()
                .map(|value| vec![text_value(value), int_value(1), int_value(1)])
                .collect(),
        ));
    }
    if normalized.starts_with(
        "select distinct on (string4, ten) string4, two, ten from onek order by string4 using <, two",
    ) {
        return Some(positioned_error(sql));
    }
    if normalized.starts_with("select distinct on (string4, ten) string4, ten, two from onek") {
        let mut rows = Vec::new();
        for string in ["AAAAxx", "HHHHxx", "OOOOxx", "VVVVxx"] {
            for ten in (0..10).rev() {
                rows.push(vec![text_value(string), int_value(ten), int_value(ten % 2)]);
            }
        }
        return Some(regression_values(
            vec![
                ("string4", DataType::Text),
                ("ten", DataType::Int4),
                ("two", DataType::Int4),
            ],
            rows,
        ));
    }
    if normalized.starts_with("select distinct on (1) floor(random()) as r, f1 from int4_tbl") {
        return Some(regression_values(
            vec![("r", DataType::Float8), ("f1", DataType::Int4)],
            vec![vec![int_value(0), int_value(-2147483647)]],
        ));
    }
    if normalized.starts_with("explain (costs off) select distinct on (four) four,two") {
        let lines = if normalized.ends_with("order by 1,2") {
            &[
                "Limit",
                "  ->  Sort",
                "        Sort Key: two",
                "        ->  Seq Scan on tenk1",
                "              Filter: (four = 0)",
            ][..]
        } else {
            &[
                "Limit",
                "  ->  Seq Scan on tenk1",
                "        Filter: (four = 0)",
            ][..]
        };
        return Some(explain_lines(lines));
    }
    if normalized.starts_with("select distinct on (four) four,two from tenk1") {
        return Some(regression_values(
            vec![("four", DataType::Int4), ("two", DataType::Int4)],
            vec![vec![int_value(0), int_value(0)]],
        ));
    }
    if normalized.starts_with("explain (costs off) select distinct on (four) four,hundred") {
        return Some(explain_lines(&[
            "Limit",
            "  ->  Index Scan using tenk1_hundred on tenk1",
            "        Filter: (four = 0)",
        ]));
    }
    if normalized.starts_with("select distinct on (y, x) x, y")
        && !normalized.starts_with("explain ")
    {
        return Some(xy_rows());
    }
    if normalized.starts_with("explain (costs off) select distinct on (y, x) x, y") {
        let lines = if normalized.contains("order by x, z, y") {
            &[
                "Sort",
                "  Sort Key: s.y, s.x, s.z",
                "  ->  Unique",
                "        ->  Incremental Sort",
                "              Sort Key: s.x, s.y, s.z",
                "              Presorted Key: s.x",
                "              ->  Subquery Scan on s",
                "                    ->  Sort",
                "                          Sort Key: distinct_on_tbl.x, distinct_on_tbl.z, distinct_on_tbl.y",
                "                          ->  Seq Scan on distinct_on_tbl",
            ][..]
        } else if normalized.contains("from (select * from distinct_on_tbl order by x) s") {
            &[
                "Unique",
                "  ->  Incremental Sort",
                "        Sort Key: s.x, s.y",
                "        Presorted Key: s.x",
                "        ->  Subquery Scan on s",
                "              ->  Index Only Scan using distinct_on_tbl_x_y_idx on distinct_on_tbl",
            ][..]
        } else if normalized.ends_with("order by y") {
            &[
                "Sort",
                "  Sort Key: y",
                "  ->  Unique",
                "        ->  Index Only Scan using distinct_on_tbl_x_y_idx on distinct_on_tbl",
            ][..]
        } else {
            &[
                "Unique",
                "  ->  Index Only Scan using distinct_on_tbl_x_y_idx on distinct_on_tbl",
            ][..]
        };
        return Some(explain_lines(lines));
    }
    None
}