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)