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