1use super::{PostgresQueryBuilder, QueryBuilder};
7use crate::{
8 dcl::{
9 AlterRoleStatement, AlterUserStatement, CreateRoleStatement, CreateUserStatement,
10 DropRoleStatement, DropUserStatement, GrantRoleStatement, GrantStatement,
11 RenameUserStatement, ResetRoleStatement, RevokeRoleStatement, RevokeStatement,
12 SetDefaultRoleStatement, SetRoleStatement,
13 },
14 query::{
15 AlterDatabaseStatement, AlterFunctionStatement, AlterIndexStatement,
16 AlterMaterializedViewStatement, AlterProcedureStatement, AlterSchemaStatement,
17 AlterSequenceStatement, AlterTableStatement, AlterTypeStatement, AnalyzeStatement,
18 CheckTableStatement, CommentStatement, CreateDatabaseStatement, CreateFunctionStatement,
19 CreateIndexStatement, CreateMaterializedViewStatement, CreateProcedureStatement,
20 CreateSchemaStatement, CreateSequenceStatement, CreateTableStatement,
21 CreateTriggerStatement, CreateTypeStatement, CreateViewStatement, DeleteStatement,
22 DropDatabaseStatement, DropFunctionStatement, DropIndexStatement,
23 DropMaterializedViewStatement, DropProcedureStatement, DropSchemaStatement,
24 DropSequenceStatement, DropTableStatement, DropTriggerStatement, DropTypeStatement,
25 DropViewStatement, InsertStatement, OptimizeTableStatement,
26 RefreshMaterializedViewStatement, ReindexStatement, RepairTableStatement, SelectStatement,
27 TruncateTableStatement, UpdateStatement, VacuumStatement,
28 },
29 value::Values,
30};
31
32#[derive(Debug, Clone, Default)]
52pub struct CockroachDBQueryBuilder {
53 postgres: PostgresQueryBuilder,
54}
55
56impl CockroachDBQueryBuilder {
57 pub fn new() -> Self {
59 Self {
60 postgres: PostgresQueryBuilder::new(),
61 }
62 }
63}
64
65impl QueryBuilder for CockroachDBQueryBuilder {
66 fn escape_identifier(&self, ident: &str) -> String {
67 self.postgres.escape_identifier(ident)
68 }
69
70 fn format_placeholder(&self, index: usize) -> String {
71 self.postgres.format_placeholder(index)
72 }
73
74 fn build_select(&self, stmt: &SelectStatement) -> (String, Values) {
75 self.postgres.build_select(stmt)
76 }
77
78 fn build_insert(&self, stmt: &InsertStatement) -> (String, Values) {
79 self.postgres.build_insert(stmt)
80 }
81
82 fn build_update(&self, stmt: &UpdateStatement) -> (String, Values) {
83 self.postgres.build_update(stmt)
84 }
85
86 fn build_delete(&self, stmt: &DeleteStatement) -> (String, Values) {
87 self.postgres.build_delete(stmt)
88 }
89
90 fn build_create_table(&self, stmt: &CreateTableStatement) -> (String, Values) {
91 self.postgres.build_create_table(stmt)
92 }
93
94 fn build_alter_table(&self, stmt: &AlterTableStatement) -> (String, Values) {
95 self.postgres.build_alter_table(stmt)
96 }
97
98 fn build_drop_table(&self, stmt: &DropTableStatement) -> (String, Values) {
99 self.postgres.build_drop_table(stmt)
100 }
101
102 fn build_create_index(&self, stmt: &CreateIndexStatement) -> (String, Values) {
103 self.postgres.build_create_index(stmt)
104 }
105
106 fn build_drop_index(&self, stmt: &DropIndexStatement) -> (String, Values) {
107 self.postgres.build_drop_index(stmt)
108 }
109
110 fn build_create_view(&self, stmt: &CreateViewStatement) -> (String, Values) {
111 self.postgres.build_create_view(stmt)
112 }
113
114 fn build_drop_view(&self, stmt: &DropViewStatement) -> (String, Values) {
115 self.postgres.build_drop_view(stmt)
116 }
117
118 fn build_truncate_table(&self, stmt: &TruncateTableStatement) -> (String, Values) {
119 self.postgres.build_truncate_table(stmt)
120 }
121
122 fn build_create_trigger(&self, stmt: &CreateTriggerStatement) -> (String, Values) {
123 self.postgres.build_create_trigger(stmt)
124 }
125
126 fn build_drop_trigger(&self, stmt: &DropTriggerStatement) -> (String, Values) {
127 self.postgres.build_drop_trigger(stmt)
128 }
129
130 fn build_alter_index(&self, stmt: &AlterIndexStatement) -> (String, Values) {
131 self.postgres.build_alter_index(stmt)
132 }
133
134 fn build_reindex(&self, stmt: &ReindexStatement) -> (String, Values) {
135 self.postgres.build_reindex(stmt)
136 }
137
138 fn build_create_schema(&self, stmt: &CreateSchemaStatement) -> (String, Values) {
139 self.postgres.build_create_schema(stmt)
141 }
142
143 fn build_alter_schema(&self, stmt: &AlterSchemaStatement) -> (String, Values) {
144 self.postgres.build_alter_schema(stmt)
146 }
147
148 fn build_drop_schema(&self, stmt: &DropSchemaStatement) -> (String, Values) {
149 self.postgres.build_drop_schema(stmt)
151 }
152
153 fn build_create_sequence(&self, stmt: &CreateSequenceStatement) -> (String, Values) {
154 self.postgres.build_create_sequence(stmt)
156 }
157
158 fn build_alter_sequence(&self, stmt: &AlterSequenceStatement) -> (String, Values) {
159 self.postgres.build_alter_sequence(stmt)
161 }
162
163 fn build_drop_sequence(&self, stmt: &DropSequenceStatement) -> (String, Values) {
164 self.postgres.build_drop_sequence(stmt)
166 }
167
168 fn build_comment(&self, stmt: &CommentStatement) -> (String, Values) {
169 self.postgres.build_comment(stmt)
171 }
172
173 fn build_create_database(&self, stmt: &CreateDatabaseStatement) -> (String, Values) {
174 self.postgres.build_create_database(stmt)
177 }
178
179 fn build_alter_database(&self, stmt: &AlterDatabaseStatement) -> (String, Values) {
180 self.postgres.build_alter_database(stmt)
183 }
184
185 fn build_drop_database(&self, stmt: &DropDatabaseStatement) -> (String, Values) {
186 self.postgres.build_drop_database(stmt)
189 }
190
191 fn build_optimize_table(&self, _stmt: &OptimizeTableStatement) -> (String, Values) {
192 panic!(
193 "OPTIMIZE TABLE is MySQL-specific. CockroachDB automatically optimizes tables in the background."
194 );
195 }
196
197 fn build_repair_table(&self, _stmt: &RepairTableStatement) -> (String, Values) {
198 panic!(
199 "REPAIR TABLE is not supported in CockroachDB. CockroachDB automatically repairs data through replication and consistency checks."
200 );
201 }
202
203 fn build_check_table(&self, _stmt: &CheckTableStatement) -> (String, Values) {
204 panic!(
205 "CHECK TABLE is not supported in CockroachDB. Use SHOW EXPERIMENTAL_RANGES or other system tables to monitor table health."
206 );
207 }
208
209 fn build_create_function(&self, stmt: &CreateFunctionStatement) -> (String, Values) {
210 self.postgres.build_create_function(stmt)
212 }
213
214 fn build_alter_function(&self, stmt: &AlterFunctionStatement) -> (String, Values) {
215 self.postgres.build_alter_function(stmt)
217 }
218
219 fn build_drop_function(&self, stmt: &DropFunctionStatement) -> (String, Values) {
220 self.postgres.build_drop_function(stmt)
222 }
223
224 fn build_create_procedure(&self, stmt: &CreateProcedureStatement) -> (String, Values) {
225 self.postgres.build_create_procedure(stmt)
227 }
228
229 fn build_alter_procedure(&self, stmt: &AlterProcedureStatement) -> (String, Values) {
230 self.postgres.build_alter_procedure(stmt)
232 }
233
234 fn build_drop_procedure(&self, stmt: &DropProcedureStatement) -> (String, Values) {
235 self.postgres.build_drop_procedure(stmt)
237 }
238
239 fn build_create_type(&self, stmt: &CreateTypeStatement) -> (String, Values) {
240 self.postgres.build_create_type(stmt)
242 }
243
244 fn build_alter_type(&self, stmt: &AlterTypeStatement) -> (String, Values) {
245 self.postgres.build_alter_type(stmt)
247 }
248
249 fn build_drop_type(&self, stmt: &DropTypeStatement) -> (String, Values) {
250 self.postgres.build_drop_type(stmt)
252 }
253
254 fn build_grant(&self, stmt: &GrantStatement) -> (String, Values) {
257 self.postgres.build_grant(stmt)
258 }
259
260 fn build_revoke(&self, stmt: &RevokeStatement) -> (String, Values) {
261 self.postgres.build_revoke(stmt)
262 }
263
264 fn build_grant_role(&self, stmt: &GrantRoleStatement) -> (String, Values) {
265 self.postgres.build_grant_role(stmt)
266 }
267
268 fn build_revoke_role(&self, stmt: &RevokeRoleStatement) -> (String, Values) {
269 self.postgres.build_revoke_role(stmt)
270 }
271
272 fn build_create_role(&self, stmt: &CreateRoleStatement) -> (String, Values) {
273 self.postgres.build_create_role(stmt)
274 }
275
276 fn build_drop_role(&self, stmt: &DropRoleStatement) -> (String, Values) {
277 self.postgres.build_drop_role(stmt)
278 }
279
280 fn build_alter_role(&self, stmt: &AlterRoleStatement) -> (String, Values) {
281 self.postgres.build_alter_role(stmt)
282 }
283
284 fn build_create_user(&self, stmt: &CreateUserStatement) -> (String, Values) {
285 self.postgres.build_create_user(stmt)
286 }
287
288 fn build_drop_user(&self, stmt: &DropUserStatement) -> (String, Values) {
289 self.postgres.build_drop_user(stmt)
290 }
291
292 fn build_alter_user(&self, stmt: &AlterUserStatement) -> (String, Values) {
293 self.postgres.build_alter_user(stmt)
294 }
295
296 fn build_rename_user(&self, stmt: &RenameUserStatement) -> (String, Values) {
297 self.postgres.build_rename_user(stmt)
298 }
299
300 fn build_set_role(&self, stmt: &SetRoleStatement) -> (String, Values) {
301 self.postgres.build_set_role(stmt)
302 }
303
304 fn build_reset_role(&self, stmt: &ResetRoleStatement) -> (String, Values) {
305 self.postgres.build_reset_role(stmt)
306 }
307
308 fn build_set_default_role(&self, stmt: &SetDefaultRoleStatement) -> (String, Values) {
309 self.postgres.build_set_default_role(stmt)
310 }
311
312 fn build_vacuum(&self, stmt: &VacuumStatement) -> (String, Values) {
315 self.postgres.build_vacuum(stmt)
316 }
317
318 fn build_analyze(&self, stmt: &AnalyzeStatement) -> (String, Values) {
319 self.postgres.build_analyze(stmt)
320 }
321
322 fn build_create_materialized_view(
325 &self,
326 stmt: &CreateMaterializedViewStatement,
327 ) -> (String, Values) {
328 self.postgres.build_create_materialized_view(stmt)
329 }
330
331 fn build_alter_materialized_view(
332 &self,
333 stmt: &AlterMaterializedViewStatement,
334 ) -> (String, Values) {
335 self.postgres.build_alter_materialized_view(stmt)
336 }
337
338 fn build_drop_materialized_view(
339 &self,
340 stmt: &DropMaterializedViewStatement,
341 ) -> (String, Values) {
342 self.postgres.build_drop_materialized_view(stmt)
343 }
344
345 fn build_refresh_materialized_view(
346 &self,
347 stmt: &RefreshMaterializedViewStatement,
348 ) -> (String, Values) {
349 self.postgres.build_refresh_materialized_view(stmt)
350 }
351}
352
353#[cfg(test)]
354mod tests {
355 use super::*;
356 use crate::query::Query;
357
358 #[test]
360 fn test_create_function_delegates_to_postgres() {
361 use crate::types::function::FunctionLanguage;
362
363 let builder = CockroachDBQueryBuilder::new();
364 let mut stmt = Query::create_function();
365 stmt.name("my_func")
366 .returns("integer")
367 .language(FunctionLanguage::Sql)
368 .body("SELECT 1");
369
370 let (sql, values) = builder.build_create_function(&stmt);
371 assert_eq!(
373 sql,
374 r#"CREATE FUNCTION "my_func"() RETURNS integer LANGUAGE SQL AS $$SELECT 1$$"#
375 );
376 assert_eq!(values.len(), 0);
377 }
378
379 #[test]
380 fn test_alter_function_delegates_to_postgres() {
381 let builder = CockroachDBQueryBuilder::new();
382 let mut stmt = Query::alter_function();
383 stmt.name("my_func").rename_to("new_func");
384
385 let (sql, values) = builder.build_alter_function(&stmt);
386 assert_eq!(sql, r#"ALTER FUNCTION "my_func" RENAME TO "new_func""#);
388 assert_eq!(values.len(), 0);
389 }
390
391 #[test]
392 fn test_drop_function_delegates_to_postgres() {
393 let builder = CockroachDBQueryBuilder::new();
394 let mut stmt = Query::drop_function();
395 stmt.name("my_func").if_exists().cascade();
396
397 let (sql, values) = builder.build_drop_function(&stmt);
398 assert_eq!(sql, r#"DROP FUNCTION IF EXISTS "my_func" CASCADE"#);
400 assert_eq!(values.len(), 0);
401 }
402
403 #[test]
405 fn test_create_type_enum_delegates_to_postgres() {
406 let builder = CockroachDBQueryBuilder::new();
407 let mut stmt = Query::create_type();
408 stmt.name("mood")
409 .as_enum(vec!["happy".to_string(), "sad".to_string()]);
410
411 let (sql, values) = builder.build_create_type(&stmt);
412 assert_eq!(sql, r#"CREATE TYPE "mood" AS ENUM ('happy', 'sad')"#);
414 assert_eq!(values.len(), 0);
415 }
416
417 #[test]
418 fn test_alter_type_delegates_to_postgres() {
419 let builder = CockroachDBQueryBuilder::new();
420 let mut stmt = Query::alter_type();
421 stmt.name("mood").rename_to("feeling");
422
423 let (sql, values) = builder.build_alter_type(&stmt);
424 assert_eq!(sql, r#"ALTER TYPE "mood" RENAME TO "feeling""#);
426 assert_eq!(values.len(), 0);
427 }
428
429 #[test]
430 fn test_drop_type_delegates_to_postgres() {
431 let builder = CockroachDBQueryBuilder::new();
432 let mut stmt = Query::drop_type();
433 stmt.name("mood").if_exists().cascade();
434
435 let (sql, values) = builder.build_drop_type(&stmt);
436 assert_eq!(sql, r#"DROP TYPE IF EXISTS "mood" CASCADE"#);
438 assert_eq!(values.len(), 0);
439 }
440
441 #[test]
443 #[should_panic(expected = "CockroachDB automatically optimizes tables")]
444 fn test_optimize_table_panics() {
445 let builder = CockroachDBQueryBuilder::new();
446 let mut stmt = Query::optimize_table();
447 stmt.table("users");
448
449 let _ = builder.build_optimize_table(&stmt);
450 }
451
452 #[test]
453 #[should_panic(expected = "not supported in CockroachDB")]
454 fn test_repair_table_panics() {
455 let builder = CockroachDBQueryBuilder::new();
456 let mut stmt = Query::repair_table();
457 stmt.table("users");
458
459 let _ = builder.build_repair_table(&stmt);
460 }
461
462 #[test]
463 #[should_panic(expected = "not supported in CockroachDB")]
464 fn test_check_table_panics() {
465 let builder = CockroachDBQueryBuilder::new();
466 let mut stmt = Query::check_table();
467 stmt.table("users");
468
469 let _ = builder.build_check_table(&stmt);
470 }
471}