Query¶
Met de query API van Fluent kunt u modellen aanmaken, lezen, bijwerken en verwijderen uit de database. Het ondersteunt het filteren van resultaten, joins, chunking, aggregaten, en nog veel meer.
// Een voorbeeld van Fluent's query API.
let planets = try await Planet.query(on: database)
.filter(\.$type == .gasGiant)
.sort(\.$name)
.with(\.$star)
.all()
Query builders zijn gebonden aan een enkel modeltype en kunnen worden aangemaakt met de static query
methode. Ze kunnen ook worden aangemaakt door het modeltype door te geven aan de query
methode op een database object.
// Maakt ook een query builder.
database.query(Planet.self)
Opmerking
U moet Fluent importeren
in het bestand met uw queries, zodat de compiler de helper-functies van Fluent kan zien.
All¶
De all()
methode geeft een array van modellen terug.
// Haalt alle planeten op.
let planets = try await Planet.query(on: database).all()
De all
methode ondersteunt ook het ophalen van slechts een enkel veld uit de resultatenverzameling.
// Haalt alle planeetnamen op.
let names = try await Planet.query(on: database).all(\.$name)
First¶
De first()
methode retourneert een enkel, optioneel model. Als de query meer dan één model oplevert, wordt alleen het eerste model teruggegeven. Als de query geen resultaten heeft, wordt nil
geretourneerd.
// Haalt de eerste planeet genaamd Earth op.
let earth = try await Planet.query(on: database)
.filter(\.$name == "Earth")
.first()
Tip
Bij gebruik van EventLoopFuture
s, kan deze methode gecombineerd worden met unwrap(of:)
om een niet-optioneel model te retourneren of een foutmelding te geven.
Filter¶
De filter
methode staat je toe om de modellen in de resultaten set te beperken. Er zijn verschillende overloads voor deze methode.
Value Filter¶
De meest gebruikte filter
methode accepteert een operator expressie met een waarde.
// Een voorbeeld van het filteren van veldwaarden.
Planet.query(on: database).filter(\.$type == .gasGiant)
Deze operator expressies accepteren een veld sleutelpad aan de linkerkant en een waarde aan de rechterkant. De geleverde waarde moet overeenkomen met het verwachte waardetype van het veld en wordt gebonden aan de resulterende query. Filteruitdrukkingen zijn sterk getypeerd, zodat een syntax met leidende punten kan worden gebruikt.
Hieronder staat een lijst van alle ondersteunde waarde operatoren.
Operator | Beschrijving |
---|---|
== |
Gelijk aan. |
!= |
Niet gelijk aan. |
>= |
Groter dan of gelijk aan. |
> |
Groter dan. |
< |
Kleiner dan. |
<= |
Kleiner dan of gelijk aan. |
Field Filter¶
De filter
methode ondersteunt het vergelijken van twee velden.
// Alle gebruikers met dezelfde voor- en achternaam.
User.query(on: database)
.filter(\.$firstName == \.$lastName)
Veldfilters ondersteunen dezelfde operatoren als value filters.
Subset Filter¶
De filter
methode ondersteunt het controleren of de waarde van een veld bestaat in een gegeven set van waarden.
// Alle planeten met ofwel gasreus ofwel klein rotsachtig type.
Planet.query(on: database)
.filter(\.$type ~~ [.gasGiant, .smallRocky])
De opgegeven set van waarden kan elke Swift Collection
zijn waarvan het Element
type overeenkomt met het veld waarde type.
Hieronder staat een lijst van alle ondersteunde subset operatoren.
Operator | Beschrijving |
---|---|
~~ |
Waarde in verzameling. |
!~ |
Waarde niet in verzameling. |
Contains Filter¶
De filter
methode ondersteunt het controleren of de waarde van een string veld een gegeven substring bevat.
// Alle planeten waarvan de naam begint met de letter M
Planet.query(on: database)
.filter(\.$name =~ "M")
Deze operatoren zijn alleen beschikbaar voor velden met string-waarden.
Hieronder vindt u een lijst van alle ondersteunde bevat operatoren.
Operator | Beschrijving |
---|---|
~~ |
Bevat een substring. |
!~ |
Bevat geen substring. |
=~ |
Komt overeen met voorvoegsel. |
!=~ |
Komt niet overeen met voorvoegsel. |
~= |
Komt overeen met achtervoegsel. |
!~= |
Komt niet overeen met achtervoegsel. |
Group¶
Standaard moeten alle filters die aan een query zijn toegevoegd overeenkomen. Query builder ondersteunt het maken van een groep filters waarbij slechts één filter moet overeenkomen.
// Alle planeten die Aarde of Mars heten
Planet.query(on: database).group(.or) { group in
group.filter(\.$name == "Earth").filter(\.$name == "Mars")
}.all()
De group
methode ondersteunt het combineren van filters door and
of or
logica. Deze groepen kunnen oneindig genest worden. Top-level filters kunnen worden gezien als in een en
groep.
Aggregate¶
Query builder ondersteunt verschillende methoden om berekeningen uit te voeren op een reeks waarden, zoals tellen of het gemiddelde berekenen.
// Aantal planeten in de database.
Planet.query(on: database).count()
Alle aggregate methodes behalve count
vereisen een sleutelpad naar een veld dat moet worden doorgegeven.
// Laagste naam alfabetisch gesorteerd.
Planet.query(on: database).min(\.$name)
Hieronder vindt u een lijst van alle beschikbare aggregatiemethoden.
Aggregate | Beschrijving |
---|---|
count |
Aantal Resultaten. |
sum |
Som van resultaatwaarden. |
average |
Gemiddelde van resultaatwaarden. |
min |
Minimale resultaatwaarde. |
max |
Maximale resultaatwaarde. |
Alle aggregatiemethoden behalve count
retourneren het waardetype van het veld als resultaat. count
retourneert altijd een geheel getal.
Chunk¶
Query builder ondersteunt het teruggeven van een resultaat set als afzonderlijke chunks. Dit helpt je om het geheugengebruik te controleren bij het uitvoeren van grote database lezingen.
// Haalt alle planeten op in stukken van maximaal 64 per keer.
Planet.query(on: self.database).chunk(max: 64) { planets in
// Behandel een stuk planeten.
}
De meegeleverde closure wordt nul of meer keer aangeroepen, afhankelijk van het totale aantal resultaten. Elk item is een Result
met ofwel het model of een foutmelding bij het decoderen van de databank gegevens.
Field¶
Standaard worden alle velden van een model door een query uit de database gelezen. U kunt ervoor kiezen om alleen een subset van de velden van een model te selecteren met de field
methode.
// Selecteer alleen het id en naam veld van de planeet
Planet.query(on: database)
.field(\.$id).field(\.$name)
.all()
Alle modelvelden die tijdens een query niet zijn geselecteerd, zullen in een niet-geïnitialiseerde toestand verkeren. Pogingen om niet-geïnitialiseerde velden direct te benaderen zullen resulteren in een fatale fout. Om te controleren of de veldwaarde van een model is ingesteld, gebruikt u de value
eigenschap.
if let name = planet.$name.value {
// Naam werd opgehaald.
} else {
// Naam werd niet opgehaald.
// Toegang tot `planet.name` zal mislukken.
}
Unique¶
Query builder's unique
methode zorgt ervoor dat alleen verschillende resultaten (geen duplicaten) worden geretourneerd.
// Geeft als resultaat alle unieke voornamen van gebruikers.
User.query(on: database).unique().all(\.$firstName)
unique
is vooral handig bij het ophalen van een enkel veld met all
. U kunt echter ook meerdere velden selecteren met de field
methode. Omdat model identifiers altijd uniek zijn, moet u voorkomen dat u ze selecteert wanneer u unique
gebruikt.
Range¶
Met de range
methoden van de Query builder kunt u een subset van de resultaten kiezen met behulp van Swift ranges.
// Haal de eerste 5 planeten op.
Planet.query(on: self.database)
.range(..<5)
Bereikwaarden zijn niet-ondertekende gehele getallen beginnend bij nul. Meer informatie over
// Sla de eerste 2 resultaten over.
.range(2...)
Join¶
Query bouwer's join
methode staat u toe om een ander model velden op te nemen in uw resultaat set. Meer dan één model kan worden toegevoegd aan uw query.
// Haalt alle planeten met een ster genaamd Zon op.
Planet.query(on: database)
.join(Star.self, on: \Planet.$star.$id == \Star.$id)
.filter(Star.self, \.$name == "Sun")
.all()
De op
parameter accepteert een gelijkheidsexpressie tussen twee velden. Een van de velden moet al bestaan in de huidige resultatenset. Het andere veld moet bestaan in het model dat wordt samengevoegd. Deze velden moeten hetzelfde waardetype hebben.
De meeste query builder methodes, zoals filter
en sort
, ondersteunen samengevoegde modellen. Als een methode gegroepeerde modellen ondersteunt, zal deze het gegroepeerde model type accepteren als de eerste parameter.
// Sorteren op het samengevoegde veld "naam" op het Star-model.
.sort(Star.self, \.$name)
Queries die joins gebruiken zullen nog steeds een array van het basismodel teruggeven. Om toegang te krijgen tot het joined model, gebruik de joined
methode.
// Toegang tot samengevoegd model vanuit query resultaat.
let planet: Planet = ...
let star = try planet.joined(Star.self)
Model Alias¶
Model aliassen staan u toe om hetzelfde model meerdere malen aan een query toe te voegen. Om een model alias aan te geven, maakt u een of meer types die voldoen aan ModelAlias
.
// Voorbeeld van model aliassen.
final class HomeTeam: ModelAlias {
static let name = "home_teams"
let model = Team()
}
final class AwayTeam: ModelAlias {
static let name = "away_teams"
let model = Team()
}
Deze types verwijzen naar het model dat gealiased wordt via de model
eigenschap. Eenmaal aangemaakt, kunt u model aliassen gebruiken zoals normale modellen in een query builder.
// Haal alle wedstrijden op waar de naam van de thuisploeg Vapor is
// en sorteer op de naam van het uitteam.
let matches = try await Match.query(on: self.database)
.join(HomeTeam.self, on: \Match.$homeTeam.$id == \HomeTeam.$id)
.join(AwayTeam.self, on: \Match.$awayTeam.$id == \AwayTeam.$id)
.filter(HomeTeam.self, \.$name == "Vapor")
.sort(AwayTeam.self, \.$name)
.all()
Alle modelvelden zijn toegankelijk via het model alias type via @dynamicMemberLookup
.
// Toegang tot het samengevoegde model vanuit het resultaat.
let home = try match.joined(HomeTeam.self)
print(home.name)
Update¶
Query builder ondersteunt het updaten van meer dan één model tegelijk met behulp van de update
methode.
// Update alle planeten genaamd "Pluto"
Planet.query(on: database)
.set(\.$type, to: .dwarf)
.filter(\.$name == "Pluto")
.update()
update
ondersteunt de set
, filter
, en range
methoden.
Delete¶
Query builder ondersteunt het verwijderen van meer dan een model tegelijk met behulp van de delete
methode.
// Verwijder alle planeten genaamd "Vulcan"
Planet.query(on: database)
.filter(\.$name == "Vulcan")
.delete()
delete
ondersteunt de filter
methode.
Paginate¶
Fluent's query API ondersteunt automatische paginering van resultaten met behulp van de paginate
methode.
// Voorbeeld van paginering op verzoek.
app.get("planets") { req in
try await Planet.query(on: req.db).paginate(for: req)
}
De paginate(for:)
methode gebruikt de page
en per
parameters beschikbaar in de request URI om de gewenste set resultaten terug te geven. Metadata over de huidige pagina en het totaal aantal resultaten is opgenomen in de metadata
sleutel.
GET /planets?page=2&per=5 HTTP/1.1
Het bovenstaande verzoek zou een antwoord opleveren met de volgende structuur.
{
"items": [...],
"metadata": {
"page": 2,
"per": 5,
"total": 8
}
}
Paginanummers beginnen bij 1
. U kunt ook een handmatige pagina aanvraag doen.
// Voorbeeld van handmatige paginering.
.paginate(PageRequest(page: 1, per: 2))
Sort¶
Query resultaten kunnen worden gesorteerd op veldwaarden met de sort
methode.
// Planeten ophalen gesorteerd op naam.
Planet.query(on: database).sort(\.$name)
Extra soorten kunnen worden toegevoegd als fallbacks in geval van een gelijke stand. De fallbacks worden gebruikt in de volgorde waarin ze zijn toegevoegd aan de query bouwer.
// Zoek gebruikers gesorteerd op naam. Als twee gebruikers dezelfde naam hebben, sorteer ze dan op leeftijd.
User.query(on: database).sort(\.$name).sort(\.$age)