纸莎草

Papyrus 通过提供简单的对象缓存层,使应用程序能够首先离线工作。

简单示例

struct Car: Papyrus {
    let id: String
    let model: String
    let manufacturer: String
}

let car = Car(id: "abc...", model: "Model S", manufacturer: "Tesla")
let store = PapyrusStore()
try await store.save(car)

实际示例

在此示例中,我们使用 AsyncThrowingStream 来传递值。

一般概念是,首先我们产生缓存数据,执行 API 请求,产生新对象,最后合并新的缓存对象。

import AsyncAlgorithms
import Papyrus

struct CarProvider {
    var all: () -> AsyncThrowingStream<[Car], Error>
}

extension CarProvider {
    static func live(
        apiClient: TeslaAPIClient = .live,
        store: PapyrusStore = .live
    ) -> Self {
        .init(
            all: {
                AsyncThrowingStream { continuation in
                    do {
                        var stores = store.objects(type: Car.self).execute()
                        continuation.yield(stores)
                        
                        let request = FetchCarsRequest()
                        cars = try await apiClient.execute(request: request)
                        continuation.yield(cars)
                        try await store.merge(with: cars)
                        continuation.finish()
                    } catch {
                        continuation.finish(throwing: error)
                    }
                }
                .removeDuplicates()
                .eraseToThrowingStream()
            }
        )
    }
}

要求

安装

Swift Package Manager

在 Xcode 中

  1. 点击 Project
  2. 点击 Package Dependencies
  3. 点击 +
  4. 输入包 URL: https://github.com/reddavis/Papyrus
  5. Papyrus 添加到你的应用程序目标。

文档

API 参考

用法

保存

任何符合 Papyrus 协议的内容都可以被存储。

Papyrus 协议只是以下三个协议的统称

示例 A

struct Car: Papyrus {
    let id: String
    let model: String
    let manufacturer: String
}

let car = Car(id: "abc...", model: "Model S", manufacturer: "Tesla")
let store = PapyrusStore()
try await store.save(car)

示例 B - 合并

在处理 API 时,一个常见的用例是获取对象集合并将结果合并到你的本地集合中。

Papyrus 为此提供了一个函数

let carA = Car(id: "abc...", model: "Model S", manufacturer: "Tesla")
let carB = Car(id: "def...", model: "Model 3", manufacturer: "Tesla")
let carC = Car(id: "ghi...", model: "Model X", manufacturer: "Tesla")

let store = PapyrusStore()
try await store.save(objects: [carA, carB])

try await store.merge(with: [carA, carC])
store
    .objects(type: Car.self)
    .execute()
// #=> [carA, carC]

按 ID 获取

获取对象有两种形式

示例 A

let store = PapyrusStore()
let tesla = store.object(id: "abc...", of: Manufacturer.self).execute()

示例 B

let store = PapyrusStore()
let stream = store.object(id: "abc...", of: Manufacturer.self).stream()

do {
    for try await object in stream {
        ...
    }
} catch {
    //.. Do something
}

获取集合

Papryrus 使你能够获取、筛选和观察对象集合。

示例 A - 简单获取

let manufacturers = self.store
    .objects(type: Manufacturer.self)
    .execute()

示例 B - 筛选

let manufacturers = await self.store
    .objects(type: Manufacturer.self)
    .filter { $0.name == "Tesla" }
    .execute()

示例 C - 排序

let manufacturers = await self.store
    .objects(type: Manufacturer.self)
    .sort { $0.name < $1.name }
    .execute()

示例 D - 观察更改

PapryrusStore.CollectionQuery 对象上调用 stream() 将返回一个 AsyncThrowingStream,它将发出对象集合。除非另有说明,否则只要检测到更改,流将继续发出对象集合。

更改包括

let stream = self.store
    .objects(type: Manufacturer.self)
    .filter { $0.name == "Tesla" }
    .sort { $0.name < $1.name }
    .stream()

do {
    for try await manufacturers in stream {
        // ... Do something with [Manufacturer].
    }
} catch {
    //.. Do something
}

删除

有几种删除对象的方法。

示例 A

let store = PapyrusStore()
let tesla = store.object(id: "abc...", of: Manufacturer.self)
try store.delete(tesla)

示例 B

let store = PapyrusStore()
try store.delete(id: "abc...", of: Manufacturer.self)

示例 C

let store = PapyrusStore()
let tesla = store.object(id: "abc...", of: Manufacturer.self)
let ford = store.object(id: "xyz...", of: Manufacturer.self)
try store.delete(objects: [tesla, ford])