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()
34 || matches!(x, Expr::Binary { .. } | Expr::Prefix { .. } | Expr::Postfix { .. })
35 {
36 write_sql!(f, fmt, "({x})");
37 } else if let Expr::Literal(Literal::Decimal(d)) = x
38 && d.is_sign_negative()
39 {
40 write_sql!(f, fmt, "({x})");
41 } else if let Expr::Literal(Literal::Integer(i)) = x
42 && i.is_negative()
43 {
44 write_sql!(f, fmt, "({x})");
45 } else if let Expr::Literal(Literal::Float(float)) = x
46 && float.is_sign_negative()
47 {
48 write_sql!(f, fmt, "({x})");
49 } else {
50 write_sql!(f, fmt, "{x}");
51 }
52 }
53 Some(x) => x.fmt_sql(f, fmt),
54 None => {}
55 };
56 for p in iter {
57 p.fmt_sql(f, fmt);
58 }
59 }
60}