use crate::err::Error;
use crate::exec::field_path::{FieldPath, FieldPathPart};
use crate::expr::field::{Field, Fields};
use crate::expr::{Expr, Idiom};
pub(crate) fn derive_field_name(expr: &Expr) -> String {
match expr {
Expr::Idiom(idiom) => idiom_to_field_name(idiom),
Expr::Param(param) => param.as_str().to_string(),
Expr::FunctionCall(call) => {
let idiom: crate::expr::idiom::Idiom = call.receiver.to_idiom();
idiom_to_field_name(&idiom)
}
_ => {
use surrealdb_types::ToSql;
expr.to_sql()
}
}
}
pub(crate) fn idiom_to_field_name(idiom: &Idiom) -> String {
use surrealdb_types::ToSql;
use crate::expr::part::Part;
for part in idiom.0.iter() {
if let Part::Lookup(lookup) = part
&& let Some(alias) = &lookup.alias
{
return idiom_to_field_name(alias);
}
}
let simplified = idiom.simplify();
if simplified.len() == 1
&& let Some(Part::Field(name)) = simplified.first()
{
return name.as_str().to_owned();
}
simplified.to_sql()
}
pub(crate) fn idiom_to_field_path(idiom: &Idiom) -> FieldPath {
use surrealdb_types::ToSql;
use crate::expr::part::Part;
for part in idiom.0.iter() {
if let Part::Lookup(lookup) = part
&& lookup.alias.is_some()
{
return FieldPath::field(idiom_to_field_name(idiom));
}
}
let simplified = idiom.simplify();
let mut parts = Vec::with_capacity(simplified.0.len());
for part in simplified.0.iter() {
match part {
Part::Field(name) => parts.push(FieldPathPart::Field(name.as_str().to_owned())),
Part::Lookup(lookup) => parts.push(FieldPathPart::Lookup(lookup.to_sql())),
_ => return FieldPath::field(idiom_to_field_name(idiom)),
}
}
if parts.is_empty() {
return FieldPath::field(idiom_to_field_name(idiom));
}
FieldPath(parts)
}
pub(crate) fn check_forbidden_group_by_params(fields: &Fields) -> Result<(), Error> {
match fields {
Fields::Value(selector) => check_expr_for_forbidden_params(&selector.expr),
Fields::Select(field_list) => {
for field in field_list {
match field {
Field::All => {}
Field::Single(selector) => {
check_expr_for_forbidden_params(&selector.expr)?;
}
}
}
Ok(())
}
}
}
fn check_expr_for_forbidden_params(expr: &Expr) -> Result<(), Error> {
use super::super::row_scope::{AnalysisScope, RowScopeKind, first_row_scoped_reference};
match first_row_scoped_reference(expr, AnalysisScope::Recursive) {
None => Ok(()),
Some(RowScopeKind::This | RowScopeKind::Self_) => Err(Error::Query {
message: "Found a `$this` parameter refering to the document of a group by select statement\nSelect statements with a group by currently have no defined document to refer to".to_string(),
}),
Some(RowScopeKind::Parent) => Err(Error::Query {
message: "Found a `$parent` parameter refering to the document of a GROUP select statement\nSelect statements with a GROUP BY or GROUP ALL currently have no defined document to refer to".to_string(),
}),
}
}