1use teaql_core::{
2 AggregateFunction, BinaryOp, DataType, DeleteCommand, EntityDescriptor, Expr, ExprFunction,
3 OrderBy, PropertyDescriptor, RecoverCommand, SelectQuery, SortDirection,
4 Value,
5};
6
7use crate::{CompiledQuery, DatabaseKind, SqlCompileError};
8
9const SQL_KEYWORDS: &[&str] = &[
10 "all", "alter", "and", "as", "asc", "between", "by", "case", "create", "delete", "desc",
11 "distinct", "drop", "exists", "false", "from", "group", "having", "in", "insert", "into", "is",
12 "join", "like", "limit", "not", "null", "offset", "on", "or", "order", "select", "set",
13 "table", "true", "type", "union", "update", "values", "where",
14];
15
16pub fn quote_identifier_if_needed(ident: &str, quote: char) -> String {
17 if is_wrapped_identifier(ident) {
18 return ident.to_owned();
19 }
20 if needs_quoted_identifier(ident) {
21 let quote_string = quote.to_string();
22 let escaped = ident.replace(quote, &(quote_string.clone() + "e_string));
23 return format!("{quote}{escaped}{quote}");
24 }
25 ident.to_owned()
26}
27
28fn is_wrapped_identifier(ident: &str) -> bool {
29 (ident.starts_with('"') && ident.ends_with('"'))
30 || (ident.starts_with('`') && ident.ends_with('`'))
31 || (ident.starts_with('[') && ident.ends_with(']'))
32}
33
34fn needs_quoted_identifier(ident: &str) -> bool {
35 if ident.is_empty()
36 || SQL_KEYWORDS
37 .binary_search(&ident.to_ascii_lowercase().as_str())
38 .is_ok()
39 {
40 return true;
41 }
42 let mut chars = ident.chars();
43 match chars.next() {
44 Some(first) if first == '_' || first.is_ascii_alphabetic() => {}
45 _ => return true,
46 }
47 chars.any(|ch| ch != '_' && !ch.is_ascii_alphanumeric())
48}
49
50
51pub trait SqlDialect {
52 fn kind(&self) -> DatabaseKind;
53 fn quote_ident(&self, ident: &str) -> String;
54 fn placeholder(&self, index: usize) -> String;
55
56 fn schema_setup_sqls(&self) -> &'static [&'static str] {
57 &[]
58 }
59
60 fn schema_type_sql(
61 &self,
62 data_type: DataType,
63 _property: &PropertyDescriptor,
64 ) -> Result<&'static str, SqlCompileError> {
65 match data_type {
66 DataType::Bool => Ok("BOOLEAN"),
67 DataType::I64 | DataType::U64 => Ok("INTEGER"),
68 DataType::F64 => Ok("REAL"),
69 DataType::Decimal => Ok("NUMERIC"),
70 DataType::Text | DataType::Json | DataType::Date | DataType::Timestamp => Ok("TEXT"),
71 }
72 }
73
74 fn column_definition_sql(
75 &self,
76 property: &PropertyDescriptor,
77 ) -> Result<String, SqlCompileError> {
78 let mut parts = vec![
79 self.quote_ident(&property.column_name),
80 self.schema_type_sql(property.data_type, property)?
81 .to_owned(),
82 ];
83
84 if property.is_id {
85 parts.push("PRIMARY KEY".to_owned());
86 }
87 if property.is_id || !property.nullable {
88 parts.push("NOT NULL".to_owned());
89 }
90
91 Ok(parts.join(" "))
92 }
93
94 fn compile_create_table(&self, entity: &EntityDescriptor) -> Result<String, SqlCompileError> {
95 let columns = entity
96 .properties
97 .iter()
98 .map(|property| self.column_definition_sql(property))
99 .collect::<Result<Vec<_>, _>>()?
100 .join(", ");
101 Ok(format!(
102 "CREATE TABLE IF NOT EXISTS {} ({columns})",
103 self.quote_ident(&entity.table_name)
104 ))
105 }
106
107 fn compile_add_column(
108 &self,
109 entity: &EntityDescriptor,
110 property: &PropertyDescriptor,
111 ) -> Result<String, SqlCompileError> {
112 Ok(format!(
113 "ALTER TABLE {} ADD COLUMN {}",
114 self.quote_ident(&entity.table_name),
115 self.column_definition_sql(property)?
116 ))
117 }
118
119 fn compile_select(
120 &self,
121 entity: &EntityDescriptor,
122 query: &SelectQuery,
123 ) -> Result<CompiledQuery, SqlCompileError> {
124 let mut params = Vec::new();
125 let sql = self.compile_select_sql(entity, query, &mut params)?;
126 Ok(CompiledQuery {
127 sql,
128 params,
129 comment: query.comment.clone(),
130 })
131 }
132
133 fn compile_select_sql(
134 &self,
135 entity: &EntityDescriptor,
136 query: &SelectQuery,
137 params: &mut Vec<Value>,
138 ) -> Result<String, SqlCompileError> {
139 if let Some(raw_sql) = &query.raw_sql {
140 return Ok(raw_sql.clone());
141 }
142
143 let projection = if query.aggregates.is_empty() {
144 self.select_projection(entity, query, params)?
145 } else {
146 self.aggregate_projection(entity, query, params)?
147 };
148
149 let mut sql = format!(
150 "SELECT {projection} FROM {}",
151 self.quote_ident(&entity.table_name)
152 );
153
154 let mut where_parts = Vec::new();
155 if let Some(filter) = &query.filter {
156 where_parts.push(self.compile_expr(entity, filter, params)?);
157 }
158
159 if let Some(search_text) = &query.search_with_text {
160 let mut or_parts = Vec::new();
161 let like_value = format!("%{}%", search_text);
162 for property in &entity.properties {
163 if property.data_type == teaql_core::DataType::Text {
164 params.push(teaql_core::Value::from(like_value.clone()));
165 or_parts.push(format!("{} LIKE {}", self.quote_ident(&property.column_name), self.placeholder(params.len())));
166 }
167 }
168 if !or_parts.is_empty() {
169 where_parts.push(format!("({})", or_parts.join(" OR ")));
170 }
171 }
172
173 where_parts.extend(query.raw_sql_search_criteria.iter().cloned());
174 if !where_parts.is_empty() {
175 sql.push_str(" WHERE ");
176 sql.push_str(&where_parts.join(" AND "));
177 }
178
179 if !query.group_by.is_empty() {
180 let group_by = query
181 .group_by
182 .iter()
183 .map(|field| self.column_sql(entity, field))
184 .collect::<Result<Vec<_>, _>>()?
185 .join(", ");
186 sql.push_str(" GROUP BY ");
187 sql.push_str(&group_by);
188 }
189
190 if let Some(having) = &query.having {
191 let having_sql = self.compile_expr(entity, having, params)?;
192 sql.push_str(" HAVING ");
193 sql.push_str(&having_sql);
194 }
195
196 if !query.order_by.is_empty() {
197 let order_by = query
198 .order_by
199 .iter()
200 .map(|order| self.order_by_sql(entity, order, params))
201 .collect::<Result<Vec<_>, _>>()?
202 .join(", ");
203 sql.push_str(" ORDER BY ");
204 sql.push_str(&order_by);
205 }
206
207 if let Some(slice) = query.slice {
208 if let Some(limit) = slice.limit {
209 sql.push_str(&format!(" LIMIT {limit}"));
210 }
211 if slice.offset > 0 {
212 sql.push_str(&format!(" OFFSET {}", slice.offset));
213 }
214 }
215
216 Ok(sql)
217 }
218
219 fn compile_insert(
220 &self,
221 entity: &EntityDescriptor,
222 command: &teaql_core::InsertCommand,
223 ) -> Result<CompiledQuery, SqlCompileError> {
224 let mut columns = Vec::new();
225 let mut placeholders = Vec::new();
226 let mut params = Vec::new();
227
228 for property in &entity.properties {
229 if let Some(value) = command.values.get(&property.name) {
230 columns.push(self.quote_ident(&property.column_name));
231 params.push(value.clone());
232 placeholders.push(self.placeholder(params.len()));
233 }
234 }
235
236 if columns.is_empty() {
237 return Err(SqlCompileError::EmptyMutation("insert".to_owned()));
238 }
239
240 Ok(CompiledQuery {
241 sql: format!(
242 "INSERT INTO {} ({}) VALUES ({})",
243 self.quote_ident(&entity.table_name),
244 columns.join(", "),
245 placeholders.join(", ")
246 ),
247 params,
248 comment: None,
249 })
250 }
251
252 fn compile_batch_insert(
253 &self,
254 entity: &EntityDescriptor,
255 command: &teaql_core::BatchInsertCommand,
256 ) -> Result<CompiledQuery, SqlCompileError> {
257 if command.batch_values.is_empty() {
258 return Err(SqlCompileError::EmptyMutation("batch_insert".to_owned()));
259 }
260
261 let mut columns = Vec::new();
262 let first_record = &command.batch_values[0];
263
264 for property in &entity.properties {
265 if first_record.contains_key(&property.name) {
266 columns.push(property.clone());
267 }
268 }
269
270 if columns.is_empty() {
271 return Err(SqlCompileError::EmptyMutation("batch_insert".to_owned()));
272 }
273
274 let column_names: Vec<String> = columns.iter().map(|p| self.quote_ident(&p.column_name)).collect();
275 let mut params = Vec::new();
276 let mut values_clauses = Vec::new();
277
278 for record in &command.batch_values {
279 let mut row_placeholders = Vec::new();
280 for property in &columns {
281 let value = record.get(&property.name).cloned().unwrap_or(teaql_core::Value::Null);
282 params.push(value);
283 row_placeholders.push(self.placeholder(params.len()));
284 }
285 values_clauses.push(format!("({})", row_placeholders.join(", ")));
286 }
287
288 Ok(CompiledQuery {
289 sql: format!(
290 "INSERT INTO {} ({}) VALUES {}",
291 self.quote_ident(&entity.table_name),
292 column_names.join(", "),
293 values_clauses.join(", ")
294 ),
295 params,
296 comment: None,
297 })
298 }
299
300 fn compile_update(
301 &self,
302 entity: &EntityDescriptor,
303 command: &teaql_core::UpdateCommand,
304 ) -> Result<CompiledQuery, SqlCompileError> {
305 let id_property = entity
306 .id_property()
307 .ok_or_else(|| SqlCompileError::MissingIdProperty(entity.name.clone()))?;
308 let mut assignments = Vec::new();
309 let mut params = Vec::new();
310
311 for property in &entity.properties {
312 if property.is_id {
313 continue;
314 }
315 if property.is_version && command.expected_version.is_some() {
316 continue;
317 }
318 if let Some(value) = command.values.get(&property.name) {
319 params.push(value.clone());
320 assignments.push(format!(
321 "{} = {}",
322 self.quote_ident(&property.column_name),
323 self.placeholder(params.len())
324 ));
325 }
326 }
327
328 if let Some(expected_version) = command.expected_version {
329 let version_property = entity
330 .version_property()
331 .ok_or_else(|| SqlCompileError::MissingVersionProperty(entity.name.clone()))?;
332 params.push(Value::I64(expected_version + 1));
333 assignments.push(format!(
334 "{} = {}",
335 self.quote_ident(&version_property.column_name),
336 self.placeholder(params.len())
337 ));
338 }
339
340 if assignments.is_empty() {
341 return Err(SqlCompileError::EmptyMutation("update".to_owned()));
342 }
343
344 params.push(command.id.clone());
345 let mut predicates = vec![format!(
346 "{} = {}",
347 self.quote_ident(&id_property.column_name),
348 self.placeholder(params.len())
349 )];
350
351 if let Some(expected_version) = command.expected_version {
352 let version_property = entity
353 .version_property()
354 .ok_or_else(|| SqlCompileError::MissingVersionProperty(entity.name.clone()))?;
355 params.push(Value::I64(expected_version));
356 predicates.push(format!(
357 "{} = {}",
358 self.quote_ident(&version_property.column_name),
359 self.placeholder(params.len())
360 ));
361 }
362
363 Ok(CompiledQuery {
364 sql: format!(
365 "UPDATE {} SET {} WHERE {}",
366 self.quote_ident(&entity.table_name),
367 assignments.join(", "),
368 predicates.join(" AND ")
369 ),
370 params,
371 comment: None,
372 })
373 }
374
375 fn compile_batch_update(
376 &self,
377 entity: &EntityDescriptor,
378 command: &teaql_core::BatchUpdateCommand,
379 ) -> Result<CompiledQuery, SqlCompileError> {
380 if command.batch_values.is_empty() {
381 return Err(SqlCompileError::EmptyMutation("batch_update".to_owned()));
382 }
383
384 let id_property = entity
385 .id_property()
386 .ok_or_else(|| SqlCompileError::MissingIdProperty(entity.name.clone()))?;
387
388 let mut params = Vec::new();
389 let mut set_clauses = Vec::new();
390
391 for field_name in &command.update_fields {
393 let property = entity.property_by_name(field_name)
394 .ok_or_else(|| SqlCompileError::UnknownField(field_name.clone()))?;
395
396 let mut case_parts = Vec::new();
397 case_parts.push(format!("CASE {}", self.quote_ident(&id_property.column_name)));
398
399 for (i, record) in command.batch_values.iter().enumerate() {
400 let id = &command.batch_ids[i];
401 let val = record.get(field_name).cloned().unwrap_or(teaql_core::Value::Null);
402
403 params.push(id.clone());
404 let id_ph = self.placeholder(params.len());
405
406 params.push(val);
407 let val_ph = self.placeholder(params.len());
408
409 case_parts.push(format!("WHEN {} THEN {}", id_ph, val_ph));
410 }
411
412 case_parts.push(format!("ELSE {} END", self.quote_ident(&property.column_name)));
413 set_clauses.push(format!("{} = {}", self.quote_ident(&property.column_name), case_parts.join(" ")));
414 }
415
416 let mut has_versions = false;
417 if let Some(version_property) = entity.version_property() {
418 let mut case_parts = Vec::new();
419 case_parts.push(format!("CASE {}", self.quote_ident(&id_property.column_name)));
420
421 for (i, exp_ver_opt) in command.batch_expected_versions.iter().enumerate() {
422 if let Some(exp_ver) = exp_ver_opt {
423 has_versions = true;
424 let id = &command.batch_ids[i];
425
426 params.push(id.clone());
427 let id_ph = self.placeholder(params.len());
428
429 params.push(teaql_core::Value::I64(*exp_ver + 1));
430 let val_ph = self.placeholder(params.len());
431
432 case_parts.push(format!("WHEN {} THEN {}", id_ph, val_ph));
433 }
434 }
435
436 if has_versions {
437 case_parts.push(format!("ELSE {} END", self.quote_ident(&version_property.column_name)));
438 set_clauses.push(format!("{} = {}", self.quote_ident(&version_property.column_name), case_parts.join(" ")));
439 }
440 }
441
442 if set_clauses.is_empty() {
443 return Err(SqlCompileError::EmptyMutation("batch_update".to_owned()));
444 }
445
446 let mut in_placeholders = Vec::new();
447 for id in &command.batch_ids {
448 params.push(id.clone());
449 in_placeholders.push(self.placeholder(params.len()));
450 }
451 let mut predicates = vec![format!(
452 "{} IN ({})",
453 self.quote_ident(&id_property.column_name),
454 in_placeholders.join(", ")
455 )];
456
457 if has_versions {
458 let version_property = entity.version_property().unwrap();
459 let mut case_parts = Vec::new();
460 case_parts.push(format!("CASE {}", self.quote_ident(&id_property.column_name)));
461
462 for (i, exp_ver_opt) in command.batch_expected_versions.iter().enumerate() {
463 if let Some(exp_ver) = exp_ver_opt {
464 let id = &command.batch_ids[i];
465
466 params.push(id.clone());
467 let id_ph = self.placeholder(params.len());
468
469 params.push(teaql_core::Value::I64(*exp_ver));
470 let val_ph = self.placeholder(params.len());
471
472 case_parts.push(format!("WHEN {} THEN {}", id_ph, val_ph));
473 }
474 }
475 case_parts.push(format!("ELSE {} END", self.quote_ident(&version_property.column_name)));
476
477 predicates.push(format!(
478 "{} = {}",
479 self.quote_ident(&version_property.column_name),
480 case_parts.join(" ")
481 ));
482 }
483
484 Ok(CompiledQuery {
485 sql: format!(
486 "UPDATE {} SET {} WHERE {}",
487 self.quote_ident(&entity.table_name),
488 set_clauses.join(", "),
489 predicates.join(" AND ")
490 ),
491 params,
492 comment: None,
493 })
494 }
495
496 fn compile_delete(
497 &self,
498 entity: &EntityDescriptor,
499 command: &DeleteCommand,
500 ) -> Result<CompiledQuery, SqlCompileError> {
501 let id_property = entity
502 .id_property()
503 .ok_or_else(|| SqlCompileError::MissingIdProperty(entity.name.clone()))?;
504 let mut params = Vec::new();
505
506 if command.soft_delete {
507 let version_property = entity
508 .version_property()
509 .ok_or_else(|| SqlCompileError::MissingVersionProperty(entity.name.clone()))?;
510 params.push(match command.expected_version {
511 Some(version) => Value::I64(-(version + 1)),
512 None => Value::I64(-1),
513 });
514
515 params.push(command.id.clone());
516 let mut predicates = vec![format!(
517 "{} = {}",
518 self.quote_ident(&id_property.column_name),
519 self.placeholder(params.len())
520 )];
521
522 if let Some(expected_version) = command.expected_version {
523 params.push(Value::I64(expected_version));
524 predicates.push(format!(
525 "{} = {}",
526 self.quote_ident(&version_property.column_name),
527 self.placeholder(params.len())
528 ));
529 }
530
531 return Ok(CompiledQuery {
532 sql: format!(
533 "UPDATE {} SET {} = {} WHERE {}",
534 self.quote_ident(&entity.table_name),
535 self.quote_ident(&version_property.column_name),
536 self.placeholder(1),
537 predicates.join(" AND ")
538 ),
539 params,
540 comment: None,
541 });
542 }
543
544 params.push(command.id.clone());
545 let mut predicates = vec![format!(
546 "{} = {}",
547 self.quote_ident(&id_property.column_name),
548 self.placeholder(params.len())
549 )];
550
551 if let Some(expected_version) = command.expected_version {
552 let version_property = entity
553 .version_property()
554 .ok_or_else(|| SqlCompileError::MissingVersionProperty(entity.name.clone()))?;
555 params.push(Value::I64(expected_version));
556 predicates.push(format!(
557 "{} = {}",
558 self.quote_ident(&version_property.column_name),
559 self.placeholder(params.len())
560 ));
561 }
562
563 Ok(CompiledQuery {
564 sql: format!(
565 "DELETE FROM {} WHERE {}",
566 self.quote_ident(&entity.table_name),
567 predicates.join(" AND ")
568 ),
569 params,
570 comment: None,
571 })
572 }
573
574 fn compile_recover(
575 &self,
576 entity: &EntityDescriptor,
577 command: &RecoverCommand,
578 ) -> Result<CompiledQuery, SqlCompileError> {
579 if command.expected_version >= 0 {
580 return Err(SqlCompileError::InvalidRecoverVersion(
581 command.expected_version,
582 ));
583 }
584
585 let id_property = entity
586 .id_property()
587 .ok_or_else(|| SqlCompileError::MissingIdProperty(entity.name.clone()))?;
588 let version_property = entity
589 .version_property()
590 .ok_or_else(|| SqlCompileError::MissingVersionProperty(entity.name.clone()))?;
591 let params = vec![
592 Value::I64(-command.expected_version + 1),
593 command.id.clone(),
594 Value::I64(command.expected_version),
595 ];
596
597 Ok(CompiledQuery {
598 sql: format!(
599 "UPDATE {} SET {} = {} WHERE {} = {} AND {} = {}",
600 self.quote_ident(&entity.table_name),
601 self.quote_ident(&version_property.column_name),
602 self.placeholder(1),
603 self.quote_ident(&id_property.column_name),
604 self.placeholder(2),
605 self.quote_ident(&version_property.column_name),
606 self.placeholder(3),
607 ),
608 params,
609 comment: None,
610 })
611 }
612
613 fn column_sql(
614 &self,
615 entity: &EntityDescriptor,
616 field: &str,
617 ) -> Result<String, SqlCompileError> {
618 let property = entity
619 .property_by_name(field)
620 .ok_or_else(|| SqlCompileError::UnknownField(field.to_owned()))?;
621 Ok(self.quote_ident(&property.column_name))
622 }
623
624 fn order_by_sql(
625 &self,
626 entity: &EntityDescriptor,
627 order_by: &OrderBy,
628 params: &mut Vec<Value>,
629 ) -> Result<String, SqlCompileError> {
630 let field = if let Some(expr) = &order_by.expr {
631 self.compile_expr(entity, expr, params)?
632 } else {
633 self.column_sql(entity, &order_by.field)?
634 };
635 let direction = match order_by.direction {
636 SortDirection::Asc => "ASC",
637 SortDirection::Desc => "DESC",
638 };
639 Ok(format!("{field} {direction}"))
640 }
641
642 fn select_projection(
643 &self,
644 entity: &EntityDescriptor,
645 query: &SelectQuery,
646 params: &mut Vec<Value>,
647 ) -> Result<String, SqlCompileError> {
648 let property_projection = |property: &PropertyDescriptor| {
649 let column = self.quote_ident(&property.column_name);
650 if property.column_name == property.name {
651 column
652 } else {
653 format!("{column} AS {}", self.quote_ident(&property.name))
654 }
655 };
656
657 if query.projection.is_empty()
658 && query.expr_projection.is_empty()
659 && query.raw_projections.is_empty()
660 && query.dynamic_properties.is_empty()
661 {
662 return Ok(entity
663 .properties
664 .iter()
665 .map(property_projection)
666 .collect::<Vec<_>>()
667 .join(", "));
668 }
669 let mut parts = query
670 .projection
671 .iter()
672 .map(|field| {
673 let property = entity
674 .property_by_name(field)
675 .ok_or_else(|| SqlCompileError::UnknownField(field.to_owned()))?;
676 Ok(property_projection(property))
677 })
678 .collect::<Result<Vec<_>, _>>()?;
679 for projection in &query.expr_projection {
680 let expr = self.compile_expr(entity, &projection.expr, params)?;
681 parts.push(format!("{expr} AS {}", self.quote_ident(&projection.alias)));
682 }
683 for projection in query
684 .raw_projections
685 .iter()
686 .chain(query.dynamic_properties.iter())
687 {
688 parts.push(format!(
689 "{} AS {}",
690 projection.raw_sql_segment,
691 self.quote_ident(&projection.property_name)
692 ));
693 }
694 Ok(parts.join(", "))
695 }
696
697 fn aggregate_projection(
698 &self,
699 entity: &EntityDescriptor,
700 query: &SelectQuery,
701 params: &mut Vec<Value>,
702 ) -> Result<String, SqlCompileError> {
703 let mut parts = Vec::new();
704 for field in query.group_by.iter().chain(query.projection.iter()) {
705 let column = self.column_sql(entity, field)?;
706 if !parts.contains(&column) {
707 parts.push(column);
708 }
709 }
710 for projection in &query.expr_projection {
711 let expr = self.compile_expr(entity, &projection.expr, params)?;
712 let aliased = format!("{expr} AS {}", self.quote_ident(&projection.alias));
713 if !parts.contains(&aliased) {
714 parts.push(aliased);
715 }
716 }
717 for projection in query
718 .raw_projections
719 .iter()
720 .chain(query.dynamic_properties.iter())
721 {
722 let aliased = format!(
723 "{} AS {}",
724 projection.raw_sql_segment,
725 self.quote_ident(&projection.property_name)
726 );
727 if !parts.contains(&aliased) {
728 parts.push(aliased);
729 }
730 }
731 parts.extend(
732 query
733 .aggregates
734 .iter()
735 .map(|aggregate| {
736 let field = if aggregate.function == AggregateFunction::Count
737 && aggregate.field == "*"
738 {
739 "*".to_owned()
740 } else {
741 self.column_sql(entity, &aggregate.field)?
742 };
743 let call = self.aggregate_call_sql(aggregate.function, &field);
744 Ok(format!("{call} AS {}", self.quote_ident(&aggregate.alias)))
745 })
746 .collect::<Result<Vec<_>, _>>()?,
747 );
748 Ok(parts.join(", "))
749 }
750
751 fn aggregate_call_sql(&self, function: AggregateFunction, field: &str) -> String {
752 let function_sql = self.aggregate_function_sql(function);
753 format!("{function_sql}({field})")
754 }
755
756 fn aggregate_function_sql(&self, function: AggregateFunction) -> &'static str {
757 match function {
758 AggregateFunction::Count => "COUNT",
759 AggregateFunction::Sum => "SUM",
760 AggregateFunction::Avg => "AVG",
761 AggregateFunction::Min => "MIN",
762 AggregateFunction::Max => "MAX",
763 AggregateFunction::Stddev => "STDDEV",
764 AggregateFunction::StddevPop => "STDDEV_POP",
765 AggregateFunction::VarSamp => "VAR_SAMP",
766 AggregateFunction::VarPop => "VAR_POP",
767 AggregateFunction::BitAnd => "BIT_AND",
768 AggregateFunction::BitOr => "BIT_OR",
769 AggregateFunction::BitXor => "BIT_XOR",
770 }
771 }
772
773 fn compile_expr(
774 &self,
775 entity: &EntityDescriptor,
776 expr: &Expr,
777 params: &mut Vec<Value>,
778 ) -> Result<String, SqlCompileError> {
779 match expr {
780 Expr::Column(name) => self.column_sql(entity, name),
781 Expr::Value(value) => {
782 params.push(value.clone());
783 Ok(self.placeholder(params.len()))
784 }
785 Expr::Function { function, args } => {
786 self.compile_function(entity, *function, args, params)
787 }
788 Expr::Binary { left, op, right } => {
789 if matches!(
790 op,
791 BinaryOp::In | BinaryOp::NotIn | BinaryOp::InLarge | BinaryOp::NotInLarge
792 ) {
793 return self.compile_in(entity, left, *op, right, params);
794 }
795 let lhs = self.compile_expr(entity, left, params)?;
796 let rhs = self.compile_expr(entity, right, params)?;
797 let op = match op {
798 BinaryOp::Eq => "=",
799 BinaryOp::Ne => "!=",
800 BinaryOp::Gt => ">",
801 BinaryOp::Gte => ">=",
802 BinaryOp::Lt => "<",
803 BinaryOp::Lte => "<=",
804 BinaryOp::Like => "LIKE",
805 BinaryOp::NotLike => "NOT LIKE",
806 BinaryOp::In | BinaryOp::NotIn | BinaryOp::InLarge | BinaryOp::NotInLarge => {
807 unreachable!()
808 }
809 };
810 Ok(format!("({lhs} {op} {rhs})"))
811 }
812 Expr::SubQuery {
813 left,
814 op,
815 entity: sub_entity,
816 query,
817 } => self.compile_subquery(entity, left, *op, sub_entity, query, params),
818 Expr::Between { expr, lower, upper } => {
819 let expr = self.compile_expr(entity, expr, params)?;
820 let lower = self.compile_expr(entity, lower, params)?;
821 let upper = self.compile_expr(entity, upper, params)?;
822 Ok(format!("({expr} BETWEEN {lower} AND {upper})"))
823 }
824 Expr::IsNull(expr) => {
825 let expr = self.compile_expr(entity, expr, params)?;
826 Ok(format!("({expr} IS NULL)"))
827 }
828 Expr::IsNotNull(expr) => {
829 let expr = self.compile_expr(entity, expr, params)?;
830 Ok(format!("({expr} IS NOT NULL)"))
831 }
832 Expr::And(parts) => self.compile_joined(entity, parts, "AND", params),
833 Expr::Or(parts) => self.compile_joined(entity, parts, "OR", params),
834 Expr::Not(expr) => {
835 let expr = self.compile_expr(entity, expr, params)?;
836 Ok(format!("(NOT {expr})"))
837 }
838 }
839 }
840
841 fn compile_function(
842 &self,
843 entity: &EntityDescriptor,
844 function: ExprFunction,
845 args: &[Expr],
846 params: &mut Vec<Value>,
847 ) -> Result<String, SqlCompileError> {
848 match function {
849 ExprFunction::Soundex => {
850 let [arg] = args else {
851 return Err(SqlCompileError::InvalidFunctionArguments(
852 "SOUNDEX expects exactly one argument".to_owned(),
853 ));
854 };
855 let arg = self.compile_expr(entity, arg, params)?;
856 Ok(format!("SOUNDEX({arg})"))
857 }
858 ExprFunction::Gbk => self.compile_gbk_function(entity, args, params),
859 ExprFunction::Count if args.is_empty() => Ok("COUNT(*)".to_owned()),
860 ExprFunction::Count => self.compile_single_arg_function(entity, "COUNT", args, params),
861 ExprFunction::Sum => self.compile_single_arg_function(entity, "SUM", args, params),
862 ExprFunction::Avg => self.compile_single_arg_function(entity, "AVG", args, params),
863 ExprFunction::Min => self.compile_single_arg_function(entity, "MIN", args, params),
864 ExprFunction::Max => self.compile_single_arg_function(entity, "MAX", args, params),
865 ExprFunction::Stddev => {
866 self.compile_single_arg_function(entity, "STDDEV", args, params)
867 }
868 ExprFunction::StddevPop => {
869 self.compile_single_arg_function(entity, "STDDEV_POP", args, params)
870 }
871 ExprFunction::VarSamp => {
872 self.compile_single_arg_function(entity, "VAR_SAMP", args, params)
873 }
874 ExprFunction::VarPop => {
875 self.compile_single_arg_function(entity, "VAR_POP", args, params)
876 }
877 ExprFunction::BitAnd => {
878 self.compile_single_arg_function(entity, "BIT_AND", args, params)
879 }
880 ExprFunction::BitOr => self.compile_single_arg_function(entity, "BIT_OR", args, params),
881 ExprFunction::BitXor => {
882 self.compile_single_arg_function(entity, "BIT_XOR", args, params)
883 }
884 }
885 }
886
887 fn compile_single_arg_function(
888 &self,
889 entity: &EntityDescriptor,
890 function: &str,
891 args: &[Expr],
892 params: &mut Vec<Value>,
893 ) -> Result<String, SqlCompileError> {
894 let [arg] = args else {
895 return Err(SqlCompileError::InvalidFunctionArguments(format!(
896 "{function} expects exactly one argument"
897 )));
898 };
899 let arg = self.compile_expr(entity, arg, params)?;
900 Ok(format!("{function}({arg})"))
901 }
902
903 fn compile_gbk_function(
907 &self,
908 entity: &EntityDescriptor,
909 args: &[Expr],
910 params: &mut Vec<Value>,
911 ) -> Result<String, SqlCompileError> {
912 let [arg] = args else {
913 return Err(SqlCompileError::InvalidFunctionArguments(
914 "GBK expects exactly one argument".to_owned(),
915 ));
916 };
917 let arg = self.compile_expr(entity, arg, params)?;
920 Ok(arg)
921 }
922
923 fn compile_subquery(
924 &self,
925 entity: &EntityDescriptor,
926 left: &Expr,
927 op: BinaryOp,
928 sub_entity: &EntityDescriptor,
929 query: &SelectQuery,
930 params: &mut Vec<Value>,
931 ) -> Result<String, SqlCompileError> {
932 let lhs = self.compile_expr(entity, left, params)?;
933 let operator = match op {
934 BinaryOp::In | BinaryOp::InLarge => "IN",
935 BinaryOp::NotIn | BinaryOp::NotInLarge => "NOT IN",
936 _ => return Err(SqlCompileError::InvalidSubQueryOperator(format!("{op:?}"))),
937 };
938 let subquery = self.compile_select_sql(sub_entity, query, params)?;
939 Ok(format!("({lhs} {operator} ({subquery}))"))
940 }
941
942 fn compile_joined(
943 &self,
944 entity: &EntityDescriptor,
945 parts: &[Expr],
946 joiner: &str,
947 params: &mut Vec<Value>,
948 ) -> Result<String, SqlCompileError> {
949 let compiled = parts
950 .iter()
951 .map(|part| self.compile_expr(entity, part, params))
952 .collect::<Result<Vec<_>, _>>()?;
953 Ok(format!("({})", compiled.join(&format!(" {joiner} "))))
954 }
955
956 fn compile_in(
957 &self,
958 entity: &EntityDescriptor,
959 left: &Expr,
960 op: BinaryOp,
961 right: &Expr,
962 params: &mut Vec<Value>,
963 ) -> Result<String, SqlCompileError> {
964 let lhs = self.compile_expr(entity, left, params)?;
965 let operator = match op {
966 BinaryOp::In | BinaryOp::InLarge => "IN",
967 BinaryOp::NotIn | BinaryOp::NotInLarge => "NOT IN",
968 _ => unreachable!(),
969 };
970 match right {
971 Expr::Value(Value::List(values)) => {
972 if values.is_empty() {
973 return Err(SqlCompileError::EmptyInList);
974 }
975 let mut placeholders = Vec::with_capacity(values.len());
976 for value in values {
977 params.push(value.clone());
978 placeholders.push(self.placeholder(params.len()));
979 }
980 Ok(format!("({lhs} {operator} ({}))", placeholders.join(", ")))
981 }
982 _ => {
983 let rhs = self.compile_expr(entity, right, params)?;
984 Ok(format!("({lhs} {operator} ({rhs}))"))
985 }
986 }
987 }
988}