Skip to content

Commit 2804b01

Browse files
authored
feat: changes for people search improvements (#1226)
* changes for people serach improvements * removing log statements * fixed prettier format issue
1 parent db19e5e commit 2804b01

File tree

9 files changed

+412
-72
lines changed

9 files changed

+412
-72
lines changed

backend/cats/src/app/resolvers/people/people.resolver.ts

Lines changed: 99 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
import { Query, Resolver, Mutation, Args, Int } from '@nestjs/graphql';
22
import { AuthenticatedUser, Public, Resource } from 'nest-keycloak-connect';
3-
import { BadRequestException, HttpStatus, UsePipes, ValidationError, ValidationPipe } from '@nestjs/common';
3+
import {
4+
BadRequestException,
5+
HttpStatus,
6+
UsePipes,
7+
ValidationError,
8+
ValidationPipe,
9+
} from '@nestjs/common';
410
import { SearchPersonResponse } from '../../dto/response/person/fetchSearchPerson';
511
import { LoggerService } from '../../logger/logger.service';
612
import { PersonService } from '../../services/people/people.service';
@@ -16,21 +22,29 @@ export class PersonResolver {
1622
constructor(
1723
private readonly personService: PersonService,
1824
private readonly loggerSerivce: LoggerService,
19-
private readonly personResponse: GenericResponseProvider<ViewPerson[]>
25+
private readonly personResponse: GenericResponseProvider<ViewPerson[]>,
2026
) {}
2127

2228
@Query(() => PersonResponse, { name: 'findAllPerson' })
2329
async findAll() {
2430
try {
2531
const result = await this.personService.findAll();
26-
if(result?.length > 0) {
32+
if (result?.length > 0) {
2733
this.loggerSerivce.log('PersonResolver.findAll() RES:200 end');
28-
return this.personResponse.createResponse('Person records fetched successfully', HttpStatus.OK, true, result);
29-
}
30-
else
31-
{
34+
return this.personResponse.createResponse(
35+
'Person records fetched successfully',
36+
HttpStatus.OK,
37+
true,
38+
result,
39+
);
40+
} else {
3241
this.loggerSerivce.log('PersonResolver.findAll() RES:404 end');
33-
return this.personResponse.createResponse('No person records found', HttpStatus.NOT_FOUND, false, []);
42+
return this.personResponse.createResponse(
43+
'No person records found',
44+
HttpStatus.NOT_FOUND,
45+
false,
46+
[],
47+
);
3448
}
3549
} catch (error) {
3650
throw new Error(`Failed to fetch person: ${error.message}`);
@@ -41,16 +55,22 @@ export class PersonResolver {
4155
async findOne(@Args('id') id: number) {
4256
try {
4357
const result = await this.personService.findOne(id);
44-
if(result) {
45-
this.loggerSerivce.log(
46-
'PersonResolver.findOne() RES:200 end',
58+
if (result) {
59+
this.loggerSerivce.log('PersonResolver.findOne() RES:200 end');
60+
return this.personResponse.createResponse(
61+
'Person record fetched successfully',
62+
HttpStatus.OK,
63+
true,
64+
[result],
65+
);
66+
} else {
67+
this.loggerSerivce.log('PersonResolver.findOne() RES:404 end');
68+
return this.personResponse.createResponse(
69+
'No person records found',
70+
HttpStatus.NOT_FOUND,
71+
false,
72+
[],
4773
);
48-
return this.personResponse.createResponse('Person record fetched successfully', HttpStatus.OK, true, [result]);
49-
}
50-
else
51-
{
52-
this.loggerSerivce.log( 'PersonResolver.findOne() RES:404 end');
53-
return this.personResponse.createResponse('No person records found', HttpStatus.NOT_FOUND, false, []);
5474
}
5575
} catch (error) {
5676
throw new Error(`Failed to find person: ${error.message}`);
@@ -75,30 +95,41 @@ export class PersonResolver {
7595
},
7696
}),
7797
)
78-
async createPerson(@Args('person') person: CreatePerson, @AuthenticatedUser() userInfo: any) {
98+
async createPerson(
99+
@Args('person') person: CreatePerson,
100+
@AuthenticatedUser() userInfo: any,
101+
) {
79102
try {
80103
// Check for duplicate person
81104
const existingPerson = await this.personService.checkForDuplicate(person);
82-
105+
83106
if (existingPerson) {
84-
this.loggerSerivce.log('PersonResolver.createPerson() RES:409 duplicate found');
107+
this.loggerSerivce.log(
108+
'PersonResolver.createPerson() RES:409 duplicate found',
109+
);
85110
return this.personResponse.createResponse(
86-
'A person with this name already exists',
87-
HttpStatus.CONFLICT,
111+
'A person with this name already exists',
112+
HttpStatus.CONFLICT,
88113
false,
89-
[existingPerson]
114+
[existingPerson],
90115
);
91116
}
92117

93118
const result = await this.personService.create(person, userInfo);
94-
if(result) {
119+
if (result) {
95120
this.loggerSerivce.log('PersonResolver.createPerson() RES:201 end');
96-
return this.personResponse.createResponse('Person created successfully', HttpStatus.CREATED, true);
97-
}
98-
else
99-
{
121+
return this.personResponse.createResponse(
122+
'Person created successfully',
123+
HttpStatus.CREATED,
124+
true,
125+
);
126+
} else {
100127
this.loggerSerivce.log('PersonResolver.createPerson() RES:400 end');
101-
return this.personResponse.createResponse('Person not created', HttpStatus.BAD_REQUEST, false);
128+
return this.personResponse.createResponse(
129+
'Person not created',
130+
HttpStatus.BAD_REQUEST,
131+
false,
132+
);
102133
}
103134
} catch (error) {
104135
throw new Error(`Failed to create person: ${error.message}`);
@@ -107,19 +138,25 @@ export class PersonResolver {
107138

108139
@Mutation(() => PersonResponse, { name: 'updatePerson' })
109140
async updatePersons(
110-
@Args('input', { type: () => [UpdatePerson] })input: [UpdatePerson],
141+
@Args('input', { type: () => [UpdatePerson] }) input: [UpdatePerson],
111142
@AuthenticatedUser() userInfo: any,
112143
) {
113144
try {
114145
const result = await this.personService.update(input, userInfo);
115-
if(result) {
146+
if (result) {
116147
this.loggerSerivce.log('PersonResolver.updatePerson() RES:200 end');
117-
return this.personResponse.createResponse('Person updated successfully', HttpStatus.OK, true);
118-
}
119-
else
120-
{
148+
return this.personResponse.createResponse(
149+
'Person updated successfully',
150+
HttpStatus.OK,
151+
true,
152+
);
153+
} else {
121154
this.loggerSerivce.log('PersonResolver.updatePerson() RES:400 end');
122-
return this.personResponse.createResponse('Person not updated', HttpStatus.BAD_REQUEST, false);
155+
return this.personResponse.createResponse(
156+
'Person not updated',
157+
HttpStatus.BAD_REQUEST,
158+
false,
159+
);
123160
}
124161
} catch (error) {
125162
throw new Error(`Failed to update person: ${error.message}`);
@@ -139,16 +176,41 @@ export class PersonResolver {
139176
@Args('searchParam', { type: () => String }) searchParam: string,
140177
@Args('page', { type: () => Int }) page: number,
141178
@Args('pageSize', { type: () => Int }) pageSize: number,
179+
@Args('searchMode', {
180+
type: () => String,
181+
nullable: true,
182+
defaultValue: 'OR',
183+
})
184+
searchMode: string,
185+
@Args('activeFilter', {
186+
type: () => String,
187+
nullable: true,
188+
defaultValue: 'all',
189+
})
190+
activeFilter: string,
142191
//@Args('filters', { type: () => SiteFilters }) filters: SiteFilters,
143192
) {
193+
const validSearchMode = ['AND', 'OR'].includes(searchMode)
194+
? (searchMode as 'AND' | 'OR')
195+
: 'OR';
196+
197+
const validActiveFilter = ['active', 'inactive', 'all'].includes(
198+
activeFilter,
199+
)
200+
? (activeFilter as 'active' | 'inactive' | 'all')
201+
: 'all';
202+
144203
this.loggerSerivce.log(
145-
'searchPerson start ' + searchParam + ' ' + page + ' ' + pageSize,
204+
`searchPerson start ${searchParam} ${page} ${pageSize} ${validSearchMode} ${validActiveFilter}`,
146205
);
206+
147207
return await this.personService.searchPerson(
148208
userInfo,
149209
searchParam,
150210
page,
151211
pageSize,
212+
validSearchMode,
213+
validActiveFilter,
152214
//filters,
153215
);
154216
}

backend/cats/src/app/services/people/people.service.spec.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,63 @@ describe('PersonService', () => {
237237
expect(result).toEqual(expect.objectContaining(expectedResponse));
238238
});
239239

240+
it('should search with AND mode', async () => {
241+
const mockQueryBuilder = {
242+
andWhere: jest.fn().mockReturnThis(),
243+
skip: jest.fn().mockReturnThis(),
244+
take: jest.fn().mockReturnThis(),
245+
setParameter: jest.fn().mockReturnThis(),
246+
getSql: jest.fn().mockReturnValue(''),
247+
getParameters: jest.fn().mockReturnValue({}),
248+
getManyAndCount: jest.fn().mockResolvedValue([[], 0]),
249+
};
250+
(personRepository.createQueryBuilder as jest.Mock).mockReturnValue(
251+
mockQueryBuilder,
252+
);
253+
await personService.searchPerson({}, 'jane admin', 1, 10, 'AND');
254+
expect(mockQueryBuilder.setParameter).toHaveBeenCalled();
255+
});
256+
257+
it('should handle exclusion operator', async () => {
258+
const mockQueryBuilder = {
259+
andWhere: jest.fn().mockReturnThis(),
260+
skip: jest.fn().mockReturnThis(),
261+
take: jest.fn().mockReturnThis(),
262+
setParameter: jest.fn().mockReturnThis(),
263+
getSql: jest.fn().mockReturnValue(''),
264+
getParameters: jest.fn().mockReturnValue({}),
265+
getManyAndCount: jest.fn().mockResolvedValue([[], 0]),
266+
};
267+
(personRepository.createQueryBuilder as jest.Mock).mockReturnValue(
268+
mockQueryBuilder,
269+
);
270+
await personService.searchPerson({}, 'jane -admin', 1, 10);
271+
expect(mockQueryBuilder.setParameter).toHaveBeenCalledWith(
272+
'kw_exclude_0',
273+
'%admin%',
274+
);
275+
});
276+
277+
it('should filter active users', async () => {
278+
const mockQueryBuilder = {
279+
andWhere: jest.fn().mockReturnThis(),
280+
skip: jest.fn().mockReturnThis(),
281+
take: jest.fn().mockReturnThis(),
282+
setParameter: jest.fn().mockReturnThis(),
283+
getSql: jest.fn().mockReturnValue(''),
284+
getParameters: jest.fn().mockReturnValue({}),
285+
getManyAndCount: jest.fn().mockResolvedValue([[], 0]),
286+
};
287+
(personRepository.createQueryBuilder as jest.Mock).mockReturnValue(
288+
mockQueryBuilder,
289+
);
290+
await personService.searchPerson({}, 'jane', 1, 10, 'OR', 'active');
291+
expect(mockQueryBuilder.andWhere).toHaveBeenCalledWith(
292+
'person.is_active = :isActive',
293+
{ isActive: true },
294+
);
295+
});
296+
240297
describe('checkForDuplicate', () => {
241298
it('should return null when no duplicate person exists', async () => {
242299
const createPersonInput = {

0 commit comments

Comments
 (0)