import FluentKit import Foundation /// A FluentKit model of a single `offers` row. final class OfferRecord: Model, @unchecked Sendable { // MARK: Properties static let schema = "offers" @ID(key: .id) var id: UUID? @Parent(key: "conversation_id") var conversation: ConversationRecord @Parent(key: "listing_id") var listing: ListingRecord @Parent(key: "buyer_id") var buyer: UserRecord @Field(key: "amount_cents") var amountCents: Int @Field(key: "status") var status: String @Field(key: "created_at") var createdAt: Date @Field(key: "expires_at") var expiresAt: Date // MARK: Initializers init() {} init( conversationID: UUID, listingID: UUID, buyerID: UUID, amountCents: Int, at date: Date ) { self.$conversation.id = conversationID self.$listing.id = listingID self.$buyer.id = buyerID self.amountCents = amountCents self.status = Offer.Status.open.rawValue self.createdAt = date self.expiresAt = date.addingTimeInterval(Offer.lifetime) } } // MARK: - Extensions extension OfferRecord { // MARK: Methods /// The `Sendable` snapshot of the saved record; its buyer, and its listing with its shop, must be eager-loaded. /// - Parameter now: the moment an open offer's expiry is judged at. func snapshot( at now: Date ) throws -> Offer { let stored = Offer.Status(rawValue: status) ?? .declined return .init( id: try requireID(), conversationID: $conversation.id, listing: listing.snapshot, buyer: try buyer.snapshot, amountCents: amountCents, status: stored == .open && expiresAt <= now ? .expired : stored, createdAt: createdAt, expiresAt: expiresAt ) } }