Query Interface Organization
============================
**The [query interface] is a Swift API that approximates the [SQLite SELECT query grammar](https://sqlite.org/lang_select.html) through a hierarchy of values and protocols.**
This document exposes its inner organization, so that you can leverage the most of those types and protocols when you want it.
In the diagram below, protocols are pale blue and have rounded corners, and standard types are grey rectangles. Solid arrows read "inherits from", and dashed arrows read "produces". Generic types are marked as such, as well as "PATs" (protocols with associated types).
Diagram items are described below:
- [Association]
- [Column]
- [ColumnExpression]
- [DatabaseRegionConvertible]
- [DatabaseValue]
- [DatabaseValueConvertible]
- [DerivableRequest]
- [FetchRequest]
- [Int, String, Date…]
- [QueryInterfaceRequest]
- [SQL]
- [SQLExpression]
- [SQLExpressible]
- [SQLOrderingTerm]
- [SQLOrdering]
- [SQLRequest]
- [SQLSelectable]
- [SQLSelection]
- [SQLSpecificExpressible]
- [SQLSubquery]
- [SQLSubqueryable]
---
### Association
`Association` is the protocol for all [associations]. It is adopted by `BelongsToAssociation`, `HasManyAssociation`, etc. It conforms to [DerivableRequest].
```swift
protocol Association: DerivableRequest {
associatedtype OriginRowDecoder
func forKey(_ key: String) -> Self
}
```
Association has two sub-protocols:
```swift
protocol AssociationToOne: Association { }
protocol AssociationToMany: Association { }
```
`AssociationToMany`, adopted by `HasManyAssociation` and `HasManyThroughAssociation`, leverages [association aggregates].
### Column
`Column` is the type for database columns. It conforms to [ColumnExpression].
```swift
Column("name")
Column("id")
Column.rowID
```
### ColumnExpression
`ColumnExpression` is the protocol for database columns. It is adopted by [Column]. It conforms to [SQLSpecificExpressible].
```swift
protocol ColumnExpression: SQLSpecificExpressible {
/// The name of a database column.
var name: String { get }
}
```
Columns can be used, for example, to query database rows:
```swift
let row = try Row.fetchOne(db, sql: "SELECT 'Arthur' AS name")!
let name: String = row[Column("name")] // "Arthur"
```
Columns are special expressions that allow some optimizations and niceties:
- Database observation: When a request is limited to a known list of rowids in a database table, changes applied to other rows do not trigger the observation. GRDB needs column expressions in order to apply this optimization:
```swift
// Optimized Observations
ValueObservation.tracking { db in
try Player.fetchOne(db, id: 1)
// or
try Player.filter { $0.id == 1 }.fetchOne(db)
}
// Non-optimized observations
ValueObservation.tracking { db in
try SQLRequest("SELECT * FROM player WHERE id = 1").fetchOne(db)
// or
try Player.filter(sql: "id = 1").fetchOne(db)
}
```
- SQL generation: when it generates SQL queries, GRDB appends `LIMIT 1` or not, depending on the primary key and unique indexes used on the queried table. GRDB needs column expressions in order to improve its SQL generation:
```swift
// Nicer SQL
// SELECT * FROM player WHERE id = 1
try Player.fetchOne(db, id: 1)
try Player.filter { $0.id == 1 }.fetchOne(db)
// Less nice SQL
// SELECT * FROM player WHERE id = 1 LIMIT 1
try Player.filter(sql: "id = 1").fetchOne(db)
```
### DatabaseRegionConvertible
`DatabaseRegionConvertible` is the protocol for observable requests. It is adopted by [FetchRequest].
```swift
protocol DatabaseRegionConvertible {
func databaseRegion(_ db: Database) throws -> DatabaseRegion
}
```
DatabaseRegionConvertible feeds [DatabaseRegionObservation], which tracks database transactions that impact a particular database region:
```swift
let request = Player.all()
let observation = DatabaseRegionObservation(tracking: request)
let observer = try observation.start(in: dbQueue) { (db: Database) in
print("Players were changed")
}
```
### DatabaseValue
`DatabaseValue` is the type for SQL values (integers, doubles, strings, blobs, and NULL). It conforms to [SQLSpecificExpressible].
You generally build a DatabaseValue from a [DatabaseValueConvertible] type:
```swift
1.databaseValue
"Hello".databaseValue
DatabaseValue.null
```
The query interface will sometimes not accept raw [SQLExpressible] values such as [Int, String, Date], etc. In this case, turn those values into DatabaseValue so that you leverage APIs that need [SQLSpecificExpressible]. For example:
```swift
// SQL: firstName || ' ' || lastName
let fullname = [
Column("firstName"),
" ".databaseValue,
Column("lastName"),
].joined(operator: .concat)
```
### DatabaseValueConvertible
`DatabaseValueConvertible` is the protocol for types that can provide [DatabaseValue]: SQL integers, doubles, strings, blobs, and NULL. It is adopted by [Int, String, Date], etc. It conforms to [SQLExpressible] because all SQL values are SQL expressions.
```swift
protocol DatabaseValueConvertible: SQLExpressible {
/// Returns a value that can be stored in the database.
var databaseValue: DatabaseValue { get }
/// Returns a value initialized from `dbValue`, if possible.
static func fromDatabaseValue(_ dbValue: DatabaseValue) -> Self?
}
```
### DerivableRequest
`DerivableRequest` is the protocol for query interface requests and associations that can be refined. It is adopted by [QueryInterfaceRequest] and [Association].
```swift
protocol DerivableRequest: AggregatingRequest, FilteredRequest,
JoinableRequest, OrderedRequest,
SelectionRequest, TableRequest
{
func distinct() -> Self
func with(_ cte: CommonTableExpression) -> Self
}
```
- `AggregatingRequest` provides grouping methods such as `groupByPrimaryKey()`
- `FilteredRequest` provides filtering methods such as `filter(expression)` or `filter(id: value)`
- `JoinableRequest` provides association methods such as `joining(required: association)` or `including(all: association)`
- `OrderedRequest` provides ordering methods such as `order(ordering)` or `reversed()`
- `SelectionRequest` provides selection methods such as `select(selection)` or `annotated(with: selection)`
- `TableRequest` provides table targeting methods such as `aliased(tableAlias)`
DerivableRequest makes it possible to build reusable code snippets that apply to both requests and associations. You'll read more about it in the [Recommended Practices for Designing Record Types](https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/recordrecommendedpractices) and [Associations](AssociationsBasics.md).
### FetchRequest
`FetchRequest` is the protocol for requests that can fetch. It is adopted by [QueryInterfaceRequest] and [SQLRequest]. It conforms to [SQLSubqueryable] and [DatabaseRegionConvertible].
```swift
protocol FetchRequest: SQLSubqueryable, DatabaseRegionConvertible {
/// The type that tells how fetched database rows should be interpreted.
associatedtype RowDecoder
/// Returns a PreparedRequest that is ready to be executed.
func makePreparedRequest(_ db: Database, forSingleResult singleResult: Bool) throws -> PreparedRequest
/// Returns the number of rows fetched by the request.
func fetchCount(_ db: Database) throws -> Int
}
```
FetchRequest can fetch values from the database as long as its `RowDecoder` associated type is `Row`, a [DatabaseValueConvertible] type, or a [FetchableRecord] type.
```swift
let row: Row? = try SQLRequest("SELECT * FROM player").fetchOne(db)
let players: [Player] = try Player.all().fetchAll(db)
```
FetchRequest usually executes a single SQL query:
```swift
// SELECT * FROM player
let request = Player.all()
try request.fetchAll(db)
```
This single SQL query is exposed through `makePreparedRequest(_:forSingleResult:)`:
```swift
let request = Player.all()
let preparedRequest = try request.makePreparedRequest(db)
print(preparedRequest.statement.sql) // SELECT * FROM player
```
But not all fetch requests execute a single SQL query. A [QueryInterfaceRequest] that involves [associations] can execute several:
```swift
// SELECT * FROM player
// SELECT * FROM award WHERE playerId IN (...)
struct PlayerInfo: Decodable, FetchableRecord {
var player: Player
var awards: [Award]
}
let playerInfos = try Player
.including(all: Player.awards)
.asRequest(of: PlayerInfo.self)
.fetchAll(db)
```
Those supplementary SQL queries are an implementation detail of `PreparedRequest`, and are not currently exposed.
### Int, String, Date…
The basic value types conform to [DatabaseValueConvertible] so that they can feed database queries with [DatabaseValue]:
```swift
// SELECT * FROM player WHERE name = 'O''Brien'
// ~~~~~~~~~~
Player.filter { $0.name == "O'Brien" }
```
### QueryInterfaceRequest
`QueryInterfaceRequest` is the type of fetch requests built by the GRDB query builder. It conforms to [FetchRequest] and [DerivableRequest].
It is generic on the type of fetched values:
```swift
struct PlayerInfo: Decodable, FetchableRecord {
var player: Player
var awards: [Award]
}
// QueryInterfaceRequest
let playerRequest = Player.all()
// QueryInterfaceRequest
let nameRequest = Player.select(Column("name"), as: String.self)
// QueryInterfaceRequest
let playerInfoRequest = Player
.including(all: Player.awards)
.asRequest(of: PlayerInfo.self)
try playerRequest.fetchAll(db) // [Player]
try nameRequest.fetchAll(db) // [String]
try playerInfoRequest.fetchAll(db) // [PlayerInfo]
```
For more information on QueryInterfaceRequest, see [Requests](../README.md#requests) and [Associations](AssociationsBasics.md).
### SQL
`SQL` is the type for SQL literals that support [SQL Interpolation]. It can feed all GRDB APIs that have a `literal` argument:
```swift
let literal: SQL = "SELECT * FROM player"
let request = SQLRequest(literal: literal)
let players: [Player] = try request.fetchAll(db)
```
`SQL` conforms to [SQLSpecificExpressible], and thus behaves as an [SQLite expression](https://sqlite.org/syntax/expr.html) by default:
```swift
let literal: SQL = "name = \("O'Brien")"
let request = Player.filter(literal)
let players: [Player] = try request.fetchAll(db)
```
:warning: **Warning**: Not all SQL snippets are expressions. It is not recommended to pass `SQL` literals around, or you may end up forgetting their content, and eventually generate invalid SQL. When possible, prefer building an explicit [SQLExpression], [SQLOrdering], [SQLSelection], [SQLRequest], or [SQLSubquery], depending on what you want to express:
```swift
// SQLExpression
SQL("name = \("O'Brien")").sqlExpression
// SQLOrdering
SQL("name DESC)").sqlOrdering
// SQLSelection
SQL("score + bonus AS total)").sqlSelection
SQL("*").sqlSelection
// SQLRequest
SQLRequest(literal: "SELECT * FROM player")
// SQLSubquery
SQLRequest(literal: "SELECT * FROM player").sqlSubquery
```
### SQLExpression
`SQLExpression` is the opaque type for all [SQLite expressions](https://sqlite.org/syntax/expr.html). It adopts [SQLSpecificExpressible], and is built from [SQLExpressible].
```swift
struct SQLExpression: SQLSpecificExpressible {
// opaque implementation
}
```
Functions and methods that build an SQL expression should return an SQLExpression value:
```swift
// SELECT * FROM player WHERE LENGTH(name) > 0
Player.filter {
length($0.name) > 0 // SQLExpression
}
```
When it looks like GRDB APIs are unable to build a particular expression, use [SQL]:
```swift
func date(_ value: SQLSpecificExpressible) -> SQLExpression {
SQL("DATE(\(value))").sqlExpression
}
// SELECT * FROM player WHERE DATE(createdAt) = '2020-01-23'
let request = Player.filter { date($0.createdAt) == "2020-01-23" }
```
This technique, based on [SQL Interpolation], is composable and works well even when several tables are involved. See how the `createdAt` column below is correctly attributed to the `player` table:
```swift
// SELECT player.*, team.* FROM player
// JOIN team ON team.id = player.teamId
// WHERE DATE(player.createdAt) = '2020-01-23'
let request = Player
.filter { date($0.createdAt) == "2020-01-23" }
.including(required: Player.team)
```
### SQLExpressible
`SQLExpressible` is the protocol for all [SQLite expressions](https://sqlite.org/syntax/expr.html). It is adopted by [Column], [SQL], [SQLExpression], and also [Int, String, Date], etc. It has an `sqlExpression` property which returns an [SQLExpression].
```swift
protocol SQLExpressible {
var sqlExpression: SQLExpression { get }
}
```
SQLExpressible-conforming types include types which are not directly related to SQL, such as [Int, String, Date], etc. Because of this, SQLExpressible has limited powers that prevent misuses and API pollution. For full-fledged SQL expressions, see [SQLSpecificExpressible]. For example, compare:
```swift
Player.filter(1) // Compiler warning (will become an error in the next major release)
Player.select(1) // Compiler error
Player.order("name") // Compiler error
length("name") // Compiler error
"name".desc // Compiler error
```
```swift
Player.filter(id: 1) // OK
Player.filter(1.databaseValue) // Odd, but OK
Player.select(1.databaseValue) // Odd, but OK
Player.order(Column("name")) // OK
length(Column("name")) // OK
Column("name").desc // OK
```
### SQLOrderingTerm
`SQLOrderingTerm` is the protocol for all [SQLite ordering terms](https://sqlite.org/syntax/ordering-term.html). It is adopted by [SQLSpecificExpressible]. It has an `sqlOrdering` property which returns an [SQLOrdering].
```swift
protocol SQLOrderingTerm {
var sqlOrdering: SQLOrdering { get }
}
```
SQLOrderingTerm feeds the `order()` method of the query interface:
```swift
// SELECT * FROM player
// ORDER BY score DESC, name COLLATE ...
Player.order(
Column("score").desc,
Column("name").collating(.localizedCaseInsensitiveCompare))
```
All [SQLSpecificExpressible] values are ordering terms. [SQLExpressible] values are not: `Player.order("name")` does not compile. Instead, use:
```swift
// SELECT * FROM player ORDER BY name -- Order according to a column
Player.order(Column("name"))
// SELECT * FROM player ORDER BY 'name' -- Order according to a constant string (why not)
Player.order("name".databaseValue)
```
### SQLOrdering
`SQLOrdering` is the opaque type for all [SQLite ordering terms](https://sqlite.org/syntax/ordering-term.html). An SQLOrdering adopts and is built from [SQLOrderingTerm].
```swift
struct SQLOrdering: SQLOrderingTerm {
// opaque implementation
}
```
Functions and methods that build ordering terms should return an SQLOrdering value:
```swift
// SELECT * FROM player ORDER BY score DESC
let ordering = Column("score").desc // SQLOrdering
Player.order(ordering)
```
To build an SQLOrdering without applying any `DESC` or `ASC` qualifier, use `sqlOrdering` (from [SQLOrderingTerm], inherited by [SQLSpecificExpressible], [ColumnExpression]...):
```swift
let ordering = Column("score").sqlOrdering // SQLOrdering
```
### SQLRequest
`SQLRequest` is the type of fetch requests expressed with raw SQL. It conforms to [FetchRequest].
It is generic on the type of fetched values (which defaults to `Row`):
```swift
let rowRequest = SQLRequest(sql: "SELECT * FROM player") // SQLRequest
let playerRequest = SQLRequest(sql: "SELECT * FROM player") // SQLRequest
let nameRequest = SQLRequest(sql: "SELECT name FROM player") // SQLRequest
try rowRequest.fetchAll(db) // [Row]
try playerRequest.fetchAll(db) // [Player]
try nameRequest.fetchAll(db) // [String]
try rowRequest.fetchOne(db) // Row?
try playerRequest.fetchOne(db) // Player?
try nameRequest.fetchOne(db) // String?
```
SQLRequest supports [SQL Interpolation]:
```swift
// SELECT * FROM player WHERE name = 'O''Brien'
let playerRequest: SQLRequest = """
SELECT * FROM player WHERE name = \("O'Brien")
"""
```
### SQLSelectable
`SQLSelectable` is the protocol for all [SQLite result columns](https://sqlite.org/syntax/result-column.html). It is adopted by [SQLSpecificExpressible]. It has an `sqlSelection` property which returns an [SQLSelection].
```swift
protocol SQLSelectable {
var sqlSelection: SQLSelection { get }
}
```
SQLSelectable feeds the `select()` method of the query interface:
```swift
Player.select(.allColumns)
Player.select(Column("name"), Column("score"))
```
All [SQLSpecificExpressible] values are selectable. Other selectable values are:
```swift
// SELECT * FROM player
Player.select(.allColumns)
// SELECT MAX(score) AS maxScore FROM player
Player.select(max(Column("score")).forKey("maxScore"))
```
[SQLExpressible] values are not selectable: `Player.select("name")` does not compile. Instead, use:
```swift
// SELECT name FROM player -- Selects a column
Player.select(Column("name"))
// SELECT 'name' FROM player -- Selects a constant string (why not)
Player.select("name".databaseValue)
```
### SQLSelection
`SQLSelection` is the opaque type for all [SQLite result columns](https://sqlite.org/syntax/result-column.html). An SQLSelection adopts and is built from [SQLSelectable].
```swift
struct SQLSelection: SQLSelectable {
// opaque implementation
}
```
Functions and methods that build result columns should return an SQLSelection value:
```swift
// SELECT (score + bonus) AS total
let selection = (Column("score") + Column("bonus")).forKey("total") // SQLSelection
Player.select(selection)
```
### SQLSpecificExpressible
`SQLSpecificExpressible` is the protocol for all SQL expressions, except values such as [Int, String, Date], etc. It conforms to [SQLExpressible], [SQLSelectable], and [SQLOrderingTerm]. It is adopted by [Column], [SQL], and [SQLExpression]. It is also adopted through [SQLSubqueryable] by [QueryInterfaceRequest] and [SQLRequest].
```swift
protocol SQLSpecificExpressible: SQLExpressible, SQLSelectable, SQLOrderingTerm { }
```
Use SQLSpecificExpressible when you want to operate on expressions, except [Int, String, Date] and other types which are not directly related to SQL. For example, the built-in `length(_:)` GRDB function accepts SQLSpecificExpressible:
```swift
/// The LENGTH SQL function
func length(_ value: SQLSpecificExpressible) -> SQLExpression { ... }
length(Column("name")) // OK
length("name") // Compiler error
```
### SQLSubquery
`SQLSubquery` is the opaque type for all [SQLite SELECT queries](https://sqlite.org/syntax/select-stmt.html). An SQLSubquery adopts and is built from [SQLSubqueryable].
```swift
struct SQLSubquery: SQLSubqueryable {
// opaque implementation
}
```
### SQLSubqueryable
`SQLSubqueryable` is the protocol for all [SQLite SELECT queries](https://sqlite.org/syntax/select-stmt.html). It conforms to [SQLSpecificExpressible], and is adopted by [FetchRequest], [QueryInterfaceRequest], [SQLRequest]. It has an `sqlSubquery` property which returns an [SQLSubquery].
```swift
protocol SQLSubqueryable: SQLSpecificExpressible {
var sqlSubquery: SQLSubquery { get }
}
```
SQLSubqueryable provides the GRDB support for subqueries. Its [SQLSpecificExpressible] facet lets you use any request as an expression:
```swift
// SELECT * FROM player
// WHERE score >= (SELECT AVG(score) FROM player)
let averageScore = Player.select(average(Column("score")))
Player.filter { $0.score >= averageScore }
```
SQLSubqueryable has the `contains(_:)` and `exists()` methods that support the `value IN (subquery)` and `EXISTS (subquery)` expressions.
Use SQLSubqueryable in order to define a function that requires a subquery argument:
```swift
func myRequest(_ nameSubquery: SQLSubqueryable) -> SQLRequest {
"""
SELECT * FROM player
WHERE name IN (\(nameSubquery) UNION ...)
"""
}
myRequest(SQLRequest("SELECT ..."))
myRequest(Player.select(...).filter(...))
```
[Association]: #association
[associations]: AssociationsBasics.md
[association aggregates]: AssociationsBasics.md#association-aggregates
[Column]: #column
[ColumnExpression]: #columnexpression
[DatabaseRegionConvertible]: https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/databaseregionconvertible
[DatabaseRegionObservation]: https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/databaseregionobservation
[DatabaseValue]: #databasevalue
[DatabaseValueConvertible]: #databasevalueconvertible
[DerivableRequest]: #derivablerequest
[FetchableRecord]: ../README.md#fetchablerecord-protocol
[FetchRequest]: #fetchrequest
[Int, String, Date…]: #int-string-date
[Int, String, Date]: #int-string-date
[query interface]: ../README.md#the-query-interface
[QueryInterfaceRequest]: #queryinterfacerequest
[SQL]: #sql
[SQL Interpolation]: SQLInterpolation.md
[SQLExpression]: #sqlexpression
[SQLExpressible]: #sqlexpressible
[SQLOrderingTerm]: #sqlorderingterm
[SQLOrdering]: #sqlordering
[SQLRequest]: #sqlrequest
[SQLSelectable]: #sqlselectable
[SQLSelection]: #sqlselection
[SQLSpecificExpressible]: #sqlspecificexpressible
[SQLSubquery]: #sqlsubquery
[SQLSubqueryable]: #sqlsubqueryable