Complete persistence metadata foundation
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
package com.livingworld.data.saved;
|
||||
|
||||
/**
|
||||
* Immutable metadata for saved game data.
|
||||
*
|
||||
* @param schemaVersion the schema version number (must be > 0)
|
||||
* @param modVersion the mod version string (must not be blank)
|
||||
* @param createdAt the timestamp when the save was created
|
||||
* @param updatedAt the timestamp when the save was last updated
|
||||
*/
|
||||
public record SaveMetadata(
|
||||
int schemaVersion,
|
||||
String modVersion,
|
||||
long createdAt,
|
||||
long updatedAt
|
||||
) {
|
||||
|
||||
/**
|
||||
* Constructs a {@link SaveMetadata} and validates all fields.
|
||||
*
|
||||
* @param schemaVersion the schema version number (must be > 0)
|
||||
* @param modVersion the mod version string (must not be blank)
|
||||
* @param createdAt the timestamp when the save was created
|
||||
* @param updatedAt the timestamp when the save was last updated
|
||||
* @throws IllegalArgumentException if {@code schemaVersion} is not greater than 0
|
||||
* @throws IllegalArgumentException if {@code modVersion} is blank
|
||||
* @throws IllegalArgumentException if {@code updatedAt} is less than {@code createdAt}
|
||||
*/
|
||||
public SaveMetadata {
|
||||
if (schemaVersion <= 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"schemaVersion must be greater than 0, got: " + schemaVersion);
|
||||
}
|
||||
|
||||
if (modVersion == null || modVersion.isBlank()) {
|
||||
throw new IllegalArgumentException("modVersion must not be blank");
|
||||
}
|
||||
|
||||
if (updatedAt < createdAt) {
|
||||
throw new IllegalArgumentException(
|
||||
"updatedAt (" + updatedAt + ") must be >= createdAt (" + createdAt + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,56 +1,47 @@
|
||||
package com.livingworld.data.serialization;
|
||||
|
||||
/**
|
||||
* Abstraction for writing save data to a persistence target.
|
||||
*
|
||||
* <p>This interface hides the underlying storage format (JSON, NBT, etc.) from
|
||||
* modules. Modules write their data through this abstraction without knowing
|
||||
* how or where it is persisted.</p>
|
||||
* Interface for writing data values with associated keys.
|
||||
*/
|
||||
public interface PersistenceWriter {
|
||||
|
||||
/**
|
||||
* Writes a string value with the given key.
|
||||
* Writes a string value.
|
||||
*
|
||||
* @param key the identifier for this value (must not be null or blank)
|
||||
* @param value the string to write
|
||||
* @throws IllegalArgumentException if key is null or blank
|
||||
* @param key the key identifier
|
||||
* @param value the string value to write
|
||||
*/
|
||||
void writeString(String key, String value);
|
||||
|
||||
/**
|
||||
* Writes an integer value with the given key.
|
||||
* Writes an integer value.
|
||||
*
|
||||
* @param key the identifier for this value (must not be null or blank)
|
||||
* @param value the integer to write
|
||||
* @throws IllegalArgumentException if key is null or blank
|
||||
* @param key the key identifier
|
||||
* @param value the integer value to write
|
||||
*/
|
||||
void writeInt(String key, int value);
|
||||
|
||||
/**
|
||||
* Writes a long value with the given key.
|
||||
* Writes a long value.
|
||||
*
|
||||
* @param key the identifier for this value (must not be null or blank)
|
||||
* @param value the long to write
|
||||
* @throws IllegalArgumentException if key is null or blank
|
||||
* @param key the key identifier
|
||||
* @param value the long value to write
|
||||
*/
|
||||
void writeLong(String key, long value);
|
||||
|
||||
/**
|
||||
* Writes a double value with the given key.
|
||||
* Writes a double value.
|
||||
*
|
||||
* @param key the identifier for this value (must not be null or blank)
|
||||
* @param value the double to write
|
||||
* @throws IllegalArgumentException if key is null or blank
|
||||
* @param key the key identifier
|
||||
* @param value the double value to write
|
||||
*/
|
||||
void writeDouble(String key, double value);
|
||||
|
||||
/**
|
||||
* Writes a boolean value with the given key.
|
||||
* Writes a boolean value.
|
||||
*
|
||||
* @param key the identifier for this value (must not be null or blank)
|
||||
* @param value the boolean to write
|
||||
* @throws IllegalArgumentException if key is null or blank
|
||||
* @param key the key identifier
|
||||
* @param value the boolean value to write
|
||||
*/
|
||||
void writeBoolean(String key, boolean value);
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.livingworld.data.saved;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class SaveMetadataTest {
|
||||
|
||||
@Test
|
||||
void acceptsVersionedChronologicalMetadata() {
|
||||
SaveMetadata metadata = new SaveMetadata(1, "0.1.0", 100L, 200L);
|
||||
|
||||
assertEquals(1, metadata.schemaVersion());
|
||||
assertEquals("0.1.0", metadata.modVersion());
|
||||
assertEquals(100L, metadata.createdAt());
|
||||
assertEquals(200L, metadata.updatedAt());
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsInvalidSchemaVersion() {
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> new SaveMetadata(0, "0.1.0", 100L, 100L));
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsBlankModVersion() {
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> new SaveMetadata(1, " ", 100L, 100L));
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsUpdateBeforeCreation() {
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> new SaveMetadata(1, "0.1.0", 200L, 100L));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user