diff --git a/app/api/route.ts b/app/api/route.ts index dd958510..fc978d6f 100644 --- a/app/api/route.ts +++ b/app/api/route.ts @@ -1,4 +1,4 @@ -import { NextResponse, NextRequest } from "next/server"; +import { NextResponse } from "next/server"; import { PrismaClient } from "@prisma/client"; const prisma = new PrismaClient(); @@ -33,267 +33,192 @@ export async function POST(request: Request) { let numberOfTransactions; // declare the variable for numbers of transactions retrieved let granularityPostcode; // declare the granularity of the postcode - const postcodeSearchSector = postcodeSector + "%"; // add the % for SQL query - - // define a type for PricePaid so that it is treated as an array - type PricePaid = { - id: number; - postcode: string; - price: number; - }; - - const pricesPaidSector = await prisma.$queryRaw` - SELECT id, postcode, price - FROM "public"."pricespaid" - WHERE propertyType = ${data.houseType} AND postcode LIKE ${postcodeSearchSector} - `; // execute query and extract results - console.log( - "pricesPaidSector: ", - pricesPaidSector, - "postcodeSearchSector: ", - postcodeSearchSector - ); - const numberOfpricesPaidSector = Array.isArray(pricesPaidSector) - ? pricesPaidSector.length - : 0; // extract the number of entries - - if ( - pricesPaidSector == null || - numberOfpricesPaidSector <= minimumNumberPostcodes - ) { - const postcodeSearchDistrict = postcodeDistrict + "%"; // add the % for SQL query - const pricesPaidDistrict = await prisma.$queryRaw` - SELECT id,postcode,price - FROM "public"."pricespaid" - WHERE propertyType = ${data.houseType} AND postcode LIKE ${postcodeSearchDistrict} - `; // create the sql query and count how many items meet the criteria; execute the query and retrieve the results - console.log( - "pricesPaidDistrict: ", - pricesPaidDistrict, - "postcodeSearchDistrict: ", - postcodeSearchDistrict - ); - const numberOfpricesPaidDistrict = Array.isArray(pricesPaidDistrict) - ? pricesPaidDistrict.length - : 0; // extract the number of entries - if ( - pricesPaidDistrict == null || - numberOfpricesPaidDistrict <= minimumNumberPostcodes - ) { - const postcodeSearchArea = postcodeArea + "%"; // add the % for SQL query - const pricesPaidArea = await prisma.$queryRaw` - SELECT id,postcode,price - FROM "public"."pricespaid" - WHERE propertytype = ${data.houseType} AND postcode LIKE ${postcodeSearchArea} - `; // create the sql query and count how many items meet the criteria; execute the query and retrieve the results - console.log( - "pricesPaidArea: ", - pricesPaidArea, - "postcodeSearchArea: ", - postcodeSearchArea - ); + const pricesPaidSector = await prisma.pricesPaid.findMany({ + where: { + propertyType: { + equals: data.houseType as string, + }, + postcode: { + startsWith: postcodeSector, + }, + }, + select: { + id: true, + postcode: true, + price: true, + } + }); + + console.log({ pricesPaidSector }); + + const isMinMetBySector = pricesPaidSector.length >= minimumNumberPostcodes; + + if (!isMinMetBySector) { + const pricesPaidDistrict = await prisma.pricesPaid.findMany({ + where: { + propertyType: { + equals: data.houseType as string, + }, + postcode: { + startsWith: postcodeDistrict, + }, + }, + select: { + id: true, + postcode: true, + price: true, + }, + }); - const numberOfpricesPaidArea = Array.isArray(pricesPaidArea) - ? pricesPaidArea.length - : 0; // extract the number of entries - pricesPaid = pricesPaidArea; // if condtion is met, the granularity is appropriate - numberOfTransactions = numberOfpricesPaidArea; // check the granularity + const isMinMetByDistrict = pricesPaidDistrict.length >= minimumNumberPostcodes; + + console.log({ pricesPaidDistrict }); + + if (!isMinMetByDistrict) { + const pricesPaidArea = await prisma.pricesPaid.findMany({ + where: { + propertyType: { + equals: data.houseType as string, + }, + postcode: { + startsWith: postcodeArea, + }, + }, + select: { + id: true, + postcode: true, + price: true, + }, + }); + console.log({ pricesPaidArea }); + + pricesPaid = pricesPaidArea; // if condition is met, the granularity is appropriate + numberOfTransactions = pricesPaidArea.length; // check the granularity granularityPostcode = postcodeArea; // granularity of the postcode when performing the average price search } else { - pricesPaid = pricesPaidDistrict; // if condtion is met, the granularity is appropriate - numberOfTransactions = numberOfpricesPaidDistrict; // check the granularity + pricesPaid = pricesPaidDistrict; // if condition is met, the granularity is appropriate + numberOfTransactions = pricesPaidDistrict.length; // check the granularity granularityPostcode = postcodeDistrict; // granularity of the postcode} } } else { - pricesPaid = pricesPaidSector; // if condtion is met, the granularity is appropriate - numberOfTransactions = numberOfpricesPaidSector; // check the granularity + pricesPaid = pricesPaidSector; // if condition is met, the granularity is appropriate + numberOfTransactions = pricesPaidSector.length; // check the granularity granularityPostcode = postcodeSector; // granularity of the postcode} } - console.log("pricesPaid: ", pricesPaid); + console.log({ pricesPaid }); // Calculate the total price if (!pricesPaid) throw Error("Prices fetching failed"); const totalPrice = pricesPaid.reduce( (total: number, item: any) => total + item.price, 0 ); - console.log("totalPrice:", totalPrice); + console.log({ totalPrice }); // Calculate the average price const averagePrice = totalPrice / pricesPaid.length; - // create type for buildPrice query - type BuildPrice = { - id: number; - housetype: string; - pricemid: number; - }; - - const buildPriceRes = await prisma.$queryRaw` - SELECT * FROM "public"."buildprices" - WHERE "housetype" = ${data.houseType} - `; - console.log("buildPriceRes:", buildPriceRes); - const buildPrice = buildPriceRes[0]["pricemid"]; - console.log("buildPrice:", buildPrice); - - // get the ITL3 value - // create type for itl3Res query - type ItlLookup = { - itl_lookup: string; - }; - - const itl3Res = await prisma.$queryRaw` - SELECT "itl_lookup"::text AS "itl_lookup" - FROM "public"."itl_lookup" - WHERE "postcode" = ${postcodeDistrict} - `; - const itlLookupValue = itl3Res[0].itl_lookup; - const itlLookupParts = itlLookupValue.split(","); - const itl3 = itlLookupParts[3]; // Extract the 3rd value (index 3) + const buildPrice = await prisma.buildPrices.findFirst({ + where: { + houseType: { equals: data.houseType as string }, + }, + select: { priceMid: true }, + }); + + const itlLookup = await prisma.itlLookup.findFirstOrThrow({ + where: { + postcode: postcodeDistrict, + itl3: { + not: null, + }, + }, + select: { + itl3: true, + }, + }); + + // Casting required as prisma does not type narrow with above clause "not: null" + const itl3 = (itlLookup.itl3 as string)[3]; // Extract the 3rd value (index 3) console.log("itl3: ", itl3); - console.log("itl3Res: ", itl3Res); - - // create type for itl3Res query - type gdhiRes = { - gdhi_2020: number; - }; - - // get the gdhi value --> Note: this need to change to accommodate future data - const gdhiRes = await prisma.$queryRaw` - SELECT gdhi_2020 - FROM "public"."gdhi" - WHERE "itl3" = ${itl3} - `; - const gdhi = gdhiRes[0]["gdhi_2020"]; - console.log("gdhiRes: ", gdhiRes); - console.log("gdhi: ", gdhi); - - // create type for itl3Res query - type rentRes = { - monthlymeanrent: number; - }; - // get the rent value --> Note: this need to change to accommodate future data - const rentRes = await prisma.$queryRaw` - SELECT monthlymeanrent - FROM "public"."rent" - WHERE itl3 = ${itl3} - `; - console.log("rentRes: ", rentRes); - let averageRent; - if (rentRes.length === 1) { - averageRent = rentRes[0].monthlymeanrent; - } else if (rentRes.length > 1) { - const totalRent = rentRes.reduce( - (sum, item) => sum + item.monthlymeanrent, - 0 - ); - averageRent = totalRent / rentRes.length; - console.log(averageRent); - - // create type for rentAdjustment query - type rentAdjustment = { - year: string; - inflation: string; - additional: string; - total: string; - }; - - // get the rent adjustements --> Note: this need to change to accommodate future data - - const socialRentAdjustments = await prisma.$queryRaw` - SELECT * - FROM "public"."soc_rent_adjustments" - `; // execute the query and retrieve the results - console.log("socialRentAdjustments[0]: ", socialRentAdjustments[0]); - - // create type for socialRentEarningRes query - type socialRentEarningRes = { - earningsperweek: number; - }; - - // get the rent value --> Note: this need to change to accommodate future data - const socialRentEarningRes = await prisma.$queryRaw< - socialRentEarningRes[] - >` - SELECT earningsperweek - FROM "public"."socialrent" - WHERE SUBSTRING(itl3 FROM 1 FOR 4) = ${itl3.substring(0, 4)} - `; - - console.log("socialRentEarningRes: ", socialRentEarningRes); - let socialRentAveEarning; - if (socialRentEarningRes.length === 1) { - socialRentAveEarning = socialRentEarningRes[0].earningsperweek; - } else if (socialRentEarningRes.length > 1) { - const socialRentTotalEarning = socialRentEarningRes.reduce( - (sum, item) => sum + item.earningsperweek, - 0 - ); - socialRentAveEarning = totalRent / socialRentEarningRes.length; + const gdhi = await prisma.gDHI.findFirst({ + where: { + itl3: { equals: itl3 }, + }, + select: { gdhi2020: true }, + }); + + const averageRent = await prisma.rent.aggregate({ + where: { itl3 }, + _avg: { + monthlyMeanRent: true, + }, + }); + + console.log({ averageRent }); + + const socialRentAdjustments = await prisma.sOCRentAdjustments.findMany(); + const itl3Prefix = itl3.substring(0, 4); + + const socialRentAveEarning = await prisma.socialRent.aggregate({ + where: { + itl3: { + startsWith: itl3Prefix + } + }, + _avg: { + earningsPerWeek: true, + }, + }); + console.log({ socialRentAveEarning }); + + const averageHpi = await prisma.hPI.aggregate({ + where: { + itl3: { + endsWith: itl3 + }, + }, + _avg: { + hpi2020: true + } } - console.log("socialRentAveEarning: ", socialRentAveEarning); - - // create type for hpiRes query - type hpiRes = { - hpi_2020: number; - }; - - // get the hpi value --> Note: this need to change to accommodate future data - const hpiRes = await prisma.$queryRaw` - SELECT hpi_2020 FROM "public"."hpi" - WHERE itl3 = ${itl3} - `; - console.log("hpiRes: ", hpiRes); - let averageHpi; - if (hpiRes.length === 1) { - averageHpi = hpiRes[0].hpi_2020; - } else { - const hpiTotal = hpiRes.reduce((sum, item) => sum + item.hpi_2020, 0); - averageHpi = hpiTotal / hpiRes.length; + ); + console.log({ averageHpi }); + + const gasBillYearly = await prisma.gasBills.findFirstOrThrow({ + where: { + itl: { + startsWith: itl3.substring(0, 3) + }, + }, + select: { + bill: true } - console.log("averageHpi: ", averageHpi); - - // create type for gas bill query - type gasBillYearlyRes = { - bill: number; - }; - - // get the gas bill value --> Note: this need to change to accommodate future data - const gasBillYearlyRes = await prisma.$queryRaw` - SELECT bill FROM "public"."gas_bills" - WHERE SUBSTRING(itl FROM 1 FOR 3) = ${itl3.substring(0, 3)} - `; - console.log("gasBillYearlyRes: ", gasBillYearlyRes); - const gasBillYearly = gasBillYearlyRes[0].bill; // get the gas bill - console.log("gasBillYearly: ", gasBillYearly); - - return NextResponse.json({ - postcode: postcode, - houseType: data.houseType, - houseAge: data.houseAge ? parseFloat(data.houseAge.toString()) : null, - houseBedrooms: data.houseBedrooms - ? parseFloat(data.houseBedrooms.toString()) - : null, - houseSize: data.houseSize - ? parseFloat(data.houseSize.toString()) - : null, - averagePrice: parseFloat(averagePrice.toFixed(2)), - itl3: itl3, - gdhi: gdhi, - hpi: averageHpi, - buildPrice: buildPrice, - averageRent: averageRent, - socialRentAdjustments: socialRentAdjustments, - socialRentAveEarning: socialRentAveEarning, - numberOfTransactions: numberOfTransactions, - granularityPostcode: granularityPostcode, - pricesPaid: pricesPaid, - gasBillYearly: gasBillYearly, - }); - } - - // return the results + }) + console.log({ gasBillYearly }); + + return NextResponse.json({ + postcode: postcode, + houseType: data.houseType, + houseAge: data.houseAge ? parseFloat(data.houseAge.toString()) : null, + houseBedrooms: data.houseBedrooms + ? parseFloat(data.houseBedrooms.toString()) + : null, + houseSize: data.houseSize + ? parseFloat(data.houseSize.toString()) + : null, + averagePrice: parseFloat(averagePrice.toFixed(2)), + itl3: itl3, + gdhi: gdhi, + hpi: averageHpi, + buildPrice: buildPrice, + averageRent: averageRent, + socialRentAdjustments: socialRentAdjustments, + socialRentAveEarning: socialRentAveEarning, + numberOfTransactions: numberOfTransactions, + granularityPostcode: granularityPostcode, + pricesPaid: pricesPaid, + gasBillYearly: gasBillYearly, + }); } catch (err) { console.log("ERROR: API - ", (err as Error).message);