ValueObservation

public struct ValueObservation<Reducer>

ValueObservation tracks changes in the results of database requests, and notifies fresh values whenever the database changes.

For example:

let observation = Player.observationForAll()
let observer = try observation.start(in: dbQueue) { players: [Player] in
    print("Players have changed.")
}
  • Default is false. Set this property to true when the observation requires write access in order to fetch fresh values. Fetches are then wrapped inside a savepoint.

    Don’t set this flag to true unless you really need it. A read/write observation is less efficient than a read-only observation.

    Declaration

    Swift

    public var requiresWriteAccess: Bool
  • scheduling controls how fresh values are notified. Default is .mainQueue.

    • .mainQueue: all values are notified on the main queue.

      If the observation starts on the main queue, an initial value is notified right upon subscription, synchronously::

      // On main queue
      let observation = Player.observationForAll()
      let observer = try observation.start(in: dbQueue) { players: [Player] in
          print("fresh players: \(players)")
      }
      // <- here "fresh players" is already printed.
      

      If the observation does not start on the main queue, an initial value is also notified on the main queue, but asynchronously:

      // Not on the main queue: "fresh players" is eventually printed
      // on the main queue.
      let observation = Player.observationForAll()
      let observer = try observation.start(in: dbQueue) { players: [Player] in
          print("fresh players: \(players)")
      }
      

      When the database changes, fresh values are asynchronously notified:

      // Eventually prints "fresh players" on the main queue
      try dbQueue.write { db in
          try Player(...).insert(db)
      }
      
    • .onQueue(_:startImmediately:): all values are asychronously notified on the specified queue.

      An initial value is fetched and notified if startImmediately is true.

    • unsafe(startImmediately:): values are not all notified on the same dispatch queue.

      If startImmediately is true, an initial value is notified right upon subscription, synchronously, on the dispatch queue which starts the observation.

      // On any queue
      var observation = Player.observationForAll()
      observation.scheduling = .unsafe(startImmediately: true)
      let observer = try observation.start(in: dbQueue) { players: [Player] in
          print("fresh players: \(players)")
      }
      // <- here "fresh players" is already printed.
      

      When the database changes, other values are notified on unspecified queues.

    Declaration

    Swift

    public var scheduling: ValueScheduling
  • Creates a ValueObservation which observes request, and notifies its count whenever it is modified by a database transaction.

    For example:

    let request = Player.all()
    let observation = ValueObservation.trackingCount(request)
    
    let observer = try observation.start(in: dbQueue) { count: Int in
        print("Number of players has changed")
    }
    

    The returned observation has the default configuration:

    • When started with the start(in:onError:onChange:) method, a fresh value is immediately notified on the main queue.
    • Upon subsequent database changes, fresh values are notified on the main queue.
    • The observation lasts until the observer returned by start is deallocated.

    Declaration

    Swift

    @available(*, deprecated, message: "Use request.observationForCount(﹚ instead")
    public static func trackingCount<Request: FetchRequest>(_ request: Request)
        -> ValueObservation<ValueReducers.RemoveDuplicates<ValueReducers.Fetch<Int>>>

    Parameters

    request

    the observed request.

    Return Value

    a ValueObservation.

  • Creates a ValueObservation which observes request, and notifies fresh values whenever the request is modified by a database transaction.

    For example:

    let request = Player.select(Column("name"), as: String.self)
    let observation = ValueObservation.trackingAll(request)
    
    let observer = try observation.start(in: dbQueue) { names: [String] in
        print("Player names have changed")
    }
    

    The returned observation has the default configuration:

    • When started with the start(in:onError:onChange:) method, a fresh value is immediately notified on the main queue.
    • Upon subsequent database changes, fresh values are notified on the main queue.
    • The observation lasts until the observer returned by start is deallocated.

    Declaration

    Swift

    @available(*, deprecated, message: "Use request.observationForAll(﹚ instead")
    public static func trackingAll<Request: FetchRequest>(_ request: Request)
        -> ValueObservation<DatabaseValuesReducer<Request.RowDecoder>>
        where Request.RowDecoder: DatabaseValueConvertible

    Parameters

    request

    the observed request.

    Return Value

    a ValueObservation.

  • Creates a ValueObservation which observes request, and notifies a fresh value whenever the request is modified by a database transaction.

    For example:

    let request = Player.select(max(Column("score")), as: Int.self)
    let observation = ValueObservation.trackingOne(request)
    
    let observer = try observation.start(in: dbQueue) { maxScore: Int? in
        print("Maximum score has changed")
    }
    

    The returned observation has the default configuration:

    • When started with the start(in:onError:onChange:) method, a fresh value is immediately notified on the main queue.
    • Upon subsequent database changes, fresh values are notified on the main queue.
    • The observation lasts until the observer returned by start is deallocated.

    Declaration

    Swift

    @available(*, deprecated, message: "Use request.observationForFirst(﹚ instead")
    public static func trackingOne<Request: FetchRequest>(_ request: Request)
        -> ValueObservation<DatabaseValueReducer<Request.RowDecoder>>
        where Request.RowDecoder: DatabaseValueConvertible

    Parameters

    request

    the observed request.

    Return Value

    a ValueObservation.

  • Creates a ValueObservation which observes request, and notifies fresh values whenever the request is modified by a database transaction.

    For example:

    let request = Player.select(Column("name"), as: Optional<String>.self)
    let observation = ValueObservation.trackingAll(request)
    
    let observer = try observation.start(in: dbQueue) { names: [String?] in
        print("Player names have changed")
    }
    

    The returned observation has the default configuration:

    • When started with the start(in:onError:onChange:) method, a fresh value is immediately notified on the main queue.
    • Upon subsequent database changes, fresh values are notified on the main queue.
    • The observation lasts until the observer returned by start is deallocated.

    Declaration

    Swift

    @available(*, deprecated, message: "Use request.observationForAll(﹚ instead")
    public static func trackingAll<Request: FetchRequest>(_ request: Request)
        -> ValueObservation<OptionalDatabaseValuesReducer<Request.RowDecoder._Wrapped>>
        where Request.RowDecoder: _OptionalProtocol,
        Request.RowDecoder._Wrapped: DatabaseValueConvertible

    Parameters

    request

    the observed request.

    Return Value

    a ValueObservation.

  • Creates a ValueObservation which observes request, and notifies fresh records whenever the request is modified by a database transaction.

    For example:

    let request = Player.all()
    let observation = ValueObservation.trackingAll(request)
    
    let observer = try observation.start(in: dbQueue) { players: [Player] in
        print("Players have changed")
    }
    

    The returned observation has the default configuration:

    • When started with the start(in:onError:onChange:) method, a fresh value is immediately notified on the main queue.
    • Upon subsequent database changes, fresh values are notified on the main queue.
    • The observation lasts until the observer returned by start is deallocated.

    Declaration

    Swift

    @available(*, deprecated, message: "Use request.observationForAll(﹚ instead")
    public static func trackingAll<Request: FetchRequest>(_ request: Request)
        -> ValueObservation<FetchableRecordsReducer<Request.RowDecoder>>
        where Request.RowDecoder: FetchableRecord

    Parameters

    request

    the observed request.

    Return Value

    a ValueObservation.

  • Creates a ValueObservation which observes request, and notifies a fresh record whenever the request is modified by a database transaction.

    For example:

    let request = Player.filter(key: 1)
    let observation = ValueObservation.trackingOne(request)
    
    let observer = try observation.start(in: dbQueue) { player: Player? in
        print("Player has changed")
    }
    

    The returned observation has the default configuration:

    • When started with the start(in:onError:onChange:) method, a fresh value is immediately notified on the main queue.
    • Upon subsequent database changes, fresh values are notified on the main queue.
    • The observation lasts until the observer returned by start is deallocated.

    Declaration

    Swift

    @available(*, deprecated, message: "Use request.observationForFirst(﹚ instead")
    public static func trackingOne<Request: FetchRequest>(_ request: Request) ->
        ValueObservation<FetchableRecordReducer<Request.RowDecoder>>
        where Request.RowDecoder: FetchableRecord

    Parameters

    request

    the observed request.

    Return Value

    a ValueObservation.

  • Creates a ValueObservation which observes request, and notifies fresh rows whenever the request is modified by a database transaction.

    For example:

    let request = SQLRequest<Row>(sql: "SELECT * FROM player")
    let observation = ValueObservation.trackingAll(request)
    
    let observer = try observation.start(in: dbQueue) { rows: [Row] in
        print("Players have changed")
    }
    

    The returned observation has the default configuration:

    • When started with the start(in:onError:onChange:) method, a fresh value is immediately notified on the main queue.
    • Upon subsequent database changes, fresh values are notified on the main queue.
    • The observation lasts until the observer returned by start is deallocated.

    Declaration

    Swift

    @available(*, deprecated, message: "Use request.observationForAll(﹚ instead")
    public static func trackingAll<Request: FetchRequest>(_ request: Request)
        -> ValueObservation<RowsReducer>
        where Request.RowDecoder == Row

    Parameters

    request

    the observed request.

    Return Value

    a ValueObservation.

  • Creates a ValueObservation which observes request, and notifies a fresh row whenever the request is modified by a database transaction.

    For example:

    let request = SQLRequest<Row>(sql: "SELECT * FROM player WHERE id = ?", arguments: [1])
    let observation = ValueObservation.trackingOne(request)
    
    let observer = try observation.start(in: dbQueue) { row: Row? in
        print("Players have changed")
    }
    

    The returned observation has the default configuration:

    • When started with the start(in:onError:onChange:) method, a fresh value is immediately notified on the main queue.
    • Upon subsequent database changes, fresh values are notified on the main queue.
    • The observation lasts until the observer returned by start is deallocated.

    Declaration

    Swift

    @available(*, deprecated, message: "Use request.observationForFirst(﹚ instead")
    public static func trackingOne<Request: FetchRequest>(_ request: Request)
        -> ValueObservation<RowReducer>
        where Request.RowDecoder == Row

    Parameters

    request

    the observed request.

    Return Value

    a ValueObservation.

  • Starts the value observation in the provided database reader (such as a database queue or database pool), and returns a transaction observer.

    Declaration

    Swift

    public func start(
        in reader: DatabaseReader,
        onChange: @escaping (Reducer.Value) -> Void) throws -> TransactionObserver

    Parameters

    reader

    A DatabaseReader.

    onChange

    A closure that is provided fresh values

    Return Value

    a TransactionObserver

  • Starts the value observation in the provided database reader (such as a database queue or database pool), and returns a transaction observer.

    Declaration

    Swift

    public func start(
        in reader: DatabaseReader,
        onError: @escaping (Error) -> Void,
        onChange: @escaping (Reducer.Value) -> Void) -> TransactionObserver

    Parameters

    reader

    A DatabaseReader.

    onError

    A closure that is provided eventual errors that happen during observation

    onChange

    A closure that is provided fresh values

    Return Value

    a TransactionObserver

  • Returns a ValueObservation which observes regions, and notifies the values returned by the reducer whenever one of the observed regions is modified by a database transaction.

    This method is the most fundamental way to create a ValueObservation.

    For example, this observation counts the number of a times the player table is modified:

    var count = 0
    let reducer = AnyValueReducer(
        fetch: { _ in /* don't fetch anything */ },
        value: { _ -> Int? in
            defer { count += 1 }
            return count })
    let observation = ValueObservation.tracking(Player.all(), reducer: { db in reducer })
    let observer = observation.start(in: dbQueue) { count: Int in
        print("Players have been modified \(count) times.")
    }
    

    The returned observation has the default configuration:

    • When started with the start(in:onError:onChange:) method, a fresh value is immediately notified on the main queue.
    • Upon subsequent database changes, fresh values are notified on the main queue.
    • The observation lasts until the observer returned by start is deallocated.

    Declaration

    Swift

    public static func tracking(
        _ regions: DatabaseRegionConvertible...,
        reducer: @escaping (Database) throws -> Reducer)
        -> ValueObservation

    Parameters

    regions

    A list of observed regions.

    reducer

    A reducer that turns database changes in the modified regions into fresh values. Currently only reducers that adopt the ValueReducer protocol are supported.

  • Returns a ValueObservation which observes regions, and notifies the values returned by the reducer whenever one of the observed regions is modified by a database transaction.

    This method is the most fundamental way to create a ValueObservation.

    For example, this observation counts the number of a times the player table is modified:

    var count = 0
    let reducer = AnyValueReducer(
        fetch: { _ in /* don't fetch anything */ },
        value: { _ -> Int? in
            defer { count += 1 }
            return count })
    let observation = ValueObservation.tracking([Player.all()], reducer: { db in reducer })
    let observer = observation.start(in: dbQueue) { count: Int in
        print("Players have been modified \(count) times.")
    }
    

    The returned observation has the default configuration:

    • When started with the start(in:onError:onChange:) method, a fresh value is immediately notified on the main queue.
    • Upon subsequent database changes, fresh values are notified on the main queue.
    • The observation lasts until the observer returned by start is deallocated.

    Declaration

    Swift

    public static func tracking(
        _ regions: [DatabaseRegionConvertible],
        reducer: @escaping (Database) throws -> Reducer)
        -> ValueObservation

    Parameters

    regions

    A list of observed regions.

    reducer

    A reducer that turns database changes in the modified regions into fresh values. Currently only reducers that adopt the ValueReducer protocol are supported.

  • Creates a ValueObservation which notifies the values returned by the fetch closure whenever a database transaction changes them.

    For example:

    let observation = ValueObservation.tracking { db in
        try Player.fetchAll(db)
    }
    
    let observer = try observation.start(in: dbQueue) { players: [Player] in
        print("Players have changed")
    }
    

    The returned observation has the default configuration:

    • When started with the start(in:onError:onChange:) method, a fresh value is immediately notified on the main queue.
    • Upon subsequent database changes, fresh values are notified on the main queue.
    • The observation lasts until the observer returned by start is deallocated.

    Declaration

    Swift

    public static func tracking<Value>(
        value: @escaping (Database) throws -> Value)
        -> ValueObservation<ValueReducers.Fetch<Value>>

    Parameters

    value

    A closure that fetches a value.

  • Creates a ValueObservation which observes regions, and notifies the values returned by the fetch closure whenever one of the observed regions is modified by a database transaction.

    For example:

    let observation = ValueObservation.tracking(
        Player.all(),
        fetch: { db in return try Player.fetchAll(db) })
    
    let observer = try observation.start(in: dbQueue) { players: [Player] in
        print("Players have changed")
    }
    

    The returned observation has the default configuration:

    • When started with the start(in:onError:onChange:) method, a fresh value is immediately notified on the main queue.
    • Upon subsequent database changes, fresh values are notified on the main queue.
    • The observation lasts until the observer returned by start is deallocated.

    Declaration

    Swift

    public static func tracking<Value>(
        _ regions: DatabaseRegionConvertible...,
        fetch: @escaping (Database) throws -> Value)
        -> ValueObservation<ValueReducers.Fetch<Value>>

    Parameters

    regions

    A list of observed regions.

    fetch

    A closure that fetches a value.

  • Creates a ValueObservation which observes regions, and notifies the values returned by the fetch closure whenever one of the observed regions is modified by a database transaction.

    For example:

    let observation = ValueObservation.tracking(
        [Player.all()],
        fetch: { db in return try Player.fetchAll(db) })
    
    let observer = try observation.start(in: dbQueue) { players: [Player] in
        print("Players have changed")
    }
    

    The returned observation has the default configuration:

    • When started with the start(in:onError:onChange:) method, a fresh value is immediately notified on the main queue.
    • Upon subsequent database changes, fresh values are notified on the main queue.
    • The observation lasts until the observer returned by start is deallocated.

    Declaration

    Swift

    public static func tracking<Value>(
        _ regions: [DatabaseRegionConvertible],
        fetch: @escaping (Database) throws -> Value)
        -> ValueObservation<ValueReducers.Fetch<Value>>

    Parameters

    regions

    A list of observed regions.

    fetch

    A closure that fetches a value.

  • Returns a ValueObservation which notifies the non-nil results of calling the given transformation which each element notified by this value observation.

    Declaration

    Swift

    public func compactMap<T>(_ transform: @escaping (Reducer.Value) -> T?)
        -> ValueObservation<ValueReducers.CompactMap<Reducer, T>>
  • Returns a ValueObservation which notifies the results of calling the given transformation which each element notified by this value observation.

    Declaration

    Swift

    public func map<T>(_ transform: @escaping (Reducer.Value) -> T)
        -> ValueObservation<ValueReducers.Map<Reducer, T>>
  • Returns a ValueObservation which filters out consecutive equal values.

    Declaration

    Swift

    @available(*, deprecated, renamed: "removeDuplicates")
    public func distinctUntilChanged()
        -> ValueObservation<ValueReducers.RemoveDuplicates<Reducer>>
  • Returns a ValueObservation which filters out consecutive equal values.

    Declaration

    Swift

    public func removeDuplicates()
        -> ValueObservation<ValueReducers.RemoveDuplicates<Reducer>>