Skip to content

Commit

Permalink
fix: add case-insensitive support in advanced Json filtering
Browse files Browse the repository at this point in the history
  • Loading branch information
lubosmato authored and Luboš Matejčík committed Aug 9, 2024
1 parent e1242e1 commit 4c75214
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,18 @@ mod json_filters {
);
}

// QueryMode::Insensitive
let res = run_query!(
runner,
jsonq(&runner, r#"string_contains: "Oo", mode: "insensitive" "#, None)
);
insta::allow_duplicates! {
insta::assert_snapshot!(
res,
@r###"{"data":{"findManyTestModel":[{"id":1},{"id":2}]}}"###
);
}

// NOT
let res = run_query!(runner, not_jsonq(&runner, r#"string_contains: "ab" "#, None));
insta::allow_duplicates! {
Expand Down Expand Up @@ -556,6 +568,18 @@ mod json_filters {
);
}

// QueryMode::insensitive
let res = run_query!(
runner,
jsonq(&runner, r#"string_starts_with: "FoO", mode: "insensitive" "#, None)
);
insta::allow_duplicates! {
insta::assert_snapshot!(
res,
@r###"{"data":{"findManyTestModel":[{"id":1},{"id":2}]}}"###
);
}

// NOT string_starts_with
let res = run_query!(runner, not_jsonq(&runner, r#"string_starts_with: "ab" "#, None));
insta::allow_duplicates! {
Expand Down Expand Up @@ -595,6 +619,18 @@ mod json_filters {
);
}

// QueryMode::insensitive
let res = run_query!(
runner,
jsonq(&runner, r#"string_ends_with: "oO", mode: "insensitive" "#, None)
);
insta::allow_duplicates! {
insta::assert_snapshot!(
res,
@r###"{"data":{"findManyTestModel":[{"id":1}]}}"###
);
}

// NOT
let res = run_query!(runner, not_jsonq(&runner, r#"string_ends_with: "oo" "#, None));
insta::allow_duplicates! {
Expand Down
93 changes: 72 additions & 21 deletions query-engine/connectors/sql-query-connector/src/filter/visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -759,13 +759,19 @@ fn convert_json_filter(

let condition: Expression = match *condition {
ScalarCondition::Contains(value) => {
(expr_json, expr_string).json_contains(field, value, target_type.unwrap(), reverse, alias, ctx)
}
ScalarCondition::StartsWith(value) => {
(expr_json, expr_string).json_starts_with(field, value, target_type.unwrap(), reverse, alias, ctx)
(expr_json, expr_string).json_contains(field, value, target_type.unwrap(), query_mode, reverse, alias, ctx)
}
ScalarCondition::StartsWith(value) => (expr_json, expr_string).json_starts_with(
field,
value,
target_type.unwrap(),
query_mode,
reverse,
alias,
ctx,
),
ScalarCondition::EndsWith(value) => {
(expr_json, expr_string).json_ends_with(field, value, target_type.unwrap(), reverse, alias, ctx)
(expr_json, expr_string).json_ends_with(field, value, target_type.unwrap(), query_mode, reverse, alias, ctx)
}
ScalarCondition::GreaterThan(value) => {
let gt = expr_json
Expand Down Expand Up @@ -1225,6 +1231,7 @@ trait JsonFilterExt {
field: &ScalarFieldRef,
value: ConditionValue,
target_type: JsonTargetType,
query_mode: QueryMode,
reverse: bool,
alias: Option<Alias>,
ctx: &Context<'_>,
Expand All @@ -1235,6 +1242,7 @@ trait JsonFilterExt {
field: &ScalarFieldRef,
value: ConditionValue,
target_type: JsonTargetType,
query_mode: QueryMode,
reverse: bool,
alias: Option<Alias>,
ctx: &Context<'_>,
Expand All @@ -1245,6 +1253,7 @@ trait JsonFilterExt {
field: &ScalarFieldRef,
value: ConditionValue,
target_type: JsonTargetType,
query_mode: QueryMode,
reverse: bool,
alias: Option<Alias>,
ctx: &Context<'_>,
Expand All @@ -1257,6 +1266,7 @@ impl JsonFilterExt for (Expression<'static>, Expression<'static>) {
field: &ScalarFieldRef,
value: ConditionValue,
target_type: JsonTargetType,
query_mode: QueryMode,
reverse: bool,
alias: Option<Alias>,
ctx: &Context<'_>,
Expand All @@ -1266,7 +1276,10 @@ impl JsonFilterExt for (Expression<'static>, Expression<'static>) {
match (value, target_type) {
// string_contains (value)
(ConditionValue::Value(value), JsonTargetType::String) => {
let contains = expr_string.like(format!("%{value}%"));
let contains = match query_mode {
QueryMode::Default => expr_string.like(format!("%{value}%")),
QueryMode::Insensitive => expr_string.compare_raw("ILIKE", format!("%{value}%")),
};

if reverse {
contains.or(expr_json.json_type_not_equals(JsonType::String)).into()
Expand All @@ -1286,11 +1299,21 @@ impl JsonFilterExt for (Expression<'static>, Expression<'static>) {
}
// string_contains (ref)
(ConditionValue::FieldRef(field_ref), JsonTargetType::String) => {
let contains = expr_string.like(quaint::ast::concat::<'_, Expression<'_>>(vec![
Value::text("%").raw().into(),
field_ref.aliased_col(alias, ctx).into(),
Value::text("%").raw().into(),
]));
let contains = match query_mode {
QueryMode::Default => expr_string.like(quaint::ast::concat::<'_, Expression<'_>>(vec![
Value::text("%").raw().into(),
field_ref.aliased_col(alias, ctx).into(),
Value::text("%").raw().into(),
])),
QueryMode::Insensitive => expr_string.compare_raw(
"ILIKE",
quaint::ast::concat::<'_, Expression<'_>>(vec![
Value::text("%").raw().into(),
field_ref.aliased_col(alias, ctx).into(),
Value::text("%").raw().into(),
]),
),
};

if reverse {
contains.or(expr_json.json_type_not_equals(JsonType::String)).into()
Expand All @@ -1316,15 +1339,20 @@ impl JsonFilterExt for (Expression<'static>, Expression<'static>) {
field: &ScalarFieldRef,
value: ConditionValue,
target_type: JsonTargetType,
query_mode: QueryMode,
reverse: bool,
alias: Option<Alias>,
ctx: &Context<'_>,
) -> Expression<'static> {
// TODO: add insensitive mode
let (expr_json, expr_string) = self;
match (value, target_type) {
// string_starts_with (value)
(ConditionValue::Value(value), JsonTargetType::String) => {
let starts_with = expr_string.like(format!("{value}%"));
let starts_with = match query_mode {
QueryMode::Default => expr_string.like(format!("{value}%")),
QueryMode::Insensitive => expr_string.compare_raw("ILIKE", format!("{value}%")),
};

if reverse {
starts_with.or(expr_json.json_type_not_equals(JsonType::String)).into()
Expand All @@ -1344,10 +1372,19 @@ impl JsonFilterExt for (Expression<'static>, Expression<'static>) {
}
// string_starts_with (ref)
(ConditionValue::FieldRef(field_ref), JsonTargetType::String) => {
let starts_with = expr_string.like(quaint::ast::concat::<'_, Expression<'_>>(vec![
field_ref.aliased_col(alias, ctx).into(),
Value::text("%").raw().into(),
]));
let starts_with = match query_mode {
QueryMode::Default => expr_string.like(quaint::ast::concat::<'_, Expression<'_>>(vec![
field_ref.aliased_col(alias, ctx).into(),
Value::text("%").raw().into(),
])),
QueryMode::Insensitive => expr_string.compare_raw(
"ILIKE",
quaint::ast::concat::<'_, Expression<'_>>(vec![
field_ref.aliased_col(alias, ctx).into(),
Value::text("%").raw().into(),
]),
),
};

if reverse {
starts_with.or(expr_json.json_type_not_equals(JsonType::String)).into()
Expand Down Expand Up @@ -1375,16 +1412,21 @@ impl JsonFilterExt for (Expression<'static>, Expression<'static>) {
field: &ScalarFieldRef,
value: ConditionValue,
target_type: JsonTargetType,
query_mode: QueryMode,
reverse: bool,
alias: Option<Alias>,
ctx: &Context<'_>,
) -> Expression<'static> {
// TODO: add case insensitive
let (expr_json, expr_string) = self;

match (value, target_type) {
// string_ends_with (value)
(ConditionValue::Value(value), JsonTargetType::String) => {
let ends_with = expr_string.like(format!("%{value}"));
let ends_with = match query_mode {
QueryMode::Default => expr_string.like(format!("%{value}")),
QueryMode::Insensitive => expr_string.compare_raw("ILIKE", format!("%{value}")),
};

if reverse {
ends_with.or(expr_json.json_type_not_equals(JsonType::String)).into()
Expand All @@ -1404,10 +1446,19 @@ impl JsonFilterExt for (Expression<'static>, Expression<'static>) {
}
// string_ends_with (ref)
(ConditionValue::FieldRef(field_ref), JsonTargetType::String) => {
let ends_with = expr_string.like(quaint::ast::concat::<'_, Expression<'_>>(vec![
Value::text("%").raw().into(),
field_ref.aliased_col(alias, ctx).into(),
]));
let ends_with = match query_mode {
QueryMode::Default => expr_string.like(quaint::ast::concat::<'_, Expression<'_>>(vec![
Value::text("%").raw().into(),
field_ref.aliased_col(alias, ctx).into(),
])),
QueryMode::Insensitive => expr_string.compare_raw(
"ILIKE",
quaint::ast::concat::<'_, Expression<'_>>(vec![
Value::text("%").raw().into(),
field_ref.aliased_col(alias, ctx).into(),
]),
),
};

if reverse {
ends_with.or(expr_json.json_type_not_equals(JsonType::String)).into()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -443,9 +443,16 @@ fn json_filters(ctx: &'_ QuerySchema) -> impl Iterator<Item = InputField<'_>> {
};
let string_with_field_ref_input = InputType::string().with_field_ref_input();
let json_with_field_ref_input = InputType::json().with_field_ref_input();
let mode_enum_type = InputType::enum_type(query_mode_enum()).with_field_ref_input();

vec![
simple_input_field(filters::PATH, path_type, None).optional(),
input_field(
filters::MODE,
mode_enum_type,
Some(DefaultKind::Single(PrismaValue::Enum(filters::DEFAULT.to_owned()))),
)
.optional(),
input_field(filters::STRING_CONTAINS, string_with_field_ref_input.clone(), None).optional(),
input_field(filters::STRING_STARTS_WITH, string_with_field_ref_input.clone(), None).optional(),
input_field(filters::STRING_ENDS_WITH, string_with_field_ref_input, None).optional(),
Expand Down

0 comments on commit 4c75214

Please sign in to comment.