use reddb_rql::ast::{FieldRef, Projection};
pub fn projection_name(projection: &Projection) -> String {
match projection {
Projection::All => "*".to_string(),
Projection::Column(column) => column.clone(),
Projection::Alias(_, alias) => alias.clone(),
Projection::Function(name, args) => {
if let Some((_, alias)) = name.split_once(':') {
alias.to_string()
} else {
render_projection_label(name, args)
}
}
Projection::Expression(_, alias) => alias.clone().unwrap_or_else(|| "expr".to_string()),
Projection::Field(field, alias) => alias.clone().unwrap_or_else(|| field_ref_name(field)),
Projection::Window { name, alias, .. } => alias.clone().unwrap_or_else(|| name.clone()),
}
}
fn projection_operator_symbol(name: &str) -> Option<&'static str> {
match name {
"ADD" => Some("+"),
"SUB" => Some("-"),
"MUL" => Some("*"),
"DIV" => Some("/"),
"MOD" => Some("%"),
"CONCAT" => Some("||"),
_ => None,
}
}
fn projection_arg_label(projection: &Projection) -> String {
match projection {
Projection::Column(column) => match column.strip_prefix("LIT:") {
Some(lit)
if lit.is_empty()
|| lit.parse::<f64>().is_ok()
|| lit.eq_ignore_ascii_case("true")
|| lit.eq_ignore_ascii_case("false")
|| lit.eq_ignore_ascii_case("null") =>
{
lit.to_string()
}
Some(lit) => format!("'{lit}'"),
None => column.clone(),
},
Projection::Function(name, args) => {
let base = name.split_once(':').map(|(b, _)| b).unwrap_or(name);
render_projection_label(base, args)
}
Projection::Field(field, _) => field_ref_name(field),
Projection::Alias(_, alias) => alias.clone(),
other => projection_name(other),
}
}
fn render_projection_label(name: &str, args: &[Projection]) -> String {
if let Some(symbol) = projection_operator_symbol(name) {
args.iter()
.map(projection_arg_label)
.collect::<Vec<_>>()
.join(&format!(" {symbol} "))
} else {
format!(
"{}({})",
name,
args.iter()
.map(projection_arg_label)
.collect::<Vec<_>>()
.join(", ")
)
}
}
pub fn field_ref_name(field: &FieldRef) -> String {
match field {
FieldRef::TableColumn { table, column } => {
if table.is_empty() {
column.clone()
} else {
format!("{table}.{column}")
}
}
FieldRef::NodeProperty { alias, property } => format!("{alias}.{property}"),
FieldRef::EdgeProperty { alias, property } => format!("{alias}.{property}"),
FieldRef::NodeId { alias } => format!("{alias}.id"),
}
}