Files

218 lines
7.0 KiB
SQL

-- +goose Up
CREATE TABLE order_dry_runs (
id TEXT PRIMARY KEY NOT NULL CHECK (length(id) = 36),
authorization_id TEXT NOT NULL UNIQUE
REFERENCES order_authorizations(id)
ON UPDATE RESTRICT ON DELETE RESTRICT,
task_id TEXT NOT NULL
REFERENCES purchase_tasks(id) ON UPDATE RESTRICT ON DELETE RESTRICT,
execution_id TEXT NOT NULL
REFERENCES task_executions(id) ON UPDATE RESTRICT ON DELETE RESTRICT,
command_sha256 TEXT NOT NULL
CHECK (
length(command_sha256) = 64
AND command_sha256 NOT GLOB '*[^0-9a-f]*'
),
status TEXT NOT NULL CHECK (status IN ('PREPARING', 'READY')),
card_signature TEXT
CHECK (
card_signature IS NULL
OR (
length(card_signature) = 64
AND card_signature NOT GLOB '*[^0-9a-f]*'
)
),
detail_signature TEXT
CHECK (
detail_signature IS NULL
OR (
length(detail_signature) = 64
AND detail_signature NOT GLOB '*[^0-9a-f]*'
)
),
observed_title TEXT,
selected_sku TEXT,
quantity INTEGER CHECK (
quantity IS NULL OR quantity BETWEEN 1 AND 99
),
unit_price_cents INTEGER CHECK (
unit_price_cents IS NULL OR unit_price_cents > 0
),
total_price_cents INTEGER CHECK (
total_price_cents IS NULL OR total_price_cents > 0
),
evidence_asset_id TEXT
REFERENCES execution_evidence_assets(id)
ON UPDATE RESTRICT ON DELETE RESTRICT,
evidence_sha256 TEXT
CHECK (
evidence_sha256 IS NULL
OR (
length(evidence_sha256) = 64
AND evidence_sha256 NOT GLOB '*[^0-9a-f]*'
)
),
started_at TEXT NOT NULL,
ready_at TEXT,
CHECK (
status = 'PREPARING'
OR (
status = 'READY'
AND card_signature IS NOT NULL
AND detail_signature IS NOT NULL
AND length(trim(observed_title)) > 0
AND length(trim(selected_sku)) > 0
AND quantity IS NOT NULL
AND unit_price_cents IS NOT NULL
AND total_price_cents IS NOT NULL
AND evidence_asset_id IS NOT NULL
AND evidence_sha256 IS NOT NULL
AND ready_at IS NOT NULL
)
)
);
CREATE INDEX order_dry_runs_task_started_idx
ON order_dry_runs (task_id, started_at DESC, id DESC);
CREATE TABLE device_order_dry_run_requests (
device_id TEXT NOT NULL
REFERENCES devices(id) ON UPDATE RESTRICT ON DELETE RESTRICT,
operation TEXT NOT NULL CHECK (operation IN ('START', 'READY')),
idempotency_key TEXT NOT NULL
CHECK (
length(trim(idempotency_key)) > 0
AND length(CAST(idempotency_key AS BLOB)) <= 128
),
request_sha256 TEXT NOT NULL
CHECK (
length(request_sha256) = 64
AND request_sha256 NOT GLOB '*[^0-9a-f]*'
),
task_id TEXT NOT NULL
REFERENCES purchase_tasks(id) ON UPDATE RESTRICT ON DELETE RESTRICT,
dry_run_id TEXT NOT NULL
REFERENCES order_dry_runs(id) ON UPDATE RESTRICT ON DELETE RESTRICT,
created_at TEXT NOT NULL,
PRIMARY KEY (device_id, operation, idempotency_key)
);
ALTER TABLE task_events RENAME TO task_events_v9;
CREATE TABLE task_events (
id TEXT PRIMARY KEY NOT NULL CHECK (length(id) = 36),
task_id TEXT NOT NULL
REFERENCES purchase_tasks(id) ON UPDATE RESTRICT ON DELETE CASCADE,
event_type TEXT NOT NULL
CHECK (
event_type IN (
'TASK_CREATED',
'TASK_CLAIMED',
'TASK_RECLAIMED',
'TASK_RELEASED',
'TASK_STARTED',
'TASK_CANCEL_REQUESTED',
'TASK_CANCELED',
'CANDIDATES_READY',
'ORDER_AUTHORIZATION_CREATED',
'ORDER_AUTHORIZATION_DELIVERED',
'ORDER_AUTHORIZATION_ACKNOWLEDGED',
'ORDER_DRY_RUN_STARTED',
'ORDER_DRY_RUN_READY'
)
),
message TEXT NOT NULL,
occurred_at TEXT NOT NULL,
actor_user_id TEXT
REFERENCES users(id) ON UPDATE RESTRICT ON DELETE RESTRICT,
actor_device_id TEXT
REFERENCES devices(id) ON UPDATE RESTRICT ON DELETE RESTRICT
);
INSERT INTO task_events (
id, task_id, event_type, message, occurred_at,
actor_user_id, actor_device_id
)
SELECT
id, task_id, event_type, message, occurred_at,
actor_user_id, actor_device_id
FROM task_events_v9;
DROP TABLE task_events_v9;
CREATE INDEX task_events_task_occurred_idx
ON task_events (task_id, occurred_at ASC, id ASC);
CREATE INDEX task_events_actor_user_idx
ON task_events (actor_user_id, occurred_at DESC, id DESC);
CREATE INDEX task_events_actor_device_idx
ON task_events (actor_device_id, occurred_at DESC, id DESC);
-- +goose Down
CREATE TEMP TABLE order_dry_runs_v10_down_guard (
allowed INTEGER NOT NULL CHECK (allowed = 1)
);
INSERT INTO order_dry_runs_v10_down_guard (allowed)
SELECT CASE
WHEN EXISTS (SELECT 1 FROM order_dry_runs)
OR EXISTS (SELECT 1 FROM device_order_dry_run_requests)
OR EXISTS (
SELECT 1 FROM task_events
WHERE event_type IN ('ORDER_DRY_RUN_STARTED', 'ORDER_DRY_RUN_READY')
)
THEN 0
ELSE 1
END;
DROP TABLE order_dry_runs_v10_down_guard;
DROP TABLE device_order_dry_run_requests;
DROP TABLE order_dry_runs;
ALTER TABLE task_events RENAME TO task_events_v10;
CREATE TABLE task_events (
id TEXT PRIMARY KEY NOT NULL CHECK (length(id) = 36),
task_id TEXT NOT NULL
REFERENCES purchase_tasks(id) ON UPDATE RESTRICT ON DELETE CASCADE,
event_type TEXT NOT NULL
CHECK (
event_type IN (
'TASK_CREATED',
'TASK_CLAIMED',
'TASK_RECLAIMED',
'TASK_RELEASED',
'TASK_STARTED',
'TASK_CANCEL_REQUESTED',
'TASK_CANCELED',
'CANDIDATES_READY',
'ORDER_AUTHORIZATION_CREATED',
'ORDER_AUTHORIZATION_DELIVERED',
'ORDER_AUTHORIZATION_ACKNOWLEDGED'
)
),
message TEXT NOT NULL,
occurred_at TEXT NOT NULL,
actor_user_id TEXT
REFERENCES users(id) ON UPDATE RESTRICT ON DELETE RESTRICT,
actor_device_id TEXT
REFERENCES devices(id) ON UPDATE RESTRICT ON DELETE RESTRICT
);
INSERT INTO task_events (
id, task_id, event_type, message, occurred_at,
actor_user_id, actor_device_id
)
SELECT
id, task_id, event_type, message, occurred_at,
actor_user_id, actor_device_id
FROM task_events_v10;
DROP TABLE task_events_v10;
CREATE INDEX task_events_task_occurred_idx
ON task_events (task_id, occurred_at ASC, id ASC);
CREATE INDEX task_events_actor_user_idx
ON task_events (actor_user_id, occurred_at DESC, id DESC);
CREATE INDEX task_events_actor_device_idx
ON task_events (actor_device_id, occurred_at DESC, id DESC);