Skip to content

Commit

Permalink
Merge pull request #34 from poojakarma/search_event_api
Browse files Browse the repository at this point in the history
PS-1767 -> Refactor API to get by events
  • Loading branch information
vaivk369 authored Aug 22, 2024
2 parents 5cdb50a + b145bc4 commit 46ec2ba
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 31 deletions.
73 changes: 72 additions & 1 deletion src/common/pipes/event-validation.pipe.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { PipeTransform, Injectable, BadRequestException } from '@nestjs/common';
import {
PipeTransform,
Injectable,
BadRequestException,
ArgumentMetadata,
} from '@nestjs/common';
import { CreateEventDto } from 'src/modules/event/dto/create-event.dto';
import { ERROR_MESSAGES } from '../utils/constants.util';
import {
Expand Down Expand Up @@ -180,6 +185,72 @@ export class AttendeesValidationPipe implements PipeTransform {
}
}

@Injectable()
export class SearchDateValidationPipe implements PipeTransform {
transform(value: any, metadata: ArgumentMetadata) {
const { date, startDate, endDate } = value.filters || {};

// Check if both startDate and endDate are passed with date
if (date && (startDate || endDate)) {
throw new BadRequestException(
'Only one of date, startDate, or endDate should be provided.',
);
}

// Check if after and before are provided with date
if (date && (!date.after || !date.before)) {
throw new BadRequestException(
'Both "after" and "before" fields are required when date is provided.',
);
}

if (
startDate &&
(!startDate.after || !startDate.before) &&
endDate === undefined
) {
throw new BadRequestException(
'Both "after" and "before" fields are required when startDate is provided.',
);
}

if (
endDate &&
(!endDate.after || !endDate.before) &&
startDate === undefined
) {
throw new BadRequestException(
'Both "after" and "before" fields are required when endDate is provided.',
);
}

if (startDate && endDate && (!startDate.after || !endDate.before)) {
throw new BadRequestException(
'if StartDate and EndDate Provided then "after" fields is required in startDate and "before fields is required in endDate',
);
}

if (
(date && new Date(date.after) > new Date(date.before)) ||
(startDate &&
!endDate &&
new Date(startDate.after) > new Date(startDate.before)) ||
(endDate &&
!startDate &&
new Date(endDate.after) > new Date(endDate.before)) ||
(startDate &&
endDate &&
new Date(startDate.after) > new Date(endDate.before))
) {
throw new BadRequestException(
'"after" should be less than and equal to "before" fields ',
);
}

return value;
}
}

@ValidatorConstraint({ name: 'endsWithZ', async: false })
export class EndsWithZConstraint implements ValidatorConstraintInterface {
validate(text: string, args: ValidationArguments) {
Expand Down
53 changes: 38 additions & 15 deletions src/modules/event/dto/search-event.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,50 @@ import { ApiProperty } from '@nestjs/swagger';
import { Type } from 'class-transformer';
import {
IsOptional,
IsDateString,
IsEnum,
IsString,
ValidateNested,
IsUUID,
IsDateString,
} from 'class-validator';

export class FilterDto {
// DateRangeDto for specifying date range filters
class DateRangeDto {
@ApiProperty({
example: '2024-07-24',
description: 'specific date in YYYY-MM-DD format',
example: '2024-07-24T00:00:00Z',
description:
'ISO 8601 format date-time representing the start of the range',
})
@IsOptional()
@IsDateString()
date: string;
after?: string;

@ApiProperty({
example: '2024-07-24',
description: 'Start date in YYYY-MM-DD format',
example: '2024-07-27T23:59:59Z',
description: 'ISO 8601 format date-time representing the end of the range',
})
@IsOptional()
@IsDateString()
startDate: string;
before?: string;
}
export class FilterDto {
@ApiProperty({ type: DateRangeDto, description: 'Start date range filter' })
@IsOptional()
@ValidateNested()
@Type(() => DateRangeDto)
date?: DateRangeDto;

@ApiProperty({
example: '2024-07-27',
description: 'End date in YYYY-MM-DD format',
})
@ApiProperty({ type: DateRangeDto, description: 'Start date range filter' })
@IsOptional()
@IsDateString()
endDate: string;
@ValidateNested()
@Type(() => DateRangeDto)
startDate?: DateRangeDto;

@ApiProperty({ type: DateRangeDto, description: 'End date range filter' })
@IsOptional()
@ValidateNested()
@Type(() => DateRangeDto)
endDate?: DateRangeDto;
@ApiProperty({
example: ['live', 'draft', 'inActive', 'archived'],
description: 'Array of status values: live, draft, inActive,archived',
Expand Down Expand Up @@ -61,10 +73,21 @@ export class FilterDto {
@IsString()
title?: string;

@ApiProperty({ example: 'CohortId', description: 'Cohort' })
@ApiProperty({
example: '76a5e84a-4336-47c8-986f-98f7ad190e0b',
description: 'Cohort',
})
@IsOptional()
@IsUUID('4')
cohortId?: string;

@ApiProperty({
example: 'eff008a8-2573-466d-b877-fddf6a4fc13e',
description: 'CreatedBy',
})
@IsOptional()
@IsUUID('4')
createdBy?: string;
}

export class SearchFilterDto {
Expand Down
6 changes: 5 additions & 1 deletion src/modules/event/event.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
RegistrationDateValidationPipe,
AttendeesValidationPipe,
RecurringEndDateValidationPipe,
SearchDateValidationPipe,
} from 'src/common/pipes/event-validation.pipe';
import { ConfigService } from '@nestjs/config';
import { AllExceptionsFilter } from 'src/common/filters/exception.filter';
Expand Down Expand Up @@ -79,7 +80,10 @@ export class EventController {
@ApiInternalServerErrorResponse({
description: ERROR_MESSAGES.INTERNAL_SERVER_ERROR,
})
@UsePipes(new ValidationPipe({ transform: true }))
@UsePipes(
new ValidationPipe({ transform: true }),
new SearchDateValidationPipe(),
)
@ApiOkResponse({
description: 'Searched',
status: 200,
Expand Down
43 changes: 29 additions & 14 deletions src/modules/event/event.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ export class EventService {

let finalquery = `SELECT
er."eventDetailId" AS "eventRepetition_eventDetailId",
er."createdBy" AS "eventRepetition_createdBy",
er.*,
e."eventId" AS "event_eventId",
e."eventDetailId" AS "event_eventDetailId",
Expand Down Expand Up @@ -170,9 +171,11 @@ export class EventService {

// Handle specific date records
if (filters?.date) {
const startDate = filters?.date;
const startDateTime = `${startDate} 00:00:00`;
const endDateTime = `${startDate} 23:59:59`;
// const startDate = filters?.date;
// const startDateTime = `${startDate} 00:00:00`;
// const endDateTime = `${startDate} 23:59:59`;
const startDateTime = filters?.date.after; // min date
const endDateTime = filters?.date.before; // max date ---> seraching on the basis of max date
whereClauses.push(
`(er."startDateTime" <= '${endDateTime}'::timestamp AT TIME ZONE 'UTC' AND er."endDateTime" >= '${startDateTime}'::timestamp AT TIME ZONE 'UTC')`,
);
Expand All @@ -181,26 +184,34 @@ export class EventService {
// Handle startDate
if (filters?.startDate && filters.endDate === undefined) {
const startDate = filters?.startDate;
const startDateTime = `${startDate} 00:00:00`;
const endDateTime = `${startDate} 23:59:59`;
// const startDateTime = `${startDate} 00:00:00`;
// const endDateTime = `${startDate} 23:59:59`;
const startDateTime = filters.startDate.after;
const endDateTime = filters.startDate.before;

whereClauses.push(
`(er."startDateTime" <= '${endDateTime}' ::timestamp AT TIME ZONE 'UTC' AND er."startDateTime" >= '${startDateTime}' ::timestamp AT TIME ZONE 'UTC')`,
);
}

if (filters?.startDate && filters.endDate) {
const startDate = filters?.startDate;
const startDateTime = `${startDate} 00:00:00`;
const endDateTime = `${filters?.endDate} 23:59:59`;
// const startDateTime = `${startDate} 00:00:00`;
// const endDateTime = `${filters?.endDate} 23:59:59`;
const startDateTime = filters.startDate.after; // 21 -> startDate
const endDateTime = filters.endDate.before;

whereClauses.push(
`(er."startDateTime" <= '${endDateTime}' ::timestamp AT TIME ZONE 'UTC' AND er."endDateTime" >= '${startDateTime}' ::timestamp AT TIME ZONE 'UTC')`,
);
}

if (filters.endDate && filters.startDate === undefined) {
const endDate = filters?.endDate;
const startDateTime = `${endDate} 00:00:00`;
const endDateTime = `${endDate} 23:59:59`;
// const endDate = filters?.endDate;
// const startDateTime = `${endDate} 00:00:00`;
// const endDateTime = `${endDate} 23:59:59`;
const startDateTime = filters.endDate.after;
const endDateTime = filters.endDate.before;
whereClauses.push(
`(er."endDateTime" <= '${endDateTime}' ::timestamp AT TIME ZONE 'UTC' AND er."endDateTime" >= '${startDateTime}' ::timestamp AT TIME ZONE 'UTC')`,
);
Expand All @@ -220,21 +231,25 @@ export class EventService {
}

// Handle status filter
if (filters.status && filters.status.length > 0) {
if (filters?.status && filters?.status.length > 0) {
const statusConditions = filters.status
.map((status) => `"status" = '${status}'`)
.map((status) => `ed."status" = '${status}'`)
.join(' OR ');
whereClauses.push(`(${statusConditions})`);
} else {
// Add default status condition if no status is passed in the filter
whereClauses.push(`"status" = 'live'`);
whereClauses.push(`ed."status" = 'live'`);
}

// Handle cohortId filter
if (filters.cohortId) {
if (filters?.cohortId) {
whereClauses.push(`ed."metadata"->>'cohortId'='${filters.cohortId}'`);
}

if (filters?.createdBy) {
whereClauses.push(`er."createdBy" = '${filters.createdBy}'`);
}

// Construct final query
if (whereClauses.length > 0) {
finalquery += ` WHERE ${whereClauses.join(' AND ')}`;
Expand Down

0 comments on commit 46ec2ba

Please sign in to comment.