diff --git a/docs/src/main/asciidoc/mongodb-panache.adoc b/docs/src/main/asciidoc/mongodb-panache.adoc index 9268ef988f2e3c..6395f24a1a6b3f 100644 --- a/docs/src/main/asciidoc/mongodb-panache.adoc +++ b/docs/src/main/asciidoc/mongodb-panache.adoc @@ -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: - `` (and single parameter) which will expand to `{'singleColumnName': '?1'}` -- `` will expand to `{}` 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. +- `` will expand to `{}` 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: diff --git a/extensions/panache/mongodb-panache/runtime/src/main/java/io/quarkus/mongodb/panache/binder/MongoParserVisitor.java b/extensions/panache/mongodb-panache/runtime/src/main/java/io/quarkus/mongodb/panache/binder/MongoParserVisitor.java index a21722ddeddf8b..abf15d6df17dae 100644 --- a/extensions/panache/mongodb-panache/runtime/src/main/java/io/quarkus/mongodb/panache/binder/MongoParserVisitor.java +++ b/extensions/panache/mongodb-panache/runtime/src/main/java/io/quarkus/mongodb/panache/binder/MongoParserVisitor.java @@ -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 diff --git a/extensions/panache/mongodb-panache/runtime/src/main/java/io/quarkus/mongodb/panache/package-info.java b/extensions/panache/mongodb-panache/runtime/src/main/java/io/quarkus/mongodb/panache/package-info.java index ac83e270bf516d..fb1e0b5809024f 100644 --- a/extensions/panache/mongodb-panache/runtime/src/main/java/io/quarkus/mongodb/panache/package-info.java +++ b/extensions/panache/mongodb-panache/runtime/src/main/java/io/quarkus/mongodb/panache/package-info.java @@ -79,7 +79,8 @@ * They will all generates the same query : {"field": "value"}. * *
  • 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.
  • + * '>', '>=', '<', '<=', '!=', 'is null', 'is not null', and 'like' that is mapped to the MongoDB `$regex` operator + * (both String and JavaScript patterns are supported). *
  • field replacement is supported based on the value of the @BsonProperty annotations
  • * *

    diff --git a/integration-tests/mongodb-panache/src/main/java/io/quarkus/it/mongodb/panache/test/TestResource.java b/integration-tests/mongodb-panache/src/main/java/io/quarkus/it/mongodb/panache/test/TestResource.java index 2a7579f0d77dcb..a122539d77f275 100644 --- a/integration-tests/mongodb-panache/src/main/java/io/quarkus/it/mongodb/panache/test/TestResource.java +++ b/integration-tests/mongodb-panache/src/main/java/io/quarkus/it/mongodb/panache/test/TestResource.java @@ -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(); @@ -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); @@ -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(); @@ -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();