Add Sentinel-1 asset management and PyINT pipeline support
This commit is contained in:
@@ -0,0 +1,371 @@
|
||||
-- Migration: Source product and orbit asset inventory
|
||||
-- Version: 10.0
|
||||
-- Date: 2026-05-12
|
||||
-- Purpose: Add first-class source product assets, orbit assets, scene-orbit bindings,
|
||||
-- inventory state, and radar_data compatibility fields.
|
||||
|
||||
ALTER TABLE IF EXISTS radar_data
|
||||
ADD COLUMN IF NOT EXISTS source_product_ref_id INTEGER NULL;
|
||||
|
||||
ALTER TABLE IF EXISTS radar_data
|
||||
ADD COLUMN IF NOT EXISTS source_archive_asset_id INTEGER NULL;
|
||||
|
||||
ALTER TABLE IF EXISTS radar_data
|
||||
ADD COLUMN IF NOT EXISTS selected_orbit_asset_id INTEGER NULL;
|
||||
|
||||
ALTER TABLE IF EXISTS radar_data
|
||||
ADD COLUMN IF NOT EXISTS orbit_binding_status VARCHAR(32) NOT NULL DEFAULT 'UNBOUND';
|
||||
|
||||
ALTER TABLE IF EXISTS radar_data
|
||||
ADD COLUMN IF NOT EXISTS orbit_binding_reason TEXT NULL;
|
||||
|
||||
ALTER TABLE IF EXISTS radar_data
|
||||
ADD COLUMN IF NOT EXISTS acquisition_start_time_utc TIMESTAMP NULL;
|
||||
|
||||
ALTER TABLE IF EXISTS radar_data
|
||||
ADD COLUMN IF NOT EXISTS acquisition_stop_time_utc TIMESTAMP NULL;
|
||||
|
||||
ALTER TABLE IF EXISTS radar_data
|
||||
ADD COLUMN IF NOT EXISTS absolute_orbit VARCHAR NULL;
|
||||
|
||||
ALTER TABLE IF EXISTS radar_data
|
||||
ADD COLUMN IF NOT EXISTS relative_orbit VARCHAR NULL;
|
||||
|
||||
ALTER TABLE IF EXISTS radar_data
|
||||
ADD COLUMN IF NOT EXISTS source_format VARCHAR(32) NULL;
|
||||
|
||||
ALTER TABLE IF EXISTS radar_data
|
||||
ADD COLUMN IF NOT EXISTS metadata_json JSON NULL;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS source_product_assets (
|
||||
id SERIAL PRIMARY KEY,
|
||||
asset_uid VARCHAR(128) NOT NULL UNIQUE,
|
||||
logical_product_uid VARCHAR(128) NULL,
|
||||
satellite_family VARCHAR(32) NULL,
|
||||
satellite VARCHAR(32) NULL,
|
||||
source_format VARCHAR(32) NOT NULL,
|
||||
product_type VARCHAR(64) NULL,
|
||||
product_level VARCHAR(64) NULL,
|
||||
imaging_mode VARCHAR(64) NULL,
|
||||
polarization VARCHAR(64) NULL,
|
||||
absolute_orbit VARCHAR(64) NULL,
|
||||
relative_orbit VARCHAR(64) NULL,
|
||||
orbit_direction VARCHAR(32) NULL,
|
||||
acquisition_start_time_utc TIMESTAMP NULL,
|
||||
acquisition_stop_time_utc TIMESTAMP NULL,
|
||||
imaging_date VARCHAR(8) NULL,
|
||||
root_ref_id INTEGER NULL REFERENCES managed_roots(id) ON DELETE SET NULL,
|
||||
root_path VARCHAR NULL,
|
||||
file_path VARCHAR NOT NULL UNIQUE,
|
||||
archive_path VARCHAR NULL,
|
||||
path_kind VARCHAR(24) NULL,
|
||||
file_name VARCHAR(255) NULL,
|
||||
file_stem VARCHAR(255) NULL,
|
||||
file_ext VARCHAR(32) NULL,
|
||||
size_bytes BIGINT NULL,
|
||||
mtime_epoch DOUBLE PRECISION NULL,
|
||||
checksum_sha256 VARCHAR(64) NULL,
|
||||
checksum_status VARCHAR(32) NOT NULL DEFAULT 'NOT_COMPUTED',
|
||||
parser_name VARCHAR(64) NULL,
|
||||
parser_version VARCHAR(32) NULL,
|
||||
parse_status VARCHAR(32) NOT NULL DEFAULT 'PENDING',
|
||||
parse_error TEXT NULL,
|
||||
parsed_at TIMESTAMP NULL,
|
||||
metadata_json JSON NULL,
|
||||
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
missing_since TIMESTAMP NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS orbit_assets (
|
||||
id SERIAL PRIMARY KEY,
|
||||
orbit_uid VARCHAR(128) NOT NULL UNIQUE,
|
||||
satellite_family VARCHAR(32) NULL,
|
||||
satellite VARCHAR(32) NULL,
|
||||
orbit_type VARCHAR(64) NOT NULL,
|
||||
native_format VARCHAR(32) NOT NULL,
|
||||
quality_class VARCHAR(32) NOT NULL DEFAULT 'unknown',
|
||||
root_ref_id INTEGER NULL REFERENCES managed_roots(id) ON DELETE SET NULL,
|
||||
root_path VARCHAR NULL,
|
||||
file_path VARCHAR NOT NULL UNIQUE,
|
||||
file_name VARCHAR(255) NULL,
|
||||
file_stem VARCHAR(255) NULL,
|
||||
file_ext VARCHAR(32) NULL,
|
||||
size_bytes BIGINT NULL,
|
||||
mtime_epoch DOUBLE PRECISION NULL,
|
||||
checksum_sha256 VARCHAR(64) NULL,
|
||||
checksum_status VARCHAR(32) NOT NULL DEFAULT 'NOT_COMPUTED',
|
||||
validity_start_time_utc TIMESTAMP NULL,
|
||||
validity_stop_time_utc TIMESTAMP NULL,
|
||||
generation_time_utc TIMESTAMP NULL,
|
||||
published_time_utc TIMESTAMP NULL,
|
||||
parser_name VARCHAR(64) NULL,
|
||||
parser_version VARCHAR(32) NULL,
|
||||
parse_status VARCHAR(32) NOT NULL DEFAULT 'PENDING',
|
||||
parse_error TEXT NULL,
|
||||
parsed_at TIMESTAMP NULL,
|
||||
metadata_json JSON NULL,
|
||||
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
missing_since TIMESTAMP NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS scene_orbit_bindings (
|
||||
id SERIAL PRIMARY KEY,
|
||||
radar_data_id INTEGER NOT NULL REFERENCES radar_data(id) ON DELETE CASCADE,
|
||||
orbit_asset_id INTEGER NOT NULL REFERENCES orbit_assets(id) ON DELETE CASCADE,
|
||||
binding_role VARCHAR(32) NOT NULL DEFAULT 'primary_orbit',
|
||||
match_status VARCHAR(32) NOT NULL DEFAULT 'CANDIDATE',
|
||||
selection_status VARCHAR(32) NOT NULL DEFAULT 'CANDIDATE',
|
||||
selection_rank INTEGER NULL,
|
||||
priority_score DOUBLE PRECISION NULL,
|
||||
coverage_margin_before_seconds DOUBLE PRECISION NULL,
|
||||
coverage_margin_after_seconds DOUBLE PRECISION NULL,
|
||||
match_rule_version VARCHAR(64) NULL,
|
||||
match_reason TEXT NULL,
|
||||
selected_at TIMESTAMP NULL,
|
||||
metadata_json JSON NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP DEFAULT NOW(),
|
||||
CONSTRAINT uq_scene_orbit_binding_role UNIQUE (radar_data_id, orbit_asset_id, binding_role)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS orbit_asset_derivatives (
|
||||
id SERIAL PRIMARY KEY,
|
||||
orbit_asset_id INTEGER NOT NULL REFERENCES orbit_assets(id) ON DELETE CASCADE,
|
||||
engine_code VARCHAR(32) NOT NULL,
|
||||
derivative_format VARCHAR(32) NOT NULL,
|
||||
derivative_role VARCHAR(64) NULL,
|
||||
pool_path VARCHAR NOT NULL,
|
||||
size_bytes BIGINT NULL,
|
||||
mtime_epoch DOUBLE PRECISION NULL,
|
||||
checksum_sha256 VARCHAR(64) NULL,
|
||||
generation_status VARCHAR(32) NOT NULL DEFAULT 'PENDING',
|
||||
generation_error TEXT NULL,
|
||||
generated_at TIMESTAMP NULL,
|
||||
metadata_json JSON NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP DEFAULT NOW(),
|
||||
CONSTRAINT uq_orbit_asset_derivative_pool_path UNIQUE (orbit_asset_id, engine_code, derivative_format, pool_path)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS asset_inventory_states (
|
||||
id SERIAL PRIMARY KEY,
|
||||
root_ref_id INTEGER NOT NULL REFERENCES managed_roots(id) ON DELETE CASCADE,
|
||||
inventory_type VARCHAR(32) NOT NULL,
|
||||
root_path VARCHAR NOT NULL,
|
||||
scan_mode VARCHAR(32) NOT NULL DEFAULT 'file_pool',
|
||||
status VARCHAR(32) NOT NULL DEFAULT 'NEVER_SCANNED',
|
||||
last_scan_started_at TIMESTAMP NULL,
|
||||
last_scan_finished_at TIMESTAMP NULL,
|
||||
last_seen_entry_count INTEGER NULL,
|
||||
last_asset_count INTEGER NULL,
|
||||
last_issue_count INTEGER NULL,
|
||||
parser_version VARCHAR(32) NULL,
|
||||
needs_rescan BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
last_error TEXT NULL,
|
||||
metadata_json JSON NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP DEFAULT NOW(),
|
||||
CONSTRAINT uq_asset_inventory_state_root_type UNIQUE (root_ref_id, inventory_type)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS asset_inventory_issues (
|
||||
id SERIAL PRIMARY KEY,
|
||||
root_ref_id INTEGER NULL REFERENCES managed_roots(id) ON DELETE SET NULL,
|
||||
inventory_type VARCHAR(32) NOT NULL,
|
||||
asset_ref_id INTEGER NULL REFERENCES source_product_assets(id) ON DELETE SET NULL,
|
||||
radar_data_id INTEGER NULL REFERENCES radar_data(id) ON DELETE SET NULL,
|
||||
orbit_asset_id INTEGER NULL REFERENCES orbit_assets(id) ON DELETE SET NULL,
|
||||
severity VARCHAR(16) NOT NULL DEFAULT 'warning',
|
||||
issue_code VARCHAR(64) NOT NULL,
|
||||
issue_message TEXT NULL,
|
||||
source_path VARCHAR NULL,
|
||||
status VARCHAR(16) NOT NULL DEFAULT 'OPEN',
|
||||
first_seen_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
last_seen_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
resolved_at TIMESTAMP NULL,
|
||||
metadata_json JSON NULL
|
||||
);
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM pg_constraint WHERE conname = 'fk_radar_data_source_product_ref_id'
|
||||
) THEN
|
||||
ALTER TABLE radar_data
|
||||
ADD CONSTRAINT fk_radar_data_source_product_ref_id
|
||||
FOREIGN KEY (source_product_ref_id)
|
||||
REFERENCES source_product_assets(id)
|
||||
ON DELETE SET NULL;
|
||||
END IF;
|
||||
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM pg_constraint WHERE conname = 'fk_radar_data_source_archive_asset_id'
|
||||
) THEN
|
||||
ALTER TABLE radar_data
|
||||
ADD CONSTRAINT fk_radar_data_source_archive_asset_id
|
||||
FOREIGN KEY (source_archive_asset_id)
|
||||
REFERENCES source_product_assets(id)
|
||||
ON DELETE SET NULL;
|
||||
END IF;
|
||||
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM pg_constraint WHERE conname = 'fk_radar_data_selected_orbit_asset_id'
|
||||
) THEN
|
||||
ALTER TABLE radar_data
|
||||
ADD CONSTRAINT fk_radar_data_selected_orbit_asset_id
|
||||
FOREIGN KEY (selected_orbit_asset_id)
|
||||
REFERENCES orbit_assets(id)
|
||||
ON DELETE SET NULL;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_radar_data_source_product_ref
|
||||
ON radar_data (source_product_ref_id);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_radar_data_source_archive_asset
|
||||
ON radar_data (source_archive_asset_id);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_radar_data_selected_orbit_asset
|
||||
ON radar_data (selected_orbit_asset_id);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_radar_data_orbit_binding_status
|
||||
ON radar_data (orbit_binding_status);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_radar_data_acquisition_start
|
||||
ON radar_data (acquisition_start_time_utc);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_radar_data_absolute_orbit
|
||||
ON radar_data (absolute_orbit);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_radar_data_relative_orbit
|
||||
ON radar_data (relative_orbit);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_radar_data_source_format
|
||||
ON radar_data (source_format);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_source_product_assets_asset_uid
|
||||
ON source_product_assets (asset_uid);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_source_product_assets_family_date
|
||||
ON source_product_assets (satellite_family, imaging_date);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_source_product_assets_satellite
|
||||
ON source_product_assets (satellite);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_source_product_assets_source_format
|
||||
ON source_product_assets (source_format);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_source_product_assets_parse_status
|
||||
ON source_product_assets (parse_status);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_source_product_assets_root_active
|
||||
ON source_product_assets (root_ref_id, is_active);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_source_product_assets_logical_product
|
||||
ON source_product_assets (logical_product_uid);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_source_product_assets_file_path
|
||||
ON source_product_assets (file_path);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_orbit_assets_orbit_uid
|
||||
ON orbit_assets (orbit_uid);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_orbit_assets_family_sat_window
|
||||
ON orbit_assets (satellite_family, satellite, validity_start_time_utc, validity_stop_time_utc);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_orbit_assets_orbit_type
|
||||
ON orbit_assets (orbit_type);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_orbit_assets_native_format
|
||||
ON orbit_assets (native_format);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_orbit_assets_quality_class
|
||||
ON orbit_assets (quality_class);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_orbit_assets_parse_status
|
||||
ON orbit_assets (parse_status);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_orbit_assets_root_active
|
||||
ON orbit_assets (root_ref_id, is_active);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_orbit_assets_file_path
|
||||
ON orbit_assets (file_path);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_scene_orbit_bindings_radar
|
||||
ON scene_orbit_bindings (radar_data_id);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_scene_orbit_bindings_orbit
|
||||
ON scene_orbit_bindings (orbit_asset_id);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_scene_orbit_bindings_match_status
|
||||
ON scene_orbit_bindings (match_status);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_scene_orbit_bindings_selection_status
|
||||
ON scene_orbit_bindings (selection_status);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_scene_orbit_bindings_scene_selected
|
||||
ON scene_orbit_bindings (radar_data_id, selection_status);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_orbit_asset_derivatives_asset_engine
|
||||
ON orbit_asset_derivatives (orbit_asset_id, engine_code);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_orbit_asset_derivatives_pool_path
|
||||
ON orbit_asset_derivatives (pool_path);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_orbit_asset_derivatives_generation_status
|
||||
ON orbit_asset_derivatives (generation_status);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_asset_inventory_states_type_status
|
||||
ON asset_inventory_states (inventory_type, status);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_asset_inventory_states_needs_rescan
|
||||
ON asset_inventory_states (needs_rescan);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_asset_inventory_issues_open
|
||||
ON asset_inventory_issues (status, severity);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_asset_inventory_issues_root_type
|
||||
ON asset_inventory_issues (root_ref_id, inventory_type);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_asset_inventory_issues_asset
|
||||
ON asset_inventory_issues (asset_ref_id);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_asset_inventory_issues_orbit
|
||||
ON asset_inventory_issues (orbit_asset_id);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_asset_inventory_issues_radar
|
||||
ON asset_inventory_issues (radar_data_id);
|
||||
|
||||
UPDATE radar_data
|
||||
SET
|
||||
orbit_binding_status = CASE
|
||||
WHEN has_orbit_data IS TRUE AND NULLIF(orbit_file_path, '') IS NOT NULL THEN 'MATCHED'
|
||||
WHEN has_orbit_data IS TRUE THEN 'MATCHED'
|
||||
ELSE COALESCE(NULLIF(orbit_binding_status, ''), 'UNBOUND')
|
||||
END
|
||||
WHERE orbit_binding_status IS NULL
|
||||
OR orbit_binding_status = ''
|
||||
OR (has_orbit_data IS TRUE AND orbit_binding_status = 'UNBOUND');
|
||||
|
||||
UPDATE radar_data
|
||||
SET absolute_orbit = COALESCE(NULLIF(absolute_orbit, ''), NULLIF(orbit_circle, ''))
|
||||
WHERE absolute_orbit IS NULL OR absolute_orbit = '';
|
||||
|
||||
UPDATE radar_data
|
||||
SET source_format = COALESCE(
|
||||
NULLIF(source_format, ''),
|
||||
CASE
|
||||
WHEN upper(replace(replace(replace(COALESCE(satellite, ''), '-', ''), '_', ''), ' ', '')) LIKE 'S1%%'
|
||||
AND lower(COALESCE(file_path, '')) LIKE '%%.zip' THEN 'S1_ZIP'
|
||||
WHEN upper(replace(replace(replace(COALESCE(satellite, ''), '-', ''), '_', ''), ' ', '')) LIKE 'S1%%'
|
||||
AND lower(COALESCE(file_path, '')) LIKE '%%.safe' THEN 'S1_SAFE_DIR'
|
||||
WHEN upper(replace(replace(replace(COALESCE(satellite, ''), '-', ''), '_', ''), ' ', '')) LIKE 'LT1%%' THEN 'LT1_DIR'
|
||||
WHEN upper(replace(replace(replace(COALESCE(satellite, ''), '-', ''), '_', ''), ' ', '')) LIKE 'GF3%%' THEN 'GF3_DIR'
|
||||
ELSE NULL
|
||||
END
|
||||
)
|
||||
WHERE source_format IS NULL OR source_format = '';
|
||||
Reference in New Issue
Block a user