import 'reflect-metadata' ; export interface ProjectionOptions { } export function Projection ( target ) ; export function Projection ( options ) ; export function Projection ( options ? ) { if ( typeof options === 'function' ) { projection ( options ) ; } else { return ( target ) => projection ( target , options ) ; } } export interface ProjectionConfiguration { properties : PropertyConfiguration [ ] ; options ? : ProjectionOptions ; } function projection ( target , options ? ) { if ( ! Reflect . hasMetadata ( 'projection' , target . prototype ) ) { throw new Error ( `Class ${ target . name } has a @Projection but is missing a @Property` ) ; } else { const projection = Reflect . getMetadata ( 'projection' , target . prototype ) ; projection . options = options ; Reflect . defineMetadata ( 'projection' , projection , target ) ; } } export type JoinType = 'left' | 'right' ; export type Transformer = ( value : any ) => any ; export interface PropertyOptions { property ? : string ; joinType ? : JoinType ; transform ? : Transformer ; } export interface PropertyConfiguration { propertyType : any ; projectionProperty : string ; modelProperty : string ; options ? : PropertyOptions ; } export function Property ( target ) ; export function Property ( options ) ; export function Property ( target , propertyName , propertyDescriptor ? ) ; export function Property ( ... args ) { if ( args . length >= 2 ) { const target = args [ 0 ] ; const propertyName = args [ 1 ] ; property ( target , propertyName ) ; return ; } return ( target , propertyName ) => { property ( target , propertyName , args [ 0 ] ) ; } ; } function property ( target , propertyName , options ? ) { if ( ! Reflect . hasMetadata ( 'projection' , target ) ) { Reflect . defineMetadata ( 'projection' , { properties : [ ] , options : { } } , target ) ; } const type = Reflect . getMetadata ( 'design:type' , target , propertyName ) ; const projection = Reflect . getMetadata ( 'projection' , target ) ; projection . properties . push ( { projectionProperty : propertyName , modelProperty : options && options . property || propertyName , propertyType : type , options } ) ; }