Replace memory cache with Boutique SQLite cache

This commit is contained in:
Thomas Ricouard 2023-02-04 12:33:28 +01:00
parent 3c0ffdb1ae
commit aae6b12666
3 changed files with 67 additions and 5 deletions

View file

@ -1,5 +1,23 @@
{ {
"pins" : [ "pins" : [
{
"identity" : "bodega",
"kind" : "remoteSourceControl",
"location" : "https://github.com/mergesort/Bodega.git",
"state" : {
"revision" : "3e7c1c58ad9a46aa8551cebfe87770003cdaaaca",
"version" : "2.0.2"
}
},
{
"identity" : "boutique",
"kind" : "remoteSourceControl",
"location" : "https://github.com/mergesort/Boutique",
"state" : {
"revision" : "b5b697de67100edc4b2d5c74724f3c1068b49d4e",
"version" : "2.1.1"
}
},
{ {
"identity" : "emojitext", "identity" : "emojitext",
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",
@ -45,6 +63,24 @@
"version" : "4.16.0" "version" : "4.16.0"
} }
}, },
{
"identity" : "sqlite.swift",
"kind" : "remoteSourceControl",
"location" : "https://github.com/stephencelis/SQLite.swift.git",
"state" : {
"revision" : "4d543d811ee644fa4cc4bfa0be996b4dd6ba0f54",
"version" : "0.13.3"
}
},
{
"identity" : "swift-collections",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-collections",
"state" : {
"revision" : "48254824bb4248676bf7ce56014ff57b142b77eb",
"version" : "1.0.2"
}
},
{ {
"identity" : "swiftsoup", "identity" : "swiftsoup",
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",

View file

@ -22,6 +22,7 @@ let package = Package(
.package(name: "Status", path: "../Status"), .package(name: "Status", path: "../Status"),
.package(name: "DesignSystem", path: "../DesignSystem"), .package(name: "DesignSystem", path: "../DesignSystem"),
.package(url: "https://github.com/siteline/SwiftUI-Introspect.git", from: "0.1.4"), .package(url: "https://github.com/siteline/SwiftUI-Introspect.git", from: "0.1.4"),
.package(url: "https://github.com/mergesort/Boutique", from: "2.1.1"),
], ],
targets: [ targets: [
.target( .target(
@ -33,6 +34,7 @@ let package = Package(
.product(name: "Status", package: "Status"), .product(name: "Status", package: "Status"),
.product(name: "DesignSystem", package: "DesignSystem"), .product(name: "DesignSystem", package: "DesignSystem"),
.product(name: "Introspect", package: "SwiftUI-Introspect"), .product(name: "Introspect", package: "SwiftUI-Introspect"),
.product(name: "Boutique", package: "Boutique"),
] ]
), ),
.testTarget( .testTarget(

View file

@ -1,20 +1,44 @@
import Models import Models
import Network import Network
import SwiftUI import SwiftUI
import Boutique
actor TimelineCache { actor TimelineCache {
static let shared: TimelineCache = .init() static let shared: TimelineCache = .init()
private var memoryCache: [Client: [Status]] = [:] private func storageFor(_ client: Client) -> SQLiteStorageEngine {
SQLiteStorageEngine.default(appendingPath: client.id)
}
private let decoder = JSONDecoder()
private let encoder = JSONEncoder()
private init() {} private init() {}
func set(statuses: [Status], client: Client) { func set(statuses: [Status], client: Client) async {
guard !statuses.isEmpty else { return } guard !statuses.isEmpty else { return }
memoryCache[client] = statuses.prefix(upTo: min(100, statuses.count - 1)).map { $0 } let statuses = statuses.prefix(upTo: min(300, statuses.count - 1)).map { $0 }
do {
let engine = storageFor(client)
try await engine.removeAllData()
let itemKeys = statuses.map({ CacheKey($0[keyPath: \.id]) })
let dataAndKeys = try zip(itemKeys, statuses)
.map({ (key: $0, data: try encoder.encode($1)) })
try await engine.write(dataAndKeys)
} catch {
}
} }
func getStatuses(for client: Client) -> [Status]? { func getStatuses(for client: Client) async -> [Status]? {
memoryCache[client] let engine = storageFor(client)
do {
return try await engine
.readAllData()
.map({ try decoder.decode(Status.self, from: $0) })
.sorted(by: { $0.createdAt > $1.createdAt })
} catch {
return nil
}
} }
} }