jamesfredley commented on code in PR #16725:
URL: https://github.com/apache/grails-core/pull/16725#discussion_r4346429893
##########
.agents/skills/mongodb-developer/SKILL.md:
##########
@@ -0,0 +1,122 @@
+---
+name: mongodb-developer
+description: Guide for working in the grails-data-mongodb module (GORM for
MongoDB) — codec-based document mapping, GeoJSON, embedded documents, TTL
indexes, multi-tenancy, and Testcontainers-backed tests. Use this when changing
code or tests under grails-data-mongodb.
+license: Apache-2.0
+---
+<!--
+SPDX-License-Identifier: Apache-2.0
+
+Licensed to the Apache Software Foundation (ASF) under one or more contributor
license agreements; and to You under the Apache License, Version 2.0.
+-->
+
+## What I Do
+
+- Provide repository-specific guidance for the `grails-data-mongodb` project
(GORM for MongoDB — a document-database GORM implementation, not a relational
one; do not bring Hibernate/binder mental models here).
+- Guide changes around `MongoMappingContext`,
`BsonPersistentEntityCodec`/`PersistentEntityCodec`, and the
codec-registry-based encode/decode pipeline.
+- Keep changes aligned with the Testcontainers-backed testing pattern this
module actually uses.
+
+## When to Use Me
+
+Activate this skill when working on the MongoDB module, especially for:
+
+- Changes under `grails-data-mongodb/**` (any of its 9 subprojects — see
Module Structure).
+- Document/collection mapping, codec, or GeoJSON-type work.
+- Index (including TTL) creation/reconciliation logic.
+- Multi-tenancy or multi-connection MongoDB work.
+
+## Module Context
+
+`grails-data-mongodb` has no `settings.gradle` of its own — it's part of the
root aggregate build, same as `grails-data-hibernate7`. All of root
`AGENTS.md`'s rules (jakarta, `@GrailsCompileStatic`,
CodeNarc/Checkstyle/PMD/SpotBugs, `dependencies.gradle`/BOM) apply here
unmodified.
+
+Nine Gradle projects live under this directory, mapped to real Gradle project
names (not always `grails-data-mongodb-<dirname>` — check before assuming):
+
+| Directory | Gradle project | Role |
+|---|---|---|
+| `core/` | `:grails-data-mongodb-core` | The actual GORM-for-MongoDB
implementation: `MongoDatastore`, `MongoMappingContext`, `MongoQuery`, GeoJSON
types |
+| `bson/` | `:grails-data-mongodb-bson` | Low-level, GORM-independent BSON
codec machinery (`BsonPersistentEntityCodec`, per-type property codecs,
hand-rolled JSON tokenizer) |
+| `ext/` | `:grails-data-mongodb-ext` | A single file, Groovy extension
methods on the raw MongoDB driver (`distinct`, `watch`/change streams,
`deleteMany`) |
+| `boot-plugin/` | `:grails-data-mongodb-spring-boot` | Spring Boot
auto-configuration (`MongoDbGormAutoConfiguration`) |
+| `spring-data/` | `:grails-data-mongodb-spring-data` | Lets GORM-for-MongoDB
and Spring Data MongoDB share a `MongoClient`/codecs/transaction |
+| `grails-plugin/` | `:grails-data-mongodb` (note: not `-grails-plugin`
suffixed) | Classic Grails plugin descriptor (`MongodbGrailsPlugin`); also
ships the app-facing `grails.test.mongodb.MongoSpec` test base via
`testFixtures` |
+| `gson-templates/` | `:grails-data-mongodb-gson-templates` | JSON Views
(`.gson`) for `ObjectId` and GeoJSON types |
+| `embedded/` | `:grails-data-mongodb-embedded` | Starts a real `mongod`
(Flapdoodle, a `compileOnly` dependency the application adds itself) before the
application context refreshes and publishes its URL into the configured
properties; for applications, not for this module's own tests |
+| `docs/` | `:grails-data-mongodb-docs` | Asciidoc manual + groovydoc
aggregation only, no source |
+
+## Key Classes and Responsibilities
+
+There is no single `GrailsDomainBinder`-equivalent class — the responsibility
splits across three cooperating layers:
+
+### Mapping (the binder equivalent)
+
+- `MongoMappingContext` (`core/.../mongo/config/MongoMappingContext.java`) —
owns the private inner `MongoDocumentMappingFactory extends
AbstractGormMappingFactory<MongoCollection, MongoAttribute>`, which is the
actual binder: forces the `_id` field name, applies the global
`stringIdDefaultStoredAs` default, wires codec-registry-backed custom types,
and registers all GeoJSON custom types.
+- `MongoCollection` (`core/.../config/MongoCollection.groovy`) — entity-level
mapping (collection name, database, `writeConcern`, indices, sort).
+- `MongoAttribute` (`core/.../config/MongoAttribute.groovy`) — property-level
mapping (`reference` for DBRef vs. embed, `field`, `geoIndex`, `index`,
`indexAttributes`).
+- `MappingBuilder.document { ... }`
(`core/.../grails/mongodb/mapping/MappingBuilder.groovy`) — the programmatic
DSL entry point.
+
+### Codec pipeline (the runtime read/write engine)
+
+- `BsonPersistentEntityCodec` (`bson/.../BsonPersistentEntityCodec.groovy`)
and its Mongo subclass `PersistentEntityCodec`
(`core/.../engine/codecs/PersistentEntityCodec.groovy`) — a static
`ENCODERS`/`DECODERS` registry keyed by `PersistentProperty` subtype
(`Identity`, `TenantId`, `Simple`, `Embedded`, `EmbeddedCollection`, `Custom`,
`Basic`, plus Mongo-specific `OneToOne`/`ManyToOne`/`OneToMany`/`ManyToMany`).
`encode`/`decode` walk `entity.persistentProperties` and dispatch per property
kind. `PersistentEntityCodec` also implements MongoDB's partial-update path
(`encodeUpdate`) via `DirtyCheckable`, producing `$set`/`$unset` documents
directly rather than rewriting the whole document.
+
+### Datastore
+
+- `MongoDatastore` (`core/.../mongo/MongoDatastore.java`) — owns index
creation/reconciliation against live MongoDB and transaction-capability
detection based on cluster topology.
+
+## Confirmed MongoDB-Specific Concepts (implemented — don't assume beyond this
list)
+
+- **Embedded documents & embedded collections** —
`Embedded`/`EmbeddedCollection` property kinds, with dedicated in-place
`$set`/`$unset` update logic distinct from top-level property updates.
+- **GeoJSON types** —
`grails.mongodb.geo.{Point,LineString,Polygon,MultiPoint,MultiLineString,MultiPolygon,GeometryCollection,Box,Circle,Sphere,Shape}`,
each with a custom-type marshaller. Query support: `near`, `nearSphere`,
`withinCircle`, `withinBox`, `withinPolygon`, `geoWithin`, `geoIntersects`.
Legacy `2d`/`2dsphere` indexes via `MongoAttribute.geoIndex(String)`.
+- **TTL indexes** — property-level `indexAttributes: [expireAfterSeconds: N]`
materializes a MongoDB TTL index, reconciled in place via `collMod` rather than
drop/rebuild (see Pitfalls).
+- **DBRef vs. embedding** — `MongoAttribute.reference` toggles whether a
`ToOne`/`ToMany` association is inline-embedded or a `com.mongodb.DBRef`.
Review Comment:
`MongoAttribute.reference` does not choose between a DBRef and an embedded
document. A false value writes the associated identifier. Embedding is `static
embedded`, a different property kind. An agent that sets `reference: false` to
embed a document will store an id instead.
Say that `reference` selects a DBRef versus a plain identifier, and point
embedding at `static embedded`.
##########
.agents/skills/mongodb-developer/SKILL.md:
##########
@@ -0,0 +1,122 @@
+---
+name: mongodb-developer
+description: Guide for working in the grails-data-mongodb module (GORM for
MongoDB) — codec-based document mapping, GeoJSON, embedded documents, TTL
indexes, multi-tenancy, and Testcontainers-backed tests. Use this when changing
code or tests under grails-data-mongodb.
+license: Apache-2.0
+---
+<!--
+SPDX-License-Identifier: Apache-2.0
+
+Licensed to the Apache Software Foundation (ASF) under one or more contributor
license agreements; and to You under the Apache License, Version 2.0.
+-->
+
+## What I Do
+
+- Provide repository-specific guidance for the `grails-data-mongodb` project
(GORM for MongoDB — a document-database GORM implementation, not a relational
one; do not bring Hibernate/binder mental models here).
+- Guide changes around `MongoMappingContext`,
`BsonPersistentEntityCodec`/`PersistentEntityCodec`, and the
codec-registry-based encode/decode pipeline.
+- Keep changes aligned with the Testcontainers-backed testing pattern this
module actually uses.
+
+## When to Use Me
+
+Activate this skill when working on the MongoDB module, especially for:
+
+- Changes under `grails-data-mongodb/**` (any of its 9 subprojects — see
Module Structure).
+- Document/collection mapping, codec, or GeoJSON-type work.
+- Index (including TTL) creation/reconciliation logic.
+- Multi-tenancy or multi-connection MongoDB work.
+
+## Module Context
+
+`grails-data-mongodb` has no `settings.gradle` of its own — it's part of the
root aggregate build, same as `grails-data-hibernate7`. All of root
`AGENTS.md`'s rules (jakarta, `@GrailsCompileStatic`,
CodeNarc/Checkstyle/PMD/SpotBugs, `dependencies.gradle`/BOM) apply here
unmodified.
+
+Nine Gradle projects live under this directory, mapped to real Gradle project
names (not always `grails-data-mongodb-<dirname>` — check before assuming):
+
+| Directory | Gradle project | Role |
+|---|---|---|
+| `core/` | `:grails-data-mongodb-core` | The actual GORM-for-MongoDB
implementation: `MongoDatastore`, `MongoMappingContext`, `MongoQuery`, GeoJSON
types |
+| `bson/` | `:grails-data-mongodb-bson` | Low-level, GORM-independent BSON
codec machinery (`BsonPersistentEntityCodec`, per-type property codecs,
hand-rolled JSON tokenizer) |
+| `ext/` | `:grails-data-mongodb-ext` | A single file, Groovy extension
methods on the raw MongoDB driver (`distinct`, `watch`/change streams,
`deleteMany`) |
+| `boot-plugin/` | `:grails-data-mongodb-spring-boot` | Spring Boot
auto-configuration (`MongoDbGormAutoConfiguration`) |
+| `spring-data/` | `:grails-data-mongodb-spring-data` | Lets GORM-for-MongoDB
and Spring Data MongoDB share a `MongoClient`/codecs/transaction |
+| `grails-plugin/` | `:grails-data-mongodb` (note: not `-grails-plugin`
suffixed) | Classic Grails plugin descriptor (`MongodbGrailsPlugin`); also
ships the app-facing `grails.test.mongodb.MongoSpec` test base via
`testFixtures` |
+| `gson-templates/` | `:grails-data-mongodb-gson-templates` | JSON Views
(`.gson`) for `ObjectId` and GeoJSON types |
+| `embedded/` | `:grails-data-mongodb-embedded` | Starts a real `mongod`
(Flapdoodle, a `compileOnly` dependency the application adds itself) before the
application context refreshes and publishes its URL into the configured
properties; for applications, not for this module's own tests |
+| `docs/` | `:grails-data-mongodb-docs` | Asciidoc manual + groovydoc
aggregation only, no source |
+
+## Key Classes and Responsibilities
+
+There is no single `GrailsDomainBinder`-equivalent class — the responsibility
splits across three cooperating layers:
+
+### Mapping (the binder equivalent)
+
+- `MongoMappingContext` (`core/.../mongo/config/MongoMappingContext.java`) —
owns the private inner `MongoDocumentMappingFactory extends
AbstractGormMappingFactory<MongoCollection, MongoAttribute>`, which is the
actual binder: forces the `_id` field name, applies the global
`stringIdDefaultStoredAs` default, wires codec-registry-backed custom types,
and registers all GeoJSON custom types.
+- `MongoCollection` (`core/.../config/MongoCollection.groovy`) — entity-level
mapping (collection name, database, `writeConcern`, indices, sort).
+- `MongoAttribute` (`core/.../config/MongoAttribute.groovy`) — property-level
mapping (`reference` for DBRef vs. embed, `field`, `geoIndex`, `index`,
`indexAttributes`).
+- `MappingBuilder.document { ... }`
(`core/.../grails/mongodb/mapping/MappingBuilder.groovy`) — the programmatic
DSL entry point.
+
+### Codec pipeline (the runtime read/write engine)
+
+- `BsonPersistentEntityCodec` (`bson/.../BsonPersistentEntityCodec.groovy`)
and its Mongo subclass `PersistentEntityCodec`
(`core/.../engine/codecs/PersistentEntityCodec.groovy`) — a static
`ENCODERS`/`DECODERS` registry keyed by `PersistentProperty` subtype
(`Identity`, `TenantId`, `Simple`, `Embedded`, `EmbeddedCollection`, `Custom`,
`Basic`, plus Mongo-specific `OneToOne`/`ManyToOne`/`OneToMany`/`ManyToMany`).
`encode`/`decode` walk `entity.persistentProperties` and dispatch per property
kind. `PersistentEntityCodec` also implements MongoDB's partial-update path
(`encodeUpdate`) via `DirtyCheckable`, producing `$set`/`$unset` documents
directly rather than rewriting the whole document.
+
+### Datastore
+
+- `MongoDatastore` (`core/.../mongo/MongoDatastore.java`) — owns index
creation/reconciliation against live MongoDB and transaction-capability
detection based on cluster topology.
+
+## Confirmed MongoDB-Specific Concepts (implemented — don't assume beyond this
list)
+
+- **Embedded documents & embedded collections** —
`Embedded`/`EmbeddedCollection` property kinds, with dedicated in-place
`$set`/`$unset` update logic distinct from top-level property updates.
+- **GeoJSON types** —
`grails.mongodb.geo.{Point,LineString,Polygon,MultiPoint,MultiLineString,MultiPolygon,GeometryCollection,Box,Circle,Sphere,Shape}`,
each with a custom-type marshaller. Query support: `near`, `nearSphere`,
`withinCircle`, `withinBox`, `withinPolygon`, `geoWithin`, `geoIntersects`.
Legacy `2d`/`2dsphere` indexes via `MongoAttribute.geoIndex(String)`.
+- **TTL indexes** — property-level `indexAttributes: [expireAfterSeconds: N]`
materializes a MongoDB TTL index, reconciled in place via `collMod` rather than
drop/rebuild (see Pitfalls).
+- **DBRef vs. embedding** — `MongoAttribute.reference` toggles whether a
`ToOne`/`ToMany` association is inline-embedded or a `com.mongodb.DBRef`.
+- **Schemaless/dynamic attributes** — `DynamicAttributes` trait support baked
into `BsonPersistentEntityCodec` and `MongoEntity`.
+- **Change streams** — `MongoExtensions.watch(...)`, a thin Groovy-extension
wrapper over the driver's native `watch()`, not a GORM-level abstraction.
+- **Multi-document transactions** — opt-in via `grails.mongodb.transactional`,
gated on cluster topology (`REPLICA_SET`/`SHARDED`/`LOAD_BALANCED` supported;
`STANDALONE` falls back with a one-time warning).
+- **Multi-tenancy / multiple named connections** — supported
(discriminator-based multi-tenancy, `grails.mongodb.connections`).
+
+### Not implemented — do not document or rely on these
+
+- **`shard "name"` in the mapping DSL is a no-op.** There is no `shard` method
on `Collection`/`MongoCollection`. The call silently falls through to the
generic `Entity.methodMissing` catch-all, which just records it as an ad hoc
property config — it never issues a MongoDB `shardCollection` command.
Verified: zero `shardCollection` calls anywhere in `core/src/main`. If you see
`shard "..."` in a mapping block, treat it as dead syntax, not a real feature.
+- **Capped collections** — not implemented anywhere in this module.
+
+## Testing Rules
+
+The module's own tests use a real MongoDB via Testcontainers; the `embedded`
subproject is a runtime feature for applications, not a test fallback. Docker
or Podman must be running on the host.
+
+- **`GrailsDataTckSpec<GrailsDataMongoTckManager>`** is the dominant pattern
(111+ specs) — the same shared TCK harness the Hibernate modules use
(`grails-datamapping-tck`), parameterized with `GrailsDataMongoTckManager`
(`core/src/test/groovy/.../GrailsDataMongoTckManager.groovy`), which starts a
real `MongoDBContainer` in `setupSpec()`/stops it in `cleanupSpec()`, and drops
all non-system databases after each test.
Review Comment:
This is not a full database reset. `GrailsDataMongoTckManager.destroy()`
clears documents and keeps the collections and their indexes. An index or
mapping spec that follows another feature in the same fork can inherit an index
the earlier feature created.
Say that documents are deleted and collections and indexes remain, and that
a spec which creates an index has to drop it itself.
--
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]