218 lines
7.0 KiB
SQL
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);
|