Skip to content

Commit 59f2e8b

Browse files
authored
Merge pull request #190 from Lemoncode/Feature/add-cache-and-revalidate
Feat: Implement caching and revalidation for reservoir data retrieval
2 parents 70eb956 + e37d085 commit 59f2e8b

12 files changed

Lines changed: 115 additions & 15 deletions

File tree

front/src/app/embalse-cuenca/[cuenca]/page.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import { EmbalsesCuencaPod, getEmbalsesPorCuenca } from "@/pods/embalse-cuenca";
22
import { cuencas } from "@/core/constants";
3-
import { Metadata } from "next";
43
import { mapLookupListFromApiToViewModel } from "@/common/mappers";
4+
import { Metadata } from "next";
5+
6+
export const revalidate = 300; // ISR: regenerar cada 5 minutos
57

68
interface Props {
79
params: Promise<{ cuenca: string }>;

front/src/app/embalse-cuenca/page.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import { EmbalseCuencaListPod } from "@/pods/embalse-cuenca-list";
33
import { getRiverBasins } from "@/pods/embalse-cuenca-list/embalse-cuenca-list.repository";
44
import { Metadata } from "next";
55

6+
export const revalidate = 300; // ISR: regenerar cada 5 minutos
7+
68
export const metadata: Metadata = {
79
title: "Embalses por cuencas",
810
};

front/src/app/embalse-provincia/[provincia]/page.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
import { PROVINCIAS } from "@/core/constants";
2-
import { EmbalseProvinciaPod } from "@/pods/embalse-provincia";
2+
import {
3+
EmbalseProvinciaPod,
4+
getEmbalsesByProvince,
5+
} from "@/pods/embalse-provincia";
36
import { mapEmbalseListFromApiToLookup } from "@/pods/embalse-provincia/embalse-provincia.mapper";
4-
import { getEmbalsesByProvince } from "@/pods/embalse-provincia/embalse-provincia.repository";
57
import { Metadata } from "next";
68

9+
export const revalidate = 300; // ISR: regenerar cada 5 minutos
10+
711
interface Props {
812
params: Promise<{ provincia: string }>;
913
}

front/src/app/embalse/[embalse]/page.tsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
import type { Metadata } from "next";
22
import { notFound } from "next/navigation";
3-
import { EmbalsePod, getReservoirInfoBySlugCached } from "@/pods/embalse";
4-
import { getEmbalseBySlug } from "@/pods/embalse/embalse.repository";
3+
import {
4+
EmbalsePod,
5+
getReservoirInfoBySlugCached,
6+
getEmbalseBySlugCached,
7+
} from "@/pods/embalse";
58
import { mapEmbalseToReservoirData } from "@/pods/embalse/embalse.mapper";
69

710
export const revalidate = 300; // ISR: regenerar cada 5 minutos
811

912
export async function generateMetadata({ params }: Props): Promise<Metadata> {
1013
const { embalse } = await params;
11-
const embalseSlug = await getEmbalseBySlug(embalse);
14+
const embalseSlug = await getEmbalseBySlugCached(embalse);
1215

1316
return {
1417
title: embalseSlug.nombre,
@@ -25,7 +28,7 @@ export default async function EmbalseDetallePage({ params }: Props) {
2528
Si no se encuentra el embalse, llamamos a notFound() que muestra la pagina 404 de Next.js
2629
*/
2730
const { embalse } = await params;
28-
const embalseDoc = await getEmbalseBySlug(embalse);
31+
const embalseDoc = await getEmbalseBySlugCached(embalse);
2932
const embalseInfo = await getReservoirInfoBySlugCached(embalse);
3033

3134
if (!embalseDoc) {

front/src/pods/embalse-cuenca-list/embalse-cuenca-list.repository.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,33 @@
22

33
import { LookupApi } from "@/common/models";
44
import { getDb } from "@/lib/mongodb";
5+
import { unstable_cache } from "next/cache";
56

6-
export async function getRiverBasins(): Promise<LookupApi[]> {
7-
try {
7+
const getCachedRiverBasins = unstable_cache(
8+
async (): Promise<LookupApi[]> => {
89
const db = await getDb();
9-
return await db
10+
const result = await db
1011
.collection<LookupApi>("cuencas")
1112
.find({}, { projection: { _id: 1, nombre: 1 } })
1213
.toArray();
14+
if (result.length === 0) {
15+
throw new Error("Empty cuencas - skip cache");
16+
}
17+
return result;
18+
},
19+
["cuencas-collection"],
20+
{ revalidate: 300 },
21+
);
22+
23+
export async function getRiverBasins(): Promise<LookupApi[]> {
24+
try {
25+
return await getCachedRiverBasins();
1326
} catch (error) {
1427
console.warn(
15-
"getEmbalsesByRiverBasin: MongoDB not available (build time?), returning empty array.",
28+
"getRiverBasins: MongoDB not available or empty, returning empty array.",
1629
"Error:",
1730
error instanceof Error ? error.message : error,
1831
);
32+
return [];
1933
}
2034
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import "server-only";
2+
import { unstable_cache } from "next/cache";
3+
import type { LookupApi } from "@/common/models";
4+
import { getEmbalsesPorCuenca as getEmbalsesPorCuencaFromDb } from "../embalse-cuenca.repository";
5+
6+
/**
7+
* Cached version of getEmbalsesPorCuenca.
8+
* Revalidates every 5 minutes.
9+
*/
10+
const getCachedEmbalsesPorCuenca = unstable_cache(
11+
async (nombre: string): Promise<LookupApi[]> => {
12+
const embalses = await getEmbalsesPorCuencaFromDb(nombre);
13+
if (!embalses || embalses.length === 0) {
14+
throw new Error("Empty embalses por cuenca - skip cache");
15+
}
16+
return embalses;
17+
},
18+
["embalses-por-cuenca"],
19+
{ revalidate: 300 },
20+
);
21+
22+
export const getEmbalsesPorCuenca = async (
23+
nombre: string,
24+
): Promise<LookupApi[]> => {
25+
try {
26+
return await getCachedEmbalsesPorCuenca(nombre);
27+
} catch {
28+
return [];
29+
}
30+
};

front/src/pods/embalse-cuenca/embalse-cuenca.repository.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,6 @@ export const getEmbalsesPorCuenca = async (
1919
"Error:",
2020
error instanceof Error ? error.message : error,
2121
);
22+
return [];
2223
}
2324
};
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
export * from "./embalse-cuenca.pod";
2-
export * from "./embalse-cuenca.repository";
2+
export * from "./api/embalse-cuenca.api";
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import "server-only";
2+
import { unstable_cache } from "next/cache";
3+
import type { EmbalseApi } from "../embalse-provincia.api-model";
4+
import { getEmbalsesByProvince as getEmbalsesByProvinceFromDb } from "../embalse-provincia.repository";
5+
6+
/**
7+
* Cached version of getEmbalsesByProvince.
8+
* Revalidates every 5 minutes.
9+
*/
10+
const getCachedEmbalsesByProvince = unstable_cache(
11+
async (provincia: string): Promise<EmbalseApi[]> => {
12+
const embalses = await getEmbalsesByProvinceFromDb(provincia);
13+
if (!embalses || embalses.length === 0) {
14+
throw new Error("Empty embalses por provincia - skip cache");
15+
}
16+
return embalses;
17+
},
18+
["embalses-por-provincia"],
19+
{ revalidate: 300 },
20+
);
21+
22+
export const getEmbalsesByProvince = async (
23+
provincia: string,
24+
): Promise<EmbalseApi[]> => {
25+
try {
26+
return await getCachedEmbalsesByProvince(provincia);
27+
} catch {
28+
return [];
29+
}
30+
};

front/src/pods/embalse-provincia/embalse-provincia.repository.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ export async function getEmbalsesByProvince(
2222
)
2323
.toArray();
2424

25-
console.log(docs);
2625
return docs.map((doc) => ({
2726
_id: doc.slug ?? String(doc._id),
2827
name: doc.nombre ?? "",

0 commit comments

Comments
 (0)