FetchableRecord

Types that adopt FetchableRecord can be initialized from a database Row.

let row = try Row.fetchOne(db, sql: "SELECT ...")!
let player = Player(row)

The protocol comes with built-in methods that allow to fetch cursors, arrays, or single records:

try Player.fetchCursor(db, sql: "SELECT ...", arguments:...) // Cursor of Player
try Player.fetchAll(db, sql: "SELECT ...", arguments:...)    // [Player]
try Player.fetchOne(db, sql: "SELECT ...", arguments:...)    // Player?

let statement = try db.makeStatement(sql: "SELECT ...")
try Player.fetchCursor(statement, arguments:...) // Cursor of Player
try Player.fetchAll(statement, arguments:...)    // [Player]
try Player.fetchOne(statement, arguments:...)    // Player?

Row Decoding

  • init(row:) Default implementation

    Creates a record from row.

    For performance reasons, the row argument may be reused during the iteration of a fetch query. If you want to keep the row for later use, make sure to store a copy: self.row = row.copy().

    Default Implementation

Customizing the Format of Database Columns

  • databaseDecodingUserInfo Default implementation

    When the FetchableRecord type also adopts the standard Decodable protocol, you can use this dictionary to customize the decoding process from database rows.

    For example:

    // A key that holds a decoder's name
    let decoderName = CodingUserInfoKey(rawValue: "decoderName")!
    
    // A FetchableRecord + Decodable record
    struct Player: FetchableRecord, Decodable {
        // Customize the decoder name when decoding a database row
        static let databaseDecodingUserInfo: [CodingUserInfoKey: Any] = [decoderName: "Database"]
    
        init(from decoder: Decoder) throws {
            // Print the decoder name
            print(decoder.userInfo[decoderName])
            ...
        }
    }
    
    // prints "Database"
    let player = try Player.fetchOne(db, ...)
    
    // prints "JSON"
    let decoder = JSONDecoder()
    decoder.userInfo = [decoderName: "JSON"]
    let player = try decoder.decode(Player.self, from: ...)
    

    Default Implementation

  • databaseJSONDecoder(for:) Default implementation

    When the FetchableRecord type also adopts the standard Decodable protocol, this method controls the decoding process of nested properties from JSON database columns.

    The default implementation returns a JSONDecoder with the following properties:

    • dataDecodingStrategy: .base64
    • dateDecodingStrategy: .millisecondsSince1970
    • nonConformingFloatDecodingStrategy: .throw

    You can override those defaults:

    struct Achievement: Decodable {
        var name: String
        var date: Date
    }
    
    struct Player: Decodable, FetchableRecord {
        // stored in a JSON column
        var achievements: [Achievement]
    
        static func databaseJSONDecoder(for column: String) -> JSONDecoder {
            let decoder = JSONDecoder()
            decoder.dateDecodingStrategy = .iso8601
            return decoder
        }
    }
    

    Default Implementation

    Returns a JSONDecoder with the following properties:

    • dataDecodingStrategy: .base64
    • dateDecodingStrategy: .millisecondsSince1970
    • nonConformingFloatDecodingStrategy: .throw
  • databaseDateDecodingStrategy Default implementation

    When the FetchableRecord type also adopts the standard Decodable protocol, this property controls the decoding of date properties.

    Default value is .deferredToDate

    For example:

    struct Player: FetchableRecord, Decodable {
        static let databaseDateDecodingStrategy: DatabaseDateDecodingStrategy = .timeIntervalSince1970
    
        var name: String
        var registrationDate: Date // decoded from epoch timestamp
    }
    

    Default Implementation

  • databaseColumnDecodingStrategy Default implementation

    When the FetchableRecord type also adopts the standard Decodable protocol, this property controls the key decoding strategy.

    Default value is .useDefaultKeys

    For example:

    struct Player: FetchableRecord, Decodable {
        static let databaseDateDecodingStrategy: DatabaseColumnDecodingStrategy = .convertFromSnakeCase
    
        var playerID: String // decoded from player_id
    }
    

    Default Implementation

Fetching All

  • fetchCursor(_:) Extension method

    A cursor over all records fetched from the database.

    // SELECT * FROM player
    let players = try Player.fetchCursor(db) // Cursor of Player
    while let player = try players.next() {  // Player
        ...
    }
    

    Records are iterated in the natural ordering of the table.

    If the database is modified during the cursor iteration, the remaining elements are undefined.

    The cursor must be iterated in a protected dispatch queue.

    The selection defaults to all columns. This default can be changed for all requests by the TableRecord.databaseSelection property, or for individual requests with the TableRecord.select method.

    Throws

    A DatabaseError is thrown whenever an SQLite error occurs.
  • fetchAll(_:) Extension method

    An array of all records fetched from the database.

    // SELECT * FROM player
    let players = try Player.fetchAll(db) // [Player]
    

    The selection defaults to all columns. This default can be changed for all requests by the TableRecord.databaseSelection property, or for individual requests with the TableRecord.select method.

    Throws

    A DatabaseError is thrown whenever an SQLite error occurs.
  • fetchOne(_:) Extension method

    The first found record.

    // SELECT * FROM player LIMIT 1
    let player = try Player.fetchOne(db) // Player?
    

    The selection defaults to all columns. This default can be changed for all requests by the TableRecord.databaseSelection property, or for individual requests with the TableRecord.select method.

    Throws

    A DatabaseError is thrown whenever an SQLite error occurs.
  • fetchSet(_:) Extension method

    A set of all records fetched from the database.

    // SELECT * FROM player
    let players = try Player.fetchSet(db) // Set<Player>
    

    The selection defaults to all columns. This default can be changed for all requests by the TableRecord.databaseSelection property, or for individual requests with the TableRecord.select method.

    Throws

    A DatabaseError is thrown whenever an SQLite error occurs.

Fetching by Single-Column Primary Key

  • fetchCursor(_:keys:) Extension method

    Returns a cursor over records, given their primary keys.

    let players = try Player.fetchCursor(db, keys: [1, 2, 3]) // Cursor of Player
    while let player = try players.next() { // Player
        ...
    }
    

    Records are iterated in unspecified order.

    Throws

    A DatabaseError is thrown whenever an SQLite error occurs.
  • fetchAll(_:keys:) Extension method

    Returns an array of records, given their primary keys.

    let players = try Player.fetchAll(db, keys: [1, 2, 3]) // [Player]
    

    The order of records in the returned array is undefined.

    Throws

    A DatabaseError is thrown whenever an SQLite error occurs.
  • fetchOne(_:key:) Extension method

    Returns a single record given its primary key.

    let player = try Player.fetchOne(db, key: 123) // Player?
    

    Throws

    A DatabaseError is thrown whenever an SQLite error occurs.
  • fetchSet(_:keys:) Extension method

    Returns a set of records, given their primary keys.

    let players = try Player.fetchSet(db, keys: [1, 2, 3]) // Set<Player>
    

    Throws

    A DatabaseError is thrown whenever an SQLite error occurs.

Fetching From Prepared Statement

  • A cursor over records fetched from a prepared statement.

    let statement = try db.makeStatement(sql: "SELECT * FROM player")
    let players = try Player.fetchCursor(statement) // Cursor of Player
    while let player = try players.next() { // Player
        ...
    }
    

    If the database is modified during the cursor iteration, the remaining elements are undefined.

    The cursor must be iterated in a protected dispatch queue.

    Throws

    A DatabaseError is thrown whenever an SQLite error occurs.
  • Returns an array of records fetched from a prepared statement.

    let statement = try db.makeStatement(sql: "SELECT * FROM player")
    let players = try Player.fetchAll(statement) // [Player]
    

    Throws

    A DatabaseError is thrown whenever an SQLite error occurs.
  • Returns a single record fetched from a prepared statement.

    let statement = try db.makeStatement(sql: "SELECT * FROM player")
    let player = try Player.fetchOne(statement) // Player?
    

    Throws

    A DatabaseError is thrown whenever an SQLite error occurs.
  • Returns a set of records fetched from a prepared statement.

    let statement = try db.makeStatement(sql: "SELECT * FROM player")
    let players = try Player.fetchSet(statement) // Set<Player>
    

    Throws

    A DatabaseError is thrown whenever an SQLite error occurs.

Fetching From SQL

  • Returns a cursor over records fetched from an SQL query.

    let players = try Player.fetchCursor(db, sql: "SELECT * FROM player") // Cursor of Player
    while let player = try players.next() { // Player
        ...
    }
    

    If the database is modified during the cursor iteration, the remaining elements are undefined.

    The cursor must be iterated in a protected dispatch queue.

    Throws

    A DatabaseError is thrown whenever an SQLite error occurs.
  • Returns an array of records fetched from an SQL query.

    let players = try Player.fetchAll(db, sql: "SELECT * FROM player") // [Player]
    

    Throws

    A DatabaseError is thrown whenever an SQLite error occurs.
  • Returns a single record fetched from an SQL query.

    let player = try Player.fetchOne(db, sql: "SELECT * FROM player") // Player?
    

    Throws

    A DatabaseError is thrown whenever an SQLite error occurs.
  • Returns a set of records fetched from an SQL query.

    let players = try Player.fetchSet(db, sql: "SELECT * FROM player") // Set<Player>
    

    Throws

    A DatabaseError is thrown whenever an SQLite error occurs.

Fetching From FetchRequest

  • fetchCursor(_:_:) Extension method

    Returns a cursor over records fetched from a fetch request.

    let request = try Player.all()
    let players = try Player.fetchCursor(db, request) // Cursor of Player
    while let player = try players.next() { // Player
        ...
    }
    

    If the database is modified during the cursor iteration, the remaining elements are undefined.

    The cursor must be iterated in a protected dispatch queue.

    Throws

    A DatabaseError is thrown whenever an SQLite error occurs.
  • fetchAll(_:_:) Extension method

    Returns an array of records fetched from a fetch request.

    let request = try Player.all()
    let players = try Player.fetchAll(db, request) // [Player]
    

    Throws

    A DatabaseError is thrown whenever an SQLite error occurs.
  • fetchOne(_:_:) Extension method

    Returns a single record fetched from a fetch request.

    let request = try Player.filter(key: 1)
    let player = try Player.fetchOne(db, request) // Player?
    

    Throws

    A DatabaseError is thrown whenever an SQLite error occurs.
  • fetchSet(_:_:) Extension method

    Returns a set of records fetched from a fetch request.

    let request = try Player.all()
    let players = try Player.fetchSet(db, request) // Set<Player>
    

    Throws

    A DatabaseError is thrown whenever an SQLite error occurs.