You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@grails.apache.org by "codeconsole (via GitHub)" <gi...@apache.org> on 2026/05/29 07:02:35 UTC

[PR] Fix constraints overwriting mapping index configuration (#15680) [grails-core]

codeconsole opened a new pull request, #15700:
URL: https://github.com/apache/grails-core/pull/15700

   ## Summary
   
   Fixes #15680.
   
   When a domain property has both `index: true, indexAttributes: [unique: true]` in `static mapping` and `unique: true` in `static constraints`, the constraint evaluation overwrites the mapping-configured property, so the database-level unique index is silently never created.
   
   ## Root Cause
   
   `AbstractGormMappingFactory.createMappedForm()` evaluates both closures through the same `DefaultMappingConfigurationBuilder`:
   1. The mapping closure (`name index: true, indexAttributes: [unique: true]`) goes through `builder.invokeMethod`, which stores a `MongoAttribute` with `index=true, indexAttributes={unique:true}` in `builder.properties['name']`.
   2. The constraint closure (`name unique: true`) goes through `Entity.methodMissing`, which creates a SEPARATE instance in `target.propertyConfigs['name']` containing only `unique=true`.
   3. `builder.getProperties()` then does `properties.putAll(target.propertyConfigs)`, overwriting the mapping-set property with the constraint-only version. `index` reverts to `false` and `indexAttributes` becomes `null`.
   
   `MongoDatastore.initializeIndices()` reads `property.getMapping().getMappedForm().isIndex()`, which now returns `false`, so the MongoDB index is silently never created.
   
   ## Fix
   
   Change `getProperties()` to use `putIfAbsent` semantics — properties already configured by the mapping closure are preserved when the constraint closure provides a conflicting entry.
   
   ## Test
   
   `DefaultMappingConfigurationBuilderSpec` covers the scenario directly: a property simulating GORM's `Entity.methodMissing` path against a builder that already has a mapping-configured property. The test FAILS before the fix and PASSES after.
   
   ## Verified
   
   Tested against a real Pixoto3 Grails 7.2 app with embedded MongoDB:
   - Before: `Category.name` declared `index: true, indexAttributes: [unique: true]` in mapping + `unique: true` in constraints → only `_id_` index in MongoDB
   - After: same declarations → `name_1` unique index correctly created in MongoDB
   
   ## Backward Compatibility
   
   Behavior change: if a user previously relied on constraints overwriting mapping (unlikely — that's the bug), they would observe their mapping-configured property surviving instead. The opposite direction (constraint values being applied on top of an existing mapping property) was already happening through `builder.invokeMethod` reusing the existing instance, so the typical "add a constraint to a mapped property" flow is unaffected.


-- 
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: notifications-unsubscribe@grails.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Fix constraints overwriting mapping index configuration (#15680) [grails-core]

Posted by "codeconsole (via GitHub)" <gi...@apache.org>.
codeconsole commented on code in PR #15700:
URL: https://github.com/apache/grails-core/pull/15700#discussion_r3323182904


##########
grails-datastore-core/src/main/groovy/org/grails/datastore/mapping/config/groovy/DefaultMappingConfigurationBuilder.groovy:
##########
@@ -47,7 +47,11 @@ class DefaultMappingConfigurationBuilder implements MappingConfigurationBuilder
 
     Map<String, Property> getProperties() {
         if (!target.propertyConfigs.isEmpty()) {
-            properties.putAll(target.propertyConfigs)
+            for (Map.Entry entry : target.propertyConfigs.entrySet()) {
+                if (!properties.containsKey(entry.key)) {
+                    properties.put(entry.key, entry.value)
+                }

Review Comment:
   Good call — added a DEBUG-level log statement when a key collision is detected. Kept it at debug because in a real Grails-app boot this fires for every property that appears in both a `static mapping` and `static constraints` block (which is most domains with any field validation alongside any explicit mapping), so info-level would be too noisy for a steady-state condition. Anyone investigating an unexpected precedence outcome can flip the logger for `org.grails.datastore.mapping.config.groovy.DefaultMappingConfigurationBuilder` to DEBUG and see exactly which keys collided.



-- 
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: notifications-unsubscribe@grails.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Fix constraints overwriting mapping index configuration (#15680) [grails-core]

Posted by "sbglasius (via GitHub)" <gi...@apache.org>.
sbglasius commented on code in PR #15700:
URL: https://github.com/apache/grails-core/pull/15700#discussion_r3322953422


##########
grails-datastore-core/src/main/groovy/org/grails/datastore/mapping/config/groovy/DefaultMappingConfigurationBuilder.groovy:
##########
@@ -47,7 +47,11 @@ class DefaultMappingConfigurationBuilder implements MappingConfigurationBuilder
 
     Map<String, Property> getProperties() {
         if (!target.propertyConfigs.isEmpty()) {
-            properties.putAll(target.propertyConfigs)
+            for (Map.Entry entry : target.propertyConfigs.entrySet()) {
+                if (!properties.containsKey(entry.key)) {
+                    properties.put(entry.key, entry.value)
+                }

Review Comment:
   Would it make sense to make a log statement if the `properties` actually contains the `entry` and that way give the developer a chance to know that there is a conflicting property?



-- 
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: notifications-unsubscribe@grails.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Fix constraints overwriting mapping index configuration (#15680) [grails-core]

Posted by "jdaugherty (via GitHub)" <gi...@apache.org>.
jdaugherty commented on PR #15700:
URL: https://github.com/apache/grails-core/pull/15700#issuecomment-4583203175

   The code style & licensing issues need addressed


-- 
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: notifications-unsubscribe@grails.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Fix constraints overwriting mapping index configuration (#15680) [grails-core]

Posted by "testlens-app[bot] (via GitHub)" <gi...@apache.org>.
testlens-app[bot] commented on PR #15700:
URL: https://github.com/apache/grails-core/pull/15700#issuecomment-4585103081

   ## ✅ All tests passed ✅
   
   🏷️ Commit: de857e829949d18179c00f3cf2c0c864b091f917
   ▶️ Tests:  47460 executed
   ⚪️ Checks: 37/37 completed
   
   ---
   _Learn more about TestLens at [testlens.app](https://testlens.app)._
   


-- 
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: notifications-unsubscribe@grails.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Fix constraints overwriting mapping index configuration (#15680) [grails-core]

Posted by "testlens-app[bot] (via GitHub)" <gi...@apache.org>.
testlens-app[bot] commented on PR #15700:
URL: https://github.com/apache/grails-core/pull/15700#issuecomment-4573430897

   ## ✅ All tests passed ✅
   
   🏷️ Commit: 365956bb4f690eb921079ea9d4c5e699281f19cb
   ▶️ Tests:  42875 executed
   ⚪️ Checks: 37/37 completed
   
   ---
   _Learn more about TestLens at [testlens.app](https://testlens.app)._
   


-- 
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: notifications-unsubscribe@grails.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Fix constraints overwriting mapping index configuration (#15680) [grails-core]

Posted by "testlens-app[bot] (via GitHub)" <gi...@apache.org>.
testlens-app[bot] commented on PR #15700:
URL: https://github.com/apache/grails-core/pull/15700#issuecomment-4587642882

   ## ✅ All tests passed ✅
   
   🏷️ Commit: 9c6e41ab38fb77c8b1e1daac3950884d879e636c
   ▶️ Tests:  37231 executed
   ⚪️ Checks: 37/37 completed
   
   ---
   _Learn more about TestLens at [testlens.app](https://testlens.app)._
   


-- 
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: notifications-unsubscribe@grails.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Fix constraints overwriting mapping index configuration (#15680) [grails-core]

Posted by "testlens-app[bot] (via GitHub)" <gi...@apache.org>.
testlens-app[bot] commented on PR #15700:
URL: https://github.com/apache/grails-core/pull/15700#issuecomment-4576386096

   ## ✅ All tests passed ✅
   
   🏷️ Commit: 214e1a8b3a8181a1fd0573c0a08e12d71ec13d52
   ▶️ Tests:  25026 executed
   ⚪️ Checks: 37/37 completed
   
   ---
   _Learn more about TestLens at [testlens.app](https://testlens.app)._
   


-- 
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: notifications-unsubscribe@grails.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Fix constraints overwriting mapping index configuration (#15680) [grails-core]

Posted by "codeconsole (via GitHub)" <gi...@apache.org>.
codeconsole commented on PR #15700:
URL: https://github.com/apache/grails-core/pull/15700#issuecomment-4572637187

   ## Updated based on review
   
   Pushed an amended commit with the following tweaks (verified by an independent multi-agent review of the original PR):
   
   ### Test coverage improved
   
   The original test (now renamed *"constraints closure does not overwrite mapping properties (standard DSL flow)"*) passed even with the fix reverted — both closures route through `builder.invokeMethod` and reuse the same instance, so `target.propertyConfigs` stays empty for that flow and the changed merge path is never exercised.
   
   The new spec adds **"mapping property in builder.properties is preserved when target.propertyConfigs has a different instance for the same key"** which:
   - Populates `builder.properties['name']` via the mapping closure (the normal `invokeMethod` path)
   - Independently populates `entity.propertyConfigs['name']` with a separate instance (simulating the constraint-evaluator / `Entity.property(name, Map)` direct-API path that actually triggers the bug in a full Grails app)
   - Asserts the builder's mapping-configured instance is the one returned by `getProperties()`
   
   **Verified:** this new test FAILS against the pre-fix `properties.putAll(target.propertyConfigs)` code and PASSES with the `putIfAbsent` fix. The TCK-based MongoDB integration spec was attempted but does not exercise the bug — the TCK uses `DefaultGrailsApplication` directly and skips the constraint-evaluator wiring that populates `propertyConfigs` in a real Grails-app boot, so it cannot reproduce the failure.
   
   Also added **"target.propertyConfigs entries fill in for keys the mapping closure never touched"** to lock in that constraint-only configuration for properties the mapping never mentions still propagates correctly.
   
   ### Code comment added
   
   Added javadoc to `getProperties()` documenting:
   - The precedence rule (mapping-side instance wins when both maps have the same key)
   - Why the asymmetry exists (dual-store legacy)
   - A link back to this issue for the structural cleanup that would let the method go away
   
   ### Known follow-up
   
   The dual-store design (`builder.properties` vs `Entity.propertyConfigs`) is the underlying root cause — this PR papers over a symptom. A future major-release cleanup should collapse the two into a single canonical store. Tracking would happen in a separate issue.


-- 
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: notifications-unsubscribe@grails.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Fix constraints overwriting mapping index configuration (#15680) [grails-core]

Posted by "testlens-app[bot] (via GitHub)" <gi...@apache.org>.
testlens-app[bot] commented on PR #15700:
URL: https://github.com/apache/grails-core/pull/15700#issuecomment-4572464350

   ## ✅ All tests passed ✅
   
   🏷️ Commit: dbba9f5fe87f5e129689cc8d865bb85bd73ba7ae
   ▶️ Tests:  35366 executed
   ⚪️ Checks: 37/37 completed
   
   ---
   _Learn more about TestLens at [testlens.app](https://testlens.app)._
   


-- 
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: notifications-unsubscribe@grails.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Fix constraints overwriting mapping index configuration (#15680) [grails-core]

Posted by "bito-code-review[bot] (via GitHub)" <gi...@apache.org>.
bito-code-review[bot] commented on PR #15700:
URL: https://github.com/apache/grails-core/pull/15700#issuecomment-4572297165

   <!-- Bito Reply -->
   The PR comments file appears to be empty (only the header row is present). I cannot analyze the suggestion or provide context-specific advice without actual review comments. Please ensure the file contains the necessary data for evaluation.


-- 
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: notifications-unsubscribe@grails.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Fix constraints overwriting mapping index configuration (#15680) [grails-core]

Posted by "codeconsole (via GitHub)" <gi...@apache.org>.
codeconsole merged PR #15700:
URL: https://github.com/apache/grails-core/pull/15700


-- 
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: notifications-unsubscribe@grails.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org