feat(grails-data-neo4j): wire Neo4j adapter to GormRegistry's GormApiFactory mechanism (PR3)#15817
Conversation
There was a problem hiding this comment.
Pull request overview
Wires the Neo4j GORM adapter into the core GormRegistry API-factory mechanism so Neo4j-backed entities resolve Neo4jGormStaticApi (instead of falling back to the generic GormStaticApi), restoring Neo4j-specific static/cypher APIs and allowing previously-pending Neo4j specs to execute normally.
Changes:
- Add
Neo4jGormApiFactorythat overrides static API creation to returnNeo4jGormStaticApi. - Register the Neo4j API factory during
Neo4jDatastoreinitialization before entity enhancement occurs. - Remove
@PendingFeatureannotations from multiple Neo4j specs that now pass with the correct static API resolution.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| grails-data-neo4j/grails-datastore-gorm-neo4j/src/main/groovy/org/grails/datastore/gorm/neo4j/Neo4jGormApiFactory.groovy | Introduces a Neo4j-specific GormApiFactory that produces Neo4jGormStaticApi instances. |
| grails-data-neo4j/grails-datastore-gorm-neo4j/src/main/groovy/org/grails/datastore/gorm/neo4j/Neo4jDatastore.java | Registers the Neo4j API factory early in datastore initialization to ensure entities bind to the Neo4j factory. |
| grails-data-neo4j/grails-datastore-gorm-neo4j/src/test/groovy/org/grails/datastore/gorm/neo4j/ApiExtensionsSpec.groovy | Unblocks cypher query spec by removing @PendingFeature. |
| grails-data-neo4j/grails-datastore-gorm-neo4j/src/test/groovy/grails/gorm/tests/CypherQueryStringSpec.groovy | Removes @PendingFeature from string/cypher static query tests now supported via Neo4jGormStaticApi. |
| grails-data-neo4j/grails-datastore-gorm-neo4j/src/test/groovy/grails/gorm/tests/OneToManyUpdateSpec.groovy | Removes @PendingFeature now that cypherStatic resolves to the Neo4j static API. |
| grails-data-neo4j/grails-datastore-gorm-neo4j/src/test/groovy/grails/gorm/tests/NativeIdentityGeneratorSpec.groovy | Removes @PendingFeature for saveAll now reachable via Neo4jGormStaticApi. |
| grails-data-neo4j/grails-datastore-gorm-neo4j/src/test/groovy/grails/gorm/tests/multitenancy/MultiTenancySpec.groovy | Removes @PendingFeature now that cypher-string find resolves to Neo4j’s static API under multi-tenancy. |
| grails-data-neo4j/grails-datastore-gorm-neo4j/src/test/groovy/grails/gorm/tests/path/PathSpec.groovy | Removes @PendingFeature for Neo4j path APIs now resolved from the correct static API. |
| grails-data-neo4j/grails-datastore-gorm-neo4j/src/test/groovy/grails/gorm/tests/path/RelationshipSpec.groovy | Removes @PendingFeature for relationship finder APIs now resolved from the correct static API. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## feat/neo4j-settings-gradle-fold #15817 +/- ##
=========================================================================
- Coverage 49.6442% 49.6272% -0.0171%
+ Complexity 17041 17033 -8
=========================================================================
Files 1961 1961
Lines 93741 93741
Branches 16465 16465
=========================================================================
- Hits 46537 46521 -16
- Misses 39961 39978 +17
+ Partials 7243 7242 -1 🚀 New features to boost your workflow:
|
1717cc4 to
26c531f
Compare
85799cd to
c56a14c
Compare
26c531f to
5fb986c
Compare
c56a14c to
c024658
Compare
5fb986c to
e3015e4
Compare
Completes the Neo4j GormRegistry migration plan's PR2: registers a Neo4jGormApiFactory so entities backed by Neo4jDatastore resolve a Neo4jGormStaticApi through GormRegistry instead of silently falling back to the generic GormStaticApi. Without this, static/cypher-string API calls (cypherStatic, findRelationship(s), findPath*, findShortestPath, find/ findAll with a cypher string) threw ClassCastException or UnsupportedOperationException, since those methods only exist on Neo4jGormStaticApi. Turned out to require far less than the "rewrite Neo4jEntity/Node/ Relationship traits" originally scoped in the migration plan: Neo4j's instance and validation APIs were already generic (GormInstanceApi/ GormValidationApi, no Neo4j-specific subclass), matching the DefaultGormApiFactory's base implementations already. Only the static API needed a factory override - mirroring MongoGormApiFactory's exact shape, which only overrides createStaticApi() for the same reason. Neo4jGormApiFactory#createStaticApi() resolves the datastore via DatastoreResolver#resolve() rather than Neo4j's old bespoke getDatastoreForQualifier()/datastoresByConnectionSource logic, since qualifier/multi-datasource routing is now handled generically by GormRegistry/GormApiResolver (the "O(M+N) scaling" work this plan depends on). Verified this doesn't regress Neo4j's own multi-tenancy/multi-datasource tests. registerApiFactory() is called from Neo4jDatastore#initialize(), before constructing the GormEnhancer whose constructor eagerly registers this datastore's entities - registering after would leave those entities bound to the generic factory forever, since GormEnhancer only registers each entity once. 17 of the 34 tests marked @PendingFeature in the prior baseline-migration commit now pass and had their annotations removed (ApiExtensionsSpec, CypherQueryStringSpec, OneToManyUpdateSpec, MultiTenancySpec, PathSpec, RelationshipSpec, NativeIdentityGeneratorSpec's saveAll test, whose fix was already in place but unreachable until this factory was registered). Full suite: 198/215 passing, 0 failures, 17 skipped (4 genuinely pending - unrelated to this change - plus pre-existing @ignore'd tests). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
c5ced04 to
087b7bc
Compare
✅ All tests passed ✅🏷️ Commit: 087b7bc Learn more about TestLens at testlens.app. |
Summary
Completes the Neo4j GormRegistry migration plan's PR3, on top of #15816 (PR1, baseline) and #15951 (PR2,
settings.gradlefold): registers aNeo4jGormApiFactoryso entities backed byNeo4jDatastoreresolve aNeo4jGormStaticApithroughGormRegistryinstead of silently falling back to the genericGormStaticApi. Without this, static/cypher-string API calls (cypherStatic,findRelationship(s),findPath*,findShortestPath,find/findAllwith a cypher string) threwClassCastExceptionorUnsupportedOperationException, since those methods only exist onNeo4jGormStaticApi.This turned out to require far less than the "rewrite Neo4jEntity/Node/Relationship traits" originally scoped in the migration plan - a nice, concrete dividend of the GormRegistry refactor: adding a new datastore's wiring is now a small, mechanical exercise rather than an integration project. Neo4j's instance and validation APIs were already generic (
GormInstanceApi/GormValidationApi, no Neo4j-specific subclass), matchingDefaultGormApiFactory's base implementations already - only the static API needed a factory override, mirroringMongoGormApiFactory's exact shape (which only overridescreateStaticApi()for the same reason). The whole change is a ~25-line factory class plus a single line registering it.Neo4jGormApiFactory#createStaticApi()resolves the datastore viaDatastoreResolver#resolve()rather than Neo4j's old bespokegetDatastoreForQualifier()/datastoresByConnectionSourcelogic - qualifier/multi-datasource routing is now handled generically byGormRegistry/GormApiResolver(the O(M+N) scaling work this plan depends on). Verified this doesn't regress Neo4j's own multi-tenancy/multi-datasource tests.registerApiFactory()is called fromNeo4jDatastore#initialize(), before constructing theGormEnhancerwhose constructor eagerly registers this datastore's entities - registering after would leave those entities bound to the generic factory forever, sinceGormEnhanceronly registers each entity once.@PendingFeaturein the baseline PR now pass and had their annotations removed (ApiExtensionsSpec,CypherQueryStringSpec,OneToManyUpdateSpec,MultiTenancySpec,PathSpec,RelationshipSpec,NativeIdentityGeneratorSpec'ssaveAlltest - whose fix was already in place from the baseline PR but unreachable until this factory was registered).Test plan
./gradlew :grails-datastore-gorm-neo4j:test-BUILD SUCCESSFUL, 198/215 passing, 0 failures, 17 skipped (4 genuinely pending and unrelated to this change, plus pre-existing@Ignore'd tests)DatastoreResolver-based routing🤖 Generated with Claude Code