mirror of
https://github.com/grafana/grafana.git
synced 2024-11-22 00:47:38 -06:00
Transformations: Use fieldMatchers for convertFieldType and add doc (#38769)
This commit is contained in:
parent
caef39b6a4
commit
2a2f10da7e
@ -10,6 +10,7 @@ Grafana comes with the following transformations:
|
||||
- [Add field from calculation]({{< relref "./types-options.md#add-field-from-calculation" >}})
|
||||
- [Concatenate fields]({{< relref "./types-options.md#concatenate-fields" >}})
|
||||
- [Config from query results]({{< relref "./config-from-query.md" >}})
|
||||
- [Convert field type]({{< relref "./types-options.md#convert-field-type" >}})
|
||||
- [Filter data by name]({{< relref "./types-options.md#filter-data-by-name" >}})
|
||||
- [Filter data by query]({{< relref "./types-options.md#filter-data-by-query" >}})
|
||||
- [Filter data by value]({{< relref "./types-options.md#filter-data-by-value" >}})
|
||||
@ -324,6 +325,36 @@ After you concatenate the fields, the data frame would be:
|
||||
| ---- | ------- | --- | ------ |
|
||||
| 15.4 | 1230233 | 3.2 | 5 |
|
||||
|
||||
## Convert field type
|
||||
|
||||
This transformation changes the field type of the specified field.
|
||||
|
||||
- **Field -** Select from available fields
|
||||
- **as -** Select the FieldType to convert to
|
||||
- **Numeric -** attempts to make the values numbers
|
||||
- **String -** will make the values strings
|
||||
- **Time -** attempts to parse the values as time
|
||||
- Will show an option to specify a DateFormat as input by a string like yyyy-mm-dd or DD MM YYYY hh:mm:ss
|
||||
- **Boolean -** will make the values booleans
|
||||
|
||||
For example the following query could be modified by selecting the time field, as Time, and Date Format as YYYY.
|
||||
|
||||
| Time | Mark | Value |
|
||||
| ---------- | ----- | ----- |
|
||||
| 2017-07-01 | above | 25 |
|
||||
| 2018-08-02 | below | 22 |
|
||||
| 2019-09-02 | below | 29 |
|
||||
| 2020-10-04 | above | 22 |
|
||||
|
||||
The result:
|
||||
|
||||
| Time | Mark | Value |
|
||||
| ------------------- | ----- | ----- |
|
||||
| 2017-01-01 00:00:00 | above | 25 |
|
||||
| 2018-01-01 00:00:00 | below | 22 |
|
||||
| 2019-01-01 00:00:00 | below | 29 |
|
||||
| 2020-01-01 00:00:00 | above | 22 |
|
||||
|
||||
## Series to rows
|
||||
|
||||
> **Note:** This transformation is available in Grafana 7.1+.
|
||||
|
@ -5,20 +5,28 @@ import { DataTransformerID } from './ids';
|
||||
import { DataFrame, Field, FieldType } from '../../types/dataFrame';
|
||||
import { dateTimeParse } from '../../datetime';
|
||||
import { ArrayVector } from '../../vector';
|
||||
import { fieldMatchers } from '../matchers';
|
||||
import { FieldMatcherID } from '../matchers/ids';
|
||||
|
||||
export interface ConvertFieldTypeTransformerOptions {
|
||||
conversions: ConvertFieldTypeOptions[];
|
||||
}
|
||||
|
||||
export interface ConvertFieldTypeOptions {
|
||||
/**
|
||||
* The field to convert field type
|
||||
*/
|
||||
targetField?: string;
|
||||
/**
|
||||
* The field type to convert to
|
||||
*/
|
||||
destinationType?: FieldType;
|
||||
/**
|
||||
* Date format to parse a string datetime
|
||||
*/
|
||||
dateFormat?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @alpha
|
||||
*/
|
||||
export const convertFieldTypeTransformer: SynchronousDataTransformerInfo<ConvertFieldTypeTransformerOptions> = {
|
||||
id: DataTransformerID.convertFieldType,
|
||||
name: 'Convert field type',
|
||||
@ -43,32 +51,44 @@ export const convertFieldTypeTransformer: SynchronousDataTransformerInfo<Convert
|
||||
};
|
||||
|
||||
/**
|
||||
* @alpha
|
||||
* Convert field types for dataframe(s)
|
||||
* @param options - field type conversion options
|
||||
* @param frames - dataframe(s) with field types to convert
|
||||
* @returns dataframe(s) with converted field types
|
||||
*/
|
||||
export function convertFieldTypes(options: ConvertFieldTypeTransformerOptions, frames: DataFrame[]): DataFrame[] {
|
||||
if (!options.conversions.length) {
|
||||
return frames;
|
||||
}
|
||||
|
||||
const frameCopy: DataFrame[] = [];
|
||||
const framesCopy = frames.map((frame) => ({ ...frame }));
|
||||
|
||||
frames.forEach((frame) => {
|
||||
for (let fieldIdx = 0; fieldIdx < frame.fields.length; fieldIdx++) {
|
||||
let field = frame.fields[fieldIdx];
|
||||
for (let cIdx = 0; cIdx < options.conversions.length; cIdx++) {
|
||||
if (field.name === options.conversions[cIdx].targetField) {
|
||||
//check in about matchers with Ryan
|
||||
const conversion = options.conversions[cIdx];
|
||||
frame.fields[fieldIdx] = convertFieldType(field, conversion);
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (const conversion of options.conversions) {
|
||||
if (!conversion.targetField) {
|
||||
continue;
|
||||
}
|
||||
frameCopy.push(frame);
|
||||
});
|
||||
return frameCopy;
|
||||
const matches = fieldMatchers.get(FieldMatcherID.byName).get(conversion.targetField);
|
||||
for (const frame of framesCopy) {
|
||||
frame.fields = frame.fields.map((field) => {
|
||||
if (matches(field, frame, framesCopy)) {
|
||||
return convertFieldType(field, conversion);
|
||||
}
|
||||
return field;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return framesCopy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a single field type to specifed field type.
|
||||
* @param field - field to convert
|
||||
* @param opts - field conversion options
|
||||
* @returns converted field
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export function convertFieldType(field: Field, opts: ConvertFieldTypeOptions): Field {
|
||||
switch (opts.destinationType) {
|
||||
case FieldType.time:
|
||||
@ -84,6 +104,9 @@ export function convertFieldType(field: Field, opts: ConvertFieldTypeOptions): F
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export function fieldToTimeField(field: Field, dateFormat?: string): Field {
|
||||
let opts = dateFormat ? { format: dateFormat } : undefined;
|
||||
|
||||
@ -109,12 +132,8 @@ function fieldToNumberField(field: Field): Field {
|
||||
const numValues = field.values.toArray().slice();
|
||||
|
||||
for (let n = 0; n < numValues.length; n++) {
|
||||
if (numValues[n]) {
|
||||
let number = +numValues[n];
|
||||
numValues[n] = Number.isFinite(number) ? number : null;
|
||||
} else {
|
||||
numValues[n] = null;
|
||||
}
|
||||
const number = +numValues[n];
|
||||
numValues[n] = Number.isFinite(number) ? number : null;
|
||||
}
|
||||
|
||||
return {
|
||||
@ -128,7 +147,7 @@ function fieldToBooleanField(field: Field): Field {
|
||||
const booleanValues = field.values.toArray().slice();
|
||||
|
||||
for (let b = 0; b < booleanValues.length; b++) {
|
||||
booleanValues[b] = Boolean(booleanValues[b]);
|
||||
booleanValues[b] = Boolean(!!booleanValues[b]);
|
||||
}
|
||||
|
||||
return {
|
||||
@ -153,7 +172,12 @@ function fieldToStringField(field: Field): Field {
|
||||
}
|
||||
|
||||
/**
|
||||
* @alpha
|
||||
* Checks the first value. Assumes any number should be time fieldtype. Otherwise attempts to make the fieldtype time.
|
||||
* @param field - field to ensure is a time fieldtype
|
||||
* @param dateFormat - date format used to parse a string datetime
|
||||
* @returns field as time
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function ensureTimeField(field: Field, dateFormat?: string): Field {
|
||||
const firstValueTypeIsNumber = typeof field.values.get(0) === 'number';
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { useCallback } from 'react';
|
||||
import React, { ChangeEvent, useCallback } from 'react';
|
||||
import {
|
||||
DataTransformerID,
|
||||
FieldNamePickerConfigSettings,
|
||||
@ -56,9 +56,9 @@ export const ConvertFieldTypeTransformerEditor: React.FC<TransformerUIProps<Conv
|
||||
);
|
||||
|
||||
const onInputFormat = useCallback(
|
||||
(idx) => (value: SelectableValue<string>) => {
|
||||
(idx) => (e: ChangeEvent<HTMLInputElement>) => {
|
||||
const conversions = options.conversions;
|
||||
conversions[idx] = { ...conversions[idx], dateFormat: value.value };
|
||||
conversions[idx] = { ...conversions[idx], dateFormat: e.currentTarget.value };
|
||||
onChange({
|
||||
...options,
|
||||
conversions: conversions,
|
||||
|
Loading…
Reference in New Issue
Block a user