Avanzate¶
Fluent si propone di creare un'API generica e indipendente dal database per lavorare con i tuoi dati. Questo rende più facile imparare Fluent indipendentemente dal driver di database che stai utilizzando. La creazione di API generalizzate può anche rendere il lavoro con il tuo database più naturale in Swift.
Tuttavia, potresti dover utilizzare una funzionalità del tuo driver di database sottostante che non è ancora supportata tramite Fluent. Questa guida tratta i pattern avanzati e le API di Fluent che funzionano solo con determinati database.
SQL¶
Tutti i driver di database SQL di Fluent sono costruiti su SQLKit. Questa implementazione SQL generica è inclusa con Fluent nel modulo FluentSQL.
Database SQL¶
Qualsiasi Database di Fluent può essere convertito in un SQLDatabase. Questo include req.db, app.db, il database passato a Migration, ecc.
import FluentSQL
if let sql = req.db as? SQLDatabase {
// The underlying database driver is SQL.
let planets = try await sql.raw("SELECT * FROM planets").all(decoding: Planet.self)
} else {
// The underlying database driver is _not_ SQL.
}
Questa conversione funzionerà solo se il driver di database sottostante è un database SQL. Per saperne di più sui metodi di SQLDatabase, consulta il README di SQLKit.
Database SQL Specifico¶
Puoi anche convertire verso database SQL specifici importando il driver.
import FluentPostgresDriver
if let postgres = req.db as? PostgresDatabase {
// The underlying database driver is PostgreSQL.
postgres.simpleQuery("SELECT * FROM planets").all()
} else {
// The underlying database is _not_ PostgreSQL.
}
Al momento della stesura, i seguenti driver SQL sono supportati.
| Database | Driver | Libreria |
|---|---|---|
PostgresDatabase |
vapor/fluent-postgres-driver | vapor/postgres-nio |
MySQLDatabase |
vapor/fluent-mysql-driver | vapor/mysql-nio |
SQLiteDatabase |
vapor/fluent-sqlite-driver | vapor/sqlite-nio |
Visita il README della libreria per ulteriori informazioni sulle API specifiche del database.
SQL Personalizzato¶
Quasi tutti i tipi di query e schema di Fluent supportano un caso .custom. Questo ti permette di utilizzare funzionalità del database che Fluent non supporta ancora.
import FluentPostgresDriver
let query = Planet.query(on: req.db)
if req.db is PostgresDatabase {
// ILIKE è supportato da PostgreSQL, quindi possiamo usarlo
query.filter(\.$name, .custom("ILIKE"), "earth")
} else {
// ILIKE non è supportato
query.group(.or) { or in
or.filter(\.$name == "earth").filter(\.$name == "Earth")
}
}
query.all()
I database SQL supportano sia String che SQLExpression in tutti i casi .custom. Il modulo FluentSQL fornisce metodi di convenienza per i casi d'uso più comuni.
import FluentSQL
let query = Planet.query(on: req.db)
if req.db is SQLDatabase {
// Il database è SQL, quindi possiamo usare le espressioni SQL personalizzate
query.filter(.sql(raw: "LOWER(name) = 'earth'"))
} else {
// Il database non è SQL
}
Di seguito è riportato un esempio di .custom tramite la convenienza .sql(raw:) utilizzata con il costruttore di schema.
import FluentSQL
let builder = database.schema("planets").id()
if database is MySQLDatabase {
// Il database è MySQL
builder.field("name", .sql(raw: "VARCHAR(64)"), .required)
} else {
// Il database non è MySQL
builder.field("name", .string, .required)
}
builder.create()
MongoDB¶
Fluent MongoDB è un'integrazione tra Fluent e il driver MongoKitten. Sfrutta il forte sistema di tipi di Swift e l'interfaccia indipendente dal database di Fluent utilizzando MongoDB.
L'identificatore più comune in MongoDB è ObjectId. Puoi usarlo per il tuo progetto usando @ID(custom: .id).
Se hai bisogno di usare gli stessi modelli con SQL, non usare ObjectId. Usa UUID invece.
final class User: Model {
// Nome della tabella o collezione.
static let schema = "users"
// Identificatore univoco per questo User.
// In questo caso, viene utilizzato ObjectId
// Fluent consiglia di utilizzare UUID per impostazione predefinita, tuttavia ObjectId è supportato
@ID(custom: .id)
var id: ObjectId?
// L'indirizzo email dell'utente
@Field(key: "email")
var email: String
// Il profilo dell'utente, memorizzato come un hash Bcrypt
@Field(key: "password")
var passwordHash: String
// Crea un nuovo profilo per questo utente
init() { }
// Crea un nuovo profilo per questo utente con tutte le proprietà impostate
init(id: ObjectId? = nil, email: String, passwordHash: String, profile: Profile) {
self.id = id
self.email = email
self.passwordHash = passwordHash
self.profile = profile
}
}
Modellazione dei Dati¶
In MongoDB, i modelli sono definiti allo stesso modo di qualsiasi altro ambiente Fluent. La principale differenza tra i database SQL e MongoDB risiede nelle relazioni e nell'architettura.
Negli ambienti SQL, è molto comune creare tabelle di join per le relazioni tra due entità. In MongoDB, invece, si può usare un array per memorizzare gli identificatori correlati. A causa del design di MongoDB, è più efficiente e pratico progettare i tuoi modelli con strutture dati annidate.
Dati Flessibili¶
Puoi aggiungere dati flessibili in MongoDB, ma questo codice non funzionerà in ambienti SQL.
Per creare uno spazio di archiviazione dati arbitrario raggruppato puoi usare Document.
@Field(key: "document")
var document: Document
Fluent non supporta query con tipi rigorosi su questi valori. Puoi usare un percorso chiave con notazione a punti nella tua query. Questo è accettato in MongoDB per accedere ai valori annidati.
Something.query(on: db).filter("document.key", .equal, 5).first()
Uso delle Espressioni Regolari¶
Puoi interrogare MongoDB usando il caso .custom(), passando un'espressione regolare. MongoDB accetta espressioni regolari compatibili con Perl.
Per esempio, puoi cercare caratteri senza distinzione tra maiuscole e minuscole nel campo 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()
Questo restituirà i pianeti contenenti 'e' ed 'E'. Puoi anche creare qualsiasi altra espressione RegEx complessa accettata da MongoDB.
Accesso Diretto¶
Per accedere all'istanza grezza di MongoDatabase, converti l'istanza del database in MongoDatabaseRepresentable come segue:
guard let db = req.db as? MongoDatabaseRepresentable else {
throw Abort(.internalServerError)
}
let mongodb = db.raw
Da qui puoi utilizzare tutte le API di MongoKitten.