module import { hasGenericType , PropertyMetadata } from '../../decorator/metadata/property-metadata.model' ; import { notNull } from '../../helper/not-null.function' ; import { fromDb , fromDbOne , toDb , toDbOne } from '../mapper' ; import { AttributeCollectionType } from '../type/attribute-type.type' ; import { BinarySetAttribute , ListAttribute , MapAttribute , NullAttribute , NumberSetAttribute , StringSetAttribute , } from '../type/attribute.type' ; import { detectCollectionTypeFromValue , isBufferType , isHomogeneous , isSet } from '../util' ; import { MapperForType } from './base.mapper' ; type CollectionAttributeTypes = StringSetAttribute | NumberSetAttribute | BinarySetAttribute | ListAttribute | NullAttribute ; function collectionFromDb ( attributeValue , propertyMetadata ? ) { const explicitType = propertyMetadata && propertyMetadata . typeInfo ? propertyMetadata . typeInfo . type : null ; let arr ; if ( 'L' in attributeValue ) { if ( hasGenericType ( propertyMetadata ) ) { arr = attributeValue . L . map ( ( item ) => fromDb ( ( < MapAttribute > item ) . M , propertyMetadata . typeInfo . genericType ) ) ; } else { arr = attributeValue . L . map ( ( v ) => fromDbOne ( v ) ) ; } return explicitType && explicitType === Set ? new Set ( arr ) : arr ; } else if ( 'SS' in attributeValue ) { arr = attributeValue . SS ; } else if ( 'NS' in attributeValue ) { arr = attributeValue . NS . map ( parseFloat ) ; } else if ( 'BS' in attributeValue ) { arr = attributeValue . BS ; } else { throw new Error ( `No Collection Data (SS | NS | BS | L) was found in attribute data, given attributeValue: ${ JSON . stringify ( attributeValue ) }` ) ; } return explicitType && explicitType === Array ? arr : new Set ( arr ) ; } function collectionToDb ( propertyValue , propertyMetadata ? ) { if ( ! ( Array . isArray ( propertyValue ) || isSet ( propertyValue ) ) ) { throw new Error ( `Given value must be either Array or Set ${ JSON . stringify ( propertyValue ) }` ) ; } let collectionType ; if ( propertyMetadata ) { collectionType = detectCollectionTypeFromMetadata ( propertyMetadata , propertyValue ) ; } else { collectionType = detectCollectionTypeFromValue ( propertyValue ) ; } propertyValue = isSet ( propertyValue ) ? Array . from ( propertyValue ) : propertyValue ; if ( collectionType !== 'L' && propertyValue . length === 0 ) { return null ; } switch ( collectionType ) { case 'SS' : return { SS : propertyValue } ; case 'NS' : return { NS : propertyValue . map ( ( num ) => num . toString ( ) ) } ; case 'BS' : return { BS : propertyValue } ; case 'L' : if ( hasGenericType ( propertyMetadata ) ) { return { L : propertyValue . map ( ( value ) => ( { M : toDb ( value , propertyMetadata . typeInfo . genericType ) , } ) ) , } ; } else { return { L : propertyValue . map ( ( v ) => toDbOne ( v ) ) . filter ( notNull ) , } ; } } } export const CollectionMapper = { fromDb : collectionFromDb , toDb : collectionToDb , } ; function detectCollectionTypeFromMetadata ( propertyMetadata , propertyValue ) { const explicitType = propertyMetadata && propertyMetadata . typeInfo ? propertyMetadata . typeInfo . type : null ; if ( ! ( explicitType === Array || explicitType === Set ) ) { throw new Error ( `only 'Array' and 'Set' are valid values for explicit type, found ${ explicitType } on value ${ JSON . stringify ( propertyValue ) }` ) ; } if ( propertyMetadata . isSortedCollection ) { return 'L' ; } if ( hasGenericType ( propertyMetadata ) ) { if ( isBufferType ( propertyMetadata . typeInfo . genericType ) ) { return 'BS' ; } switch ( propertyMetadata . typeInfo . genericType ) { case String : return 'SS' ; case Number : return 'NS' ; default : return 'L' ; } } if ( explicitType === Array ) { return 'L' ; } if ( [ ... propertyValue ] . length === 0 ) { return 'SS' ; } else { const { homogeneous , type } = isHomogeneous ( propertyValue ) ; if ( homogeneous ) { switch ( type ) { case 'S' : return 'SS' ; case 'N' : return 'NS' ; case 'B' : return 'BS' ; } } return 'L' ; } }