import Fluent import struct Foundation.UUID import Vapor // TODO: Add soft-delete?? /// The employee database model. /// /// An employee is someone that PO's can be generated for. They can be either a field /// employee / technician, an office employee, or an administrator. /// /// # NOTE: Only `User` types can login and generate po's for employees. /// final class Employee: Model, @unchecked Sendable { static let schema = "employee" @ID(key: .id) var id: UUID? @Field(key: "first_name") var firstName: String @Field(key: "last_name") var lastName: String @Field(key: "is_active") var active: Bool @Timestamp(key: "created_at", on: .create) var createdAt: Date? @Timestamp(key: "updated_at", on: .update) var updatedAt: Date? init() {} init( id: UUID? = nil, firstName: String, lastName: String, active: Bool, createdAt: Date? = nil, updatedAt: Date? = nil ) { self.id = id self.firstName = firstName self.lastName = lastName self.active = active self.createdAt = createdAt self.updatedAt = updatedAt } func toDTO() -> DTO { .init( id: id, firstName: $firstName.value, lastName: $lastName.value, active: $active.value, createdAt: createdAt, updatedAt: updatedAt ) } func applyUpdates(_ updates: Update) { if let firstName = updates.firstName { self.firstName = firstName } if let lastName = updates.lastName { self.lastName = lastName } if let active = updates.active { self.active = active } } } // MARK: - Helpers extension Employee { struct Create: Content { let firstName: String let lastName: String let active: Bool? func toModel() -> Employee { .init( firstName: firstName, lastName: lastName, active: active ?? true ) } } struct DTO: Content { var id: UUID? var firstName: String? var lastName: String? var active: Bool? var createdAt: Date? var updatedAt: Date? func toModel() -> Employee { let model = Employee() model.id = id if let firstName { model.firstName = firstName } if let lastName { model.lastName = lastName } if let active { model.active = active } return model } } struct Migrate: AsyncMigration { let name = "CreateEmployee" func prepare(on database: Database) async throws { try await database.schema(Employee.schema) .id() .field("first_name", .string, .required) .field("last_name", .string, .required) .field("is_active", .bool, .required, .sql(.default(true))) .field("created_at", .datetime) .field("updated_at", .datetime) .unique(on: "first_name", "last_name") .create() } func revert(on database: Database) async throws { try await database.schema(Employee.schema).delete() } } struct Update: Content { var firstName: String? var lastName: String? var active: Bool? } } // MARK: - Validations extension Employee.Create: Validatable { static func validations(_ validations: inout Validations) { validations.add("firstName", as: String.self, is: !.empty) validations.add("lastName", as: String.self, is: !.empty) } } extension Employee.Update: Validatable { static func validations(_ validations: inout Validations) { validations.add("firstName", as: String?.self, is: .nil || !.empty, required: false) validations.add("lastName", as: String?.self, is: .nil || !.empty, required: false) } }