From 31a166e6e040b7d43b59ff64622181756f75b4c2 Mon Sep 17 00:00:00 2001 From: Bryann Yeap Kok Keong <77266823+BryannYeap@users.noreply.github.com> Date: Mon, 7 Nov 2022 15:59:36 +0800 Subject: [PATCH] [offers][refactor] Calculate overall and company analyses asychronously (#523) * [offers][refactor] Calculate overall and company analyses asychronously * [offers][refactor] Calculate overall and company analyses asychronously --- apps/portal/src/mappers/offers-mappers.ts | 2 +- .../offers/analysis/analysisGeneration.ts | 200 +++++++++++++----- 2 files changed, 147 insertions(+), 55 deletions(-) diff --git a/apps/portal/src/mappers/offers-mappers.ts b/apps/portal/src/mappers/offers-mappers.ts index 8fa69461..fa91fb9a 100644 --- a/apps/portal/src/mappers/offers-mappers.ts +++ b/apps/portal/src/mappers/offers-mappers.ts @@ -330,7 +330,7 @@ export const profileAnalysisDtoMapper = ( }) | null, ) => { - if (!analysis) { + if (analysis == null) { return null; } diff --git a/apps/portal/src/utils/offers/analysis/analysisGeneration.ts b/apps/portal/src/utils/offers/analysis/analysisGeneration.ts index 392bb876..4588f852 100644 --- a/apps/portal/src/utils/offers/analysis/analysisGeneration.ts +++ b/apps/portal/src/utils/offers/analysis/analysisGeneration.ts @@ -3,6 +3,8 @@ import type { City, Company, Country, + OffersAnalysis, + OffersAnalysisUnit, OffersBackground, OffersCurrency, OffersExperience, @@ -20,6 +22,98 @@ import { TRPCError } from '@trpc/server'; import { analysisInclusion } from './analysisInclusion'; import { profileAnalysisDtoMapper } from '../../../mappers/offers-mappers'; +type Analysis = + | (OffersAnalysis & { + companyAnalysis: Array< + OffersAnalysisUnit & { + analysedOffer: OffersOffer & { + company: Company; + offersFullTime: + | (OffersFullTime & { totalCompensation: OffersCurrency }) + | null; + offersIntern: + | (OffersIntern & { monthlySalary: OffersCurrency }) + | null; + profile: OffersProfile & { background: OffersBackground | null }; + }; + topSimilarOffers: Array< + OffersOffer & { + company: Company; + location: City & { state: State & { country: Country } }; + offersFullTime: + | (OffersFullTime & { totalCompensation: OffersCurrency }) + | null; + offersIntern: + | (OffersIntern & { monthlySalary: OffersCurrency }) + | null; + profile: OffersProfile & { + background: + | (OffersBackground & { + experiences: Array< + OffersExperience & { + company: Company | null; + location: + | (City & { state: State & { country: Country } }) + | null; + } + >; + }) + | null; + }; + } + >; + } + >; + overallAnalysis: OffersAnalysisUnit & { + analysedOffer: OffersOffer & { + company: Company; + offersFullTime: + | (OffersFullTime & { totalCompensation: OffersCurrency }) + | null; + offersIntern: + | (OffersIntern & { monthlySalary: OffersCurrency }) + | null; + profile: OffersProfile & { background: OffersBackground | null }; + }; + topSimilarOffers: Array< + OffersOffer & { + company: Company; + location: City & { state: State & { country: Country } }; + offersFullTime: + | (OffersFullTime & { totalCompensation: OffersCurrency }) + | null; + offersIntern: + | (OffersIntern & { monthlySalary: OffersCurrency }) + | null; + profile: OffersProfile & { + background: + | (OffersBackground & { + experiences: Array< + OffersExperience & { + company: Company | null; + location: + | (City & { state: State & { country: Country } }) + | null; + } + >; + }) + | null; + }; + } + >; + }; + overallHighestOffer: OffersOffer & { + company: Company; + location: City & { state: State & { country: Country } }; + offersFullTime: + | (OffersFullTime & { totalCompensation: OffersCurrency }) + | null; + offersIntern: (OffersIntern & { monthlySalary: OffersCurrency }) | null; + profile: OffersProfile & { background: OffersBackground | null }; + }; + }) + | null; + type Offer = OffersOffer & { company: Company; location: City & { state: State & { country: Country } }; @@ -285,6 +379,8 @@ export const generateAnalysis = async (params: { }; input: { profileId: string }; }) => { + let analysis: Analysis = null; + const { ctx, input } = params; await ctx.prisma.offersAnalysis.deleteMany({ where: { @@ -352,17 +448,8 @@ export const generateAnalysis = async (params: { } const overallHighestOffer = offers[0]; - const usersOfferIds = offers.map((offer) => offer.id); - // OVERALL ANALYSIS - const overallAnalysisUnit = await generateAnalysisUnit( - ctx.prisma, - overallHighestOffer, - usersOfferIds, - ); - - // COMPANY ANALYSIS const companyMap = new Map(); offers.forEach((offer) => { if (companyMap.get(offer.companyId) == null) { @@ -370,65 +457,70 @@ export const generateAnalysis = async (params: { } }); - const companyAnalysis = await Promise.all( - Array.from(companyMap.values()).map(async (companyOffer) => { - return await generateAnalysisUnit( - ctx.prisma, - companyOffer, - usersOfferIds, - true, - ); - }), - ); + Promise.all([ + generateAnalysisUnit(ctx.prisma, overallHighestOffer, usersOfferIds), + Promise.all( + Array.from(companyMap.values()).map(async (companyOffer) => { + return await generateAnalysisUnit( + ctx.prisma, + companyOffer, + usersOfferIds, + true, + ); + }), + ), + ]).then(async (analyses) => { + const [overallAnalysisUnit, companyAnalysis] = analyses; - const analysis = await ctx.prisma.offersAnalysis.create({ - data: { - companyAnalysis: { - create: companyAnalysis.map((analysisUnit) => { - return { + analysis = await ctx.prisma.offersAnalysis.create({ + data: { + companyAnalysis: { + create: companyAnalysis.map((analysisUnit) => { + return { + analysedOffer: { + connect: { + id: analysisUnit.analysedOfferId, + }, + }, + noOfSimilarOffers: analysisUnit.noOfSimilarOffers, + percentile: analysisUnit.percentile, + topSimilarOffers: { + connect: analysisUnit.topSimilarOffers.map((offer) => { + return { id: offer.id }; + }), + }, + }; + }), + }, + overallAnalysis: { + create: { analysedOffer: { connect: { - id: analysisUnit.analysedOfferId, + id: overallAnalysisUnit.analysedOfferId, }, }, - noOfSimilarOffers: analysisUnit.noOfSimilarOffers, - percentile: analysisUnit.percentile, + noOfSimilarOffers: overallAnalysisUnit.noOfSimilarOffers, + percentile: overallAnalysisUnit.percentile, topSimilarOffers: { - connect: analysisUnit.topSimilarOffers.map((offer) => { + connect: overallAnalysisUnit.topSimilarOffers.map((offer) => { return { id: offer.id }; }), }, - }; - }), - }, - overallAnalysis: { - create: { - analysedOffer: { - connect: { - id: overallAnalysisUnit.analysedOfferId, - }, - }, - noOfSimilarOffers: overallAnalysisUnit.noOfSimilarOffers, - percentile: overallAnalysisUnit.percentile, - topSimilarOffers: { - connect: overallAnalysisUnit.topSimilarOffers.map((offer) => { - return { id: offer.id }; - }), }, }, - }, - overallHighestOffer: { - connect: { - id: overallHighestOffer.id, + overallHighestOffer: { + connect: { + id: overallHighestOffer.id, + }, }, - }, - profile: { - connect: { - id: input.profileId, + profile: { + connect: { + id: input.profileId, + }, }, }, - }, - include: analysisInclusion, + include: analysisInclusion, + }); }); return profileAnalysisDtoMapper(analysis);