Association

public protocol Association : DerivableRequest

Experimental

The base protocol for all associations that define a connection between two record types.

  • The record type at the origin of the association.

    In the belongsTo association below, it is Book:

    struct Book: TableRecord {
        // BelongsToAssociation<Book, Author>
        static let author = belongsTo(Author.self)
    }
    

    Declaration

    Swift

    associatedtype OriginRowDecoder : TableRecord
  • forKey(_:) Default implementation

    Creates an association with the given key.

    This new key impacts how rows fetched from the resulting association should be consumed:

    struct Player: TableRecord {
        static let team = belongsTo(Team.self)
    }
    
    // Consume rows:
    let request = Player.including(required: Player.team.forKey("custom"))
    for row in Row.fetchAll(db, request) {
        let team: Team = row["custom"]
    }
    

    Default Implementation

    Creates an association with the given key.

    This new key helps Decodable records decode rows fetched from the resulting association:

    struct Player: TableRecord {
        static let team = belongsTo(Team.self)
    }
    
    struct PlayerInfo: FetchableRecord, Decodable {
        let player: Player
        let team: Team
    
        static func all() -> QueryInterfaceRequest<PlayerInfo> {
            return Player
                .including(required: Player.team.forKey(CodingKeys.team))
                .asRequest(of: PlayerInfo.self)
        }
    }
    
    let playerInfos = PlayerInfo.all().fetchAll(db)
    print(playerInfos.first?.team)
    

    Declaration

    Swift

    func forKey(_ key: String) -> Self
  • select(_:) Extension method

    Creates an association which selects selection.

    struct Player: TableRecord {
        static let team = belongsTo(Team.self)
    }
    
    // SELECT player.*, team.color
    // FROM player
    // JOIN team ON team.id = player.teamId
    let association = Player.team.select([Column("color")])
    var request = Player.including(required: association)
    

    Any previous selection is replaced:

    // SELECT player.*, team.color
    // FROM player
    // JOIN team ON team.id = player.teamId
    let association = Player.team
        .select([Column("id")])
        .select([Column("color")])
    var request = Player.including(required: association)
    

    Declaration

    Swift

    public func select(_ selection: [SQLSelectable]) -> Self
  • annotated(with:) Extension method

    Creates an association which appends selection.

    struct Player: TableRecord {
        static let team = belongsTo(Team.self)
    }
    
    // SELECT player.*, team.color, team.name
    // FROM player
    // JOIN team ON team.id = player.teamId
    let association = Player.team
        .select([Column("color")])
        .annotated(with: [Column("name")])
    var request = Player.including(required: association)
    

    Declaration

    Swift

    public func annotated(with selection: [SQLSelectable]) -> Self
  • filter(_:) Extension method

    Creates an association with the provided predicate promise added to the eventual set of already applied predicates.

    struct Player: TableRecord {
        static let team = belongsTo(Team.self)
    }
    
    // SELECT player.*, team.*
    // FROM player
    // JOIN team ON team.id = player.teamId AND 1
    let association = Player.team.filter { db in true }
    var request = Player.including(required: association)
    

    Declaration

    Swift

    public func filter(_ predicate: @escaping (Database) throws -> SQLExpressible) -> Self
  • order(_:) Extension method

    Creates an association with the provided orderings promise.

    struct Player: TableRecord {
        static let team = belongsTo(Team.self)
    }
    
    // SELECT player.*, team.*
    // FROM player
    // JOIN team ON team.id = player.teamId
    // ORDER BY team.name
    let association = Player.team.order { _ in [Column("name")] }
    var request = Player.including(required: association)
    

    Any previous ordering is replaced:

    // SELECT player.*, team.*
    // FROM player
    // JOIN team ON team.id = player.teamId
    // ORDER BY team.name
    let association = Player.team
        .order{ _ in [Column("color")] }
        .reversed()
        .order{ _ in [Column("name")] }
    var request = Player.including(required: association)
    

    Declaration

    Swift

    public func order(_ orderings: @escaping (Database) throws -> [SQLOrderingTerm]) -> Self
  • reversed() Extension method

    Creates an association that reverses applied orderings.

    struct Player: TableRecord {
        static let team = belongsTo(Team.self)
    }
    
    // SELECT player.*, team.*
    // FROM player
    // JOIN team ON team.id = player.teamId
    // ORDER BY team.name DESC
    let association = Player.team.order(Column("name")).reversed()
    var request = Player.including(required: association)
    

    If no ordering was applied, the returned association is identical.

    // SELECT player.*, team.*
    // FROM player
    // JOIN team ON team.id = player.teamId
    let association = Player.team.reversed()
    var request = Player.including(required: association)
    

    Declaration

    Swift

    public func reversed() -> Self
  • unordered() Extension method

    Creates an association without any ordering.

    struct Player: TableRecord {
        static let team = belongsTo(Team.self)
    }
    
    // SELECT player.*, team.*
    // FROM player
    // JOIN team ON team.id = player.teamId
    let association = Player.team.order(Column("name")).unordered()
    var request = Player.including(required: association)
    

    Declaration

    Swift

    public func unordered() -> Self
  • aliased(_:) Extension method

    Creates an association that allows you to define expressions that target a specific database table.

    In the example below, the team.color = ‘red’ condition in the where clause could be not achieved without table aliases.

    struct Player: TableRecord {
        static let team = belongsTo(Team.self)
    }
    
    // SELECT player.*, team.*
    // JOIN team ON ...
    // WHERE team.color = 'red'
    let teamAlias = TableAlias()
    let request = Player
        .including(required: Player.team.aliased(teamAlias))
        .filter(teamAlias[Column("color")] == "red")
    

    When you give a name to a table alias, you can reliably inject sql snippets in your requests:

    // SELECT player.*, custom.*
    // JOIN team custom ON ...
    // WHERE custom.color = 'red'
    let teamAlias = TableAlias(name: "custom")
    let request = Player
        .including(required: Player.team.aliased(teamAlias))
        .filter(sql: "custom.color = ?", arguments: ["red"])
    

    Declaration

    Swift

    public func aliased(_ alias: TableAlias) -> Self