Migrations
Migrations are a key part of working with an SQL database. Each migration defines changes to the schema of your database that can be either applied or rolled back. You’ll typically create new migrations each time you want to make a change to your database, so that you can keep track of all the changes you’ve made over time.
Creating a migration
You can create a new migration using the CLI.
This will create a new migration file in Sources/App/Migrations
.
Implementing Migrations
A migration conforms to the Migration
protocol and is implemented by filling out the up
and down
functions. up
is run when a migration is applied to a database. down
is run when a migration is rolled back.
up
and down
are passed a Schema
object representing the schema of the database to which this migration will be applied. The database schema is modified via functions on Schema
.
For example, this migration renames the user_todos
table to todos
. Notice the down
function does the reverse. You don’t have to fill out the down function of a migration, but it may be useful for rolling back the operation later.
Schema functions
Schema
has a variety of useful builder methods for doing various database migrations.
Creating a table
You can create a new table using Schema.create(table: String, builder: (inout CreateTableBuilder) -> Void)
.
The CreateTableBuilder
comes packed with a variety of functions for adding columns of various types & modifiers to the new table.
Adding Columns
You may add a column onto a table builder with functions like .string()
or .int()
. These define a named column of the given type and return a column builder for adding modifiers to the column.
Supported builder functions for adding columns are
Table Builder Functions | Column Builder Functions |
---|---|
.uuid(_ column: String) | .default(expression: String) |
.int(_ column: String) | .default(val: String) |
.string(_ column: String) | .notNull() |
.increments(_ column: String) | .unique() |
.double(_ column: String) | .primary() |
.bool(_ column: String) | .references(_ column: String, on table: String) |
.date(_ column: String) | |
.json(_ column: String) |
Adding Indexes
Indexes can be added via .addIndex
. They can be on a single column or multiple columns and can be defined as unique or not.
Indexes are named by concatinating table name + columns + “key” if unique or “idx” if not, all joined with underscores. For example, the index defined above would be named users_email_key
.
Altering a Table
You can alter an existing table with alter(table: String, builder: (inout AlterTableBuilder) -> Void)
.
AlterTableBuilder
has the exact same interface as CreateTableBuilder
with a few extra functions for dropping columns, dropping indexes, and renaming columns.
Other schema functions
You can also drop tables, rename tables, or execute arbitrary SQL strings from a migration.
Running a Migration
To begin, you need to ensure that your migrations are registered on Database.default
. You can should do this in your Application.boot
function.
Via Command
Applying
You can then apply all outstanding migrations in a single batch by passing the migrate
argument to your app. This will cause the app to migrate Database.default
instead of serving.
Rolling Back
You can pass the --rollback
flag to instead rollback the latest batch of migrations.
When Serving
If you’d prefer to avoid running a separate migration command, you may pass the --migrate
flag when running your server to automatically run outstanding migrations before serving.
Note: Alchemy keeps track of run migrations and the current batch in your database in the migrations
table. You can delete this table to clear all records of migrations.
Via Code
Applying
You may also migrate your database in code. The future will complete when the migration is finished.
Rolling Back
Rolling back the latest migration batch is also possible in code.