use crate::exec::function::FunctionRegistry;
use crate::expr::visit::{MutVisitor, Visit, VisitMut, Visitor};
use crate::expr::{Cond, Expr, Literal};
pub(crate) const SELECT_ITERATION_PARAMS: &[&str] = super::super::row_scope::ROW_SCOPED_PARAMS;
pub(crate) async fn resolve_param_value(
name: &str,
ctx: &crate::ctx::FrozenContext,
ns_db: Option<(crate::catalog::NamespaceId, crate::catalog::DatabaseId)>,
row_scoped: &[&str],
) -> Option<crate::val::Value> {
use crate::catalog::providers::DatabaseProvider;
if row_scoped.contains(&name) {
return None;
}
if let Some(value) = ctx.value(name) {
return Some(value.clone());
}
if let Some((ns, db)) = ns_db
&& let Some(txn) = ctx.try_tx()
&& let Ok(param_def) = txn.get_db_param(ns, db, name, None).await
&& matches!(param_def.permissions, crate::catalog::Permission::Full)
{
return Some(param_def.value.clone());
}
None
}
pub(crate) async fn resolve_condition_params(
cond: &Cond,
ctx: &crate::ctx::FrozenContext,
ns_db: Option<(crate::catalog::NamespaceId, crate::catalog::DatabaseId)>,
row_scoped: &[&str],
) -> Cond {
let mut collector = ParamCollector {
names: std::collections::HashSet::new(),
};
let _ = collector.visit_expr(&cond.0);
if collector.names.is_empty() {
return cond.clone();
}
let mut resolved = std::collections::HashMap::with_capacity(collector.names.len());
for name in &collector.names {
if let Some(value) = resolve_param_value(name, ctx, ns_db, row_scoped).await {
resolved.insert(name.clone(), value);
}
}
if resolved.is_empty() {
return cond.clone();
}
let mut expr = cond.0.clone();
let _ = ParamResolver {
values: &resolved,
}
.visit_mut_expr(&mut expr);
Cond(expr)
}
pub(crate) fn resolve_projection_field_idioms(cond: &mut Cond, registry: &FunctionRegistry) {
let mut resolver = ProjectionFieldResolver {
registry,
};
let _ = resolver.visit_mut_expr(&mut cond.0);
}
struct ParamCollector {
names: std::collections::HashSet<String>,
}
impl Visitor for ParamCollector {
type Error = std::convert::Infallible;
fn visit_expr(&mut self, expr: &Expr) -> Result<(), Self::Error> {
if let Expr::Param(param) = expr {
self.names.insert(param.as_str().to_string());
}
expr.visit(self)
}
fn visit_select(&mut self, _: &crate::expr::SelectStatement) -> Result<(), Self::Error> {
Ok(())
}
}
struct ParamResolver<'a> {
values: &'a std::collections::HashMap<String, crate::val::Value>,
}
impl MutVisitor for ParamResolver<'_> {
type Error = std::convert::Infallible;
fn visit_mut_expr(&mut self, expr: &mut Expr) -> Result<(), Self::Error> {
if let Expr::Param(param) = expr
&& let Some(value) = self.values.get(param.as_str())
{
*expr = value.clone().into_literal();
return Ok(());
}
expr.visit_mut(self)
}
fn visit_mut_select(
&mut self,
_: &mut crate::expr::SelectStatement,
) -> Result<(), Self::Error> {
Ok(())
}
}
struct ProjectionFieldResolver<'a> {
registry: &'a FunctionRegistry,
}
impl MutVisitor for ProjectionFieldResolver<'_> {
type Error = std::convert::Infallible;
fn visit_mut_expr(&mut self, expr: &mut Expr) -> Result<(), Self::Error> {
use crate::expr::function::Function;
expr.visit_mut(self)?;
if let Expr::FunctionCall(fc) = expr
&& let Function::Normal(name) = &fc.receiver
&& self.registry.is_projection(name)
&& fc.arguments.len() == 1
&& let Expr::Literal(Literal::String(s)) = &fc.arguments[0]
&& let Ok(idiom) = crate::syn::idiom(s)
{
*expr = Expr::Idiom(idiom.into());
}
Ok(())
}
fn visit_mut_select(
&mut self,
_: &mut crate::expr::SelectStatement,
) -> Result<(), Self::Error> {
Ok(())
}
}