diff --git a/packages/grafana-data/src/dataframe/ArrowDataFrame.test.ts b/packages/grafana-data/src/dataframe/ArrowDataFrame.test.ts index d7beb342353..cf3da3d4fc4 100644 --- a/packages/grafana-data/src/dataframe/ArrowDataFrame.test.ts +++ b/packages/grafana-data/src/dataframe/ArrowDataFrame.test.ts @@ -71,7 +71,27 @@ describe('Read/Write arrow Table to DataFrame', () => { expect(after).toEqual(before); }); - test('should parse output with dataframe', () => { + test('should support duplicate field names', () => { + const frame = toDataFrame({ + name: 'Hello', + refId: 'XYZ', + fields: [ + { name: 'time', config: {}, type: FieldType.time, values: [1, 2, 3] }, + { name: 'a', values: [1, 2, 3] }, + { name: 'a', values: ['a', 'b', 'c'] }, + ], + }); + + const table = grafanaDataFrameToArrowTable(frame); + expect(table.length).toEqual(frame.length); + + // Now back to DataFrame + const before = JSON.stringify(toDataFrameDTO(frame), null, 2); + const after = JSON.stringify(toDataFrameDTO(arrowTableToDataFrame(table)), null, 2); + expect(after).toEqual(before); + }); + + test('should read all types', () => { const fullpath = path.resolve(__dirname, './__snapshots__/all_types.golden.arrow'); const arrow = fs.readFileSync(fullpath); const table = Table.from([arrow]); diff --git a/packages/grafana-data/src/dataframe/ArrowDataFrame.ts b/packages/grafana-data/src/dataframe/ArrowDataFrame.ts index 16c6ab3be36..311721a936b 100644 --- a/packages/grafana-data/src/dataframe/ArrowDataFrame.ts +++ b/packages/grafana-data/src/dataframe/ArrowDataFrame.ts @@ -72,7 +72,7 @@ export function arrowTableToDataFrame(table: Table): ArrowDataFrame { } fields.push({ - name: col.name, + name: stripFieldNamePrefix(col.name), type, values, config: parseOptionalMeta(col.metadata.get('config')) || {}, @@ -91,6 +91,17 @@ 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 { // OR: Float64Vector.from([1, 2, 3])); @@ -117,10 +128,17 @@ export function grafanaDataFrameToArrowTable(data: DataFrame): Table { if (table instanceof Table) { return table as Table; } + // Make sure the names are unique + const names = new Set(); table = Table.new( - data.fields.map(field => { - const column = Column.new(field.name, toArrowVector(field)); + data.fields.map((field, index) => { + let name = field.name; + if (names.has(field.name)) { + name = `${index}${fieldNamePrefixSep}${field.name}`; + } + names.add(name); + const column = Column.new(name, toArrowVector(field)); if (field.labels) { column.metadata.set('labels', JSON.stringify(field.labels)); } diff --git a/packages/grafana-data/src/dataframe/__snapshots__/ArrowDataFrame.test.ts.snap b/packages/grafana-data/src/dataframe/__snapshots__/ArrowDataFrame.test.ts.snap index ec232bff1b7..358c55e3907 100644 --- a/packages/grafana-data/src/dataframe/__snapshots__/ArrowDataFrame.test.ts.snap +++ b/packages/grafana-data/src/dataframe/__snapshots__/ArrowDataFrame.test.ts.snap @@ -103,7 +103,7 @@ Array [ ] `; -exports[`Read/Write arrow Table to DataFrame should parse output with dataframe 1`] = ` +exports[`Read/Write arrow Table to DataFrame should read all types 1`] = ` Object { "fields": Array [ Object { diff --git a/packages/grafana-data/src/dataframe/__snapshots__/all_types.golden.arrow b/packages/grafana-data/src/dataframe/__snapshots__/all_types.golden.arrow index d1732b1e782..67f764eee6c 100644 Binary files a/packages/grafana-data/src/dataframe/__snapshots__/all_types.golden.arrow and b/packages/grafana-data/src/dataframe/__snapshots__/all_types.golden.arrow differ