Server-Side Swift VaporのFluent+PostgreSQLでMigrationでINDEXを追加する
Last Updated on 2023年8月16日 by lemonade
この記事は、Server-Side SwiftのORM, Fluentを用いた際にIndexを追加する方法を説明するものです。
はじめに
Vaporを使用している際にカラムにインデックスを貼っているでしょうか? 私はつい最近までMySQLでは基本的に外部キーに設定したカラムにINDEXが貼られるのでPostgreSQLでも勝手に貼られるだろうと勘違いしておりほとんどINDEXを貼ってきませんでした。
FluentのPostgreSQLではINDEXを貼る方法がまだ公式で提供されていないように思ったため、追加する方法を説明したいなと思います。※以前Vaporコミュニティのドキュメントプレビューの方でINDEXが貼れそうな構文が見受けられたため、もうすぐ貼れるようになれるかもしれません。
結論
以下のようにFluent.Databaseを拡張します。
import Fluent
import PostgresKit
extension Fluent.Database {
func createIndex(schema: String, columns: String...) async throws {
_ = try await (self as! SQLDatabase).raw("""
CREATE INDEX \(raw: indexID(schema: schema, columns: columns))
ON \(raw: schema) (\(raw: columns.joined(separator: ", ")))
""").all()
}
func deleteIndex(schema: String, columns: String...) async throws {
_ = try await (self as! SQLDatabase).raw(
"DROP INDEX \(raw: indexID(schema: schema, columns: columns))"
).all()
}
private func indexID(schema: String, columns: [String]) -> String {
"\(schema)_\(columns.joined(separator: "_"))_index"
}
}
使い方としては以下のようになります。カラムを複数指定すると複合INDEXになります。(Userは自分で定義したFluent.Modelに準拠したクラスになります)
import Fluent
extension User {
struct Migration: AsyncMigration {
private let schema = "users"
func prepare(on database: Database) async throws {
try await database.schema(schema)
.id()
.field("name", .string, .required)
.field("display_name", .string, .required)
.field("created_at", .datetime, .required)
.field("updated_at", .datetime, .required)
.create()
try await database.createIndex(schema: schema, columns: "name")
try await database.createIndex(schema: schema, columns: "id", "display_name")
}
func revert(on database: Database) async throws {
try await database.schema(schema).delete()
}
}
}
後書き
公式でINDEXが対応されていたら教えてください。