ExtractFields: properly detect value types from extracted fields (#41995)

This commit is contained in:
Ryan McKinley 2021-11-19 09:50:30 -08:00 committed by GitHub
parent cf995ea420
commit 82cf49143d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 61 additions and 35 deletions

View File

@ -11,6 +11,7 @@ import { DataFrameDTO, FieldType, TableData, TimeSeries } from '../types/index';
import { dateTime } from '../datetime/moment_wrapper';
import { MutableDataFrame } from './MutableDataFrame';
import { ArrayDataFrame } from './ArrayDataFrame';
import { getFieldTypeFromValue } from '.';
describe('toDataFrame', () => {
it('converts timeseries to series', () => {
@ -118,15 +119,13 @@ describe('toDataFrame', () => {
expect(guessFieldTypeFromValue('xxxx')).toBe(FieldType.string);
});
it('Guess Column Types from strings', () => {
expect(guessFieldTypeFromValue('1')).toBe(FieldType.number);
expect(guessFieldTypeFromValue('1.234')).toBe(FieldType.number);
expect(guessFieldTypeFromValue('NaN')).toBe(FieldType.number);
expect(guessFieldTypeFromValue('3.125e7')).toBe(FieldType.number);
expect(guessFieldTypeFromValue('True')).toBe(FieldType.boolean);
expect(guessFieldTypeFromValue('FALSE')).toBe(FieldType.boolean);
expect(guessFieldTypeFromValue('true')).toBe(FieldType.boolean);
expect(guessFieldTypeFromValue('xxxx')).toBe(FieldType.string);
it('Get column types from values', () => {
expect(getFieldTypeFromValue(1)).toBe(FieldType.number);
expect(getFieldTypeFromValue(1.234)).toBe(FieldType.number);
expect(getFieldTypeFromValue(NaN)).toBe(FieldType.number);
expect(getFieldTypeFromValue(3.125e7)).toBe(FieldType.number);
expect(getFieldTypeFromValue(true)).toBe(FieldType.boolean);
expect(getFieldTypeFromValue('xxxx')).toBe(FieldType.string);
});
it('Guess Column Types from series', () => {

View File

@ -189,10 +189,33 @@ export function guessFieldTypeFromNameAndValue(name: string, v: any): FieldType
return guessFieldTypeFromValue(v);
}
/**
* Check the field type to see what the contents are
*/
export function getFieldTypeFromValue(v: any): FieldType {
if (v instanceof Date || isDateTime(v)) {
return FieldType.time;
}
if (isNumber(v)) {
return FieldType.number;
}
if (isString(v)) {
return FieldType.string;
}
if (isBoolean(v)) {
return FieldType.boolean;
}
return FieldType.other;
}
/**
* Given a value this will guess the best column type
*
* TODO: better Date/Time support! Look for standard date strings?
* NOTE: this is will try to see if string values can be mapped to other types (like number)
*/
export function guessFieldTypeFromValue(v: any): FieldType {
if (v instanceof Date || isDateTime(v)) {
@ -237,7 +260,7 @@ export function guessFieldTypeForField(field: Field): FieldType | undefined {
// 2. Check the first non-null value
for (let i = 0; i < field.values.length; i++) {
const v = field.values.get(i);
if (v !== null) {
if (v != null) {
return guessFieldTypeFromValue(v);
}
}

View File

@ -14,23 +14,28 @@ describe('Fields from JSON', () => {
const frames = extractFieldsTransformer.transformer(cfg)([data]);
expect(frames.length).toEqual(1);
expect(frames[0].fields.map((v) => v.name)).toMatchInlineSnapshot(`
Array [
"a",
"av",
"c",
"e",
"ev",
"h",
"l",
"o",
"op",
"s",
"sym",
"v",
"vw",
"z",
]
expect(
frames[0].fields.reduce((acc, v) => {
acc[v.name] = v.type;
return acc;
}, {} as any)
).toMatchInlineSnapshot(`
Object {
"a": "string",
"av": "number",
"c": "string",
"e": "number",
"ev": "string",
"h": "string",
"l": "string",
"o": "string",
"op": "string",
"s": "number",
"sym": "string",
"v": "number",
"vw": "string",
"z": "number",
}
`);
});
});

View File

@ -4,7 +4,7 @@ import {
DataTransformerID,
Field,
FieldType,
guessFieldTypeForField,
getFieldTypeFromValue,
SynchronousDataTransformerInfo,
} from '@grafana/data';
import { findField } from 'app/features/dimensions';
@ -72,14 +72,13 @@ function addExtractedFields(frame: DataFrame, options: ExtractFieldsOptions): Da
}
const fields = names.map((name) => {
const f: Field = {
const buffer = values.get(name);
return {
name,
values: new ArrayVector(values.get(name)),
type: FieldType.boolean,
values: new ArrayVector(buffer),
type: buffer ? getFieldTypeFromValue(buffer.find((v) => v != null)) : FieldType.other,
config: {},
};
f.type = guessFieldTypeForField(f) ?? FieldType.other;
return f;
} as Field;
});
if (!options.replace) {