@_exported import ApiController import DatabaseClient import Dependencies import Logging import SharedModels extension ApiController: DependencyKey { public static var liveValue: ApiController { .init(json: { try await $0.respond() }) } } private extension ApiController.Request { func respond() async throws -> (any Encodable)? { @Dependency(\.database) var database switch route { case let .employee(route): return try await route.handleApiRequest(logger: logger) case let .login(login): return try await TokenResponse(token: database.users.login(login)) case let .purchaseOrder(route): return try await route.handleApiRequest(logger: logger) case let .user(route): return try await route.handleApiRequest(logger: logger) case let .vendor(route): return try await route.handleApiRequest(logger: logger) case let .vendorBranch(route): return try await route.handleApiRequest(logger: logger) } } } private struct TokenResponse: Encodable { let token: String init(token: User.Token) { self.token = token.value } } private extension SiteRoute.Api.EmployeeRoute { func handleApiRequest(logger: Logger) async throws -> (any Encodable)? { @Dependency(\.database) var database switch self { case let .delete(id: id): try await database.employees.delete(id) return nil case let .create(employee): return try await database.employees.create(employee) case .index: return try await database.employees.fetchAll() case let .get(id: id): guard let employee = try await database.employees.get(id) else { logger.error("Employee not found for id: \(id)") throw ApiError(reason: "Employee not found") } return employee case let .update(id: id, updates: updates): return try await database.employees.update(id, updates) } } } private extension SiteRoute.Api.PurchaseOrderRoute { func handleApiRequest(logger: Logger) async throws -> (any Encodable)? { @Dependency(\.database.purchaseOrders) var purchaseOrders switch self { case let .delete(id: id): try await purchaseOrders.delete(id) return nil case .index: return try await purchaseOrders.fetchAll() case let .create(purchaseOrder): return try await purchaseOrders.create(purchaseOrder) case let .get(id: id): guard let output = try await purchaseOrders.get(id) else { logger.error("Purchase Order not found for id: \(id)") throw ApiError(reason: "Purchase order not found.") } return output case let .page(page: page, limit: limit): return try await purchaseOrders.fetchPage(.init(page: page, per: limit)) } } } private extension SiteRoute.Api.UserRoute { func handleApiRequest(logger: Logger) async throws -> (any Encodable)? { @Dependency(\.database.users) var users switch self { case let .delete(id: id): try await users.delete(id) return nil case let .create(user): return try await users.create(user) case .index: return try await users.fetchAll() case let .get(id: id): logger.error("User not found for id: \(id)") guard let user = try await users.get(id) else { throw ApiError(reason: "Employee not found") } return user // case let .login(user): // return try await users.login(user) case let .resetPassword(id: id, request: request): try await users.resetPassword(id, request) return nil case let .update(id: id, updates: updates): return try await users.update(id, updates) } } } private extension SiteRoute.Api.VendorRoute { func handleApiRequest(logger: Logger) async throws -> (any Encodable)? { @Dependency(\.database.vendors) var vendors switch self { case let .delete(id: id): try await vendors.delete(id) return nil case let .create(vendor): return try await vendors.create(vendor) case let .get(id: id): guard let vendor = try await vendors.get(id) else { logger.error("Vendor not found for id: \(id)") throw ApiError(reason: "Vendor not found") } return vendor case let .update(id: id, updates: updates): return try await vendors.update(id, with: updates) case let .index(withBranches: withBranches): guard withBranches == true else { return try await vendors.fetchAll() } return try await vendors.fetchAll(.withBranches) } } } private extension SiteRoute.Api.VendorBranchRoute { func handleApiRequest(logger: Logger) async throws -> (any Encodable)? { @Dependency(\.database.vendorBranches) var vendorBranches switch self { case let .delete(id: id): try await vendorBranches.delete(id) return nil case let .create(branch): return try await vendorBranches.create(branch) case let .index(for: optionalVendorID): guard let vendorID = optionalVendorID else { return try await vendorBranches.fetchAll() } return try await vendorBranches.fetchAll(.for(vendorID: vendorID)) case let .get(id: id): guard let branch = try await vendorBranches.get(id) else { logger.error("Vendor branch not found for id: \(id)") throw ApiError(reason: "Vendor branch not found") } return branch case let .update(id: id, updates: updates): return try await vendorBranches.update(id, updates) } } } struct ApiError: Error { let reason: String }