import * as Sequelize from 'sequelize' ; import { decorate , injectable } from 'inversify' ; import { IBaseRepository } from '../IBaseRepository' ; import { ApiError } from '../../config/ErrorHandler' ; import constants from '../../config/constants' ; import { cleanQuery , safeParse , isId } from '../../utils' ; import { BaseEntity } from './entities/BaseEntity' ; export abstract class BaseRepository < EntityType > implements IBaseRepository < EntityType > { protected formatter : any = Object ; protected entityModel : BaseEntity ; protected getInclude : Sequelize . IncludeOptions [ ] = [ ] ; protected saveInclude : Sequelize . IncludeOptions [ ] = [ ] ; public async create ( model , include = this . saveInclude ) { const res = await this . entityModel . model . create ( this . cleanToSave ( model ) , { include } ) ; return new this . formatter ( res ) ; } public async update ( _id , model , include = this . saveInclude ) { await this . entityModel . model . update ( this . cleanToSave ( model ) , { where : { _id } } ) ; } public async delete ( _id ) { const n = await this . entityModel . model . destroy ( { where : { _id } } ) ; return { n } ; } public async find ( offset = 0 , limit = 250 , sort , query , include = this . getInclude ) { const sortObject = this . cleanSort ( sort ) ; const order = Object . keys ( sortObject ) . map ( key => [ key , sortObject [ key ] ] ) ; const where = this . cleanWhere ( query ) ; const options = { include , where , limit , offset } ; if ( order ) options . order = order ; return ( await this . entityModel . model . findAll ( options ) ) . map ( item => new this . formatter ( item ) ) ; } public async findOne < T > ( where , include = this . getInclude ) { const res = await this . entityModel . model . findOne ( { where , include } ) ; if ( ! res ) throw new ApiError ( constants . errorTypes . notFound ) ; return new this . formatter ( res ) ; } public async count ( query ) { return this . entityModel . model . count ( { where : this . cleanWhere ( query ) } ) ; } protected cleanToSave ( entity ) { const copy = new this . formatter ( entity ) ; const loop = ( value ) : any => { if ( ! value || typeof value !== 'object' ) return ; /** formatting logic to save goes here */ Object . keys ( value ) . forEach ( key => loop ( value [ key ] ) ) ; } ; loop ( copy ) ; return copy ; } protected sortQueryFormatter ( key , value ) { if ( value === 'asc' ) return 'asc' ; if ( value === 'desc' ) return 'desc' ; return undefined ; } protected whereQueryFormatter = ( key , value ) : any => { value = safeParse ( value , value ) ; if ( value instanceof Array ) return { [ Sequelize . Op . or ] : value . map ( v => this . whereQueryFormatter ( key , v ) ) } ; else if ( isId ( key ) ) return { [ Sequelize . Op . eq ] : value } ; else if ( typeof value === 'string' ) return { [ Sequelize . Op . like ] : `%${ value }%` } ; else return { [ Sequelize . Op . eq ] : value } ; } ; protected cleanSort ( sort ) { return cleanQuery ( sort , this . sortQueryFormatter ) ; } protected cleanWhere ( query ) { return cleanQuery ( query , this . whereQueryFormatter ) ; } } decorate ( injectable ( ) , BaseRepository ) ;