Skip to content

Instantly share code, notes, and snippets.

@nartc
Last active Oct 3, 2021
Embed
What would you like to do?
import { InternalServerErrorException } from '@nestjs/common';
import { DocumentType, ReturnModelType } from '@typegoose/typegoose';
import { MongoError } from 'mongodb';
import {
EnforceDocument,
FilterQuery,
QueryOptions as MongooseQueryOptions,
QueryWithHelpers,
Types,
UpdateQuery,
UpdateWithAggregationPipeline
} from 'mongoose';
import { BaseModel } from './base.model';
interface QueryOptions {
lean?: boolean;
autopopulate?: boolean;
}
export type EnforceDocumentType<TModel extends BaseModel> = EnforceDocument<DocumentType<TModel>, Record<string, unknown>>;
export type QueryList<TModel extends BaseModel> = QueryWithHelpers<Array<EnforceDocumentType<TModel>>, EnforceDocumentType<TModel>>;
export type QueryItem<TModel extends BaseModel> = QueryWithHelpers<EnforceDocumentType<TModel>, EnforceDocumentType<TModel>>;
export type ModelType<TModel extends BaseModel> = ReturnModelType<new (...args: unknown[]) => TModel>;
export abstract class BaseRepository<TModel extends BaseModel> {
protected constructor(protected model: ModelType<TModel>) {
}
private static get defaultOptions(): QueryOptions {
return { lean: true, autopopulate: true };
}
private static getQueryOptions(options?: QueryOptions) {
const mergedOptions = {
...BaseRepository.defaultOptions,
...(options || {})
};
const option = mergedOptions.lean ? { virtuals: true } : null;
if (option && mergedOptions.autopopulate) {
option['autopopulate'] = true;
}
return { lean: option, autopopulate: mergedOptions.autopopulate };
}
protected static throwMongoError(err: MongoError): void {
throw new InternalServerErrorException(err, err.errmsg);
}
createModel(doc?: Partial<TModel>): TModel {
return new this.model(doc);
}
findAll(options?: QueryOptions): QueryList<TModel> {
return this.model.find().setOptions(BaseRepository.getQueryOptions(options));
}
findOne(options?: QueryOptions): QueryItem<TModel> {
return this.model.findOne().setOptions(BaseRepository.getQueryOptions(options));
}
findById(id: string, options?: QueryOptions): QueryItem<TModel> {
return this.model
.findById(Types.ObjectId(id))
.setOptions(BaseRepository.getQueryOptions(options));
}
async create(item: TModel): Promise<DocumentType<TModel>> {
try {
return await this.model.create(item);
} catch (e) {
BaseRepository.throwMongoError(e);
}
}
deleteOne(options?: QueryOptions): QueryItem<TModel> {
return this.model.findOneAndDelete().setOptions(BaseRepository.getQueryOptions(options));
}
deleteById(id: string, options?: QueryOptions): QueryItem<TModel> {
return this.model
.findByIdAndDelete(Types.ObjectId(id))
.setOptions(BaseRepository.getQueryOptions(options));
}
update(item: TModel, options?: QueryOptions): QueryItem<TModel> {
return this.model
.findByIdAndUpdate(Types.ObjectId(item.id), { $set: item } as unknown as UpdateWithAggregationPipeline, {
omitUndefined: true,
new: true
})
.setOptions(BaseRepository.getQueryOptions(options));
}
updateById(
id: string,
updateQuery: UpdateQuery<DocumentType<TModel>>,
updateOptions: MongooseQueryOptions & { multi?: boolean } = {},
options?: QueryOptions
): QueryItem<TModel> {
return this.updateByFilter(
{ _id: Types.ObjectId(id) } as FilterQuery<DocumentType<TModel>> ,
updateQuery,
updateOptions,
options
);
}
updateByFilter(
filter: FilterQuery<DocumentType<TModel>> = {},
updateQuery: UpdateQuery<DocumentType<TModel>>,
updateOptions: MongooseQueryOptions = {},
options?: QueryOptions
): QueryItem<TModel> {
return this.model
.findOneAndUpdate(filter, updateQuery, {
...Object.assign({ omitUndefined: true }, updateOptions),
new: true
})
.setOptions(BaseRepository.getQueryOptions(options));
}
count(filter: FilterQuery<DocumentType<TModel>> = {}): QueryWithHelpers<number, EnforceDocumentType<TModel>> {
return this.model.count(filter);
}
async countAsync(filter: FilterQuery<DocumentType<TModel>> = {}): Promise<number> {
try {
return await this.count(filter);
} catch (e) {
BaseRepository.throwMongoError(e);
}
}
async exists(filter: FilterQuery<DocumentType<TModel>> = {}): Promise<boolean> {
try {
return await this.model.exists(filter);
} catch (e) {
BaseRepository.throwMongoError(e);
}
}
}
@devlegacy

This comment has been minimized.

Copy link

@devlegacy devlegacy commented Sep 28, 2021

How can contributed?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment