module import { PropertyMetadata } from '../decorator/metadata/property-metadata.model' ; import { isBoolean } from '../helper/is-boolean.function' ; import { isNumber } from '../helper/is-number.function' ; import { isString } from '../helper/is-string.function' ; import { ModelConstructor } from '../model/model-constructor' ; import { AttributeCollectionType , AttributeType } from './type/attribute-type.type' ; import { AttributeValueType } from './type/attribute-value-type.type' ; import { Attribute } from './type/attribute.type' ; import { Binary } from './type/binary.type' ; import { NullType } from './type/null.type' ; import { UndefinedType } from './type/undefined.type' ; hidden export function getPropertyPath < T > ( modelConstructorOrPropertyMetadata , propertyKey ) { if ( modelConstructorOrPropertyMetadata && modelConstructorOrPropertyMetadata . name ) { return `[${ modelConstructorOrPropertyMetadata . name }::${ propertyKey }]` ; } else { return `[unknown::${ propertyKey }]` ; } } hidden export function messageWithPath ( propertyPath , message ) { if ( ! ! propertyPath ) { return `${ propertyPath } ${ message }` ; } else { return `${ message }` ; } } hidden const BUFFER_TYPES = [ 'Buffer' , 'File' , 'Blob' , 'ArrayBuffer' , 'DataView' , 'Int8Array' , 'Uint8Array' , 'Uint8ClampedArray' , 'Int16Array' , 'Uint16Array' , 'Int32Array' , 'Uint32Array' , 'Float32Array' , 'Float64Array' , ] ; param { any [ ] | Set < any > } collection returns { AttributeCollectionType } hidden export function detectCollectionTypeFromValue ( collection ) { if ( Array . isArray ( collection ) ) { return 'L' ; } else if ( isSet ( collection ) ) { if ( collection . size ) { const { homogeneous , type } = isHomogeneous ( collection ) ; if ( homogeneous ) { switch ( type ) { case 'S' : return 'SS' ; case 'N' : return 'NS' ; case 'B' : return 'BS' ; default : throw new Error ( `"Set<CustomType>" without decorator is not supported. Add the @CollectionProperty() decorator (optionally with {itemType:CustomType}) for a Set<->[L]ist mapping)` ) ; } } else { throw new Error ( `"Set with values of different types without decorator is not supported. Use an array instead.` ) ; } } else { return 'SS' ; } } else { throw new Error ( 'given collection was neither array nor Set -> type could not be detected' ) ; } } hidden export function isHomogeneous ( collection ) { const collectionAsArray = isSet ( collection ) ? Array . from ( collection ) : collection ; const firstValueType = collectionAsArray . length ? detectType ( collectionAsArray [ 0 ] ) : null ; let homogeneous = true ; for ( const item of collectionAsArray ) { const type = detectType ( item ) ; if ( type !== firstValueType ) { homogeneous = false ; break ; } } if ( homogeneous ) { return { homogeneous : true , type : firstValueType } ; } else { return { homogeneous : false } ; } } hidden export function isCollection ( value ) { return value && ( Array . isArray ( value ) || isSet ( value ) ) ; } hidden export function isSet ( value ) { return ( ( value !== null && value !== undefined && value . hasOwnProperty ( 'name' ) && value . name === 'Set' ) || value instanceof Set ) ; } hidden export function detectType ( value ) { if ( isString ( value ) ) { return 'S' ; } else if ( isNumber ( value ) ) { return 'N' ; } else if ( isBinary ( value ) ) { return 'B' ; } else if ( value === null ) { return 'NULL' ; } else if ( isBoolean ( value ) ) { return 'BOOL' ; } else if ( isCollection ( value ) ) { return detectCollectionTypeFromValue ( value ) ; } else if ( typeof value === 'object' ) { return 'M' ; } throw new Error ( `the type for value ${ value } could not be detected.` ) ; } hidden export function typeOf ( propertyValue , propertyPath ? ) { if ( propertyValue === null ) { return NullType ; } else if ( Array . isArray ( propertyValue ) ) { return Array ; } else if ( isSet ( propertyValue ) ) { return Set ; } else if ( propertyValue instanceof Map ) { return Map ; } else if ( isBinary ( propertyValue ) ) { return Binary ; } else if ( isString ( propertyValue ) ) { return String ; } else if ( isNumber ( propertyValue ) ) { return Number ; } else if ( isBoolean ( propertyValue ) ) { return Boolean ; } else if ( typeof propertyValue === 'undefined' ) { return UndefinedType ; } else if ( typeof propertyValue === 'object' ) { return Object ; } throw new Error ( messageWithPath ( propertyPath , `typeof data ${ propertyValue } could not be detected` ) ) ; } hidden export function typeOfFromDb ( attributeValue ? ) { if ( attributeValue ) { const dynamoType = < AttributeType > Object . keys ( attributeValue ) [ 0 ] ; switch ( dynamoType ) { case 'S' : return String ; case 'N' : return Number ; case 'B' : return Binary ; case 'BOOL' : return Boolean ; case 'SS' : case 'NS' : case 'BS' : return Set ; case 'L' : return Array ; case 'M' : return Object ; case 'NULL' : return NullType ; } } throw new Error ( `could not resolve the dynamo db type for attribute value ${ attributeValue }` ) ; } hidden export function isBinary ( data ) { if ( isNode ( ) ) { return Buffer . isBuffer ( data ) ; } else { return BUFFER_TYPES . some ( ( type ) => data !== undefined && data . constructor && ( isType ( data , type ) || typeName ( data . constructor ) === type ) ) ; } } hidden export function isBufferType ( type ) { return BUFFER_TYPES . includes ( type ) ; } hidden export function isType ( obj , type ) { if ( typeof type === 'function' ) { type = typeName ( type ) ; } return Object . prototype . toString . call ( obj ) === `[object ${ type }]` ; } hidden const isGlobalScopeWindow = new Function ( 'try {return this===window;}catch(e){ return false;}' ) ( ) ; hidden export function isBrowser ( ) { return isGlobalScopeWindow ; } hidden export function isNode ( ) { return ! isGlobalScopeWindow ; } hidden export function typeName ( type ) { if ( type !== null && type !== undefined ) { if ( Object . prototype . hasOwnProperty . call ( type , 'name' ) ) { return type . name ; } else { const str = type . toString ( ) ; const match = str . match ( /^\s*function (.+)\(/ ) ; return match ? match [ 1 ] : str ; } } else { if ( type === null ) { return 'Null' ; } else if ( type === undefined ) { return 'Undefined' ; } } throw new Error ( `was not able to resolve type name for type ${ type }` ) ; }