一个 Swift 包,用于模拟带有类似 CRUD
接口的远程存储。
通常需要模拟数据库客户端,以便进行 Xcode 预览或在不使用实际客户端的情况下测试代码。 这个包构建在 swift-identified-collections 中的 IdentifiedArray
类型之上,并依赖 swift-dependencies 来实现可控的 clock
操作。
将其作为 Swift 包安装到你的项目中。
import PackageDescription
let package = Package(
...
dependencies: [
.package(url: "https://github.com/m-housh/swift-identified-storage.git", from: "0.1.0")
],
targets: [
.target(
name: "<My Target>",
dependencies: [
.product(name: "IdentifiedStorage", package: "swift-identified-storage")
]
)
]
)
给定以下 Todo
模型。
struct Todo: Equatable, Identifiable {
var id: UUID
var description: String
var isComplete: Bool = false
}
#if DEBUG
extension Todo {
static let mocks: [Self] = [
.init(id: UUID(0), description: "Buy milk"),
.init(id: UUID(1), description: "Walk the dog"),
.init(id: UUID(2), description: "Wash the car", isComplete: true)
]
}
#endif
以及 todo 客户端接口。
struct TodoClient {
var delete: (Todo.ID) async throws -> Void
var fetch: (FetchRequest) async throws -> IdentifiedArrayOf<Todo>
var insert: (InsertRequest) async throws -> Todo
var update: (Todo.ID, UpdateRequest) async throws -> Todo
func fetch() async throws -> IdentifiedArrayOf<Todo> {
try await self.fetch(.all)
}
enum FetchRequest {
case all
case filtered(by: Filter)
enum Filter {
case complete
case incomplete
}
}
struct InsertRequest {
let description: String
}
struct UpdateRequest {
let description: String
}
}
使请求类型符合适当的转换类型。
#if DEBUG
import IdentifiedStorage
extension TodoClient.FetchRequest: FetchRequestConvertible {
func fetch(from values: IdentifiedArrayOf<Todo>) -> IdentifiedArrayOf<Todo> {
switch self {
case .all:
return values
case let .filtered(by: filter):
return values.filter {
$0.isComplete == (filter == .complete ? true : false)
}
}
}
}
extension TodoClient.InsertRequest: InsertRequestConvertible {
typealias ID = Todo.ID
func transform() -> Todo {
@Dependency(\.uuid) var uuid;
return .init(id: uuid(), description: description)
}
}
extension TodoClient.UpdateRequest: UpdateRequestConvertible {
typealias ID = Todo.ID
func apply(to state: inout Todo) {
state.description = description
}
}
#endif
创建一个模拟客户端工厂。
extension TodoClient {
static func mock(
initialValues todos: [Todo],
timeDelays: IdentifiedStorageDelays? = .default
) -> Self {
// using the `IdentifiedStorage` as the storage for the mock client.
// this uses the passed in time delays to simulate a remote data store for
// use in previews and tests.
let storage = IdentifiedStorageOf<Todo>(
initialValues: todos,
timeDelays: timeDelays
)
return TodoClient(
delete: { try await storage.delete(id: $0) },
fetch: { try await storage.fetch(request: $0) },
insert: { try await storage.insert(request: $0) },
update: { try await storage.update(id: $0, request: $1) }
)
}
}
extension TodoClient: DependencyKey {
...
static var previewValue: Self {
TodoClient.mock(initialValues: .init(uniqueElements: Todo.mocks))
}
}
在此处查看 API 文档:here.
所有模块均在 MIT 许可证下发布。 有关详细信息,请参见 LICENSE。