diff --git a/packages/grafana-data/src/index.ts b/packages/grafana-data/src/index.ts index 79d19e620ba..1762076825b 100644 --- a/packages/grafana-data/src/index.ts +++ b/packages/grafana-data/src/index.ts @@ -1,4 +1,5 @@ -export * from './utils/index'; -export * from './types/index'; +export * from './utils'; +export * from './types'; export * from './vector'; export * from './dataframe'; +export * from './transformations'; diff --git a/packages/grafana-data/src/transformations/index.ts b/packages/grafana-data/src/transformations/index.ts new file mode 100644 index 00000000000..81db0ed19e6 --- /dev/null +++ b/packages/grafana-data/src/transformations/index.ts @@ -0,0 +1,8 @@ +export * from './matchers/ids'; +export * from './transformers/ids'; +export * from './transformersRegistry'; +export * from './matchers/matchers'; +export * from './transformersRegistry'; +export * from './transformDataFrame'; +export { FilterFieldsByNameTransformerOptions } from './transformers/filterByName'; +export { ReduceTransformerOptions } from './transformers/reduce'; diff --git a/packages/grafana-data/src/utils/matchers/fieldTypeMatcher.test.ts b/packages/grafana-data/src/transformations/matchers/fieldTypeMatcher.test.ts similarity index 91% rename from packages/grafana-data/src/utils/matchers/fieldTypeMatcher.test.ts rename to packages/grafana-data/src/transformations/matchers/fieldTypeMatcher.test.ts index 99884f3d60c..1d539585bc3 100644 --- a/packages/grafana-data/src/utils/matchers/fieldTypeMatcher.test.ts +++ b/packages/grafana-data/src/transformations/matchers/fieldTypeMatcher.test.ts @@ -1,7 +1,7 @@ import { FieldType } from '../../types/dataFrame'; import { fieldMatchers } from './matchers'; import { FieldMatcherID } from './ids'; -import { toDataFrame } from '../processDataFrame'; +import { toDataFrame } from '../../utils/processDataFrame'; export const simpleSeriesWithTypes = toDataFrame({ fields: [ diff --git a/packages/grafana-data/src/utils/matchers/fieldTypeMatcher.ts b/packages/grafana-data/src/transformations/matchers/fieldTypeMatcher.ts similarity index 95% rename from packages/grafana-data/src/utils/matchers/fieldTypeMatcher.ts rename to packages/grafana-data/src/transformations/matchers/fieldTypeMatcher.ts index 385bcefca44..38dc9c5ef0a 100644 --- a/packages/grafana-data/src/utils/matchers/fieldTypeMatcher.ts +++ b/packages/grafana-data/src/transformations/matchers/fieldTypeMatcher.ts @@ -1,6 +1,6 @@ import { Field, FieldType } from '../../types/dataFrame'; -import { FieldMatcherInfo } from './matchers'; import { FieldMatcherID } from './ids'; +import { FieldMatcherInfo } from '../../types/transformations'; // General Field matcher const fieldTypeMacher: FieldMatcherInfo = { diff --git a/packages/grafana-data/src/utils/matchers/ids.ts b/packages/grafana-data/src/transformations/matchers/ids.ts similarity index 100% rename from packages/grafana-data/src/utils/matchers/ids.ts rename to packages/grafana-data/src/transformations/matchers/ids.ts diff --git a/packages/grafana-data/src/utils/matchers/matchers.test.ts b/packages/grafana-data/src/transformations/matchers/matchers.test.ts similarity index 100% rename from packages/grafana-data/src/utils/matchers/matchers.test.ts rename to packages/grafana-data/src/transformations/matchers/matchers.test.ts diff --git a/packages/grafana-data/src/utils/matchers/matchers.ts b/packages/grafana-data/src/transformations/matchers/matchers.ts similarity index 66% rename from packages/grafana-data/src/utils/matchers/matchers.ts rename to packages/grafana-data/src/transformations/matchers/matchers.ts index d5b45ff771a..463c265dcf2 100644 --- a/packages/grafana-data/src/utils/matchers/matchers.ts +++ b/packages/grafana-data/src/transformations/matchers/matchers.ts @@ -1,27 +1,16 @@ -import { Field, DataFrame } from '../../types/dataFrame'; -import { Registry, RegistryItemWithOptions } from '../registry'; - -export type FieldMatcher = (field: Field) => boolean; -export type FrameMatcher = (frame: DataFrame) => boolean; - -export interface FieldMatcherInfo extends RegistryItemWithOptions { - get: (options: TOptions) => FieldMatcher; -} - -export interface FrameMatcherInfo extends RegistryItemWithOptions { - get: (options: TOptions) => FrameMatcher; -} - -export interface MatcherConfig { - id: string; - options?: TOptions; -} - // Load the Buildtin matchers import { getFieldPredicateMatchers, getFramePredicateMatchers } from './predicates'; import { getFieldNameMatchers, getFrameNameMatchers } from './nameMatcher'; import { getFieldTypeMatchers } from './fieldTypeMatcher'; import { getRefIdMatchers } from './refIdMatcher'; +import { + FieldMatcherInfo, + MatcherConfig, + FrameMatcherInfo, + FieldMatcher, + FrameMatcher, +} from '../../types/transformations'; +import { Registry } from '../../utils/registry'; export const fieldMatchers = new Registry(() => { return [ diff --git a/packages/grafana-data/src/utils/matchers/nameMatcher.test.ts b/packages/grafana-data/src/transformations/matchers/nameMatcher.test.ts similarity index 95% rename from packages/grafana-data/src/utils/matchers/nameMatcher.test.ts rename to packages/grafana-data/src/transformations/matchers/nameMatcher.test.ts index 7f2880ff0f6..9bf238dadef 100644 --- a/packages/grafana-data/src/utils/matchers/nameMatcher.test.ts +++ b/packages/grafana-data/src/transformations/matchers/nameMatcher.test.ts @@ -1,6 +1,6 @@ import { getFieldMatcher } from './matchers'; import { FieldMatcherID } from './ids'; -import { toDataFrame } from '../processDataFrame'; +import { toDataFrame } from '../../utils/processDataFrame'; describe('Field Name Matcher', () => { it('Match all with wildcard regex', () => { diff --git a/packages/grafana-data/src/utils/matchers/nameMatcher.ts b/packages/grafana-data/src/transformations/matchers/nameMatcher.ts similarity index 90% rename from packages/grafana-data/src/utils/matchers/nameMatcher.ts rename to packages/grafana-data/src/transformations/matchers/nameMatcher.ts index 626b6a908a8..a951e221d39 100644 --- a/packages/grafana-data/src/utils/matchers/nameMatcher.ts +++ b/packages/grafana-data/src/transformations/matchers/nameMatcher.ts @@ -1,7 +1,7 @@ import { Field, DataFrame } from '../../types/dataFrame'; -import { FieldMatcherInfo, FrameMatcherInfo } from './matchers'; import { FieldMatcherID, FrameMatcherID } from './ids'; -import { stringToJsRegex } from '../string'; +import { FieldMatcherInfo, FrameMatcherInfo } from '../../types/transformations'; +import { stringToJsRegex } from '../../utils/string'; // General Field matcher const fieldNameMacher: FieldMatcherInfo = { diff --git a/packages/grafana-data/src/utils/matchers/predicates.test.ts b/packages/grafana-data/src/transformations/matchers/predicates.test.ts similarity index 92% rename from packages/grafana-data/src/utils/matchers/predicates.test.ts rename to packages/grafana-data/src/transformations/matchers/predicates.test.ts index 97e95ba3129..99901a74f8c 100644 --- a/packages/grafana-data/src/utils/matchers/predicates.test.ts +++ b/packages/grafana-data/src/transformations/matchers/predicates.test.ts @@ -1,7 +1,8 @@ import { FieldType } from '../../types/dataFrame'; -import { MatcherConfig, fieldMatchers } from './matchers'; +import { fieldMatchers } from './matchers'; import { simpleSeriesWithTypes } from './fieldTypeMatcher.test'; import { FieldMatcherID, MatcherID } from './ids'; +import { MatcherConfig } from '../../types/transformations'; const matchesNumberConfig: MatcherConfig = { id: FieldMatcherID.byType, diff --git a/packages/grafana-data/src/utils/matchers/predicates.ts b/packages/grafana-data/src/transformations/matchers/predicates.ts similarity index 97% rename from packages/grafana-data/src/utils/matchers/predicates.ts rename to packages/grafana-data/src/transformations/matchers/predicates.ts index 502cceef311..942d3b5444a 100644 --- a/packages/grafana-data/src/utils/matchers/predicates.ts +++ b/packages/grafana-data/src/transformations/matchers/predicates.ts @@ -1,14 +1,7 @@ import { Field, DataFrame } from '../../types/dataFrame'; import { MatcherID } from './ids'; -import { - FrameMatcherInfo, - FieldMatcherInfo, - MatcherConfig, - getFieldMatcher, - fieldMatchers, - getFrameMatchers, - frameMatchers, -} from './matchers'; +import { getFieldMatcher, fieldMatchers, getFrameMatchers, frameMatchers } from './matchers'; +import { FieldMatcherInfo, MatcherConfig, FrameMatcherInfo } from '../../types/transformations'; const anyFieldMatcher: FieldMatcherInfo = { id: MatcherID.anyMatch, diff --git a/packages/grafana-data/src/utils/matchers/refIdMatcher.ts b/packages/grafana-data/src/transformations/matchers/refIdMatcher.ts similarity index 89% rename from packages/grafana-data/src/utils/matchers/refIdMatcher.ts rename to packages/grafana-data/src/transformations/matchers/refIdMatcher.ts index 51b0db3af80..0d525d53dd9 100644 --- a/packages/grafana-data/src/utils/matchers/refIdMatcher.ts +++ b/packages/grafana-data/src/transformations/matchers/refIdMatcher.ts @@ -1,6 +1,6 @@ import { DataFrame } from '../../types/dataFrame'; -import { FrameMatcherInfo } from './matchers'; import { FrameMatcherID } from './ids'; +import { FrameMatcherInfo } from '../../types/transformations'; // General Field matcher const refIdMacher: FrameMatcherInfo = { diff --git a/packages/grafana-data/src/transformations/transformDataFrame.ts b/packages/grafana-data/src/transformations/transformDataFrame.ts new file mode 100644 index 00000000000..f35eb950709 --- /dev/null +++ b/packages/grafana-data/src/transformations/transformDataFrame.ts @@ -0,0 +1,31 @@ +import { DataTransformerConfig } from '../types/transformations'; +import { DataFrame } from '../types/dataFrame'; +import { transformersRegistry } from './transformersRegistry'; + +/** + * Apply configured transformations to the input data + */ +export function transformDataFrame(options: DataTransformerConfig[], data: DataFrame[]): DataFrame[] { + let processed = data; + for (const config of options) { + const info = transformersRegistry.get(config.id); + const transformer = info.transformer(config.options); + const after = transformer(processed); + + // Add a key to the metadata if the data changed + if (after && after !== processed) { + for (const series of after) { + if (!series.meta) { + series.meta = {}; + } + if (!series.meta.transformations) { + series.meta.transformations = [info.id]; + } else { + series.meta.transformations = [...series.meta.transformations, info.id]; + } + } + processed = after; + } + } + return processed; +} diff --git a/packages/grafana-data/src/utils/transformers/__snapshots__/reduce.test.ts.snap b/packages/grafana-data/src/transformations/transformers/__snapshots__/reduce.test.ts.snap similarity index 100% rename from packages/grafana-data/src/utils/transformers/__snapshots__/reduce.test.ts.snap rename to packages/grafana-data/src/transformations/transformers/__snapshots__/reduce.test.ts.snap diff --git a/packages/grafana-data/src/utils/transformers/append.test.ts b/packages/grafana-data/src/transformations/transformers/append.test.ts similarity index 79% rename from packages/grafana-data/src/utils/transformers/append.test.ts rename to packages/grafana-data/src/transformations/transformers/append.test.ts index 4881c714f28..53cbff29782 100644 --- a/packages/grafana-data/src/utils/transformers/append.test.ts +++ b/packages/grafana-data/src/transformations/transformers/append.test.ts @@ -1,6 +1,7 @@ -import { transformDataFrame, dataTransformers } from './transformers'; import { DataTransformerID } from './ids'; -import { toDataFrame } from '../processDataFrame'; +import { toDataFrame } from '../../utils/processDataFrame'; +import { transformDataFrame } from '../transformDataFrame'; +import { transformersRegistry } from '../transformersRegistry'; const seriesAB = toDataFrame({ columns: [{ text: 'A' }, { text: 'B' }], @@ -24,7 +25,7 @@ describe('Append Transformer', () => { id: DataTransformerID.append, options: {}, }; - const x = dataTransformers.get(DataTransformerID.append); + const x = transformersRegistry.get(DataTransformerID.append); expect(x.id).toBe(cfg.id); const processed = transformDataFrame([cfg], [seriesAB, seriesBC])[0]; diff --git a/packages/grafana-data/src/utils/transformers/append.ts b/packages/grafana-data/src/transformations/transformers/append.ts similarity index 96% rename from packages/grafana-data/src/utils/transformers/append.ts rename to packages/grafana-data/src/transformations/transformers/append.ts index c1cf37430b1..952f006bbe2 100644 --- a/packages/grafana-data/src/utils/transformers/append.ts +++ b/packages/grafana-data/src/transformations/transformers/append.ts @@ -1,7 +1,7 @@ -import { DataTransformerInfo } from './transformers'; import { DataFrame } from '../../types/dataFrame'; import { DataTransformerID } from './ids'; import { MutableDataFrame } from '../../dataframe/MutableDataFrame'; +import { DataTransformerInfo } from '../../types/transformations'; export interface AppendOptions {} diff --git a/packages/grafana-data/src/utils/transformers/filter.test.ts b/packages/grafana-data/src/transformations/transformers/filter.test.ts similarity index 87% rename from packages/grafana-data/src/utils/transformers/filter.test.ts rename to packages/grafana-data/src/transformations/transformers/filter.test.ts index 28b3c11f6f7..300a1d63b08 100644 --- a/packages/grafana-data/src/utils/transformers/filter.test.ts +++ b/packages/grafana-data/src/transformations/transformers/filter.test.ts @@ -1,8 +1,8 @@ import { FieldType } from '../../types/dataFrame'; -import { FieldMatcherID } from '../matchers/ids'; -import { transformDataFrame } from './transformers'; import { DataTransformerID } from './ids'; -import { toDataFrame } from '../processDataFrame'; +import { toDataFrame } from '../../utils/processDataFrame'; +import { transformDataFrame } from '../transformDataFrame'; +import { FieldMatcherID } from '../matchers/ids'; export const simpleSeriesWithTypes = toDataFrame({ fields: [ diff --git a/packages/grafana-data/src/utils/transformers/filter.ts b/packages/grafana-data/src/transformations/transformers/filter.ts similarity index 94% rename from packages/grafana-data/src/utils/transformers/filter.ts rename to packages/grafana-data/src/transformations/transformers/filter.ts index 7837c03d233..a94f24b548b 100644 --- a/packages/grafana-data/src/utils/transformers/filter.ts +++ b/packages/grafana-data/src/transformations/transformers/filter.ts @@ -1,9 +1,9 @@ -import { DataTransformerInfo } from './transformers'; import { noopTransformer } from './noop'; import { DataFrame, Field } from '../../types/dataFrame'; -import { FieldMatcherID } from '../matchers/ids'; import { DataTransformerID } from './ids'; -import { MatcherConfig, getFieldMatcher, getFrameMatchers } from '../matchers/matchers'; +import { DataTransformerInfo, MatcherConfig } from '../../types/transformations'; +import { FieldMatcherID } from '../matchers/ids'; +import { getFieldMatcher, getFrameMatchers } from '../matchers/matchers'; export interface FilterOptions { include?: MatcherConfig; diff --git a/packages/grafana-data/src/utils/transformers/filterByName.test.ts b/packages/grafana-data/src/transformations/transformers/filterByName.test.ts similarity index 94% rename from packages/grafana-data/src/utils/transformers/filterByName.test.ts rename to packages/grafana-data/src/transformations/transformers/filterByName.test.ts index 75525065412..c08178c4e46 100644 --- a/packages/grafana-data/src/utils/transformers/filterByName.test.ts +++ b/packages/grafana-data/src/transformations/transformers/filterByName.test.ts @@ -1,6 +1,7 @@ -import { toDataFrame, transformDataFrame } from '../index'; +import { toDataFrame } from '../../utils/index'; import { FieldType } from '../../index'; import { DataTransformerID } from './ids'; +import { transformDataFrame } from '../transformDataFrame'; export const seriesWithNamesToMatch = toDataFrame({ fields: [ diff --git a/packages/grafana-data/src/utils/transformers/filterByName.ts b/packages/grafana-data/src/transformations/transformers/filterByName.ts similarity index 94% rename from packages/grafana-data/src/utils/transformers/filterByName.ts rename to packages/grafana-data/src/transformations/transformers/filterByName.ts index 1d72116dc72..7ece827065c 100644 --- a/packages/grafana-data/src/utils/transformers/filterByName.ts +++ b/packages/grafana-data/src/transformations/transformers/filterByName.ts @@ -1,7 +1,7 @@ -import { DataTransformerInfo } from './transformers'; -import { FieldMatcherID } from '../matchers/ids'; import { DataTransformerID } from './ids'; import { filterFieldsTransformer, FilterOptions } from './filter'; +import { DataTransformerInfo } from '../../types/transformations'; +import { FieldMatcherID } from '../matchers/ids'; export interface FilterFieldsByNameTransformerOptions { include?: string; diff --git a/packages/grafana-data/src/utils/transformers/ids.ts b/packages/grafana-data/src/transformations/transformers/ids.ts similarity index 100% rename from packages/grafana-data/src/utils/transformers/ids.ts rename to packages/grafana-data/src/transformations/transformers/ids.ts diff --git a/packages/grafana-data/src/utils/transformers/noop.ts b/packages/grafana-data/src/transformations/transformers/noop.ts similarity index 90% rename from packages/grafana-data/src/utils/transformers/noop.ts rename to packages/grafana-data/src/transformations/transformers/noop.ts index 96bded6b89a..7feb0b853d6 100644 --- a/packages/grafana-data/src/utils/transformers/noop.ts +++ b/packages/grafana-data/src/transformations/transformers/noop.ts @@ -1,6 +1,6 @@ -import { DataTransformerInfo } from './transformers'; import { DataTransformerID } from './ids'; import { DataFrame } from '../../types/dataFrame'; +import { DataTransformerInfo } from '../../types/transformations'; export interface NoopTransformerOptions { include?: string; diff --git a/packages/grafana-data/src/utils/transformers/reduce.test.ts b/packages/grafana-data/src/transformations/transformers/reduce.test.ts similarity index 77% rename from packages/grafana-data/src/utils/transformers/reduce.test.ts rename to packages/grafana-data/src/transformations/transformers/reduce.test.ts index ed0ce16b6f7..a8d06ffd244 100644 --- a/packages/grafana-data/src/utils/transformers/reduce.test.ts +++ b/packages/grafana-data/src/transformations/transformers/reduce.test.ts @@ -1,7 +1,7 @@ -import { transformDataFrame } from './transformers'; -import { ReducerID } from '../fieldReducer'; +import { ReducerID } from '../../utils/fieldReducer'; import { DataTransformerID } from './ids'; -import { toDataFrame, toDataFrameDTO } from '../processDataFrame'; +import { toDataFrame, toDataFrameDTO } from '../../utils/processDataFrame'; +import { transformDataFrame } from '../transformDataFrame'; const seriesWithValues = toDataFrame({ fields: [ diff --git a/packages/grafana-data/src/utils/transformers/reduce.ts b/packages/grafana-data/src/transformations/transformers/reduce.ts similarity index 88% rename from packages/grafana-data/src/utils/transformers/reduce.ts rename to packages/grafana-data/src/transformations/transformers/reduce.ts index 30ca389d235..507db09d9ae 100644 --- a/packages/grafana-data/src/utils/transformers/reduce.ts +++ b/packages/grafana-data/src/transformations/transformers/reduce.ts @@ -1,12 +1,12 @@ -import { DataTransformerInfo } from './transformers'; -import { DataFrame, FieldType, Field } from '../../types/dataFrame'; -import { MatcherConfig, getFieldMatcher } from '../matchers/matchers'; -import { alwaysFieldMatcher } from '../matchers/predicates'; import { DataTransformerID } from './ids'; -import { ReducerID, fieldReducers, reduceField } from '../fieldReducer'; -import { KeyValue } from '../../types/data'; -import { guessFieldTypeForField } from '../processDataFrame'; +import { MatcherConfig, DataTransformerInfo } from '../../types/transformations'; +import { ReducerID, fieldReducers, reduceField } from '../../utils/fieldReducer'; +import { alwaysFieldMatcher } from '../matchers/predicates'; +import { DataFrame, Field, FieldType } from '../../types/dataFrame'; import { ArrayVector } from '../../vector/ArrayVector'; +import { KeyValue } from '../../types/data'; +import { guessFieldTypeForField } from '../../utils/processDataFrame'; +import { getFieldMatcher } from '../matchers/matchers'; export interface ReduceTransformerOptions { reducers: ReducerID[]; diff --git a/packages/grafana-data/src/utils/transformers/transformers.test.ts b/packages/grafana-data/src/transformations/transformersRegistry.test.ts similarity index 62% rename from packages/grafana-data/src/utils/transformers/transformers.test.ts rename to packages/grafana-data/src/transformations/transformersRegistry.test.ts index 0a8e29abec8..814790f1094 100644 --- a/packages/grafana-data/src/utils/transformers/transformers.test.ts +++ b/packages/grafana-data/src/transformations/transformersRegistry.test.ts @@ -1,13 +1,13 @@ -import { DataTransformerID } from './ids'; -import { dataTransformers } from './transformers'; -import { toDataFrame } from '../processDataFrame'; -import { ReducerID } from '../fieldReducer'; -import { DataFrameView } from '../../dataframe/DataFrameView'; +import { DataTransformerID } from './transformers/ids'; +import { transformersRegistry } from './transformersRegistry'; +import { toDataFrame } from '../utils/processDataFrame'; +import { ReducerID } from '../utils/fieldReducer'; +import { DataFrameView } from '../dataframe/DataFrameView'; describe('Transformers', () => { it('should load all transformeres', () => { for (const name of Object.keys(DataTransformerID)) { - const calc = dataTransformers.get(name); + const calc = transformersRegistry.get(name); expect(calc.id).toBe(name); } }); @@ -20,7 +20,7 @@ describe('Transformers', () => { }); it('should use fluent API', () => { - const results = dataTransformers.reduce([seriesWithValues], { + const results = transformersRegistry.reduce([seriesWithValues], { reducers: [ReducerID.first], }); expect(results.length).toBe(1); diff --git a/packages/grafana-data/src/transformations/transformersRegistry.ts b/packages/grafana-data/src/transformations/transformersRegistry.ts new file mode 100644 index 00000000000..aa30a85b0f1 --- /dev/null +++ b/packages/grafana-data/src/transformations/transformersRegistry.ts @@ -0,0 +1,43 @@ +import { DataFrame } from '../types/dataFrame'; +import { Registry } from '../utils/registry'; +// Initalize the Registry + +import { appendTransformer, AppendOptions } from './transformers/append'; +import { reduceTransformer, ReduceTransformerOptions } from './transformers/reduce'; +import { filterFieldsTransformer, filterFramesTransformer } from './transformers/filter'; +import { filterFieldsByNameTransformer, FilterFieldsByNameTransformerOptions } from './transformers/filterByName'; +import { noopTransformer } from './transformers/noop'; +import { DataTransformerInfo } from '../types/transformations'; + +/** + * Registry of transformation options that can be driven by + * stored configuration files. + */ +class TransformerRegistry extends Registry { + // ------------------------------------------------------------ + // Nacent options for more functional programming + // The API to these functions should change to match the actual + // needs of people trying to use it. + // filterFields|Frames is left off since it is likely easier to + // support with `frames.filter( f => {...} )` + // ------------------------------------------------------------ + + append(data: DataFrame[], options?: AppendOptions): DataFrame | undefined { + return appendTransformer.transformer(options || appendTransformer.defaultOptions)(data)[0]; + } + + reduce(data: DataFrame[], options: ReduceTransformerOptions): DataFrame[] { + return reduceTransformer.transformer(options)(data); + } +} + +export const transformersRegistry = new TransformerRegistry(() => [ + noopTransformer, + filterFieldsTransformer, + filterFieldsByNameTransformer, + filterFramesTransformer, + appendTransformer, + reduceTransformer, +]); + +export { ReduceTransformerOptions, FilterFieldsByNameTransformerOptions }; diff --git a/packages/grafana-data/src/types/index.ts b/packages/grafana-data/src/types/index.ts index 08340b2d010..fd8d362074a 100644 --- a/packages/grafana-data/src/types/index.ts +++ b/packages/grafana-data/src/types/index.ts @@ -11,3 +11,4 @@ export * from './valueMapping'; export * from './displayValue'; export * from './graph'; export * from './ScopedVars'; +export * from './transformations'; diff --git a/packages/grafana-data/src/types/transformations.ts b/packages/grafana-data/src/types/transformations.ts new file mode 100644 index 00000000000..28a13a163ca --- /dev/null +++ b/packages/grafana-data/src/types/transformations.ts @@ -0,0 +1,32 @@ +import { DataFrame, Field } from './dataFrame'; +import { RegistryItemWithOptions } from '../utils/registry'; + +/** + * Immutable data transformation + */ +export type DataTransformer = (data: DataFrame[]) => DataFrame[]; + +export interface DataTransformerInfo extends RegistryItemWithOptions { + transformer: (options: TOptions) => DataTransformer; +} + +export interface DataTransformerConfig { + id: string; + options: TOptions; +} + +export type FieldMatcher = (field: Field) => boolean; +export type FrameMatcher = (frame: DataFrame) => boolean; + +export interface FieldMatcherInfo extends RegistryItemWithOptions { + get: (options: TOptions) => FieldMatcher; +} + +export interface FrameMatcherInfo extends RegistryItemWithOptions { + get: (options: TOptions) => FrameMatcher; +} + +export interface MatcherConfig { + id: string; + options?: TOptions; +} diff --git a/packages/grafana-data/src/utils/index.ts b/packages/grafana-data/src/utils/index.ts index c5260ac0bad..fb011851ba2 100644 --- a/packages/grafana-data/src/utils/index.ts +++ b/packages/grafana-data/src/utils/index.ts @@ -19,8 +19,3 @@ export { getMappedValue } from './valueMappings'; import * as dateMath from './datemath'; import * as rangeUtil from './rangeutil'; export { dateMath, rangeUtil }; - -export * from './matchers/ids'; -export * from './matchers/matchers'; -export * from './transformers/ids'; -export * from './transformers/transformers'; diff --git a/packages/grafana-data/src/utils/transformers/transformers.ts b/packages/grafana-data/src/utils/transformers/transformers.ts deleted file mode 100644 index 04cee6e7634..00000000000 --- a/packages/grafana-data/src/utils/transformers/transformers.ts +++ /dev/null @@ -1,85 +0,0 @@ -import { DataFrame } from '../../types/dataFrame'; -import { Registry, RegistryItemWithOptions } from '../registry'; - -/** - * Immutable data transformation - */ -export type DataTransformer = (data: DataFrame[]) => DataFrame[]; - -export interface DataTransformerInfo extends RegistryItemWithOptions { - transformer: (options: TOptions) => DataTransformer; -} - -export interface DataTransformerConfig { - id: string; - options: TOptions; -} - -/** - * Apply configured transformations to the input data - */ -export function transformDataFrame(options: DataTransformerConfig[], data: DataFrame[]): DataFrame[] { - let processed = data; - for (const config of options) { - const info = dataTransformers.get(config.id); - const transformer = info.transformer(config.options); - const after = transformer(processed); - - // Add a key to the metadata if the data changed - if (after && after !== processed) { - for (const series of after) { - if (!series.meta) { - series.meta = {}; - } - if (!series.meta.transformations) { - series.meta.transformations = [info.id]; - } else { - series.meta.transformations = [...series.meta.transformations, info.id]; - } - } - processed = after; - } - } - return processed; -} - -// Initalize the Registry - -import { appendTransformer, AppendOptions } from './append'; -import { reduceTransformer, ReduceTransformerOptions } from './reduce'; -import { filterFieldsTransformer, filterFramesTransformer } from './filter'; -import { filterFieldsByNameTransformer, FilterFieldsByNameTransformerOptions } from './filterByName'; -import { noopTransformer } from './noop'; - -/** - * Registry of transformation options that can be driven by - * stored configuration files. - */ -class TransformerRegistry extends Registry { - // ------------------------------------------------------------ - // Nacent options for more functional programming - // The API to these functions should change to match the actual - // needs of people trying to use it. - // filterFields|Frames is left off since it is likely easier to - // support with `frames.filter( f => {...} )` - // ------------------------------------------------------------ - - append(data: DataFrame[], options?: AppendOptions): DataFrame | undefined { - return appendTransformer.transformer(options || appendTransformer.defaultOptions)(data)[0]; - } - - reduce(data: DataFrame[], options: ReduceTransformerOptions): DataFrame[] { - return reduceTransformer.transformer(options)(data); - } -} - -export const dataTransformers = new TransformerRegistry(() => [ - noopTransformer, - filterFieldsTransformer, - filterFieldsByNameTransformer, - filterFramesTransformer, - appendTransformer, - reduceTransformer, -]); - -export { ReduceTransformerOptions, FilterFieldsByNameTransformerOptions }; diff --git a/packages/grafana-ui/src/components/TransformersUI/FilterByNameTransformerEditor.tsx b/packages/grafana-ui/src/components/TransformersUI/FilterByNameTransformerEditor.tsx index b44c130b9b9..9b9561816fd 100644 --- a/packages/grafana-ui/src/components/TransformersUI/FilterByNameTransformerEditor.tsx +++ b/packages/grafana-ui/src/components/TransformersUI/FilterByNameTransformerEditor.tsx @@ -1,5 +1,5 @@ import React, { useContext } from 'react'; -import { FilterFieldsByNameTransformerOptions, DataTransformerID, dataTransformers, KeyValue } from '@grafana/data'; +import { FilterFieldsByNameTransformerOptions, DataTransformerID, transformersRegistry, KeyValue } from '@grafana/data'; import { TransformerUIProps, TransformerUIRegistyItem } from './types'; import { ThemeContext } from '../../themes/ThemeContext'; import { css, cx } from 'emotion'; @@ -157,7 +157,7 @@ const FilterPill: React.FC = ({ label, selected, onClick }) => export const filterFieldsByNameTransformRegistryItem: TransformerUIRegistyItem = { id: DataTransformerID.filterFieldsByName, component: FilterByNameTransformerEditor, - transformer: dataTransformers.get(DataTransformerID.filterFieldsByName), + transformer: transformersRegistry.get(DataTransformerID.filterFieldsByName), name: 'Filter by name', description: 'UI for filter by name transformation', }; diff --git a/packages/grafana-ui/src/components/TransformersUI/ReduceTransformerEditor.tsx b/packages/grafana-ui/src/components/TransformersUI/ReduceTransformerEditor.tsx index d12e9f86e46..484dd10077f 100644 --- a/packages/grafana-ui/src/components/TransformersUI/ReduceTransformerEditor.tsx +++ b/packages/grafana-ui/src/components/TransformersUI/ReduceTransformerEditor.tsx @@ -1,8 +1,7 @@ import React from 'react'; import { StatsPicker } from '../StatsPicker/StatsPicker'; -import { ReduceTransformerOptions, DataTransformerID, ReducerID } from '@grafana/data'; +import { ReduceTransformerOptions, DataTransformerID, ReducerID, transformersRegistry } from '@grafana/data'; import { TransformerUIRegistyItem, TransformerUIProps } from './types'; -import { dataTransformers } from '@grafana/data'; // TODO: Minimal implementation, needs some <3 export const ReduceTransformerEditor: React.FC> = ({ @@ -29,7 +28,7 @@ export const ReduceTransformerEditor: React.FC = { id: DataTransformerID.reduce, component: ReduceTransformerEditor, - transformer: dataTransformers.get(DataTransformerID.reduce), + transformer: transformersRegistry.get(DataTransformerID.reduce), name: 'Reduce', description: 'UI for reduce transformation', };