add swiftUI code

This commit is contained in:
zeus
2025-01-22 14:09:10 +08:00
parent 68e7b7347c
commit 8a99853829
2531 changed files with 486215 additions and 0 deletions
@@ -0,0 +1,20 @@
extension ValueReducers {
/// A `ValueReducer` that perform database fetches.
public struct Fetch<Value>: ValueReducer {
private let __fetch: (Database) throws -> Value
/// Creates a reducer which passes raw fetched values through.
init(fetch: @escaping (Database) throws -> Value) {
self.__fetch = fetch
}
public func _fetch(_ db: Database) throws -> Value {
assert(db.isInsideTransaction, "Fetching in a non-isolated way is illegal")
return try __fetch(db)
}
public func _value(_ fetched: Value) -> Value? {
fetched
}
}
}
@@ -0,0 +1,53 @@
extension ValueObservation {
/// Transforms all values from the upstream observation with a
/// provided closure.
///
/// For example:
///
/// ```swift
/// // Turn an observation of Player? into an observation of UIImage?
/// let observation = ValueObservation
/// .tracking { db in try Player.fetchOne(db, id: 42) }
/// .map { player in player?.image }
/// ```
///
/// The `transform` closure does not run on the main thread, and does not
/// block any database access This makes the `map` operator a tool that
/// helps reducing database contention
/// (see <doc:ValueObservation#ValueObservation-Performance>).
///
/// - parameter transform: A closure that takes one value as its parameter
/// and returns a new value.
public func map<T>(_ transform: @escaping (Reducer.Value) throws -> T)
-> ValueObservation<ValueReducers.Map<Reducer, T>>
{
mapReducer { ValueReducers.Map($0, transform) }
}
}
extension ValueReducers {
/// A `ValueReducer` whose values consist of those in a `Base` reduced
/// passed through a transform function.
///
/// See ``ValueObservation/map(_:)``.
public struct Map<Base: _ValueReducer, Value>: _ValueReducer {
private var base: Base
private let transform: (Base.Value) throws -> Value
init(_ base: Base, _ transform: @escaping (Base.Value) throws -> Value) {
self.base = base
self.transform = transform
}
public mutating func _value(_ fetched: Base.Fetched) throws -> Value? {
guard let value = try base._value(fetched) else { return nil }
return try transform(value)
}
}
}
extension ValueReducers.Map: ValueReducer where Base: ValueReducer {
public func _fetch(_ db: Database) throws -> Base.Fetched {
try base._fetch(db)
}
}
@@ -0,0 +1,98 @@
extension ValueObservation {
/// Notifies only values that dont match the previously observed value, as
/// evaluated by a provided closure.
///
/// - parameter predicate: A closure to evaluate whether two values are
/// equivalent, for purposes of filtering. Return true from this closure
/// to indicate that the second element is a duplicate of the first.
public func removeDuplicates(by predicate: @escaping (Reducer.Value, Reducer.Value) -> Bool)
-> ValueObservation<ValueReducers.RemoveDuplicates<Reducer>>
{
mapReducer { ValueReducers.RemoveDuplicates($0, predicate: predicate) }
}
}
extension ValueObservation where Reducer.Value: Equatable {
/// Notifies only values that dont match the previously observed value.
///
/// For example:
///
/// ```swift
/// // An observation of distinct Player?
/// let observation = ValueObservation
/// .tracking { db in try Player.fetchOne(db, id: 42) }
/// .removeDuplicates()
/// ```
///
/// > Tip: When the observed value does not adopt `Equatable`, and it is
/// > impractical to provide a custom comparison function, you can observe
/// > distinct raw database values such as ``Row`` or ``DatabaseValue``,
/// > before converting them to the desired type. For example, the previous
/// > observation can be rewritten as below:
/// >
/// > ```swift
/// > // An observation of distinct `Player?`
/// > let request = Player.filter(id: 42)
/// > let observation = ValueObservation
/// > .tracking { db in try Row.fetchOne(db, request) }
/// > .removeDuplicates()
/// > .map { row in try row.map(Player.init(row:)) }
/// > ```
/// >
/// > This technique is also available for requests that
/// > involve associations:
/// >
/// > ```swift
/// > struct TeamInfo: Decodable, FetchableRecord {
/// > var team: Team
/// > var players: [Player]
/// > }
/// >
/// > // An observation of distinct `[TeamInfo]`
/// > let request = Team.including(all: Team.players)
/// > let observation = ValueObservation
/// > .tracking { db in try Row.fetchAll(db, request) }
/// > .removeDuplicates() // Row adopts Equatable
/// > .map { rows in try rows.map(TeamInfo.init(row:)) }
/// > ```
public func removeDuplicates()
-> ValueObservation<ValueReducers.RemoveDuplicates<Reducer>>
{
mapReducer { ValueReducers.RemoveDuplicates($0, predicate: ==) }
}
}
extension ValueReducers {
/// A `ValueReducer` that notifies only values that dont match the
/// previously observed value.
///
/// See ``ValueObservation/removeDuplicates()``.
public struct RemoveDuplicates<Base: _ValueReducer>: _ValueReducer {
private var base: Base
private var previousValue: Base.Value?
private var predicate: (Base.Value, Base.Value) -> Bool
init(_ base: Base, predicate: @escaping (Base.Value, Base.Value) -> Bool) {
self.base = base
self.predicate = predicate
}
public mutating func _value(_ fetched: Base.Fetched) throws -> Base.Value? {
guard let value = try base._value(fetched) else {
return nil
}
if let previousValue, predicate(previousValue, value) {
// Don't notify consecutive identical values
return nil
}
self.previousValue = value
return value
}
}
}
extension ValueReducers.RemoveDuplicates: ValueReducer where Base: ValueReducer {
public func _fetch(_ db: Database) throws -> Base.Fetched {
try base._fetch(db)
}
}
@@ -0,0 +1,28 @@
extension ValueReducers {
// swiftlint:disable line_length
/// A `ValueReducer` that handles ``ValueObservation`` events.
///
/// See ``ValueObservation/handleEvents(willStart:willFetch:willTrackRegion:databaseDidChange:didReceiveValue:didFail:didCancel:)``
/// and ``ValueObservation/print(_:to:)``.
public struct Trace<Base: _ValueReducer>: _ValueReducer {
var base: Base
let willFetch: () -> Void
let didReceiveValue: (Base.Value) -> Void
public mutating func _value(_ fetched: Base.Fetched) throws -> Base.Value? {
guard let value = try base._value(fetched) else {
return nil
}
didReceiveValue(value)
return value
}
}
// swiftlint:enable line_length
}
extension ValueReducers.Trace: ValueReducer where Base: ValueReducer {
public func _fetch(_ db: Database) throws -> Base.Fetched {
willFetch()
return try base._fetch(db)
}
}
@@ -0,0 +1,42 @@
/// Implementation details of `ValueReducer`.
public protocol _ValueReducer {
/// The type of fetched database values
associatedtype Fetched
/// The type of observed values
associatedtype Value
/// Transforms a fetched value into an eventual observed value. Returns nil
/// when observer should not be notified.
///
/// This method runs in some unspecified dispatch queue.
///
/// ValueReducer semantics require that the first invocation of this
/// method returns a non-nil value:
///
/// let reducer = MyReducer()
/// reducer._value(...) // MUST NOT be nil
/// reducer._value(...) // MAY be nil
/// reducer._value(...) // MAY be nil
mutating func _value(_ fetched: Fetched) throws -> Value?
}
/// `ValueReducer` supports ``ValueObservation``.
///
/// A `ValueReducer` fetches and transforms the database values
/// observed by a ``ValueObservation``.
///
/// ## Topics
///
/// ### Support
///
/// - ``ValueReducers``
public protocol ValueReducer: _ValueReducer {
/// Fetches database values upon changes in an observed database region.
///
/// This method must does not depend on the state of the reducer.
func _fetch(_ db: Database) throws -> Fetched
}
/// A namespace for concrete types that adopt the ``ValueReducer`` protocol.
public enum ValueReducers { }