import { Mapping } from './Mapping' ; import { QueryBuilder } from './QueryBuilder' ; import * as knex from 'knex' ; import { Store } from './Store' ; import { EntityCtor } from './EntityInterface' ; import { EntityManager } from './EntityManager' ; import { Scope } from './Scope' ; export class EntityRepository < T > { type { EntityManager | Scope } protected entityManager : EntityManager | Scope ; type { { } } protected entity : EntityCtor < T > ; type { Mapping } protected mapping : Mapping < T > ; type { string [ ] } protected queryOptions : Array < string > = [ 'orderBy' , 'limit' , 'offset' , 'groupBy' , 'select' ] ; param { EntityManager | Scope } entityManager param { { } } entity public constructor ( entityManager , entity ) { this . entityManager = entityManager ; this . entity = entity ; this . mapping = Mapping . forEntity ( entity ) ; } returns { Mapping } public getMapping ( ) { return this . mapping ; } param { string } alias param { knex . QueryBuilder } statement param { boolean } managed returns { QueryBuilder } public getQueryBuilder ( alias ? , statement ? , managed = true ) { const builderAlias = this . getAlias ( alias ) ; return new QueryBuilder ( this . getScope ( ) , this . getStatement ( builderAlias , statement ) , this . mapping , builderAlias , managed ) ; } param { string } alias protected getAlias ( alias ? ) { return alias || this . mapping . getTableName ( ) ; } param { string } alias param { knex . QueryBuilder } statement returns { knex . QueryBuilder } protected getStatement ( alias , statement ? ) { if ( statement ) { return statement ; } const connection = this . getConnection ( ) ; return connection ( `${ this . mapping . getTableName ( ) } as ${ alias }` ) ; } param { QueryBuilder } derivedFrom param { string } alias returns { QueryBuilder } public getDerivedQueryBuilder ( derivedFrom , alias ? ) { return this . getQueryBuilder ( ) . from ( derivedFrom , alias ) ; } param { string } role returns { knex } public getConnection ( role = Store . ROLE_SLAVE ) { return this . entityManager . getStore ( this . entity ) . getConnection ( role ) ; } param { { } } criteria param { FindOptions } options returns { QueryBuilder } public prepareFindQuery ( criteria ? , options = { } ) { options . alias = options . alias || this . mapping . getTableName ( ) ; const queryBuilder = this . getQueryBuilder ( options . alias ) ; if ( ! options . select ) { queryBuilder . select ( options . alias ) ; } if ( criteria ) { queryBuilder . where ( criteria ) ; } if ( options . page && options . limit ) { options . offset = ( options . page - 1 ) * options . limit ; } this . applyOptions ( queryBuilder , options ) ; if ( ! options . populate ) { return queryBuilder ; } if ( options . populate === true ) { const relations = this . mapping . getRelations ( ) ; if ( typeof relations === 'object' && relations !== null ) { options . populate = Reflect . ownKeys ( relations ) ; } } else if ( typeof options . populate === 'string' ) { options . populate = [ options . populate ] ; } if ( Array . isArray ( options . populate ) && options . populate . length ) { options . populate . forEach ( join => { let column = join as string ; let alias = join as string ; if ( typeof join === 'object' ) { column = Object . keys ( join ) [ 0 ] ; alias = join [ column ] ; } else if ( join . indexOf ( '.' ) > - 1 ) { alias = join . split ( '.' ) [ 1 ] ; } const targetBuilder = queryBuilder . quickJoin ( column , alias ) ; if ( ! options . select ) { targetBuilder . select ( alias ) ; } } ) ; } else if ( options . populate && ! Array . isArray ( options . populate ) ) { Object . getOwnPropertyNames ( options . populate ) . forEach ( column => { const targetBuilder = queryBuilder . quickJoin ( column , options . populate [ column ] ) ; if ( ! options . select ) { targetBuilder . select ( options . populate [ column ] ) ; } } ) ; } return queryBuilder ; } param { { } } criteria param { FindOptions } options returns { Promise < Array > } public find ( criteria ? , options = { } ) { return this . prepareFindQuery ( criteria , options ) . getQuery ( ) . getResult ( ) ; } param { { } | number | string } criteria param { FindOptions } options returns { Promise < Object > } public findOne ( criteria ? , options = { } ) { options . alias = options . alias || this . mapping . getTableName ( ) ; if ( typeof criteria === 'number' || typeof criteria === 'string' ) { criteria = { [ options . alias + '.' + this . mapping . getPrimaryKeyField ( ) ] : criteria } ; } options . limit = 1 ; return this . find ( criteria , options ) . then ( result => result ? result [ 0 ] : null ) ; } param { QueryBuilder < T > } queryBuilder param { FindOptions } options returns { QueryBuilder } public applyOptions ( queryBuilder , options ) { this . queryOptions . forEach ( clause => { if ( options [ clause ] ) { queryBuilder [ clause ] ( options [ clause ] ) ; } } ) ; return queryBuilder ; } returns { EntityManager | Scope } protected getEntityManager ( ) { return this . entityManager ; } returns { Scope } protected getScope ( ) { if ( this . entityManager instanceof Scope ) { return this . entityManager ; } return this . entityManager . createScope ( ) ; } } export interface FindOptions { select ? : Array < string > ; orderBy ? : any ; groupBy ? : any ; alias ? : string ; page ? : number ; limit ? : number ; offset ? : number ; debug ? : boolean ; populate ? : string | boolean | { } | Array < string | { } > ; }