1use json::{JsonValue, object};
2
3static DISABLE_FIELD: &[&str] = &["default", "select", "delete", "insert", "update", "order", "group", "user", "password", "desc", "index", "from", "host", "user", "read", "partition"];
4
5pub mod sql_safety {
7 static SQL_KEYWORDS: &[&str] = &[
8 "select", "insert", "update", "delete", "drop", "truncate", "alter",
9 "create", "exec", "execute", "union",
10 ];
11
12 static DANGEROUS_PATTERNS: &[&str] = &[
13 "--", "/*", "*/", ";", "xp_", "sp_", "0x",
14 ];
15
16 #[inline]
17 pub fn validate_table_name(name: &str) -> bool {
18 if name.is_empty() || name.len() > 128 {
19 return false;
20 }
21 let bytes = name.as_bytes();
22 let first = bytes[0];
23 if !first.is_ascii_alphabetic() && first != b'_' {
24 return false;
25 }
26 for &b in bytes {
27 if !b.is_ascii_alphanumeric() && b != b'_' {
28 return false;
29 }
30 }
31 let lower = name.to_lowercase();
32 if SQL_KEYWORDS.iter().any(|kw| lower == *kw) {
33 return false;
34 }
35 !DANGEROUS_PATTERNS.iter().any(|p| lower.contains(p))
36 }
37
38 #[inline]
39 pub fn validate_field_name(name: &str) -> bool {
40 if name.is_empty() || name.len() > 256 {
41 return false;
42 }
43 for part in name.split('.') {
44 if part.is_empty() {
45 return false;
46 }
47 let bytes = part.as_bytes();
48 let first = bytes[0];
49 if !first.is_ascii_alphabetic() && first != b'_' {
50 return false;
51 }
52 for &b in bytes {
53 if !b.is_ascii_alphanumeric() && b != b'_' {
54 return false;
55 }
56 }
57 }
58 let lower = name.to_lowercase();
59 if SQL_KEYWORDS.iter().any(|kw| lower == *kw) {
60 return false;
61 }
62 !DANGEROUS_PATTERNS.iter().any(|p| lower.contains(p))
63 }
64
65 #[inline]
66 pub fn escape_string(value: &str) -> String {
67 value
68 .replace('\\', "\\\\")
69 .replace('\'', "''")
70 .replace('\0', "")
71 .replace('\n', "\\n")
72 .replace('\r', "\\r")
73 }
74
75 #[inline]
76 pub fn validate_compare_orator(op: &str) -> bool {
77 matches!(
78 op.to_lowercase().as_str(),
79 "=" | "!=" | "<>" | "<" | ">" | "<=" | ">=" | "like" | "not like" |
80 "in" | "not in" | "notin" | "between" | "is" | "isnot" | "is not" |
81 "set" | "location" | "notlike"
82 )
83 }
84
85 #[cfg(test)]
86 mod tests {
87 use super::*;
88
89 #[test]
90 fn test_validate_table_name_valid() {
91 assert!(validate_table_name("users"));
92 assert!(validate_table_name("user_profiles"));
93 assert!(validate_table_name("_private_table"));
94 assert!(validate_table_name("Table123"));
95 assert!(validate_table_name("batch_insert_perf"));
96 assert!(validate_table_name("my_update_log"));
97 }
98
99 #[test]
100 fn test_validate_table_name_invalid() {
101 assert!(!validate_table_name(""));
102 assert!(!validate_table_name("123table"));
103 assert!(!validate_table_name("user-name"));
104 assert!(!validate_table_name("table.name"));
105 assert!(!validate_table_name("table name"));
106 }
107
108 #[test]
109 fn test_validate_table_name_sql_keywords() {
110 assert!(!validate_table_name("select"));
111 assert!(!validate_table_name("SELECT"));
112 assert!(!validate_table_name("insert"));
113 assert!(!validate_table_name("drop"));
114 assert!(!validate_table_name("union"));
115 }
116
117 #[test]
118 fn test_validate_table_name_dangerous_patterns() {
119 assert!(!validate_table_name("table;drop"));
120 assert!(!validate_table_name("table--comment"));
121 assert!(!validate_table_name("xp_cmdshell"));
122 assert!(!validate_table_name("sp_execute"));
123 }
124
125 #[test]
126 fn test_validate_table_name_length() {
127 let long_name = "a".repeat(128);
128 assert!(validate_table_name(&long_name));
129 let too_long = "a".repeat(129);
130 assert!(!validate_table_name(&too_long));
131 }
132
133 #[test]
134 fn test_validate_field_name_valid() {
135 assert!(validate_field_name("id"));
136 assert!(validate_field_name("user_name"));
137 assert!(validate_field_name("_hidden"));
138 assert!(validate_field_name("table1.field1"));
139 }
140
141 #[test]
142 fn test_validate_field_name_invalid() {
143 assert!(!validate_field_name(""));
144 assert!(!validate_field_name("123field"));
145 assert!(!validate_field_name("field-name"));
146 assert!(!validate_field_name(".field"));
147 assert!(!validate_field_name("field."));
148 }
149
150 #[test]
151 fn test_escape_string() {
152 assert_eq!(escape_string("hello"), "hello");
153 assert_eq!(escape_string("it's"), "it''s");
154 assert_eq!(escape_string("new\nline"), "new\\nline");
155 assert_eq!(escape_string("carriage\rreturn"), "carriage\\rreturn");
156 }
157
158 #[test]
159 fn test_escape_string_sql_injection() {
160 assert_eq!(escape_string("'; DROP TABLE users; --"), "''; DROP TABLE users; --");
161 assert_eq!(escape_string("1' OR '1'='1"), "1'' OR ''1''=''1");
162 }
163
164 #[test]
165 fn test_validate_compare_operator_valid() {
166 assert!(validate_compare_orator("="));
167 assert!(validate_compare_orator("!="));
168 assert!(validate_compare_orator("like"));
169 assert!(validate_compare_orator("LIKE"));
170 assert!(validate_compare_orator("in"));
171 assert!(validate_compare_orator("between"));
172 }
173
174 #[test]
175 fn test_validate_compare_operator_invalid() {
176 assert!(!validate_compare_orator(""));
177 assert!(!validate_compare_orator("invalid"));
178 assert!(!validate_compare_orator("=="));
179 assert!(!validate_compare_orator("&&"));
180 }
181 }
182}
183
184#[inline]
185pub fn quote_identifier(name: &str, mode: &str) -> String {
186 match mode {
187 "mysql" | "sqlite" => format!("`{}`", name),
188 "pgsql" => format!("\"{}\"", name),
189 "mssql" => format!("[{}]", name),
190 _ => name.to_string(),
191 }
192}
193
194#[cfg(feature = "db-sqlite")]
195pub mod sqlite;
196#[cfg(feature = "db-sqlite")]
197pub mod sqlite_transaction;
198#[cfg(feature = "db-mysql")]
199pub mod mysql;
200#[cfg(feature = "db-mysql")]
201pub mod mysql_transaction;
202#[cfg(feature = "db-mssql")]
203pub mod mssql;
204#[cfg(feature = "db-pgsql")]
205pub mod pgsql;
206#[cfg(feature = "db-pgsql")]
207pub mod pgsql_transaction;
208
209pub trait DbMode {
210 fn database_tables(&mut self) -> JsonValue;
212 fn database_create(&mut self, name: &str) -> bool;
214 fn backups(&mut self, _filename: &str) -> bool {
216 false
217 }
218}
219
220#[derive(Debug, Clone)]
221pub struct TableOptions {
222 table_name: String,
223 table_title: String,
224 table_key: String,
225 table_fields: JsonValue,
226 table_unique: Vec<String>,
227 table_index: Vec<Vec<String>>,
228 table_partition: bool,
229 table_partition_columns: JsonValue,
230}
231impl TableOptions {
232 pub fn set_table_name(&mut self, name: &str) {
233 self.table_name = name.to_string()
234 }
235 pub fn set_table_title(&mut self, name: &str) {
236 self.table_title = name.to_string()
237 }
238 pub fn set_table_key(&mut self, name: &str) {
239 self.table_key = name.to_string()
240 }
241 pub fn set_table_fields(&mut self, fields: JsonValue) {
242 self.table_fields = fields;
243 }
244 pub fn set_table_unique(&mut self, unique: Vec<&str>) {
245 self.table_unique = unique.iter().map(|s| s.to_string()).collect();
246 }
247 pub fn set_table_index(&mut self, index: Vec<Vec<&str>>) {
248 self.table_index = index.iter().map(|s| s.iter().map(|s| s.to_string()).collect()).collect();
249 }
250 pub fn set_table_partition(&mut self, index: bool) {
251 self.table_partition = index;
252 }
253 pub fn set_table_partition_columns(&mut self, index: JsonValue) {
254 self.table_partition_columns = index;
255 }
256}
257impl Default for TableOptions {
258 fn default() -> Self {
259 Self {
260 table_name: "".to_string(),
261 table_title: "".to_string(),
262 table_key: "".to_string(),
263 table_fields: JsonValue::Null,
264 table_unique: vec![],
265 table_index: vec![],
266 table_partition: false,
267 table_partition_columns: JsonValue::Null,
268 }
269 }
270}
271pub trait Mode: DbMode {
272 fn table_create(&mut self, options: TableOptions) -> JsonValue;
273 fn table_update(&mut self, options: TableOptions) -> JsonValue;
274 fn table_info(&mut self, table: &str) -> JsonValue;
276 fn table_is_exist(&mut self, name: &str) -> bool;
278 fn table(&mut self, name: &str) -> &mut Self;
280 fn change_table(&mut self, name: &str) -> &mut Self;
282
283 fn autoinc(&mut self) -> &mut Self;
285 fn fetch_sql(&mut self) -> &mut Self;
287 fn order(&mut self, field: &str, by: bool) -> &mut Self;
289 fn group(&mut self, field: &str) -> &mut Self;
291 fn distinct(&mut self) -> &mut Self;
293 fn json(&mut self, field: &str) -> &mut Self;
295 fn location(&mut self, field: &str) -> &mut Self;
297 fn field(&mut self, field: &str) -> &mut Self;
299 fn hidden(&mut self, name: &str) -> &mut Self;
301 fn where_and(&mut self, field: &str, compare: &str, value: JsonValue) -> &mut Self;
303 fn where_or(&mut self, field: &str, compare: &str, value: JsonValue) -> &mut Self;
304
305 fn where_column(&mut self, field_a: &str, compare: &str, field_b: &str) -> &mut Self;
307 fn update_column(&mut self, field_a: &str, compare: &str) -> &mut Self;
309 fn page(&mut self, page: i32, limit: i32) -> &mut Self;
311 fn column(&mut self, field: &str) -> JsonValue;
313 fn count(&mut self) -> JsonValue;
315 fn max(&mut self, field: &str) -> JsonValue;
317 fn min(&mut self, field: &str) -> JsonValue;
319 fn sum(&mut self, field: &str) -> JsonValue;
321 fn avg(&mut self, field: &str) -> JsonValue;
323 fn select(&mut self) -> JsonValue;
325 fn find(&mut self) -> JsonValue;
327 fn value(&mut self, field: &str) -> JsonValue;
329 fn insert(&mut self, data: JsonValue) -> JsonValue;
331 fn insert_all(&mut self, data: JsonValue) -> JsonValue;
333
334 fn update(&mut self, data: JsonValue) -> JsonValue;
336 fn update_all(&mut self, data: JsonValue) -> JsonValue;
338 fn delete(&mut self) -> JsonValue;
340
341 fn transaction(&mut self) -> bool;
343 fn commit(&mut self) -> bool;
345 fn rollback(&mut self) -> bool;
347 fn sql(&mut self, sql: &str) -> Result<JsonValue, String>;
349 fn sql_execute(&mut self, sql: &str) -> Result<JsonValue, String>;
350 fn inc(&mut self, field: &str, num: f64) -> &mut Self;
352 fn dec(&mut self, field: &str, num: f64) -> &mut Self;
354
355 fn buildsql(&mut self) -> String;
357
358 fn join_fields(&mut self, fields: Vec<&str>) -> &mut Self;
359 fn join(&mut self, main_table: &str, main_fields: &str, right_table: &str, right_fields: &str) -> &mut Self;
365
366 fn join_inner(&mut self, table: &str, main_fields: &str, second_fields: &str) -> &mut Self;
372}
373
374#[derive(Clone, Debug)]
375pub struct Params {
376 pub mode: String,
377 pub autoinc: bool,
378 pub table: String,
379 pub where_and: Vec<String>,
380 pub where_or: Vec<String>,
381 pub where_column: String,
382 pub update_column: Vec<String>,
383 pub inc_dec: JsonValue,
384 pub page: i32,
385 pub limit: i32,
386 pub fields: JsonValue,
387 pub top: String,
388 pub top2: String,
389 pub order: JsonValue,
390 pub group: JsonValue,
391 pub distinct: bool,
392 pub json: JsonValue,
393 pub location: JsonValue,
394 pub sql: bool,
395 pub join: Vec<String>,
396 pub join_inner: Vec<String>,
397 pub join_table: String,
398}
399
400impl Params {
401 pub fn default(mode: &str) -> Self {
402 Self {
403 mode: mode.to_string(),
404 autoinc: false,
405 table: "".to_string(),
406 where_and: vec![],
407 where_or: vec![],
408 where_column: "".to_string(),
409 update_column: vec![],
410 inc_dec: object! {},
411 page: -1,
412 limit: 10,
413 fields: object! {},
414 top: String::new(),
415 top2: String::new(),
416 order: object! {},
417 group: object! {},
418 distinct: false,
419 json: object! {},
420 location: object! {},
421 sql: false,
422 join: Vec::new(),
423 join_inner: Vec::new(),
424 join_table: "".to_string(),
425 }
426 }
427 pub fn where_sql(&mut self) -> String {
428 let mut where_and_sql = vec![];
429 let mut where_or_sql = vec![];
430 let mut sql = vec![];
431
432 for item in self.where_or.iter() {
433 where_or_sql.push(item.clone());
434 }
435 if !where_or_sql.is_empty() {
436 sql.push(format!(" ( {} ) ", where_or_sql.join(" OR ")));
437 }
438
439 for item in self.where_and.iter() {
440 where_and_sql.push(item.clone());
441 }
442 if !where_and_sql.is_empty() {
443 sql.push(where_and_sql.join(" AND "));
444 }
445
446 if !self.where_column.is_empty() {
447 sql.push(self.where_column.clone());
448 }
449
450 if !sql.is_empty() {
451 return format!("WHERE {}", sql.join(" AND "));
452 }
453 "".to_string()
454 }
455 pub fn page_limit_sql(&mut self) -> String {
456 if self.page == -1 {
457 return "".to_string();
458 }
459 match self.mode.as_str() {
460 "mysql" => {
461 format!("LIMIT {},{}", self.page * self.limit - self.limit, self.limit)
462 }
463 "sqlite" => {
464 format!("LIMIT {} OFFSET {}", self.limit, self.page * self.limit - self.limit)
465 }
466 _ => "".to_string()
467 }
468 }
469 pub fn fields(&mut self) -> String {
470 let mut fields = vec![];
471 for (_, value) in self.fields.entries() {
472 match self.mode.as_str() {
473 "mssql" => {
474 fields.push(format!("{value}"));
475 }
476 "mysql" => {
477 if let Some(s) = value.as_str() {
478 if DISABLE_FIELD.contains(&s) {
479 fields.push(format!("`{value}`"));
480 } else {
481 fields.push(format!("{value}"));
482 }
483 } else {
484 fields.push(format!("{value}"));
485 }
486 }
487 _ => {
488 fields.push(format!("{value}"));
489 }
490 }
491 }
492 let fields = {
493 if fields.is_empty() {
494 "*".into()
495 } else {
496 fields.join(",")
497 }
498 };
499 match self.mode.as_str() {
500 "mysql" => {
501 fields.to_string()
502 }
503 "sqlite" => {
504 fields.to_string()
505 }
506 "mssql" => {
507 fields.to_string()
508 }
509 _ => fields.to_string()
510 }
511 }
512 pub fn top(&mut self) -> String {
513 match self.mode.as_str() {
514 "mssql" => {
515 let wheres = self.where_sql();
516 if !self.top2.is_empty() {
517 let order = self.order();
518 if order.is_empty() {
519 self.top = format!("(select ROW_NUMBER() OVER(ORDER BY rand()) as ROW,* from {} {}) as ", self.table, wheres);
520 } else {
521 self.top = format!("(select ROW_NUMBER() OVER({}) as ROW,* from {} {}) as ", order, self.table, wheres);
522 }
523 return self.top.to_string();
524 }
525 self.top.to_string()
526 }
527 _ => {
528 "".to_string()
529 }
530 }
531 }
532 pub fn top2(&mut self) -> String {
533 match self.mode.as_str() {
534 "mssql" => {
535 if self.where_and.is_empty() && self.where_or.is_empty() && !self.top2.is_empty() {
536 return format!("where {}", self.top2);
537 }
538 if (!self.where_and.is_empty() || !self.where_or.is_empty()) && !self.top2.is_empty() {
539 return format!("AND {}", self.top2);
540 }
541 self.top2.to_string()
542 }
543 _ => {
544 "".to_string()
545 }
546 }
547 }
548 pub fn table(&mut self) -> String {
549 match self.mode.as_str() {
550 "mssql" => {
551 if !self.top2.is_empty() {
552 return "t".to_string();
553 }
554 self.table.to_string()
555 }
556 _ => {
557 self.table.to_string()
558 }
559 }
560 }
561 pub fn join(&mut self) -> String {
562 match self.mode.as_str() {
563 "mssql" => {
564 self.join.join(" ")
565 }
566 _ => {
567 self.join.join(" ")
568 }
569 }
570 }
571
572 pub fn join_inner(&mut self) -> String {
574 match self.mode.as_str() {
575 "mysql" => {
576 let mut join_inner = "".to_string();
577 for item in self.join_inner.iter() {
578 join_inner = format!("{join_inner} {item}");
579 }
580 join_inner.to_string()
581 }
582 _ => {
583 "".to_string()
584 }
585 }
586 }
587
588
589 pub fn order(&mut self) -> String {
590 let mut sql = vec![];
591 for (field, item) in self.order.entries() {
592 match self.mode.as_str() {
593 "mssql" => {
594 if DISABLE_FIELD.contains(&field) {
595 sql.push(format!("[{field}] {item}"));
596 } else {
597 sql.push(format!("{field} {item}"));
598 }
599 }
600
601 "pgsql" => {
602 if DISABLE_FIELD.contains(&field) {
603 sql.push(format!("\"{field}\" {item}"));
604 } else {
605 sql.push(format!("{field} {item}"));
606 }
607 }
608 _ => {
609 if DISABLE_FIELD.contains(&field) {
610 sql.push(format!("`{field}` {item}"));
611 } else {
612 sql.push(format!("{field} {item}"));
613 }
614 }
615 }
616 }
617 if !sql.is_empty() {
618 return format!("ORDER BY {}", sql.join(","));
619 }
620 "".to_string()
621 }
622 pub fn group(&mut self) -> String {
623 let mut sql = vec![];
624 for (_, field) in self.group.entries() {
625 if DISABLE_FIELD.contains(&&*field.clone().to_string()) {
626 sql.push(format!("`{field}`"));
627 } else if field.to_string().contains(".") {
628 sql.push(format!("{}", field));
629 } else {
630 sql.push(format!("{}.{}", self.table, field));
631 }
632 }
633 if !sql.is_empty() {
634 return format!("GROUP BY {}", sql.join(","));
635 }
636 "".to_string()
637 }
638 pub fn distinct(&self) -> String {
639 if self.distinct {
640 "DISTINCT".to_string()
641 } else {
642 "".to_string()
643 }
644 }
645 pub fn select_sql(&mut self) -> String {
646 format!("SELECT {} {} FROM {} {} {} {} {} {} {} {} {}", self.distinct(), self.fields(), self.top(), self.table(), self.join(), self.join_inner(), self.where_sql(), self.top2(), self.group(), self.order(), self.page_limit_sql())
647 }
648}
649
650#[cfg(test)]
651mod params_tests {
652 use super::*;
653 use json::object;
654
655 #[test]
656 fn test_quote_identifier_mysql() {
657 assert_eq!(quote_identifier("name", "mysql"), "`name`");
658 assert_eq!(quote_identifier("user", "mysql"), "`user`");
659 }
660
661 #[test]
662 fn test_quote_identifier_sqlite() {
663 assert_eq!(quote_identifier("name", "sqlite"), "`name`");
664 assert_eq!(quote_identifier("order", "sqlite"), "`order`");
665 }
666
667 #[test]
668 fn test_quote_identifier_pgsql() {
669 assert_eq!(quote_identifier("name", "pgsql"), "\"name\"");
670 assert_eq!(quote_identifier("select", "pgsql"), "\"select\"");
671 }
672
673 #[test]
674 fn test_quote_identifier_mssql() {
675 assert_eq!(quote_identifier("name", "mssql"), "[name]");
676 assert_eq!(quote_identifier("index", "mssql"), "[index]");
677 }
678
679 #[test]
680 fn test_quote_identifier_unknown() {
681 assert_eq!(quote_identifier("name", "unknown"), "name");
682 assert_eq!(quote_identifier("field", ""), "field");
683 }
684
685 #[test]
686 fn test_table_options_default() {
687 let opts = TableOptions::default();
688 assert_eq!(opts.table_name, "");
689 assert_eq!(opts.table_title, "");
690 assert_eq!(opts.table_key, "");
691 assert!(opts.table_fields.is_null());
692 assert!(opts.table_unique.is_empty());
693 assert!(opts.table_index.is_empty());
694 assert!(!opts.table_partition);
695 assert!(opts.table_partition_columns.is_null());
696 }
697
698 #[test]
699 fn test_table_options_set_table_name() {
700 let mut opts = TableOptions::default();
701 opts.set_table_name("users");
702 assert_eq!(opts.table_name, "users");
703 }
704
705 #[test]
706 fn test_table_options_set_table_title() {
707 let mut opts = TableOptions::default();
708 opts.set_table_title("User Table");
709 assert_eq!(opts.table_title, "User Table");
710 }
711
712 #[test]
713 fn test_table_options_set_table_key() {
714 let mut opts = TableOptions::default();
715 opts.set_table_key("id");
716 assert_eq!(opts.table_key, "id");
717 }
718
719 #[test]
720 fn test_table_options_set_table_fields() {
721 let mut opts = TableOptions::default();
722 let fields = object! { "name" => "varchar", "age" => "int" };
723 opts.set_table_fields(fields);
724 assert_eq!(opts.table_fields["name"], "varchar");
725 assert_eq!(opts.table_fields["age"], "int");
726 }
727
728 #[test]
729 fn test_table_options_set_table_unique() {
730 let mut opts = TableOptions::default();
731 opts.set_table_unique(vec!["email", "username"]);
732 assert_eq!(opts.table_unique, vec!["email".to_string(), "username".to_string()]);
733 }
734
735 #[test]
736 fn test_table_options_set_table_index() {
737 let mut opts = TableOptions::default();
738 opts.set_table_index(vec![vec!["name", "age"], vec!["email"]]);
739 assert_eq!(opts.table_index.len(), 2);
740 assert_eq!(opts.table_index[0], vec!["name".to_string(), "age".to_string()]);
741 assert_eq!(opts.table_index[1], vec!["email".to_string()]);
742 }
743
744 #[test]
745 fn test_table_options_set_table_partition() {
746 let mut opts = TableOptions::default();
747 assert!(!opts.table_partition);
748 opts.set_table_partition(true);
749 assert!(opts.table_partition);
750 }
751
752 #[test]
753 fn test_table_options_set_table_partition_columns() {
754 let mut opts = TableOptions::default();
755 let cols = object! { "col1" => "range", "col2" => "hash" };
756 opts.set_table_partition_columns(cols);
757 assert_eq!(opts.table_partition_columns["col1"], "range");
758 assert_eq!(opts.table_partition_columns["col2"], "hash");
759 }
760
761 #[test]
762 fn test_params_default_mysql() {
763 let p = Params::default("mysql");
764 assert_eq!(p.mode, "mysql");
765 assert!(!p.autoinc);
766 assert_eq!(p.table, "");
767 assert!(p.where_and.is_empty());
768 assert!(p.where_or.is_empty());
769 assert_eq!(p.where_column, "");
770 assert!(p.update_column.is_empty());
771 assert!(p.inc_dec.is_object());
772 assert_eq!(p.page, -1);
773 assert_eq!(p.limit, 10);
774 assert!(p.fields.is_object());
775 assert_eq!(p.top, "");
776 assert_eq!(p.top2, "");
777 assert!(p.order.is_object());
778 assert!(p.group.is_object());
779 assert!(!p.distinct);
780 assert!(p.json.is_object());
781 assert!(p.location.is_object());
782 assert!(!p.sql);
783 assert!(p.join.is_empty());
784 assert!(p.join_inner.is_empty());
785 assert_eq!(p.join_table, "");
786 }
787
788 #[test]
789 fn test_params_default_pgsql() {
790 let p = Params::default("pgsql");
791 assert_eq!(p.mode, "pgsql");
792 assert_eq!(p.page, -1);
793 assert_eq!(p.limit, 10);
794 }
795
796 #[test]
797 fn test_params_default_mssql() {
798 let p = Params::default("mssql");
799 assert_eq!(p.mode, "mssql");
800 }
801
802 #[test]
803 fn test_params_default_sqlite() {
804 let p = Params::default("sqlite");
805 assert_eq!(p.mode, "sqlite");
806 }
807
808 #[test]
809 fn test_where_sql_empty() {
810 let mut p = Params::default("mysql");
811 assert_eq!(p.where_sql(), "");
812 }
813
814 #[test]
815 fn test_where_sql_only_and() {
816 let mut p = Params::default("mysql");
817 p.where_and.push("a = 1".to_string());
818 p.where_and.push("b = 2".to_string());
819 assert_eq!(p.where_sql(), "WHERE a = 1 AND b = 2");
820 }
821
822 #[test]
823 fn test_where_sql_only_or() {
824 let mut p = Params::default("mysql");
825 p.where_or.push("a = 1".to_string());
826 p.where_or.push("b = 2".to_string());
827 assert_eq!(p.where_sql(), "WHERE ( a = 1 OR b = 2 ) ");
828 }
829
830 #[test]
831 fn test_where_sql_and_plus_or() {
832 let mut p = Params::default("mysql");
833 p.where_and.push("c = 3".to_string());
834 p.where_or.push("a = 1".to_string());
835 p.where_or.push("b = 2".to_string());
836 let result = p.where_sql();
837 assert!(result.starts_with("WHERE"));
838 assert!(result.contains("( a = 1 OR b = 2 )"));
839 assert!(result.contains("c = 3"));
840 assert!(result.contains(" AND "));
841 }
842
843 #[test]
844 fn test_where_sql_with_where_column() {
845 let mut p = Params::default("mysql");
846 p.where_column = "x.id = y.id".to_string();
847 assert_eq!(p.where_sql(), "WHERE x.id = y.id");
848 }
849
850 #[test]
851 fn test_where_sql_all_three() {
852 let mut p = Params::default("mysql");
853 p.where_and.push("a = 1".to_string());
854 p.where_or.push("b = 2".to_string());
855 p.where_or.push("c = 3".to_string());
856 p.where_column = "x.id = y.id".to_string();
857 let result = p.where_sql();
858 assert!(result.starts_with("WHERE"));
859 assert!(result.contains("( b = 2 OR c = 3 )"));
860 assert!(result.contains("a = 1"));
861 assert!(result.contains("x.id = y.id"));
862 }
863
864 #[test]
865 fn test_page_limit_sql_default_page_neg1() {
866 let mut p = Params::default("mysql");
867 assert_eq!(p.page_limit_sql(), "");
868 }
869
870 #[test]
871 fn test_page_limit_sql_mysql() {
872 let mut p = Params::default("mysql");
873 p.page = 1;
874 p.limit = 10;
875 assert_eq!(p.page_limit_sql(), "LIMIT 0,10");
876 }
877
878 #[test]
879 fn test_page_limit_sql_mysql_page2() {
880 let mut p = Params::default("mysql");
881 p.page = 2;
882 p.limit = 20;
883 assert_eq!(p.page_limit_sql(), "LIMIT 20,20");
884 }
885
886 #[test]
887 fn test_page_limit_sql_sqlite() {
888 let mut p = Params::default("sqlite");
889 p.page = 1;
890 p.limit = 10;
891 assert_eq!(p.page_limit_sql(), "LIMIT 10 OFFSET 0");
892 }
893
894 #[test]
895 fn test_page_limit_sql_sqlite_page3() {
896 let mut p = Params::default("sqlite");
897 p.page = 3;
898 p.limit = 5;
899 assert_eq!(p.page_limit_sql(), "LIMIT 5 OFFSET 10");
900 }
901
902 #[test]
903 fn test_page_limit_sql_unknown_mode() {
904 let mut p = Params::default("unknown");
905 p.page = 1;
906 p.limit = 10;
907 assert_eq!(p.page_limit_sql(), "");
908 }
909
910 #[test]
911 fn test_fields_empty() {
912 let mut p = Params::default("mysql");
913 assert_eq!(p.fields(), "*");
914 }
915
916 #[test]
917 fn test_fields_mysql_with_disable_field() {
918 let mut p = Params::default("mysql");
919 p.fields = object! { "f1" => "order", "f2" => "name" };
920 let result = p.fields();
921 assert!(result.contains("`order`"));
922 assert!(result.contains("name"));
923 assert!(!result.contains("`name`"));
924 }
925
926 #[test]
927 fn test_fields_mysql_normal() {
928 let mut p = Params::default("mysql");
929 p.fields = object! { "f1" => "id", "f2" => "name" };
930 let result = p.fields();
931 assert!(result.contains("id"));
932 assert!(result.contains("name"));
933 }
934
935 #[test]
936 fn test_fields_mssql() {
937 let mut p = Params::default("mssql");
938 p.fields = object! { "f1" => "id", "f2" => "name" };
939 let result = p.fields();
940 assert!(result.contains("id"));
941 assert!(result.contains("name"));
942 }
943
944 #[test]
945 fn test_fields_other_mode() {
946 let mut p = Params::default("pgsql");
947 p.fields = object! { "f1" => "id", "f2" => "email" };
948 let result = p.fields();
949 assert!(result.contains("id"));
950 assert!(result.contains("email"));
951 }
952
953 #[test]
954 fn test_top_non_mssql() {
955 let mut p = Params::default("mysql");
956 assert_eq!(p.top(), "");
957 }
958
959 #[test]
960 fn test_top_mssql_without_top2() {
961 let mut p = Params::default("mssql");
962 p.table = "users".to_string();
963 assert_eq!(p.top(), "");
964 }
965
966 #[test]
967 fn test_top_mssql_with_top2() {
968 let mut p = Params::default("mssql");
969 p.table = "users".to_string();
970 p.top2 = "ROW BETWEEN 1 AND 10".to_string();
971 let result = p.top();
972 assert!(result.contains("ROW_NUMBER"));
973 assert!(result.contains("users"));
974 assert!(result.contains("as "));
975 }
976
977 #[test]
978 fn test_top_mssql_with_top2_and_order() {
979 let mut p = Params::default("mssql");
980 p.table = "users".to_string();
981 p.top2 = "ROW BETWEEN 1 AND 10".to_string();
982 p.order = object! { "id" => "ASC" };
983 let result = p.top();
984 assert!(result.contains("ROW_NUMBER"));
985 assert!(result.contains("ORDER BY"));
986 assert!(result.contains("id ASC"));
987 }
988
989 #[test]
990 fn test_top2_non_mssql() {
991 let mut p = Params::default("mysql");
992 p.top2 = "something".to_string();
993 assert_eq!(p.top2(), "");
994 }
995
996 #[test]
997 fn test_top2_mssql_no_where_with_top2() {
998 let mut p = Params::default("mssql");
999 p.top2 = "ROW BETWEEN 1 AND 10".to_string();
1000 let result = p.top2();
1001 assert_eq!(result, "where ROW BETWEEN 1 AND 10");
1002 }
1003
1004 #[test]
1005 fn test_top2_mssql_with_where_and_top2() {
1006 let mut p = Params::default("mssql");
1007 p.where_and.push("a = 1".to_string());
1008 p.top2 = "ROW BETWEEN 1 AND 10".to_string();
1009 let result = p.top2();
1010 assert_eq!(result, "AND ROW BETWEEN 1 AND 10");
1011 }
1012
1013 #[test]
1014 fn test_top2_mssql_empty_top2() {
1015 let mut p = Params::default("mssql");
1016 assert_eq!(p.top2(), "");
1017 }
1018
1019 #[test]
1020 fn test_table_mssql_with_top2() {
1021 let mut p = Params::default("mssql");
1022 p.table = "users".to_string();
1023 p.top2 = "ROW BETWEEN 1 AND 10".to_string();
1024 assert_eq!(p.table(), "t");
1025 }
1026
1027 #[test]
1028 fn test_table_mssql_without_top2() {
1029 let mut p = Params::default("mssql");
1030 p.table = "users".to_string();
1031 assert_eq!(p.table(), "users");
1032 }
1033
1034 #[test]
1035 fn test_table_other_modes() {
1036 let mut p = Params::default("mysql");
1037 p.table = "orders".to_string();
1038 assert_eq!(p.table(), "orders");
1039
1040 let mut p2 = Params::default("pgsql");
1041 p2.table = "products".to_string();
1042 assert_eq!(p2.table(), "products");
1043 }
1044
1045 #[test]
1046 fn test_join_empty() {
1047 let mut p = Params::default("mysql");
1048 assert_eq!(p.join(), "");
1049 }
1050
1051 #[test]
1052 fn test_join_with_entries() {
1053 let mut p = Params::default("mysql");
1054 p.join.push("LEFT JOIN orders ON users.id = orders.user_id".to_string());
1055 p.join.push("LEFT JOIN items ON orders.id = items.order_id".to_string());
1056 let result = p.join();
1057 assert!(result.contains("LEFT JOIN orders ON users.id = orders.user_id"));
1058 assert!(result.contains("LEFT JOIN items ON orders.id = items.order_id"));
1059 assert!(result.contains(" "));
1060 }
1061
1062 #[test]
1063 fn test_join_mssql() {
1064 let mut p = Params::default("mssql");
1065 p.join.push("JOIN t2 ON t1.id = t2.fk".to_string());
1066 let result = p.join();
1067 assert_eq!(result, "JOIN t2 ON t1.id = t2.fk");
1068 }
1069
1070 #[test]
1071 fn test_join_inner_empty() {
1072 let mut p = Params::default("mysql");
1073 assert_eq!(p.join_inner(), "");
1074 }
1075
1076 #[test]
1077 fn test_join_inner_mysql() {
1078 let mut p = Params::default("mysql");
1079 p.join_inner.push("INNER JOIN orders ON users.id = orders.uid".to_string());
1080 p.join_inner.push("INNER JOIN items ON orders.id = items.oid".to_string());
1081 let result = p.join_inner();
1082 assert!(result.contains("INNER JOIN orders ON users.id = orders.uid"));
1083 assert!(result.contains("INNER JOIN items ON orders.id = items.oid"));
1084 }
1085
1086 #[test]
1087 fn test_join_inner_non_mysql() {
1088 let mut p = Params::default("pgsql");
1089 p.join_inner.push("INNER JOIN orders ON users.id = orders.uid".to_string());
1090 assert_eq!(p.join_inner(), "");
1091
1092 let mut p2 = Params::default("mssql");
1093 p2.join_inner.push("INNER JOIN orders ON users.id = orders.uid".to_string());
1094 assert_eq!(p2.join_inner(), "");
1095 }
1096
1097 #[test]
1098 fn test_order_empty() {
1099 let mut p = Params::default("mysql");
1100 assert_eq!(p.order(), "");
1101 }
1102
1103 #[test]
1104 fn test_order_with_entries() {
1105 let mut p = Params::default("mysql");
1106 p.order = object! { "id" => "ASC", "name" => "DESC" };
1107 let result = p.order();
1108 assert!(result.starts_with("ORDER BY"));
1109 assert!(result.contains("id ASC"));
1110 assert!(result.contains("name DESC"));
1111 }
1112
1113 #[test]
1114 fn test_order_mysql_disable_field() {
1115 let mut p = Params::default("mysql");
1116 p.order = object! { "order" => "ASC" };
1117 let result = p.order();
1118 assert!(result.contains("`order` ASC"));
1119 }
1120
1121 #[test]
1122 fn test_order_pgsql_disable_field() {
1123 let mut p = Params::default("pgsql");
1124 p.order = object! { "order" => "DESC" };
1125 let result = p.order();
1126 assert!(result.contains("\"order\" DESC"));
1127 }
1128
1129 #[test]
1130 fn test_order_mssql_disable_field() {
1131 let mut p = Params::default("mssql");
1132 p.order = object! { "order" => "ASC" };
1133 let result = p.order();
1134 assert!(result.contains("[order] ASC"));
1135 }
1136
1137 #[test]
1138 fn test_group_empty() {
1139 let mut p = Params::default("mysql");
1140 assert_eq!(p.group(), "");
1141 }
1142
1143 #[test]
1144 fn test_group_with_entries() {
1145 let mut p = Params::default("mysql");
1146 p.table = "users".to_string();
1147 p.group = object! { "g1" => "status" };
1148 let result = p.group();
1149 assert!(result.starts_with("GROUP BY"));
1150 assert!(result.contains("users.status"));
1151 }
1152
1153 #[test]
1154 fn test_group_disable_field() {
1155 let mut p = Params::default("mysql");
1156 p.table = "users".to_string();
1157 p.group = object! { "g1" => "order" };
1158 let result = p.group();
1159 assert!(result.contains("`order`"));
1160 }
1161
1162 #[test]
1163 fn test_group_dotted_field() {
1164 let mut p = Params::default("mysql");
1165 p.table = "users".to_string();
1166 p.group = object! { "g1" => "orders.status" };
1167 let result = p.group();
1168 assert!(result.contains("orders.status"));
1169 assert!(!result.contains("users.orders.status"));
1170 }
1171
1172 #[test]
1173 fn test_distinct_false() {
1174 let p = Params::default("mysql");
1175 assert_eq!(p.distinct(), "");
1176 }
1177
1178 #[test]
1179 fn test_distinct_true() {
1180 let mut p = Params::default("mysql");
1181 p.distinct = true;
1182 assert_eq!(p.distinct(), "DISTINCT");
1183 }
1184
1185 #[test]
1186 fn test_select_sql_basic() {
1187 let mut p = Params::default("mysql");
1188 p.table = "users".to_string();
1189 let result = p.select_sql();
1190 assert!(result.contains("SELECT"));
1191 assert!(result.contains("*"));
1192 assert!(result.contains("FROM"));
1193 assert!(result.contains("users"));
1194 }
1195
1196 #[test]
1197 fn test_select_sql_with_where_and_order() {
1198 let mut p = Params::default("mysql");
1199 p.table = "users".to_string();
1200 p.where_and.push("age > 18".to_string());
1201 p.order = object! { "name" => "ASC" };
1202 p.page = 1;
1203 p.limit = 10;
1204 let result = p.select_sql();
1205 assert!(result.contains("SELECT"));
1206 assert!(result.contains("FROM"));
1207 assert!(result.contains("users"));
1208 assert!(result.contains("WHERE age > 18"));
1209 assert!(result.contains("ORDER BY name ASC"));
1210 assert!(result.contains("LIMIT 0,10"));
1211 }
1212
1213 #[test]
1214 fn test_select_sql_with_distinct_and_group() {
1215 let mut p = Params::default("mysql");
1216 p.table = "orders".to_string();
1217 p.distinct = true;
1218 p.group = object! { "g1" => "status" };
1219 p.fields = object! { "f1" => "status", "f2" => "count" };
1220 let result = p.select_sql();
1221 assert!(result.contains("DISTINCT"));
1222 assert!(result.contains("GROUP BY"));
1223 assert!(result.contains("orders.status"));
1224 }
1225}