Swift Vapor 开发利器:AutoMigrator,拒绝苦力活

315 阅读2分钟

如果你用 Vapor 写后端,那么你肯定写过下面类似代码。

Todo.swift 文件

import Vapor
import Fluent

final class Todo: Model {
    static let schema = "todos"

    @ID(key: .id)
    var id: UUID?

    @Field(key: "name")
    var name: String
    
    @Parent(key: "user")
    var user: User
    
    init() {}

    init(id: UUID? = nil, name: String) {
        self.id = id
        self.name = name
    }
}

User.swift 文件

final class User: Model {
    static let schema = "users"

    @ID(key: .id)
    var id: UUID?

    @Field(key: "name")
    var name: String
    
    init() {}

    init(id: UUID? = nil, name: String) {
        self.id = id
        self.name = name
    }
}

按照官方使用指南,我们还需要写迁移类:

extension CreateTodo: AsyncMigration {
    func prepare(on database: Database) async throws {
        try await database.schema("todos")
            .field("id", .uuid, .identifier(auto: false))
            .field("name", .string, .required)
            .field("user", .uuid, .required, .references("users", .id, onDelete: .cascade, onUpdate: .cascade))
            .create()
    }

    func revert(on database: Database) async throws {
        try await database.schema("todos")
            .delete()
    }
}

extension CreateUser: AsyncMigration {
    func prepare(on database: Database) async throws {
        try await database.schema("users")
            .field("id", .uuid, .identifier(auto: false))
            .field("name", .string, .required)
            .create()
    }

    func revert(on database: Database) async throws {
        try await database.schema("users")
            .delete()
    }
}

写完迁移类后,我们还需要添加迁移:

app.databases.use(.postgres(configuration: .init(
    hostname: "localhost",
    port: SQLPostgresConfiguration.ianaPortNumber,
    username: "vapor",
    password: "vapor",
    database: "hello",
    tls: .disable
  )
), as: .psql)
    
app.migrations.add(CreateUser())
app.migrations.add(CreateTodo())

try await app.autoMigrate()

完成这些后才会在数据库中生成对应的表:

如果项目简单,写迁移类的所花的时间还可以接受,但是如果是这样:

工作量就不是一般的大了,而且写多了,你会觉得写这些代码没有任何营养,它就是个体力活,为什么这么说?

@Field(key: "name")
var name: String

从这块代码,我们就可以知道这个属性信息,完全能够通过这些信息自动去生成迁移类,flask-migrate 就是这么做的,开发效率非常高效,那么有没有针对 Vapor 的类似工具呢?

AutoMigrator

源代码:github.com/MatsMoll/Au…

国外小哥应该也意识到了这点,开发了这个库。原理也非常简单:

  • 获取到数据库中表信息
  • 通过类型反射获取到属性信息
  • 对比差异,生成迁移文件

实现细节可以阅读源码。

使用

添加依赖

.package(url: "https://github.com/swiftdo/AutoMigrator.git", from: "0.2.0")

MatsMoll/AutoMigrator 还有些小bug,个人进行了修复,所以引用了自己的源

然后在 testTarget 添加:

AppTests 上添加

然后直接运行单元测试,运行完成后:

然后迁移代码:

app.migrations.add(MigrationBatch1.users())
app.migrations.add(MigrationBatch1.todos())

完工,以后每修改模型,跑一下testHelloWorld测试用例,就会自动将修改生成到 Migrations 目录下,然后我们将手动调用下新增的迁移类就行。

Swift 爱好者,不妨关注的微信公众号:OldBirds,可入Swift微信群。