Copilot commented on code in PR #15435:
URL: https://github.com/apache/grails-core/pull/15435#discussion_r2836926682


##########
grails-test-examples/datasources/src/integration-test/groovy/functionaltests/DatasourceSwitchingSpec.groovy:
##########
@@ -367,4 +367,90 @@ class DatasourceSwitchingSpec extends Specification {
         and: "secondary books still exist"
         SecondBook.withTransaction { SecondBook.countByTitleLike("Delete Me%") 
} == 2
     }
+
+    def "executeQuery routes to secondary datasource"() {
+        given: "books in both datasources"
+        def primaryTitle = "Primary Query ${UUID.randomUUID()}"
+        def secondaryTitle = "Secondary Query ${UUID.randomUUID()}"
+        new Book(title: primaryTitle).save(flush: true)
+        SecondBook.withTransaction {
+            new SecondBook(title: secondaryTitle).save(flush: true)
+        }
+
+        when: "executing query on secondary"
+        def results
+        SecondBook.withTransaction {
+            results = SecondBook.executeQuery("from ds2.Book where title = 
:t", [t: secondaryTitle])
+        }
+
+        then: "only secondary data is returned"
+        results.size() == 1
+        results.first().title == secondaryTitle
+    }
+
+    def "withCriteria routes to secondary datasource"() {
+        given: "books in both datasources"
+        def primaryTitle = "Primary Criteria ${UUID.randomUUID()}"
+        def secondaryTitle = "Secondary Criteria ${UUID.randomUUID()}"
+        new Book(title: primaryTitle).save(flush: true)
+        SecondBook.withTransaction {
+            new SecondBook(title: secondaryTitle).save(flush: true)
+        }
+
+        when: "executing criteria on secondary"
+        def results
+        SecondBook.withTransaction {
+            results = SecondBook.withCriteria {
+                eq('title', secondaryTitle)
+            }
+        }
+
+        then: "only secondary data is returned"
+        results.size() == 1
+        results.first().title == secondaryTitle
+    }
+
+    def "createCriteria routes to secondary datasource"() {
+        given: "books in both datasources"
+        def primaryTitle = "Primary CreateCriteria ${UUID.randomUUID()}"
+        def secondaryTitle = "Secondary CreateCriteria ${UUID.randomUUID()}"
+        new Book(title: primaryTitle).save(flush: true)
+        SecondBook.withTransaction {
+            new SecondBook(title: secondaryTitle).save(flush: true)
+        }
+
+        when: "executing createCriteria on secondary"
+        def results
+        SecondBook.withTransaction {
+            results = SecondBook.createCriteria().list {
+                eq('title', secondaryTitle)
+            }
+        }
+
+        then: "only secondary data is returned"
+        results.size() == 1
+        results.first().title == secondaryTitle
+    }
+
+    def "executeUpdate routes to secondary datasource"() {
+        given: "books in both datasources"
+        def primaryTitle = "Primary Update ${UUID.randomUUID()}"
+        def secondaryTitle = "Secondary Update ${UUID.randomUUID()}"
+        def updatedTitle = "Secondary Updated ${UUID.randomUUID()}"
+        new Book(title: primaryTitle).save(flush: true)
+        SecondBook.withTransaction {
+            new SecondBook(title: secondaryTitle).save(flush: true)
+        }
+
+        when: "executing update on secondary"
+        int updated
+        SecondBook.withTransaction {
+            updated = SecondBook.executeUpdate("update ds2.Book set title = 
:newTitle where title = :oldTitle", [newTitle: updatedTitle, oldTitle: 
secondaryTitle])

Review Comment:
   Same as above: the update HQL hard-codes `ds2.Book`. Using the domain class’ 
actual name (e.g., derived from `SecondBook`) avoids stringly-typed coupling 
and keeps the test focused on datasource routing rather than a fixed package 
name.
   ```suggestion
               updated = SecondBook.executeUpdate("update ${SecondBook.name} 
set title = :newTitle where title = :oldTitle", [newTitle: updatedTitle, 
oldTitle: secondaryTitle])
   ```



##########
grails-datamapping-core/src/test/groovy/org/grails/datastore/gorm/GormEnhancerAllQualifiersSpec.groovy:
##########
@@ -102,6 +102,38 @@ class GormEnhancerAllQualifiersSpec extends Specification {
         qualifiers == ['secondary']
     }
 
+    void "registerEntity adds static api under default and secondary for 
non-default datasource"() {
+        given: "a non-MultiTenant entity with datasource 'secondary'"
+        def enhancer = createEnhancer()
+        def entity = mockEntity(NonMultiTenantSecondaryEntity, ['secondary'])
+        def staticApis = GormEnhancer.@STATIC_APIS
+        staticApis.get(ConnectionSource.DEFAULT).remove(entity.name)
+        staticApis.get('secondary').remove(entity.name)
+
+        when: "registering the entity"
+        enhancer.registerEntity(entity)
+
+        then: "static api is available under DEFAULT and secondary qualifiers"
+        staticApis.get(ConnectionSource.DEFAULT).containsKey(entity.name)
+        staticApis.get('secondary').containsKey(entity.name)

Review Comment:
   These assertions reach into the private `GormEnhancer.@STATIC_APIS` map and 
only verify the raw key exists. That makes the test brittle to internal 
refactors and can miss real lookup issues (e.g., if `NameUtils.getClassName()` 
diverges from `entity.name`). Prefer asserting via the public API 
(`GormEnhancer.findStaticApi(YourClass, qualifier)` does not throw) for DEFAULT 
and 'secondary' to validate behavior the production code actually uses.



##########
grails-datamapping-core/src/test/groovy/org/grails/datastore/gorm/GormEnhancerAllQualifiersSpec.groovy:
##########
@@ -159,6 +191,20 @@ class GormEnhancerAllQualifiersSpec extends Specification {
         qualifiers == [ConnectionSource.DEFAULT]
     }
 
+    void "registerEntity adds static api under default for default 
datasource"() {
+        given: "a non-MultiTenant entity on the default datasource"
+        def enhancer = createEnhancer()
+        def entity = mockEntity(NonMultiTenantDefaultEntity, 
[ConnectionSource.DEFAULT])
+        def staticApis = GormEnhancer.@STATIC_APIS
+        staticApis.get(ConnectionSource.DEFAULT).remove(entity.name)
+
+        when: "registering the entity"
+        enhancer.registerEntity(entity)
+
+        then: "static api is available under DEFAULT qualifier"
+        staticApis.get(ConnectionSource.DEFAULT).containsKey(entity.name)

Review Comment:
   This test also inspects `GormEnhancer.@STATIC_APIS` directly. Using 
`GormEnhancer.findStaticApi(NonMultiTenantDefaultEntity, 
ConnectionSource.DEFAULT)` (and asserting no exception) would both avoid 
relying on private state and ensure the registration is visible through the 
same lookup path used at runtime.
   ```suggestion
   
           when: "registering the entity"
           enhancer.registerEntity(entity)
           def staticApi = 
GormEnhancer.findStaticApi(NonMultiTenantDefaultEntity, 
ConnectionSource.DEFAULT)
   
           then: "static api is available under DEFAULT qualifier"
           staticApi != null
   ```



##########
grails-test-examples/datasources/src/integration-test/groovy/functionaltests/DatasourceSwitchingSpec.groovy:
##########
@@ -367,4 +367,90 @@ class DatasourceSwitchingSpec extends Specification {
         and: "secondary books still exist"
         SecondBook.withTransaction { SecondBook.countByTitleLike("Delete Me%") 
} == 2
     }
+
+    def "executeQuery routes to secondary datasource"() {
+        given: "books in both datasources"
+        def primaryTitle = "Primary Query ${UUID.randomUUID()}"
+        def secondaryTitle = "Secondary Query ${UUID.randomUUID()}"
+        new Book(title: primaryTitle).save(flush: true)
+        SecondBook.withTransaction {
+            new SecondBook(title: secondaryTitle).save(flush: true)
+        }
+
+        when: "executing query on secondary"
+        def results
+        SecondBook.withTransaction {
+            results = SecondBook.executeQuery("from ds2.Book where title = 
:t", [t: secondaryTitle])

Review Comment:
   The HQL strings hard-code the entity name (`ds2.Book`). This makes the test 
brittle to package/entity-name changes and duplicates the information already 
available via `SecondBook`. Consider building the HQL using `SecondBook.name` 
(or `SecondBook.simpleName` if appropriate) so the test stays correct if the 
domain class is moved/renamed while still exercising routing.
   ```suggestion
               results = SecondBook.executeQuery("from ${SecondBook.name} where 
title = :t", [t: secondaryTitle])
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to