Skip to content

Commit

Permalink
feat: date ranges from group filter (#238)
Browse files Browse the repository at this point in the history
  • Loading branch information
y0000ga committed Jun 19, 2024
1 parent c0a4371 commit ff13755
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 53 deletions.
69 changes: 57 additions & 12 deletions src/dto/group/groupFilterDto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,26 @@ import {
} from '../../types/group.type';
import { SortOrder } from '../../types/common.type';

type TDateRange = {
$and: {
time: {
$gte?: Date;
$lte?: Date;
};
}[];
};

export class GroupFilterDto {
private readonly _title?: string;
private readonly _movieTitle?: string[];
private readonly _theater?: string[];
private readonly _participantCount?: number;
private readonly _status: GroupStatus;
private readonly _haveTicket?: boolean;
private readonly _startAt?: Date;
private readonly _endAt?: Date;
private readonly _page: number;
private readonly _limit: number;
private readonly _sort: Record<string, 1 | -1>;
private readonly _dateRanges: TDateRange[] = [];

get filter() {
const titleRegex = this._title ? new RegExp(this._title) : undefined;
Expand All @@ -30,12 +38,7 @@ export class GroupFilterDto {
amount: { $eq: this._participantCount },
}),
...(this._haveTicket && { haveTicket: this._haveTicket }),
...((this._startAt || this._endAt) && {
time: {
...(this._endAt && { $lte: this._endAt }),
...(this._startAt && { $gte: this._startAt }),
},
}),
$or: this._dateRanges,
};
}

Expand All @@ -58,6 +61,10 @@ export class GroupFilterDto {
};
}

get dateRanges() {
return this._dateRanges;
}

constructor(req: IGetGroupsReq) {
const {
title,
Expand All @@ -66,8 +73,10 @@ export class GroupFilterDto {
participantCount,
status,
haveTicket,
startAt,
endAt,
endTime,
startTime,
startDate,
endDate,
page,
limit,
sortField,
Expand All @@ -87,7 +96,43 @@ export class GroupFilterDto {
this._theater = theater ? theater.split(',') : undefined;
this._haveTicket =
haveTicket === undefined ? undefined : haveTicket === 'true';
this._startAt = startAt ? moment(startAt).toDate() : undefined;
this._endAt = endAt ? moment(endAt).toDate() : undefined;

// date range

const dateFrom = moment(startDate, 'YYYY/MM/DD').startOf('day');
const dateTo = moment(endDate, 'YYYY/MM/DD').endOf('day');
const timeFrom = moment(startTime, 'HH:mm');
const timeTo = moment(endTime, 'HH:mm');

const dateRanges: TDateRange[] = [];
for (
let date = dateFrom.clone();
date.isSameOrBefore(dateTo);
date.add(1, 'days')
) {
const start = {
hour: timeFrom.hours(),
minute: timeFrom.minutes(),
second: 0,
millisecond: 0,
};
const end = {
hour: timeTo.hours(),
minute: timeTo.minutes(),
second: 0,
millisecond: 0,
};

const dateRange = {
$and: [
{ time: { $gte: new Date(date.clone().set(start).toISOString()) } },
{ time: { $lte: new Date(date.clone().set(end).toISOString()) } },
],
};

dateRanges.push(dateRange);
}

this._dateRanges = dateRanges;
}
}
34 changes: 22 additions & 12 deletions src/routes/groupRoute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -258,23 +258,33 @@ export class GroupRoute extends BaseRoute {
$ref: "#/definitions/CustomGetGroupCountQuery"
}
}
#swagger.parameters['startAt'] = {
#swagger.parameters['startDate'] = {
in: 'query',
required: false,
description: '開始活動時間-起',
required: true,
description: '開始活動日期-起 (一定要遵循以下格式)',
type: 'string',
schema:{
$ref: "#/definitions/CustomTimeAtFromQuery"
}
example: '2024/01/12'
}
#swagger.parameters['endAt'] = {
#swagger.parameters['endDate'] = {
in: 'query',
required: false,
description: '開始活動時間-迄',
required: true,
description: '開始活動日期-迄 (一定要遵循以下格式)',
type: 'string',
schema:{
$ref: "#/definitions/CustomTimeAtToQuery"
}
example:'2024/07/12'
}
#swagger.parameters['startTime'] = {
in: 'query',
required: true,
description: '開始活動時間-起 (一定要遵循以下格式)',
type: 'string',
example: '01:00'
}
#swagger.parameters['endTime'] = {
in: 'query',
required: true,
description: '開始活動時間-迄 (一定要遵循以下格式)',
type: 'string',
example: '23:00'
}
#swagger.parameters['sortField'] = {
in: 'query',
Expand Down
9 changes: 9 additions & 0 deletions src/service/groupService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,15 @@ export class GroupService {
}
}
public async findGroups(groupFilterDto: GroupFilterDto) {
const { dateRanges } = groupFilterDto;

if (dateRanges.length === 0) {
throwError(
CustomResponseType.INVALID_GROUP_FILTER_MESSAGE + '時間區間有誤',
CustomResponseType.INVALID_GROUP_FILTER,
);
}

return await this.groupRepository.findGroups(groupFilterDto);
}

Expand Down
6 changes: 4 additions & 2 deletions src/types/group.type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,10 @@ export interface IGetGroupsReq extends IUserReq {
participantCount?: string;
status?: GroupStatus;
haveTicket?: string;
startAt?: string;
endAt?: string;
startTime?: string;
endTime?: string;
startDate?: string;
endDate?: string;
};
}

Expand Down
40 changes: 14 additions & 26 deletions src/validator/group/getGroup.pipe.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,12 @@
import { PipeBase } from '../pipe.base';
import { query } from 'express-validator';
import { CustomResponseType } from '../../types/customResponseType';
import {
GroupSortField,
GroupStatus,
IGetGroupsReq,
} from '../../types/group.type';
import { OptionType, TCustomValidator } from '../index.type';
import { GroupSortField, GroupStatus } from '../../types/group.type';
import { OptionType } from '../index.type';
import { SortOrder } from '../../types/common.type';
import { booleanStrings, nullableOption } from '../../utils/constants';

export class GetGroupsPipe extends PipeBase {
private validateStartAt: TCustomValidator = (value, { req }) => {
const { endAt } = (req as IGetGroupsReq).query;
return this.validatePeriod(value, endAt, (a, b) => a.isBefore(b));
};

private validateEndAt: TCustomValidator = (value, { req }) => {
const { startAt } = (req as IGetGroupsReq).query;
return this.validatePeriod(value, startAt, (a, b) => a.isAfter(b));
};

public transform = () => [
this.limitValidation(
query('limit'),
Expand All @@ -46,20 +32,22 @@ export class GetGroupsPipe extends PipeBase {
.withMessage(
CustomResponseType.INVALID_GROUP_FILTER_MESSAGE + 'participantCount',
),
query('startAt')
.optional(nullableOption)
.custom(this.validateDate)
.custom(this.validateStartAt)
query('startTime')
.exists()
.withMessage(
CustomResponseType.INVALID_GROUP_FILTER_MESSAGE + 'startAtTo',
CustomResponseType.INVALID_GROUP_FILTER_MESSAGE + 'startTime',
),
query('endAt')
.optional(nullableOption)
.custom(this.validateDate)
.custom(this.validateEndAt)
query('endTime')
.exists()
.withMessage(CustomResponseType.INVALID_GROUP_FILTER_MESSAGE + 'endTime'),
query('startDate')
.exists()
.withMessage(
CustomResponseType.INVALID_GROUP_FILTER_MESSAGE + 'startAtTo',
CustomResponseType.INVALID_GROUP_FILTER_MESSAGE + 'startDate',
),
query('endDate')
.exists()
.withMessage(CustomResponseType.INVALID_GROUP_FILTER_MESSAGE + 'endDate'),
query('sortField')
.optional(nullableOption)
.custom(this.validateOption(OptionType.item, GroupSortField))
Expand Down
5 changes: 4 additions & 1 deletion src/validator/pipe.base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,10 @@ export abstract class PipeBase {
this.validateDate(fromValue);

return isNeedCheckPeriod
? compareFn(moment(value), moment(fromValue))
? compareFn(
moment(value, moment.ISO_8601),
moment(fromValue, moment.ISO_8601),
)
: true;
};

Expand Down

0 comments on commit ff13755

Please sign in to comment.