feat: Working on mocks and mock storage.
This commit is contained in:
@@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
private var storage: [Model.ID: Model]
|
private var storage: [Model.ID: Model]
|
||||||
|
|
||||||
private let modelFromCreate: @Sendable (Create) -> Model
|
private let modelFromCreate: @Sendable (Create) async throws -> Model
|
||||||
private let fetchToPredicate: @Sendable (Fetch) -> ((Model) -> Bool)
|
private let fetchToPredicate: @Sendable (Fetch) -> ((Model) -> Bool)
|
||||||
private let fetchExtras: @Sendable (Fetch, [Model]) async throws -> [Model]
|
private let fetchExtras: @Sendable (Fetch, [Model]) async throws -> [Model]
|
||||||
private let applyUpdates: @Sendable (inout Model, Update, Get?) async throws -> Void
|
private let applyUpdates: @Sendable (inout Model, Update, Get?) async throws -> Void
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
init(
|
init(
|
||||||
_ mocks: [Model] = [],
|
_ mocks: [Model] = [],
|
||||||
create modelFromCreate: @Sendable @escaping (Create) -> Model,
|
create modelFromCreate: @Sendable @escaping (Create) async throws -> Model,
|
||||||
fetch fetchToPredicate: @Sendable @escaping (Fetch) -> ((Model) -> Bool),
|
fetch fetchToPredicate: @Sendable @escaping (Fetch) -> ((Model) -> Bool),
|
||||||
fetchExtras: @Sendable @escaping (Fetch, [Model]) async throws -> [Model] = { $1 },
|
fetchExtras: @Sendable @escaping (Fetch, [Model]) async throws -> [Model] = { $1 },
|
||||||
get getExtras: @Sendable @escaping (Get?, Model) async throws -> Model,
|
get getExtras: @Sendable @escaping (Get?, Model) async throws -> Model,
|
||||||
@@ -41,7 +41,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
func create(_ create: Create) async throws -> Model {
|
func create(_ create: Create) async throws -> Model {
|
||||||
let model = modelFromCreate(create)
|
let model = try await modelFromCreate(create)
|
||||||
storage[model.id] = model
|
storage[model.id] = model
|
||||||
return model
|
return model
|
||||||
}
|
}
|
||||||
@@ -75,7 +75,7 @@
|
|||||||
extension MockStorage where Get == Void {
|
extension MockStorage where Get == Void {
|
||||||
init(
|
init(
|
||||||
_ mocks: [Model] = [],
|
_ mocks: [Model] = [],
|
||||||
create modelFromCreate: @Sendable @escaping (Create) -> Model,
|
create modelFromCreate: @Sendable @escaping (Create) async throws -> Model,
|
||||||
fetch fetchToPredicate: @Sendable @escaping (Fetch) -> ((Model) -> Bool),
|
fetch fetchToPredicate: @Sendable @escaping (Fetch) -> ((Model) -> Bool),
|
||||||
fetchExtras: @Sendable @escaping (Fetch, [Model]) async throws -> [Model] = { $1 },
|
fetchExtras: @Sendable @escaping (Fetch, [Model]) async throws -> [Model] = { $1 },
|
||||||
update applyUpdates: @Sendable @escaping (inout Model, Update) async throws -> Void
|
update applyUpdates: @Sendable @escaping (inout Model, Update) async throws -> Void
|
||||||
@@ -103,7 +103,7 @@
|
|||||||
extension MockStorage where Fetch == Void {
|
extension MockStorage where Fetch == Void {
|
||||||
init(
|
init(
|
||||||
_ mocks: [Model] = [],
|
_ mocks: [Model] = [],
|
||||||
create modelFromCreate: @Sendable @escaping (Create) -> Model,
|
create modelFromCreate: @Sendable @escaping (Create) async throws -> Model,
|
||||||
fetchExtras: @Sendable @escaping (Fetch, [Model]) async throws -> [Model] = { $1 },
|
fetchExtras: @Sendable @escaping (Fetch, [Model]) async throws -> [Model] = { $1 },
|
||||||
get getExtras: @Sendable @escaping (Get?, Model) async throws -> Model,
|
get getExtras: @Sendable @escaping (Get?, Model) async throws -> Model,
|
||||||
update applyUpdates: @Sendable @escaping (inout Model, Update, Get?) async throws -> Void
|
update applyUpdates: @Sendable @escaping (inout Model, Update, Get?) async throws -> Void
|
||||||
@@ -126,7 +126,7 @@
|
|||||||
extension MockStorage where Fetch == Void, Get == Void {
|
extension MockStorage where Fetch == Void, Get == Void {
|
||||||
init(
|
init(
|
||||||
_ mocks: [Model] = [],
|
_ mocks: [Model] = [],
|
||||||
create modelFromCreate: @Sendable @escaping (Create) -> Model,
|
create modelFromCreate: @Sendable @escaping (Create) async throws -> Model,
|
||||||
fetchExtras: @Sendable @escaping (Fetch, [Model]) async throws -> [Model] = { $1 },
|
fetchExtras: @Sendable @escaping (Fetch, [Model]) async throws -> [Model] = { $1 },
|
||||||
update applyUpdates: @Sendable @escaping (inout Model, Update) async throws -> Void
|
update applyUpdates: @Sendable @escaping (inout Model, Update) async throws -> Void
|
||||||
) {
|
) {
|
||||||
@@ -138,6 +138,5 @@
|
|||||||
update: { model, updates, _ in try await applyUpdates(&model, updates) }
|
update: { model, updates, _ in try await applyUpdates(&model, updates) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -22,3 +22,74 @@ extension PurchaseOrder.Create: Content {}
|
|||||||
extension DatabaseClient.PurchaseOrders: TestDependencyKey {
|
extension DatabaseClient.PurchaseOrders: TestDependencyKey {
|
||||||
public static let testValue: DatabaseClient.PurchaseOrders = Self()
|
public static let testValue: DatabaseClient.PurchaseOrders = Self()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
typealias PurchaseOrderMockStorage = MockStorage<
|
||||||
|
PurchaseOrder,
|
||||||
|
PurchaseOrder.Create,
|
||||||
|
Void,
|
||||||
|
Void,
|
||||||
|
Void
|
||||||
|
>
|
||||||
|
|
||||||
|
public extension DependencyValues {
|
||||||
|
var purchaseOrderID: PurchaseOrderIDGenerator {
|
||||||
|
get { self[PurchaseOrderIDGenerator.self] }
|
||||||
|
set { self[PurchaseOrderIDGenerator.self] = newValue }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@DependencyClient
|
||||||
|
public struct PurchaseOrderIDGenerator: Sendable {
|
||||||
|
var nextID: @Sendable () async throws -> Int
|
||||||
|
}
|
||||||
|
|
||||||
|
extension PurchaseOrderIDGenerator: DependencyKey {
|
||||||
|
public static let testValue: PurchaseOrderIDGenerator = .liveValue
|
||||||
|
|
||||||
|
public static var liveValue: Self {
|
||||||
|
let counter = Counter()
|
||||||
|
return .init(nextID: { await counter.nextID() })
|
||||||
|
}
|
||||||
|
|
||||||
|
actor Counter {
|
||||||
|
private var count: Int
|
||||||
|
|
||||||
|
init(starting: Int = 1) {
|
||||||
|
self.count = starting
|
||||||
|
}
|
||||||
|
|
||||||
|
func nextID() async -> Int {
|
||||||
|
count += 1
|
||||||
|
return count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// private extension PurchaseOrderMockStorage {
|
||||||
|
// static func make(_ mocks: [PurchaseOrder]) -> Self {
|
||||||
|
// @Dependency(\.date.now) var now
|
||||||
|
// @Dependency(\.purchaseOrderID) var purchaseOrderID
|
||||||
|
//
|
||||||
|
// return .init(
|
||||||
|
// mocks,
|
||||||
|
// create: { model in
|
||||||
|
// try await PurchaseOrder(
|
||||||
|
// id: purchaseOrderID.nextID(),
|
||||||
|
// workOrder: model.workOrder,
|
||||||
|
// materials: model.materials,
|
||||||
|
// customer: model.customer,
|
||||||
|
// truckStock: model.truckStock,
|
||||||
|
// createdBy: model.createdForID,
|
||||||
|
// createdFor: model.createdForID,
|
||||||
|
// vendorBranch: .i
|
||||||
|
//
|
||||||
|
// )
|
||||||
|
// },
|
||||||
|
// update: { _, _ in
|
||||||
|
// fatalError()
|
||||||
|
// }
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -28,3 +28,66 @@ extension User.Update: Content {}
|
|||||||
extension DatabaseClient.Users: TestDependencyKey {
|
extension DatabaseClient.Users: TestDependencyKey {
|
||||||
public static let testValue: DatabaseClient.Users = Self()
|
public static let testValue: DatabaseClient.Users = Self()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
typealias UserMockStorage = MockStorage<
|
||||||
|
User,
|
||||||
|
User.Create,
|
||||||
|
Void,
|
||||||
|
Void,
|
||||||
|
User.Update
|
||||||
|
>
|
||||||
|
|
||||||
|
private extension UserMockStorage {
|
||||||
|
static func make(_ mocks: [User]) -> Self {
|
||||||
|
@Dependency(\.date.now) var now
|
||||||
|
@Dependency(\.uuid) var uuid
|
||||||
|
|
||||||
|
return .init(
|
||||||
|
create: { model in
|
||||||
|
User(
|
||||||
|
id: uuid(),
|
||||||
|
email: model.email,
|
||||||
|
username: model.username,
|
||||||
|
createdAt: now,
|
||||||
|
updatedAt: now
|
||||||
|
)
|
||||||
|
},
|
||||||
|
update: { model, updates in
|
||||||
|
let user = User(
|
||||||
|
id: model.id,
|
||||||
|
email: updates.email ?? model.email,
|
||||||
|
username: updates.username ?? model.username,
|
||||||
|
createdAt: model.createdAt,
|
||||||
|
updatedAt: now
|
||||||
|
)
|
||||||
|
model = user
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public extension User.Token {
|
||||||
|
static func mock(id: User.ID) -> Self {
|
||||||
|
.init(id: UUID(0), userID: id, value: "test")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public extension DatabaseClient.Users {
|
||||||
|
|
||||||
|
static func mock(_ mocks: [User]) -> Self {
|
||||||
|
let storage = UserMockStorage.make(mocks)
|
||||||
|
return .init(
|
||||||
|
count: { try await storage.count() },
|
||||||
|
create: { try await storage.create($0) },
|
||||||
|
delete: { try await storage.delete($0) },
|
||||||
|
fetchAll: { try await storage.fetchAll() },
|
||||||
|
get: { try await storage.get($0) },
|
||||||
|
login: { _ in .mock(id: UUID(0)) },
|
||||||
|
logout: { _ in },
|
||||||
|
token: { .mock(id: $0) },
|
||||||
|
update: { try await storage.update($0, $1) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -40,6 +40,8 @@ public struct PurchaseOrder: Codable, Equatable, Identifiable, Sendable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public extension PurchaseOrder {
|
public extension PurchaseOrder {
|
||||||
|
|
||||||
|
// TODO: Add created by id.
|
||||||
struct Create: Codable, Sendable {
|
struct Create: Codable, Sendable {
|
||||||
|
|
||||||
public let id: Int?
|
public let id: Int?
|
||||||
|
|||||||
Reference in New Issue
Block a user