diff --git a/src/modules/blog-category/blog-category.controller.ts b/src/modules/blog-category/blog-category.controller.ts index 47e421641..f9d89d9db 100644 --- a/src/modules/blog-category/blog-category.controller.ts +++ b/src/modules/blog-category/blog-category.controller.ts @@ -1,4 +1,15 @@ -import { Body, Controller, Post, UseGuards, Request, Patch, Param } from '@nestjs/common'; +import { + Body, + Controller, + Post, + UseGuards, + Request, + Patch, + Param, + Get, + Query, + NotFoundException, +} from '@nestjs/common'; import { ApiBearerAuth, ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger'; import { SuperAdminGuard } from '../../guards/super-admin.guard'; import { BlogCategoryService } from './blog-category.service'; @@ -36,4 +47,14 @@ export class BlogCategoryController { async updateBlogCategory(@Param('id') id: string, @Body() updateBlogCategoryDto: UpdateBlogCategoryDto) { return await this.blogCategoryService.updateOrganisationCategory(id, updateBlogCategoryDto); } + + @Get('search') + @ApiOperation({ summary: 'Search blog categories by name' }) + @ApiResponse({ status: 200, description: 'Categories found' }) + @ApiResponse({ status: 404, description: 'No categories found' }) + async searchCategories(@Query('term') searchTerm: string) { + console.log('Search Term: ', searchTerm); + const result = await this.blogCategoryService.searchCategories(searchTerm); + return result; + } } diff --git a/src/modules/blog-category/blog-category.service.ts b/src/modules/blog-category/blog-category.service.ts index 6d8c04a3e..00d24df7c 100644 --- a/src/modules/blog-category/blog-category.service.ts +++ b/src/modules/blog-category/blog-category.service.ts @@ -1,7 +1,7 @@ import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { BlogCategory } from './entities/blog-category.entity'; -import { Repository } from 'typeorm'; +import { Like, Repository } from 'typeorm'; import { CreateBlogCategoryDto } from './dto/create-blog-category.dto'; import { CustomHttpException } from '../../helpers/custom-http-filter'; import { CATEGORY_NOT_FOUND, ORG_NOT_FOUND } from '../../helpers/SystemMessages'; @@ -29,4 +29,37 @@ export class BlogCategoryService { await this.blogCategoryRepository.save(category); return { data: category, message: 'Organisation category updated successfully.' }; } + + async searchCategories(searchTerm: string): Promise<{ + status: string; + status_code: number; + message: string; + data: { categories: BlogCategory[]; total: number }; + }> { + // Handle empty search term + if (!searchTerm || searchTerm.trim() === '') { + return { + status: 'success', + status_code: 200, + message: 'No search term provided', + data: { categories: [], total: 0 }, + }; + } + + // Perform a case-insensitive search + const categories = await this.blogCategoryRepository + .createQueryBuilder('category') + .where('LOWER(category.name) LIKE LOWER(:searchTerm)', { + searchTerm: `%${searchTerm}%`, + }) + .getMany(); + + // Return the results in the desired format + return { + status: 'success', + status_code: 200, + message: categories.length > 0 ? 'Categories found successfully' : 'No categories found', + data: { categories, total: categories.length }, + }; + } } diff --git a/src/modules/blog-category/tests/blog-category.service.spec.ts b/src/modules/blog-category/tests/blog-category.service.spec.ts index a310844ef..e784df0ef 100644 --- a/src/modules/blog-category/tests/blog-category.service.spec.ts +++ b/src/modules/blog-category/tests/blog-category.service.spec.ts @@ -57,4 +57,66 @@ describe('BlogCategoryService', () => { await expect(service.createOrganisationCategory(createBlogCategoryDto)).rejects.toThrow('Save failed'); }); + + it('should return empty array and total 0 for empty search term', async () => { + const result = await service.searchCategories(''); + expect(result).toEqual({ + status: 'success', + status_code: 200, + message: 'No search term provided', + data: { categories: [], total: 0 }, + }); + }); + + it('should return matching categories for partial search term', async () => { + const mockCategories = [ + { id: '1', name: 'Technology' }, + { id: '2', name: 'Tech News' }, + ]; + + jest.spyOn(repository, 'createQueryBuilder').mockReturnValue({ + where: jest.fn().mockReturnThis(), + getMany: jest.fn().mockResolvedValue(mockCategories), + } as any); + + const result = await service.searchCategories('tech'); + expect(result).toEqual({ + status: 'success', + status_code: 200, + message: 'Categories found successfully', + data: { categories: mockCategories, total: 2 }, + }); + }); + + it('should return empty array and total 0 for no matches', async () => { + jest.spyOn(repository, 'createQueryBuilder').mockReturnValue({ + where: jest.fn().mockReturnThis(), + getMany: jest.fn().mockResolvedValue([]), + } as any); + + const result = await service.searchCategories('nonexistent'); + expect(result).toEqual({ + status: 'success', + status_code: 200, + message: 'No categories found', + data: { categories: [], total: 0 }, + }); + }); + + it('should handle search term with special characters', async () => { + const mockCategories = [{ id: '1', name: 'C# Programming' }]; + + jest.spyOn(repository, 'createQueryBuilder').mockReturnValue({ + where: jest.fn().mockReturnThis(), + getMany: jest.fn().mockResolvedValue(mockCategories), + } as any); + + const result = await service.searchCategories('C#'); + expect(result).toEqual({ + status: 'success', + status_code: 200, + message: 'Categories found successfully', + data: { categories: mockCategories, total: 1 }, + }); + }); });