nodedb_sql/parser/database_stmt/
parse.rs1use crate::ddl_ast::statement::NodedbStatement;
11use crate::error::SqlError;
12
13pub fn try_parse_database_statement(sql: &str) -> Result<Option<NodedbStatement>, SqlError> {
20 let trimmed = sql.trim();
21 if trimmed.is_empty() {
22 return Ok(None);
23 }
24 let upper = trimmed.to_uppercase();
25 let parts: Vec<&str> = trimmed.split_whitespace().collect();
26 if parts.is_empty() {
27 return Ok(None);
28 }
29 crate::ddl_ast::parse::database::try_parse(&upper, &parts, trimmed).transpose()
30}
31
32#[cfg(test)]
33mod tests {
34 use super::*;
35 use crate::ddl_ast::statement::{AlterDatabaseOperation, NodedbStatement};
36
37 fn ok(sql: &str) -> NodedbStatement {
38 try_parse_database_statement(sql)
39 .expect("expected Ok")
40 .expect("expected Some")
41 }
42
43 #[test]
44 fn parse_create_database() {
45 match ok("CREATE DATABASE mydb") {
46 NodedbStatement::CreateDatabase {
47 name,
48 if_not_exists,
49 ..
50 } => {
51 assert_eq!(name, "mydb");
52 assert!(!if_not_exists);
53 }
54 other => panic!("unexpected: {other:?}"),
55 }
56 }
57
58 #[test]
59 fn parse_create_database_if_not_exists() {
60 match ok("CREATE DATABASE IF NOT EXISTS mydb") {
61 NodedbStatement::CreateDatabase {
62 name,
63 if_not_exists,
64 ..
65 } => {
66 assert_eq!(name, "mydb");
67 assert!(if_not_exists);
68 }
69 other => panic!("unexpected: {other:?}"),
70 }
71 }
72
73 #[test]
74 fn parse_drop_database() {
75 match ok("DROP DATABASE mydb CASCADE") {
76 NodedbStatement::DropDatabase { name, cascade, .. } => {
77 assert_eq!(name, "mydb");
78 assert!(cascade);
79 }
80 other => panic!("unexpected: {other:?}"),
81 }
82 }
83
84 #[test]
85 fn parse_drop_database_if_exists() {
86 match ok("DROP DATABASE IF EXISTS mydb") {
87 NodedbStatement::DropDatabase {
88 name, if_exists, ..
89 } => {
90 assert_eq!(name, "mydb");
91 assert!(if_exists);
92 }
93 other => panic!("unexpected: {other:?}"),
94 }
95 }
96
97 #[test]
98 fn parse_alter_database_rename() {
99 match ok("ALTER DATABASE mydb RENAME TO newdb") {
100 NodedbStatement::AlterDatabase { name, operation } => {
101 assert_eq!(name, "mydb");
102 assert_eq!(
103 operation,
104 AlterDatabaseOperation::Rename {
105 new_name: "newdb".into()
106 }
107 );
108 }
109 other => panic!("unexpected: {other:?}"),
110 }
111 }
112
113 #[test]
114 fn parse_alter_database_set_quota() {
115 match ok("ALTER DATABASE mydb SET QUOTA (max_qps = 500)") {
116 NodedbStatement::AlterDatabase { name, operation } => {
117 assert_eq!(name, "mydb");
118 match operation {
119 AlterDatabaseOperation::SetQuota(spec) => {
120 assert_eq!(spec.max_qps, Some(500));
121 }
122 other => panic!("expected SetQuota, got {other:?}"),
123 }
124 }
125 other => panic!("unexpected: {other:?}"),
126 }
127 }
128
129 #[test]
130 fn parse_alter_database_materialize() {
131 match ok("ALTER DATABASE mydb MATERIALIZE") {
132 NodedbStatement::AlterDatabase { operation, .. } => {
133 assert_eq!(operation, AlterDatabaseOperation::Materialize);
134 }
135 other => panic!("unexpected: {other:?}"),
136 }
137 }
138
139 #[test]
140 fn parse_alter_database_promote() {
141 match ok("ALTER DATABASE mydb PROMOTE") {
142 NodedbStatement::AlterDatabase { operation, .. } => {
143 assert_eq!(operation, AlterDatabaseOperation::Promote);
144 }
145 other => panic!("unexpected: {other:?}"),
146 }
147 }
148
149 #[test]
150 fn parse_show_databases() {
151 assert_eq!(
152 try_parse_database_statement("SHOW DATABASES")
153 .unwrap()
154 .unwrap(),
155 NodedbStatement::ShowDatabases
156 );
157 }
158
159 #[test]
160 fn parse_use_database() {
161 match ok("USE DATABASE mydb") {
162 NodedbStatement::UseDatabase { name } => assert_eq!(name, "mydb"),
163 other => panic!("unexpected: {other:?}"),
164 }
165 }
166
167 #[test]
168 fn passthrough_non_database_sql() {
169 assert!(
170 try_parse_database_statement("SELECT * FROM t")
171 .unwrap()
172 .is_none()
173 );
174 assert!(
175 try_parse_database_statement("CREATE COLLECTION users")
176 .unwrap()
177 .is_none()
178 );
179 assert!(
180 try_parse_database_statement("INSERT INTO foo VALUES (1)")
181 .unwrap()
182 .is_none()
183 );
184 }
185
186 #[test]
187 fn parse_clone_database() {
188 use crate::ddl_ast::CloneAsOf;
189 match ok("CLONE DATABASE new_db FROM source_db") {
190 NodedbStatement::CloneDatabase {
191 new_name,
192 source_name,
193 as_of,
194 } => {
195 assert_eq!(new_name, "new_db");
196 assert_eq!(source_name, "source_db");
197 assert_eq!(as_of, CloneAsOf::Latest);
198 }
199 other => panic!("unexpected: {other:?}"),
200 }
201 }
202
203 #[test]
204 fn parse_mirror_database() {
205 use crate::ddl_ast::MirrorMode;
206 match ok("MIRROR DATABASE replica FROM prod-us.source") {
207 NodedbStatement::MirrorDatabase {
208 local_name,
209 source_cluster,
210 source_database,
211 mode,
212 } => {
213 assert_eq!(local_name, "replica");
214 assert_eq!(source_cluster, "prod-us");
215 assert_eq!(source_database, "source");
216 assert_eq!(mode, MirrorMode::Async);
217 }
218 other => panic!("unexpected: {other:?}"),
219 }
220 }
221
222 #[test]
223 fn parse_backup_database() {
224 match ok("BACKUP DATABASE mydb TO 's3://bucket/path'") {
225 NodedbStatement::BackupDatabase { name, uri } => {
226 assert_eq!(name, "mydb");
227 assert!(!uri.is_empty());
228 }
229 other => panic!("unexpected: {other:?}"),
230 }
231 }
232
233 #[test]
234 fn parse_restore_database() {
235 match ok("RESTORE DATABASE mydb FROM 's3://bucket/path'") {
236 NodedbStatement::RestoreDatabase { name, uri } => {
237 assert_eq!(name, "mydb");
238 assert!(!uri.is_empty());
239 }
240 other => panic!("unexpected: {other:?}"),
241 }
242 }
243
244 #[test]
245 fn parse_move_tenant() {
246 match ok("MOVE TENANT t1 FROM db_a TO db_b") {
247 NodedbStatement::MoveTenant {
248 tenant_name,
249 from_db,
250 to_db,
251 } => {
252 assert_eq!(tenant_name, "t1");
253 assert_eq!(from_db, "db_a");
254 assert_eq!(to_db, "db_b");
255 }
256 other => panic!("unexpected: {other:?}"),
257 }
258 }
259
260 #[test]
261 fn drop_missing_name_returns_error() {
262 let result = try_parse_database_statement("DROP DATABASE");
263 assert!(result.is_err() || result.unwrap().is_some());
264 }
265}