mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Arrow DataFrame: cast BigInt/UInt to numbers (#25811)
This commit is contained in:
parent
629ce6897d
commit
f59d7acee6
@ -7,13 +7,15 @@ describe('Array DataFrame', () => {
|
|||||||
{ name: 'first', value: 1, time: 123 },
|
{ name: 'first', value: 1, time: 123 },
|
||||||
{ name: 'second', value: 2, time: 456, extra: 'here' },
|
{ name: 'second', value: 2, time: 456, extra: 'here' },
|
||||||
{ name: 'third', value: 3, time: 789 },
|
{ name: 'third', value: 3, time: 789 },
|
||||||
|
{ name: '4th (NaN)', value: NaN, time: 1000 },
|
||||||
|
{ name: '5th (Null)', value: null, time: 1100 },
|
||||||
];
|
];
|
||||||
|
|
||||||
const frame = new ArrayDataFrame(input);
|
const frame = new ArrayDataFrame(input);
|
||||||
frame.name = 'Hello';
|
frame.name = 'Hello';
|
||||||
frame.refId = 'Z';
|
frame.refId = 'Z';
|
||||||
frame.setFieldType('phantom', FieldType.string, v => '🦥');
|
frame.setFieldType('phantom', FieldType.string, v => '🦥');
|
||||||
const field = frame.fields.find(f => f.name == 'value');
|
const field = frame.fields.find(f => f.name === 'value');
|
||||||
field!.config.unit = 'kwh';
|
field!.config.unit = 'kwh';
|
||||||
|
|
||||||
test('Should support functional methods', () => {
|
test('Should support functional methods', () => {
|
||||||
@ -48,6 +50,8 @@ describe('Array DataFrame', () => {
|
|||||||
"first",
|
"first",
|
||||||
"second",
|
"second",
|
||||||
"third",
|
"third",
|
||||||
|
"4th (NaN)",
|
||||||
|
"5th (Null)",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
Object {
|
Object {
|
||||||
@ -61,6 +65,8 @@ describe('Array DataFrame', () => {
|
|||||||
1,
|
1,
|
||||||
2,
|
2,
|
||||||
3,
|
3,
|
||||||
|
NaN,
|
||||||
|
null,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
Object {
|
Object {
|
||||||
@ -72,6 +78,8 @@ describe('Array DataFrame', () => {
|
|||||||
123,
|
123,
|
||||||
456,
|
456,
|
||||||
789,
|
789,
|
||||||
|
1000,
|
||||||
|
1100,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
Object {
|
Object {
|
||||||
@ -83,6 +91,8 @@ describe('Array DataFrame', () => {
|
|||||||
"🦥",
|
"🦥",
|
||||||
"🦥",
|
"🦥",
|
||||||
"🦥",
|
"🦥",
|
||||||
|
"🦥",
|
||||||
|
"🦥",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { DataFrame, FieldType, Field, Vector } from '../types';
|
import { DataFrame, FieldType, Field, Vector } from '../types';
|
||||||
|
import { FunctionalVector } from '../vector/FunctionalVector';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Table,
|
Table,
|
||||||
@ -48,14 +49,18 @@ export function arrowTableToDataFrame(table: Table): ArrowDataFrame {
|
|||||||
if (col) {
|
if (col) {
|
||||||
const schema = table.schema.fields[i];
|
const schema = table.schema.fields[i];
|
||||||
let type = FieldType.other;
|
let type = FieldType.other;
|
||||||
const values: Vector<any> = col;
|
let values: Vector<any> = col;
|
||||||
switch ((schema.typeId as unknown) as ArrowType) {
|
switch ((schema.typeId as unknown) as ArrowType) {
|
||||||
case ArrowType.Decimal:
|
case ArrowType.Decimal:
|
||||||
case ArrowType.Int:
|
|
||||||
case ArrowType.FloatingPoint: {
|
case ArrowType.FloatingPoint: {
|
||||||
type = FieldType.number;
|
type = FieldType.number;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case ArrowType.Int: {
|
||||||
|
type = FieldType.number;
|
||||||
|
values = new NumberColumn(col); // Cast to number
|
||||||
|
break;
|
||||||
|
}
|
||||||
case ArrowType.Bool: {
|
case ArrowType.Bool: {
|
||||||
type = FieldType.boolean;
|
type = FieldType.boolean;
|
||||||
break;
|
break;
|
||||||
@ -73,7 +78,7 @@ export function arrowTableToDataFrame(table: Table): ArrowDataFrame {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fields.push({
|
fields.push({
|
||||||
name: stripFieldNamePrefix(col.name),
|
name: col.name,
|
||||||
type,
|
type,
|
||||||
values,
|
values,
|
||||||
config: parseOptionalMeta(col.metadata.get('config')) || {},
|
config: parseOptionalMeta(col.metadata.get('config')) || {},
|
||||||
@ -92,17 +97,6 @@ export function arrowTableToDataFrame(table: Table): ArrowDataFrame {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// fieldNamePrefixSep is the delimiter used with fieldNamePrefix.
|
|
||||||
const fieldNamePrefixSep = '🦥: ';
|
|
||||||
|
|
||||||
function stripFieldNamePrefix(name: string): string {
|
|
||||||
const idx = name.indexOf(fieldNamePrefixSep);
|
|
||||||
if (idx > 0) {
|
|
||||||
return name.substring(idx + fieldNamePrefixSep.length);
|
|
||||||
}
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
function toArrowVector(field: Field): ArrowVector {
|
function toArrowVector(field: Field): ArrowVector {
|
||||||
// OR: Float64Vector.from([1, 2, 3]));
|
// OR: Float64Vector.from([1, 2, 3]));
|
||||||
|
|
||||||
@ -129,17 +123,10 @@ export function grafanaDataFrameToArrowTable(data: DataFrame): Table {
|
|||||||
if (table instanceof Table) {
|
if (table instanceof Table) {
|
||||||
return table as Table;
|
return table as Table;
|
||||||
}
|
}
|
||||||
// Make sure the names are unique
|
|
||||||
const names = new Set<string>();
|
|
||||||
|
|
||||||
table = Table.new(
|
table = Table.new(
|
||||||
data.fields.map((field, index) => {
|
data.fields.map((field, index) => {
|
||||||
let name = field.name;
|
const column = Column.new(field.name, toArrowVector(field));
|
||||||
if (names.has(field.name)) {
|
|
||||||
name = `${index}${fieldNamePrefixSep}${field.name}`;
|
|
||||||
}
|
|
||||||
names.add(name);
|
|
||||||
const column = Column.new(name, toArrowVector(field));
|
|
||||||
if (field.labels) {
|
if (field.labels) {
|
||||||
column.metadata.set('labels', JSON.stringify(field.labels));
|
column.metadata.set('labels', JSON.stringify(field.labels));
|
||||||
}
|
}
|
||||||
@ -161,3 +148,26 @@ export function grafanaDataFrameToArrowTable(data: DataFrame): Table {
|
|||||||
}
|
}
|
||||||
return table;
|
return table;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class NumberColumn extends FunctionalVector<number> {
|
||||||
|
constructor(private col: Column) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
get length() {
|
||||||
|
return this.col.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
get(index: number): number {
|
||||||
|
const v = this.col.get(index);
|
||||||
|
if (v === null || isNaN(v)) {
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The conversion operations are always silent, never give errors,
|
||||||
|
// but if the bigint is too huge and won’t fit the number type,
|
||||||
|
// then extra bits will be cut off, so we should be careful doing such conversion.
|
||||||
|
// See https://javascript.info/bigint
|
||||||
|
return Number(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -21,6 +21,7 @@ Object {
|
|||||||
Object {
|
Object {
|
||||||
"config": Object {
|
"config": Object {
|
||||||
"decimals": 2,
|
"decimals": 2,
|
||||||
|
"displayName": "Grafana ❤️ (Previous should be heart emoji) 🦥 (Previous should be sloth emoji)",
|
||||||
"filterable": false,
|
"filterable": false,
|
||||||
"links": Array [
|
"links": Array [
|
||||||
Object {
|
Object {
|
||||||
@ -33,7 +34,6 @@ Object {
|
|||||||
"min": null,
|
"min": null,
|
||||||
"noValue": "😤",
|
"noValue": "😤",
|
||||||
"nullValueMode": "null",
|
"nullValueMode": "null",
|
||||||
"title": "Grafana ❤️ (Previous should be heart emoji) 🦥 (Previous should be sloth emoji)",
|
|
||||||
},
|
},
|
||||||
"labels": Object {
|
"labels": Object {
|
||||||
"aLabelKey": "aLabelValue",
|
"aLabelKey": "aLabelValue",
|
||||||
@ -136,11 +136,11 @@ Object {
|
|||||||
"name": "int64_values",
|
"name": "int64_values",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"values": Array [
|
"values": Array [
|
||||||
"\\"-9223372036854775808\\"",
|
-9223372036854776000,
|
||||||
"\\"-9007199254740991\\"",
|
-9007199254740991,
|
||||||
"\\"1\\"",
|
1,
|
||||||
"\\"9007199254740991\\"",
|
9007199254740991,
|
||||||
"\\"9223372036854775807\\"",
|
9223372036854776000,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
Object {
|
Object {
|
||||||
@ -149,11 +149,11 @@ Object {
|
|||||||
"name": "nullable_int64_values",
|
"name": "nullable_int64_values",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"values": Array [
|
"values": Array [
|
||||||
"\\"-9223372036854775808\\"",
|
-9223372036854776000,
|
||||||
"\\"-9007199254740991\\"",
|
-9007199254740991,
|
||||||
null,
|
null,
|
||||||
"\\"9007199254740991\\"",
|
9007199254740991,
|
||||||
"\\"9223372036854775807\\"",
|
9223372036854776000,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
Object {
|
Object {
|
||||||
@ -240,11 +240,11 @@ Object {
|
|||||||
"name": "uint64_values",
|
"name": "uint64_values",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"values": Array [
|
"values": Array [
|
||||||
"\\"0\\"",
|
0,
|
||||||
"\\"0\\"",
|
0,
|
||||||
"\\"1\\"",
|
1,
|
||||||
"\\"9007199254740991\\"",
|
9007199254740991,
|
||||||
"\\"18446744073709551615\\"",
|
18446744073709552000,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
Object {
|
Object {
|
||||||
@ -253,11 +253,11 @@ Object {
|
|||||||
"name": "nullable_uint64_values",
|
"name": "nullable_uint64_values",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"values": Array [
|
"values": Array [
|
||||||
"\\"0\\"",
|
0,
|
||||||
"\\"0\\"",
|
0,
|
||||||
null,
|
null,
|
||||||
"\\"9007199254740991\\"",
|
9007199254740991,
|
||||||
"\\"18446744073709551615\\"",
|
18446744073709552000,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
Object {
|
Object {
|
||||||
@ -351,6 +351,19 @@ Object {
|
|||||||
9223372036854.775,
|
9223372036854.775,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
Object {
|
||||||
|
"config": Object {},
|
||||||
|
"labels": undefined,
|
||||||
|
"name": "timestamps",
|
||||||
|
"type": "time",
|
||||||
|
"values": Array [
|
||||||
|
0,
|
||||||
|
1568039445000,
|
||||||
|
1568039450000,
|
||||||
|
9007199254.740992,
|
||||||
|
9223372036854.775,
|
||||||
|
],
|
||||||
|
},
|
||||||
Object {
|
Object {
|
||||||
"config": Object {},
|
"config": Object {},
|
||||||
"labels": undefined,
|
"labels": undefined,
|
||||||
@ -366,13 +379,9 @@ Object {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
"meta": Object {
|
"meta": Object {
|
||||||
"limit": 4242,
|
"custom": Object {
|
||||||
"searchWords": Array [
|
"Hi": "there",
|
||||||
"Grafana",
|
},
|
||||||
"❤️",
|
|
||||||
" 🦥 ",
|
|
||||||
"test",
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
"name": "many_types",
|
"name": "many_types",
|
||||||
"refId": "A",
|
"refId": "A",
|
||||||
|
Binary file not shown.
Loading…
Reference in New Issue
Block a user