From b84bc4138ac15570f7f68f576d0863ce7bb390f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Fagundes?= Date: Fri, 24 May 2024 20:29:38 -0300 Subject: [PATCH] feat: added decay shelter supply behaviour --- .../shelter-supply-history.interceptor.ts | 4 +- .../shelter-supply-history/utils.ts | 20 +--- src/prisma/prisma.service.ts | 2 - src/shelter/shelter.service.ts | 113 +++++++++++++++++- src/shelter/types/types.ts | 8 ++ 5 files changed, 126 insertions(+), 21 deletions(-) diff --git a/src/interceptors/interceptors/shelter-supply-history/shelter-supply-history.interceptor.ts b/src/interceptors/interceptors/shelter-supply-history/shelter-supply-history.interceptor.ts index 358afc1b..83baed4b 100644 --- a/src/interceptors/interceptors/shelter-supply-history/shelter-supply-history.interceptor.ts +++ b/src/interceptors/interceptors/shelter-supply-history/shelter-supply-history.interceptor.ts @@ -8,7 +8,7 @@ import { Observable } from 'rxjs'; import { ShelterSupplyHistoryAction } from './types'; import { handler } from './utils'; -import { prisma } from '../../../prisma/prisma.service'; +import { PrismaService } from '../../../prisma/prisma.service'; @Injectable() export class ShelterSupplyHistoryInterceptor implements NestInterceptor { @@ -16,7 +16,7 @@ export class ShelterSupplyHistoryInterceptor implements NestInterceptor { intercept(context: ExecutionContext, next: CallHandler): Observable { const request = context.switchToHttp().getRequest(); - handler(prisma, this.action, request); + handler(PrismaService.getInstance(), this.action, request); return next.handle(); } } diff --git a/src/interceptors/interceptors/shelter-supply-history/utils.ts b/src/interceptors/interceptors/shelter-supply-history/utils.ts index 61debcae..46119734 100644 --- a/src/interceptors/interceptors/shelter-supply-history/utils.ts +++ b/src/interceptors/interceptors/shelter-supply-history/utils.ts @@ -14,15 +14,14 @@ import { ShelterSupplyHistoryAction, UserIdentity } from './types'; import { getSessionData } from '@/utils/utils'; function registerSupplyLog( - prismaService: PrismaService, body: z.infer, - user: UserIdentity, + user: UserIdentity = {}, ) { const fn = async () => { const { shelterId, supplyId, ...rest } = CreateSupplyHistorySchema.parse(body); - const prev = await prismaService.supplyHistory.findFirst({ + const prev = await PrismaService.getInstance().supplyHistory.findFirst({ where: { shelterId, supplyId, @@ -32,7 +31,7 @@ function registerSupplyLog( }, }); - await prismaService.supplyHistory.create({ + await PrismaService.getInstance().supplyHistory.create({ data: { shelterId, supplyId, @@ -57,23 +56,20 @@ function registerSupplyLog( } function registerCreateSupplyLog( - prismaService: PrismaService, body: z.infer, user: UserIdentity, ) { const payload = CreateShelterSupplySchema.parse(body); - registerSupplyLog(prismaService, payload, user); + registerSupplyLog(payload, user); } function registerUpdateSupplyLog( - prismaService: PrismaService, body: z.infer, user: UserIdentity, ) { const payload = UpdateShelterSupplySchema.parse(body); registerSupplyLog( - prismaService, { shelterId: payload.where.shelterId, supplyId: payload.where.supplyId, @@ -85,7 +81,6 @@ function registerUpdateSupplyLog( } function registerUpdateManySupplyLog( - prismaService: PrismaService, body: z.infer, user: UserIdentity, ) { @@ -93,7 +88,6 @@ function registerUpdateManySupplyLog( ids.forEach((id) => registerSupplyLog( - prismaService, { shelterId, supplyId: id, @@ -124,11 +118,10 @@ function handler( switch (action) { case ShelterSupplyHistoryAction.Create: - registerCreateSupplyLog(prismaService, request.body as any, user); + registerCreateSupplyLog(request.body as any, user); break; case ShelterSupplyHistoryAction.Update: registerUpdateSupplyLog( - prismaService, { data: request.body as any, where: request.params as any, @@ -138,7 +131,6 @@ function handler( break; case ShelterSupplyHistoryAction.UpdateMany: registerUpdateManySupplyLog( - prismaService, { shelterId: (request.params as any).shelterId, ids: (request.body as any).ids, @@ -149,4 +141,4 @@ function handler( } } -export { handler }; +export { handler, registerSupplyLog }; diff --git a/src/prisma/prisma.service.ts b/src/prisma/prisma.service.ts index 12806a87..72379391 100644 --- a/src/prisma/prisma.service.ts +++ b/src/prisma/prisma.service.ts @@ -39,5 +39,3 @@ export class PrismaService }); } } - -export const prisma = PrismaService.getInstance(); diff --git a/src/shelter/shelter.service.ts b/src/shelter/shelter.service.ts index f79ac367..058db35f 100644 --- a/src/shelter/shelter.service.ts +++ b/src/shelter/shelter.service.ts @@ -1,7 +1,7 @@ -import { Injectable, OnModuleInit } from '@nestjs/common'; -import { Prisma } from '@prisma/client'; +import { Injectable, Logger, OnModuleInit } from '@nestjs/common'; +import { Prisma, ShelterSupply } from '@prisma/client'; import { DefaultArgs } from '@prisma/client/runtime/library'; -import { subDays } from 'date-fns'; +import { millisecondsToHours, subDays } from 'date-fns'; import * as qs from 'qs'; import { z } from 'zod'; @@ -13,11 +13,14 @@ import { ShelterSearchPropsSchema } from './types/search.types'; import { CreateShelterSchema, FullUpdateShelterSchema, + IShelterSupplyDecay, UpdateShelterSchema, } from './types/types'; +import { registerSupplyLog } from '@/interceptors/interceptors/shelter-supply-history/utils'; @Injectable() export class ShelterService implements OnModuleInit { + private logger = new Logger(ShelterService.name); private voluntaryIds: string[] = []; constructor(private readonly prismaService: PrismaService) {} @@ -93,6 +96,10 @@ export class ShelterService implements OnModuleInit { select: { priority: true, quantity: true, + supplyId: true, + shelterId: true, + createdAt: true, + updatedAt: true, supply: { select: { id: true, @@ -115,6 +122,8 @@ export class ShelterService implements OnModuleInit { }, }); + if (data) this.decayShelterSupply(data.shelterSupplies); + return data; } @@ -181,6 +190,8 @@ export class ShelterService implements OnModuleInit { }, }); + this.decayShelterSupply(results.flatMap((r) => r.shelterSupplies)); + const parsed = parseTagResponse(queryData, results, this.voluntaryIds); return { @@ -228,4 +239,100 @@ export class ShelterService implements OnModuleInit { this.voluntaryIds.push(...resp.map((s) => s.id)); }); } + + private parseShelterSupply( + shelterSupply: ShelterSupply, + ): IShelterSupplyDecay { + return { + shelterId: shelterSupply.shelterId, + supplyId: shelterSupply.supplyId, + priority: shelterSupply.priority, + createdAt: new Date(shelterSupply.createdAt).getTime(), + updatedAt: shelterSupply.updatedAt + ? new Date(shelterSupply.updatedAt).getTime() + : 0, + }; + } + + private canDecayShelterSupply( + shelterSupply: IShelterSupplyDecay, + priorities: SupplyPriority[], + timeInHoursToDecay: number, + ): boolean { + return ( + priorities.includes(shelterSupply.priority) && + millisecondsToHours( + new Date().getTime() - + Math.max(shelterSupply.createdAt, shelterSupply.updatedAt), + ) > timeInHoursToDecay + ); + } + + private async handleDecayShelterSupply( + shelterSupplies: IShelterSupplyDecay[], + newPriority: SupplyPriority, + ) { + const shelterIds: Set = new Set(); + shelterSupplies.forEach((s) => shelterIds.add(s.shelterId)); + + await this.prismaService.$transaction([ + this.prismaService.shelter.updateMany({ + where: { + id: { + in: Array.from(shelterIds), + }, + }, + data: { + updatedAt: new Date().toISOString(), + }, + }), + ...shelterSupplies.map((s) => + this.prismaService.shelterSupply.update({ + where: { + shelterId_supplyId: { + shelterId: s.shelterId, + supplyId: s.supplyId, + }, + }, + data: { + priority: newPriority, + updatedAt: new Date().toISOString(), + }, + }), + ), + ]); + + shelterSupplies.forEach((s) => { + registerSupplyLog({ + shelterId: s.shelterId, + supplyId: s.supplyId, + priority: newPriority, + }); + }); + } + + private async decayShelterSupply(shelterSupplies: ShelterSupply[]) { + this.handleDecayShelterSupply( + shelterSupplies + .map(this.parseShelterSupply) + .filter((f) => + this.canDecayShelterSupply(f, [SupplyPriority.Urgent], 12), + ), + + SupplyPriority.Needing, + ); + + this.handleDecayShelterSupply( + shelterSupplies + .map(this.parseShelterSupply) + .filter((f) => + this.canDecayShelterSupply( + f, + [SupplyPriority.Needing, SupplyPriority.Remaining], + 48, + ), + ), + SupplyPriority.UnderControl, + ); + } } diff --git a/src/shelter/types/types.ts b/src/shelter/types/types.ts index 0bdee096..c2361788 100644 --- a/src/shelter/types/types.ts +++ b/src/shelter/types/types.ts @@ -49,6 +49,14 @@ const FullUpdateShelterSchema = ShelterSchema.omit({ .partial() .transform((args) => removeEmptyStrings(args)); +export interface IShelterSupplyDecay { + shelterId: string; + supplyId: string; + priority: number; + createdAt: number; + updatedAt: number; +} + export { ShelterSchema, CreateShelterSchema,