Skip to main content

nodedb_sql/
types_array.rs

1// SPDX-License-Identifier: Apache-2.0
2
3//! Engine-agnostic AST shapes for array DDL/DML carried on `SqlPlan`.
4//!
5//! Kept free of any dependency on `nodedb-array` so the SQL crate stays
6//! lean. The Origin-side SqlPlan→PhysicalPlan converter is responsible
7//! for translating these into typed `nodedb_array::ArraySchema` and
8//! engine-typed coord/cell values before crossing the bridge.
9
10/// Dimension type tag (mirrors `nodedb_array::schema::DimType`).
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub enum ArrayDimType {
13    Int64,
14    Float64,
15    TimestampMs,
16    String,
17}
18
19/// Attribute type tag (mirrors `nodedb_array::schema::AttrType`).
20#[derive(Debug, Clone, Copy, PartialEq, Eq)]
21pub enum ArrayAttrType {
22    Int64,
23    Float64,
24    String,
25    Bytes,
26}
27
28/// Cell-order strategy AST mirror.
29#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
30pub enum ArrayCellOrderAst {
31    RowMajor,
32    ColMajor,
33    #[default]
34    Hilbert,
35    ZOrder,
36}
37
38/// Tile-order strategy AST mirror.
39#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
40pub enum ArrayTileOrderAst {
41    RowMajor,
42    ColMajor,
43    #[default]
44    Hilbert,
45    ZOrder,
46}
47
48/// Domain bound carrying its dim's type tag.
49#[derive(Debug, Clone, PartialEq)]
50pub enum ArrayDomainBound {
51    Int64(i64),
52    Float64(f64),
53    TimestampMs(i64),
54    String(String),
55}
56
57/// One dim spec in `CREATE ARRAY ... DIMS (...)`.
58#[derive(Debug, Clone, PartialEq)]
59pub struct ArrayDimAst {
60    pub name: String,
61    pub dtype: ArrayDimType,
62    pub lo: ArrayDomainBound,
63    pub hi: ArrayDomainBound,
64}
65
66/// One attribute spec in `CREATE ARRAY ... ATTRS (...)`.
67#[derive(Debug, Clone, PartialEq)]
68pub struct ArrayAttrAst {
69    pub name: String,
70    pub dtype: ArrayAttrType,
71    pub nullable: bool,
72}
73
74/// One coord scalar in `INSERT INTO ARRAY ... COORDS (...)` — a literal
75/// value typed loosely; the converter coerces against the schema's
76/// declared dim type.
77#[derive(Debug, Clone, PartialEq)]
78pub enum ArrayCoordLiteral {
79    Int64(i64),
80    Float64(f64),
81    String(String),
82}
83
84/// One attribute literal in `... VALUES (...)`. `Null` permitted only
85/// for nullable attrs (validated in the converter).
86#[derive(Debug, Clone, PartialEq)]
87pub enum ArrayAttrLiteral {
88    Int64(i64),
89    Float64(f64),
90    String(String),
91    Bytes(Vec<u8>),
92    Null,
93}
94
95/// One row of an `INSERT INTO ARRAY ...`: `COORDS (...) VALUES (...)`.
96#[derive(Debug, Clone, PartialEq)]
97pub struct ArrayInsertRow {
98    pub coords: Vec<ArrayCoordLiteral>,
99    pub attrs: Vec<ArrayAttrLiteral>,
100}
101
102/// One named `dim: [lo, hi]` entry in a slice predicate.
103///
104/// The literal type is loose at planning time; the converter coerces
105/// against the array's declared dim dtype before encoding to wire.
106#[derive(Debug, Clone, PartialEq)]
107pub struct NamedDimRange {
108    /// Schema dim name. Resolved to a positional index by the converter.
109    pub dim: String,
110    pub lo: ArrayCoordLiteral,
111    pub hi: ArrayCoordLiteral,
112}
113
114/// `ARRAY_SLICE(...)` slice predicate: an unordered set of named
115/// dim ranges, expanded to per-position `Option<DimRange>` by the
116/// converter (unconstrained dims become `None`).
117#[derive(Debug, Clone, Default, PartialEq)]
118pub struct ArraySliceAst {
119    pub dim_ranges: Vec<NamedDimRange>,
120}
121
122/// Reducer carried on `SqlPlan::ArrayAgg`. Mirrors
123/// `crate::bridge::physical_plan::ArrayReducer` without the bridge dep.
124#[derive(Debug, Clone, Copy, PartialEq, Eq)]
125pub enum ArrayReducerAst {
126    Sum,
127    Count,
128    Min,
129    Max,
130    Mean,
131}
132
133impl ArrayReducerAst {
134    /// Parse the SQL-surface string ('sum', 'count', ...). Returns `None`
135    /// for any other value so the planner can surface an `Unsupported`
136    /// error with the offending token.
137    pub fn parse(s: &str) -> Option<Self> {
138        match s.to_ascii_lowercase().as_str() {
139            "sum" => Some(ArrayReducerAst::Sum),
140            "count" => Some(ArrayReducerAst::Count),
141            "min" => Some(ArrayReducerAst::Min),
142            "max" => Some(ArrayReducerAst::Max),
143            "mean" | "avg" => Some(ArrayReducerAst::Mean),
144            _ => None,
145        }
146    }
147}
148
149/// Pairwise op carried on `SqlPlan::ArrayElementwise`. Mirrors
150/// `crate::bridge::physical_plan::ArrayBinaryOp`.
151#[derive(Debug, Clone, Copy, PartialEq, Eq)]
152pub enum ArrayBinaryOpAst {
153    Add,
154    Sub,
155    Mul,
156    Div,
157}
158
159impl ArrayBinaryOpAst {
160    pub fn parse(s: &str) -> Option<Self> {
161        match s.to_ascii_lowercase().as_str() {
162            "add" | "+" => Some(ArrayBinaryOpAst::Add),
163            "sub" | "-" => Some(ArrayBinaryOpAst::Sub),
164            "mul" | "*" => Some(ArrayBinaryOpAst::Mul),
165            "div" | "/" => Some(ArrayBinaryOpAst::Div),
166            _ => None,
167        }
168    }
169}