feat: Begins breaking database out into it's own module, using dependencies
This commit is contained in:
174
Sources/DatabaseClientLive/PurchaseOrders.swift
Normal file
174
Sources/DatabaseClientLive/PurchaseOrders.swift
Normal file
@@ -0,0 +1,174 @@
|
||||
import DatabaseClient
|
||||
import FluentKit
|
||||
import Foundation
|
||||
import SharedModels
|
||||
|
||||
public extension DatabaseClient.PurchaseOrders {
|
||||
|
||||
static func live(database: any Database) -> Self {
|
||||
.init { create, createdById in
|
||||
let model = try create.toModel(createdByID: createdById)
|
||||
try await model.save(on: database)
|
||||
return try model.toDTO()
|
||||
} fetchAll: {
|
||||
try await PurchaseOrderModel.allQuery(on: database)
|
||||
.all()
|
||||
.map { try $0.toDTO() }
|
||||
} fetchPage: { request in
|
||||
try await PurchaseOrderModel.allQuery(on: database)
|
||||
.paginate(request)
|
||||
.map { try $0.toDTO() }
|
||||
} get: { id in
|
||||
try await PurchaseOrderModel.allQuery(on: database)
|
||||
.filter(\.$id == id)
|
||||
.first()
|
||||
.map { try $0.toDTO() }
|
||||
} delete: { id in
|
||||
guard let model = try await PurchaseOrderModel.find(id, on: database) else {
|
||||
throw NotFoundError()
|
||||
}
|
||||
try await model.delete(on: database)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension PurchaseOrder {
|
||||
struct Migrate: AsyncMigration {
|
||||
|
||||
let name = "CreatePurchaseOrder"
|
||||
|
||||
func prepare(on database: any Database) async throws {
|
||||
try await database.schema(PurchaseOrderModel.schema)
|
||||
.field("id", .int, .identifier(auto: true))
|
||||
.field("work_order", .int)
|
||||
.field("customer", .string, .required)
|
||||
.field("materials", .string, .required)
|
||||
.field("truck_stock", .bool, .required)
|
||||
.field("created_by_id", .uuid, .required, .references(UserModel.schema, "id"))
|
||||
.field("created_for_id", .uuid, .required, .references(EmployeeModel.schema, "id"))
|
||||
.field("vendor_branch_id", .uuid, .required, .references(VendorBranchModel.schema, "id"))
|
||||
.field("created_at", .datetime)
|
||||
.field("updated_at", .datetime)
|
||||
.create()
|
||||
}
|
||||
|
||||
func revert(on database: any Database) async throws {
|
||||
try await database.schema(PurchaseOrderModel.schema).delete()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension PurchaseOrder.Create {
|
||||
|
||||
func toModel(createdByID: User.ID) throws -> PurchaseOrderModel {
|
||||
try validate()
|
||||
return .init(
|
||||
materials: materials,
|
||||
customer: customer,
|
||||
truckStock: truckStock ?? false,
|
||||
createdByID: createdByID,
|
||||
createdForID: createdForID,
|
||||
vendorBranchID: vendorBranchID
|
||||
)
|
||||
}
|
||||
|
||||
func validate() throws {
|
||||
guard !materials.isEmpty else {
|
||||
throw ValidationError(message: "Materials should not be empty.")
|
||||
}
|
||||
guard !customer.isEmpty else {
|
||||
throw ValidationError(message: "Customer should not be empty.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The purchase order database model.
|
||||
///
|
||||
/// # NOTE: An initial purchase order should be created with an `id` higher than our current PO
|
||||
/// so that subsequent PO's are generated with higher values than our current system produces.
|
||||
/// once the first one is set, the rest will auto-increment from there.
|
||||
final class PurchaseOrderModel: Model, Codable, @unchecked Sendable {
|
||||
static let schema = "purchase_order"
|
||||
|
||||
@ID(custom: "id", generatedBy: .database)
|
||||
var id: Int?
|
||||
|
||||
@Field(key: "work_order")
|
||||
var workOrder: Int?
|
||||
|
||||
@Field(key: "materials")
|
||||
var materials: String
|
||||
|
||||
@Field(key: "customer")
|
||||
var customer: String
|
||||
|
||||
@Field(key: "truck_stock")
|
||||
var truckStock: Bool
|
||||
|
||||
@Parent(key: "created_by_id")
|
||||
var createdBy: UserModel
|
||||
|
||||
@Parent(key: "created_for_id")
|
||||
var createdFor: EmployeeModel
|
||||
|
||||
@Parent(key: "vendor_branch_id")
|
||||
var vendorBranch: VendorBranchModel
|
||||
|
||||
@Timestamp(key: "created_at", on: .create)
|
||||
var createdAt: Date?
|
||||
|
||||
@Timestamp(key: "updated_at", on: .update)
|
||||
var updatedAt: Date?
|
||||
|
||||
init() {}
|
||||
|
||||
init(
|
||||
id: Int? = nil,
|
||||
workOrder: Int? = nil,
|
||||
materials: String,
|
||||
customer: String,
|
||||
truckStock: Bool,
|
||||
createdByID: UserModel.IDValue,
|
||||
createdForID: EmployeeModel.IDValue,
|
||||
vendorBranchID: VendorBranchModel.IDValue,
|
||||
createdAt: Date? = nil,
|
||||
updatedAt: Date? = nil
|
||||
) {
|
||||
self.id = id
|
||||
self.workOrder = workOrder
|
||||
self.materials = materials
|
||||
self.customer = customer
|
||||
self.truckStock = truckStock
|
||||
$createdBy.id = createdByID
|
||||
$createdFor.id = createdForID
|
||||
$vendorBranch.id = vendorBranchID
|
||||
self.createdAt = createdAt
|
||||
self.updatedAt = updatedAt
|
||||
}
|
||||
|
||||
func toDTO() throws -> PurchaseOrder {
|
||||
try .init(
|
||||
id: requireID(),
|
||||
workOrder: workOrder,
|
||||
materials: materials,
|
||||
customer: customer,
|
||||
truckStock: truckStock,
|
||||
createdBy: createdBy.toDTO(),
|
||||
createdFor: createdFor.toDTO(),
|
||||
vendorBranch: vendorBranch.toDTO(),
|
||||
createdAt: createdAt,
|
||||
updatedAt: updatedAt
|
||||
)
|
||||
}
|
||||
|
||||
static func allQuery(on db: any Database) -> QueryBuilder<PurchaseOrderModel> {
|
||||
PurchaseOrderModel.query(on: db)
|
||||
.sort(\.$id, .descending)
|
||||
.with(\.$createdBy)
|
||||
.with(\.$createdFor)
|
||||
.with(\.$vendorBranch) { branch in
|
||||
branch.with(\.$vendor)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user