8.3 KiB
Fluent Queries
Once you have a model you can start querying your database to create, read, update, and delete data.
Connection
The first thing you need to query your database, is a connection to it. Luckily, they are easy to get.
Request
The easiest way to connect to your database is simply using the incoming Request. This will use the model's defaultDatabase property to automatically fetch a pooled connection to the database.
router.get("galaxies") { req in
return Galaxy.query(on: req).all()
}
You can use convenience methods on a Container to create connections manually. Learn more about that in DatabaseKit → Overview → Connections.
Create
One of the first things you will need to do is save some data to your database. You do this by initializing an instance of your model then calling create(on:).
router.post("galaxies") { req in
let galaxy: Galaxy = ...
return galaxy.create(on: req)
}
The create method will return the saved model. The returned model will include any generated fields such as the ID or fields with default values.
If your model also conforms to Content you can return the result of the Fluent query directly.
Read
To read models from the database, you can use query(on:) or find(_:on:).
Find
The easiest way to find a single model is by passing its ID to find(_:on:).
Galaxy.find(42, on: conn)
The result will be a future containing an optional value. You can use unwrap(or:) to unwrap the future value or throw an error.
Galaxy.find(42, on: conn).unwrap(or: Abort(...))
Query
You can use the query(on:) method to build database queries with filters, joins, sorts, and more.
Galaxy.query(on: conn).filter(\.name == "Milky Way")
Filter
The filter(_:) method accepts filters created from Fluent's operators. This provides a concise, Swifty way for building Fluent queries.
Calls to filter can be chained and even grouped.
Galaxy.query(on: conn).filter(\.mass >= 500).filter(\.type == .spiral)
Below is a list of all supported operators.
| operator | type |
|---|---|
== |
Equal |
!= |
Not equal |
> |
Greater than |
< |
Less than |
>= |
Greater than or equal |
<= |
Less than or equal |
By default, all chained filters will be used to limit the result set. You can use filter groups to change this behavior.
Galaxy.query(on: conn).group(.or) {
$0.filter(\.mass <= 250).filter(\.mass >= 500)
}.filter(\.type == .spiral)
The above query will include results where the galaxy's mass is below 250 or above 500 and the type is spiral.
!!! tip If you get an error that states your operator cannot be applied to two operands you are comparing in a filter, ensure you have imported your specific Fluent ORM (FluentSQLite, FluentMySQL, etc).
Range
You can apply Swift ranges to a query builder to limit the result set.
Galaxy.query(on: conn).range(..<50)
The above query will include only the first 50 results.
For more information on ranges, see docs for Swift's Range type.
Sort
Query results can be sorted by a given field.
Galaxy.query(on: conn).sort(\.name, .descending)
You can sort by multiple fields to perform tie breaking behavior where there is duplicate information in the one of the sorted fields.
Join
Other models can be joined to an existing query in order to further filter the results.
Galaxy.query(on: conn).join(\Planet.galaxyID, to: \Galaxy.id)
.filter(\Planet.name == "Earth")
Once a table has been joined using join(_:to:), you can use fully-qualified key paths to filter results based on data in the joined table.
The above query fetches all galaxies that have a planet named Earth.
You can even decode the joined models using alsoDecode(...).
Galaxy.query(on: conn)
// join Planet and filter
.alsoDecode(Planet.self).all()
The above query will decode an array of (Galaxy, Planet) tuples.
Fetch
To fetch the results of a query, use all(), chunk(max:closure:), first() or an aggregate method.
All
The most common method for fetching results is with all(). This will return all matching results according to any fliters applied.
Galaxy.query(on: conn).all()
When combined with range(_:), you can efficiently limit how many results are returned by the database.
Galaxy.query(on: conn).range(..<50).all()
Chunk
For situations where memory conservation is important, use chunk(...). This method returns the result set in multiple calls of a maximum chunk size.
Galaxy.query(on: conn).chunk(max: 32) { galaxies in
print(galaxies) // Array of 32 or less galaxies
}
First
The first() method is a convenience for fetching the first result of a query. It will automatically apply a range restriction to avoid transferring unnecessary data.
Galaxy.query(on: conn).filter(\.name == "Milky Way").first()
This method is more efficient than calling all and getting the first item in the array.
Update
After a model has been fetched from the database and mutated, you can use update(on:) to save the changes.
var planet: Planet ... // fetched from database
planet.name = "Earth"
planet.update(on: conn)
Delete
After a model has been fetched from the database, you can use delete(on:) to delete it.
var planet: Planet ... // fetched from database
planet.delete(on: conn)