refactor(api): implementation of sealed unions - #232
Merged
Conversation
Each of the 9 flag operations wrapped the SessionFactory in try-with-resources, closing the shared singleton after the first call. Subsequent flag operations then failed with "SessionFactory is closed". Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The entity-to-model direction was constructing a new HomePositionEntity instead of the HomePosition API model, so callers received an entity where they expected the DTO. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Previously a HibernateException was swallowed, databaseService was left null, and the plugin continued to enable with null service references, NPEing on the first command. Throw IllegalStateException instead so the plugin entry point can log and disable cleanly. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wrap the PandorasClusterImpl construction in onEnable so a failed Hibernate bootstrap no longer leaves the plugin half-initialized — the PluginManager disables the plugin and the error is surfaced in the log. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- removeClaimedChunk hard-coded return false, so callers never saw a successful deletion. - getClaimedChunk declared a :chunkIndex named parameter but never bound it, making the query return an arbitrary row. - Document unclaimArea as a best-effort composition of already- transactional sub-operations so future readers do not assume atomicity. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- createLand now persists the land, its home, its flag container, the default LandArea and its initial ClaimedChunk in a single transaction so a partial failure rolls back cleanly. Previously the area creation ran after the outer commit, leaving orphan rows on exception. - unclaimLand moves its cross-service sub-calls (removeFlagsFromLand, landAreaService::unclaimArea) outside the session, then loads the LandEntity by id and removes it along with its HomePositionEntity. The old code called session.remove(land) with the API model. - getLands eagerly fetches owner, home, flagContainer and areas to prevent LazyInitializationException after the session closes. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Without @joincolumn, Hibernate generated implementation-defined FK column names. Bind owner/home/flagContainerEntity to owner_id, home_id and flag_container_id respectively, all NOT NULL, and mark the flag_container side as the owning side of the OneToOne (the inverse mappedBy moves to FlagContainerEntity). Add id-based equals/hashCode with a null-id identity fallback. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Drop the unmapped OneToOne so the LandEntity side alone owns the FK column (flag_container_id). Add id-based equals/hashCode. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
A player can be a member of multiple land areas, so the OneToOne was semantically wrong — the second addLandMember for the same player would violate the uniqueness implied by OneToOne. Also add an explicit member_id join column. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replace dialect-specific columnDefinition with portable length / nullable / unique annotations. uuid becomes the natural unique key (length 36), name is length 16 NOT NULL. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
A position without world + coordinates has no meaning; declare every column non-nullable and give world a 64-char bound. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
name had no @column annotation, so Hibernate generated an unbounded nullable column. Declare length 64 NOT NULL and add id-based equals/hashCode. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Rename chunkIndex to chunk_index and add a composite unique constraint on (landArea_id, chunk_index) so the same chunk can no longer be claimed twice in the same area. Also add id-based equals/hashCode. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add length/NOT NULL on name, state, role and flagContainer_id, plus a uk_role_flags_container_name unique constraint so the same role flag cannot be persisted twice for one container. Add id-based equality. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add length/NOT NULL on name, state and flagContainer_id, plus a uk_natural_flags_container_name unique constraint. Add id-based equality. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add length/NOT NULL on name, spawn_limit and flagContainer_id, plus a uk_entitycap_flags_container_name unique constraint. Add id-based equality. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
getChunks was feeding ClaimedChunkDto instances into a new LandAreaMappingStrategy, so the instanceof check failed and every chunk came back null. Use ClaimedChunkMappingStrategy.create() instead. Also document that the strategy must run inside an open Hibernate session. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The three flag collections were previously mapped through a single LandMappingStrategy instance, so every NaturalFlag / RoleFlag / EntityCapFlag failed the instanceof check and came back null. Wire each collection to its own NaturalFlagMappingStrategy / RoleFlagMappingStrategy / EntityCapFlagMappingStrategy and keep the land link on its own context. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The common module builds the SessionFactory, so the <mapping class="…"/> list lives here. The plugin-side hibernate.cfg.xml becomes redundant and is removed in a follow-up commit. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Entity mappings now live in common/hibernate.cfg.xml. Keeping two copies invited drift — the plugin copy had the mappings while the common copy had the dialect/connection block. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The test config pointed at localhost PostgreSQL, so a developer needed a running Postgres container to execute :common:test. Switch to an in-memory H2 database with H2Dialect and create-drop so tests can run in isolation. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
New in-memory test configuration in connection.cfg.xml needs the H2 driver at runtime for :common:test. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The common module does not apply the Kotlin plugin, so this test support file never compiled. It also referenced DBO classes that were removed long ago. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Dead test support code referencing removed DatabaseService contract. Common module has no Kotlin plugin applied so it never compiled. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Dead test support code referencing removed DBO types. Common module has no Kotlin plugin applied so it never compiled. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Dead test support code referencing removed DBO types. Common module has no Kotlin plugin applied so it never compiled. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Dead test support code referencing removed DBO types. Common module has no Kotlin plugin applied so it never compiled. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Dead test support code referencing a removed PandorasClusterApi interface and the wrong service constructors. Common module has no Kotlin plugin applied so it never compiled. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The liquibase Gradle plugin was applied but never configured — no
changelog file, no liquibase {} block, no activities. Schema is owned
by Hibernate via hbm2ddl.auto=update, so remove the dead alias.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ntities in PandorasCluster interface
…thods for LandArea, Land, and LandWorld
…ntity in hibernate configuration
…s for entity conversion
… to return results directly
…for database representation
…ved encapsulation
…r improved consistency
…ldEntity to LandEntity for improved data structure
…eadability and simplicity
…ed structure and readability
…oved structure and readability
…kResult for improved clarity
… structure and clarity
…and improve query efficiency
theShadowsDust
marked this pull request as ready for review
August 3, 2026 21:01
…nd improve land creation handling
…Position method for improved clarity
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Overview
This is a major architectural refactor that transforms PandorasCluster's API and data layer from a DTO-based mapper framework to a sealed-union result type pattern, combined with entity-to-record conversion. The refactor eliminates the abstraction gap between DTOs and entities while introducing type-safe, discriminated error handling throughout the service layer.
Submitter Checklist
@since TODO.