#if DEBUG import Dependencies import Vapor actor MockStorage< Model: Identifiable, Create: Sendable, Fetch: Sendable, Get: Sendable, Update: Sendable > where Model: Sendable { @Dependency(\.date.now) var now @Dependency(\.uuid) var uuid private var storage: [Model.ID: Model] private let modelFromCreate: @Sendable (Create) -> Model private let fetchToPredicate: @Sendable (Fetch) -> ((Model) -> Bool) private let fetchExtras: @Sendable (Fetch, [Model]) async throws -> [Model] private let applyUpdates: @Sendable (inout Model, Update, Get?) async throws -> Void private let getExtras: @Sendable (Get?, Model) async throws -> Model init( _ mocks: [Model] = [], create modelFromCreate: @Sendable @escaping (Create) -> Model, fetch fetchToPredicate: @Sendable @escaping (Fetch) -> ((Model) -> Bool), fetchExtras: @Sendable @escaping (Fetch, [Model]) async throws -> [Model] = { $1 }, get getExtras: @Sendable @escaping (Get?, Model) async throws -> Model, update applyUpdates: @Sendable @escaping (inout Model, Update, Get?) async throws -> Void ) { self.storage = mocks.reduce(into: [Model.ID: Model]()) { $0[$1.id] = $1 } self.modelFromCreate = modelFromCreate self.fetchToPredicate = fetchToPredicate self.fetchExtras = fetchExtras self.applyUpdates = applyUpdates self.getExtras = getExtras } func count() async throws -> Int { storage.count } func create(_ create: Create) async throws -> Model { let model = modelFromCreate(create) storage[model.id] = model return model } func delete(_ id: Model.ID) async throws { storage[id] = nil } func fetchAll(_ request: Fetch) async throws -> [Model] { let predicate = fetchToPredicate(request) return try await fetchExtras(request, Array(storage.values.filter { predicate($0) })) } func get(_ id: Model.ID, _ request: Get?) async throws -> Model? { if let model = storage[id] { return try await getExtras(request, model) } return nil } func update(_ id: Model.ID, _ updates: Update, _ get: Get?) async throws -> Model { guard var model = storage[id] else { throw Abort(.badRequest, reason: "Model not found.") } try await applyUpdates(&model, updates, get) storage[id] = model return model } } extension MockStorage where Get == Void { init( _ mocks: [Model] = [], create modelFromCreate: @Sendable @escaping (Create) -> Model, fetch fetchToPredicate: @Sendable @escaping (Fetch) -> ((Model) -> Bool), fetchExtras: @Sendable @escaping (Fetch, [Model]) async throws -> [Model] = { $1 }, update applyUpdates: @Sendable @escaping (inout Model, Update) async throws -> Void ) { self.init( mocks, create: modelFromCreate, fetch: fetchToPredicate, fetchExtras: fetchExtras, get: { _, model in model }, update: { model, updates, _ in try await applyUpdates(&model, updates) } ) } func get(_ id: Model.ID) async throws -> Model? { storage[id] } func update(_ id: Model.ID, _ updates: Update) async throws -> Model { try await update(id, updates, ()) } } extension MockStorage where Fetch == Void { init( _ mocks: [Model] = [], create modelFromCreate: @Sendable @escaping (Create) -> Model, fetchExtras: @Sendable @escaping (Fetch, [Model]) async throws -> [Model] = { $1 }, get getExtras: @Sendable @escaping (Get?, Model) async throws -> Model, update applyUpdates: @Sendable @escaping (inout Model, Update, Get?) async throws -> Void ) { self.init( mocks, create: modelFromCreate, fetch: { _ in { _ in true } }, fetchExtras: fetchExtras, get: getExtras, update: applyUpdates ) } func fetchAll() async throws -> [Model] { try await fetchAll(()) } } extension MockStorage where Fetch == Void, Get == Void { init( _ mocks: [Model] = [], create modelFromCreate: @Sendable @escaping (Create) -> Model, fetchExtras: @Sendable @escaping (Fetch, [Model]) async throws -> [Model] = { $1 }, update applyUpdates: @Sendable @escaping (inout Model, Update) async throws -> Void ) { self.init( mocks, create: modelFromCreate, fetchExtras: fetchExtras, get: { _, model in model }, update: { model, updates, _ in try await applyUpdates(&model, updates) } ) } } #endif