Skip to main content

radixdb_sql/ast/
source.rs

1// Copyright 2026 RadixDB Contributors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use super::*;
16
17// ============================================================================
18// Table Sources
19// ============================================================================
20
21/// Simple table source
22#[derive(Debug, Clone, PartialEq)]
23pub struct SimpleTableSource {
24    pub token: Token,
25    pub name: Identifier,
26    pub alias: Option<Identifier>,
27    pub as_of: Option<AsOfClause>,
28}
29
30impl fmt::Display for SimpleTableSource {
31    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32        let mut result = self.name.to_string();
33        if let Some(ref as_of) = self.as_of {
34            result.push_str(&format!(" {}", as_of));
35        }
36        if let Some(ref alias) = self.alias {
37            result.push_str(&format!(" AS {}", alias));
38        }
39        write!(f, "{}", result)
40    }
41}
42
43/// AS OF clause for temporal queries
44#[derive(Debug, Clone, PartialEq)]
45pub struct AsOfClause {
46    pub token: Token,
47    pub as_of_type: SmartString, // "TRANSACTION" or "TIMESTAMP"
48    pub value: Box<Expression>,
49}
50
51impl fmt::Display for AsOfClause {
52    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
53        write!(f, "AS OF {} {}", self.as_of_type, self.value)
54    }
55}
56
57/// Join table source
58#[derive(Debug, Clone, PartialEq)]
59pub struct JoinTableSource {
60    pub token: Token,
61    pub left: Box<Expression>,
62    pub join_type: SmartString,
63    pub right: Box<Expression>,
64    pub condition: Option<Box<Expression>>,
65    /// USING clause columns (e.g., USING(id, name))
66    pub using_columns: Vec<Identifier>,
67}
68
69impl fmt::Display for JoinTableSource {
70    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
71        let mut result = self.left.to_string();
72        result.push_str(&format!(" {} JOIN {}", self.join_type, self.right));
73        if let Some(ref cond) = self.condition {
74            result.push_str(&format!(" ON {}", cond));
75        } else if !self.using_columns.is_empty() {
76            let cols: Vec<String> = self.using_columns.iter().map(|c| c.to_string()).collect();
77            result.push_str(&format!(" USING ({})", cols.join(", ")));
78        }
79        write!(f, "{}", result)
80    }
81}
82
83/// Subquery table source
84#[derive(Debug, Clone, PartialEq)]
85pub struct SubqueryTableSource {
86    pub token: Token,
87    pub subquery: Box<SelectStatement>,
88    pub alias: Option<Identifier>,
89}
90
91impl fmt::Display for SubqueryTableSource {
92    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
93        let mut result = format!("({})", self.subquery);
94        if let Some(ref alias) = self.alias {
95            result.push_str(&format!(" AS {}", alias));
96        }
97        write!(f, "{}", result)
98    }
99}
100
101/// VALUES table source (e.g., VALUES (1, 'a'), (2, 'b') AS t(col1, col2))
102#[derive(Debug, Clone, PartialEq)]
103pub struct ValuesTableSource {
104    pub token: Token,
105    /// Each row is a list of expressions
106    pub rows: Vec<Vec<Expression>>,
107    /// Optional alias for the derived table
108    pub alias: Option<Identifier>,
109    /// Optional column aliases (e.g., t(col1, col2))
110    pub column_aliases: Vec<Identifier>,
111}
112
113impl fmt::Display for ValuesTableSource {
114    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
115        let mut result = String::from("(VALUES ");
116        let rows_str: Vec<String> = self
117            .rows
118            .iter()
119            .map(|row| {
120                let values: Vec<String> = row.iter().map(|e| e.to_string()).collect();
121                format!("({})", values.join(", "))
122            })
123            .collect();
124        result.push_str(&rows_str.join(", "));
125        result.push(')');
126
127        if let Some(ref alias) = self.alias {
128            result.push_str(&format!(" AS {}", alias));
129            if !self.column_aliases.is_empty() {
130                let cols: Vec<String> = self.column_aliases.iter().map(|c| c.to_string()).collect();
131                result.push_str(&format!("({})", cols.join(", ")));
132            }
133        }
134        write!(f, "{}", result)
135    }
136}
137
138/// Function table source (table-valued function in FROM clause)
139/// e.g., SELECT * FROM generate_series(1, 10) AS gs(value)
140#[derive(Debug, Clone, PartialEq)]
141pub struct FunctionTableSource {
142    pub token: Token,
143    /// Function name
144    pub function: Identifier,
145    /// Function arguments
146    pub arguments: Vec<Expression>,
147    /// Optional table alias
148    pub alias: Option<Identifier>,
149    /// Optional column aliases (e.g., AS gs(value))
150    pub column_aliases: Vec<Identifier>,
151}
152
153impl fmt::Display for FunctionTableSource {
154    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
155        write!(f, "{}(", self.function)?;
156        for (i, arg) in self.arguments.iter().enumerate() {
157            if i > 0 {
158                write!(f, ", ")?;
159            }
160            write!(f, "{}", arg)?;
161        }
162        write!(f, ")")?;
163        if let Some(ref alias) = self.alias {
164            write!(f, " AS {}", alias)?;
165            if !self.column_aliases.is_empty() {
166                let cols: Vec<String> = self.column_aliases.iter().map(|c| c.to_string()).collect();
167                write!(f, "({})", cols.join(", "))?;
168            }
169        }
170        Ok(())
171    }
172}
173
174/// CTE reference
175#[derive(Debug, Clone, PartialEq)]
176pub struct CteReference {
177    pub token: Token,
178    pub name: Identifier,
179    pub alias: Option<Identifier>,
180}
181
182impl fmt::Display for CteReference {
183    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
184        let mut result = self.name.to_string();
185        if let Some(ref alias) = self.alias {
186            result.push_str(&format!(" AS {}", alias));
187        }
188        write!(f, "{}", result)
189    }
190}
191
192// ============================================================================
193// ORDER BY
194// ============================================================================
195
196/// ORDER BY expression
197#[derive(Debug, Clone, PartialEq)]
198pub struct OrderByExpression {
199    pub expression: Expression,
200    pub ascending: bool,
201    /// None = default (NULLS LAST for ASC, NULLS FIRST for DESC in SQL standard)
202    /// Some(true) = NULLS FIRST
203    /// Some(false) = NULLS LAST
204    pub nulls_first: Option<bool>,
205}
206
207impl fmt::Display for OrderByExpression {
208    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
209        if self.ascending {
210            write!(f, "{} ASC", self.expression)?;
211        } else {
212            write!(f, "{} DESC", self.expression)?;
213        }
214        if let Some(nulls_first) = self.nulls_first {
215            if nulls_first {
216                write!(f, " NULLS FIRST")?;
217            } else {
218                write!(f, " NULLS LAST")?;
219            }
220        }
221        Ok(())
222    }
223}