Skip to content

Commit

Permalink
Support MongoDB JavaScript $regex pattern
Browse files Browse the repository at this point in the history
  • Loading branch information
loicmathieu committed May 12, 2020
1 parent 048c674 commit b76463c
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 3 deletions.
2 changes: 1 addition & 1 deletion docs/src/main/asciidoc/mongodb-panache.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,7 @@ MongoDB with Panache will then map it to a MongoDB native query.
If your query does not start with `{`, we will consider it a PanacheQL query:

- `<singlePropertyName>` (and single parameter) which will expand to `{'singleColumnName': '?1'}`
- `<query>` will expand to `{<query>}` where we will map the PanacheQL query to MongoDB native query form. We support the following operators that will be mapped to the corresponding MongoDB operators: 'and', 'or' ( mixing 'and' and 'or' is not currently supported), '=', '>', '>=', '<', '<=', '!=', 'is null', 'is not null', and 'like' that is mapped to the MongoDB `$regex` operator.
- `<query>` will expand to `{<query>}` where we will map the PanacheQL query to MongoDB native query form. We support the following operators that will be mapped to the corresponding MongoDB operators: 'and', 'or' ( mixing 'and' and 'or' is not currently supported), '=', '>', '>=', '<', '<=', '!=', 'is null', 'is not null', and 'like' that is mapped to the MongoDB `$regex` operator (both String and JavaScript patterns are supported).

Here are some query examples:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,13 @@ public String visitLessThanOrEqualPredicate(HqlParser.LessThanOrEqualPredicateCo

@Override
public String visitLikePredicate(HqlParser.LikePredicateContext ctx) {
return ctx.expression(0).accept(this) + ":{'$regex':" + ctx.expression(1).accept(this) + "}";
String parameter = ctx.expression(1).accept(this);
if (parameter.indexOf('/') == 1 && parameter.lastIndexOf('/') > 1) {
// In case we have something like '/.*/.*' we are in a JavaScript regex so we must unescape the parameter.
// We do this here instead of inside visitParameterExpression to avoid unescaping for non-regex parameters.
parameter = parameter.substring(1, parameter.length() - 1);
}
return ctx.expression(0).accept(this) + ":{'$regex':" + parameter + "}";
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@
* They will all generates the same query : {"field": "value"}.
* </li>
* <li>We support the following query operators: 'and', 'or' ( mixing 'and' and 'or' is not currently supported), '=',
* '>', '>=', '<', '<=', '!=', 'is null', 'is not null', and 'like' that is mapped to the MongoDB `$regex` operator.</li>
* '>', '>=', '<', '<=', '!=', 'is null', 'is not null', and 'like' that is mapped to the MongoDB `$regex` operator
* (both String and JavaScript patterns are supported).</li>
* <li>field replacement is supported based on the value of the <code>@BsonProperty</code> annotations</li>
* </ul>
* </p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,13 @@ public Response testImperativeEntity() {
Assertions.assertEquals(0, TestImperativeEntity.list("category = :category",
Parameters.with("category", null)).size());

// regex
TestImperativeEntity entityWithUpperCase = new TestImperativeEntity("title11", "upperCaseCategory", "desc");
entityWithUpperCase.persist();
Assertions.assertEquals(1, TestImperativeEntity.list("category like ?1", "upperCase.*").size());
Assertions.assertEquals(1, TestImperativeEntity.list("category like ?1", "/uppercase.*/i").size());
entityWithUpperCase.delete();

// sort
TestImperativeEntity entityA = new TestImperativeEntity("aaa", "aaa", "aaa");
entityA.persist();
Expand Down Expand Up @@ -187,6 +194,13 @@ public Response testImperativeRepository() {
Assertions.assertEquals(0, testImperativeRepository.list("category = :category",
Parameters.with("category", null)).size());

// regex
TestImperativeEntity entityWithUpperCase = new TestImperativeEntity("title11", "upperCaseCategory", "desc");
testImperativeRepository.persist(entityWithUpperCase);
Assertions.assertEquals(1, testImperativeRepository.list("category like ?1", "upperCase.*").size());
Assertions.assertEquals(1, testImperativeRepository.list("category like ?1", "/uppercase.*/i").size());
testImperativeRepository.delete(entityWithUpperCase);

// sort
TestImperativeEntity entityA = new TestImperativeEntity("aaa", "aaa", "aaa");
testImperativeRepository.persist(entityA);
Expand Down Expand Up @@ -374,6 +388,15 @@ public Response testReactiveEntity() {
Assertions.assertEquals(0, TestReactiveEntity.list("category = :category",
Parameters.with("category", null)).await().indefinitely().size());

// regex
TestReactiveEntity entityWithUpperCase = new TestReactiveEntity("title11", "upperCaseCategory", "desc");
entityWithUpperCase.persist().await().indefinitely();
Assertions.assertEquals(1, TestReactiveEntity.list("category like ?1", "upperCase.*")
.await().indefinitely().size());
Assertions.assertEquals(1, TestReactiveEntity.list("category like ?1", "/uppercase.*/i")
.await().indefinitely().size());
entityWithUpperCase.delete();

// sort
TestReactiveEntity entityA = new TestReactiveEntity("aaa", "aaa", "aaa");
entityA.persist().await().indefinitely();
Expand Down Expand Up @@ -495,6 +518,15 @@ public Response testReactiveRepository() {
Assertions.assertEquals(0, testReactiveRepository.list("category = :category",
Parameters.with("category", null)).await().indefinitely().size());

// regex
TestReactiveEntity entityWithUpperCase = new TestReactiveEntity("title11", "upperCaseCategory", "desc");
testReactiveRepository.persist(entityWithUpperCase).await().indefinitely();
Assertions.assertEquals(1, testReactiveRepository.list("category like ?1", "upperCase.*")
.await().indefinitely().size());
Assertions.assertEquals(1, testReactiveRepository.list("category like ?1", "/uppercase.*/i")
.await().indefinitely().size());
testReactiveRepository.delete(entityWithUpperCase);

// sort
TestReactiveEntity entityA = new TestReactiveEntity("aaa", "aaa", "aaa");
testReactiveRepository.persist(entityA).await().indefinitely();
Expand Down

0 comments on commit b76463c

Please sign in to comment.