The SQLite API has built-in support for database migrations. Migrations don't happen automatically, but the API provides methods for doing so, and it is extremely simple to wire this up.
Configuring Migrations
First, create a List of MigrationStep objects. Each object consists of the DB version and a transaction.
List<MigrationStep> steps = List.of(
new MigrationStep(1, tx -> {
tx.execute("""
CREATE TABLE IF NOT EXISTS regions (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL
);
""");
}),
new MigrationStep(2, tx -> {
tx.execute("""
CREATE VIRTUAL TABLE IF NOT EXISTS region_index
USING rtree(id, minX, maxX, minZ, maxZ);
""");
})
);
This migration on version 1 would create a regions table, and on version 2 would create a regions index using rtree.
Running Migrations
Once you have this list of MigrationStep objects created, initialize a UserVersionMigrator and call its migrate method, providing your instance of SqliteDatabase as its sole parameter.
new UserVersionMigrator("anchor_table", steps).migrate(db);
The migrator will automatically look at your DB's version and run the migrations that need to be run. The version is stored in the user_version pragma, so developers should never change this value manually.
To prevent the migrator from attempting to run migrations on a brand new DB, it requires an "anchor table". The anchor table is just a table that should exist in the database. If it doesn't exist, then it's assumed the database is being initialized for the first time and migrations are skipped.