feat(db): bulk cadastre schema — 7 tables + cadastre_jobs (#168 PR1/5) #169
1 changed files with 152 additions and 9 deletions
|
|
@ -32,7 +32,9 @@
|
|||
-- J. Migrate data: cad_parcels_geom -> cad_parcels
|
||||
-- K. Backup + replace: cad_buildings -> cad_buildings_old_apr26 -> DROP + rename
|
||||
-- L. Restore FK + views
|
||||
-- M. DROP cad_parcels_geom (after data migrated)
|
||||
-- M. Replace cad_parcels_geom TABLE with back-compat VIEW over cad_parcels
|
||||
-- N. COMMENT ON TABLE for all 8 tables
|
||||
-- O. set_updated_at triggers for all tables with updated_at column
|
||||
--
|
||||
-- Idempotency: safe to re-run — all DDL uses IF NOT EXISTS / IF EXISTS guards.
|
||||
-- Data migrations use INSERT ... ON CONFLICT DO NOTHING.
|
||||
|
|
@ -293,7 +295,11 @@ CREATE TABLE IF NOT EXISTS cadastre_jobs (
|
|||
error TEXT,
|
||||
phase_state JSONB,
|
||||
raw_targets JSONB,
|
||||
CONSTRAINT cadastre_jobs_pkey PRIMARY KEY (job_id)
|
||||
CONSTRAINT cadastre_jobs_pkey PRIMARY KEY (job_id),
|
||||
CONSTRAINT cadastre_jobs_status_chk
|
||||
CHECK (status IN (
|
||||
'queued', 'running', 'done', 'failed', 'zombie', 'cancelled', 'paused'
|
||||
))
|
||||
);
|
||||
|
||||
-- ===========================================================================
|
||||
|
|
@ -499,14 +505,13 @@ BEGIN
|
|||
ALTER TABLE cad_buildings_new RENAME TO cad_buildings;
|
||||
-- Rename indexes to drop the _new suffix
|
||||
ALTER INDEX IF EXISTS cad_buildings_new_pkey RENAME TO cad_buildings_pkey;
|
||||
-- Note: ALTER INDEX RENAME on a PK index also renames the constraint
|
||||
-- automatically in PG 16. No separate RENAME CONSTRAINT needed.
|
||||
ALTER INDEX IF EXISTS cad_buildings_new_geom_gist RENAME TO cad_buildings_geom_gist;
|
||||
ALTER INDEX IF EXISTS cad_buildings_new_quarter_idx RENAME TO cad_buildings_quarter_idx;
|
||||
ALTER INDEX IF EXISTS cad_buildings_new_objdoc_idx RENAME TO cad_buildings_objdoc_idx;
|
||||
ALTER INDEX IF EXISTS cad_buildings_new_complex_idx RENAME TO cad_buildings_complex_idx;
|
||||
ALTER INDEX IF EXISTS cad_buildings_new_purpose_idx RENAME TO cad_buildings_purpose_idx;
|
||||
-- Rename constraint
|
||||
ALTER TABLE cad_buildings
|
||||
RENAME CONSTRAINT cad_buildings_new_pkey TO cad_buildings_pkey;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
|
|
@ -627,21 +632,159 @@ SELECT
|
|||
FROM complexes c;
|
||||
|
||||
-- ===========================================================================
|
||||
-- M. DROP cad_parcels_geom (original table — data migrated to cad_parcels)
|
||||
-- Only dropped if cad_parcels exists and has at least as many rows.
|
||||
-- Guard: skip drop if the new table doesn't exist yet (paranoia).
|
||||
-- M. Replace cad_parcels_geom TABLE with a back-compat VIEW over cad_parcels.
|
||||
-- Original table had exactly: cad_num, geom, raw_props, fetched_at.
|
||||
-- The view preserves the same 4-column signature so that any legacy callers
|
||||
-- (e.g. site-finder analyze fallback) continue to work without code changes.
|
||||
-- Bulk PR2/5 will switch callers to cad_parcels directly, after which this
|
||||
-- view can be dropped.
|
||||
-- ===========================================================================
|
||||
DO $$
|
||||
BEGIN
|
||||
-- Drop the old table only if cad_parcels (migration target) already exists.
|
||||
-- Guard prevents accidental drop if J INSERT was skipped on re-run.
|
||||
IF EXISTS (
|
||||
SELECT 1 FROM information_schema.tables
|
||||
WHERE table_schema = 'public' AND table_name = 'cad_parcels'
|
||||
) AND EXISTS (
|
||||
SELECT 1 FROM information_schema.tables
|
||||
WHERE table_schema = 'public' AND table_name = 'cad_parcels_geom'
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name = 'cad_parcels_geom'
|
||||
AND table_type = 'BASE TABLE'
|
||||
) THEN
|
||||
DROP TABLE cad_parcels_geom;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- Create back-compat VIEW (idempotent via CREATE OR REPLACE).
|
||||
-- Matches original column order and types exactly.
|
||||
CREATE OR REPLACE VIEW cad_parcels_geom AS
|
||||
SELECT
|
||||
cad_num,
|
||||
geom,
|
||||
raw_props,
|
||||
fetched_at
|
||||
FROM cad_parcels;
|
||||
|
||||
COMMENT ON VIEW cad_parcels_geom IS
|
||||
'Back-compat shim: preserves original 4-column signature (cad_num, geom, '
|
||||
'raw_props, fetched_at) for legacy site-finder analyze fallback. '
|
||||
'Bulk PR2/5 will migrate callers to cad_parcels directly; drop this view then.';
|
||||
|
||||
-- ===========================================================================
|
||||
-- N. COMMENT ON TABLE for all 8 tables
|
||||
-- ===========================================================================
|
||||
COMMENT ON TABLE cad_parcels IS
|
||||
'Земельные участки ЕГРН из NSPD (categoryId 36368, EKB кадастровый округ 66:41:*). '
|
||||
'Широкая схема с полными атрибутами NSPD + геометрия. Заменяет cad_parcels_geom.';
|
||||
|
||||
COMMENT ON TABLE cad_buildings IS
|
||||
'Здания ЕГРН из NSPD (categoryId 36369). Широкая схема: objdoc_id для '
|
||||
'tab-group-data lookup, complex_id FK на complexes, cultural_heritage_object BOOLEAN.';
|
||||
|
||||
COMMENT ON TABLE cad_constructions IS
|
||||
'Сооружения из NSPD (categoryId 36383). Объединяет Сооружения и Сооружения ЕГРН '
|
||||
'(is_egrn=TRUE). Полный набор технических параметров (высота, объём, протяжённость).';
|
||||
|
||||
COMMENT ON TABLE cad_oncs IS
|
||||
'Объекты незавершённого строительства из NSPD (categoryId 36384, EKB 66:41:*).';
|
||||
|
||||
COMMENT ON TABLE cad_enk IS
|
||||
'Единые недвижимые комплексы из NSPD (categoryId 39663, EKB 66:41:*).';
|
||||
|
||||
COMMENT ON TABLE cad_zouit IS
|
||||
'Зоны с особыми условиями использования территории из NSPD '
|
||||
'(categoryIds 36940 / 469039 / 469040 / 469042, все в одной таблице). '
|
||||
'Натуральный ключ: (reg_numb_border, category_id) — один border может входить '
|
||||
'в несколько категорий.';
|
||||
|
||||
COMMENT ON TABLE cad_quarter_stats IS
|
||||
'Агрегированная статистика кадастрового квартала (1-to-1 с cad_quarters_geom). '
|
||||
'Заполняется bulk-harvest worker''ом: счётчики объектов, суммы площадей, кадастровая '
|
||||
'стоимость, real_srid ответа NSPD.';
|
||||
|
||||
COMMENT ON TABLE cadastre_jobs IS
|
||||
'Resumable saga state для bulk harvest runs (один job = один кадастровый квартал '
|
||||
'или batch). Зеркалит паттерн nspd_geo_jobs. heartbeat_at обновляется worker''ом '
|
||||
'каждые N секунд; zombie-детектор переводит зависшие jobs в статус zombie.';
|
||||
|
||||
-- ===========================================================================
|
||||
-- O. set_updated_at triggers for all tables with updated_at column.
|
||||
-- set_updated_at() function already exists in this DB (verified).
|
||||
-- CREATE OR REPLACE TRIGGER is not available in PG 16 — use DO guard.
|
||||
-- ===========================================================================
|
||||
|
||||
DO $$ BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM pg_trigger WHERE tgname = 'cad_parcels_set_updated_at'
|
||||
) THEN
|
||||
CREATE TRIGGER cad_parcels_set_updated_at
|
||||
BEFORE UPDATE ON cad_parcels
|
||||
FOR EACH ROW EXECUTE FUNCTION set_updated_at();
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM pg_trigger WHERE tgname = 'cad_buildings_set_updated_at'
|
||||
) THEN
|
||||
CREATE TRIGGER cad_buildings_set_updated_at
|
||||
BEFORE UPDATE ON cad_buildings
|
||||
FOR EACH ROW EXECUTE FUNCTION set_updated_at();
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM pg_trigger WHERE tgname = 'cad_constructions_set_updated_at'
|
||||
) THEN
|
||||
CREATE TRIGGER cad_constructions_set_updated_at
|
||||
BEFORE UPDATE ON cad_constructions
|
||||
FOR EACH ROW EXECUTE FUNCTION set_updated_at();
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM pg_trigger WHERE tgname = 'cad_oncs_set_updated_at'
|
||||
) THEN
|
||||
CREATE TRIGGER cad_oncs_set_updated_at
|
||||
BEFORE UPDATE ON cad_oncs
|
||||
FOR EACH ROW EXECUTE FUNCTION set_updated_at();
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM pg_trigger WHERE tgname = 'cad_enk_set_updated_at'
|
||||
) THEN
|
||||
CREATE TRIGGER cad_enk_set_updated_at
|
||||
BEFORE UPDATE ON cad_enk
|
||||
FOR EACH ROW EXECUTE FUNCTION set_updated_at();
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM pg_trigger WHERE tgname = 'cad_zouit_set_updated_at'
|
||||
) THEN
|
||||
CREATE TRIGGER cad_zouit_set_updated_at
|
||||
BEFORE UPDATE ON cad_zouit
|
||||
FOR EACH ROW EXECUTE FUNCTION set_updated_at();
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM pg_trigger WHERE tgname = 'cad_quarter_stats_set_updated_at'
|
||||
) THEN
|
||||
CREATE TRIGGER cad_quarter_stats_set_updated_at
|
||||
BEFORE UPDATE ON cad_quarter_stats
|
||||
FOR EACH ROW EXECUTE FUNCTION set_updated_at();
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- cadastre_jobs intentionally excluded — heartbeat_at is the liveness mechanism,
|
||||
-- not updated_at (which the table does not have).
|
||||
|
||||
COMMIT;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue