Database migration management using Migratus.
This namespace provides functions to manage database schema migrations:
Migrations are discovered from the application's migrations/ directory and
from any library manifests published on the classpath.
Database migration management using Migratus. This namespace provides functions to manage database schema migrations: - Run pending migrations (up) - Rollback migrations (down) - Check migration status - Create new migrations Migrations are discovered from the application's `migrations/` directory and from any library manifests published on the classpath.
(auto-migrate)Automatically runs pending migrations on application startup.
This function is safe to call on every startup - it only runs pending migrations and is idempotent.
Prefer :migrate-on-start? on :wagoe/db-context, which is what boots the
schema now. It migrates the pool the application is about to query rather
than re-reading config.edn for the first :active database, and it lets a
failure fail the boot — this swallows one and returns false, so the app
starts with whatever schema it happened to have (BOU-485).
Returns: true if migrations ran successfully, false otherwise
Automatically runs pending migrations on application startup. This function is safe to call on every startup - it only runs pending migrations and is idempotent. Prefer `:migrate-on-start?` on `:wagoe/db-context`, which is what boots the schema now. It migrates the pool the application is about to query rather than re-reading config.edn for the first `:active` database, and it lets a failure fail the boot — this swallows one and returns false, so the app starts with whatever schema it happened to have (BOU-485). Returns: true if migrations ran successfully, false otherwise
(capturing-source resolved project-dir)How to describe what captures migrations/, or nil when it is the project.
nil means the project directory is what gets read, which is the only layout with nothing at risk.
How to describe what captures `migrations/`, or nil when it is the project. nil means the project directory is what gets read, which is the only layout with nothing at risk.
(create-config read-config)Narrow a read config to one suitable for creating a migration.
:migration-dir must be a single directory string here. The read config
carries the discovered vector of every directory on the classpath, which
up, status and rollback accept — but migratus/create casts it to
String, so bb migrate create died with a ClassCastException and a stack
trace for everyone who followed bb migrate --help (BOU-271).
The override is the project directory rather than the first element of the discovered list: a migration you author belongs to your project, and a dependency reordering that list must not decide where your files land.
Narrow a read config to one suitable for *creating* a migration. `:migration-dir` must be a single directory string here. The read config carries the discovered vector of every directory on the classpath, which `up`, `status` and `rollback` accept — but `migratus/create` casts it to String, so `bb migrate create` died with a ClassCastException and a stack trace for everyone who followed `bb migrate --help` (BOU-271). The override is the project directory rather than the first element of the discovered list: a migration you author belongs to your project, and a dependency reordering that list must not decide where your files land.
(create-destination)(create-destination resolved)The directory migratus/create will actually write to.
Not the one create-config names, when they differ: a resources/migrations
takes the file while the config still says migrations/. Reporting the
config value is why bb migrate create printed "Migration files created in:
migrations/" for files it had written to resources/.
A jar cannot be written to, so it falls back to the project directory — the create path is a development command, and migratus fails on its own there.
The directory `migratus/create` will actually write to. Not the one `create-config` names, when they differ: a `resources/migrations` takes the file while the config still says `migrations/`. Reporting the config value is why `bb migrate create` printed "Migration files created in: migrations/" for files it had written to resources/. A jar cannot be written to, so it falls back to the project directory — the create path is a development command, and migratus fails on its own there.
(create-migration name)Creates a new migration file pair (up and down).
Args: name: Migration name (e.g., 'add-user-table')
Returns: Map with :up and :down file paths
Note: This creates timestamped migration files in migrations/ directory
Creates a new migration file pair (up and down). Args: name: Migration name (e.g., 'add-user-table') Returns: Map with :up and :down file paths Note: This creates timestamped migration files in migrations/ directory
(create-migratus-config db-config)Creates Migratus configuration from database config.
Args: db-config: Database configuration map with :datasource
Returns: Migratus configuration map
Creates Migratus configuration from database config. Args: db-config: Database configuration map with :datasource Returns: Migratus configuration map
(discover-migration-dirs)Return the complete set of migration directories visible to the application.
The root application keeps using migrations/. Libraries can contribute
additional Migratus-compatible directories by publishing a
wagoe/migration-paths.edn resource on the classpath.
Return the complete set of migration directories visible to the application. The root application keeps using `migrations/`. Libraries can contribute additional Migratus-compatible directories by publishing a `wagoe/migration-paths.edn` resource on the classpath.
(ensure-project-migration-dir!)(ensure-project-migration-dir! dir)Create migrations/ if absent, so migratus resolves the name to it.
Without this, creating the first migration in a fresh project lands it under resources/ — a different directory from the one the scaffolder uses, and the start of the shadowing above.
Takes the directory for the same reason as shadowed-migration-dirs: the
default is relative to the working directory, so the no-arg form can only be
exercised against the repository itself.
Create `migrations/` if absent, so migratus resolves the name to it. Without this, creating the first migration in a fresh project lands it under resources/ — a different directory from the one the scaffolder uses, and the start of the shadowing above. Takes the directory for the same reason as `shadowed-migration-dirs`: the default is relative to the working directory, so the no-arg form can only be exercised against the repository itself.
(get-migration-config)Gets migration configuration for the active database.
Returns: Migratus configuration map
Throws: Exception if database configuration cannot be loaded
Gets migration configuration for the active database. Returns: Migratus configuration map Throws: Exception if database configuration cannot be loaded
(init)Initializes the migration system by creating the schema_migrations table.
Returns: nil
Initializes the migration system by creating the schema_migrations table. Returns: nil
(migrate)Runs all pending database migrations.
Returns: nil
Throws: Exception if migration fails
Runs all pending database migrations. Returns: nil Throws: Exception if migration fails
(migrate-datasource! datasource)Run pending migrations against datasource.
migrate finds its database by re-reading config.edn and taking the first
:active entry. That is right for the CLI, which has nothing else to go on,
and wrong at boot: the application already holds the pool it is about to
query, and an application with more than one active database would migrate
whichever came first rather than the one its context was built for.
Args: datasource - the javax.sql.DataSource to migrate
Returns: nil
Throws: Exception if migration fails
Run pending migrations against `datasource`. `migrate` finds its database by re-reading config.edn and taking the first `:active` entry. That is right for the CLI, which has nothing else to go on, and wrong at boot: the application already holds the pool it is about to query, and an application with more than one active database would migrate whichever came first rather than the one its context was built for. Args: datasource - the javax.sql.DataSource to migrate Returns: nil Throws: Exception if migration fails
(migration-status)Gets the current migration status.
Returns: Map with:
Gets the current migration status. Returns: Map with: - :applied - List of applied migration IDs - :total-applied - Count of applied migrations - :pending - List of pending migration IDs - :total-pending - Count of pending migrations
(pending-list)Lists all pending migrations.
Returns: Vector of migration IDs
Lists all pending migrations. Returns: Vector of migration IDs
(print-status)Prints the current migration status in a human-readable format.
Returns: nil (prints to stdout)
Prints the current migration status in a human-readable format. Returns: nil (prints to stdout)
Where new migrations are written.
Library-contributed directories are read from, never written to: a migration
you author belongs to your project, not to a dependency. Kept as a single
string because Migratus wants one directory when creating, and because
create-migration must not be handed the whole discovered vector (BOU-271).
Where new migrations are written. Library-contributed directories are read from, never written to: a migration you author belongs to your project, not to a dependency. Kept as a single string because Migratus wants one directory when creating, and because `create-migration` must not be handed the whole discovered vector (BOU-271).
(refuse-shadowed-migration-dirs!)Throw when migrations sit in a directory nothing reads.
Public for the same reason shadowed-migration-dirs is: both migrate and
migrate-datasource! depend on it, and a test asserts neither opts out.
Outside the try in get-migration-config: that handler rewraps everything
as "Migration configuration failed" with the real message demoted into
ex-data, and the whole point of this check is the message.
Throw when migrations sit in a directory nothing reads. Public for the same reason `shadowed-migration-dirs` is: both `migrate` and `migrate-datasource!` depend on it, and a test asserts neither opts out. Outside the try in `get-migration-config`: that handler rewraps everything as "Migration configuration failed" with the real message demoted into ex-data, and the whole point of this check is the message.
(reset)Resets the database by rolling back all migrations and re-applying them.
WARNING: This is destructive! Use only in development.
Returns: nil
Resets the database by rolling back all migrations and re-applying them. WARNING: This is destructive! Use only in development. Returns: nil
(resolved-migration-dir)(resolved-migration-dir dir)What migratus will actually read migrations/ from — a File, JarFile, or nil.
Delegates to migratus.utils/find-migration-dir instead of reimplementing
it. That function tries, in order: the system classloader, the context
classloader, resources/migrations (its default-migration-parent is
"resources/"), and finally migrations/. Only the last of those is the
project directory.
Measured: with a jar containing migrations/ on the classpath and a
populated migrations/ on disk, this returns the JarFile — so a check that
only looked for a resources/migrations directory on the filesystem saw no
conflict while the on-disk migrations were skipped.
What migratus will actually read `migrations/` from — a File, JarFile, or nil. Delegates to `migratus.utils/find-migration-dir` instead of reimplementing it. That function tries, in order: the system classloader, the context classloader, `resources/migrations` (its `default-migration-parent` is "resources/"), and finally `migrations/`. Only the last of those is the project directory. Measured: with a jar containing `migrations/` on the classpath and a populated `migrations/` on disk, this returns the JarFile — so a check that only looked for a `resources/migrations` directory on the filesystem saw no conflict while the on-disk migrations were skipped.
(rollback)Rolls back the last applied migration.
Returns: nil
Throws: Exception if rollback fails
Rolls back the last applied migration. Returns: nil Throws: Exception if rollback fails
(rollback-until-just-after migration-id)Rolls back to specific migration (exclusive).
Args: migration-id: Migration ID (e.g., 20241203120000)
Returns: nil
Rolls back to specific migration (exclusive). Args: migration-id: Migration ID (e.g., 20241203120000) Returns: nil
(shadowed-migration-dirs)(shadowed-migration-dirs project-dir resolved)Migrations in migrations/ that no command will read — otherwise nil.
migrations/ is a name that resolves to exactly one place, and it is not
always the project directory: a resources/migrations directory or a jar on
the classpath carrying migrations/ both take it. When that happens the
project directory is skipped entirely — not applied, not listed as pending,
not counted. A green migrate up and a clean status are both consistent
with a table that was never created (BOU-274).
Only this direction is a hazard. If the winning source is the one holding the
migrations, nothing is lost — resources/migrations alone is an
unconventional but working layout, and it is what this repository uses. It is
SQL under migrations/ that silently goes nowhere, so that is what this
reports.
Reachable without doing anything unusual: bb migrate create used to write
to resources/ in a project with no migrations/ directory, while the
scaffolder always writes to the project root — so one project's migrations
could end up split across both without the user choosing anything.
Both the directory and the resolved source are parameters as well as defaults: they depend on the working directory and the classpath, neither of which a test can change from inside the JVM.
Migrations in `migrations/` that no command will read — otherwise nil. `migrations/` is a name that resolves to exactly one place, and it is not always the project directory: a `resources/migrations` directory or a jar on the classpath carrying `migrations/` both take it. When that happens the project directory is skipped entirely — not applied, not listed as pending, not counted. A green `migrate up` and a clean `status` are both consistent with a table that was never created (BOU-274). Only this direction is a hazard. If the winning source is the one holding the migrations, nothing is lost — `resources/migrations` alone is an unconventional but working layout, and it is what this repository uses. It is SQL under `migrations/` that silently goes nowhere, so that is what this reports. Reachable without doing anything unusual: `bb migrate create` used to write to resources/ in a project with no `migrations/` directory, while the scaffolder always writes to the project root — so one project's migrations could end up split across both without the user choosing anything. Both the directory and the resolved source are parameters as well as defaults: they depend on the working directory and the classpath, neither of which a test can change from inside the JVM.
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |