Files
recflare/apps/econ/migrations/0021_room_consumable.sql
T
2026-09-14 16:33:47 -04:00

42 lines
2.2 KiB
SQL

-- Room consumables — the things a room sells.
--
-- The other half of a room's economy: `room_currency` (migration 0017) is the money a room
-- mints and hands out, and this is the shop that takes it back — a Health Potion for 25
-- tokens, a custom shirt for 500. A row here is the LISTING: its name, its picture, what it
-- costs and in which of the room's currencies. Written by
-- `PUT /api/roomconsumables/v1/roomConsumable` and read by
-- `GET /api/roomconsumables/v1/roomConsumable/room/{roomId}`. Owned by the `econ` worker;
-- generated from src/room-consumable-db.ts (ROOM_CONSUMABLE_SCHEMA_DDL) — keep in sync.
--
-- `room_consumable_id` is a GUID rather than an autoincrement, like a room currency's: it is
-- how the client names this listing afterwards, and a room's consumables are created
-- independently of every other room's.
--
-- The write body's `PriceAndCurrency` object is COLLAPSED here into `price` and
-- `purchase_currency_id`. It is one price in one currency, and a nested object would buy
-- nothing but a JSON blob to query through. Note the client READS them flat, so the write
-- shape and the read shape genuinely differ — do not unify them.
--
-- `purchase_currency_id` points at a `room_currency` and is nullable (`Guid?` in the client's
-- model), for a listing that names no currency. Nothing resolves or validates it yet: a
-- consumable priced in a currency that has since been deleted still lists, at a price nobody
-- can pay. `image_name` is nullable for the same reason — a listing with no picture. `price`
-- is not: a listing always has one, even if it is zero.
--
-- Nothing BUYS a consumable yet. There is no purchase endpoint, so
-- `maximum_count_per_purchase` is stored and served and read by nothing.
CREATE TABLE IF NOT EXISTS room_consumable (
room_consumable_id TEXT PRIMARY KEY,
room_id INTEGER NOT NULL,
name TEXT NOT NULL,
description TEXT NOT NULL,
image_name TEXT,
price INTEGER NOT NULL,
purchase_currency_id TEXT,
modified_at TEXT NOT NULL,
maximum_count_per_purchase INTEGER NOT NULL DEFAULT 0
);
-- Every read is "this room's shop" — the whole access pattern.
CREATE INDEX IF NOT EXISTS idx_room_consumable_room ON room_consumable (room_id);