|
| 1 | +use std::borrow::Cow; |
1 | 2 | use crate::{
|
2 | 3 | ast::*,
|
3 | 4 | visitor::{self, Visitor},
|
@@ -416,6 +417,102 @@ impl<'a> Visitor<'a> for Postgres<'a> {
|
416 | 417 |
|
417 | 418 | Ok(())
|
418 | 419 | }
|
| 420 | + |
| 421 | + fn visit_like(&mut self, left: Expression<'a>, right: Cow<str>) -> visitor::Result { |
| 422 | + let need_cast = matches!(&left.kind, ExpressionKind::Column(_)); |
| 423 | + self.visit_expression(left)?; |
| 424 | + |
| 425 | + // NOTE: Pg is strongly typed, LIKE comparisons are only between strings. |
| 426 | + // to avoid problems with types without implicit casting we explicitly cast to text |
| 427 | + if need_cast { |
| 428 | + self.write("::text")?; |
| 429 | + } |
| 430 | + |
| 431 | + self.add_parameter(Value::text(format!( |
| 432 | + "{}{}{}", |
| 433 | + Self::C_WILDCARD, |
| 434 | + right, |
| 435 | + Self::C_WILDCARD |
| 436 | + ))); |
| 437 | + |
| 438 | + self.write(" LIKE ")?; |
| 439 | + self.parameter_substitution() |
| 440 | + } |
| 441 | + |
| 442 | + fn visit_not_like(&mut self, left: Expression<'a>, right: Cow<str>) -> visitor::Result { |
| 443 | + let need_cast = matches!(&left.kind, ExpressionKind::Column(_)); |
| 444 | + self.visit_expression(left)?; |
| 445 | + |
| 446 | + if need_cast { |
| 447 | + self.write("::text")?; |
| 448 | + } |
| 449 | + |
| 450 | + self.add_parameter(Value::text(format!( |
| 451 | + "{}{}{}", |
| 452 | + Self::C_WILDCARD, |
| 453 | + right, |
| 454 | + Self::C_WILDCARD |
| 455 | + ))); |
| 456 | + |
| 457 | + self.write(" NOT LIKE ")?; |
| 458 | + self.parameter_substitution() |
| 459 | + } |
| 460 | + |
| 461 | + fn visit_begins_with(&mut self, left: Expression<'a>, right: Cow<str>) -> visitor::Result { |
| 462 | + let need_cast = matches!(&left.kind, ExpressionKind::Column(_)); |
| 463 | + self.visit_expression(left)?; |
| 464 | + |
| 465 | + if need_cast { |
| 466 | + self.write("::text")?; |
| 467 | + } |
| 468 | + |
| 469 | + self.add_parameter(Value::text(format!("{}{}", right, Self::C_WILDCARD))); |
| 470 | + |
| 471 | + self.write(" LIKE ")?; |
| 472 | + self.parameter_substitution() |
| 473 | + } |
| 474 | + |
| 475 | + fn visit_not_begins_with(&mut self, left: Expression<'a>, right: Cow<str>) -> visitor::Result { |
| 476 | + let need_cast = matches!(&left.kind, ExpressionKind::Column(_)); |
| 477 | + self.visit_expression(left)?; |
| 478 | + |
| 479 | + if need_cast { |
| 480 | + self.write("::text")?; |
| 481 | + } |
| 482 | + |
| 483 | + self.add_parameter(Value::text(format!("{}{}", right, Self::C_WILDCARD))); |
| 484 | + |
| 485 | + self.write(" NOT LIKE ")?; |
| 486 | + self.parameter_substitution() |
| 487 | + } |
| 488 | + |
| 489 | + fn visit_ends_with(&mut self, left: Expression<'a>, right: Cow<str>) -> visitor::Result { |
| 490 | + let need_cast = matches!(&left.kind, ExpressionKind::Column(_)); |
| 491 | + self.visit_expression(left)?; |
| 492 | + |
| 493 | + if need_cast { |
| 494 | + self.write("::text")?; |
| 495 | + } |
| 496 | + |
| 497 | + self.add_parameter(Value::text(format!("{}{}", Self::C_WILDCARD, right,))); |
| 498 | + |
| 499 | + self.write(" LIKE ")?; |
| 500 | + self.parameter_substitution() |
| 501 | + } |
| 502 | + |
| 503 | + fn visit_not_ends_with(&mut self, left: Expression<'a>, right: Cow<str>) -> visitor::Result { |
| 504 | + let need_cast = matches!(&left.kind, ExpressionKind::Column(_)); |
| 505 | + self.visit_expression(left)?; |
| 506 | + |
| 507 | + if need_cast { |
| 508 | + self.write("::text")?; |
| 509 | + } |
| 510 | + |
| 511 | + self.add_parameter(Value::text(format!("{}{}", Self::C_WILDCARD, right,))); |
| 512 | + |
| 513 | + self.write(" NOT LIKE ")?; |
| 514 | + self.parameter_substitution() |
| 515 | + } |
419 | 516 | }
|
420 | 517 |
|
421 | 518 | #[cfg(test)]
|
@@ -813,6 +910,102 @@ mod tests {
|
813 | 910 | assert_eq!(r#"SELECT "foo".* FROM "foo" WHERE "bar" ILIKE $1"#, sql);
|
814 | 911 | }
|
815 | 912 |
|
| 913 | + #[test] |
| 914 | + fn test_like_cast_to_string() { |
| 915 | + let expected = expected_values( |
| 916 | + r#"SELECT "test".* FROM "test" WHERE "jsonField"::text LIKE $1"#, |
| 917 | + vec!["%foo%"], |
| 918 | + ); |
| 919 | + |
| 920 | + let query = |
| 921 | + Select::from_table("test") |
| 922 | + .so_that(Column::from("jsonField").like("foo")); |
| 923 | + let (sql, params) = Postgres::build(query).unwrap(); |
| 924 | + |
| 925 | + assert_eq!(expected.0, sql); |
| 926 | + assert_eq!(expected.1, params); |
| 927 | + } |
| 928 | + |
| 929 | + #[test] |
| 930 | + fn test_not_like_cast_to_string() { |
| 931 | + let expected = expected_values( |
| 932 | + r#"SELECT "test".* FROM "test" WHERE "jsonField"::text NOT LIKE $1"#, |
| 933 | + vec!["%foo%"], |
| 934 | + ); |
| 935 | + |
| 936 | + let query = |
| 937 | + Select::from_table("test") |
| 938 | + .so_that(Column::from("jsonField").not_like("foo")); |
| 939 | + let (sql, params) = Postgres::build(query).unwrap(); |
| 940 | + |
| 941 | + assert_eq!(expected.0, sql); |
| 942 | + assert_eq!(expected.1, params); |
| 943 | + } |
| 944 | + |
| 945 | + #[test] |
| 946 | + fn test_begins_with_cast_to_string() { |
| 947 | + let expected = expected_values( |
| 948 | + r#"SELECT "test".* FROM "test" WHERE "jsonField"::text LIKE $1"#, |
| 949 | + vec!["foo%"], |
| 950 | + ); |
| 951 | + |
| 952 | + let query = |
| 953 | + Select::from_table("test") |
| 954 | + .so_that(Column::from("jsonField").begins_with("foo")); |
| 955 | + let (sql, params) = Postgres::build(query).unwrap(); |
| 956 | + |
| 957 | + assert_eq!(expected.0, sql); |
| 958 | + assert_eq!(expected.1, params); |
| 959 | + } |
| 960 | + |
| 961 | + #[test] |
| 962 | + fn test_not_begins_with_cast_to_string() { |
| 963 | + let expected = expected_values( |
| 964 | + r#"SELECT "test".* FROM "test" WHERE "jsonField"::text NOT LIKE $1"#, |
| 965 | + vec!["foo%"], |
| 966 | + ); |
| 967 | + |
| 968 | + let query = |
| 969 | + Select::from_table("test") |
| 970 | + .so_that(Column::from("jsonField").not_begins_with("foo")); |
| 971 | + let (sql, params) = Postgres::build(query).unwrap(); |
| 972 | + |
| 973 | + assert_eq!(expected.0, sql); |
| 974 | + assert_eq!(expected.1, params); |
| 975 | + } |
| 976 | + |
| 977 | + #[test] |
| 978 | + fn test_ends_with_cast_to_string() { |
| 979 | + let expected = expected_values( |
| 980 | + r#"SELECT "test".* FROM "test" WHERE "jsonField"::text LIKE $1"#, |
| 981 | + vec!["%foo"], |
| 982 | + ); |
| 983 | + |
| 984 | + let query = |
| 985 | + Select::from_table("test") |
| 986 | + .so_that(Column::from("jsonField").ends_into("foo")); |
| 987 | + let (sql, params) = Postgres::build(query).unwrap(); |
| 988 | + |
| 989 | + assert_eq!(expected.0, sql); |
| 990 | + assert_eq!(expected.1, params); |
| 991 | + } |
| 992 | + |
| 993 | + #[test] |
| 994 | + fn test_not_ends_with_cast_to_string() { |
| 995 | + let expected = expected_values( |
| 996 | + r#"SELECT "test".* FROM "test" WHERE "jsonField"::text NOT LIKE $1"#, |
| 997 | + vec!["%foo"], |
| 998 | + ); |
| 999 | + |
| 1000 | + let query = |
| 1001 | + Select::from_table("test") |
| 1002 | + .so_that(Column::from("jsonField").not_ends_into("foo")); |
| 1003 | + let (sql, params) = Postgres::build(query).unwrap(); |
| 1004 | + |
| 1005 | + assert_eq!(expected.0, sql); |
| 1006 | + assert_eq!(expected.1, params); |
| 1007 | + } |
| 1008 | + |
816 | 1009 | #[test]
|
817 | 1010 | fn test_default_insert() {
|
818 | 1011 | let insert = Insert::single_into("foo")
|
|
0 commit comments