feat: add projection to the base logic

This commit is contained in:
yassinedorbozgithub 2024-12-04 08:06:25 +01:00
parent de459fcbac
commit a33c9f2510
2 changed files with 56 additions and 32 deletions

View File

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

View File

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