module import { NESTED_ATTR_PATH_CAPTURED_REGEX , NESTED_ATTR_PATH_REGEX , } from '../../dynamo/expression/functions/attribute-names.const' ; import { ModelConstructor } from '../../model/model-constructor' ; import { Omit } from '../../model/omit.type' ; import { SecondaryIndex } from '../impl/index/secondary-index' ; import { KEY_MODEL } from '../impl/model/key-model.const' ; import { ModelMetadata } from './model-metadata.model' ; import { PropertyMetadata } from './property-metadata.model' ; hidden export type MetadataWithSortKey < T > = Omit < Metadata < T > , 'getSortKey' > & { getSortKey : ( indexName ? : string ) => keyof T ; } ; hidden export function hasSortKey < T > ( metadata ) { return metadata . getSortKey ( ) !== null ; } export class Metadata < T > { readonly modelOptions : ModelMetadata < T > ; private static findMetaDataForProperty < M > ( modelOpts , propertyName ) { return modelOpts . properties . find ( ( property ) => property . name === propertyName || property . nameDb === propertyName ) ; } constructor ( modelConstructor ) { this . modelOptions = Reflect . getMetadata ( KEY_MODEL , modelConstructor ) ; } forProperty ( propertyKey ) { if ( this . modelOptions . properties . length === 0 ) { return ; } if ( typeof propertyKey === 'string' && NESTED_ATTR_PATH_REGEX . test ( < string > propertyKey ) ) { const regex = new RegExp ( NESTED_ATTR_PATH_CAPTURED_REGEX ) ; let re ; let currentMeta = this . modelOptions ; let lastPropMeta ; let lastPathPart = '' ; while ( ( re = regex . exec ( < string > propertyKey ) ) !== null ) { lastPathPart = re [ 1 ] ; lastPropMeta = Metadata . findMetaDataForProperty ( currentMeta , < any > lastPathPart ) ; if ( lastPropMeta && lastPropMeta . typeInfo ) { currentMeta = new Metadata ( lastPropMeta . typeInfo . genericType || lastPropMeta . typeInfo . type ) . modelOptions ; } else { break ; } } if ( lastPropMeta && ( lastPathPart === lastPropMeta . name || lastPathPart === lastPropMeta . nameDb ) ) { return lastPropMeta ; } } else { return Metadata . findMetaDataForProperty ( this . modelOptions , < keyof T > propertyKey ) ; } return ; } returns { Array < PropertyMetadata < any > > } getPropertiesWithDefaultValueProvider ( ) { return filterBy ( this . modelOptions , p => ! ! p . defaultValueProvider , [ ] ) ; } param { string } indexName returns { string } throws throws getPartitionKey ( indexName ? ) { if ( indexName ) { const index = this . getIndex ( indexName ) ; if ( index ) { if ( index . partitionKey ) { return index . partitionKey ; } else { throw new Error ( 'the index exists but no partition key for it was defined. use @GSIPartitionKey(indexName)' ) ; } } else { throw new Error ( `there is no index defined for name ${ indexName }` ) ; } } else { const property = filterByFirst ( this . modelOptions , ( p ) => ! ! ( p . key && p . key . type === 'HASH' ) ) ; if ( property ) { return property . name ; } else { throw new Error ( 'could not find any partition key' ) ; } } } param { string } indexName returns { keyof T } throws getSortKey ( indexName ? ) { if ( indexName ) { const index = this . getIndex ( indexName ) ; if ( index ) { if ( index . sortKey ) { return index . sortKey ; } else { throw new Error ( `there is no sort key defined for index ${ indexName }` ) ; } } else { throw new Error ( `there is no index defined for name ${ indexName }` ) ; } } else { const property = filterByFirst ( this . modelOptions , ( p ) => ! ! ( p . key && p . key . type === 'RANGE' ) ) ; return property ? property . name : null ; } } returns { SecondaryIndex [ ] } getIndexes ( ) { return Array . from ( this . modelOptions . indexes . values ( ) ) ; } param { string } indexName returns { SecondaryIndex } getIndex ( indexName ) { return this . modelOptions . indexes . get ( indexName ) || null ; } } hidden function filterBy < T , R > ( modelOptions , predicate , defaultValue ) { if ( modelOptions ) { const properties = modelOptions . properties . filter ( predicate ) ; if ( properties . length ) { return properties ; } } return defaultValue ; } hidden function filterByFirst < T > ( modelOptions , predicate ) { const properties = filterBy ( modelOptions , predicate , null ) ; return properties && properties . length ? properties [ 0 ] : null ; }