-- +goose Up CREATE TABLE erp_sync_runs ( id TEXT PRIMARY KEY NOT NULL CHECK (length(id) = 36), creator_subject TEXT NOT NULL, created_by_user_id TEXT NOT NULL REFERENCES users(id) ON UPDATE RESTRICT ON DELETE RESTRICT, mode TEXT NOT NULL CHECK (mode = 'ORDER_NUMBER'), order_number TEXT NOT NULL CHECK ( length(trim(order_number)) > 0 AND length(CAST(order_number AS BLOB)) <= 128 ), query_sha256 TEXT NOT NULL CHECK ( length(query_sha256) = 64 AND query_sha256 NOT GLOB '*[^0-9a-f]*' ), 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]*' ), status TEXT NOT NULL CHECK (status IN ('PENDING', 'RUNNING', 'SUCCEEDED', 'FAILED')), error_code TEXT CHECK ( error_code IS NULL OR length(CAST(error_code AS BLOB)) <= 64 ), order_count INTEGER NOT NULL DEFAULT 0 CHECK (order_count >= 0), item_count INTEGER NOT NULL DEFAULT 0 CHECK (item_count >= 0), created_at TEXT NOT NULL, started_at TEXT, finished_at TEXT, CHECK ( (status = 'PENDING' AND started_at IS NULL AND finished_at IS NULL AND error_code IS NULL) OR (status = 'RUNNING' AND started_at IS NOT NULL AND finished_at IS NULL AND error_code IS NULL) OR (status = 'SUCCEEDED' AND started_at IS NOT NULL AND finished_at IS NOT NULL AND error_code IS NULL) OR (status = 'FAILED' AND finished_at IS NOT NULL AND error_code IS NOT NULL) ), UNIQUE (creator_subject, idempotency_key) ); CREATE INDEX erp_sync_runs_creator_created_idx ON erp_sync_runs (creator_subject, created_at DESC, id DESC); CREATE TABLE freight_orders ( id TEXT PRIMARY KEY NOT NULL CHECK (length(id) = 36), creator_subject TEXT NOT NULL, source_system TEXT NOT NULL CHECK (source_system = 'SHUNYUNBAO'), external_stock_id TEXT NOT NULL CHECK (length(trim(external_stock_id)) > 0), source_code TEXT NOT NULL CHECK (length(CAST(source_code AS BLOB)) <= 256), platform_order_no TEXT CHECK ( platform_order_no IS NULL OR length(CAST(platform_order_no AS BLOB)) <= 256 ), shop_name TEXT CHECK ( shop_name IS NULL OR length(CAST(shop_name AS BLOB)) <= 512 ), source_created_at TEXT, order_status TEXT CHECK ( order_status IS NULL OR length(CAST(order_status AS BLOB)) <= 128 ), purchase_status TEXT CHECK ( purchase_status IS NULL OR length(CAST(purchase_status AS BLOB)) <= 128 ), is_canceled INTEGER CHECK (is_canceled IS NULL OR is_canceled IN (0, 1)), canonical_sha256 TEXT NOT NULL CHECK ( length(canonical_sha256) = 64 AND canonical_sha256 NOT GLOB '*[^0-9a-f]*' ), revision INTEGER NOT NULL CHECK (revision >= 1), first_sync_run_id TEXT NOT NULL REFERENCES erp_sync_runs(id) ON UPDATE RESTRICT ON DELETE RESTRICT, last_sync_run_id TEXT NOT NULL REFERENCES erp_sync_runs(id) ON UPDATE RESTRICT ON DELETE RESTRICT, created_at TEXT NOT NULL, updated_at TEXT NOT NULL, UNIQUE (creator_subject, source_system, external_stock_id) ); CREATE INDEX freight_orders_creator_updated_idx ON freight_orders (creator_subject, updated_at DESC, id DESC); CREATE TABLE freight_order_items ( id TEXT PRIMARY KEY NOT NULL CHECK (length(id) = 36), freight_order_id TEXT NOT NULL REFERENCES freight_orders(id) ON UPDATE RESTRICT ON DELETE RESTRICT, external_item_id TEXT NOT NULL CHECK (length(trim(external_item_id)) > 0), title TEXT NOT NULL CHECK (length(CAST(title AS BLOB)) <= 2048), product_spec TEXT NOT NULL CHECK (length(CAST(product_spec AS BLOB)) <= 1024), sku TEXT NOT NULL CHECK (length(CAST(sku AS BLOB)) <= 512), quantity INTEGER CHECK (quantity IS NULL OR quantity > 0), product_thumb_ref TEXT CHECK ( product_thumb_ref IS NULL OR length(CAST(product_thumb_ref AS BLOB)) <= 512 ), purchase_status TEXT CHECK ( purchase_status IS NULL OR length(CAST(purchase_status AS BLOB)) <= 128 ), canonical_sha256 TEXT NOT NULL CHECK ( length(canonical_sha256) = 64 AND canonical_sha256 NOT GLOB '*[^0-9a-f]*' ), revision INTEGER NOT NULL CHECK (revision >= 1), is_present INTEGER NOT NULL CHECK (is_present IN (0, 1)), first_sync_run_id TEXT NOT NULL REFERENCES erp_sync_runs(id) ON UPDATE RESTRICT ON DELETE RESTRICT, last_sync_run_id TEXT NOT NULL REFERENCES erp_sync_runs(id) ON UPDATE RESTRICT ON DELETE RESTRICT, created_at TEXT NOT NULL, updated_at TEXT NOT NULL, UNIQUE (freight_order_id, external_item_id) ); CREATE INDEX freight_order_items_order_present_idx ON freight_order_items (freight_order_id, is_present, id); -- +goose Down CREATE TEMP TABLE freight_v12_down_guard ( allowed INTEGER NOT NULL CHECK (allowed = 1) ); INSERT INTO freight_v12_down_guard (allowed) SELECT CASE WHEN EXISTS (SELECT 1 FROM erp_sync_runs) OR EXISTS (SELECT 1 FROM freight_orders) OR EXISTS (SELECT 1 FROM freight_order_items) THEN 0 ELSE 1 END; DROP TABLE freight_v12_down_guard; DROP TABLE freight_order_items; DROP TABLE freight_orders; DROP TABLE erp_sync_runs;