mirror of https://github.com/grafana/grafana
ArrayDataFrame: Convert to a simple utility function rather than dynamically loaded values (#67427)
parent
63383ef545
commit
8352e716dd
@ -1,118 +1,69 @@ |
||||
import { makeArrayIndexableVector, QueryResultMeta } from '../types'; |
||||
import { Field, FieldType, DataFrame } from '../types/dataFrame'; |
||||
import { FunctionalVector } from '../vector/FunctionalVector'; |
||||
import { vectorToArray } from '../vector/vectorToArray'; |
||||
import { QueryResultMeta } from '../types'; |
||||
import { Field, FieldType, DataFrame, TIME_SERIES_VALUE_FIELD_NAME } from '../types/dataFrame'; |
||||
|
||||
import { guessFieldTypeFromNameAndValue, toDataFrameDTO } from './processDataFrame'; |
||||
|
||||
/** @public */ |
||||
export type ValueConverter<T = any> = (val: unknown) => T; |
||||
|
||||
const NOOP: ValueConverter = (v) => v; |
||||
|
||||
class ArrayPropertyVector<T = any> extends FunctionalVector<T> { |
||||
converter = NOOP; |
||||
|
||||
constructor(private source: any[], private prop: string) { |
||||
super(); |
||||
return makeArrayIndexableVector(this); |
||||
} |
||||
|
||||
get length(): number { |
||||
return this.source.length; |
||||
} |
||||
|
||||
get(index: number): T { |
||||
return this.converter(this.source[index][this.prop]); |
||||
} |
||||
|
||||
toArray(): T[] { |
||||
return vectorToArray(this); |
||||
} |
||||
|
||||
toJSON(): T[] { |
||||
return vectorToArray(this); |
||||
} |
||||
} |
||||
import { guessFieldTypeForField } from './processDataFrame'; |
||||
|
||||
/** |
||||
* The ArrayDataFrame takes an array of objects and presents it as a DataFrame |
||||
* |
||||
* @alpha |
||||
* @deprecated use arrayToDataFrame |
||||
*/ |
||||
export class ArrayDataFrame<T = any> extends FunctionalVector<T> implements DataFrame { |
||||
export class ArrayDataFrame<T = any> implements DataFrame { |
||||
fields: Field[] = []; |
||||
length = 0; |
||||
name?: string; |
||||
refId?: string; |
||||
meta?: QueryResultMeta; |
||||
|
||||
fields: Field[] = []; |
||||
length = 0; |
||||
constructor(source: T[], names?: string[]) { |
||||
return arrayToDataFrame(source, names) as ArrayDataFrame<T>; // returns a standard DataFrame
|
||||
} |
||||
} |
||||
|
||||
constructor(private source: T[], names?: string[]) { |
||||
super(); |
||||
/** |
||||
* arrayToDataFrame will convert any array into a DataFrame |
||||
* |
||||
* @public |
||||
*/ |
||||
export function arrayToDataFrame(source: any[], names?: string[]): DataFrame { |
||||
const df: DataFrame = { |
||||
fields: [], |
||||
length: source.length, |
||||
}; |
||||
if (!source?.length) { |
||||
return df; |
||||
} |
||||
|
||||
this.length = source.length; |
||||
const first: any = source.length ? source[0] : {}; |
||||
if (names) { |
||||
this.fields = names.map((name) => { |
||||
return { |
||||
if (names) { |
||||
for (const name of names) { |
||||
df.fields.push( |
||||
makeFieldFromValues( |
||||
name, |
||||
type: guessFieldTypeFromNameAndValue(name, first[name]), |
||||
config: {}, |
||||
values: new ArrayPropertyVector(source, name), |
||||
}; |
||||
}); |
||||
} else { |
||||
this.setFieldsFromObject(first); |
||||
source.map((v) => v[name]) |
||||
) |
||||
); |
||||
} |
||||
return makeArrayIndexableVector(this); |
||||
return df; |
||||
} |
||||
|
||||
/** |
||||
* Add a field for each property in the object. This will guess the type |
||||
*/ |
||||
setFieldsFromObject(obj: Record<string, unknown>) { |
||||
this.fields = Object.keys(obj).map((name) => { |
||||
return { |
||||
name, |
||||
type: guessFieldTypeFromNameAndValue(name, obj[name]), |
||||
config: {}, |
||||
values: new ArrayPropertyVector(this.source, name), |
||||
}; |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* Configure how the object property is passed to the data frame |
||||
*/ |
||||
setFieldType(name: string, type: FieldType, converter?: ValueConverter): Field { |
||||
let field = this.fields.find((f) => f.name === name); |
||||
if (field) { |
||||
field.type = type; |
||||
const first = source.find((v) => v != null); // first not null|undefined
|
||||
if (first != null) { |
||||
if (typeof first === 'object') { |
||||
df.fields = Object.keys(first).map((name) => { |
||||
return makeFieldFromValues( |
||||
name, |
||||
source.map((v) => v[name]) |
||||
); |
||||
}); |
||||
} else { |
||||
field = { |
||||
name, |
||||
type, |
||||
config: {}, |
||||
values: new ArrayPropertyVector(this.source, name), |
||||
}; |
||||
this.fields.push(field); |
||||
df.fields.push(makeFieldFromValues(TIME_SERIES_VALUE_FIELD_NAME, source)); |
||||
} |
||||
(field.values as any).converter = converter ?? NOOP; |
||||
return field; |
||||
} |
||||
|
||||
/** |
||||
* Get an object with a property for each field in the DataFrame |
||||
*/ |
||||
get(idx: number): T { |
||||
return this.source[idx]; |
||||
} |
||||
return df; |
||||
} |
||||
|
||||
/** |
||||
* The simplified JSON values used in JSON.stringify() |
||||
*/ |
||||
toJSON() { |
||||
return toDataFrameDTO(this); |
||||
} |
||||
function makeFieldFromValues(name: string, values: unknown[]): Field { |
||||
const f = { name, config: {}, values, type: FieldType.other }; |
||||
f.type = guessFieldTypeForField(f) ?? FieldType.other; |
||||
return f; |
||||
} |
||||
|
Loading…
Reference in new issue