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
|
-- J. Migrate data: cad_parcels_geom -> cad_parcels
|
||||||
-- K. Backup + replace: cad_buildings -> cad_buildings_old_apr26 -> DROP + rename
|
-- K. Backup + replace: cad_buildings -> cad_buildings_old_apr26 -> DROP + rename
|
||||||
-- L. Restore FK + views
|
-- 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.
|
-- Idempotency: safe to re-run — all DDL uses IF NOT EXISTS / IF EXISTS guards.
|
||||||
-- Data migrations use INSERT ... ON CONFLICT DO NOTHING.
|
-- Data migrations use INSERT ... ON CONFLICT DO NOTHING.
|
||||||
|
|
@ -293,7 +295,11 @@ CREATE TABLE IF NOT EXISTS cadastre_jobs (
|
||||||
error TEXT,
|
error TEXT,
|
||||||
phase_state JSONB,
|
phase_state JSONB,
|
||||||
raw_targets 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;
|
ALTER TABLE cad_buildings_new RENAME TO cad_buildings;
|
||||||
-- Rename indexes to drop the _new suffix
|
-- Rename indexes to drop the _new suffix
|
||||||
ALTER INDEX IF EXISTS cad_buildings_new_pkey RENAME TO cad_buildings_pkey;
|
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_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_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_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_complex_idx RENAME TO cad_buildings_complex_idx;
|
||||||
ALTER INDEX IF EXISTS cad_buildings_new_purpose_idx RENAME TO cad_buildings_purpose_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 IF;
|
||||||
END $$;
|
END $$;
|
||||||
|
|
||||||
|
|
@ -627,21 +632,159 @@ SELECT
|
||||||
FROM complexes c;
|
FROM complexes c;
|
||||||
|
|
||||||
-- ===========================================================================
|
-- ===========================================================================
|
||||||
-- M. DROP cad_parcels_geom (original table — data migrated to cad_parcels)
|
-- M. Replace cad_parcels_geom TABLE with a back-compat VIEW over cad_parcels.
|
||||||
-- Only dropped if cad_parcels exists and has at least as many rows.
|
-- Original table had exactly: cad_num, geom, raw_props, fetched_at.
|
||||||
-- Guard: skip drop if the new table doesn't exist yet (paranoia).
|
-- 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 $$
|
DO $$
|
||||||
BEGIN
|
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 (
|
IF EXISTS (
|
||||||
SELECT 1 FROM information_schema.tables
|
SELECT 1 FROM information_schema.tables
|
||||||
WHERE table_schema = 'public' AND table_name = 'cad_parcels'
|
WHERE table_schema = 'public' AND table_name = 'cad_parcels'
|
||||||
) AND EXISTS (
|
) AND EXISTS (
|
||||||
SELECT 1 FROM information_schema.tables
|
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
|
) THEN
|
||||||
DROP TABLE cad_parcels_geom;
|
DROP TABLE cad_parcels_geom;
|
||||||
END IF;
|
END IF;
|
||||||
END $$;
|
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;
|
COMMIT;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue