import Dependencies import DependenciesMacros import SharedModels import Vapor public extension DatabaseClient { @DependencyClient struct Vendors: Sendable { public var create: @Sendable (Vendor.Create) async throws -> Vendor public var delete: @Sendable (Vendor.ID) async throws -> Void public var fetchAll: @Sendable (FetchRequest) async throws -> [Vendor] public var get: @Sendable (Vendor.ID, GetRequest?) async throws -> Vendor? public var update: @Sendable (Vendor.ID, Vendor.Update, GetRequest?) async throws -> Vendor public enum FetchRequest: Sendable { case all case withBranches } public enum GetRequest: Sendable { case withBranches } @Sendable public func fetchAll() async throws -> [Vendor] { try await fetchAll(.all) } @Sendable public func get(_ id: Vendor.ID) async throws -> Vendor? { try await get(id, nil) } @Sendable public func update( _ id: Vendor.ID, with updates: Vendor.Update, returnWithBranches: Bool = false ) async throws -> Vendor { try await update(id, updates, returnWithBranches ? GetRequest.withBranches : nil) } } } extension Vendor: Content {} extension Vendor.Create: Content {} extension Vendor.Update: Content {} extension DatabaseClient.Vendors.FetchRequest: Content {} extension DatabaseClient.Vendors.GetRequest: Content {} extension DatabaseClient.Vendors: TestDependencyKey { public static let testValue: DatabaseClient.Vendors = Self() } #if DEBUG typealias VendorMockStorage = MockStorage< Vendor, Vendor.Create, DatabaseClient.Vendors.FetchRequest, DatabaseClient.Vendors.GetRequest, Vendor.Update > private extension VendorMockStorage { // swiftlint:disable function_body_length static func vendors(_ mocks: [Vendor]) -> Self { @Dependency(\.date.now) var now @Dependency(\.uuid) var uuid @Dependency(\.database.vendorBranches) var vendorBranches return .init( mocks, create: { Vendor( id: uuid(), name: $0.name, createdAt: now, updatedAt: now ) }, fetch: { _ in { _ in true } }, fetchExtras: { request, models in guard request == .withBranches else { return models } let branches = try await vendorBranches.fetchAll() return models.map { model in Vendor( id: model.id, name: model.name, branches: Array(branches.filter { $0.vendorID == model.id }), createdAt: model.createdAt, updatedAt: model.updatedAt ) } }, get: { req, model in guard req == .withBranches else { return model } let branches = try await vendorBranches.fetchAll(.for(vendorID: model.id)) return Vendor( id: model.id, name: model.name, branches: branches, createdAt: model.createdAt, updatedAt: model.updatedAt ) }, update: { model, updates, get in var branches: [VendorBranch]? if get == .withBranches { branches = try await vendorBranches.fetchAll(.for(vendorID: model.id)) } let vendor = Vendor( id: model.id, name: updates.name ?? model.name, branches: branches ?? model.branches, createdAt: model.createdAt, updatedAt: now ) model = vendor } ) } // swiftlint:enable function_body_length } public extension DatabaseClient.Vendors { static func mock(_ mocks: [Vendor]) -> Self { let storage = VendorMockStorage.vendors(mocks) return .init( create: { try await storage.create($0) }, delete: { try await storage.delete($0) }, fetchAll: { try await storage.fetchAll($0) }, get: { try await storage.get($0, $1) }, update: { req, updates, get in try await storage.update(req, updates, get) } ) } } #endif