From a184127cd47dbf97d3bcf56e3e07037243965f44 Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Wed, 17 Jun 2026 14:25:41 +0000 Subject: [PATCH] fix(plan-detail): read recommendations denormalised, not via plan_recommendations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit getRecommendations read the retired plan_recommendations join table, which is empty for new-approach plans, so the plan detail page showed no recommendations. Read the recommendation table directly. Because recommendation.plan_id is unindexed (26M rows), key off the plan's property_id (indexed) and filter plan_id in memory — fast for any plan, default or not. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../building-passport/[propertyId]/utils.ts | 34 +++++++++++-------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/src/app/portfolio/[slug]/building-passport/[propertyId]/utils.ts b/src/app/portfolio/[slug]/building-passport/[propertyId]/utils.ts index 0ab77e7b..7ab6bece 100644 --- a/src/app/portfolio/[slug]/building-passport/[propertyId]/utils.ts +++ b/src/app/portfolio/[slug]/building-passport/[propertyId]/utils.ts @@ -1,6 +1,7 @@ import S3 from "aws-sdk/clients/s3"; import { Recommendation, + recommendation, planRecommendations, plan, Plan, @@ -163,23 +164,26 @@ export async function getEnergyAssessmentDocuments( export async function getRecommendations( planId: string ): Promise { - const data = (await db.query.planRecommendations.findMany({ - where: eq(planRecommendations.planId, BigInt(planId)), - columns: {}, - with: { - recommendation: true, - }, - })) as RecommendationList; - - if (!data) { - throw new Error("Network response was not ok"); + // Recommendations link to their plan via recommendation.plan_id (the + // plan_recommendations join table is retired). recommendation.plan_id is NOT + // indexed and the table has tens of millions of rows, so we key off the plan's + // property_id (indexed) and filter plan_id in memory. We drop already-installed + // measures, matching the previous behaviour. + const planRow = await db.query.plan.findFirst({ + columns: { propertyId: true }, + where: eq(plan.id, BigInt(planId)), + }); + if (!planRow?.propertyId) { + return []; } - // unnest the recommendations - // We drop measures that are already installed - const recommendations = data - .map((item) => item.recommendation) - .filter((rec) => !rec.alreadyInstalled); + const recommendations = await db.query.recommendation.findMany({ + where: and( + eq(recommendation.propertyId, planRow.propertyId), + eq(recommendation.planId, BigInt(planId)), + eq(recommendation.alreadyInstalled, false) + ), + }); return recommendations; }