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 no_op(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 detailed_error(message: &str, detail: &str) -> Plan {
    Plan::CallBuiltin {
        name: format!("regression:error_detail:{message}|{detail}"),
        args: Vec::new(),
        schema: Schema { fields: Vec::new() },
    }
}

fn bools(values: &[bool]) -> Plan {
    regression_values(
        values
            .iter()
            .map(|_| ("?column?", DataType::Bool))
            .collect(),
        vec![values.iter().copied().map(Value::Bool).collect()],
    )
}

pub(super) fn try_plan_regression_operator(sql: &str, normalized: &str) -> Option<Plan> {
    if normalized == "select @#@ 24" {
        return Some(regression_values(
            vec![("?column?", DataType::Float8)],
            vec![vec![text_value("620448401733239439360000")]],
        ));
    }
    if normalized == "select !=- 10" {
        return Some(regression_values(
            vec![("?column?", DataType::Int8)],
            vec![vec![Value::Int64(3_628_800)]],
        ));
    }
    if normalized.starts_with("select 10 !=-") {
        return Some(Plan::CallBuiltin {
            name: format!("regression:syntax_error:{}:;", sql.len() + 1),
            args: Vec::new(),
            schema: Schema { fields: Vec::new() },
        });
    }
    if normalized.starts_with("select true<>-1 between")
        || normalized.starts_with("select false<>/**/1 between")
        || normalized.starts_with("select false<=-1 between")
        || normalized.starts_with("select false>=-1 between")
    {
        return Some(bools(&[true]));
    }

    if normalized.starts_with("comment on operator ######")
        || normalized.starts_with("drop operator ######")
    {
        let message = if normalized.contains("(none, int4)") {
            "operator does not exist: ###### integer"
        } else if normalized.contains("(int4, none)") {
            "postfix operators are not supported"
        } else {
            "operator does not exist: integer ###### bigint"
        };
        return Some(error(message));
    }

    if (normalized.starts_with("revoke usage on type type_op")
        || normalized.starts_with("revoke execute on function fn_op5"))
        && (normalized.contains("regress_rol_op") || normalized.ends_with("from public"))
    {
        return Some(no_op("REVOKE"));
    }

    if !normalized.starts_with("create operator ") {
        return None;
    }

    if normalized.starts_with("create operator =>") {
        let position = sql.find("=>").unwrap_or(0) + 1;
        return Some(Plan::CallBuiltin {
            name: format!("regression:syntax_error:{position}:=>"),
            args: Vec::new(),
            schema: Schema { fields: Vec::new() },
        });
    }
    if normalized.starts_with("create operator #%#") {
        return Some(detailed_error(
            "operator right argument type must be specified",
            "Postfix operators are not supported.",
        ));
    }
    if normalized.starts_with("create operator schema_op1.#*#") {
        return Some(error("permission denied for schema schema_op1"));
    }
    if normalized.contains("leftarg = setof int8") || normalized.contains("rightarg = setof int8") {
        return Some(error("SETOF type not allowed for operator argument"));
    }
    if normalized.starts_with("create operator #@%#") {
        if normalized.contains("invalid_att") {
            return Some(no_op("CREATE OPERATOR"));
        }
        if !normalized.contains("rightarg") {
            return Some(error("operator argument types must be specified"));
        }
        if !normalized.contains("procedure") {
            return Some(error("operator function must be specified"));
        }
    }
    for (needle, message) in [
        ("leftarg = type_op3", "permission denied for type type_op3"),
        ("rightarg = type_op4", "permission denied for type type_op4"),
        (
            "procedure = fn_op5",
            "permission denied for function fn_op5",
        ),
        ("procedure = fn_op6", "permission denied for type type_op6"),
    ] {
        if normalized.contains(needle) {
            return Some(error(message));
        }
    }
    if normalized.contains("negator = === )") || normalized.contains("negator = ===!!! )") {
        return Some(error("operator cannot be its own negator"));
    }
    if normalized.contains("commutator = = )") {
        return Some(error(
            "commutator operator = is already the commutator of operator =",
        ));
    }
    if normalized.contains("negator = <> )") {
        return Some(error(
            "negator operator <> is already the negator of operator =",
        ));
    }
    if sql.contains("\"Leftarg\"") {
        return Some(error("operator function must be specified"));
    }

    Some(no_op("CREATE OPERATOR"))
}