Files
vapor-po/Sources/DatabaseClientLive/Vendors+live.swift

145 lines
3.5 KiB
Swift

import DatabaseClient
import FluentKit
import Foundation
import SharedModels
import Vapor
public extension DatabaseClient.Vendors {
static func live(database db: any Database) -> Self {
.init { create in
let model = try create.toModel()
try await model.save(on: db)
return try model.toDTO()
} delete: { id in
guard let model = try await VendorModel.find(id, on: db) else {
throw NotFoundError()
}
try await model.delete(on: db)
} fetchAll: { request in
var query = VendorModel.query(on: db).sort(\VendorModel.$name, .ascending)
let withBranches = request == .withBranches
switch request {
case .withBranches:
query = query.with(\VendorModel.$branches)
case .all:
break
}
return try await query.all().map { try $0.toDTO(includeBranches: withBranches) }
} get: { id, request in
var query = VendorModel.query(on: db).filter(\.$id == id)
let withBranches = request == .withBranches
if withBranches {
query = query.with(\VendorModel.$branches)
}
return try await query.first().map { try $0.toDTO(includeBranches: withBranches) }
} update: { id, updates, withBranches in
guard let model = try await VendorModel.find(id, on: db) else {
throw NotFoundError()
}
try model.applyUpdates(updates)
try await model.save(on: db)
if withBranches != .withBranches {
return try model.toDTO()
}
return try await VendorModel.query(on: db)
.filter(\VendorModel.$id == id)
.with(\VendorModel.$branches)
.first()!
.toDTO()
}
}
}
extension Vendor {
struct Migrate: AsyncMigration {
let name = "CreateVendor"
func prepare(on database: any Database) async throws {
try await database.schema(VendorModel.schema)
.id()
.field("name", .string, .required)
.field("created_at", .datetime)
.field("updated_at", .datetime)
.unique(on: "name")
.create()
}
func revert(on database: any Database) async throws {
try await database.schema(VendorModel.schema).delete()
}
}
}
extension Vendor.Create {
func toModel() throws -> VendorModel {
try validate()
return .init(name: name)
}
func validate() throws {
guard !name.isEmpty else {
throw ValidationError(message: "Vendor name should not be empty.")
}
}
}
extension Vendor.Update {
func validate() throws {
guard !name.isEmpty else {
throw ValidationError(message: "Vendor name should not be empty.")
}
}
}
// The primary database model.
final class VendorModel: Model, @unchecked Sendable {
static let schema = "vendor"
@ID(key: .id)
var id: UUID?
@Field(key: "name")
var name: String
@Timestamp(key: "created_at", on: .create, format: .iso8601)
var createdAt: Date?
@Timestamp(key: "updated_at", on: .update, format: .iso8601)
var updatedAt: Date?
@Children(for: \.$vendor)
var branches: [VendorBranchModel]
init() {}
init(id: UUID? = nil, name: String) {
self.id = id
self.name = name
}
func toDTO(includeBranches: Bool? = nil) throws -> Vendor {
try .init(
id: requireID(),
name: name,
branches: ($branches.value != nil && $branches.value!.count > 0)
? $branches.value!.map { try $0.toDTO() }
: [],
createdAt: createdAt,
updatedAt: updatedAt
)
}
func applyUpdates(_ updates: Vendor.Update) throws {
try updates.validate()
name = updates.name
}
}