use nodedb_types::DatabaseId;
use crate::catalog::SqlCatalog;
use crate::types::*;
pub fn optimize(plan: SqlPlan, catalog: &dyn SqlCatalog) -> SqlPlan {
match plan {
SqlPlan::Scan {
ref collection,
ref alias,
ref engine,
ref filters,
ref projection,
ref temporal,
..
} if filters.len() == 1
&& !temporal.is_temporal()
&& !projection
.iter()
.any(|p| matches!(p, Projection::Computed { .. })) =>
{
let pk = catalog
.get_collection(DatabaseId::DEFAULT, collection)
.ok()
.flatten()
.and_then(|info| info.primary_key);
if let Some((key_col, key_val)) = extract_pk_equality(&filters[0], pk.as_deref()) {
return SqlPlan::PointGet {
collection: collection.clone(),
alias: alias.clone(),
engine: *engine,
key_column: key_col,
key_value: key_val,
projection: projection.clone(),
};
}
plan
}
_ => plan,
}
}
fn extract_pk_equality(filter: &Filter, pk: Option<&str>) -> Option<(String, SqlValue)> {
let is_pk_column = |col: &str| -> bool {
let conventional = col == "id" || col == "document_id" || col == "key";
match pk {
Some(pk) => conventional && col.eq_ignore_ascii_case(pk),
None => conventional,
}
};
match &filter.expr {
FilterExpr::Comparison {
field,
op: CompareOp::Eq,
value,
} => {
let f = field.to_lowercase();
if is_pk_column(&f) {
Some((f, value.clone()))
} else {
None
}
}
FilterExpr::Expr(SqlExpr::BinaryOp {
left,
op: BinaryOp::Eq,
right,
}) => {
let col = match left.as_ref() {
SqlExpr::Column { name, .. } => name.to_lowercase(),
_ => return None,
};
if !is_pk_column(&col) {
return None;
}
let val = match right.as_ref() {
SqlExpr::Literal(v) => v.clone(),
_ => return None,
};
Some((col, val))
}
_ => None,
}
}