import Dependencies import DependenciesMacros import Fluent import Vapor extension DependencyValues { // An intermediate layer between our api and view controllers that interacts with the // database model. var employees: EmployeeDB { get { self[EmployeeDB.self] } set { self[EmployeeDB.self] = newValue } } } @DependencyClient struct EmployeeDB: Sendable { var create: @Sendable (Employee.Create) async throws -> Employee.DTO var fetchAll: @Sendable (Bool) async throws -> [Employee.DTO] var get: @Sendable (Employee.IDValue) async throws -> Employee.DTO? var update: @Sendable (Employee.IDValue, Employee.Update) async throws -> Employee.DTO var delete: @Sendable (Employee.IDValue) async throws -> Void var toggleActive: @Sendable (Employee.IDValue) async throws -> Employee.DTO func fetchAll() async throws -> [Employee.DTO] { try await fetchAll(false) } func get(_ id: String?) async throws -> Employee.DTO? { guard let idString = id, let id = UUID(uuidString: idString) else { throw Abort(.badRequest, reason: "Employee id not valid.") } return try await get(id) } } extension EmployeeDB: TestDependencyKey { static let testValue: EmployeeDB = Self() static func live(database: any Database) -> Self { .init( create: { model in let model = model.toModel() try await model.save(on: database) return model.toDTO() }, fetchAll: { active in var query = Employee.query(on: database) .sort(\.$lastName) if active { query = query.filter(\.$active == active) } return try await query.all().map { $0.toDTO() } }, get: { id in try await Employee.find(id, on: database).map { $0.toDTO() } }, update: { id, updates in guard let employee = try await Employee.find(id, on: database) else { throw Abort(.badRequest, reason: "Employee id not found.") } employee.applyUpdates(updates) try await employee.save(on: database) return employee.toDTO() }, delete: { id in guard let employee = try await Employee.find(id, on: database) else { throw Abort(.badRequest, reason: "Employee id not found.") } try await employee.delete(on: database) }, toggleActive: { id in guard let employee = try await Employee.find(id, on: database) else { throw Abort(.notFound) } employee.active.toggle() try await employee.save(on: database) return employee.toDTO() } ) } }