Skip to content

Instantly share code, notes, and snippets.

@yobayob
Created June 26, 2018 12:06
Show Gist options
  • Save yobayob/109e6093df36dd931cd3695267f25c10 to your computer and use it in GitHub Desktop.
Save yobayob/109e6093df36dd931cd3695267f25c10 to your computer and use it in GitHub Desktop.
supermodel.ts
import * as mongoose from 'mongoose';
import {
Connection,
connection,
Model,
Schema,
Document,
Error,
} from 'mongoose';
import {ApplicationError} from '../error';
const SAVE_METHODS = [`save`, `update`, `findOneAndUpdate`, `insertMany`];
/**
* This is wrapper on default mongoose model.
* Supermodel can use as injectable arg in constructor to another class and
* it used mongoose sequence.
*/
abstract class SuperModel<T extends Document> {
public static connection: Connection = connection;
private schema: Schema;
/**
* current model
* yon can't access to object properties from controller
* every model must be extend from SuperModel and override
* needed methods
*/
protected readonly objects: Model<T>;
/**
* Handling errors from mongodb
* More code and errors - https://github.com/mongodb/mongo/blob/master/src/mongo/base/error_codes.err
*/
public static handleErrors(name: string) {
return async (error: any, res: any, next: any) => {
if (error.name === `MongoError` && error.code === 11000) {
await next(new ApplicationError(`The ${name} returned a duplicate error`, 400));
} else {
await next();
}
}
}
constructor(modelName: string, schema: Schema) {
this.createHandlers(modelName, schema);
this.prepareToJson(modelName, schema);
this.objects = this.createModel(modelName, schema);
this.schema = schema;
}
private prepareToJson(modelName: string, schema: Schema): void {
schema.set('toJSON', {
transform: (doc: any, ret: any, options: any) => {
ret.id = ret._id;
delete ret._id;
delete ret.__v;
return ret;
},
});
}
private createHandlers(modelName: string, schema: Schema): void {
const handlerError = SuperModel.handleErrors(modelName);
SAVE_METHODS.forEach((item) => {
schema.post(item, handlerError)
});
}
private createModel(modelName: string, schema: Schema): Model<T> {
return SuperModel.connection.model(modelName, schema) as Model<T>;
}
/**
* List of all items
*/
public all() {
return this.objects.find();
}
/**
* Create item. If item not found throw Application Error
*/
public create(obj: any) {
return this.objects.create(obj);
}
/**
* Get item. If item not found throw Application Error
*/
public async get(obj: any) {
const res = await this.objects.findOne(obj);
if (res) {
return res
}
// leave obj fields up to logger
// throw new ApplicationError(`Object with params ${JSON.stringify(obj)} not found`, 404)
throw new ApplicationError('Object not found', 404);
}
/**
* Filter items
*/
public filter(obj: any) {
return this.objects.find(obj);
}
/**
* returned updated object
*/
public updateOne(obj: any, update: any) {
return this.objects.findOneAndUpdate(obj, update, {new: true});
}
/**
* Remove item. If item not found throw Application Error
*/
public async delete(obj: any) {
const item = await this.get(obj);
if (item) {
await item.remove();
}
}
}
export default SuperModel;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment