Skip to content

Commit 46ec2ba

Browse files
authored
Merge pull request #34 from poojakarma/search_event_api
PS-1767 -> Refactor API to get by events
2 parents 5cdb50a + b145bc4 commit 46ec2ba

File tree

4 files changed

+144
-31
lines changed

4 files changed

+144
-31
lines changed

src/common/pipes/event-validation.pipe.ts

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
import { PipeTransform, Injectable, BadRequestException } from '@nestjs/common';
1+
import {
2+
PipeTransform,
3+
Injectable,
4+
BadRequestException,
5+
ArgumentMetadata,
6+
} from '@nestjs/common';
27
import { CreateEventDto } from 'src/modules/event/dto/create-event.dto';
38
import { ERROR_MESSAGES } from '../utils/constants.util';
49
import {
@@ -180,6 +185,72 @@ export class AttendeesValidationPipe implements PipeTransform {
180185
}
181186
}
182187

188+
@Injectable()
189+
export class SearchDateValidationPipe implements PipeTransform {
190+
transform(value: any, metadata: ArgumentMetadata) {
191+
const { date, startDate, endDate } = value.filters || {};
192+
193+
// Check if both startDate and endDate are passed with date
194+
if (date && (startDate || endDate)) {
195+
throw new BadRequestException(
196+
'Only one of date, startDate, or endDate should be provided.',
197+
);
198+
}
199+
200+
// Check if after and before are provided with date
201+
if (date && (!date.after || !date.before)) {
202+
throw new BadRequestException(
203+
'Both "after" and "before" fields are required when date is provided.',
204+
);
205+
}
206+
207+
if (
208+
startDate &&
209+
(!startDate.after || !startDate.before) &&
210+
endDate === undefined
211+
) {
212+
throw new BadRequestException(
213+
'Both "after" and "before" fields are required when startDate is provided.',
214+
);
215+
}
216+
217+
if (
218+
endDate &&
219+
(!endDate.after || !endDate.before) &&
220+
startDate === undefined
221+
) {
222+
throw new BadRequestException(
223+
'Both "after" and "before" fields are required when endDate is provided.',
224+
);
225+
}
226+
227+
if (startDate && endDate && (!startDate.after || !endDate.before)) {
228+
throw new BadRequestException(
229+
'if StartDate and EndDate Provided then "after" fields is required in startDate and "before fields is required in endDate',
230+
);
231+
}
232+
233+
if (
234+
(date && new Date(date.after) > new Date(date.before)) ||
235+
(startDate &&
236+
!endDate &&
237+
new Date(startDate.after) > new Date(startDate.before)) ||
238+
(endDate &&
239+
!startDate &&
240+
new Date(endDate.after) > new Date(endDate.before)) ||
241+
(startDate &&
242+
endDate &&
243+
new Date(startDate.after) > new Date(endDate.before))
244+
) {
245+
throw new BadRequestException(
246+
'"after" should be less than and equal to "before" fields ',
247+
);
248+
}
249+
250+
return value;
251+
}
252+
}
253+
183254
@ValidatorConstraint({ name: 'endsWithZ', async: false })
184255
export class EndsWithZConstraint implements ValidatorConstraintInterface {
185256
validate(text: string, args: ValidationArguments) {

src/modules/event/dto/search-event.dto.ts

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,38 +2,50 @@ import { ApiProperty } from '@nestjs/swagger';
22
import { Type } from 'class-transformer';
33
import {
44
IsOptional,
5-
IsDateString,
65
IsEnum,
76
IsString,
87
ValidateNested,
98
IsUUID,
9+
IsDateString,
1010
} from 'class-validator';
1111

12-
export class FilterDto {
12+
// DateRangeDto for specifying date range filters
13+
class DateRangeDto {
1314
@ApiProperty({
14-
example: '2024-07-24',
15-
description: 'specific date in YYYY-MM-DD format',
15+
example: '2024-07-24T00:00:00Z',
16+
description:
17+
'ISO 8601 format date-time representing the start of the range',
1618
})
1719
@IsOptional()
1820
@IsDateString()
19-
date: string;
21+
after?: string;
2022

2123
@ApiProperty({
22-
example: '2024-07-24',
23-
description: 'Start date in YYYY-MM-DD format',
24+
example: '2024-07-27T23:59:59Z',
25+
description: 'ISO 8601 format date-time representing the end of the range',
2426
})
2527
@IsOptional()
2628
@IsDateString()
27-
startDate: string;
29+
before?: string;
30+
}
31+
export class FilterDto {
32+
@ApiProperty({ type: DateRangeDto, description: 'Start date range filter' })
33+
@IsOptional()
34+
@ValidateNested()
35+
@Type(() => DateRangeDto)
36+
date?: DateRangeDto;
2837

29-
@ApiProperty({
30-
example: '2024-07-27',
31-
description: 'End date in YYYY-MM-DD format',
32-
})
38+
@ApiProperty({ type: DateRangeDto, description: 'Start date range filter' })
3339
@IsOptional()
34-
@IsDateString()
35-
endDate: string;
40+
@ValidateNested()
41+
@Type(() => DateRangeDto)
42+
startDate?: DateRangeDto;
3643

44+
@ApiProperty({ type: DateRangeDto, description: 'End date range filter' })
45+
@IsOptional()
46+
@ValidateNested()
47+
@Type(() => DateRangeDto)
48+
endDate?: DateRangeDto;
3749
@ApiProperty({
3850
example: ['live', 'draft', 'inActive', 'archived'],
3951
description: 'Array of status values: live, draft, inActive,archived',
@@ -61,10 +73,21 @@ export class FilterDto {
6173
@IsString()
6274
title?: string;
6375

64-
@ApiProperty({ example: 'CohortId', description: 'Cohort' })
76+
@ApiProperty({
77+
example: '76a5e84a-4336-47c8-986f-98f7ad190e0b',
78+
description: 'Cohort',
79+
})
6580
@IsOptional()
6681
@IsUUID('4')
6782
cohortId?: string;
83+
84+
@ApiProperty({
85+
example: 'eff008a8-2573-466d-b877-fddf6a4fc13e',
86+
description: 'CreatedBy',
87+
})
88+
@IsOptional()
89+
@IsUUID('4')
90+
createdBy?: string;
6891
}
6992

7093
export class SearchFilterDto {

src/modules/event/event.controller.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import {
3232
RegistrationDateValidationPipe,
3333
AttendeesValidationPipe,
3434
RecurringEndDateValidationPipe,
35+
SearchDateValidationPipe,
3536
} from 'src/common/pipes/event-validation.pipe';
3637
import { ConfigService } from '@nestjs/config';
3738
import { AllExceptionsFilter } from 'src/common/filters/exception.filter';
@@ -79,7 +80,10 @@ export class EventController {
7980
@ApiInternalServerErrorResponse({
8081
description: ERROR_MESSAGES.INTERNAL_SERVER_ERROR,
8182
})
82-
@UsePipes(new ValidationPipe({ transform: true }))
83+
@UsePipes(
84+
new ValidationPipe({ transform: true }),
85+
new SearchDateValidationPipe(),
86+
)
8387
@ApiOkResponse({
8488
description: 'Searched',
8589
status: 200,

src/modules/event/event.service.ts

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ export class EventService {
106106

107107
let finalquery = `SELECT
108108
er."eventDetailId" AS "eventRepetition_eventDetailId",
109+
er."createdBy" AS "eventRepetition_createdBy",
109110
er.*,
110111
e."eventId" AS "event_eventId",
111112
e."eventDetailId" AS "event_eventDetailId",
@@ -170,9 +171,11 @@ export class EventService {
170171

171172
// Handle specific date records
172173
if (filters?.date) {
173-
const startDate = filters?.date;
174-
const startDateTime = `${startDate} 00:00:00`;
175-
const endDateTime = `${startDate} 23:59:59`;
174+
// const startDate = filters?.date;
175+
// const startDateTime = `${startDate} 00:00:00`;
176+
// const endDateTime = `${startDate} 23:59:59`;
177+
const startDateTime = filters?.date.after; // min date
178+
const endDateTime = filters?.date.before; // max date ---> seraching on the basis of max date
176179
whereClauses.push(
177180
`(er."startDateTime" <= '${endDateTime}'::timestamp AT TIME ZONE 'UTC' AND er."endDateTime" >= '${startDateTime}'::timestamp AT TIME ZONE 'UTC')`,
178181
);
@@ -181,26 +184,34 @@ export class EventService {
181184
// Handle startDate
182185
if (filters?.startDate && filters.endDate === undefined) {
183186
const startDate = filters?.startDate;
184-
const startDateTime = `${startDate} 00:00:00`;
185-
const endDateTime = `${startDate} 23:59:59`;
187+
// const startDateTime = `${startDate} 00:00:00`;
188+
// const endDateTime = `${startDate} 23:59:59`;
189+
const startDateTime = filters.startDate.after;
190+
const endDateTime = filters.startDate.before;
191+
186192
whereClauses.push(
187193
`(er."startDateTime" <= '${endDateTime}' ::timestamp AT TIME ZONE 'UTC' AND er."startDateTime" >= '${startDateTime}' ::timestamp AT TIME ZONE 'UTC')`,
188194
);
189195
}
190196

191197
if (filters?.startDate && filters.endDate) {
192198
const startDate = filters?.startDate;
193-
const startDateTime = `${startDate} 00:00:00`;
194-
const endDateTime = `${filters?.endDate} 23:59:59`;
199+
// const startDateTime = `${startDate} 00:00:00`;
200+
// const endDateTime = `${filters?.endDate} 23:59:59`;
201+
const startDateTime = filters.startDate.after; // 21 -> startDate
202+
const endDateTime = filters.endDate.before;
203+
195204
whereClauses.push(
196205
`(er."startDateTime" <= '${endDateTime}' ::timestamp AT TIME ZONE 'UTC' AND er."endDateTime" >= '${startDateTime}' ::timestamp AT TIME ZONE 'UTC')`,
197206
);
198207
}
199208

200209
if (filters.endDate && filters.startDate === undefined) {
201-
const endDate = filters?.endDate;
202-
const startDateTime = `${endDate} 00:00:00`;
203-
const endDateTime = `${endDate} 23:59:59`;
210+
// const endDate = filters?.endDate;
211+
// const startDateTime = `${endDate} 00:00:00`;
212+
// const endDateTime = `${endDate} 23:59:59`;
213+
const startDateTime = filters.endDate.after;
214+
const endDateTime = filters.endDate.before;
204215
whereClauses.push(
205216
`(er."endDateTime" <= '${endDateTime}' ::timestamp AT TIME ZONE 'UTC' AND er."endDateTime" >= '${startDateTime}' ::timestamp AT TIME ZONE 'UTC')`,
206217
);
@@ -220,21 +231,25 @@ export class EventService {
220231
}
221232

222233
// Handle status filter
223-
if (filters.status && filters.status.length > 0) {
234+
if (filters?.status && filters?.status.length > 0) {
224235
const statusConditions = filters.status
225-
.map((status) => `"status" = '${status}'`)
236+
.map((status) => `ed."status" = '${status}'`)
226237
.join(' OR ');
227238
whereClauses.push(`(${statusConditions})`);
228239
} else {
229240
// Add default status condition if no status is passed in the filter
230-
whereClauses.push(`"status" = 'live'`);
241+
whereClauses.push(`ed."status" = 'live'`);
231242
}
232243

233244
// Handle cohortId filter
234-
if (filters.cohortId) {
245+
if (filters?.cohortId) {
235246
whereClauses.push(`ed."metadata"->>'cohortId'='${filters.cohortId}'`);
236247
}
237248

249+
if (filters?.createdBy) {
250+
whereClauses.push(`er."createdBy" = '${filters.createdBy}'`);
251+
}
252+
238253
// Construct final query
239254
if (whereClauses.length > 0) {
240255
finalquery += ` WHERE ${whereClauses.join(' AND ')}`;

0 commit comments

Comments
 (0)