{"version":3,"file":"queryResponse.mjs","sources":["../../../src/utils/queryResponse.ts"],"sourcesContent":["import {\n  type DataQueryResponse,\n  type KeyValue,\n  LoadingState,\n  type DataQueryError,\n  type TimeSeries,\n  type TableData,\n  toDataFrame,\n  type DataFrame,\n  type MetricFindValue,\n  FieldType,\n  type DataQuery,\n  type DataFrameJSON,\n  dataFrameFromJSON,\n  type QueryResultMetaNotice,\n} from '@grafana/data';\n\nimport { type FetchError, type FetchResponse } from '../services';\n\nimport { type HealthCheckResultDetails } from './DataSourceWithBackend';\nimport { toDataQueryError } from './toDataQueryError';\n\nexport const cachedResponseNotice: QueryResultMetaNotice = { severity: 'info', text: 'Cached response' };\n\n/**\n * Single response object from a backend data source. Properties are optional but response should contain at least\n * an error or a some data (but can contain both). Main way to send data is with dataframes attribute as series and\n * tables data attributes are legacy formats.\n *\n * @internal\n */\nexport interface DataResponse {\n  error?: string;\n  refId?: string;\n  frames?: DataFrameJSON[];\n  status?: number;\n\n  // Legacy TSDB format...\n  series?: TimeSeries[];\n  tables?: TableData[];\n}\n\n/**\n * This is the type of response expected form backend datasource.\n *\n * @internal\n */\nexport interface BackendDataSourceResponse {\n  results: KeyValue<DataResponse>;\n}\n\n/**\n * Parse the results from /api/ds/query into a DataQueryResponse\n *\n * @param res - the HTTP response data.\n * @param queries - optional DataQuery array that will order the response based on the order of query refId's.\n *\n * @public\n */\nexport function toDataQueryResponse(\n  res:\n    | { data: BackendDataSourceResponse | undefined }\n    | FetchResponse<BackendDataSourceResponse | undefined>\n    | DataQueryError,\n  queries?: DataQuery[]\n): DataQueryResponse {\n  const rsp: DataQueryResponse = { data: [], state: LoadingState.Done };\n\n  const traceId = 'traceId' in res ? res.traceId : undefined;\n\n  if (traceId != null) {\n    rsp.traceIds = [traceId];\n  }\n\n  // If the response isn't in a correct shape we just ignore the data and pass empty DataQueryResponse.\n  const fetchResponse = res as FetchResponse;\n  if (fetchResponse.data?.results) {\n    const results = fetchResponse.data.results;\n    const refIDs = queries?.length ? queries.map((q) => q.refId) : Object.keys(results);\n    const cachedResponse = isCachedResponse(fetchResponse);\n    const data: DataResponse[] = [];\n\n    for (const refId of refIDs) {\n      const dr = results[refId];\n      if (!dr) {\n        continue;\n      }\n      dr.refId = refId;\n      data.push(dr);\n    }\n\n    for (const dr of data) {\n      if (dr.error) {\n        const errorObj: DataQueryError = {\n          refId: dr.refId,\n          message: dr.error,\n          status: dr.status,\n        };\n        if (traceId != null) {\n          errorObj.traceId = traceId;\n        }\n        if (!rsp.error) {\n          rsp.error = { ...errorObj };\n        }\n        if (rsp.errors) {\n          rsp.errors.push({ ...errorObj });\n        } else {\n          rsp.errors = [{ ...errorObj }];\n        }\n        rsp.state = LoadingState.Error;\n      }\n\n      if (dr.frames?.length) {\n        for (let js of dr.frames) {\n          if (cachedResponse) {\n            js = addCacheNotice(js);\n          }\n          const df = dataFrameFromJSON(js);\n          if (!df.refId) {\n            df.refId = dr.refId;\n          }\n          rsp.data.push(df);\n        }\n        continue; // the other tests are legacy\n      }\n\n      if (dr.series?.length) {\n        for (const s of dr.series) {\n          if (!s.refId) {\n            s.refId = dr.refId;\n          }\n          rsp.data.push(toDataFrame(s));\n        }\n      }\n\n      if (dr.tables?.length) {\n        for (const s of dr.tables) {\n          if (!s.refId) {\n            s.refId = dr.refId;\n          }\n          rsp.data.push(toDataFrame(s));\n        }\n      }\n    }\n  }\n\n  // When it is not an OK response, make sure the error gets added\n  if (fetchResponse.status && fetchResponse.status !== 200) {\n    if (rsp.state !== LoadingState.Error) {\n      rsp.state = LoadingState.Error;\n    }\n    if (!rsp.error) {\n      rsp.error = toDataQueryError(res);\n    }\n  }\n\n  return rsp;\n}\n\nfunction isCachedResponse(res: FetchResponse<BackendDataSourceResponse | undefined>): boolean {\n  const headers = res?.headers;\n  if (!headers || !headers.get) {\n    return false;\n  }\n  return headers.get('X-Cache') === 'HIT';\n}\n\nfunction addCacheNotice(frame: DataFrameJSON): DataFrameJSON {\n  return {\n    ...frame,\n    schema: {\n      ...frame.schema,\n      fields: [...(frame.schema?.fields ?? [])],\n      meta: {\n        ...frame.schema?.meta,\n        notices: [...(frame.schema?.meta?.notices ?? []), cachedResponseNotice],\n        isCachedResponse: true,\n      },\n    },\n  };\n}\n\nexport interface TestingStatus {\n  message?: string | null;\n  status?: string | null;\n  details?: HealthCheckResultDetails;\n}\n\n/**\n * Data sources using api/ds/query to test data sources can use this function to\n * handle errors and convert them to TestingStatus object.\n *\n * If possible, this should be avoided in favor of implementing /health endpoint\n * and testing data source with DataSourceWithBackend.testDataSource()\n *\n * Re-thrown errors are handled by testDataSource() in public/app/features/datasources/state/actions.ts\n *\n * @returns {TestingStatus}\n */\nexport function toTestingStatus(err: FetchError): TestingStatus {\n  const queryResponse = toDataQueryResponse(err);\n  // POST api/ds/query errors returned as { message: string, error: string } objects\n  if (queryResponse.error?.data?.message) {\n    return {\n      status: 'error',\n      message: queryResponse.error.data.message,\n      details: queryResponse.error?.data?.error ? { message: queryResponse.error.data.error } : undefined,\n    };\n  }\n  // POST api/ds/query errors returned in results object\n  else if (queryResponse.error?.refId && queryResponse.error?.message) {\n    return {\n      status: 'error',\n      message: queryResponse.error.message,\n    };\n  }\n\n  throw err;\n}\n\n/**\n * Return the first string or non-time field as the value\n *\n * @beta\n */\nexport function frameToMetricFindValue(frame: DataFrame): MetricFindValue[] {\n  if (!frame || !frame.length) {\n    return [];\n  }\n\n  const values: MetricFindValue[] = [];\n  let field = frame.fields.find((f) => f.type === FieldType.string);\n  if (!field) {\n    field = frame.fields.find((f) => f.type !== FieldType.time);\n  }\n  if (field) {\n    for (let i = 0; i < field.values.length; i++) {\n      values.push({ text: '' + field.values[i] });\n    }\n  }\n  return values;\n}\n"],"names":[],"mappings":"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"}