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.

Leave a rating/review
Download materials
Save for later
Share
You are currently viewing page 4 of 4 of this article. Click here to view the first page.

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:

  1. Import FluentKit to expose the migration APIs
  2. Add a unique constraint on the combination of the two fields name and maker 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.
  3. 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.

The tools table after adding a unique constraint to tool and maker.

The tools table after adding a unique constraint to tool and maker (indicated with a 1).

The tools table after adding a unique constraint to tool and maker.

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:

  1. Create a list of three tools, two of which have a maker.
  2. Map over the three tools and save each one to the database.
  3. 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.

Postico view of the tools table after the seed migration runs. It now has three tools.

Postico view of the tools table after the seed migration runs.

Postico view of the tools table after the seed migration runs. It now has three tools.

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!