1use common::fmt::EscapeIdent;
2use surrealdb_strand::Strand;
3use surrealdb_types::write_sql;
4
5use crate::{Expr, Literal, Part};
6
7#[derive(Clone, Debug, Default, PartialEq, Eq)]
8pub struct Idiom(pub Vec<Part>);
9
10impl Idiom {
11 pub fn simplify(&self) -> Idiom {
13 Idiom(
14 self.0
15 .iter()
16 .filter(|&p| matches!(p, Part::Field(_) | Part::Start(_) | Part::Graph(_)))
17 .cloned()
18 .collect(),
19 )
20 }
21
22 pub fn field(name: impl Into<Strand>) -> Self {
23 Idiom(vec![Part::Field(name.into())])
24 }
25}
26
27impl surrealdb_types::ToSql for Idiom {
28 fn fmt_sql(&self, f: &mut String, fmt: surrealdb_types::SqlFormat) {
29 let mut iter = self.0.iter();
30 match iter.next() {
31 Some(Part::Field(v)) => EscapeIdent(v).fmt_sql(f, fmt),
32 Some(Part::Start(x)) => {
33 if x.needs_parentheses()
39 || matches!(
40 x,
41 Expr::Binary { .. }
42 | Expr::Prefix { .. } | Expr::Postfix { .. }
43 | Expr::Idiom(_)
44 ) {
45 write_sql!(f, fmt, "({x})");
46 } else if let Expr::Literal(Literal::Decimal(d)) = x
47 && d.is_sign_negative()
48 {
49 write_sql!(f, fmt, "({x})");
50 } else if let Expr::Literal(Literal::Integer(i)) = x
51 && i.is_negative()
52 {
53 write_sql!(f, fmt, "({x})");
54 } else if let Expr::Literal(Literal::Float(float)) = x
55 && float.is_sign_negative()
56 {
57 write_sql!(f, fmt, "({x})");
58 } else {
59 write_sql!(f, fmt, "{x}");
60 }
61 }
62 Some(x) => x.fmt_sql(f, fmt),
63 None => {}
64 };
65 for p in iter {
66 p.fmt_sql(f, fmt);
67 }
68 }
69}