datafusion_federation/sql/
table_reference.rs1use std::sync::Arc;
2
3use datafusion::{
4 error::DataFusionError,
5 sql::{
6 sqlparser::{
7 self,
8 ast::FunctionArg,
9 dialect::{Dialect, GenericDialect},
10 tokenizer::Token,
11 },
12 TableReference,
13 },
14};
15
16#[derive(Debug, Clone, PartialEq, Eq, Hash)]
28pub struct RemoteTableRef {
29 pub table_ref: TableReference,
30 pub args: Option<Arc<[FunctionArg]>>,
31}
32
33impl RemoteTableRef {
34 pub fn to_quoted_string(&self) -> String {
36 self.table_ref.to_quoted_string()
37 }
38
39 pub fn parse_with_default_dialect(s: &str) -> Result<Self, DataFusionError> {
41 Self::parse_with_dialect(s, &GenericDialect {})
42 }
43
44 pub fn parse_with_dialect(s: &str, dialect: &dyn Dialect) -> Result<Self, DataFusionError> {
46 let mut parser = sqlparser::parser::Parser::new(dialect).try_with_sql(s)?;
47 let name = parser.parse_object_name(true)?;
48 let args = if parser.consume_token(&Token::LParen) {
49 parser.parse_optional_args()?
50 } else {
51 vec![]
52 };
53
54 let table_ref = match (name.0.first(), name.0.get(1), name.0.get(2)) {
55 (Some(catalog), Some(schema), Some(table)) => TableReference::full(
56 catalog.value.clone(),
57 schema.value.clone(),
58 table.value.clone(),
59 ),
60 (Some(schema), Some(table), None) => {
61 TableReference::partial(schema.value.clone(), table.value.clone())
62 }
63 (Some(table), None, None) => TableReference::bare(table.value.clone()),
64 _ => {
65 return Err(DataFusionError::NotImplemented(
66 "Unable to parse string into TableReference".to_string(),
67 ))
68 }
69 };
70
71 if !args.is_empty() {
72 Ok(RemoteTableRef {
73 table_ref,
74 args: Some(args.into()),
75 })
76 } else {
77 Ok(RemoteTableRef {
78 table_ref,
79 args: None,
80 })
81 }
82 }
83
84 pub fn table_ref(&self) -> &TableReference {
85 &self.table_ref
86 }
87
88 pub fn args(&self) -> Option<&[FunctionArg]> {
89 self.args.as_deref()
90 }
91}
92
93impl From<TableReference> for RemoteTableRef {
94 fn from(table_ref: TableReference) -> Self {
95 RemoteTableRef {
96 table_ref,
97 args: None,
98 }
99 }
100}
101
102impl From<RemoteTableRef> for TableReference {
103 fn from(remote_table_ref: RemoteTableRef) -> Self {
104 remote_table_ref.table_ref
105 }
106}
107
108impl From<&RemoteTableRef> for TableReference {
109 fn from(remote_table_ref: &RemoteTableRef) -> Self {
110 remote_table_ref.table_ref.clone()
111 }
112}
113
114impl From<(TableReference, Vec<FunctionArg>)> for RemoteTableRef {
115 fn from((table_ref, args): (TableReference, Vec<FunctionArg>)) -> Self {
116 RemoteTableRef {
117 table_ref,
118 args: Some(args.into()),
119 }
120 }
121}
122
123impl TryFrom<&str> for RemoteTableRef {
124 type Error = DataFusionError;
125 fn try_from(s: &str) -> Result<Self, Self::Error> {
126 Self::parse_with_default_dialect(s)
127 }
128}
129
130impl TryFrom<String> for RemoteTableRef {
131 type Error = DataFusionError;
132 fn try_from(s: String) -> Result<Self, Self::Error> {
133 Self::parse_with_default_dialect(&s)
134 }
135}
136
137impl TryFrom<&String> for RemoteTableRef {
138 type Error = DataFusionError;
139 fn try_from(s: &String) -> Result<Self, Self::Error> {
140 Self::parse_with_default_dialect(s)
141 }
142}
143
144#[cfg(test)]
145mod tests {
146 use super::*;
147 use sqlparser::{
148 ast::{self, Expr, FunctionArgOperator, Ident, Value},
149 dialect,
150 };
151
152 #[test]
153 fn bare_table_reference() {
154 let table_ref = RemoteTableRef::parse_with_default_dialect("table").unwrap();
155 let expected = RemoteTableRef::from(TableReference::bare("table"));
156 assert_eq!(table_ref, expected);
157
158 let table_ref = RemoteTableRef::parse_with_default_dialect("Table").unwrap();
159 let expected = RemoteTableRef::from(TableReference::bare("Table"));
160 assert_eq!(table_ref, expected);
161 }
162
163 #[test]
164 fn bare_table_reference_with_args() {
165 let table_ref = RemoteTableRef::parse_with_default_dialect("table(1, 2)").unwrap();
166 let expected = RemoteTableRef::from((
167 TableReference::bare("table"),
168 vec![
169 FunctionArg::Unnamed(Expr::Value(Value::Number("1".to_string(), false)).into()),
170 FunctionArg::Unnamed(Expr::Value(Value::Number("2".to_string(), false)).into()),
171 ],
172 ));
173 assert_eq!(table_ref, expected);
174
175 let table_ref = RemoteTableRef::parse_with_default_dialect("Table(1, 2)").unwrap();
176 let expected = RemoteTableRef::from((
177 TableReference::bare("Table"),
178 vec![
179 FunctionArg::Unnamed(Expr::Value(Value::Number("1".to_string(), false)).into()),
180 FunctionArg::Unnamed(Expr::Value(Value::Number("2".to_string(), false)).into()),
181 ],
182 ));
183 assert_eq!(table_ref, expected);
184 }
185
186 #[test]
187 fn bare_table_reference_with_args_and_whitespace() {
188 let table_ref = RemoteTableRef::parse_with_default_dialect("table (1, 2)").unwrap();
189 let expected = RemoteTableRef::from((
190 TableReference::bare("table"),
191 vec![
192 FunctionArg::Unnamed(Expr::Value(Value::Number("1".to_string(), false)).into()),
193 FunctionArg::Unnamed(Expr::Value(Value::Number("2".to_string(), false)).into()),
194 ],
195 ));
196 assert_eq!(table_ref, expected);
197
198 let table_ref = RemoteTableRef::parse_with_default_dialect("Table (1, 2)").unwrap();
199 let expected = RemoteTableRef::from((
200 TableReference::bare("Table"),
201 vec![
202 FunctionArg::Unnamed(Expr::Value(Value::Number("1".to_string(), false)).into()),
203 FunctionArg::Unnamed(Expr::Value(Value::Number("2".to_string(), false)).into()),
204 ],
205 ));
206 assert_eq!(table_ref, expected);
207 }
208
209 #[test]
210 fn multi_table_reference_with_no_args() {
211 let table_ref = RemoteTableRef::parse_with_default_dialect("schema.table").unwrap();
212 let expected = RemoteTableRef::from(TableReference::partial("schema", "table"));
213 assert_eq!(table_ref, expected);
214
215 let table_ref = RemoteTableRef::parse_with_default_dialect("schema.Table").unwrap();
216 let expected = RemoteTableRef::from(TableReference::partial("schema", "Table"));
217 assert_eq!(table_ref, expected);
218 }
219
220 #[test]
221 fn multi_table_reference_with_args() {
222 let table_ref = RemoteTableRef::parse_with_default_dialect("schema.table(1, 2)").unwrap();
223 let expected = RemoteTableRef::from((
224 TableReference::partial("schema", "table"),
225 vec![
226 FunctionArg::Unnamed(Expr::Value(Value::Number("1".to_string(), false)).into()),
227 FunctionArg::Unnamed(Expr::Value(Value::Number("2".to_string(), false)).into()),
228 ],
229 ));
230 assert_eq!(table_ref, expected);
231
232 let table_ref = RemoteTableRef::parse_with_default_dialect("schema.Table(1, 2)").unwrap();
233 let expected = RemoteTableRef::from((
234 TableReference::partial("schema", "Table"),
235 vec![
236 FunctionArg::Unnamed(Expr::Value(Value::Number("1".to_string(), false)).into()),
237 FunctionArg::Unnamed(Expr::Value(Value::Number("2".to_string(), false)).into()),
238 ],
239 ));
240 assert_eq!(table_ref, expected);
241 }
242
243 #[test]
244 fn multi_table_reference_with_args_and_whitespace() {
245 let table_ref = RemoteTableRef::parse_with_default_dialect("schema.table (1, 2)").unwrap();
246 let expected = RemoteTableRef::from((
247 TableReference::partial("schema", "table"),
248 vec![
249 FunctionArg::Unnamed(Expr::Value(Value::Number("1".to_string(), false)).into()),
250 FunctionArg::Unnamed(Expr::Value(Value::Number("2".to_string(), false)).into()),
251 ],
252 ));
253 assert_eq!(table_ref, expected);
254 }
255
256 #[test]
257 fn bare_reference_with_named_args() {
258 let table_ref = RemoteTableRef::parse_with_dialect(
259 "Table (user_id => 1, age => 2)",
260 &dialect::PostgreSqlDialect {},
261 )
262 .unwrap();
263 let expected = RemoteTableRef::from((
264 TableReference::bare("Table"),
265 vec![
266 FunctionArg::ExprNamed {
267 name: ast::Expr::Identifier(Ident::new("user_id")),
268 arg: Expr::Value(Value::Number("1".to_string(), false)).into(),
269 operator: FunctionArgOperator::RightArrow,
270 },
271 FunctionArg::ExprNamed {
272 name: ast::Expr::Identifier(Ident::new("age")),
273 arg: Expr::Value(Value::Number("2".to_string(), false)).into(),
274 operator: FunctionArgOperator::RightArrow,
275 },
276 ],
277 ));
278 assert_eq!(table_ref, expected);
279 }
280}