Created
June 26, 2018 12:06
-
-
Save yobayob/109e6093df36dd931cd3695267f25c10 to your computer and use it in GitHub Desktop.
supermodel.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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