146 lines
4.0 KiB
TypeScript
146 lines
4.0 KiB
TypeScript
import { NextResponse } from "next/server";
|
|
import { prisma } from "@/core/storage/prisma";
|
|
|
|
export const runtime = "nodejs";
|
|
export const dynamic = "force-dynamic";
|
|
|
|
/**
|
|
* GET /api/eterra/db-summary
|
|
*
|
|
* Returns a summary of ALL data in the GIS database, grouped by UAT.
|
|
* No siruta required — shows everything across all UATs.
|
|
*
|
|
* Response shape:
|
|
* {
|
|
* uats: [{
|
|
* siruta, uatName,
|
|
* layers: [{ layerId, count, enrichedCount, lastSynced }],
|
|
* totalFeatures, totalEnriched
|
|
* }],
|
|
* totalFeatures, totalUats
|
|
* }
|
|
*/
|
|
export async function GET() {
|
|
try {
|
|
// Feature counts per siruta + layerId
|
|
const featureCounts = await prisma.gisFeature.groupBy({
|
|
by: ["siruta", "layerId"],
|
|
_count: { id: true },
|
|
});
|
|
|
|
// Enriched counts per siruta + layerId
|
|
const enrichedCounts = await prisma.gisFeature.groupBy({
|
|
by: ["siruta", "layerId"],
|
|
where: { enrichedAt: { not: null } },
|
|
_count: { id: true },
|
|
});
|
|
const enrichedMap = new Map<string, number>();
|
|
for (const e of enrichedCounts) {
|
|
enrichedMap.set(`${e.siruta}:${e.layerId}`, e._count.id);
|
|
}
|
|
|
|
// Latest sync run per siruta + layerId
|
|
const latestRuns = await prisma.gisSyncRun.findMany({
|
|
where: { status: "done" },
|
|
orderBy: { completedAt: "desc" },
|
|
select: {
|
|
siruta: true,
|
|
uatName: true,
|
|
layerId: true,
|
|
completedAt: true,
|
|
},
|
|
});
|
|
const latestRunMap = new Map<
|
|
string,
|
|
{ completedAt: Date | null; uatName: string | null }
|
|
>();
|
|
for (const r of latestRuns) {
|
|
const key = `${r.siruta}:${r.layerId}`;
|
|
if (!latestRunMap.has(key)) {
|
|
latestRunMap.set(key, {
|
|
completedAt: r.completedAt,
|
|
uatName: r.uatName,
|
|
});
|
|
}
|
|
}
|
|
|
|
// UAT names from GisUat table
|
|
const uatNames = await prisma.gisUat.findMany({
|
|
select: { siruta: true, name: true, county: true },
|
|
});
|
|
const uatNameMap = new Map<
|
|
string,
|
|
{ name: string; county: string | null }
|
|
>();
|
|
for (const u of uatNames) {
|
|
uatNameMap.set(u.siruta, { name: u.name, county: u.county });
|
|
}
|
|
|
|
// Group by siruta
|
|
const uatMap = new Map<
|
|
string,
|
|
{
|
|
siruta: string;
|
|
uatName: string;
|
|
county: string | null;
|
|
layers: {
|
|
layerId: string;
|
|
count: number;
|
|
enrichedCount: number;
|
|
lastSynced: string | null;
|
|
}[];
|
|
totalFeatures: number;
|
|
totalEnriched: number;
|
|
}
|
|
>();
|
|
|
|
for (const fc of featureCounts) {
|
|
if (!uatMap.has(fc.siruta)) {
|
|
const uatInfo = uatNameMap.get(fc.siruta);
|
|
const runInfo = latestRunMap.get(`${fc.siruta}:${fc.layerId}`);
|
|
uatMap.set(fc.siruta, {
|
|
siruta: fc.siruta,
|
|
uatName: uatInfo?.name ?? runInfo?.uatName ?? `UAT ${fc.siruta}`,
|
|
county: uatInfo?.county ?? null,
|
|
layers: [],
|
|
totalFeatures: 0,
|
|
totalEnriched: 0,
|
|
});
|
|
}
|
|
|
|
const uat = uatMap.get(fc.siruta)!;
|
|
const enriched = enrichedMap.get(`${fc.siruta}:${fc.layerId}`) ?? 0;
|
|
const runInfo = latestRunMap.get(`${fc.siruta}:${fc.layerId}`);
|
|
|
|
uat.layers.push({
|
|
layerId: fc.layerId,
|
|
count: fc._count.id,
|
|
enrichedCount: enriched,
|
|
lastSynced: runInfo?.completedAt?.toISOString() ?? null,
|
|
});
|
|
uat.totalFeatures += fc._count.id;
|
|
uat.totalEnriched += enriched;
|
|
|
|
// Update UAT name if we got one from sync runs
|
|
if (uat.uatName.startsWith("UAT ") && runInfo?.uatName) {
|
|
uat.uatName = runInfo.uatName;
|
|
}
|
|
}
|
|
|
|
const uats = Array.from(uatMap.values()).sort(
|
|
(a, b) => b.totalFeatures - a.totalFeatures,
|
|
);
|
|
|
|
const totalFeatures = uats.reduce((s, u) => s + u.totalFeatures, 0);
|
|
|
|
return NextResponse.json({
|
|
uats,
|
|
totalFeatures,
|
|
totalUats: uats.length,
|
|
});
|
|
} catch (error) {
|
|
const message = error instanceof Error ? error.message : "Eroare server";
|
|
return NextResponse.json({ error: message }, { status: 500 });
|
|
}
|
|
}
|