import { isDefined , SupersetClient , SupersetClientInterface , RequestConfig , SupersetClientClass , QueryFormData , Datasource , } from '../..' ; import getChartBuildQueryRegistry from '../registries/ChartBuildQueryRegistrySingleton' ; import getChartMetadataRegistry from '../registries/ChartMetadataRegistrySingleton' ; import { QueryData } from '../types/QueryResponse' ; import { AnnotationLayerMetadata } from '../types/Annotation' ; import { PlainObject } from '../types/Base' ; type AtLeastOne < All , Each = { [ K in keyof All ] : Pick < All , K > ; } > = Partial < All > & Each [ keyof Each ] ; export type SliceIdAndOrFormData = AtLeastOne < { sliceId : number ; formData : Partial < QueryFormData > ; } > ; interface AnnotationData { [ key ] : PlainObject ; } export interface ChartData { annotationData : AnnotationData ; datasource : PlainObject ; formData : QueryFormData ; queriesData : QueryData [ ] ; } export default class ChartClient { readonly client : SupersetClientInterface | SupersetClientClass ; constructor ( config = { } ) { const { client = SupersetClient } = config ; this . client = client ; } loadFormData ( input , options ? ) { if ( 'sliceId' in input ) { const promise = this . client . get ( { endpoint : `/api/v1/form_data/?slice_id=${ input . sliceId }` , ... options , } as RequestConfig ) . then ( response => response . json as QueryFormData ) ; return promise . then ( ( dbFormData ) => ( { ... dbFormData , ... input . formData , } ) ) ; } return input . formData ? Promise . resolve ( input . formData as QueryFormData ) : Promise . reject ( new Error ( 'At least one of sliceId or formData must be specified' ) ) ; } async loadQueryData ( formData , options ? ) { const { viz_type : visType } = formData ; const metaDataRegistry = getChartMetadataRegistry ( ) ; const buildQueryRegistry = getChartBuildQueryRegistry ( ) ; if ( metaDataRegistry . has ( visType ) ) { const { useLegacyApi } = metaDataRegistry . get ( visType ) ! ; const buildQuery = ( await buildQueryRegistry . get ( visType ) ) ?? ( ( ) => formData ) ; const requestConfig = useLegacyApi ? { endpoint : '/superset/explore_json/' , postPayload : { form_data : buildQuery ( formData ) , } , ... options , } : { endpoint : '/api/v1/chart/data' , jsonPayload : { query_context : buildQuery ( formData ) , } , ... options , } ; return this . client . post ( requestConfig ) . then ( response => Array . isArray ( response . json ) ? response . json : [ response . json ] ) ; } return Promise . reject ( new Error ( `Unknown chart type: ${ visType }` ) ) ; } loadDatasource ( datasourceKey , options ? ) { return this . client . get ( { endpoint : `/superset/fetch_datasource_metadata?datasourceKey=${ datasourceKey }` , ... options , } as RequestConfig ) . then ( response => response . json as Datasource ) ; } loadAnnotation ( annotationLayer ) { if ( ! isDefined ( annotationLayer . sourceType ) ) { return Promise . resolve ( { } as AnnotationData ) ; } return Promise . reject ( new Error ( 'This feature is not implemented yet.' ) ) ; } loadAnnotations ( annotationLayers ? ) { if ( Array . isArray ( annotationLayers ) && annotationLayers . length > 0 ) { return Promise . all ( annotationLayers . map ( layer => this . loadAnnotation ( layer ) ) ) . then ( results => annotationLayers . reduce ( ( prev , layer , i ) => { const output = prev ; output [ layer . name ] = results [ i ] ; return output ; } , { } ) ) ; } return Promise . resolve ( { } ) ; } loadChartData ( input ) { return this . loadFormData ( input ) . then ( ( formData ) => Promise . all ( [ this . loadAnnotations ( formData . annotation_layers ) , this . loadDatasource ( formData . datasource ) , this . loadQueryData ( formData ) , ] ) . then ( ( [ annotationData , datasource , queriesData ] ) => ( { annotationData , datasource , formData , queriesData , } ) ) ) ; } }