Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
80e780c
fix(db): stop closing shared SessionFactory in flag service
TheMeinerLP Apr 18, 2026
044c12d
fix(db): return HomePosition model from entityToModel mapper
TheMeinerLP Apr 18, 2026
97ad743
fix(db): fail fast when the Hibernate SessionFactory cannot be built
TheMeinerLP Apr 18, 2026
dad15bf
fix(plugin): disable plugin cleanly when bootstrap throws
TheMeinerLP Apr 18, 2026
f27ba63
fix(db): correct chunk-removal return value and parameter binding
TheMeinerLP Apr 18, 2026
2706486
fix(db): tighten transaction boundaries in land service
TheMeinerLP Apr 18, 2026
63ef306
fix(db): add explicit join columns and id-based equality to LandEntity
TheMeinerLP Apr 18, 2026
35101bf
fix(db): make FlagContainerEntity the inverse side of the Land link
TheMeinerLP Apr 18, 2026
3c1dbd6
fix(db): switch LandMemberEntity.member to ManyToOne
TheMeinerLP Apr 18, 2026
a2cd12e
fix(db): add unique, NOT NULL and length constraints to LandPlayerEntity
TheMeinerLP Apr 18, 2026
b55efe2
fix(db): enforce NOT NULL on HomePositionEntity columns
TheMeinerLP Apr 18, 2026
9cc26f3
fix(db): add name column and id-based equality to LandAreaEntity
TheMeinerLP Apr 18, 2026
1958e95
fix(db): prevent duplicate claims on the same chunk
TheMeinerLP Apr 18, 2026
bd69263
fix(db): constrain LandRoleFlagEntity columns and de-duplicate
TheMeinerLP Apr 18, 2026
7a9f300
fix(db): constrain LandNaturalFlagEntity columns and de-duplicate
TheMeinerLP Apr 18, 2026
2435a10
fix(db): constrain LandEntityCapFlagEntity columns and de-duplicate
TheMeinerLP Apr 18, 2026
118ad11
fix(db): use ClaimedChunkMappingStrategy for chunk mapping
TheMeinerLP Apr 18, 2026
ff604dd
fix(db): use per-flag strategies when mapping FlagContainer children
TheMeinerLP Apr 18, 2026
439bb0d
docs(db): document session-open requirement for LandMappingStrategy
TheMeinerLP Apr 18, 2026
72b5873
chore(config): consolidate entity mappings into common/hibernate.cfg.xml
TheMeinerLP Apr 18, 2026
ff3336e
chore(config): drop duplicate plugin-side hibernate.cfg.xml
TheMeinerLP Apr 18, 2026
bfbd9d6
chore(test): run common tests against in-memory H2
TheMeinerLP Apr 18, 2026
cb1ad90
chore(build): pull in H2 for the common test classpath
TheMeinerLP Apr 18, 2026
062a92a
chore(test): remove obsolete constants.kt
TheMeinerLP Apr 18, 2026
91efbb0
chore(test): remove obsolete TestDatabaseServiceImpl.kt
TheMeinerLP Apr 18, 2026
cd2340d
chore(test): remove obsolete TestLandFlagService.kt
TheMeinerLP Apr 18, 2026
d6fb427
chore(test): remove obsolete TestLandPlayerService.kt
TheMeinerLP Apr 18, 2026
22f1d47
chore(test): remove obsolete TestLandService.kt
TheMeinerLP Apr 18, 2026
b8b7df1
chore(test): remove obsolete TestPandorasClusterApiImpl.kt
TheMeinerLP Apr 18, 2026
3e49c13
chore(build): drop unused Liquibase plugin alias
TheMeinerLP Apr 18, 2026
ae654f6
chore(build): drop Liquibase and migrate Shadow to com.gradleup.shadow
TheMeinerLP Apr 18, 2026
ac3eee1
fix(db): split bag collections in getLandArea to avoid MultipleBagFet…
TheMeinerLP Apr 18, 2026
0ea331e
fix(db): persist createLand graph in FK-dependency order
TheMeinerLP Apr 18, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@
import java.util.List;
import java.util.function.Function;

/**
* Must be invoked while the Hibernate {@link org.hibernate.Session} that loaded the entity
* is still open — this strategy traverses {@code land}, {@code naturalFlags},
* {@code roleFlags} and {@code entityCapFlags} lazy associations.
*/
public final class FlagContainerMappingStrategy implements MapperStrategy {

@Override
Expand All @@ -27,25 +32,33 @@ public Function<PandorasModel, PandorasModel> entityToModel() {
if (entity == null) return null;
if (!(entity instanceof FlagContainerDto flagContainer)) return null;

MappingContext mappingContext = MappingContext.create();
mappingContext.setMappingStrategy(LandMappingStrategy.create());
mappingContext.setMappingType(MapperType.ENTITY_TO_MODEL);

Land land = (Land) mappingContext.doMapping(flagContainer.land());
MappingContext landCtx = MappingContext.create();
landCtx.setMappingStrategy(LandMappingStrategy.create());
landCtx.setMappingType(MapperType.ENTITY_TO_MODEL);
Land land = (Land) landCtx.doMapping(flagContainer.land());

MappingContext naturalCtx = MappingContext.create();
naturalCtx.setMappingStrategy(NaturalFlagMappingStrategy.create());
naturalCtx.setMappingType(MapperType.ENTITY_TO_MODEL);
List<LandNaturalFlag> naturalFlags = flagContainer.naturalFlags()
.stream()
.map(naturalFlagDBO -> (LandNaturalFlag) mappingContext.doMapping(naturalFlagDBO))
.map(flag -> (LandNaturalFlag) naturalCtx.doMapping(flag))
.toList();

MappingContext roleCtx = MappingContext.create();
roleCtx.setMappingStrategy(RoleFlagMappingStrategy.create());
roleCtx.setMappingType(MapperType.ENTITY_TO_MODEL);
List<LandRoleFlag> roleFlags = flagContainer.roleFlags()
.stream()
.map(naturalFlagDBO -> (LandRoleFlag) mappingContext.doMapping(naturalFlagDBO))
.map(flag -> (LandRoleFlag) roleCtx.doMapping(flag))
.toList();

MappingContext capCtx = MappingContext.create();
capCtx.setMappingStrategy(EntityCapFlagMappingStrategy.create());
capCtx.setMappingType(MapperType.ENTITY_TO_MODEL);
List<LandEntityCapFlag> entityCapFlags = flagContainer.entityCapFlags()
.stream()
.map(naturalFlagDBO -> (LandEntityCapFlag) mappingContext.doMapping(naturalFlagDBO))
.map(flag -> (LandEntityCapFlag) capCtx.doMapping(flag))
.toList();

return new FlagContainer(flagContainer.id(), land, naturalFlags, roleFlags, entityCapFlags);
Expand All @@ -59,27 +72,35 @@ public Function<PandorasModel, PandorasModel> modelToEntity() {
if (model == null) return null;
if(!(model instanceof FlagContainer flagContainer)) return null;

MappingContext mappingContext = MappingContext.create();
mappingContext.setMappingStrategy(LandMappingStrategy.create());
mappingContext.setMappingType(MapperType.MODEL_TO_ENTITY);
MappingContext landCtx = MappingContext.create();
landCtx.setMappingStrategy(LandMappingStrategy.create());
landCtx.setMappingType(MapperType.MODEL_TO_ENTITY);
LandEntity land = (LandEntity) landCtx.doMapping(flagContainer.getLand());

MappingContext naturalCtx = MappingContext.create();
naturalCtx.setMappingStrategy(NaturalFlagMappingStrategy.create());
naturalCtx.setMappingType(MapperType.MODEL_TO_ENTITY);
List<LandNaturalFlagEntity> naturalFlags = flagContainer.getNaturalFlags()
.stream()
.map(naturalFlagDBO -> (LandNaturalFlagEntity) mappingContext.doMapping(naturalFlagDBO))
.map(flag -> (LandNaturalFlagEntity) naturalCtx.doMapping(flag))
.toList();

MappingContext roleCtx = MappingContext.create();
roleCtx.setMappingStrategy(RoleFlagMappingStrategy.create());
roleCtx.setMappingType(MapperType.MODEL_TO_ENTITY);
List<LandRoleFlagEntity> roleFlags = flagContainer.getRoleFlags()
.stream()
.map(naturalFlagDBO -> (LandRoleFlagEntity) mappingContext.doMapping(naturalFlagDBO))
.map(flag -> (LandRoleFlagEntity) roleCtx.doMapping(flag))
.toList();

MappingContext capCtx = MappingContext.create();
capCtx.setMappingStrategy(EntityCapFlagMappingStrategy.create());
capCtx.setMappingType(MapperType.MODEL_TO_ENTITY);
List<LandEntityCapFlagEntity> entityCapFlags = flagContainer.getEntityCapFlags()
.stream()
.map(naturalFlagDBO -> (LandEntityCapFlagEntity) mappingContext.doMapping(naturalFlagDBO))
.map(flag -> (LandEntityCapFlagEntity) capCtx.doMapping(flag))
.toList();

LandEntity land = (LandEntity) mappingContext.doMapping(flagContainer.getLand());

return new FlagContainerEntity(flagContainer.getId(), land, naturalFlags, roleFlags, entityCapFlags);
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
import java.util.List;
import java.util.function.Function;

/**
* Must be invoked while the Hibernate {@link org.hibernate.Session} that loaded the entity
* is still open — this strategy traverses {@code members} and {@code chunks} lazy collections.
*/
public final class LandAreaMappingStrategy implements MapperStrategy {

public static LandAreaMappingStrategy create() {
Expand Down Expand Up @@ -61,7 +65,7 @@ private Land getLand(LandDto land) {

private List<ClaimedChunk> getChunks(List<ClaimedChunkDto> chunks) {
MappingContext mappingContext = MappingContext.create();
mappingContext.setMappingStrategy(create());
mappingContext.setMappingStrategy(ClaimedChunkMappingStrategy.create());
mappingContext.setMappingType(MapperType.ENTITY_TO_MODEL);
return chunks.stream().map(chunk -> (ClaimedChunk) mappingContext.doMapping(chunk)).toList();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@
import java.util.List;
import java.util.function.Function;

/**
* Must be invoked while the Hibernate {@link org.hibernate.Session} that loaded the entity
* is still open — this strategy traverses {@code owner}, {@code home}, {@code flagContainer},
* and {@code areas}. Use {@code DatabaseLandService#getLands()} as the canonical JOIN FETCH pattern.
*/
public final class LandMappingStrategy implements MapperStrategy {

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public Function<PandorasModel, PandorasModel> entityToModel() {
return entity -> {
if(entity == null) return null;
if(!(entity instanceof HomePositionEntity home)) return null;
return new HomePositionEntity(home.id(), home.world(), home.posX(), home.posY(), home.posZ(), home.yaw(), home.pitch());
return new HomePosition(home.id(), home.world(), home.posX(), home.posY(), home.posZ(), home.yaw(), home.pitch());
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,27 @@
import net.onelitefeather.pandorascluster.dto.chunk.ClaimedChunkDto;
import net.onelitefeather.pandorascluster.dto.land.LandAreaDto;

import java.util.Objects;

@Entity
@Table(name = "land_chunks")
@Table(
name = "land_chunks",
uniqueConstraints = @UniqueConstraint(
name = "uk_land_chunks_area_chunk",
columnNames = {"landArea_id", "chunk_index"}
)
)
public final class ClaimedChunkEntity implements ClaimedChunkDto {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column
@Column(name = "chunk_index", nullable = false)
private Long chunkIndex;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "landArea_id")
@JoinColumn(name = "landArea_id", nullable = false)
private LandAreaEntity landArea;

public ClaimedChunkEntity() {
Expand All @@ -43,4 +51,17 @@ public Long chunkIndex() {
public LandAreaDto landArea() {
return landArea;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof ClaimedChunkEntity that)) return false;
if (id == null || that.id == null) return false;
return Objects.equals(id, that.id);
}

@Override
public int hashCode() {
return id == null ? System.identityHashCode(this) : Objects.hashCode(id);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

import java.util.Collections;
import java.util.List;
import java.util.Objects;

@Entity
@Table(name = "flag_containers")
Expand All @@ -28,7 +29,7 @@ public final class FlagContainerEntity implements FlagContainerDto {
@OneToMany(fetch = FetchType.LAZY, mappedBy = "flagContainer")
private List<LandEntityCapFlagEntity> entityCapFlags;

@OneToOne
@OneToOne(mappedBy = "flagContainerEntity")
private LandEntity land;

public static final FlagContainerEntity EMPTY = new FlagContainerEntity(
Expand Down Expand Up @@ -83,4 +84,17 @@ public List<RoleFlagDto> roleFlags() {
public LandDto land() {
return this.land;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof FlagContainerEntity that)) return false;
if (id == null || that.id == null) return false;
return Objects.equals(id, that.id);
}

@Override
public int hashCode() {
return id == null ? System.identityHashCode(this) : Objects.hashCode(id);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,30 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Objects;

@Entity
@Table(name = "entityCap_flags")
@Table(
name = "entityCap_flags",
uniqueConstraints = @UniqueConstraint(
name = "uk_entitycap_flags_container_name",
columnNames = {"flagContainer_id", "name"}
)
)
public final class LandEntityCapFlagEntity implements EntityCapFlagDto {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column
@Column(name = "name", length = 64, nullable = false)
private String name;

@Column
@Column(name = "spawn_limit", nullable = false)
private Integer spawnLimit;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "flagContainer_id")
@JoinColumn(name = "flagContainer_id", nullable = false)
private FlagContainerEntity flagContainer;


Expand Down Expand Up @@ -56,4 +64,17 @@ public Integer spawnLimit() {
public FlagContainerDto flagContainer() {
return this.flagContainer;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof LandEntityCapFlagEntity that)) return false;
if (id == null || that.id == null) return false;
return Objects.equals(id, that.id);
}

@Override
public int hashCode() {
return id == null ? System.identityHashCode(this) : Objects.hashCode(id);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,30 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Objects;

@Entity
@Table(name = "natural_flags")
@Table(
name = "natural_flags",
uniqueConstraints = @UniqueConstraint(
name = "uk_natural_flags_container_name",
columnNames = {"flagContainer_id", "name"}
)
)
public final class LandNaturalFlagEntity implements NaturalFlagDto {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column
@Column(name = "name", length = 64, nullable = false)
private String name;

@Column
@Column(name = "state", nullable = false)
private boolean state;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "flagContainer_id")
@JoinColumn(name = "flagContainer_id", nullable = false)
private FlagContainerEntity flagContainer;

public LandNaturalFlagEntity() {
Expand Down Expand Up @@ -54,4 +62,17 @@ public boolean state() {
public FlagContainerDto flagContainer() {
return flagContainer;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof LandNaturalFlagEntity that)) return false;
if (id == null || that.id == null) return false;
return Objects.equals(id, that.id);
}

@Override
public int hashCode() {
return id == null ? System.identityHashCode(this) : Objects.hashCode(id);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,34 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Objects;

@Entity
@Table(name = "role_flags")
@Table(
name = "role_flags",
uniqueConstraints = @UniqueConstraint(
name = "uk_role_flags_container_name",
columnNames = {"flagContainer_id", "name"}
)
)
public final class LandRoleFlagEntity implements RoleFlagDto {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column
@Column(name = "name", length = 64, nullable = false)
private String name;

@Column
@Column(name = "state", nullable = false)
private boolean state;

@Enumerated(EnumType.STRING)
@Column(name = "role", length = 32, nullable = false)
private LandRole role;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "flagContainer_id")
@JoinColumn(name = "flagContainer_id", nullable = false)
private FlagContainerEntity flagContainer;

public LandRoleFlagEntity() {
Expand Down Expand Up @@ -65,4 +74,16 @@ public FlagContainerDto flagContainer() {
return this.flagContainer;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof LandRoleFlagEntity that)) return false;
if (id == null || that.id == null) return false;
return Objects.equals(id, that.id);
}

@Override
public int hashCode() {
return id == null ? System.identityHashCode(this) : Objects.hashCode(id);
}
}
Loading