Skip to content

Commit

Permalink
Merge pull request #589 from folio-org/MODFQMMGR-613
Browse files Browse the repository at this point in the history
MODFQMMGR-613:Implement Optimized Contains and StartsWith Operators
  • Loading branch information
kjain110 authored Jan 21, 2025
2 parents 001e132 + ffb3862 commit 4b73f69
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 23 deletions.
57 changes: 34 additions & 23 deletions src/main/java/org/folio/fqm/service/FqlToSqlConverterService.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
import org.folio.fql.model.NotEqualsCondition;
import org.folio.fql.model.NotInCondition;
import org.folio.fql.model.RegexCondition;
import org.folio.fql.model.StartsWithCondition;
import org.folio.fql.model.ContainsCondition;
import org.folio.fql.service.FqlService;
import org.folio.fql.service.FqlValidationService;
import org.folio.fqm.exception.FieldNotFoundException;
Expand Down Expand Up @@ -117,29 +119,31 @@ public Condition getSqlCondition(String fqlCriteria, EntityType entityType) {
* Converts the given FQL condition to the corresponding SQL query
*/
public static Condition getSqlCondition(FqlCondition<?> fqlCondition, EntityType entityType) {
final org.jooq.Field<Object> field = fqlCondition instanceof FieldCondition<?> fieldCondition
? field(fieldCondition, entityType)
: null;

// TODO: make this better
// I don't love the casts here, but the only way to avoid that is a massive chain of if-else statements
// with instanceof, and that'd be well over double the size. Hopefully JDK 21 will bring some improvements...
return switch (fqlCondition.getClass().getSimpleName()) {
case "EqualsCondition" -> handleEquals((EqualsCondition) fqlCondition, entityType, field);
case "NotEqualsCondition" -> handleNotEquals((NotEqualsCondition) fqlCondition, entityType, field);
case "InCondition" -> handleIn((InCondition) fqlCondition, entityType, field);
case "NotInCondition" -> handleNotIn((NotInCondition) fqlCondition, entityType, field);
case "GreaterThanCondition" -> handleGreaterThan((GreaterThanCondition) fqlCondition, entityType, field);
case "LessThanCondition" -> handleLessThan((LessThanCondition) fqlCondition, entityType, field);
case "AndCondition" -> handleAnd((AndCondition) fqlCondition, entityType);
case "RegexCondition" -> handleRegEx((RegexCondition) fqlCondition, entityType, field);
case "ContainsAllCondition" -> handleContainsAll((ContainsAllCondition) fqlCondition, entityType, field);
case "NotContainsAllCondition" -> handleNotContainsAll((NotContainsAllCondition) fqlCondition, entityType, field);
case "ContainsAnyCondition" -> handleContainsAny((ContainsAnyCondition) fqlCondition, entityType, field);
case "NotContainsAnyCondition" -> handleNotContainsAny((NotContainsAnyCondition) fqlCondition, entityType, field);
case "EmptyCondition" -> handleEmpty((EmptyCondition) fqlCondition, entityType, field);
default -> falseCondition();
};
if (fqlCondition instanceof FieldCondition<?> fieldCondition) {
final org.jooq.Field<Object> field = field(fieldCondition, entityType);
return switch (fqlCondition.getClass().getSimpleName()) {
case "EqualsCondition" -> handleEquals((EqualsCondition) fqlCondition, entityType, field);
case "NotEqualsCondition" -> handleNotEquals((NotEqualsCondition) fqlCondition, entityType, field);
case "InCondition" -> handleIn((InCondition) fqlCondition, entityType, field);
case "NotInCondition" -> handleNotIn((NotInCondition) fqlCondition, entityType, field);
case "GreaterThanCondition" -> handleGreaterThan((GreaterThanCondition) fqlCondition, entityType, field);
case "LessThanCondition" -> handleLessThan((LessThanCondition) fqlCondition, entityType, field);
case "RegexCondition" -> handleRegEx((RegexCondition) fqlCondition, entityType, field);
case "ContainsAllCondition" -> handleContainsAll((ContainsAllCondition) fqlCondition, entityType, field);
case "NotContainsAllCondition" -> handleNotContainsAll((NotContainsAllCondition) fqlCondition, entityType, field);
case "ContainsAnyCondition" -> handleContainsAny((ContainsAnyCondition) fqlCondition, entityType, field);
case "NotContainsAnyCondition" -> handleNotContainsAny((NotContainsAnyCondition) fqlCondition, entityType, field);
case "StartsWithCondition" -> handleStartsWith((StartsWithCondition) fqlCondition, entityType, field);
case "ContainsCondition" -> handleContains((ContainsCondition) fqlCondition, entityType, field);
case "EmptyCondition" -> handleEmpty((EmptyCondition) fqlCondition, entityType, field);
default -> falseCondition();
};
} else {
return switch (fqlCondition.getClass().getSimpleName()) {
case "AndCondition" -> handleAnd((AndCondition) fqlCondition, entityType);
default -> falseCondition();
};
}
}

private static Condition handleEquals(EqualsCondition equalsCondition, EntityType entityType, org.jooq.Field<Object> field) {
Expand Down Expand Up @@ -395,6 +399,13 @@ private static Condition handleNotContainsAny(NotContainsAnyCondition notContain
}
}

private static Condition handleContains(ContainsCondition containsCondition, EntityType entityType, org.jooq.Field<Object> field) {
return field.contains(valueField(containsCondition.value(), containsCondition, entityType));
}

private static Condition handleStartsWith(StartsWithCondition startsWithCondition, EntityType entityType, org.jooq.Field<Object> field) {
return field.startsWith(valueField(startsWithCondition.value(), startsWithCondition, entityType));
}
private static Condition handleEmpty(EmptyCondition emptyCondition, EntityType entityType, org.jooq.Field<Object> field) {
String fieldType = getFieldDataType(entityType, emptyCondition);
boolean isEmpty = Boolean.TRUE.equals(emptyCondition.value());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,18 @@ static List<Arguments> jooqConditionsSource() {
{"fieldWithAValueFunction": {"$regex": "some_text"}}""",
condition("{0} ~* {1}", field("fieldWithAValueFunction"), field("upper(:value)", String.class, param("value", "some_text")))
),
Arguments.of(
"starts_with",
"""
{"field1": {"$starts_with": "prefix"}}""",
field("field1").startsWith("prefix")
),
Arguments.of(
"contains",
"""
{"field1": {"$contains": "substring"}}""",
field("field1").contains("substring")
),
Arguments.of(
"in list",
"""
Expand Down

0 comments on commit 4b73f69

Please sign in to comment.