Merge pull request #400 from Hexastack/367-issue-refactor-api-controller-actions-find-findpage

Refactor: merge find findPage - findAndPopulate findPageAndPopulate
This commit is contained in:
Med Marrouchi 2024-12-06 15:08:39 +01:00 committed by GitHub
commit a1590a4a58
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
49 changed files with 238 additions and 228 deletions

View File

@ -80,14 +80,9 @@ export class BlockController extends BaseController<
filters: TFilterQuery<Block>,
@Query(PageQueryPipe) pageQuery?: PageQueryDto<Block>,
): Promise<Block[] | BlockFull[]> {
if (pageQuery?.limit) {
return this.canPopulate(populate)
? await this.blockService.findPageAndPopulate(filters, pageQuery)
: await this.blockService.findPage(filters, pageQuery);
}
return this.canPopulate(populate)
? await this.blockService.findAndPopulate(filters, pageQuery?.sort)
: await this.blockService.find(filters, pageQuery?.sort);
? await this.blockService.findAndPopulate(filters, pageQuery)
: await this.blockService.find(filters, pageQuery);
}
/**

View File

@ -57,11 +57,7 @@ export class CategoryController extends BaseController<Category> {
@Query(new SearchFilterPipe<Category>({ allowedFields: ['label'] }))
filters: TFilterQuery<Category>,
) {
if (pageQuery.limit) {
return await this.categoryService.findPage(filters, pageQuery);
}
return await this.categoryService.find(filters, pageQuery.sort);
return await this.categoryService.find(filters, pageQuery);
}
/**

View File

@ -28,7 +28,7 @@ import {
ContextVarUpdateDto,
} from '../dto/context-var.dto';
import { ContextVarRepository } from '../repositories/context-var.repository';
import { ContextVarModel, ContextVar } from '../schemas/context-var.schema';
import { ContextVar, ContextVarModel } from '../schemas/context-var.schema';
import { ContextVarService } from '../services/context-var.service';
import { ContextVarController } from './context-var.controller';
@ -80,10 +80,10 @@ describe('ContextVarController', () => {
describe('findPage', () => {
it('should return an array of contextVars', async () => {
const pageQuery = getPageQuery<ContextVar>();
jest.spyOn(contextVarService, 'findPage');
jest.spyOn(contextVarService, 'find');
const result = await contextVarController.findPage(pageQuery, {});
expect(contextVarService.findPage).toHaveBeenCalledWith({}, pageQuery);
expect(contextVarService.find).toHaveBeenCalledWith({}, pageQuery);
expect(result).toEqualPayload(contextVarFixtures.sort(sortRowsBy));
});
});

View File

@ -60,11 +60,7 @@ export class ContextVarController extends BaseController<ContextVar> {
@Query(new SearchFilterPipe<ContextVar>({ allowedFields: ['label'] }))
filters: TFilterQuery<ContextVar>,
): Promise<ContextVar[]> {
if (pageQuery.limit) {
return await this.contextVarService.findPage(filters, pageQuery);
}
return await this.contextVarService.find(filters, pageQuery.sort);
return await this.contextVarService.find(filters, pageQuery);
}
/**

View File

@ -104,13 +104,13 @@ describe('LabelController', () => {
describe('findPage', () => {
const pageQuery = getPageQuery<Label>();
it('should find labels', async () => {
jest.spyOn(labelService, 'findPage');
jest.spyOn(labelService, 'find');
const result = await labelController.findPage(pageQuery, [], {});
const labelsWithBuiltin = labelFixtures.map((labelFixture) => ({
...labelFixture,
}));
expect(labelService.findPage).toHaveBeenCalledWith({}, pageQuery);
expect(labelService.find).toHaveBeenCalledWith({}, pageQuery);
expect(result).toEqualPayload(labelsWithBuiltin.sort(sortRowsBy), [
...IGNORED_TEST_FIELDS,
'nextBlocks',
@ -118,7 +118,7 @@ describe('LabelController', () => {
});
it('should find labels, and foreach label populate its corresponding users', async () => {
jest.spyOn(labelService, 'findPageAndPopulate');
jest.spyOn(labelService, 'findAndPopulate');
const result = await labelController.findPage(pageQuery, ['users'], {});
const allLabels = await labelService.findAll();
const allSubscribers = await subscriberService.findAll();
@ -127,10 +127,7 @@ describe('LabelController', () => {
users: allSubscribers,
}));
expect(labelService.findPageAndPopulate).toHaveBeenCalledWith(
{},
pageQuery,
);
expect(labelService.findAndPopulate).toHaveBeenCalledWith({}, pageQuery);
expect(result).toEqualPayload(labelsWithUsers.sort(sortRowsBy));
});
});

View File

@ -62,15 +62,9 @@ export class LabelController extends BaseController<
@Query(new SearchFilterPipe<Label>({ allowedFields: ['name', 'title'] }))
filters: TFilterQuery<Label>,
) {
if (pageQuery.limit) {
return this.canPopulate(populate)
? await this.labelService.findPageAndPopulate(filters, pageQuery)
: await this.labelService.findPage(filters, pageQuery);
}
return this.canPopulate(populate)
? await this.labelService.findAndPopulate(filters, pageQuery.sort)
: await this.labelService.find(filters, pageQuery.sort);
? await this.labelService.findAndPopulate(filters, pageQuery)
: await this.labelService.find(filters, pageQuery);
}
/**

View File

@ -185,7 +185,7 @@ describe('MessageController', () => {
describe('findPage', () => {
const pageQuery = getPageQuery<Message>();
it('should find messages', async () => {
jest.spyOn(messageService, 'findPage');
jest.spyOn(messageService, 'find');
const result = await messageController.findPage(pageQuery, [], {});
const messagesWithSenderAndRecipient = allMessages.map((message) => ({
...message,
@ -195,12 +195,12 @@ describe('MessageController', () => {
sentBy: allUsers.find(({ id }) => id === message['sentBy']).id,
}));
expect(messageService.findPage).toHaveBeenCalledWith({}, pageQuery);
expect(messageService.find).toHaveBeenCalledWith({}, pageQuery);
expect(result).toEqualPayload(messagesWithSenderAndRecipient);
});
it('should find messages, and foreach message populate the corresponding sender and recipient', async () => {
jest.spyOn(messageService, 'findPageAndPopulate');
jest.spyOn(messageService, 'findAndPopulate');
const result = await messageController.findPage(
pageQuery,
['sender', 'recipient'],
@ -213,7 +213,7 @@ describe('MessageController', () => {
sentBy: allUsers.find(({ id }) => id === message['sentBy']).id,
}));
expect(messageService.findPageAndPopulate).toHaveBeenCalledWith(
expect(messageService.findAndPopulate).toHaveBeenCalledWith(
{},
pageQuery,
);

View File

@ -80,15 +80,9 @@ export class MessageController extends BaseController<
)
filters: TFilterQuery<Message>,
) {
if (pageQuery.limit) {
return this.canPopulate(populate)
? await this.messageService.findPageAndPopulate(filters, pageQuery)
: await this.messageService.findPage(filters, pageQuery);
}
return this.canPopulate(populate)
? await this.messageService.findAndPopulate(filters, pageQuery.sort)
: await this.messageService.find(filters, pageQuery.sort);
? await this.messageService.findAndPopulate(filters, pageQuery)
: await this.messageService.find(filters, pageQuery);
}
/**

View File

@ -18,7 +18,7 @@ import { RoleRepository } from '@/user/repositories/role.repository';
import { UserRepository } from '@/user/repositories/user.repository';
import { PermissionModel } from '@/user/schemas/permission.schema';
import { RoleModel } from '@/user/schemas/role.schema';
import { UserModel, User } from '@/user/schemas/user.schema';
import { User, UserModel } from '@/user/schemas/user.schema';
import { RoleService } from '@/user/services/role.service';
import {
installSubscriberFixtures,
@ -35,8 +35,8 @@ import { WebsocketGateway } from '@/websocket/websocket.gateway';
import { LabelRepository } from '../repositories/label.repository';
import { SubscriberRepository } from '../repositories/subscriber.repository';
import { LabelModel, Label } from '../schemas/label.schema';
import { SubscriberModel, Subscriber } from '../schemas/subscriber.schema';
import { Label, LabelModel } from '../schemas/label.schema';
import { Subscriber, SubscriberModel } from '../schemas/subscriber.schema';
import { SubscriberService } from '../services/subscriber.service';
import { UserService } from './../../user/services/user.service';
@ -153,7 +153,7 @@ describe('SubscriberController', () => {
describe('findPage', () => {
const pageQuery = getPageQuery<Subscriber>();
it('should find subscribers', async () => {
jest.spyOn(subscriberService, 'findPage');
jest.spyOn(subscriberService, 'find');
const result = await subscriberController.findPage(pageQuery, [], {});
const subscribersWithIds = allSubscribers.map(({ labels, ...rest }) => ({
...rest,
@ -162,12 +162,12 @@ describe('SubscriberController', () => {
.map(({ id }) => id),
}));
expect(subscriberService.findPage).toHaveBeenCalledWith({}, pageQuery);
expect(subscriberService.find).toHaveBeenCalledWith({}, pageQuery);
expect(result).toEqualPayload(subscribersWithIds.sort(sortRowsBy));
});
it('should find subscribers, and foreach subscriber populate the corresponding labels', async () => {
jest.spyOn(subscriberService, 'findPageAndPopulate');
jest.spyOn(subscriberService, 'findAndPopulate');
const result = await subscriberController.findPage(
pageQuery,
['labels'],
@ -181,7 +181,7 @@ describe('SubscriberController', () => {
}),
);
expect(subscriberService.findPageAndPopulate).toHaveBeenCalledWith(
expect(subscriberService.findAndPopulate).toHaveBeenCalledWith(
{},
pageQuery,
);

View File

@ -73,15 +73,9 @@ export class SubscriberController extends BaseController<
)
filters: TFilterQuery<Subscriber>,
) {
if (pageQuery.limit) {
return this.canPopulate(populate)
? await this.subscriberService.findPageAndPopulate(filters, pageQuery)
: await this.subscriberService.findPage(filters, pageQuery);
}
return this.canPopulate(populate)
? await this.subscriberService.findAndPopulate(filters, pageQuery.sort)
: await this.subscriberService.find(filters, pageQuery.sort);
? await this.subscriberService.findAndPopulate(filters, pageQuery)
: await this.subscriberService.find(filters, pageQuery);
}
/**

View File

@ -68,7 +68,10 @@ describe('BlockRepository', () => {
jest.spyOn(blockModel, 'findById');
const result = await blockRepository.findOneAndPopulate(hasNextBlocks.id);
expect(blockModel.findById).toHaveBeenCalledWith(hasNextBlocks.id);
expect(blockModel.findById).toHaveBeenCalledWith(
hasNextBlocks.id,
undefined,
);
expect(result).toEqualPayload({
...blockFixtures.find(({ name }) => name === hasNextBlocks.name),
category,
@ -92,7 +95,7 @@ describe('BlockRepository', () => {
blockFixture.name === 'hasNextBlocks' ? [hasPreviousBlocks] : [],
}));
expect(blockModel.find).toHaveBeenCalledWith({});
expect(blockModel.find).toHaveBeenCalledWith({}, undefined);
expect(result).toEqualPayload(blocksWithCategory);
});
@ -109,7 +112,7 @@ describe('BlockRepository', () => {
blockFixture.name === 'hasNextBlocks' ? [hasPreviousBlocks] : [],
}));
expect(blockModel.find).toHaveBeenCalledWith({});
expect(blockModel.find).toHaveBeenCalledWith({}, undefined);
expect(result).toEqualPayload(blocksWithCategory);
});
});

View File

@ -21,8 +21,8 @@ import {
rootMongooseTestModule,
} from '@/utils/test/test';
import { LabelModel, Label } from '../schemas/label.schema';
import { SubscriberModel, Subscriber } from '../schemas/subscriber.schema';
import { Label, LabelModel } from '../schemas/label.schema';
import { Subscriber, SubscriberModel } from '../schemas/subscriber.schema';
import { LabelRepository } from './label.repository';
import { SubscriberRepository } from './subscriber.repository';
@ -62,7 +62,7 @@ describe('LabelRepository', () => {
const label = await labelRepository.findOne({ name: 'TEST_TITLE_2' });
const result = await labelRepository.findOneAndPopulate(label.id);
expect(labelModel.findById).toHaveBeenCalledWith(label.id);
expect(labelModel.findById).toHaveBeenCalledWith(label.id, undefined);
expect(result).toEqualPayload({
...labelFixtures.find(({ name }) => name === label.name),
users,
@ -79,7 +79,7 @@ describe('LabelRepository', () => {
users,
}));
expect(labelModel.find).toHaveBeenCalledWith({});
expect(labelModel.find).toHaveBeenCalledWith({}, undefined);
expect(result).toEqualPayload(labelsWithUsers);
});
});
@ -94,7 +94,7 @@ describe('LabelRepository', () => {
users,
}));
expect(labelModel.find).toHaveBeenCalledWith({});
expect(labelModel.find).toHaveBeenCalledWith({}, undefined);
expect(result).toEqualPayload(labelsWithUsers.sort(sortRowsBy));
});
});

View File

@ -23,7 +23,7 @@ import {
rootMongooseTestModule,
} from '@/utils/test/test';
import { MessageModel, Message } from '../schemas/message.schema';
import { Message, MessageModel } from '../schemas/message.schema';
import { SubscriberModel } from '../schemas/subscriber.schema';
import { AnyMessage } from '../schemas/types/message';
@ -70,7 +70,7 @@ describe('MessageRepository', () => {
const user = await userRepository.findOne(message['sentBy']);
const result = await messageRepository.findOneAndPopulate(message.id);
expect(messageModel.findById).toHaveBeenCalledWith(message.id);
expect(messageModel.findById).toHaveBeenCalledWith(message.id, undefined);
expect(result).toEqualPayload({
...messageFixtures.find(({ mid }) => mid === message.mid),
sender,
@ -95,7 +95,7 @@ describe('MessageRepository', () => {
sentBy: allUsers.find(({ id }) => id === message['sentBy']).id,
}));
expect(messageModel.find).toHaveBeenCalledWith({});
expect(messageModel.find).toHaveBeenCalledWith({}, undefined);
expect(result).toEqualPayload(messages);
});
});

View File

@ -19,7 +19,7 @@ import {
import { AttachmentService } from '@/attachment/services/attachment.service';
import { LoggerService } from '@/logger/logger.service';
import { UserRepository } from '@/user/repositories/user.repository';
import { UserModel, User } from '@/user/schemas/user.schema';
import { User, UserModel } from '@/user/schemas/user.schema';
import {
installSubscriberFixtures,
subscriberFixtures,
@ -31,11 +31,11 @@ import {
rootMongooseTestModule,
} from '@/utils/test/test';
import { LabelModel, Label } from '../schemas/label.schema';
import { Label, LabelModel } from '../schemas/label.schema';
import {
SubscriberModel,
Subscriber,
SubscriberFull,
SubscriberModel,
} from '../schemas/subscriber.schema';
import { LabelRepository } from './label.repository';
@ -119,7 +119,10 @@ describe('SubscriberRepository', () => {
assignedTo: allUsers.find(({ id }) => subscriber.assignedTo === id),
};
expect(subscriberModel.findById).toHaveBeenCalledWith(subscriber.id);
expect(subscriberModel.findById).toHaveBeenCalledWith(
subscriber.id,
undefined,
);
expect(result).toEqualPayload(subscriberWithLabels);
});
});
@ -133,7 +136,7 @@ describe('SubscriberRepository', () => {
pageQuery,
);
expect(subscriberModel.find).toHaveBeenCalledWith({});
expect(subscriberModel.find).toHaveBeenCalledWith({}, undefined);
expect(result).toEqualPayload(
subscribersWithPopulatedFields.sort(sortRowsBy),
);
@ -145,7 +148,7 @@ describe('SubscriberRepository', () => {
jest.spyOn(subscriberModel, 'find');
const result = await subscriberRepository.findAllAndPopulate();
expect(subscriberModel.find).toHaveBeenCalledWith({});
expect(subscriberModel.find).toHaveBeenCalledWith({}, undefined);
expect(result).toEqualPayload(
subscribersWithPopulatedFields.sort(sortRowsBy),
);

View File

@ -170,7 +170,10 @@ describe('BlockService', () => {
jest.spyOn(blockRepository, 'findOneAndPopulate');
const result = await blockService.findOneAndPopulate(block.id);
expect(blockRepository.findOneAndPopulate).toHaveBeenCalledWith(block.id);
expect(blockRepository.findOneAndPopulate).toHaveBeenCalledWith(
block.id,
undefined,
);
expect(result).toEqualPayload({
...blockFixtures.find(({ name }) => name === 'hasNextBlocks'),
category,
@ -196,6 +199,7 @@ describe('BlockService', () => {
expect(blockRepository.findAndPopulate).toHaveBeenCalledWith(
{},
undefined,
undefined,
);
expect(result).toEqualPayload(blocksWithCategory);
});

View File

@ -113,6 +113,7 @@ describe('MessageService', () => {
expect(messageRepository.findOneAndPopulate).toHaveBeenCalledWith(
message.id,
undefined,
);
expect(result).toEqualPayload({
...messageFixtures.find(({ mid }) => mid === message.mid),

View File

@ -88,9 +88,9 @@ describe('ContentTypeController', () => {
describe('findPage', () => {
it('should return all contentTypes', async () => {
const pageQuery = getPageQuery<ContentType>({ sort: ['_id', 'asc'] });
jest.spyOn(contentTypeService, 'findPage');
jest.spyOn(contentTypeService, 'find');
const result = await contentTypeController.findPage(pageQuery, {});
expect(contentTypeService.findPage).toHaveBeenCalledWith({}, pageQuery);
expect(contentTypeService.find).toHaveBeenCalledWith({}, pageQuery);
expect(result).toHaveLength(contentTypeFixtures.length);
expect(result).toEqualPayload(contentTypeFixtures);
});

View File

@ -75,11 +75,7 @@ export class ContentTypeController extends BaseController<ContentType> {
@Query(new SearchFilterPipe<ContentType>({ allowedFields: ['name'] }))
filters: TFilterQuery<ContentType>,
) {
if (pageQuery.limit) {
return await this.contentTypeService.findPage(filters, pageQuery);
}
return await this.contentTypeService.find(filters, pageQuery.sort);
return await this.contentTypeService.find(filters, pageQuery);
}
/**

View File

@ -194,14 +194,9 @@ export class ContentController extends BaseController<
)
filters: TFilterQuery<Content>,
) {
if (pageQuery.limit) {
return this.canPopulate(populate)
? await this.contentService.findPageAndPopulate(filters, pageQuery)
: await this.contentService.findPage(filters, pageQuery);
}
return this.canPopulate(populate)
? await this.contentService.findAndPopulate(filters, pageQuery.sort)
: await this.contentService.find(filters, pageQuery.sort);
? await this.contentService.findAndPopulate(filters, pageQuery)
: await this.contentService.find(filters, pageQuery);
}
/**

View File

@ -76,11 +76,7 @@ export class MenuController extends BaseController<
@Query(new SearchFilterPipe<Menu>({ allowedFields: ['parent'] }))
filters: TFilterQuery<Menu>,
) {
if (pageQuery.limit) {
return await this.menuService.findPage(filters, pageQuery);
}
return await this.menuService.find(filters, pageQuery.sort);
return await this.menuService.find(filters, pageQuery);
}
/**

View File

@ -26,8 +26,8 @@ import {
import { Content, ContentModel } from '../schemas/content.schema';
import {
installContentFixtures,
contentFixtures,
installContentFixtures,
} from './../../utils/test/fixtures/content';
import { ContentRepository } from './content.repository';
@ -63,7 +63,7 @@ describe('ContentRepository', () => {
const content = await contentModel.findOne({ title: 'Jean' });
const contentType = await contentTypeModel.findById(content.entity);
const result = await contentRepository.findOneAndPopulate(content.id);
expect(findSpy).toHaveBeenCalledWith(content.id);
expect(findSpy).toHaveBeenCalledWith(content.id, undefined);
expect(result).toEqualPayload({
...contentFixtures.find(({ title }) => title === 'Jean'),
entity: contentTypeFixtures.find(

View File

@ -84,7 +84,7 @@ describe('ContentService', () => {
const content = await contentService.findOne({ title: 'Jean' });
const contentType = await contentTypeService.findOne(content.entity);
const result = await contentService.findOneAndPopulate(content.id);
expect(findSpy).toHaveBeenCalledWith(content.id);
expect(findSpy).toHaveBeenCalledWith(content.id, undefined);
expect(result).toEqualPayload({
...contentFixtures.find(({ title }) => title === 'Jean'),
entity: contentType,

View File

@ -100,10 +100,10 @@ describe('LanguageController', () => {
describe('findPage', () => {
const pageQuery = getPageQuery<Language>({ sort: ['code', 'asc'] });
it('should find languages', async () => {
jest.spyOn(languageService, 'findPage');
jest.spyOn(languageService, 'find');
const result = await languageController.findPage(pageQuery, {});
expect(languageService.findPage).toHaveBeenCalledWith({}, pageQuery);
expect(languageService.find).toHaveBeenCalledWith({}, pageQuery);
expect(result).toEqualPayload(
languageFixtures.sort(({ code: codeA }, { code: codeB }) => {
if (codeA < codeB) {

View File

@ -57,11 +57,7 @@ export class LanguageController extends BaseController<Language> {
@Query(new SearchFilterPipe<Language>({ allowedFields: ['title', 'code'] }))
filters: TFilterQuery<Language>,
) {
if (pageQuery.limit) {
return await this.languageService.findPage(filters, pageQuery);
}
return await this.languageService.find(filters, pageQuery.sort);
return await this.languageService.find(filters, pageQuery);
}
/**

View File

@ -172,10 +172,10 @@ describe('TranslationController', () => {
describe('findPage', () => {
const pageQuery = getPageQuery<Translation>();
it('should find translations', async () => {
jest.spyOn(translationService, 'findPage');
jest.spyOn(translationService, 'find');
const result = await translationController.findPage(pageQuery, {});
expect(translationService.findPage).toHaveBeenCalledWith({}, pageQuery);
expect(translationService.find).toHaveBeenCalledWith({}, pageQuery);
expect(result).toEqualPayload(translationFixtures);
});
});

View File

@ -55,10 +55,7 @@ export class TranslationController extends BaseController<Translation> {
@Query(new SearchFilterPipe<Translation>({ allowedFields: ['str'] }))
filters: TFilterQuery<Translation>,
) {
if (pageQuery.limit) {
return await this.translationService.findPage(filters, pageQuery);
}
return await this.translationService.find(filters, pageQuery.sort);
return await this.translationService.find(filters, pageQuery);
}
/**

View File

@ -135,15 +135,9 @@ export class NlpEntityController extends BaseController<
@Query(new SearchFilterPipe<NlpEntity>({ allowedFields: ['name', 'doc'] }))
filters: TFilterQuery<NlpEntity>,
) {
if (pageQuery.limit) {
return this.canPopulate(populate)
? await this.nlpEntityService.findPageAndPopulate(filters, pageQuery)
: await this.nlpEntityService.findPage(filters, pageQuery);
}
return this.canPopulate(populate)
? await this.nlpEntityService.findAndPopulate(filters)
: await this.nlpEntityService.find(filters, pageQuery.sort);
? await this.nlpEntityService.findAndPopulate(filters, pageQuery)
: await this.nlpEntityService.find(filters, pageQuery);
}
/**

View File

@ -280,15 +280,9 @@ export class NlpSampleController extends BaseController<
)
filters: TFilterQuery<NlpSample>,
) {
if (pageQuery.limit) {
return this.canPopulate(populate)
? await this.nlpSampleService.findPageAndPopulate(filters, pageQuery)
: await this.nlpSampleService.findPage(filters, pageQuery);
}
return this.canPopulate(populate)
? await this.nlpSampleService.findAndPopulate(filters, pageQuery.sort)
: await this.nlpSampleService.find(filters, pageQuery.sort);
? await this.nlpSampleService.findAndPopulate(filters, pageQuery)
: await this.nlpSampleService.find(filters, pageQuery);
}
/**

View File

@ -146,15 +146,9 @@ export class NlpValueController extends BaseController<
)
filters: TFilterQuery<NlpValue>,
) {
if (pageQuery.limit) {
return this.canPopulate(populate)
? await this.nlpValueService.findPageAndPopulate(filters, pageQuery)
: await this.nlpValueService.findPage(filters, pageQuery);
}
return this.canPopulate(populate)
? await this.nlpValueService.findAndPopulate(filters, pageQuery.sort)
: await this.nlpValueService.find(filters, pageQuery.sort);
? await this.nlpValueService.findAndPopulate(filters, pageQuery)
: await this.nlpValueService.find(filters, pageQuery);
}
/**

View File

@ -78,6 +78,8 @@ describe('SettingController', () => {
{},
{
sort: ['weight', 'asc'],
limit: undefined,
skip: undefined,
},
);

View File

@ -20,7 +20,7 @@ import { CsrfCheck } from '@tekuconcept/nestjs-csrf';
import { CsrfInterceptor } from '@/interceptors/csrf.interceptor';
import { LoggerService } from '@/logger/logger.service';
import { QuerySortDto } from '@/utils/pagination/pagination-query.dto';
import { PageQueryDto } from '@/utils/pagination/pagination-query.dto';
import { PageQueryPipe } from '@/utils/pagination/pagination-query.pipe';
import { SearchFilterPipe } from '@/utils/pipes/search-filter.pipe';
import { TFilterQuery } from '@/utils/types/filter.types';
@ -52,9 +52,9 @@ export class SettingController {
}),
)
filters: TFilterQuery<Setting>,
@Query(PageQueryPipe) { sort }: { sort: QuerySortDto<Setting> },
@Query(PageQueryPipe) pageQuery: PageQueryDto<Setting>,
) {
return await this.settingService.find(filters, sort);
return await this.settingService.find(filters, pageQuery);
}
/**

View File

@ -23,9 +23,9 @@ import { PermissionCreateDto } from '../dto/permission.dto';
import { ModelRepository } from '../repositories/model.repository';
import { PermissionRepository } from '../repositories/permission.repository';
import { RoleRepository } from '../repositories/role.repository';
import { ModelModel, Model } from '../schemas/model.schema';
import { PermissionModel, Permission } from '../schemas/permission.schema';
import { RoleModel, Role } from '../schemas/role.schema';
import { Model, ModelModel } from '../schemas/model.schema';
import { Permission, PermissionModel } from '../schemas/permission.schema';
import { Role, RoleModel } from '../schemas/role.schema';
import { ModelService } from '../services/model.service';
import { PermissionService } from '../services/permission.service';
import { RoleService } from '../services/role.service';

View File

@ -30,7 +30,7 @@ import { PermissionRepository } from '../repositories/permission.repository';
import { RoleRepository } from '../repositories/role.repository';
import { UserRepository } from '../repositories/user.repository';
import { PermissionModel } from '../schemas/permission.schema';
import { RoleModel, Role } from '../schemas/role.schema';
import { Role, RoleModel } from '../schemas/role.schema';
import { UserModel } from '../schemas/user.schema';
import { PermissionService } from '../services/permission.service';
import { RoleService } from '../services/role.service';
@ -96,14 +96,14 @@ describe('RoleController', () => {
describe('findPage', () => {
const pageQuery = getPageQuery<Role>({ sort: ['_id', 'asc'] });
it('should find roles', async () => {
jest.spyOn(roleService, 'findPage');
jest.spyOn(roleService, 'find');
const result = await roleController.findPage(pageQuery, [], {});
expect(roleService.findPage).toHaveBeenCalledWith({}, pageQuery);
expect(roleService.find).toHaveBeenCalledWith({}, pageQuery);
expect(result).toEqualPayload(roleFixtures);
});
it('should find roles, and for each role populate the corresponding users and permissions', async () => {
jest.spyOn(roleService, 'findPageAndPopulate');
jest.spyOn(roleService, 'findAndPopulate');
const allRoles = await roleService.findAll();
const allPermissions = await permissionService.findAll();
const allUsers = await userService.findAll();
@ -128,10 +128,7 @@ describe('RoleController', () => {
return acc;
}, []);
expect(roleService.findPageAndPopulate).toHaveBeenCalledWith(
{},
pageQuery,
);
expect(roleService.findAndPopulate).toHaveBeenCalledWith({}, pageQuery);
expect(result).toEqualPayload(rolesWithPermissionsAndUsers);
});
});

View File

@ -68,15 +68,9 @@ export class RoleController extends BaseController<
@Query(new SearchFilterPipe<Role>({ allowedFields: ['name'] }))
filters: TFilterQuery<Role>,
) {
if (pageQuery.limit) {
return this.canPopulate(populate)
? await this.roleService.findPageAndPopulate(filters, pageQuery)
: await this.roleService.findPage(filters, pageQuery);
}
return this.canPopulate(populate)
? await this.roleService.findAndPopulate(filters, pageQuery.sort)
: await this.roleService.find(filters, pageQuery.sort);
? await this.roleService.findAndPopulate(filters, pageQuery)
: await this.roleService.find(filters, pageQuery);
}
/**

View File

@ -168,15 +168,9 @@ export class ReadOnlyUserController extends BaseController<
)
filters: TFilterQuery<User>,
) {
if (pageQuery.limit) {
return this.canPopulate(populate)
? await this.userService.findPageAndPopulate(filters, pageQuery)
: await this.userService.findPage(filters, pageQuery);
}
return this.canPopulate(populate)
? await this.userService.findAndPopulate(filters, pageQuery.sort)
: await this.userService.find(filters, pageQuery.sort);
? await this.userService.findAndPopulate(filters, pageQuery)
: await this.userService.find(filters, pageQuery);
}
/**

View File

@ -23,7 +23,7 @@ import {
rootMongooseTestModule,
} from '@/utils/test/test';
import { InvitationModel, Invitation } from '../schemas/invitation.schema';
import { Invitation, InvitationModel } from '../schemas/invitation.schema';
import { PermissionModel } from '../schemas/permission.schema';
import { RoleModel } from '../schemas/role.schema';
@ -81,7 +81,10 @@ describe('InvitationRepository', () => {
const result = await invitationRepository.findOneAndPopulate(
invitation.id,
);
expect(invitationModel.findById).toHaveBeenCalledWith(invitation.id);
expect(invitationModel.findById).toHaveBeenCalledWith(
invitation.id,
undefined,
);
expect(result).toEqualPayload({
...toTestAgainst,
roles,
@ -110,7 +113,7 @@ describe('InvitationRepository', () => {
return acc;
}, []);
expect(invitationModel.find).toHaveBeenCalledWith({});
expect(invitationModel.find).toHaveBeenCalledWith({}, undefined);
expect(result).toEqualPayload(invitationsWithRoles);
});
});

View File

@ -56,7 +56,7 @@ describe('ModelRepository', () => {
it('should find a model and populate its permissions', async () => {
jest.spyOn(modelModel, 'findById');
const result = await modelRepository.findOneAndPopulate(model.id);
expect(modelModel.findById).toHaveBeenCalledWith(model.id);
expect(modelModel.findById).toHaveBeenCalledWith(model.id, undefined);
expect(result).toEqualPayload({
...modelFixtures.find(({ name }) => name === 'ContentType'),
permissions,
@ -79,7 +79,7 @@ describe('ModelRepository', () => {
});
return acc;
}, []);
expect(modelModel.find).toHaveBeenCalledWith({});
expect(modelModel.find).toHaveBeenCalledWith({}, undefined);
expect(result).toEqualPayload(modelsWithPermissions);
});
});

View File

@ -24,7 +24,7 @@ import { ModelRepository } from '../repositories/model.repository';
import { PermissionRepository } from '../repositories/permission.repository';
import { RoleRepository } from '../repositories/role.repository';
import { ModelModel } from '../schemas/model.schema';
import { PermissionModel, Permission } from '../schemas/permission.schema';
import { Permission, PermissionModel } from '../schemas/permission.schema';
import { RoleModel } from '../schemas/role.schema';
import { Action } from '../types/action.type';
@ -77,8 +77,12 @@ describe('PermissionRepository', () => {
const model = await modelRepository.findOne(permission.model);
const result = await permissionRepository.findOneAndPopulate(
permission.id,
undefined,
);
expect(permissionModel.findById).toHaveBeenCalledWith(
permission.id,
undefined,
);
expect(permissionModel.findById).toHaveBeenCalledWith(permission.id);
expect(result).toEqualPayload({
...permissionFixtures.find(({ action }) => action === 'create'),
role,
@ -111,7 +115,7 @@ describe('PermissionRepository', () => {
},
[],
);
expect(permissionModel.find).toHaveBeenCalledWith({});
expect(permissionModel.find).toHaveBeenCalledWith({}, undefined);
expect(result).toEqualPayload(permissionsWithRolesAndModels);
});
});

View File

@ -74,7 +74,7 @@ describe('RoleRepository', () => {
jest.spyOn(roleModel, 'findById');
const permissions = await permissionRepository.find({ role: role.id });
const result = await roleRepository.findOneAndPopulate(role.id);
expect(roleModel.findById).toHaveBeenCalledWith(role.id);
expect(roleModel.findById).toHaveBeenCalledWith(role.id, undefined);
expect(result).toEqualPayload({
...roleFixtures.find(({ name }) => name === 'admin'),
users,
@ -106,7 +106,7 @@ describe('RoleRepository', () => {
return acc;
}, []);
expect(roleModel.find).toHaveBeenCalledWith({});
expect(roleModel.find).toHaveBeenCalledWith({}, undefined);
expect(result).toEqualPayload(rolesWithPermissionsAndUsers);
});
});

View File

@ -27,8 +27,8 @@ import { PermissionRepository } from '../repositories/permission.repository';
import { RoleRepository } from '../repositories/role.repository';
import { UserRepository } from '../repositories/user.repository';
import { PermissionModel } from '../schemas/permission.schema';
import { RoleModel, Role } from '../schemas/role.schema';
import { UserModel, User } from '../schemas/user.schema';
import { Role, RoleModel } from '../schemas/role.schema';
import { User, UserModel } from '../schemas/user.schema';
describe('UserRepository', () => {
let roleRepository: RoleRepository;
@ -91,7 +91,7 @@ describe('UserRepository', () => {
it('should find one user and populate its role', async () => {
jest.spyOn(userModel, 'findById');
const result = await userRepository.findOneAndPopulate(user.id);
expect(userModel.findById).toHaveBeenCalledWith(user.id);
expect(userModel.findById).toHaveBeenCalledWith(user.id, undefined);
expect(result).toEqualPayload(
{
...userFixtures.find(({ username }) => username === 'admin'),
@ -118,7 +118,7 @@ describe('UserRepository', () => {
return acc;
}, []);
expect(userModel.find).toHaveBeenCalledWith({});
expect(userModel.find).toHaveBeenCalledWith({}, undefined);
expect(result).toEqualPayload(usersWithRoles);
});
});

View File

@ -77,7 +77,11 @@ describe('AuthService', () => {
'admin@admin.admin',
'adminadmin',
);
expect(userRepository.findOne).toHaveBeenCalledWith(searchCriteria, {});
expect(userRepository.findOne).toHaveBeenCalledWith(
searchCriteria,
{},
undefined,
);
expect(result.id).toBe(user.id);
});
it('should not validate user if the provided password is incorrect', async () => {
@ -85,7 +89,11 @@ describe('AuthService', () => {
'admin@admin.admin',
'randomPassword',
);
expect(userRepository.findOne).toHaveBeenCalledWith(searchCriteria, {});
expect(userRepository.findOne).toHaveBeenCalledWith(
searchCriteria,
{},
undefined,
);
expect(result).toBeNull();
});
@ -99,6 +107,7 @@ describe('AuthService', () => {
email: 'admin2@admin.admin',
},
{},
undefined,
);
expect(result).toBeNull();
});

View File

@ -19,8 +19,8 @@ import {
import { ModelRepository } from '../repositories/model.repository';
import { PermissionRepository } from '../repositories/permission.repository';
import { ModelModel, Model } from '../schemas/model.schema';
import { PermissionModel, Permission } from '../schemas/permission.schema';
import { Model, ModelModel } from '../schemas/model.schema';
import { Permission, PermissionModel } from '../schemas/permission.schema';
import { ModelService } from './model.service';
@ -83,6 +83,7 @@ describe('ModelService', () => {
expect(modelRepository.findAndPopulate).toHaveBeenCalledWith(
{},
undefined,
undefined,
);
expect(result).toEqualPayload(modelsWithPermissions);
});

View File

@ -26,9 +26,9 @@ import { PermissionRepository } from '../repositories/permission.repository';
import { RoleRepository } from '../repositories/role.repository';
import { ModelModel } from '../schemas/model.schema';
import {
PermissionModel,
Permission,
PermissionFull,
PermissionModel,
} from '../schemas/permission.schema';
import { RoleModel } from '../schemas/role.schema';
import { Action } from '../types/action.type';
@ -89,6 +89,7 @@ describe('PermissionService', () => {
const result = await permissionService.findOneAndPopulate(permission.id);
expect(permissionRepository.findOneAndPopulate).toHaveBeenLastCalledWith(
permission.id,
undefined,
);
expect(result).toEqualPayload({
...permissionFixtures.find(({ action }) => action === 'create'),

View File

@ -20,9 +20,9 @@ import {
import { PermissionRepository } from '../repositories/permission.repository';
import { RoleRepository } from '../repositories/role.repository';
import { UserRepository } from '../repositories/user.repository';
import { PermissionModel, Permission } from '../schemas/permission.schema';
import { RoleModel, Role } from '../schemas/role.schema';
import { UserModel, User } from '../schemas/user.schema';
import { Permission, PermissionModel } from '../schemas/permission.schema';
import { Role, RoleModel } from '../schemas/role.schema';
import { User, UserModel } from '../schemas/user.schema';
import { roleFixtures } from './../../utils/test/fixtures/role';
import { RoleService } from './role.service';
@ -72,8 +72,11 @@ describe('RoleService', () => {
describe('findOneAndPopulate', () => {
it('should find one role and populate its permissions and users', async () => {
jest.spyOn(roleRepository, 'findOneAndPopulate');
const result = await roleService.findOneAndPopulate(role.id);
expect(roleRepository.findOneAndPopulate).toHaveBeenCalledWith(role.id);
const result = await roleService.findOneAndPopulate(role.id, undefined);
expect(roleRepository.findOneAndPopulate).toHaveBeenCalledWith(
role.id,
undefined,
);
expect(result).toEqualPayload({
...roleFixtures.find(({ name }) => name == 'admin'),
users,

View File

@ -28,8 +28,8 @@ import { PermissionRepository } from '../repositories/permission.repository';
import { RoleRepository } from '../repositories/role.repository';
import { UserRepository } from '../repositories/user.repository';
import { PermissionModel } from '../schemas/permission.schema';
import { RoleModel, Role } from '../schemas/role.schema';
import { UserModel, User } from '../schemas/user.schema';
import { Role, RoleModel } from '../schemas/role.schema';
import { User, UserModel } from '../schemas/user.schema';
import { PermissionService } from './permission.service';
import { RoleService } from './role.service';
@ -100,7 +100,10 @@ describe('UserService', () => {
it('should find one user and populate its role', async () => {
jest.spyOn(userRepository, 'findOneAndPopulate');
const result = await userService.findOneAndPopulate(user.id);
expect(userRepository.findOneAndPopulate).toHaveBeenCalledWith(user.id);
expect(userRepository.findOneAndPopulate).toHaveBeenCalledWith(
user.id,
undefined,
);
expect(result).toEqualPayload(
{
...userFixtures.find(({ username }) => username === 'admin'),

View File

@ -72,7 +72,7 @@ describe('BaseRepository', () => {
jest.spyOn(dummyModel, 'findById');
const result = await dummyRepository.findOne(createdId);
expect(dummyModel.findById).toHaveBeenCalledWith(createdId);
expect(dummyModel.findById).toHaveBeenCalledWith(createdId, undefined);
expect(result).toEqualPayload({
dummy: 'dummy test 5',
});
@ -82,9 +82,12 @@ describe('BaseRepository', () => {
jest.spyOn(dummyModel, 'findOne');
const result = await dummyRepository.findOne({ dummy: 'dummy test 5' });
expect(dummyModel.findOne).toHaveBeenCalledWith({
dummy: 'dummy test 5',
});
expect(dummyModel.findOne).toHaveBeenCalledWith(
{
dummy: 'dummy test 5',
},
undefined,
);
expect(result).toEqualPayload({
dummy: 'dummy test 5',
});

View File

@ -17,6 +17,7 @@ import {
FlattenMaps,
HydratedDocument,
Model,
ProjectionType,
Query,
SortOrder,
UpdateQuery,
@ -215,48 +216,64 @@ export abstract class BaseRepository<
return plainToClass(cls, doc, options ?? this.transformOpts);
}
protected findOneQuery(criteria: string | TFilterQuery<T>) {
protected findOneQuery(
criteria: string | TFilterQuery<T>,
projection?: ProjectionType<T>,
) {
if (!criteria) {
// An empty criteria would return the first document that it finds
throw new Error('findOneQuery() should not have an empty criteria');
}
return typeof criteria === 'string'
? this.model.findById(criteria)
: this.model.findOne<T>(criteria);
? this.model.findById(criteria, projection)
: this.model.findOne<T>(criteria, projection);
}
async findOne(
criteria: string | TFilterQuery<T>,
options?: ClassTransformOptions,
projection?: ProjectionType<T>,
) {
if (!criteria) {
// @TODO : Issue a warning ?
return Promise.resolve(undefined);
}
const query =
typeof criteria === 'string'
? this.model.findById<T>(criteria)
: this.model.findOne<T>(criteria);
const query = this.findOneQuery(criteria, projection);
return await this.executeOne(query, this.cls, options);
}
async findOneAndPopulate(criteria: string | TFilterQuery<T>) {
async findOneAndPopulate(
criteria: string | TFilterQuery<T>,
projection?: ProjectionType<T>,
) {
this.ensureCanPopulate();
const query = this.findOneQuery(criteria).populate(this.populate);
const query = this.findOneQuery(criteria, projection).populate(
this.populate,
);
return await this.executeOne(query, this.clsPopulate);
}
protected findQuery(filter: TFilterQuery<T>, sort?: QuerySortDto<T>) {
const query = this.model.find<T>(filter);
if (sort) {
return query.sort([sort] as [string, SortOrder][]);
}
return query;
protected findQuery(
filter: TFilterQuery<T>,
pageQuery?: PageQueryDto<T>,
projection?: ProjectionType<T>,
) {
const { skip = 0, limit, sort = ['createdAt', 'asc'] } = pageQuery || {};
const query = this.model.find<T>(filter, projection);
return query
.skip(skip)
.limit(limit)
.sort([sort] as [string, SortOrder][]);
}
async find(filter: TFilterQuery<T>, sort?: QuerySortDto<T>) {
const query = this.findQuery(filter, sort);
async find(
filter: TFilterQuery<T>,
pageQuery?: PageQueryDto<T>,
projection?: ProjectionType<T>,
) {
const query = this.findQuery(filter, pageQuery, projection);
return await this.execute(query, this.cls);
}
@ -266,18 +283,24 @@ export abstract class BaseRepository<
}
}
async findAndPopulate(filters: TFilterQuery<T>, sort?: QuerySortDto<T>) {
async findAndPopulate(
filters: TFilterQuery<T>,
pageQuery?: PageQueryDto<T>,
projection?: ProjectionType<T>,
) {
this.ensureCanPopulate();
const query = this.findQuery(filters, sort).populate(this.populate);
const query = this.findQuery(filters, pageQuery, projection).populate(
this.populate,
);
return await this.execute(query, this.clsPopulate);
}
protected findAllQuery(sort?: QuerySortDto<T>) {
return this.findQuery({}, sort);
return this.findQuery({}, { limit: undefined, skip: undefined, sort });
}
async findAll(sort?: QuerySortDto<T>) {
return await this.find({}, sort);
return await this.find({}, { limit: undefined, skip: undefined, sort });
}
async findAllAndPopulate(sort?: QuerySortDto<T>) {
@ -286,6 +309,9 @@ export abstract class BaseRepository<
return await this.execute(query, this.clsPopulate);
}
/**
* @deprecated
*/
protected findPageQuery(
filters: TFilterQuery<T>,
{ skip, limit, sort }: PageQueryDto<T>,
@ -296,6 +322,9 @@ export abstract class BaseRepository<
.sort([sort] as [string, SortOrder][]);
}
/**
* @deprecated
*/
async findPage(
filters: TFilterQuery<T>,
pageQuery: PageQueryDto<T>,
@ -304,6 +333,9 @@ export abstract class BaseRepository<
return await this.execute(query, this.cls);
}
/**
* @deprecated
*/
async findPageAndPopulate(
filters: TFilterQuery<T>,
pageQuery: PageQueryDto<T>,

View File

@ -58,6 +58,7 @@ describe('BaseService', () => {
expect(dummyRepository.findOne).toHaveBeenCalledWith(
createdId,
undefined,
undefined,
);
expect(result).toEqualPayload(createdPayload);
});
@ -69,6 +70,7 @@ describe('BaseService', () => {
expect(dummyRepository.findOne).toHaveBeenCalledWith(
createdPayload,
undefined,
undefined,
);
expect(result).toEqualPayload(createdPayload);
});

View File

@ -9,6 +9,7 @@
import { ConflictException } from '@nestjs/common';
import { ClassTransformOptions } from 'class-transformer';
import { MongoError } from 'mongodb';
import { ProjectionType } from 'mongoose';
import { TFilterQuery } from '@/utils/types/filter.types';
@ -31,20 +32,36 @@ export abstract class BaseService<
async findOne(
criteria: string | TFilterQuery<T>,
options?: ClassTransformOptions,
projection?: ProjectionType<T>,
): Promise<T> {
return await this.repository.findOne(criteria, options);
return await this.repository.findOne(criteria, options, projection);
}
async findOneAndPopulate(criteria: string | TFilterQuery<T>) {
return await this.repository.findOneAndPopulate(criteria);
async findOneAndPopulate(
criteria: string | TFilterQuery<T>,
projection?: ProjectionType<T>,
) {
return await this.repository.findOneAndPopulate(criteria, projection);
}
async find(filter: TFilterQuery<T>, sort?: QuerySortDto<T>): Promise<T[]> {
return await this.repository.find(filter, sort);
async find(
filter: TFilterQuery<T>,
pageQuery?: PageQueryDto<T>,
projection?: ProjectionType<T>,
): Promise<T[]> {
return await this.repository.find(filter, pageQuery, projection);
}
async findAndPopulate(filters: TFilterQuery<T>, sort?: QuerySortDto<T>) {
return await this.repository.findAndPopulate(filters, sort);
async findAndPopulate(
filters: TFilterQuery<T>,
pageQuery?: PageQueryDto<T>,
projection?: ProjectionType<T>,
) {
return await this.repository.findAndPopulate(
filters,
pageQuery,
projection,
);
}
async findAll(sort?: QuerySortDto<T>): Promise<T[]> {
@ -55,6 +72,9 @@ export abstract class BaseService<
return await this.repository.findAllAndPopulate(sort);
}
/**
* @deprecated
*/
async findPage(
filters: TFilterQuery<T>,
pageQueryDto: PageQueryDto<T>,
@ -62,6 +82,9 @@ export abstract class BaseService<
return await this.repository.findPage(filters, pageQueryDto);
}
/**
* @deprecated
*/
async findPageAndPopulate(
filters: TFilterQuery<T>,
pageQueryDto: PageQueryDto<T>,