import { createLogger , partition , upperCaseSnakeCase } from '@sap-cloud-sdk/util' ; import { isNavigationProperty } from './properties-util' ; import type { EntityApi , EntityBase } from './entity-base' ; import { DeSerializers } from './de-serializers' ; const logger = createLogger ( { package : 'odata-common' , messageContext : 'entity-builder' } ) ; type NullishTypes = null | undefined ; type NonNullishType < T > = Exclude < T , NullishTypes > ; type PureEntityType < T > = Omit < NonNullishType < T > , keyof EntityBase > ; typeparam type FromJsonType < JsonT > = { [ key ] : any ; } & { [ P in keyof PureEntityType < JsonT > ] ? : PureEntityType < JsonT > [ P ] extends ( infer U ) [ ] ? U extends Record < string , any > ? FromJsonType < U > [ ] : PureEntityType < JsonT > [ P ] : PureEntityType < JsonT > [ P ] extends Record < string , any > | null | undefined ? FromJsonType < PureEntityType < JsonT > [ P ] > | null | undefined : PureEntityType < JsonT > [ P ] ; } ; internal export class EntityBuilder < EntityT extends EntityBase , DeSerializersT extends DeSerializers > { protected entity : EntityT ; constructor ( private _entityApi ) { if ( ! this . entity ) { this . entity = new _entityApi . entityConstructor ( _entityApi . schema ) ; } } param customFields returns public withCustomFields ( customFields ) { const validCustomFields = this . filterCustomFields ( customFields ) ; this . entity = this . entity . setCustomFields ( validCustomFields ) ; return this ; } returns public build ( ) { const entity = this . entity ; this . entity = new this . _entityApi . entityConstructor ( this . _entityApi . schema ) ; return entity ; } param json returns public fromJson ( json ) { const entityBuilder = this ; const [ entityEntries , customEntries ] = partition ( Object . entries ( json ) , ( [ key ] ) => typeof entityBuilder [ key ] === 'function' ) ; entityEntries . forEach ( ( [ key , value ] ) => { const propertyValue = isNavigationProperty ( key , this . _entityApi . schema ) && ! ! value ? buildNavigationPropertyFromJson ( key , value , this . _entityApi ) : value ; entityBuilder [ key ] ( propertyValue ) ; } ) ; const customFields = customEntries . reduce ( ( customFieldsObj , [ key , value ] ) => { if ( key === '_customFields' ) { logger . warn ( "Setting custom fields in 'fromJson' through '_customFields' is deprecated and will soon be removed. Add properties to your JSON instead. (Deprecated since v1.38.1)" ) ; return { ... customFieldsObj , ... value } ; } return { ... customFieldsObj , [ key ] : value } ; } , { } ) ; entityBuilder . withCustomFields ( customFields ) ; return entityBuilder . build ( ) ; } private filterCustomFields ( customFields ) { return Object . keys ( customFields ) . reduce ( ( validCfs , cf ) => { if ( ! this . _entityApi . schema [ upperCaseSnakeCase ( cf ) ] ) { validCfs [ cf ] = customFields [ cf ] ; } logger . warn ( `Field name "${ cf }" is already existing in "${ toClassName ( this . _entityApi . entityConstructor . _entityName ) }" and thus cannot be defined as custom field. ` ) ; return validCfs ; } , { } ) ; } } function toClassName ( entityName ) { return entityName . substr ( entityName . indexOf ( '_' ) + 1 ) ; } function buildNavigationPropertyFromJson < EntityT extends EntityBase , DeSerializersT extends DeSerializers , LinkedEntityT extends EntityBase > ( key , value , entityApi ) { const field = entityApi . schema [ upperCaseSnakeCase ( key ) ] ; const linkedEntityApi = field . _linkedEntityApi ; return Array . isArray ( value ) ? value . map ( item => buildSingleEntityFromJson ( item , linkedEntityApi ) ) : ( buildSingleEntityFromJson ( value , linkedEntityApi ) as LinkedEntityT ) ; } function buildSingleEntityFromJson < LinkedEntityT extends EntityBase , DeSerializersT extends DeSerializers > ( json , linkedEntityApi ) { return json instanceof linkedEntityApi . entityConstructor ? json : ( linkedEntityApi . entityBuilder ( ) . fromJson ( json ) as LinkedEntityT ) ; }