import { EMPTY , Observable } from 'rxjs' ; import { concatMap , expand , map , toArray } from 'rxjs/operators' ; import { ODataApi } from '../../api' ; import { ODataCollection , ODataModel } from '../../models' ; import { ODataStructuredType } from '../../schema' ; import { PathSegmentNames , QueryOptionNames } from '../../types' ; import { ODataPathSegments } from '../path' ; import { ODataQueryOptions } from '../query' ; import { ODataResource } from '../resource' ; import { ODataEntities , ODataEntity } from '../responses' ; import { ODataCountResource } from './count' ; import { ODataMediaResource } from './media' ; import { ODataEntitiesOptions , ODataEntityOptions , ODataOptions , } from './options' ; import { ODataPropertyResource } from './property' ; import { ODataReferenceResource } from './reference' ; /**
 * OData Navigation Property Resource
 * https://www.odata.org/getting-started/advanced-tutorial/#containment
 * https://www.odata.org/getting-started/advanced-tutorial/#derived
 */ export class ODataNavigationPropertyResource < T > extends ODataResource < T > { static factory < N > ( api , { path , type , schema , segments , query , } ) { const segment = segments . add ( PathSegmentNames . navigationProperty , path ) ; if ( schema !== undefined ) segment . type ( schema . type ( ) ) ; else if ( type !== undefined ) segment . type ( type ) ; query ?. keep ( QueryOptionNames . format ) ; return new ODataNavigationPropertyResource < N > ( api , { segments , query , schema , } ) ; } static fromResource < N > ( resource , path ) { const baseType = resource . type ( ) ; let baseSchema = resource . schema as ODataStructuredType < any > | undefined ; let fieldType ; let fieldSchema ; if ( baseSchema !== undefined ) { const field = baseSchema . findFieldByName < N > ( path ) ; fieldType = field ?. type ; fieldSchema = fieldType !== undefined ? resource . api . findStructuredTypeForType ( fieldType ) : undefined ; baseSchema = field !== undefined ? baseSchema . findSchemaForField < N > ( field ) : undefined ; } const navigation = ODataNavigationPropertyResource . factory < N > ( resource . api , { path , type : fieldType , schema : fieldSchema , segments : resource . cloneSegments ( ) , query : resource . cloneQuery < N > ( ) , } ) ; if ( baseSchema !== undefined && baseSchema . type ( ) !== baseType ) { let entitySet = resource . api . findEntitySetForType ( baseSchema . type ( ) ) ; if ( entitySet !== undefined ) { navigation . segment ( ( s ) => s . entitySet ( ) . path ( entitySet ! . name ) ) ; } } return navigation ; } key ( value ) { const navigation = this . clone < ODataNavigationPropertyResource < T > > ( ) ; var key = this . resolveKey ( value ) ; if ( key !== undefined ) navigation . segment ( ( s ) => s . navigationProperty ( ) . key ( key ) ) ; return navigation ; } keys ( values ) { const navigation = this . clone < ODataNavigationPropertyResource < T > > ( ) ; const types = this . pathSegments . types ( { key : true } ) ; const keys = values . map ( ( value , index ) => ODataResource . resolveKey ( value , this . api . findStructuredTypeForType < T > ( types [ index ] ) ) ) ; navigation . segment ( ( s ) => s . keys ( keys ) ) ; return navigation ; } media ( ) { return ODataMediaResource . factory < T > ( this . api , { segments : this . cloneSegments ( ) , query : this . cloneQuery < T > ( ) , } ) ; } reference ( ) { return ODataReferenceResource . factory < T > ( this . api , { segments : this . cloneSegments ( ) , } ) ; } navigationProperty < N > ( path ) { return ODataNavigationPropertyResource . fromResource < N > ( this , path ) ; } property < P > ( path ) { return ODataPropertyResource . fromResource < P > ( this , path ) ; } count ( ) { return ODataCountResource . factory < T > ( this . api , { segments : this . cloneSegments ( ) , query : this . cloneQuery < T > ( ) , } ) ; } cast < C > ( type ) { const baseSchema = this . schema as ODataStructuredType < T > ; const castSchema = this . api . findStructuredTypeForType < C > ( type ) ; if ( castSchema !== undefined && baseSchema !== undefined && ! castSchema . isSubtypeOf ( baseSchema ) ) throw new Error ( `Cannot cast to ${ type }` ) ; const segments = this . cloneSegments ( ) ; segments . add ( PathSegmentNames . type , type ) . type ( type ) ; return new ODataNavigationPropertyResource < C > ( this . api , { segments , schema : castSchema , query : this . cloneQuery < C > ( ) , } ) ; } protected override post ( attrs , options = { } ) { return super . post ( attrs , { responseType : 'entity' , ... options } ) ; } protected override put ( attrs , options = { } ) { return super . put ( attrs , { responseType : 'entity' , ... options } ) ; } protected override patch ( attrs , options = { } ) { return super . patch ( attrs , { responseType : 'entity' , ... options } ) ; } protected override delete ( options = { } ) { return super . delete ( { responseType : 'entity' , ... options } ) ; } protected override get ( options = { } ) { return super . get ( options ) ; } param attrs param options returns create ( attrs , options ? ) { return this . post ( attrs , options ) ; } param attrs param options param etag returns update ( attrs , options ? ) { return this . put ( attrs , options ) ; } param attrs param options param etag returns modify ( attrs , options ? ) { return this . patch ( attrs , options ) ; } param options param etag returns destroy ( options ? ) { return this . delete ( options ) ; } param options return fetch ( options ? ) ; fetch ( options ? ) ; fetch ( options = { } ) { return this . get ( options ) ; } param options returns fetchEntity ( options = { } ) { return this . fetch ( { responseType : 'entity' , ... options } ) . pipe ( map ( ( { entity } ) => entity ) ) ; } param options returns fetchModel < M extends ODataModel < T > > ( options = { } ) { return this . fetch ( { responseType : 'entity' , ... options } ) . pipe ( map ( ( { entity , annots } ) => entity ? this . asModel < M > ( entity , { annots , reset : true } ) : null ) ) ; } param options returns fetchEntities ( options = { } ) { return this . fetch ( { responseType : 'entities' , ... options } ) . pipe ( map ( ( { entities } ) => entities ) ) ; } param options returns fetchCollection < M extends ODataModel < T > , C extends ODataCollection < T , M > > ( options = { } ) { return this . fetch ( { responseType : 'entities' , ... options } ) . pipe ( map ( ( { entities , annots } ) => entities ? this . asCollection < M , C > ( entities , { annots , reset : true } ) : null ) ) ; } param options returns fetchAll ( options = { } ) { let res = this . clone < ODataNavigationPropertyResource < T > > ( ) ; res . query ( ( q ) => q . clearPaging ( ) ) ; let fetch = ( opts ? ) : Observable < ODataEntities < T > > => { if ( opts ) { res . query ( ( q ) => q . paging ( opts ) ) ; } return res . fetch ( { responseType : 'entities' , ... options } ) ; } ; return fetch ( ) . pipe ( expand ( ( { annots : meta } ) => meta . skip || meta . skiptoken ? fetch ( meta ) : EMPTY ) , concatMap ( ( { entities } ) => entities || [ ] ) , toArray ( ) ) ; } }