risingwave_sqlparser/
test_utils.rs1#[cfg(not(feature = "std"))]
20use alloc::{
21 boxed::Box,
22 string::{String, ToString},
23 vec,
24 vec::Vec,
25};
26use core::fmt::Debug;
27
28use crate::ast::*;
29use crate::parser::{Parser, ParserError};
30use crate::tokenizer::Tokenizer;
31
32pub fn run_parser_method<F, T: Debug + PartialEq>(sql: &str, f: F) -> T
33where
34 F: Fn(&mut Parser<'_>) -> T,
35{
36 let mut tokenizer = Tokenizer::new(sql);
37 let tokens = tokenizer.tokenize_with_location().unwrap();
38 f(&mut Parser(&tokens))
39}
40
41pub fn parse_sql_statements(sql: &str) -> Result<Vec<Statement>, ParserError> {
42 Parser::parse_sql(sql)
43 }
46
47#[track_caller]
54pub fn one_statement_parses_to(sql: &str, canonical: &str) -> Statement {
55 let mut statements = parse_sql_statements(sql).unwrap();
56 assert_eq!(statements.len(), 1);
57
58 if !canonical.is_empty() && sql != canonical {
59 assert_eq!(parse_sql_statements(canonical).unwrap(), statements);
60 }
61
62 let only_statement = statements.pop().unwrap();
63 if !canonical.is_empty() {
64 assert_eq!(canonical, only_statement.to_string())
65 }
66 only_statement
67}
68
69#[track_caller]
72pub fn verified_stmt(query: &str) -> Statement {
73 one_statement_parses_to(query, query)
74}
75
76#[track_caller]
79pub fn verified_query(sql: &str) -> Query {
80 match verified_stmt(sql) {
81 Statement::Query(query) => *query,
82 _ => panic!("Expected Query"),
83 }
84}
85
86#[track_caller]
87pub fn query(sql: &str, canonical: &str) -> Query {
88 match one_statement_parses_to(sql, canonical) {
89 Statement::Query(query) => *query,
90 _ => panic!("Expected Query"),
91 }
92}
93
94#[track_caller]
97pub fn verified_only_select(query: &str) -> Select {
98 match verified_query(query).body {
99 SetExpr::Select(s) => *s,
100 _ => panic!("Expected SetExpr::Select"),
101 }
102}
103
104pub fn verified_expr(sql: &str) -> Expr {
107 let ast = run_parser_method(sql, |parser| parser.parse_expr()).unwrap();
108 assert_eq!(sql, &ast.to_string(), "round-tripping without changes");
109 ast
110}
111
112pub fn only<T>(v: impl IntoIterator<Item = T>) -> T {
113 let mut iter = v.into_iter();
114 match (iter.next(), iter.next()) {
115 (Some(item), None) => item,
116 _ => {
117 panic!("only called on collection without exactly one item")
118 }
119 }
120}
121
122pub fn expr_from_projection(item: &SelectItem) -> &Expr {
123 match item {
124 SelectItem::UnnamedExpr(expr) => expr,
125 _ => panic!("Expected UnnamedExpr"),
126 }
127}
128
129pub fn number(n: &'static str) -> Value {
130 Value::Number(n.parse().unwrap())
131}
132
133pub fn table_alias(name: impl Into<String>) -> Option<TableAlias> {
134 Some(TableAlias {
135 name: Ident::new_unchecked(name),
136 columns: vec![],
137 })
138}
139
140pub fn table(name: impl Into<String>) -> TableFactor {
141 TableFactor::Table {
142 name: ObjectName(vec![Ident::new_unchecked(name.into())]),
143 as_of: None,
144 alias: None,
145 }
146}
147
148pub fn join(relation: TableFactor) -> Join {
149 Join {
150 relation,
151 join_operator: JoinOperator::Inner(JoinConstraint::Natural),
152 }
153}