Skip to content

Commit

Permalink
feat: ✨ personal general 에 dailyActivities 추가
Browse files Browse the repository at this point in the history
- 기존과는 다른 구조로 제작하였습니다. 앞으로 db 정리하고 이런 방식으로 고치면 어떨까 하는 생각입니다.
- daily_logtimes collection 을 추가했습니다.
- scale_teams, events_users 로 인해 성능 저하가 심각한 수준이면 별도 collection 으로 분리할 예정입니다. 현재 자체 테스트에선 dev 기준 100 ~ 300ms 정도 나옵니다.

- close #388
- close #389
  • Loading branch information
jpham005 committed Nov 7, 2023
1 parent 5910567 commit 88e3071
Show file tree
Hide file tree
Showing 17 changed files with 470 additions and 2 deletions.
18 changes: 18 additions & 0 deletions app/src/api/dailyLogtime/db/dailyLogtime.database.schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import type { HydratedDocument } from 'mongoose';

export type DailyLogtimeDocument = HydratedDocument<daily_logtimes>;

@Schema({ collection: 'daily_logtimes' })
export class daily_logtimes {
@Prop({ required: true })
userId: number;

@Prop({ required: true })
date: Date;

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

export const dailyLogtimeSchema = SchemaFactory.createForClass(daily_logtimes);
11 changes: 11 additions & 0 deletions app/src/api/event/db/event.database.aggregate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import {
lookupStage,
type CollectionLookup,
} from 'src/database/mongoose/database.mongoose.aggregation';
import { events } from './event.database.schema';

export const lookupEvents: CollectionLookup = (
localField,
foreignField,
pipeline,
) => lookupStage(events.name, localField, foreignField, pipeline);
27 changes: 27 additions & 0 deletions app/src/api/event/db/event.database.schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import type { HydratedDocument } from 'mongoose';

export type eventDocument = HydratedDocument<events>;

@Schema({ collection: 'events' })
export class events {
@Prop({ required: true })
id: number;

@Prop({ required: true })
beginAt: Date;

@Prop({ required: true })
endAt: Date;

@Prop({ required: true })
name: string;

@Prop({ required: true })
description: string;

@Prop({ required: true })
location: string;
}

export const eventSchema = SchemaFactory.createForClass(events);
11 changes: 11 additions & 0 deletions app/src/api/eventsUser/db/eventsUser.database.aggregate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import {
lookupStage,
type CollectionLookup,
} from 'src/database/mongoose/database.mongoose.aggregation';
import { events_users } from './eventsUser.database.schema';

export const lookupEventsUsers: CollectionLookup = (
localField,
foreignField,
pipeline,
) => lookupStage(events_users.name, localField, foreignField, pipeline);
13 changes: 13 additions & 0 deletions app/src/api/eventsUser/db/eventsUser.database.schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Prop, Schema } from '@nestjs/mongoose';

@Schema({ collection: 'events_users' })
export class events_users {
@Prop({ required: true })
id: number;

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

@Prop({ required: true })
userId: number;
}
2 changes: 1 addition & 1 deletion app/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ import { TeamInfoModule } from './page/teamInfo/teamInfo.module';
CacheModule.register({
isGlobal: true,
store: new ShallowStore({
max: 100000,
max: 10000000,
ttl: DateWrapper.MIN * 3,
}),
}),
Expand Down
19 changes: 18 additions & 1 deletion app/src/dateRange/dateRange.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Injectable } from '@nestjs/common';
import { DateWrapper } from 'src/dateWrapper/dateWrapper';
import { DateRangeArgs, DateTemplate } from './dtos/dateRange.dto';
import { DateRange, DateRangeArgs, DateTemplate } from './dtos/dateRange.dto';
import type { IDateRangedType } from './models/dateRange.model';

@Injectable()
Expand Down Expand Up @@ -55,4 +55,21 @@ export class DateRangeService {
$lt: end,
};
}

getAbsoluteDateRangeByYear(year: number): DateRange {
const start = DateWrapper.createByYear(year).startOfYear().toDate();
const end = DateWrapper.createByYear(year)
.startOfYear()
.moveYear(1)
.toDate();

return { start, end };
}

getRelativeDateRange(): DateRange {
const start = new DateWrapper().startOfDate().moveDate(-364).toDate();
const end = new DateWrapper().startOfDate().moveDate(1).toDate();

return { start, end };
}
}
6 changes: 6 additions & 0 deletions app/src/dateWrapper/dateWrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,4 +111,10 @@ export class DateWrapper {
static currWeek = (): DateWrapper => new DateWrapper().startOfWeek();
static lastWeek = (): DateWrapper => DateWrapper.currWeek().moveWeek(-1);
static nextWeek = (): DateWrapper => DateWrapper.currWeek().moveWeek(1);

static currYear = (): DateWrapper => new DateWrapper().startOfYear();

static createByYear = (year: number): DateWrapper => {
return new DateWrapper(`${year - 1}-12-31T15:00:00.000Z`);
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { ArgsType, Field } from '@nestjs/graphql';
import { IsOptional, Max, Min } from 'class-validator';

@ArgsType()
export class GetPersonalGeneralDailyActivitiesArgs {
@IsOptional()
@Min(2000)
@Max(2100)
@Field({ nullable: true })
year?: number;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import type { Model } from 'mongoose';
import { daily_logtimes } from 'src/api/dailyLogtime/db/dailyLogtime.database.schema';
import { lookupEvents } from 'src/api/event/db/event.database.aggregate';
import { events } from 'src/api/event/db/event.database.schema';
import { events_users } from 'src/api/eventsUser/db/eventsUser.database.schema';
import { scale_team } from 'src/api/scaleTeam/db/scaleTeam.database.schema';
import {
DailyActivityType,
type DailyActivityRecordUnion,
type DailyDefaultRecord,
type DailyLogtimeRecord,
} from '../models/personal.general.dailyActivity.model';

export type DailyActivityDto = {
date: Date;
records: (typeof DailyActivityRecordUnion)[];
};

export type DailyActivityDao = {
findAllRecordByDate: (args: {
userId: number;
start: Date;
end: Date;
}) => Promise<(typeof DailyActivityRecordUnion)[]>;
};

@Injectable()
export class DailyActivityDaoImpl implements DailyActivityDao {
constructor(
@InjectModel(scale_team.name)
private readonly scaleTeamModel: Model<scale_team>,
) {}

async findAllRecordByDate({
userId,
start,
end,
}: {
userId: number;
start: Date;
end: Date;
}): Promise<((DailyLogtimeRecord & { date: Date }) | DailyDefaultRecord)[]> {
return await this.scaleTeamModel
.aggregate<(DailyLogtimeRecord & { date: Date }) | DailyDefaultRecord>()
.match({
$or: [{ 'corrector.id': userId }, { 'correcteds.id': userId }],
filledAt: {
$gte: start,
$lt: end,
},
})
.sort({ filledAt: 1 })
.project({
_id: 0,
id: 1,
at: '$filledAt',
type: {
$cond: {
if: { $eq: ['$corrector.id', userId] },
then: DailyActivityType.CORRECTOR,
else: DailyActivityType.CORRECTED,
},
},
})
.unionWith({
coll: daily_logtimes.name,
pipeline: [
{
$match: {
userId,
date: {
$gte: start,
$lt: end,
},
},
},
{
$project: {
_id: 0,
date: '$date',
type: { $literal: DailyActivityType.LOGTIME },
value: 1,
},
},
],
})
.unionWith({
coll: events_users.name,
pipeline: [
{
$match: {
userId,
},
},
lookupEvents('eventId', 'id', [
{
$match: {
date: {
$gte: start,
$lt: end,
},
},
},
]),
{
$project: {
_id: 0,
id: 1,
at: { $first: `$${events.name}.endAt` },
type: { $literal: DailyActivityType.EVENT },
},
},
{
$match: {
at: { $ne: null },
},
},
{
$sort: {
at: 1,
},
},
],
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import {
Field,
ObjectType,
createUnionType,
registerEnumType,
} from '@nestjs/graphql';

export enum DailyActivityType {
CORRECTOR,
CORRECTED,
EVENT,
LOGTIME,
}

registerEnumType(DailyActivityType, {
name: 'DailyAcitivtyType',
});

@ObjectType()
export class DailyLogtimeRecord {
@Field((_type) => DailyActivityType)
type: DailyActivityType.LOGTIME;

@Field()
value: number;
}

@ObjectType()
export class DailyDefaultRecord {
@Field((_type) => DailyActivityType)
type: Exclude<DailyActivityType, DailyActivityType.LOGTIME>;

@Field()
id: number;

@Field()
at: Date;
}

export const DailyActivityRecordUnion = createUnionType({
name: 'DailyActivityRecord',
types: () => [DailyLogtimeRecord, DailyDefaultRecord] as const,
resolveType: (value) => {
switch (value.type) {
case DailyActivityType.LOGTIME:
return DailyLogtimeRecord;
default:
return DailyDefaultRecord;
}
},
});

@ObjectType()
export class DailyActivity {
@Field()
date: Date;

@Field((_type) => [DailyActivityRecordUnion])
records: (typeof DailyActivityRecordUnion)[];
}
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 {
ScaleTeamSchema,
scale_team,
} from 'src/api/scaleTeam/db/scaleTeam.database.schema';
import { CacheUtilModule } from 'src/cache/cache.util.module';
import { DailyActivityDaoImpl } from './db/personal.general.dailyActivity.dao';
import { PersonalGeneralDailyActivityService } from './personal.general.dailyActivity.service';

@Module({
imports: [
MongooseModule.forFeature([
{ name: scale_team.name, schema: ScaleTeamSchema },
]),
CacheUtilModule,
],
providers: [PersonalGeneralDailyActivityService, DailyActivityDaoImpl],
exports: [PersonalGeneralDailyActivityService, MongooseModule],
})
// eslint-disable-next-line
export class PersonalGeneralDailyActivityModule {}
Loading

0 comments on commit 88e3071

Please sign in to comment.