feat: Reorganizes files.

This commit is contained in:
2025-01-10 14:03:52 -05:00
parent 280bc31a03
commit 455287fe1c
10 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,49 @@
import Fluent
import Vapor
// An intermediate layer between our api and view controllers that interacts with the
// database model.
struct EmployeeDB {
func create(_ model: Employee.Create, on db: any Database) async throws -> Employee.DTO {
let model = model.toModel()
try await model.save(on: db)
return model.toDTO()
}
func fetchAll(active: Bool? = nil, on db: any Database) async throws -> [Employee.DTO] {
var query = Employee.query(on: db)
.sort(\.$lastName)
if let active {
query = query.filter(\.$active == active)
}
return try await query.all().map { $0.toDTO() }
}
func get(id: Employee.IDValue, on db: any Database) async throws -> Employee.DTO? {
try await Employee.find(id, on: db).map { $0.toDTO() }
}
func update(
id: Employee.IDValue,
with updates: Employee.Update,
on db: any Database
) async throws -> Employee.DTO {
guard let employee = try await Employee.find(id, on: db) else {
throw Abort(.badRequest, reason: "Employee id not found.")
}
employee.applyUpdates(updates)
try await employee.save(on: db)
return employee.toDTO()
}
func delete(id: Employee.IDValue, on db: any Database) async throws {
guard let employee = try await Employee.find(id, on: db) else {
throw Abort(.badRequest, reason: "Employee id not found.")
}
try await employee.delete(on: db)
}
}

View File

@@ -0,0 +1,65 @@
import Fluent
import Vapor
// An intermediate between our api and view controllers that interacts with the
// database.
struct PurchaseOrderDB {
func create(
_ model: PurchaseOrder.Create,
createdById: User.IDValue,
on db: any Database
) async throws -> PurchaseOrder.DTO {
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 get(id: purchaseOrder.requireID(), on: db) else {
return purchaseOrder.toDTO()
}
return loaded
}
func fetchAll(on db: any Database) async throws -> [PurchaseOrder.DTO] {
try await PurchaseOrder.allQuery(on: db)
.sort(\.$id, .descending)
.all().map { $0.toDTO() }
}
func fetchPage(_ page: Int, limit: Int, on db: any Database) async throws -> Page<PurchaseOrder.DTO> {
try await PurchaseOrder.allQuery(on: db)
.sort(\.$id, .descending)
.paginate(PageRequest(page: page, per: limit))
.map { $0.toDTO() }
}
func get(id: PurchaseOrder.IDValue, on db: any Database) async throws -> PurchaseOrder.DTO? {
try await PurchaseOrder.allQuery(on: db)
.filter(\.$id == id)
.first()?.toDTO()
}
func delete(id: PurchaseOrder.IDValue, on db: any Database) async throws {
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> {
PurchaseOrder.query(on: db)
.with(\.$createdBy)
.with(\.$createdFor)
.with(\.$vendorBranch) { branch in
branch.with(\.$vendor)
}
}
}

View File

@@ -0,0 +1,36 @@
import Fluent
import Vapor
struct UserDB {
func create(_ model: User.Create, on db: any Database) async throws -> User.DTO {
guard model.password == model.confirmPassword else {
throw Abort(.badRequest, reason: "Passwords did not match.")
}
let user = try User(
username: model.username,
email: model.email,
passwordHash: Bcrypt.hash(model.password)
)
try await user.save(on: db)
return user.toDTO()
}
func login(user: User, on db: any Database) async throws -> UserToken {
let token = try user.generateToken()
try await token.save(on: db)
return token
}
func fetchAll(on db: any Database) async throws -> [User.DTO] {
try await User.query(on: db).all().map { $0.toDTO() }
}
func delete(id: User.IDValue, on db: any Database) async throws {
guard let user = try await User.find(id, on: db) else {
throw Abort(.notFound)
}
try await user.delete(on: db)
}
}

View File

@@ -0,0 +1,62 @@
import Fluent
import Vapor
struct VendorBranchDB {
func create(
_ model: VendorBranch.Create,
for vendorID: Vendor.IDValue,
on db: any Database
) async throws -> VendorBranch.DTO {
let branch = model.toModel()
guard let vendor = try await Vendor.find(vendorID, on: db) else {
throw Abort(.badRequest, reason: "Vendor does not exist.")
}
try await vendor.$branches.create(branch, on: db)
return branch.toDTO()
}
func fetchAll(withVendor: Bool? = nil, on db: any Database) async throws -> [VendorBranch.DTO] {
var query = VendorBranch.query(on: db)
if withVendor == true {
query = query.with(\.$vendor)
}
return try await query.all().map { $0.toDTO() }
}
func fetch(for vendorID: Vendor.IDValue, on db: any Database) async throws -> [VendorBranch.DTO] {
guard let vendor = try await Vendor.query(on: db)
.filter(\.$id == vendorID)
.with(\.$branches)
.first()
else {
throw Abort(.notFound)
}
return vendor.branches.map { $0.toDTO() }
}
func get(id: VendorBranch.IDValue, on db: any Database) async throws -> VendorBranch.DTO? {
try await VendorBranch.find(id, on: db).map { $0.toDTO() }
}
func update(
id: VendorBranch.IDValue,
with updates: VendorBranch.Update,
on db: any Database
) async throws -> VendorBranch.DTO {
guard let branch = try await VendorBranch.find(id, on: db) else {
throw Abort(.notFound)
}
branch.applyUpdates(updates)
try await branch.save(on: db)
return branch.toDTO()
}
func delete(id: VendorBranch.IDValue, on db: any Database) async throws {
guard let branch = try await VendorBranch.find(id, on: db) else {
throw Abort(.notFound)
}
try await branch.delete(on: db)
}
}

View File

@@ -0,0 +1,47 @@
import Fluent
import Vapor
struct VendorDB {
func create(_ model: Vendor.Create, on db: any Database) async throws -> Vendor.DTO {
let model = model.toModel()
try await model.save(on: db)
return model.toDTO()
}
func fetchAll(withBranches: Bool? = nil, on db: any Database) async throws -> [Vendor.DTO] {
var query = Vendor.query(on: db).sort(\.$name, .ascending)
if withBranches == true {
query = query.with(\.$branches)
}
return try await query.all().map { $0.toDTO(includeBranches: withBranches) }
}
func get(id: Vendor.IDValue, withBranches: Bool? = nil, on db: any Database) async throws -> Vendor.DTO? {
var query = Vendor.query(on: db).filter(\.$id == id)
if withBranches == true {
query = query.with(\.$branches)
}
return try await query.first().map { $0.toDTO(includeBranches: withBranches) }
}
func update(
id: Vendor.IDValue,
with updates: Vendor.Update,
on db: any Database
) async throws -> Vendor.DTO {
guard let vendor = try await Vendor.find(id, on: db) else {
throw Abort(.notFound)
}
vendor.applyUpdates(updates)
return vendor.toDTO()
}
func delete(id: Vendor.IDValue, on db: any Database) async throws {
guard let vendor = try await Vendor.find(id, on: db) else {
throw Abort(.notFound)
}
try await vendor.delete(on: db)
}
}

View File

@@ -0,0 +1,97 @@
import Vapor
/// Represents a generic form context that is used to generate form templates
/// that are handled by htmx.
struct HtmxFormCTX<Context: Content>: Content {
let formClass: String?
let formId: String
let htmxPostTargetUrl: String?
let htmxPutTargetUrl: String?
let htmxTarget: String
let htmxPushUrl: Bool
let htmxResetAfterRequest: Bool
let htmxSwapOob: String?
let htmxSwap: String?
let context: Context
init(
formClass: String? = nil,
formId: String,
htmxTargetUrl: TargetUrl,
htmxTarget: String,
htmxPushUrl: Bool,
htmxResetAfterRequest: Bool = true,
htmxSwapOob: HtmxSwap? = nil,
htmxSwap: HtmxSwap? = nil,
context: Context
) {
self.formClass = formClass
self.formId = formId
self.htmxPostTargetUrl = htmxTargetUrl.postUrl
self.htmxPutTargetUrl = htmxTargetUrl.putUrl
self.htmxTarget = htmxTarget
self.htmxPushUrl = htmxPushUrl
self.htmxResetAfterRequest = htmxResetAfterRequest
self.htmxSwapOob = htmxSwapOob?.rawValue
self.htmxSwap = htmxSwap?.rawValue
self.context = context
}
enum HtmxSwap: String {
case innerHTML
case outerHTML
case afterbegin
case beforebegin
case afterend
case beforeend
case delete
case none
}
enum TargetUrl {
case put(String)
case post(String)
var putUrl: String? {
guard case let .put(url) = self else { return nil }
return url
}
var postUrl: String? {
guard case let .post(url) = self else { return nil }
return url
}
}
}
struct EmptyContent: Content {}
struct ButtonLabelContext: Content {
let buttonLabel: String
}
extension HtmxFormCTX where Context == ButtonLabelContext {
init(
formClass: String? = nil,
formId: String,
htmxTargetUrl: TargetUrl,
htmxTarget: String,
htmxPushUrl: Bool,
htmxResetAfterRequest: Bool = true,
htmxSwapOob: HtmxSwap? = nil,
htmxSwap: HtmxSwap? = nil,
buttonLabel: String
) {
self.init(
formClass: formClass,
formId: formId,
htmxTargetUrl: htmxTargetUrl,
htmxTarget: htmxTarget,
htmxPushUrl: htmxPushUrl,
htmxResetAfterRequest: htmxResetAfterRequest,
htmxSwapOob: htmxSwapOob,
htmxSwap: htmxSwapOob,
context: .init(buttonLabel: buttonLabel)
)
}
}