Skip to main content

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}