# 高度な使い方 {#advanced} Fluentは、データを扱うための汎用的でデータベースに依存しないAPIの作成を目指しています。これにより、どのデータベースドライバーを使用しているかに関わらず、Fluentを学習しやすくなります。汎用的なAPIを作成することで、Swiftでデータベースを扱う際により自然に感じられるようになります。 しかし、Fluentでまだサポートされていない基礎となるデータベースドライバーの機能を使用する必要がある場合があります。このガイドでは、特定のデータベースでのみ動作するFluentの高度なパターンとAPIについて説明します。 ## SQL {#sql} Fluentのすべての SQLデータベースドライバーは[SQLKit](https://github.com/vapor/sql-kit)上に構築されています。この汎用SQL実装は、`FluentSQL`モジュールでFluentと共に提供されています。 ### SQLデータベース {#sql-database} 任意のFluent `Database`は`SQLDatabase`にキャストできます。これには`req.db`、`app.db`、`Migration`に渡される`database`などが含まれます。 ```swift 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](https://github.com/vapor/sql-kit)で詳しく学べます。 ### 特定のSQLデータベース {#specific-sql-database} ドライバーをインポートすることで、特定のSQLデータベースにキャストすることもできます。 ```swift import FluentPostgresDriver if let postgres = req.db as? PostgresDatabase { // 基礎となるデータベースドライバーはPostgreSQLです。 postgres.simpleQuery("SELECT * FROM planets").all() } else { // 基礎となるデータベースはPostgreSQLではありません。 } ``` 執筆時点で、以下のSQLドライバーがサポートされています。 |データベース|ドライバー|ライブラリ| |-|-|-| |`PostgresDatabase`|[vapor/fluent-postgres-driver](https://github.com/vapor/fluent-postgres-driver)|[vapor/postgres-nio](https://github.com/vapor/postgres-nio)| |`MySQLDatabase`|[vapor/fluent-mysql-driver](https://github.com/vapor/fluent-mysql-driver)|[vapor/mysql-nio](https://github.com/vapor/mysql-nio)| |`SQLiteDatabase`|[vapor/fluent-sqlite-driver](https://github.com/vapor/fluent-sqlite-driver)|[vapor/sqlite-nio](https://github.com/vapor/sqlite-nio)| データベース固有のAPIについての詳細は、各ライブラリのREADMEをご覧ください。 ### SQLカスタム {#sql-custom} Fluentのクエリとスキーマタイプのほぼすべてが`.custom`ケースをサポートしています。これにより、Fluentがまだサポートしていないデータベース機能を利用できます。 ```swift 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`モジュールは、一般的な使用例のための便利なメソッドを提供しています。 ```swift 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`を使用する例です。 ```swift 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 {#mongodb} Fluent MongoDBは、[Fluent](../fluent/overview.md)と[MongoKitten](https://github.com/OpenKitten/MongoKitten/)ドライバー間の統合です。Swiftの強力な型システムとFluentのデータベース非依存インターフェースをMongoDBで活用します。 MongoDBで最も一般的な識別子はObjectIdです。`@ID(custom: .id)`を使用してプロジェクトでこれを使用できます。 SQLで同じモデルを使用する必要がある場合は、`ObjectId`を使用しないでください。代わりに`UUID`を使用してください。 ```swift 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 } } ``` ### データモデリング {#data-modelling} MongoDBでは、モデルは他のFluent環境と同じように定義されます。SQLデータベースとMongoDBの主な違いは、リレーションシップとアーキテクチャにあります。 SQL環境では、2つのエンティティ間の関係のために結合テーブルを作成することが非常に一般的です。しかし、MongoDBでは、配列を使用して関連する識別子を保存できます。MongoDBの設計により、ネストされたデータ構造でモデルを設計する方がより効率的で実用的です。 ### 柔軟なデータ {#flexible-data} MongoDBでは柔軟なデータを追加できますが、このコードはSQL環境では動作しません。 グループ化された任意のデータストレージを作成するには、`Document`を使用できます。 ```swift @Field(key: "document") var document: Document ``` Fluentはこれらの値に対する厳密に型付けされたクエリをサポートできません。クエリでドット記法のキーパスを使用できます。 これは、ネストされた値にアクセスするためにMongoDBで受け入れられています。 ```swift Something.query(on: db).filter("document.key", .equal, 5).first() ``` ### 正規表現の使用 {#use-of-regular-expressions} `.custom()`ケースを使用し、正規表現を渡してMongoDBをクエリできます。[MongoDB](https://www.mongodb.com/docs/manual/reference/operator/query/regex/)はPerl互換の正規表現を受け入れます。 例えば、`name`フィールドで大文字と小文字を区別しない文字をクエリできます: ```swift 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が受け入れる他の複雑な正規表現も作成できます。 ### 生のアクセス {#raw-access} 生の`MongoDatabase`インスタンスにアクセスするには、データベースインスタンスを`MongoDatabaseRepresentable`にキャストします: ```swift guard let db = req.db as? MongoDatabaseRepresentable else { throw Abort(.internalServerError) } let mongodb = db.raw ``` ここから、すべてのMongoKitten APIを使用できます。