import Dependencies import DependenciesMacros import Fluent import Vapor extension DependencyValues { // An intermediate between our api and view controllers that interacts with the // database. var purchaseOrders: PurchaseOrdersDB { get { self[PurchaseOrdersDB.self] } set { self[PurchaseOrdersDB.self] = newValue } } } @DependencyClient struct PurchaseOrdersDB: Sendable { var create: @Sendable (PurchaseOrder.Create, User.IDValue) async throws -> PurchaseOrder.DTO var fetchAll: @Sendable () async throws -> [PurchaseOrder.DTO] var fetchPage: @Sendable (PageRequest) async throws -> Page var get: @Sendable (PurchaseOrder.IDValue) async throws -> PurchaseOrder.DTO? // var update: @Sendable (PurchaseOrder.IDValue, PurchaseOrder.Update) async throws -> PurchaseOrder.DTO var delete: @Sendable (PurchaseOrder.IDValue) async throws -> Void } extension PurchaseOrdersDB: TestDependencyKey { static let testValue: PurchaseOrdersDB = Self() static func live(database db: any Database) -> Self { .init( create: { model, createdById in guard let employee = try await Employee.find(model.createdForID, on: db) else { throw Abort(.notFound, reason: "Employee not found.") } guard employee.active else { throw Abort(.badRequest, reason: "Employee is not active, unable to generate a PO for in-active employees") } let purchaseOrder = model.toModel(createdByID: createdById) try await purchaseOrder.save(on: db) guard let loaded = try await PurchaseOrder.get(purchaseOrder.requireID(), on: db) else { return purchaseOrder.toDTO() } return loaded }, fetchAll: { try await PurchaseOrder.allQuery(on: db) .sort(\.$id, .descending) .all().map { $0.toDTO() } }, fetchPage: { request in try await PurchaseOrder.allQuery(on: db) .sort(\.$id, .descending) .paginate(request) .map { $0.toDTO() } }, get: { id in try await PurchaseOrder.get(id, on: db) }, delete: { id in guard let purchaseOrder = try await PurchaseOrder.find(id, on: db) else { throw Abort(.notFound) } try await purchaseOrder.delete(on: db) } ) } } private extension PurchaseOrder { static func allQuery(on db: any Database) -> QueryBuilder { PurchaseOrder.query(on: db) .with(\.$createdBy) .with(\.$createdFor) .with(\.$vendorBranch) { branch in branch.with(\.$vendor) } } static func get(_ id: PurchaseOrder.IDValue, on db: any Database) async throws -> PurchaseOrder.DTO? { try await PurchaseOrder.allQuery(on: db) .filter(\.$id == id) .first()?.toDTO() } }