made a pagination service

This commit is contained in:
2025-11-29 12:04:50 +05:30
parent e0b841b437
commit 264f2fa29c
6 changed files with 149 additions and 18 deletions

View File

@@ -282,7 +282,7 @@ submitCompanyDetails:
submitPQQ_Answer:
handler: src/modules/host/handlers/Activity_Hub/OnBoarding/submitPQQ_Answer.handler
memorySize: 384
memorySize: 1024
package:
patterns:
- 'src/modules/host/handlers/submitPqqAns.*'

View File

@@ -0,0 +1,66 @@
// common/utils/pagination/pagination.service.ts
import { PaginationOptions, PaginationParams, PaginatedResponse } from './pagination.types';
export class PaginationService {
private readonly DEFAULT_PAGE = 1;
private readonly DEFAULT_LIMIT = 10;
private readonly MAX_LIMIT = 100;
/**
* Parse and validate pagination parameters
*/
parsePaginationParams(params: PaginationParams): PaginationOptions {
let page = Number(params.page) || this.DEFAULT_PAGE;
let limit = Number(params.limit) || this.DEFAULT_LIMIT;
// Validate and constrain values
page = Math.max(1, page);
limit = Math.max(1, Math.min(limit, this.MAX_LIMIT));
const skip = (page - 1) * limit;
return {
page,
limit,
skip,
};
}
/**
* Create paginated response
*/
createPaginatedResponse<T>(
data: T[],
totalCount: number,
paginationOptions: PaginationOptions,
): PaginatedResponse<T> {
const { page, limit } = paginationOptions;
const totalPages = Math.ceil(totalCount / limit);
return {
data,
pagination: {
currentPage: page,
pageSize: limit,
totalCount,
totalPages,
hasNext: page < totalPages,
hasPrevious: page > 1,
},
};
}
/**
* Extract pagination params from API Gateway event
*/
getPaginationFromEvent(event: any): PaginationParams {
const queryParams = event.queryStringParameters || {};
return {
page: queryParams.page,
limit: queryParams.limit,
};
}
}
export const paginationService = new PaginationService();

View File

@@ -0,0 +1,23 @@
// common/utils/pagination/pagination.types.ts
export interface PaginationOptions {
page: number;
limit: number;
skip: number;
}
export interface PaginatedResponse<T> {
data: T[];
pagination: {
currentPage: number;
pageSize: number;
totalCount: number;
totalPages: number;
hasNext: boolean;
hasPrevious: boolean;
};
}
export interface PaginationParams {
page?: string | number;
limit?: string | number;
}

View File

@@ -38,16 +38,25 @@ async function uploadToS3(buffer: Buffer, mimeType: string, originalName: string
let s3Key: string;
// If existing URL provided, use the same S3 key to replace the file
// if (existingUrl) {
// s3Key = getS3KeyFromUrl(existingUrl);
// // Delete existing file first
// await deleteFromS3(s3Key);
// } else {
// // Generate new unique key for new file
// const uniqueKey = `${crypto.randomUUID()}_${originalName}`;
// s3Key = `${prefix}/${uniqueKey}`;
// }
if (existingUrl) {
s3Key = getS3KeyFromUrl(existingUrl);
// Delete existing file first
await deleteFromS3(s3Key);
} else {
// Generate new unique key for new file
const uniqueKey = `${crypto.randomUUID()}_${originalName}`;
s3Key = `${prefix}/${uniqueKey}`;
// Delete old file, but DO NOT reuse its name
const oldKey = getS3KeyFromUrl(existingUrl);
await deleteFromS3(oldKey);
}
// Create new key always
const uniqueKey = `${crypto.randomUUID()}_${originalName}`;
s3Key = `${prefix}/${uniqueKey}`;
// Upload new file (replaces existing if same key)
await s3.upload({
Bucket: config.aws.bucketName,

View File

@@ -4,13 +4,13 @@ import { PrismaService } from '../../../../../common/database/prisma.service';
import { MinglarService } from '../../../services/minglar.service';
import ApiError from '../../../../../common/utils/helper/ApiError';
import { verifyMinglarAdminToken } from '../../../../../common/middlewares/jwt/authForMinglarAdmin';
import { paginationService } from '../../../../../common/utils/pagination/pagination.service';
const prismaService = new PrismaService();
const minglarService = new MinglarService(prismaService);
/**
* Get all host applications handler
* Returns host details with status, submission date, and account manager info
* Get all host applications handler with pagination
*/
export const handler = safeHandler(async (
event: APIGatewayProxyEvent,
@@ -35,13 +35,29 @@ export const handler = safeHandler(async (
throw new ApiError(404, 'User not found');
}
// Get search query from query parameters
// Get query parameters
const search = event.queryStringParameters?.search || '';
// Extract userStatus (e.g. 'new') from query parameters
const userStatus = event.queryStringParameters?.userStatus || '';
// Parse pagination parameters
const paginationParams = paginationService.getPaginationFromEvent(event);
const paginationOptions = paginationService.parsePaginationParams(paginationParams);
// Get all host applications from service based on user role
const hostApplications = await minglarService.getAllHostApplications(user.id, Number(user.roleXid), search, userStatus);
// Get paginated host applications
const { data, totalCount } = await minglarService.getAllHostApplications(
user.id,
Number(user.roleXid),
search,
userStatus,
paginationOptions
);
// Create paginated response
const paginatedResponse = paginationService.createPaginatedResponse(
data,
totalCount,
paginationOptions
);
return {
statusCode: 200,
@@ -52,7 +68,7 @@ export const handler = safeHandler(async (
body: JSON.stringify({
success: true,
message: 'Host applications retrieved successfully',
data: hostApplications,
...paginatedResponse,
}),
};
});
});

View File

@@ -26,6 +26,7 @@ import { CreateMinglarDto, UpdateMinglarDto } from '../dto/minglar.dto';
import { sendAMEmailForHostAssign } from './AMEmail.service';
import { getPresignedUrl } from '@/common/middlewares/aws/getPreSignedUrl';
import config from '@/config/config';
import { PaginationOptions } from '@/common/utils/pagination/pagination.types';
@Injectable()
export class MinglarService {
@@ -636,11 +637,13 @@ export class MinglarService {
});
}
// Update your MinglarService method
async getAllHostApplications(
userId: number,
userRoleXid: number,
search?: string,
userStatus?: string,
paginationOptions?: PaginationOptions,
) {
const filters: any = {
isActive: true,
@@ -693,7 +696,14 @@ export class MinglarService {
}
/** -----------------------------------
* MAIN QUERY
* COUNT TOTAL RECORDS
* ----------------------------------- */
const totalCount = await this.prisma.hostHeader.count({
where: filters,
});
/** -----------------------------------
* MAIN QUERY WITH PAGINATION
* ----------------------------------- */
const results = await this.prisma.hostHeader.findMany({
where: filters,
@@ -732,12 +742,14 @@ export class MinglarService {
},
},
orderBy: { createdAt: 'desc' },
skip: paginationOptions?.skip || 0,
take: paginationOptions?.limit || 10,
});
/** -----------------------------------
* TRANSFORM RESPONSE
* ----------------------------------- */
return results.map((h) => ({
const transformedData = results.map((h) => ({
hostId: h.id,
host: h.user,
hostStatusDisplay: h.hostStatusDisplay,
@@ -752,6 +764,11 @@ export class MinglarService {
country: h.countries || null,
assignedOn: h.assignedOn || null,
}));
return {
data: transformedData,
totalCount,
};
}
async getAllOnboardingHostApplications() {