Database Migrations With Vapor
In this Server-Side Swift tutorial, learn how to perform database migrations with Vapor on your application database – a useful tool for tasks such as creating tables, seeding data, and adding columns. By Heidi Hermann.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Database Migrations With Vapor
25 mins
- Getting Started
- Configuring Your Local PostgreSQL Database Using Docker
- Connecting to Your Database
- Writing Your First Migration
- Migrations in Vapor 4
- Creating a Tools Migration
- Running Your Application
- Implementing FieldKeys
- Rewriting Your First Migration Using FieldKeys
- Replacing Stringly Typed Keys with FieldKeys in Tool and Its Migration
- Reverting Your Migration
- Rerunning Your First Migration
- Adding a Maker to Your Tools
- Adding a New Migration
- Running Your Migration
- Adding a Unique Requirement to Your Tool/Maker Combination
- Building and Running Your App
- Seeding Data Using Migrations
- Where to Go From Here?
Adding a Unique Requirement to Your Tool/Maker Combination
As your tool catalog grows, you'll realize the need to prevent duplicate entries in the database.
So, it's time to write another migration to add a unique constraint on the combination of tool and maker. Since you aren't adding any new fields to the table, you don't have to create any new keys.
Create a new Swift file in your migrations folder named 21-06-02_Tool+MakeToolUnique.swift.
Then, paste the following:
// 1
import FluentKit
extension Tool {
struct MakeToolUnique: Migration {
func prepare(on database: Database) -> EventLoopFuture<Void> {
database
.schema(Tool.schema)
// 2
.unique(
on: Tool.Create_20210531.name, Tool.AddMaker_20210601.maker,
name: "unique_tool_maker"
)
.update()
}
func revert(on database: Database) -> EventLoopFuture<Void> {
database
.schema(Tool.schema)
// 3
.deleteUnique(
on: Tool.Create_20210531.name,
Tool.AddMaker_20210601.maker
)
.update()
}
}
}
Here, you:
- Import
FluentKit
to expose the migration APIs - Add a unique constraint on the combination of the two fields
name
andmaker
and call it unique_tool_maker. You can add the unique constraint on any combination of one or many fields and provide a readable name for the constraint if you like. - Delete the unique constraint again when the migration reverts.
Next, register the migration in configure.swift. Paste the following line below the other migrations:
app.migrations.add(Tool.MakeToolUnique())
You're almost done!
Building and Running Your App
Now, confirm you still have the migrate argument enabled in your build scheme.
Build and run. Then, open Postico to view the tools table, selecting the Structure.
Here, you can see that the unique index is added on the combination of name
and maker
with the name you just gave it.
Seeding Data Using Migrations
Migrations are useful for more than just changing the structure of your database.
You can also use them to seed data, such as a list of general categories, or some example data to use in your front end or unit tests.
So, time for you to write your last migration.
Add a new file in the migrations folder named 21-06-03_Tool+Seed.swift and paste the following:
import FluentKit
extension Tool {
struct Seed: Migration {
func prepare(on database: Database) -> EventLoopFuture<Void> {
// 1
let tools: [Tool] = [
.init(name: "Hammer", maker: nil),
.init(name: "Food Processor", maker: "Bosch"),
.init(name: "Zigsaw", maker: "Makita")
]
// 2
return tools.map { tool in
tool.save(on: database)
}
.flatten(on: database.eventLoop)
}
func revert(on database: Database) -> EventLoopFuture<Void> {
// 3
Tool.query(on: database).delete()
}
}
}
Here, you:
- Create a list of three tools, two of which have a maker.
- Map over the three tools and save each one to the database.
- Delete all records in tools on revert.
Next, register the migration in configure.swift below the other migrations:
app.migrations.add(Tool.Seed())
Finally, build and run your migration. Then open the tools table in Postico.
You can see that the table now has three tools in it.
Where to Go From Here?
Download the completed project files by clicking the Download Materials button at the top or bottom of the tutorial.
In this article, you learned the basics of what a migration is and why you should use migrations to configure your database. You also learned most of the common migration options you'll use in your own apps.
If you want to learn more about migrations, check out Server-Side Swift with Vapor or the official Vapor documentation.
If you're looking for a challenge beyond this tutorial, here are a few things you can try:
- Create a REST API to interact with your app.
- Add a type to the
Tool
entity (using an Enum). - Add a quantity property to the
Tool
entity with a default value of 1. - Introduce a new
Loan
entity so you can keep track of which friend borrowed what tool. Remember to set references up correctly in the database!
We hope you enjoyed this tutorial! If you have any questions or comments, please join the forum discussion below!