Skip to content

Commit

Permalink
feat: ✨ daily coalition score 추가를 통한 scoreRecordsPerCoalition last 추가
Browse files Browse the repository at this point in the history
  • Loading branch information
jpham005 committed Nov 13, 2023
1 parent c3a5ffd commit f01f2f9
Show file tree
Hide file tree
Showing 11 changed files with 233 additions and 79 deletions.
12 changes: 12 additions & 0 deletions app/src/dailyCoalitionScore/dailyCoalitionScore.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import type { coalition } from 'src/api/coalition/db/coalition.database.schema';
import type { DateRange } from 'src/dateRange/dtos/dateRange.dto';

export type FindScorePerCoalitionByDateInput = DateRange;

export type FindScorePerCoalitionByDateOutput = {
coalition: coalition;
scores: {
date: Date;
value: number;
}[];
};
22 changes: 22 additions & 0 deletions app/src/dailyCoalitionScore/dailyCoalitionScore.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { CoalitionModule } from 'src/api/coalition/coalition.module';
import { DailyCoalitionScoreService } from './dailyCoalitionScore.service';
import { DailyCoalitionScoreDaoImpl } from './db/dailyCoalitionScore.database.dao';
import {
dailyCoalitionScoreSchema,
mv_daily_score_values,
} from './db/dailyCoalitionScore.database.schema';

@Module({
imports: [
MongooseModule.forFeature([
{ name: mv_daily_score_values.name, schema: dailyCoalitionScoreSchema },
]),
CoalitionModule,
],
providers: [DailyCoalitionScoreService, DailyCoalitionScoreDaoImpl],
exports: [DailyCoalitionScoreService],
})
// eslint-disable-next-line @typescript-eslint/no-extraneous-class
export class DailyCoalitionScoreModule {}
29 changes: 29 additions & 0 deletions app/src/dailyCoalitionScore/dailyCoalitionScore.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Injectable } from '@nestjs/common';
import { DailyCoalitionScoreDaoImpl } from './db/dailyCoalitionScore.database.dao';
import { ScoreRecordPerCoalition } from 'src/page/home/coalition/models/home.coalition.model';
import type { DateRange } from 'src/dateRange/dtos/dateRange.dto';
import { CoalitionService } from 'src/api/coalition/coalition.service';

@Injectable()
export class DailyCoalitionScoreService {
constructor(
private readonly dailyCoalitionScoreDao: DailyCoalitionScoreDaoImpl,
private readonly coalitionService: CoalitionService,
) {}

async scoreRecordsPerCoalitions({
start,
end,
}: DateRange): Promise<ScoreRecordPerCoalition[]> {
const scoresPerCoalition =
await this.dailyCoalitionScoreDao.findScoresPerCoalitionByDate({
start,
end,
});

return scoresPerCoalition.map(({ coalition, scores }) => ({
coalition: this.coalitionService.daoToDto(coalition),
records: scores.map(({ date, value }) => ({ at: date, value })),
}));
}
}
91 changes: 91 additions & 0 deletions app/src/dailyCoalitionScore/db/dailyCoalitionScore.database.dao.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { Inject, Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import type { Model } from 'mongoose';
import { mv_daily_score_values } from './dailyCoalitionScore.database.schema';
import type {
FindScorePerCoalitionByDateInput,
FindScorePerCoalitionByDateOutput,
} from '../dailyCoalitionScore.dto';
import { RUNTIME_CONFIG } from 'src/config/runtime';
import type { ConfigType } from '@nestjs/config';
import { lookupCoalition } from 'src/api/coalition/db/coalition.database.aggregate';
import { coalition } from 'src/api/coalition/db/coalition.database.schema';

export type DailyCoalitionScoreDao = {
findScoresPerCoalitionByDate: (
args: FindScorePerCoalitionByDateInput,
) => Promise<FindScorePerCoalitionByDateOutput[]>;
};

@Injectable()
export class DailyCoalitionScoreDaoImpl implements DailyCoalitionScoreDao {
constructor(
@InjectModel(mv_daily_score_values.name)
private readonly dailyCoalitionScore: Model<mv_daily_score_values>,
@Inject(RUNTIME_CONFIG.KEY)
private readonly runtimeConfig: ConfigType<typeof RUNTIME_CONFIG>,
) {}

async findScoresPerCoalitionByDate({
start,
end,
}: FindScorePerCoalitionByDateInput): Promise<
FindScorePerCoalitionByDateOutput[]
> {
return await this.dailyCoalitionScore
.aggregate<FindScorePerCoalitionByDateOutput>()
.match({
date: {
$gte: start,
$lt: end,
},
})
.group({
_id: {
date: {
$dateFromParts: {
year: {
$year: {
date: '$date',
timezone: this.runtimeConfig.TIMEZONE,
},
},
month: {
$month: {
date: '$date',
timezone: this.runtimeConfig.TIMEZONE,
},
},
timezone: this.runtimeConfig.TIMEZONE,
},
},
coalitionId: '$coalitionId',
},
value: {
$sum: '$value',
},
})
.sort({
'_id.date': 1,
'_id.coalitionId': 1,
})
.group({
_id: '$_id.coalitionId',
scores: {
$push: {
date: '$_id.date',
value: '$value',
},
},
})
.append(lookupCoalition('_id', 'id'))
.sort({ _id: 1 })
.project({
_id: 0,
coalition: {
$first: `$${coalition.name}s`,
},
scores: 1,
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import type { HydratedDocument } from 'mongoose';

export type DailyCoalitionScoreDocument =
HydratedDocument<mv_daily_score_values>;

@Schema({ collection: 'mv_daily_score_values' })
export class mv_daily_score_values {
@Prop({ required: true })
date: Date;

@Prop({ required: true })
coalitionId: number;

@Prop({ required: true })
value: number;
}

export const dailyCoalitionScoreSchema = SchemaFactory.createForClass(
mv_daily_score_values,
);
25 changes: 1 addition & 24 deletions app/src/lambda/lambda.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,14 @@ import { ScaleTeamService } from 'src/api/scaleTeam/scaleTeam.service';
import { scoreDateRangeFilter } from 'src/api/score/db/score.database.aggregate';
import {
SCORE_RANKING,
SCORE_RECORDS,
TOTAL_SCORES_BY_COALITION,
WIN_COUNT_PER_COALITION,
} from 'src/api/score/score.cache.service';
import { ScoreService } from 'src/api/score/score.service';
import { CacheUtilRankingService } from 'src/cache/cache.util.ranking.service';
import { CacheUtilService } from 'src/cache/cache.util.service';
import { DateRangeService } from 'src/dateRange/dateRange.service';
import { DateTemplate, type DateRange } from 'src/dateRange/dtos/dateRange.dto';
import { DateWrapper } from 'src/dateWrapper/dateWrapper';
import { DateTemplate } from 'src/dateRange/dtos/dateRange.dto';

export const LAMBDA_UPDATED_AT = 'lambdaUpdatedAt';

Expand Down Expand Up @@ -177,7 +175,6 @@ export class LambdaService {
);

await this.updateTotalScoresPerCoalition(updatedAt);
await this.updateScoreRecords(updatedAt);
await this.updateWinCountPerCoalition(updatedAt);

const currMonthExp = await this.experienceUserService.increamentRanking(
Expand Down Expand Up @@ -284,26 +281,6 @@ export class LambdaService {
);
}

private async updateScoreRecords(updatedAt: Date): Promise<void> {
const nextMonth = DateWrapper.currMonth().moveMonth(1);
const lastYear = nextMonth.moveYear(-1);

const dateRange: DateRange = {
start: lastYear.toDate(),
end: nextMonth.toDate(),
};

const scoreRecords = await this.scoreService.scoreRecordsPerCoalition({
filter: scoreDateRangeFilter(dateRange),
});

await this.cacheUtilService.setWithDate(
SCORE_RECORDS,
scoreRecords,
updatedAt,
);
}

private async updateWinCountPerCoalition(updatedAt: Date): Promise<void> {
const winCountPerCoalition = await this.scoreService.winCountPerCoalition();

Expand Down
9 changes: 8 additions & 1 deletion app/src/page/home/coalition/home.coalition.module.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
import { Module } from '@nestjs/common';
import { ScoreModule } from 'src/api/score/score.module';
import { CacheUtilModule } from 'src/cache/cache.util.module';
import { DailyCoalitionScoreModule } from 'src/dailyCoalitionScore/dailyCoalitionScore.module';
import { DateRangeModule } from 'src/dateRange/dateRange.module';
import { HomeCoalitionResolver } from './home.coalition.resolver';
import { HomeCoalitionService } from './home.coalition.service';

@Module({
imports: [ScoreModule, DateRangeModule],
imports: [
ScoreModule,
DateRangeModule,
DailyCoalitionScoreModule,
CacheUtilModule,
],
providers: [HomeCoalitionResolver, HomeCoalitionService],
})
// eslint-disable-next-line
Expand Down
39 changes: 36 additions & 3 deletions app/src/page/home/coalition/home.coalition.resolver.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import { UseFilters, UseGuards } from '@nestjs/common';
import { Args, Query, ResolveField, Resolver } from '@nestjs/graphql';
import { StatAuthGuard } from 'src/auth/statAuthGuard';
import { CacheUtilService } from 'src/cache/cache.util.service';
import { DailyCoalitionScoreService } from 'src/dailyCoalitionScore/dailyCoalitionScore.service';
import { DateTemplateArgs } from 'src/dateRange/dtos/dateRange.dto';
import { DateWrapper } from 'src/dateWrapper/dateWrapper';
import { HttpExceptionFilter } from 'src/http-exception.filter';
import { HomeCoalitionService } from './home.coalition.service';
import {
GetScoreRecordsPerCoalitionArgs,
HomeCoalition,
IntPerCoalition,
IntPerCoalitionDateRanged,
Expand All @@ -15,7 +19,11 @@ import {
@UseGuards(StatAuthGuard)
@Resolver((_of: unknown) => HomeCoalition)
export class HomeCoalitionResolver {
constructor(private readonly homeCoalitionService: HomeCoalitionService) {}
constructor(
private readonly homeCoalitionService: HomeCoalitionService,
private readonly dailyCoalitionScoreService: DailyCoalitionScoreService,
private readonly cacheUtilService: CacheUtilService,
) {}

@Query((_of) => HomeCoalition)
async getHomeCoalition() {
Expand All @@ -28,8 +36,33 @@ export class HomeCoalitionResolver {
}

@ResolveField((_returns) => [ScoreRecordPerCoalition])
async scoreRecordsPerCoalition(): Promise<ScoreRecordPerCoalition[]> {
return await this.homeCoalitionService.scoreRecordsPerCoalition();
async scoreRecordsPerCoalition(
@Args() { last }: GetScoreRecordsPerCoalitionArgs,
): Promise<ScoreRecordPerCoalition[]> {
const nextMonth = DateWrapper.nextMonth().toDate();
const start = DateWrapper.currMonth()
.moveMonth(1 - last)
.toDate();

const cacheKey = `homeCoalitionScoreRecordsPerCoalition:${start.getTime()}:${nextMonth.getTime()}`;

const cached = await this.cacheUtilService.get<ScoreRecordPerCoalition[]>(
cacheKey,
);

if (cached) {
return cached;
}

const result =
await this.dailyCoalitionScoreService.scoreRecordsPerCoalitions({
start,
end: nextMonth,
});

await this.cacheUtilService.set(cacheKey, result, DateWrapper.MIN);

return result;
}

@ResolveField((_returns) => IntPerCoalitionDateRanged)
Expand Down
50 changes: 1 addition & 49 deletions app/src/page/home/coalition/home.coalition.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,11 @@ import { ScoreCacheService } from 'src/api/score/score.cache.service';
import { ScoreService } from 'src/api/score/score.service';
import { CacheOnReturn } from 'src/cache/decrators/onReturn/cache.decorator.onReturn.symbol';
import { assertExist } from 'src/common/assertExist';
import type { IntRecord } from 'src/common/models/common.valueRecord.model';
import { DateRangeService } from 'src/dateRange/dateRange.service';
import { DateRange, DateTemplate } from 'src/dateRange/dtos/dateRange.dto';
import { DateWrapper } from 'src/dateWrapper/dateWrapper';
import { DateTemplate } from 'src/dateRange/dtos/dateRange.dto';
import type {
IntPerCoalition,
IntPerCoalitionDateRanged,
ScoreRecordPerCoalition,
} from './models/home.coalition.model';

@Injectable()
Expand All @@ -29,51 +26,6 @@ export class HomeCoalitionService {
return cachedTotalScores ?? (await this.scoreService.scoresPerCoalition());
}

async scoreRecordsPerCoalition(): Promise<ScoreRecordPerCoalition[]> {
const cachedScoreRecords = await this.scoreCacheService.getScoreRecords();

const nextMonth = new DateWrapper().startOfMonth().moveMonth(1);
const lastYear = nextMonth.moveYear(-1);

const dateRange: DateRange = {
start: lastYear.toDate(),
end: nextMonth.toDate(),
};

const scoreRecords =
cachedScoreRecords ??
(await this.scoreService.scoreRecordsPerCoalition({
filter: scoreDateRangeFilter(dateRange),
}));

const dates: Date[] = [];

for (
let currMonth = lastYear;
currMonth.toDate() < nextMonth.toDate();
currMonth = currMonth.moveMonth(1)
) {
dates.push(currMonth.toDate());
}

return scoreRecords.map(({ coalition, records }) => {
const zeroFilledRecords = dates.reduce((newRecords, currDate) => {
const currValue = records.find(
({ at }) => currDate.getTime() === at.getTime(),
)?.value;

newRecords.push({ at: currDate, value: currValue ?? 0 });

return newRecords;
}, new Array<IntRecord>());

return {
coalition,
records: zeroFilledRecords,
};
});
}

@CacheOnReturn()
async tigCountPerCoalitionByDateTemplate(
dateTemplate: DateTemplate,
Expand Down
Loading

0 comments on commit f01f2f9

Please sign in to comment.