fieldLookup.ts 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. import { mergeMap, from } from 'rxjs';
  2. import {
  3. ArrayVector,
  4. DataFrame,
  5. DataTransformerID,
  6. Field,
  7. FieldMatcher,
  8. FieldMatcherID,
  9. fieldMatchers,
  10. DataTransformerInfo,
  11. } from '@grafana/data';
  12. import { COUNTRIES_GAZETTEER_PATH, Gazetteer, getGazetteer } from 'app/features/geo/gazetteer/gazetteer';
  13. export interface FieldLookupOptions {
  14. lookupField?: string;
  15. gazetteer?: string;
  16. }
  17. export const fieldLookupTransformer: DataTransformerInfo<FieldLookupOptions> = {
  18. id: DataTransformerID.fieldLookup,
  19. name: 'Lookup fields from resource',
  20. description: 'Retrieve matching data based on specified field',
  21. defaultOptions: {},
  22. operator: (options) => (source) => source.pipe(mergeMap((data) => from(doGazetteerXform(data, options)))),
  23. };
  24. async function doGazetteerXform(frames: DataFrame[], options: FieldLookupOptions): Promise<DataFrame[]> {
  25. const fieldMatches = fieldMatchers.get(FieldMatcherID.byName).get(options?.lookupField);
  26. const gaz = await getGazetteer(options?.gazetteer ?? COUNTRIES_GAZETTEER_PATH);
  27. if (!gaz.frame) {
  28. return Promise.reject('missing frame in gazetteer');
  29. }
  30. return addFieldsFromGazetteer(frames, gaz, fieldMatches);
  31. }
  32. export function addFieldsFromGazetteer(frames: DataFrame[], gaz: Gazetteer, matcher: FieldMatcher): DataFrame[] {
  33. const src = gaz.frame!()?.fields;
  34. if (!src) {
  35. return frames;
  36. }
  37. return frames.map((frame) => {
  38. const length = frame.length;
  39. const fields: Field[] = [];
  40. for (const field of frame.fields) {
  41. fields.push(field);
  42. //if the field matches
  43. if (matcher(field, frame, frames)) {
  44. const values = field.values.toArray();
  45. const sub: any[][] = [];
  46. for (const f of src) {
  47. const buffer = new Array(length);
  48. sub.push(buffer);
  49. fields.push({ ...f, values: new ArrayVector(buffer) });
  50. }
  51. // Add all values to the buffer
  52. for (let v = 0; v < sub.length; v++) {
  53. const found = gaz.find(values[v]);
  54. if (found?.index != null) {
  55. for (let i = 0; i < src.length; i++) {
  56. sub[i][v] = src[i].values.get(found.index);
  57. }
  58. }
  59. }
  60. }
  61. }
  62. return {
  63. ...frame,
  64. fields,
  65. };
  66. });
  67. }