高度な使い方¶
Fluentは、データを扱うための汎用的でデータベースに依存しないAPIの作成を目指しています。これにより、どのデータベースドライバーを使用しているかに関わらず、Fluentを学習しやすくなります。汎用的なAPIを作成することで、Swiftでデータベースを扱う際により自然に感じられるようになります。
しかし、Fluentでまだサポートされていない基礎となるデータベースドライバーの機能を使用する必要がある場合があります。このガイドでは、特定のデータベースでのみ動作するFluentの高度なパターンとAPIについて説明します。
SQL¶
Fluentのすべての SQLデータベースドライバーはSQLKit上に構築されています。この汎用SQL実装は、FluentSQL
モジュールでFluentと共に提供されています。
SQLデータベース¶
任意のFluent Database
はSQLDatabase
にキャストできます。これにはreq.db
、app.db
、Migration
に渡されるdatabase
などが含まれます。
import FluentSQL
if let sql = req.db as? SQLDatabase {
// 基礎となるデータベースドライバーはSQLです。
let planets = try await sql.raw("SELECT * FROM planets").all(decoding: Planet.self)
} else {
// 基礎となるデータベースドライバーはSQLではありません。
}
このキャストは、基礎となるデータベースドライバーがSQLデータベースである場合にのみ機能します。SQLDatabase
のメソッドについては、SQLKitのREADMEで詳しく学べます。
特定のSQLデータベース¶
ドライバーをインポートすることで、特定のSQLデータベースにキャストすることもできます。
import FluentPostgresDriver
if let postgres = req.db as? PostgresDatabase {
// 基礎となるデータベースドライバーはPostgreSQLです。
postgres.simpleQuery("SELECT * FROM planets").all()
} else {
// 基礎となるデータベースはPostgreSQLではありません。
}
執筆時点で、以下のSQLドライバーがサポートされています。
データベース | ドライバー | ライブラリ |
---|---|---|
PostgresDatabase |
vapor/fluent-postgres-driver | vapor/postgres-nio |
MySQLDatabase |
vapor/fluent-mysql-driver | vapor/mysql-nio |
SQLiteDatabase |
vapor/fluent-sqlite-driver | vapor/sqlite-nio |
データベース固有のAPIについての詳細は、各ライブラリのREADMEをご覧ください。
SQLカスタム¶
Fluentのクエリとスキーマタイプのほぼすべてが.custom
ケースをサポートしています。これにより、Fluentがまだサポートしていないデータベース機能を利用できます。
import FluentPostgresDriver
let query = Planet.query(on: req.db)
if req.db is PostgresDatabase {
// ILIKEがサポートされています。
query.filter(\.$name, .custom("ILIKE"), "earth")
} else {
// ILIKEはサポートされていません。
query.group(.or) { or in
or.filter(\.$name == "earth").filter(\.$name == "Earth")
}
}
query.all()
SQLデータベースは、すべての.custom
ケースでString
とSQLExpression
の両方をサポートしています。FluentSQL
モジュールは、一般的な使用例のための便利なメソッドを提供しています。
import FluentSQL
let query = Planet.query(on: req.db)
if req.db is SQLDatabase {
// 基礎となるデータベースドライバーはSQLです。
query.filter(.sql(raw: "LOWER(name) = 'earth'"))
} else {
// 基礎となるデータベースドライバーはSQLではありません。
}
以下は、スキーマビルダーで.sql(raw:)
の便利な機能を介して.custom
を使用する例です。
import FluentSQL
let builder = database.schema("planets").id()
if database is MySQLDatabase {
// 基礎となるデータベースドライバーはMySQLです。
builder.field("name", .sql(raw: "VARCHAR(64)"), .required)
} else {
// 基礎となるデータベースドライバーはMySQLではありません。
builder.field("name", .string, .required)
}
builder.create()
MongoDB¶
Fluent MongoDBは、FluentとMongoKittenドライバー間の統合です。Swiftの強力な型システムとFluentのデータベース非依存インターフェースをMongoDBで活用します。
MongoDBで最も一般的な識別子はObjectIdです。@ID(custom: .id)
を使用してプロジェクトでこれを使用できます。
SQLで同じモデルを使用する必要がある場合は、ObjectId
を使用しないでください。代わりにUUID
を使用してください。
final class User: Model {
// テーブルまたはコレクションの名前。
static let schema = "users"
// このUserの一意識別子。
// この場合、ObjectIdが使用されています
// Fluentはデフォルトで UUID の使用を推奨しますが、ObjectIdもサポートされています
@ID(custom: .id)
var id: ObjectId?
// ユーザーのメールアドレス
@Field(key: "email")
var email: String
// BCryptハッシュとして保存されるユーザーのパスワード
@Field(key: "password")
var passwordHash: String
// Fluentが使用するための新しい空のUserインスタンスを作成します
init() { }
// すべてのプロパティが設定された新しいUserを作成します。
init(id: ObjectId? = nil, email: String, passwordHash: String, profile: Profile) {
self.id = id
self.email = email
self.passwordHash = passwordHash
self.profile = profile
}
}
データモデリング¶
MongoDBでは、モデルは他のFluent環境と同じように定義されます。SQLデータベースとMongoDBの主な違いは、リレーションシップとアーキテクチャにあります。
SQL環境では、2つのエンティティ間の関係のために結合テーブルを作成することが非常に一般的です。しかし、MongoDBでは、配列を使用して関連する識別子を保存できます。MongoDBの設計により、ネストされたデータ構造でモデルを設計する方がより効率的で実用的です。
柔軟なデータ¶
MongoDBでは柔軟なデータを追加できますが、このコードはSQL環境では動作しません。
グループ化された任意のデータストレージを作成するには、Document
を使用できます。
@Field(key: "document")
var document: Document
Fluentはこれらの値に対する厳密に型付けされたクエリをサポートできません。クエリでドット記法のキーパスを使用できます。 これは、ネストされた値にアクセスするためにMongoDBで受け入れられています。
Something.query(on: db).filter("document.key", .equal, 5).first()
正規表現の使用¶
.custom()
ケースを使用し、正規表現を渡してMongoDBをクエリできます。MongoDBはPerl互換の正規表現を受け入れます。
例えば、name
フィールドで大文字と小文字を区別しない文字をクエリできます:
import FluentMongoDriver
var queryDocument = Document()
queryDocument["name"]["$regex"] = "e"
queryDocument["name"]["$options"] = "i"
let planets = try Planet.query(on: req.db).filter(.custom(queryDocument)).all()
これは'e'と'E'を含む惑星を返します。MongoDBが受け入れる他の複雑な正規表現も作成できます。
生のアクセス¶
生のMongoDatabase
インスタンスにアクセスするには、データベースインスタンスをMongoDatabaseRepresentable
にキャストします:
guard let db = req.db as? MongoDatabaseRepresentable else {
throw Abort(.internalServerError)
}
let mongodb = db.raw
ここから、すべてのMongoKitten APIを使用できます。