Migrations & Metadata Mapping
This guide covers how to create custom field mappings and metadata transformations in PikaORM, allowing you to handle complex data types, custom serialization, and specialized database storage requirements.
toColumn()transformForDB()transformFromDB()asId()asVersionColumn()Core Mapping Components
The FieldMapping class is the core component that defines how a field maps to a database column:
public class FieldMapping {
// Core configuration methods
FieldMapping toColumn(String columnName) // Set custom column name
FieldMapping asType(Class<?> dbClass) // Set database storage type
FieldMapping asId() // Mark as ID column
FieldMapping asVersionColumn() // Mark as version column
// Data transformation methods
FieldMapping transformForDB(UnaryOperator<Object> func) // Java โ Database
FieldMapping transformFromDB(UnaryOperator<Object> func) // Database โ Java
FieldMapping withVersionIncrementer(UnaryOperator<Object> incrementer)
}
Custom Mapping Examples
JSON Field Mapping
Store Java objects as JSON strings in the database using GSON:
public class HasCustomizedMetadata {
@Override
public void migrations() {
add(this::customMetadataExample);
}
public PikaMigration customMetadataExample() {
return makeMigration("customMetadataExample")
.up("""
CREATE TABLE IF NOT EXISTS foos (
id INTEGER PRIMARY KEY,
json TEXT
);
""")
.down("DROP TABLE foos;");
}
public static Mapping mapping() {
Gson gson = new Gson();
return new Mapping() {
@Override
public String mapToTable() { return "foos"; }
@Override
public FieldMapping mapField(Field field) {
return switch (field.getName()) {
case "ignoreMe" -> ignore(field);
case "myId" -> map(field).toColumn("id").asId();
case "json" -> map(field).asType(String.class)
.transformForDB(gson::toJson)
.transformFromDB(val -> gson.fromJson(
String.valueOf(val), Map.class));
default -> defaultMapping(field);
};
}
};
}
String ignoreMe;
long myId;
Map json;
// Getters and Setters...
}
All customized mapping is done by overriding the methods for metadata mapping with the
Mapping class and FieldMapping. We recommend using switch and
case statements for better readability with your custom classes.
Usage with ORM
The ORM will automatically detect and use your inner Mapping class when initializing the
schema or manipulating records.
@Test
public void testCustomMapping() {
PikaORM orm = new PikaORM("jdbc:sqlite:web.db")
.withLogLevel(TRACE)
.makeDefaultORM();
// The ORM automatically detects and uses the inner Mapping class
HasCustomizedMetadata entity = new HasCustomizedMetadata();
entity.setMap(Map.of("foo", 1.0, "bar", 2.0));
orm.insert(entity);
var retrieved = orm.find(HasCustomizedMetadata.class).byId(entity.getId());
}
Overall the sky is the limit! We can't wait to see what kind of crazy migrations and custom metadata architecture the community could create โ we hope these examples can point you in the right direction.