This is an automated email from the ASF dual-hosted git repository.

borinquenkid pushed a commit to branch 8.0.x-hibernate7
in repository https://gitbox.apache.org/repos/asf/grails-core.git

commit c63b7be93d4a80d35eeee95e410e21f7390cda85
Author: Walter B Duque de Estrada <[email protected]>
AuthorDate: Wed Jan 28 12:38:35 2026 -0600

    Rlike added
---
 .../query/GrailsRLikeFunctionContributor.java      | 27 +++++++++++++++
 .../grails/orm/hibernate/query/HibernateQuery.java |  3 +-
 .../orm/hibernate/query/PredicateGenerator.java    |  9 ++++-
 .../orm/hibernate/query/RegexDialectPattern.java   | 38 ++++++++++++++++++++++
 .../org.hibernate.boot.model.FunctionContributor   |  1 +
 .../test/groovy/grails/gorm/specs/RLikeSpec.groovy |  2 --
 .../specs/hibernatequery/HibernateQuerySpec.groovy |  3 +-
 .../hibernate/query/RegexDialectPatternSpec.groovy | 28 ++++++++++++++++
 8 files changed, 105 insertions(+), 6 deletions(-)

diff --git 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/GrailsRLikeFunctionContributor.java
 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/GrailsRLikeFunctionContributor.java
new file mode 100644
index 0000000000..a0c85d6595
--- /dev/null
+++ 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/GrailsRLikeFunctionContributor.java
@@ -0,0 +1,27 @@
+package org.grails.orm.hibernate.query;
+
+import org.hibernate.boot.model.FunctionContributions;
+import org.hibernate.boot.model.FunctionContributor;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.type.StandardBasicTypes;
+
+public class GrailsRLikeFunctionContributor implements FunctionContributor {
+
+    public static final String RLIKE = "rlike";
+
+    @Override
+    public void contributeFunctions(FunctionContributions 
functionContributions) {
+        Dialect dialect = functionContributions.getDialect();
+
+        // Use the Enum to resolve the pattern
+        String pattern = RegexDialectPattern.findPatternForDialect(dialect);
+
+        functionContributions.getFunctionRegistry().registerPattern(
+                RLIKE,
+                pattern,
+                functionContributions.getTypeConfiguration()
+                        .getBasicTypeRegistry()
+                        .resolve(StandardBasicTypes.BOOLEAN)
+        );
+    }
+}
diff --git 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/HibernateQuery.java
 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/HibernateQuery.java
index 423f26ad6f..0dd747c2de 100644
--- 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/HibernateQuery.java
+++ 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/HibernateQuery.java
@@ -316,7 +316,8 @@ public class HibernateQuery extends Query {
 
     @Override
     public Query rlike(String property, String expr) {
-        throw new UnsupportedOperationException("Needs RLIKE extension");
+        detachedCriteria.rlike(property,expr);
+        return this;
     }
 
     @Override
diff --git 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/PredicateGenerator.java
 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/PredicateGenerator.java
index 93e4c1312a..12ff7965ff 100644
--- 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/PredicateGenerator.java
+++ 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/PredicateGenerator.java
@@ -19,6 +19,7 @@ import org.grails.datastore.mapping.model.types.Association;
 import org.grails.datastore.mapping.query.Query;
 import org.grails.datastore.mapping.query.api.QueryableCriteria;
 import org.hibernate.query.criteria.HibernateCriteriaBuilder;
+import org.hibernate.query.criteria.JpaFunction;
 import org.hibernate.query.criteria.JpaInPredicate;
 import org.hibernate.query.criteria.JpaPredicate;
 import org.hibernate.query.sqm.tree.domain.SqmPath;
@@ -131,7 +132,13 @@ public class PredicateGenerator {
                         } else if (criterion instanceof Query.ILike c) {
                             return cb.ilike(fullyQualifiedPath, 
c.getValue().toString());
                         } else if (criterion instanceof Query.RLike c) {
-                            return cb.like(fullyQualifiedPath, c.getPattern(), 
'\\');
+                            String pattern = c.getPattern();
+                            pattern = pattern.replaceAll("^/|/$", "");
+                            return cb.equal(cb.function(
+                                    GrailsRLikeFunctionContributor.RLIKE,      
     // The name we registered
+                                    Boolean.class,     // Expected return type
+                                    fullyQualifiedPath, // The property path
+                                    cb.literal(pattern)), true);
                         } else if (criterion instanceof Query.Like c) {
                             return cb.like(fullyQualifiedPath, 
c.getValue().toString());
                         } else if (criterion instanceof Query.In c) {
diff --git 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/RegexDialectPattern.java
 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/RegexDialectPattern.java
new file mode 100644
index 0000000000..1d4025e70d
--- /dev/null
+++ 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/RegexDialectPattern.java
@@ -0,0 +1,38 @@
+package org.grails.orm.hibernate.query;
+
+import org.hibernate.dialect.*;
+import java.util.Arrays;
+
+public enum RegexDialectPattern {
+    MYSQL(MySQLDialect.class, "?1 RLIKE ?2"),
+    MARIADB(MariaDBDialect.class, "?1 REGEXP ?2"),
+    POSTGRES(PostgreSQLDialect.class, "?1 ~ ?2"),
+    ORACLE(OracleDialect.class, "REGEXP_LIKE(?1, ?2)"),
+    H2(H2Dialect.class, "REGEXP_LIKE(?1, ?2)"),
+    // Default fallback
+    DEFAULT(Dialect.class, "?1 LIKE ?2");
+
+    private final Class<? extends Dialect> dialectClass;
+    private final String sqlPattern;
+
+    RegexDialectPattern(Class<? extends Dialect> dialectClass, String 
sqlPattern) {
+        this.dialectClass = dialectClass;
+        this.sqlPattern = sqlPattern;
+    }
+
+    public String getSqlPattern() {
+        return sqlPattern;
+    }
+
+    /**
+     * Resolves the pattern by checking if the runtime dialect
+     * is an instance of the supported dialect class.
+     */
+    public static String findPatternForDialect(Dialect runtimeDialect) {
+        return Arrays.stream(values())
+                .filter(p -> p != DEFAULT && 
p.dialectClass.isInstance(runtimeDialect))
+                .findFirst()
+                .map(RegexDialectPattern::getSqlPattern)
+                .orElse(DEFAULT.sqlPattern);
+    }
+}
diff --git 
a/grails-data-hibernate7/core/src/main/resources/META-INF/services/org.hibernate.boot.model.FunctionContributor
 
b/grails-data-hibernate7/core/src/main/resources/META-INF/services/org.hibernate.boot.model.FunctionContributor
new file mode 100644
index 0000000000..5f64497633
--- /dev/null
+++ 
b/grails-data-hibernate7/core/src/main/resources/META-INF/services/org.hibernate.boot.model.FunctionContributor
@@ -0,0 +1 @@
+org.grails.orm.hibernate.query.GrailsRLikeFunctionContributor
diff --git 
a/grails-data-hibernate7/core/src/test/groovy/grails/gorm/specs/RLikeSpec.groovy
 
b/grails-data-hibernate7/core/src/test/groovy/grails/gorm/specs/RLikeSpec.groovy
index b5d5f04e2b..07dc293ae0 100644
--- 
a/grails-data-hibernate7/core/src/test/groovy/grails/gorm/specs/RLikeSpec.groovy
+++ 
b/grails-data-hibernate7/core/src/test/groovy/grails/gorm/specs/RLikeSpec.groovy
@@ -23,13 +23,11 @@ import 
org.apache.grails.data.hibernate7.core.GrailsDataHibernate7TckManager
 import org.apache.grails.data.testing.tck.base.GrailsDataTckSpec
 import spock.lang.Ignore
 
-//TODO Rlike Needs to be implemented for Hibernate 6
 class RLikeSpec extends GrailsDataTckSpec<GrailsDataHibernate7TckManager> {
     void setupSpec() {
         manager.addAllDomainClasses([RlikeFoo])
     }
 
-    @Ignore
     void "test rlike works with H2"() {
         given:
         new RlikeFoo(name: "ABC").save(flush: true)
diff --git 
a/grails-data-hibernate7/core/src/test/groovy/grails/gorm/specs/hibernatequery/HibernateQuerySpec.groovy
 
b/grails-data-hibernate7/core/src/test/groovy/grails/gorm/specs/hibernatequery/HibernateQuerySpec.groovy
index 139dd564d2..b4b7059c35 100644
--- 
a/grails-data-hibernate7/core/src/test/groovy/grails/gorm/specs/hibernatequery/HibernateQuerySpec.groovy
+++ 
b/grails-data-hibernate7/core/src/test/groovy/grails/gorm/specs/hibernatequery/HibernateQuerySpec.groovy
@@ -207,11 +207,10 @@ class HibernateQuerySpec extends 
HibernateGormDatastoreSpec {
         oldBob == newBob
     }
 
-    @Ignore("Must add custom functionality")
     def rlike() {
         given:
         new Person(firstName: "Fred", lastName: "Rogers", age: 52).save(flush: 
true)
-        hibernateQuery.rlike("firstName", "/Bob*/")
+        hibernateQuery.rlike("firstName", "Bob.*")
         when:
         def newBob = hibernateQuery.singleResult()
         then:
diff --git 
a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/query/RegexDialectPatternSpec.groovy
 
b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/query/RegexDialectPatternSpec.groovy
new file mode 100644
index 0000000000..25a6b1b51d
--- /dev/null
+++ 
b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/query/RegexDialectPatternSpec.groovy
@@ -0,0 +1,28 @@
+package org.grails.orm.hibernate.query
+
+import org.hibernate.dialect.H2Dialect
+import org.hibernate.dialect.MySQLDialect
+import org.hibernate.dialect.MariaDBDialect
+import org.hibernate.dialect.PostgreSQLDialect
+import org.hibernate.dialect.OracleDialect
+import org.hibernate.dialect.SQLServerDialect
+import spock.lang.Specification
+import spock.lang.Unroll
+
+class RegexDialectPatternSpec extends Specification {
+
+    @Unroll
+    void "test findPatternForDialect for #dialect.class.simpleName"() {
+        expect:
+        RegexDialectPattern.findPatternForDialect(dialect) == expectedPattern
+
+        where:
+        dialect                  | expectedPattern
+        new MySQLDialect()       | "?1 RLIKE ?2"
+        new MariaDBDialect()     | "?1 REGEXP ?2"
+        new PostgreSQLDialect()  | "?1 ~ ?2"
+        new OracleDialect()      | "REGEXP_LIKE(?1, ?2)"
+        new H2Dialect()          | "REGEXP_LIKE(?1, ?2)"
+        new SQLServerDialect()   | "?1 LIKE ?2" // Fallback
+    }
+}

Reply via email to