import { camelCase , createLogger , pickValueIgnoreCase } from '@sap-cloud-sdk/util' ; import { createValueDeserializer , DeSerializers } from './de-serializers' ; import { EntityApi , EntityBase , isExpandedProperty , isSelectedProperty } from './entity-base' ; import { EdmTypeShared , isEdmType } from './edm-types' ; import { ComplexTypeNamespace , isComplexTypeNameSpace , PropertyMetadata , Field , Link , EdmTypeField , EnumField , CollectionField , ComplexTypeField , OneToOneLink } from './selectable' ; const logger = createLogger ( { package : 'odata-common' , messageContext : 'entity-deserializer' } ) ; internal export interface EntityDeserializer { deserializeEntity : < EntityT extends EntityBase = EntityBase > ( json : any , entityApi : EntityApi < EntityT , any > , requestHeader ? : any ) => EntityT ; deserializeComplexType : ( json : Record < string , any > , complexType : ComplexTypeNamespace < any > ) => any ; } type ExtractODataETagType = ( json : Record < string , any > ) => string | undefined ; type ExtractDataFromOneToManyLinkType = ( data : any ) => any [ ] ; param deSerializers param extractODataETag param extractDataFromOneToManyLink returns internal export function entityDeserializer < T extends DeSerializers > ( deSerializers , extractODataETag , extractDataFromOneToManyLink ) { const edmToTs = createValueDeserializer ( deSerializers ) ; param json param entityApi param requestHeader returns function deserializeEntity < EntityT extends EntityBase , JsonT > ( json , entityApi , requestHeader ? ) { const etag = extractODataETag ( json ) || extractEtagFromHeader ( requestHeader ) ; return Object . values ( entityApi . schema ) . filter ( field => isSelectedProperty ( json , field ) ) . reduce ( ( entity , staticField ) => { entity [ camelCase ( staticField . _fieldName ) ] = getFieldValue ( json , staticField ) ; return entity ; } , new entityApi . entityConstructor ( entityApi . schema ) ) . setCustomFields ( extractCustomFields ( json , entityApi . schema ) ) . setVersionIdentifier ( etag ) . setOrInitializeRemoteState ( ) ; } function getFieldValue < EntityT extends EntityBase , DeSerializersT extends DeSerializers , JsonT > ( json , field ) { if ( field instanceof EdmTypeField ) { return edmToTs ( json [ field . _fieldName ] , field . edmType ) ; } if ( field instanceof Link ) { return getLinkFromJson ( json , field ) ; } if ( field instanceof ComplexTypeField ) { if ( json [ field . _fieldName ] ) { return field . _complexType ? deserializeComplexType ( json [ field . _fieldName ] , field . _complexType ) : deserializeComplexTypeLegacy ( json [ field . _fieldName ] , field ) ; } return json [ field . _fieldName ] ; } if ( field instanceof CollectionField ) { return deserializeCollectionType ( json [ field . _fieldName ] , field . _fieldType ) ; } if ( field instanceof EnumField ) { return json [ field . _fieldName ] ; } } function getLinkFromJson < EntityT extends EntityBase , DeSerializersT extends DeSerializers , LinkedEntityT extends EntityBase , JsonT > ( json , link ) { return link instanceof OneToOneLink ? getSingleLinkFromJson ( json , link ) : getMultiLinkFromJson ( json , link ) ; } function getSingleLinkFromJson < EntityT extends EntityBase , DeSerializersT extends DeSerializers , LinkedEntityT extends EntityBase , JsonT > ( json , link ) { if ( isExpandedProperty ( json , link ) ) { return deserializeEntity ( json [ link . _fieldName ] , link . _linkedEntityApi ) ; } return null ; } function getMultiLinkFromJson < EntityT extends EntityBase , DeSerializersT extends DeSerializers , LinkedEntityT extends EntityBase , JsonT > ( json , link ) { if ( isSelectedProperty ( json , link ) ) { const results = extractDataFromOneToManyLink ( json [ link . _fieldName ] ) ; return results . map ( linkJson => deserializeEntity ( linkJson , link . _linkedEntityApi ) ) ; } } function deserializeComplexTypeLegacy < EntityT extends EntityBase , DeSerializersT extends DeSerializers > ( json , complexTypeField ) { logger . warn ( 'It seems that you are using an outdated OData client. To make this warning disappear, please regenerate your client using the latest version of the SAP Cloud SDK generator.' ) ; if ( json === null ) { return null ; } return Object . entries ( complexTypeField ) . filter ( ( [ , field ] ) => ( field instanceof EdmTypeField || field instanceof ComplexTypeField ) && typeof json [ field . _fieldName ] !== 'undefined' ) . reduce ( ( complexTypeObject , [ fieldName , field ] ) => ( { ... complexTypeObject , [ camelCase ( fieldName ) ] : field instanceof EdmTypeField ? edmToTs ( json [ field . _fieldName ] , field . edmType ) : deserializeComplexTypeLegacy ( json [ field . _fieldName ] , field ) } ) , { } ) ; } function deserializeComplexTypeProperty ( propertyValue , propertyMetadata ) { if ( propertyMetadata . isCollection ) { return deserializeCollectionType ( propertyValue , propertyMetadata . type ) ; } if ( isComplexTypeNameSpace ( propertyMetadata . type ) ) { return deserializeComplexType ( propertyValue , propertyMetadata . type ) ; } return edmToTs ( propertyValue , propertyMetadata . type ) ; } function deserializeComplexType ( json , complexType ) { if ( json === null ) { return null ; } return complexType . _propertyMetadata . map ( property => ( { ... ( typeof json [ property . originalName ] !== 'undefined' && { [ property . name ] : deserializeComplexTypeProperty ( json [ property . originalName ] , property ) } ) } ) ) . reduce ( ( complexTypeInstance , property ) => ( { ... complexTypeInstance , ... property } ) ) ; } function deserializeCollectionType < FieldT extends EdmTypeShared < 'any' > | Record < string , any > > ( json , fieldType ) { if ( isEdmType ( fieldType ) ) { return json . map ( val => edmToTs ( val , fieldType ) ) ; } if ( isComplexTypeNameSpace ( fieldType ) ) { return json . map ( val => deserializeComplexType ( val , fieldType ) ) ; } return json ; } return { deserializeEntity , deserializeComplexType } ; } param headers returns internal export function extractEtagFromHeader ( headers ) { return pickValueIgnoreCase ( headers , 'etag' ) ; } param json param schema returns internal export function extractCustomFields < JsonT > ( json , schema ) { const regularODataProperties = [ '__metadata' , '__deferred' , ... Object . values ( schema ) . map ( field => field . _fieldName ) ] ; const regularFields = new Set < string > ( regularODataProperties ) ; return Object . keys ( json ) . filter ( key => ! regularFields . has ( key ) ) . reduce ( ( customFields , key ) => { customFields [ key ] = json [ key ] ; return customFields ; } , { } ) ; }