NoOverbooking { all b: Book | { let totalOrdered = sum o: Order | (o.book = b and o.status != Cancelled) => o.quantity else 0 | let currentStock = sum inv: Inventory | (inv.book = b) => inv.stock else 0 | totalOrdered <= currentStock // 数学的に厳密 } }
items: set OrderItem, status: one OrderStatus, createdAt: Time } { some items // 注文には必ず商品が含まれる } sig OrderItem { book: one Book, quantity: Int, order: one Order } { quantity > 0 // 数量は正数 } abstract sig OrderStatus {} one sig Pending, Confirmed, Shipped, Cancelled extends OrderStatus {}
≤ 物理在庫 all b: Book | { let allConfirmedItems = { oi: OrderItem | oi.book = b and oi.order.status in (Confirmed + Shipped) } | let totalOrdered = sum oi: allConfirmedItems | oi.quantity | let currentStock = sum inv: Inventory | (inv.book = b) => inv.stock else 0 | totalOrdered <= currentStock } }
all o: Order | o in o.customer.orders all c: Customer | all o: c.orders | o.customer = c } fact OrderItemConsistency { // 注文項目と注文の整合性 all oi: OrderItem | oi in oi.order.items all o: Order | all oi: o.items | oi.order = o }
在庫競合が発生する状況を探す run InventoryConflict { // 異なる2つの注文が同じ本を含む状況 some disj o1, o2: Order | o1.status = Pending and o2.status = Pending and some oi1: o1.items, oi2: o2.items | oi1.book = oi2.book } for 4 // 最大4個のオブジェクトで探索
sealed class PaymentMethod { data class CreditCard(val number: String, val expiry: String) : PaymentMethod() data class BankTransfer(val accountNumber: String) : PaymentMethod() object Cash : PaymentMethod() } // PaymentMethod = CreditCard OR BankTransfer OR Cash 2. Product Type(直積型) - AND の関係 data class Address( // すべてのフィールドが必要 val street: String, // street AND val city: String, // city AND val zipCode: String // zipCode ) // Address = street AND city AND zipCode