Skip to content

Commit 0a6733c

Browse files
committed
feat(blog-category): add search functionality to BlogCategoryService
1 parent 4966505 commit 0a6733c

File tree

3 files changed

+118
-2
lines changed

3 files changed

+118
-2
lines changed

src/modules/blog-category/blog-category.controller.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,15 @@
1-
import { Body, Controller, Post, UseGuards, Request, Patch, Param } from '@nestjs/common';
1+
import {
2+
Body,
3+
Controller,
4+
Post,
5+
UseGuards,
6+
Request,
7+
Patch,
8+
Param,
9+
Get,
10+
Query,
11+
NotFoundException,
12+
} from '@nestjs/common';
213
import { ApiBearerAuth, ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
314
import { SuperAdminGuard } from '../../guards/super-admin.guard';
415
import { BlogCategoryService } from './blog-category.service';
@@ -36,4 +47,14 @@ export class BlogCategoryController {
3647
async updateBlogCategory(@Param('id') id: string, @Body() updateBlogCategoryDto: UpdateBlogCategoryDto) {
3748
return await this.blogCategoryService.updateOrganisationCategory(id, updateBlogCategoryDto);
3849
}
50+
51+
@Get('search')
52+
@ApiOperation({ summary: 'Search blog categories by name' })
53+
@ApiResponse({ status: 200, description: 'Categories found' })
54+
@ApiResponse({ status: 404, description: 'No categories found' })
55+
async searchCategories(@Query('term') searchTerm: string) {
56+
console.log('Search Term: ', searchTerm);
57+
const result = await this.blogCategoryService.searchCategories(searchTerm);
58+
return result;
59+
}
3960
}

src/modules/blog-category/blog-category.service.ts

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Injectable } from '@nestjs/common';
22
import { InjectRepository } from '@nestjs/typeorm';
33
import { BlogCategory } from './entities/blog-category.entity';
4-
import { Repository } from 'typeorm';
4+
import { Like, Repository } from 'typeorm';
55
import { CreateBlogCategoryDto } from './dto/create-blog-category.dto';
66
import { CustomHttpException } from '../../helpers/custom-http-filter';
77
import { CATEGORY_NOT_FOUND, ORG_NOT_FOUND } from '../../helpers/SystemMessages';
@@ -29,4 +29,37 @@ export class BlogCategoryService {
2929
await this.blogCategoryRepository.save(category);
3030
return { data: category, message: 'Organisation category updated successfully.' };
3131
}
32+
33+
async searchCategories(searchTerm: string): Promise<{
34+
status: string;
35+
status_code: number;
36+
message: string;
37+
data: { categories: BlogCategory[]; total: number };
38+
}> {
39+
// Handle empty search term
40+
if (!searchTerm || searchTerm.trim() === '') {
41+
return {
42+
status: 'success',
43+
status_code: 200,
44+
message: 'No search term provided',
45+
data: { categories: [], total: 0 },
46+
};
47+
}
48+
49+
// Perform a case-insensitive search
50+
const categories = await this.blogCategoryRepository
51+
.createQueryBuilder('category')
52+
.where('LOWER(category.name) LIKE LOWER(:searchTerm)', {
53+
searchTerm: `%${searchTerm}%`,
54+
})
55+
.getMany();
56+
57+
// Return the results in the desired format
58+
return {
59+
status: 'success',
60+
status_code: 200,
61+
message: categories.length > 0 ? 'Categories found successfully' : 'No categories found',
62+
data: { categories, total: categories.length },
63+
};
64+
}
3265
}

src/modules/blog-category/tests/blog-category.service.spec.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,66 @@ describe('BlogCategoryService', () => {
5757

5858
await expect(service.createOrganisationCategory(createBlogCategoryDto)).rejects.toThrow('Save failed');
5959
});
60+
61+
it('should return empty array and total 0 for empty search term', async () => {
62+
const result = await service.searchCategories('');
63+
expect(result).toEqual({
64+
status: 'success',
65+
status_code: 200,
66+
message: 'No search term provided',
67+
data: { categories: [], total: 0 },
68+
});
69+
});
70+
71+
it('should return matching categories for partial search term', async () => {
72+
const mockCategories = [
73+
{ id: '1', name: 'Technology' },
74+
{ id: '2', name: 'Tech News' },
75+
];
76+
77+
jest.spyOn(repository, 'createQueryBuilder').mockReturnValue({
78+
where: jest.fn().mockReturnThis(),
79+
getMany: jest.fn().mockResolvedValue(mockCategories),
80+
} as any);
81+
82+
const result = await service.searchCategories('tech');
83+
expect(result).toEqual({
84+
status: 'success',
85+
status_code: 200,
86+
message: 'Categories found successfully',
87+
data: { categories: mockCategories, total: 2 },
88+
});
89+
});
90+
91+
it('should return empty array and total 0 for no matches', async () => {
92+
jest.spyOn(repository, 'createQueryBuilder').mockReturnValue({
93+
where: jest.fn().mockReturnThis(),
94+
getMany: jest.fn().mockResolvedValue([]),
95+
} as any);
96+
97+
const result = await service.searchCategories('nonexistent');
98+
expect(result).toEqual({
99+
status: 'success',
100+
status_code: 200,
101+
message: 'No categories found',
102+
data: { categories: [], total: 0 },
103+
});
104+
});
105+
106+
it('should handle search term with special characters', async () => {
107+
const mockCategories = [{ id: '1', name: 'C# Programming' }];
108+
109+
jest.spyOn(repository, 'createQueryBuilder').mockReturnValue({
110+
where: jest.fn().mockReturnThis(),
111+
getMany: jest.fn().mockResolvedValue(mockCategories),
112+
} as any);
113+
114+
const result = await service.searchCategories('C#');
115+
expect(result).toEqual({
116+
status: 'success',
117+
status_code: 200,
118+
message: 'Categories found successfully',
119+
data: { categories: mockCategories, total: 1 },
120+
});
121+
});
60122
});

0 commit comments

Comments
 (0)