nodedb_sql/types_expr.rs
1// SPDX-License-Identifier: Apache-2.0
2
3//! SQL value / expression / operator types.
4//!
5//! Re-exported from `types` so downstream `use crate::types::*` continues
6//! to resolve these symbols without change.
7
8use nodedb_types::columnar::DecimalTypmod;
9use nodedb_types::datetime::NdbDateTime;
10
11use crate::types::SqlPlan;
12
13/// SQL value literal.
14#[derive(Debug, Clone, PartialEq)]
15pub enum SqlValue {
16 Int(i64),
17 Float(f64),
18 /// Arbitrary-precision decimal (exact arithmetic, no float rounding).
19 Decimal(rust_decimal::Decimal),
20 String(String),
21 Bool(bool),
22 Null,
23 Bytes(Vec<u8>),
24 Array(Vec<SqlValue>),
25 /// Typed naive timestamp literal: `TIMESTAMP '...'` or `'...'::TIMESTAMP`.
26 Timestamp(NdbDateTime),
27 /// Typed timezone-aware timestamp literal: `TIMESTAMPTZ '...'` or `'...'::TIMESTAMPTZ`.
28 Timestamptz(NdbDateTime),
29}
30
31/// SQL-side payload-bitmap predicate atom. Mirrors `nodedb_types::PayloadAtom`
32/// but holds `SqlValue` (not `nodedb_types::Value`) so the planner can build
33/// it without a sql→types translation step. The convert layer lowers
34/// `SqlPayloadAtom` to `nodedb_types::PayloadAtom` before crossing the bridge.
35#[derive(Debug, Clone, PartialEq)]
36pub enum SqlPayloadAtom {
37 Eq(String, SqlValue),
38 In(String, Vec<SqlValue>),
39 Range {
40 field: String,
41 low: Option<SqlValue>,
42 low_inclusive: bool,
43 high: Option<SqlValue>,
44 high_inclusive: bool,
45 },
46}
47
48/// SQL expression tree.
49#[derive(Debug, Clone)]
50pub enum SqlExpr {
51 /// Column reference, optionally qualified: `name` or `users.name`
52 Column { table: Option<String>, name: String },
53 /// Literal value.
54 Literal(SqlValue),
55 /// Binary operation: `a + b`, `x > 5`
56 BinaryOp {
57 left: Box<SqlExpr>,
58 op: BinaryOp,
59 right: Box<SqlExpr>,
60 },
61 /// Unary operation: `-x`, `NOT flag`
62 UnaryOp { op: UnaryOp, expr: Box<SqlExpr> },
63 /// Function call: `COUNT(*)`, `vector_distance(field, ARRAY[...])`
64 Function {
65 name: String,
66 args: Vec<SqlExpr>,
67 distinct: bool,
68 },
69 /// CASE WHEN ... THEN ... ELSE ... END
70 Case {
71 operand: Option<Box<SqlExpr>>,
72 when_then: Vec<(SqlExpr, SqlExpr)>,
73 else_expr: Option<Box<SqlExpr>>,
74 },
75 /// CAST(expr AS type)
76 Cast { expr: Box<SqlExpr>, to_type: String },
77 /// Subquery expression (IN, EXISTS, scalar)
78 Subquery(Box<SqlPlan>),
79 /// Wildcard `*`
80 Wildcard,
81 /// `IS NULL` / `IS NOT NULL`
82 IsNull { expr: Box<SqlExpr>, negated: bool },
83 /// `expr IN (values)`
84 InList {
85 expr: Box<SqlExpr>,
86 list: Vec<SqlExpr>,
87 negated: bool,
88 },
89 /// `expr BETWEEN low AND high`
90 Between {
91 expr: Box<SqlExpr>,
92 low: Box<SqlExpr>,
93 high: Box<SqlExpr>,
94 negated: bool,
95 },
96 /// `expr LIKE pattern` / `expr ILIKE pattern`
97 Like {
98 expr: Box<SqlExpr>,
99 pattern: Box<SqlExpr>,
100 negated: bool,
101 /// `true` for ILIKE (case-insensitive match), `false` for LIKE.
102 case_insensitive: bool,
103 },
104 /// Array literal: `ARRAY[1.0, 2.0, 3.0]`
105 ArrayLiteral(Vec<SqlExpr>),
106}
107
108/// Binary operators.
109#[derive(Debug, Clone, Copy, PartialEq, Eq)]
110pub enum BinaryOp {
111 // Arithmetic
112 Add,
113 Sub,
114 Mul,
115 Div,
116 Mod,
117 // Comparison
118 Eq,
119 Ne,
120 Gt,
121 Ge,
122 Lt,
123 Le,
124 // Logical
125 And,
126 Or,
127 // String
128 Concat,
129}
130
131/// Unary operators.
132#[derive(Debug, Clone, Copy, PartialEq, Eq)]
133pub enum UnaryOp {
134 Neg,
135 Not,
136}
137
138/// SQL data type for schema resolution.
139#[derive(Debug, Clone, PartialEq, Eq)]
140pub enum SqlDataType {
141 Int64,
142 Float64,
143 String,
144 Bool,
145 Bytes,
146 /// Naive (no-timezone) timestamp.
147 Timestamp,
148 /// Timezone-aware timestamp.
149 Timestamptz,
150 /// Exact decimal. `Some` carries the declared `DECIMAL(p,s)` typmod that
151 /// every written value is fitted to. `None` is a plain `DECIMAL`.
152 Decimal(Option<DecimalTypmod>),
153 Uuid,
154 Vector(usize),
155 Geometry,
156 /// A structured value: a JSON document, or a typed `ARRAY`, `SET`,
157 /// `RANGE` or `RECORD` cell. It reads back as its JSON text.
158 Json,
159 Unknown,
160}