0dc5e58b55
LEFT JOIN caused duplicate rows and column conflicts. Replaced with a correlated subquery (LIMIT 1) to safely look up BUILD_LEGAL from the parent parcel's enrichment. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
99 lines
3.4 KiB
TypeScript
99 lines
3.4 KiB
TypeScript
/**
|
|
* GET /api/geoportal/setup-enrichment-views — check if views exist
|
|
* POST /api/geoportal/setup-enrichment-views — create enrichment status views
|
|
*
|
|
* Creates gis_terenuri_status and gis_cladiri_status views that include
|
|
* enrichment metadata (has_enrichment, has_building, build_legal).
|
|
* Martin serves these as vector tile sources, MapLibre uses them for
|
|
* data-driven styling in the ParcelSync Harta tab.
|
|
*
|
|
* IMPORTANT: Does NOT modify existing gis_terenuri/gis_cladiri views
|
|
* used by the Geoportal module.
|
|
*/
|
|
import { NextResponse } from "next/server";
|
|
import { prisma } from "@/core/storage/prisma";
|
|
|
|
export const runtime = "nodejs";
|
|
export const dynamic = "force-dynamic";
|
|
|
|
const VIEWS = [
|
|
{
|
|
name: "gis_terenuri_status",
|
|
sql: `CREATE OR REPLACE VIEW gis_terenuri_status AS
|
|
SELECT
|
|
f.id,
|
|
f."layerId" AS layer_id,
|
|
f.siruta,
|
|
f."objectId" AS object_id,
|
|
f."cadastralRef" AS cadastral_ref,
|
|
f."areaValue" AS area_value,
|
|
f."isActive" AS is_active,
|
|
CASE WHEN f.enrichment IS NOT NULL AND f."enrichedAt" IS NOT NULL THEN 1 ELSE 0 END AS has_enrichment,
|
|
COALESCE((f.enrichment->>'HAS_BUILDING')::int, 0) AS has_building,
|
|
COALESCE((f.enrichment->>'BUILD_LEGAL')::int, 0) AS build_legal,
|
|
f.geom
|
|
FROM "GisFeature" f
|
|
WHERE f.geom IS NOT NULL
|
|
AND (f."layerId" LIKE 'TERENURI%' OR f."layerId" LIKE 'CADGEN_LAND%')`,
|
|
},
|
|
{
|
|
name: "gis_cladiri_status",
|
|
sql: `CREATE OR REPLACE VIEW gis_cladiri_status AS
|
|
SELECT
|
|
f.id,
|
|
f."layerId" AS layer_id,
|
|
f.siruta,
|
|
f."objectId" AS object_id,
|
|
f."cadastralRef" AS cadastral_ref,
|
|
f."areaValue" AS area_value,
|
|
f."isActive" AS is_active,
|
|
COALESCE(
|
|
(SELECT (p.enrichment->>'BUILD_LEGAL')::int
|
|
FROM "GisFeature" p
|
|
WHERE p.siruta = f.siruta
|
|
AND p."cadastralRef" = f."cadastralRef"
|
|
AND (p."layerId" LIKE 'TERENURI%' OR p."layerId" LIKE 'CADGEN_LAND%')
|
|
AND p.enrichment IS NOT NULL
|
|
LIMIT 1),
|
|
-1
|
|
) AS build_legal,
|
|
f.geom
|
|
FROM "GisFeature" f
|
|
WHERE f.geom IS NOT NULL
|
|
AND (f."layerId" LIKE 'CLADIRI%' OR f."layerId" LIKE 'CADGEN_BUILDING%')`,
|
|
},
|
|
];
|
|
|
|
/** GET — check if enrichment views exist */
|
|
export async function GET() {
|
|
try {
|
|
const existing = await prisma.$queryRaw`
|
|
SELECT viewname FROM pg_views
|
|
WHERE schemaname = 'public' AND (viewname = 'gis_terenuri_status' OR viewname = 'gis_cladiri_status')
|
|
` as Array<{ viewname: string }>;
|
|
|
|
const existingNames = new Set(existing.map((r) => r.viewname));
|
|
const missing = VIEWS.filter((v) => !existingNames.has(v.name)).map((v) => v.name);
|
|
|
|
return NextResponse.json({ ready: missing.length === 0, missing });
|
|
} catch (error) {
|
|
const msg = error instanceof Error ? error.message : "Eroare";
|
|
return NextResponse.json({ ready: false, missing: VIEWS.map((v) => v.name), error: msg });
|
|
}
|
|
}
|
|
|
|
/** POST — create enrichment views (idempotent) */
|
|
export async function POST() {
|
|
const results: string[] = [];
|
|
try {
|
|
for (const v of VIEWS) {
|
|
await prisma.$executeRawUnsafe(v.sql);
|
|
results.push(`${v.name} OK`);
|
|
}
|
|
return NextResponse.json({ status: "ok", results });
|
|
} catch (error) {
|
|
const msg = error instanceof Error ? error.message : "Eroare";
|
|
return NextResponse.json({ status: "error", results, error: msg }, { status: 500 });
|
|
}
|
|
}
|