-- ============================================================================= -- PostGIS native geometry setup for GisFeature -- Run once via POST /api/eterra/setup-postgis (idempotent — safe to re-run) -- -- What this does: -- 1. Ensures PostGIS extension -- 2. Adds native geometry column (geom) if missing -- 3. Creates trigger to auto-convert GeoJSON → native on INSERT/UPDATE -- 4. Backfills existing features that have JSON geometry but no native geom -- 5. Creates GiST spatial index for fast spatial queries -- 6. Creates QGIS-friendly views with clean column names -- ============================================================================= -- 1. Ensure PostGIS extension CREATE EXTENSION IF NOT EXISTS postgis; -- 2. Add native geometry column (idempotent) DO $$ BEGIN IF NOT EXISTS ( SELECT 1 FROM information_schema.columns WHERE table_name = 'GisFeature' AND column_name = 'geom' ) THEN ALTER TABLE "GisFeature" ADD COLUMN geom geometry(Geometry, 3844); END IF; END $$; -- 3. Trigger function: auto-convert GeoJSON (geometry JSON column) → native PostGIS (geom) CREATE OR REPLACE FUNCTION gis_feature_sync_geom() RETURNS TRIGGER AS $$ BEGIN IF NEW.geometry IS NOT NULL THEN BEGIN NEW.geom := ST_SetSRID(ST_GeomFromGeoJSON(NEW.geometry::text), 3844); EXCEPTION WHEN OTHERS THEN -- Invalid GeoJSON → leave geom NULL rather than fail the write NEW.geom := NULL; END; ELSE NEW.geom := NULL; END IF; RETURN NEW; END; $$ LANGUAGE plpgsql; -- 4. Attach trigger (drop + recreate for idempotency) DROP TRIGGER IF EXISTS trg_gis_feature_sync_geom ON "GisFeature"; CREATE TRIGGER trg_gis_feature_sync_geom BEFORE INSERT OR UPDATE OF geometry ON "GisFeature" FOR EACH ROW EXECUTE FUNCTION gis_feature_sync_geom(); -- 5. Backfill: convert existing JSON geometries to native UPDATE "GisFeature" SET geom = ST_SetSRID(ST_GeomFromGeoJSON(geometry::text), 3844) WHERE geometry IS NOT NULL AND geom IS NULL; -- 6. GiST spatial index for fast bounding-box / intersection queries CREATE INDEX IF NOT EXISTS gis_feature_geom_idx ON "GisFeature" USING GIST (geom); -- ============================================================================= -- 7. QGIS-friendly views -- - Clean snake_case column names -- - Only rows with valid geometry -- - One master view + per-category views -- ============================================================================= -- Master view: all features CREATE OR REPLACE VIEW gis_features AS SELECT id, "layerId" AS layer_id, siruta, "objectId" AS object_id, "inspireId" AS inspire_id, "cadastralRef" AS cadastral_ref, "areaValue" AS area_value, "isActive" AS is_active, attributes, enrichment, "enrichedAt" AS enriched_at, "projectId" AS project_id, "createdAt" AS created_at, "updatedAt" AS updated_at, geom FROM "GisFeature" WHERE geom IS NOT NULL; -- Terenuri (parcels) CREATE OR REPLACE VIEW gis_terenuri AS SELECT * FROM gis_features WHERE layer_id LIKE 'TERENURI%' OR layer_id LIKE 'CADGEN_LAND%'; -- Clădiri (buildings) CREATE OR REPLACE VIEW gis_cladiri AS SELECT * FROM gis_features WHERE layer_id LIKE 'CLADIRI%' OR layer_id LIKE 'CADGEN_BUILDING%'; -- Documentații (expertize, zone interes, recepții) CREATE OR REPLACE VIEW gis_documentatii AS SELECT * FROM gis_features WHERE layer_id LIKE 'EXPERTIZA%' OR layer_id LIKE 'ZONE_INTERES%' OR layer_id LIKE 'RECEPTII%'; -- Administrativ (limite UAT, intravilan, arii speciale) CREATE OR REPLACE VIEW gis_administrativ AS SELECT * FROM gis_features WHERE layer_id LIKE 'LIMITE%' OR layer_id LIKE 'SPECIAL_AREAS%'; -- ============================================================================= -- Done! QGIS connection: PostgreSQL → 10.10.10.166:5432 / architools_db -- Add layers from views: gis_terenuri, gis_cladiri, gis_documentatii, etc. -- SRID: 3844 (Stereo70) -- =============================================================================