-- +goose Up CREATE TABLE freight_item_images ( freight_order_item_id TEXT PRIMARY KEY NOT NULL REFERENCES freight_order_items(id) ON UPDATE RESTRICT ON DELETE CASCADE, product_thumb_ref TEXT NOT NULL CHECK ( product_thumb_ref GLOB '[1-9]*' AND product_thumb_ref NOT GLOB '*[^0-9]*' AND length(product_thumb_ref) <= 20 ), status TEXT NOT NULL CHECK (status IN ('READY', 'MISSING', 'FAILED')), media_type TEXT, size_bytes INTEGER, sha256 TEXT, storage_key TEXT UNIQUE, error_code TEXT CHECK ( error_code IS NULL OR ( length(trim(error_code)) > 0 AND length(CAST(error_code AS BLOB)) <= 64 ) ), attempt_count INTEGER NOT NULL CHECK (attempt_count >= 1), updated_at TEXT NOT NULL, CHECK ( ( status = 'READY' AND media_type = 'image/jpeg' AND size_bytes > 0 AND length(sha256) = 64 AND sha256 NOT GLOB '*[^0-9a-f]*' AND length(trim(storage_key)) > 0 AND length(CAST(storage_key AS BLOB)) <= 512 AND error_code IS NULL ) OR ( status IN ('MISSING', 'FAILED') AND media_type IS NULL AND size_bytes IS NULL AND sha256 IS NULL AND storage_key IS NULL AND error_code IS NOT NULL ) ) ); CREATE INDEX freight_item_images_status_idx ON freight_item_images (status, updated_at, freight_order_item_id); -- +goose Down CREATE TEMP TABLE freight_item_images_v16_down_guard ( allowed INTEGER NOT NULL CHECK (allowed = 1) ); INSERT INTO freight_item_images_v16_down_guard (allowed) SELECT CASE WHEN EXISTS (SELECT 1 FROM freight_item_images) THEN 0 ELSE 1 END; DROP TABLE freight_item_images_v16_down_guard; DROP TABLE freight_item_images;