FieldValues: Implement array accessors for deprecated Vector types (#66807)

pull/66813/head
Ryan McKinley 2 years ago committed by GitHub
parent 9452c0d718
commit 987eff82a3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 26
      .betterer.results
  2. 38
      packages/grafana-data/src/transformations/transformers/calculateField.ts
  3. 2
      packages/grafana-data/src/transformations/transformers/convertFieldType.ts
  4. 27
      packages/grafana-data/src/types/vector.ts
  5. 3
      packages/grafana-data/src/vector/AppendedVectors.test.ts
  6. 5
      packages/grafana-data/src/vector/AppendedVectors.ts
  7. 17
      packages/grafana-data/src/vector/AsNumberVector.ts
  8. 8
      packages/grafana-data/src/vector/BinaryOperationVector.test.ts
  9. 29
      packages/grafana-data/src/vector/BinaryOperationVector.ts
  10. 4
      packages/grafana-data/src/vector/CircularVector.test.ts
  11. 3
      packages/grafana-data/src/vector/CircularVector.ts
  12. 3
      packages/grafana-data/src/vector/ConstantVector.test.ts
  13. 26
      packages/grafana-data/src/vector/ConstantVector.ts
  14. 18
      packages/grafana-data/src/vector/FormattedVector.ts
  15. 23
      packages/grafana-data/src/vector/IndexVector.ts
  16. 33
      packages/grafana-data/src/vector/RowVector.ts
  17. 13
      packages/grafana-data/src/vector/SortedVector.test.ts
  18. 3
      packages/grafana-data/src/vector/SortedVector.ts

@ -270,8 +270,11 @@ exports[`better eslint`] = {
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
],
"packages/grafana-data/src/transformations/transformers/calculateField.ts:5381": [
[0, 0, 0, "Do not use any type assertions.", "0"],
[0, 0, 0, "Do not use any type assertions.", "1"]
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
[0, 0, 0, "Unexpected any. Specify a different type.", "1"],
[0, 0, 0, "Do not use any type assertions.", "2"],
[0, 0, 0, "Do not use any type assertions.", "3"],
[0, 0, 0, "Unexpected any. Specify a different type.", "4"]
],
"packages/grafana-data/src/transformations/transformers/ensureColumns.ts:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
@ -497,7 +500,9 @@ exports[`better eslint`] = {
[0, 0, 0, "Unexpected any. Specify a different type.", "8"],
[0, 0, 0, "Unexpected any. Specify a different type.", "9"],
[0, 0, 0, "Unexpected any. Specify a different type.", "10"],
[0, 0, 0, "Unexpected any. Specify a different type.", "11"]
[0, 0, 0, "Unexpected any. Specify a different type.", "11"],
[0, 0, 0, "Do not use any type assertions.", "12"],
[0, 0, 0, "Unexpected any. Specify a different type.", "13"]
],
"packages/grafana-data/src/utils/OptionsUIBuilders.ts:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
@ -664,15 +669,23 @@ exports[`better eslint`] = {
[0, 0, 0, "Unexpected any. Specify a different type.", "1"],
[0, 0, 0, "Unexpected any. Specify a different type.", "2"]
],
"packages/grafana-data/src/vector/AsNumberVector.ts:5381": [
[0, 0, 0, "Do not use any type assertions.", "0"]
],
"packages/grafana-data/src/vector/BinaryOperationVector.ts:5381": [
[0, 0, 0, "Do not use any type assertions.", "0"]
],
"packages/grafana-data/src/vector/CircularVector.ts:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
[0, 0, 0, "Unexpected any. Specify a different type.", "1"]
],
"packages/grafana-data/src/vector/ConstantVector.ts:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
[0, 0, 0, "Do not use any type assertions.", "1"]
],
"packages/grafana-data/src/vector/FormattedVector.ts:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
[0, 0, 0, "Do not use any type assertions.", "1"]
],
"packages/grafana-data/src/vector/FunctionalVector.ts:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
@ -687,6 +700,9 @@ exports[`better eslint`] = {
[0, 0, 0, "Unexpected any. Specify a different type.", "9"],
[0, 0, 0, "Unexpected any. Specify a different type.", "10"]
],
"packages/grafana-data/src/vector/IndexVector.ts:5381": [
[0, 0, 0, "Do not use any type assertions.", "0"]
],
"packages/grafana-data/src/vector/SortedVector.ts:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
],

@ -3,11 +3,8 @@ import { map } from 'rxjs/operators';
import { getTimeField } from '../../dataframe/processDataFrame';
import { getFieldDisplayName } from '../../field';
import { DataFrame, DataTransformerInfo, Field, FieldType, NullValueMode, Vector } from '../../types';
import { DataFrame, DataTransformerInfo, Field, FieldType, NullValueMode } from '../../types';
import { BinaryOperationID, binaryOperators } from '../../utils/binaryOperators';
import { BinaryOperationVector, ConstantVector } from '../../vector';
import { AsNumberVector } from '../../vector/AsNumberVector';
import { RowVector } from '../../vector/RowVector';
import { doStandardCalcs, fieldReducers, ReducerID } from '../fieldReducer';
import { getFieldMatcher } from '../matchers';
import { FieldMatcherID } from '../matchers/ids';
@ -61,7 +58,7 @@ export interface CalculateFieldTransformerOptions {
// TODO: config?: FieldConfig; or maybe field overrides? since the UI exists
}
type ValuesCreator = (data: DataFrame) => Vector;
type ValuesCreator = (data: DataFrame) => any[];
export const calculateFieldTransformer: DataTransformerInfo<CalculateFieldTransformerOptions> = {
id: DataTransformerID.calculateField,
@ -181,7 +178,7 @@ function getReduceRowCreator(options: ReduceOptions, allFrames: DataFrame[]): Va
return (frame: DataFrame) => {
// Find the columns that should be examined
const columns: Vector[] = [];
const columns: any[] = [];
for (const field of frame.fields) {
if (matcher(field, frame, allFrames)) {
columns.push(field.values);
@ -189,26 +186,31 @@ function getReduceRowCreator(options: ReduceOptions, allFrames: DataFrame[]): Va
}
// Prepare a "fake" field for the row
const iter = new RowVector(columns);
const size = columns.length;
const row: Field = {
name: 'temp',
values: iter,
values: new Array(size),
type: FieldType.number,
config: {},
};
const vals: number[] = [];
for (let i = 0; i < frame.length; i++) {
iter.rowIndex = i;
const val = reducer(row, ignoreNulls, nullAsZero)[options.reducer];
vals.push(val);
for (let j = 0; j < size; j++) {
row.values[j] = columns[j][i];
}
vals.push(reducer(row, ignoreNulls, nullAsZero)[options.reducer]);
}
return vals;
};
}
function findFieldValuesWithNameOrConstant(frame: DataFrame, name: string, allFrames: DataFrame[]): Vector | undefined {
function findFieldValuesWithNameOrConstant(
frame: DataFrame,
name: string,
allFrames: DataFrame[]
): number[] | undefined {
if (!name) {
return undefined;
}
@ -216,7 +218,7 @@ function findFieldValuesWithNameOrConstant(frame: DataFrame, name: string, allFr
for (const f of frame.fields) {
if (name === getFieldDisplayName(f, frame, allFrames)) {
if (f.type === FieldType.boolean) {
return new AsNumberVector(f.values);
return f.values.map((v) => (v ? 1 : 0));
}
return f.values;
}
@ -224,7 +226,7 @@ function findFieldValuesWithNameOrConstant(frame: DataFrame, name: string, allFr
const v = parseFloat(name);
if (!isNaN(v)) {
return new ConstantVector(v, frame.length);
return new Array(frame.length).fill(v);
}
return undefined;
@ -237,10 +239,14 @@ function getBinaryCreator(options: BinaryOptions, allFrames: DataFrame[]): Value
const left = findFieldValuesWithNameOrConstant(frame, options.left, allFrames);
const right = findFieldValuesWithNameOrConstant(frame, options.right, allFrames);
if (!left || !right || !operator) {
return undefined as unknown as Vector;
return undefined as unknown as any[];
}
return new BinaryOperationVector(left, right, operator.operation);
const arr = new Array(left.length);
for (let i = 0; i < arr.length; i++) {
arr[i] = operator.operation(left[i], right[i]);
}
return arr;
};
}

@ -147,7 +147,7 @@ function fieldToNumberField(field: Field): Field {
for (let n = 0; n < numValues.length; n++) {
let toBeConverted = numValues[n];
if (valuesAsStrings) {
if (valuesAsStrings && toBeConverted != null) {
// some numbers returned from datasources have commas
// strip the commas, coerce the string to a number
toBeConverted = toBeConverted.replace(/,/g, '');

@ -97,3 +97,30 @@ export interface ReadWriteVector<T = any> extends Vector<T> {}
* @deprecated -- this is now part of the base Vector interface
*/
export interface MutableVector<T = any> extends ReadWriteVector<T> {}
/**
* This is an extremely inefficient Vector wrapper that allows vectors to
* be treated as arrays. We should avoid using this wrapper, but it is helpful
* for a clean migration to arrays
*
* @deprecated
*/
export function makeArrayIndexableVector<T extends Vector>(v: T): T {
return new Proxy(v, {
get(target: Vector, property: string, receiver: Vector) {
const idx = +property;
if (String(idx) === property) {
return target.get(idx);
}
return Reflect.get(target, property, receiver);
},
set(target: Vector, property: string, value: any, receiver: Vector) {
const idx = +property;
if (String(idx) === property) {
target.set(idx, value);
return true;
}
return Reflect.set(target, property, value, receiver);
},
}) as T;
}

@ -8,6 +8,9 @@ describe('Check Appending Vector', () => {
appended.append(new ArrayVector([4, 5, 6]));
appended.append(new ArrayVector([7, 8, 9]));
expect(appended.length).toEqual(9);
expect(appended[0]).toEqual(1);
expect(appended[1]).toEqual(2);
expect(appended[100]).toEqual(undefined);
appended.setLength(5);
expect(appended.length).toEqual(5);

@ -1,4 +1,4 @@
import { Vector } from '../types/vector';
import { Vector, makeArrayIndexableVector } from '../types/vector';
import { FunctionalVector } from './FunctionalVector';
import { vectorToArray } from './vectorToArray';
@ -14,7 +14,7 @@ interface AppendedVectorInfo<T> {
* RAM -- rather than allocate a new array the size of all previous arrays, this just
* points the correct index to their original array values
*
* @deprecated use a simple Arrays
* @deprecated use a simple Arrays. NOTE this is not used in grafana core
*/
export class AppendedVectors<T = any> extends FunctionalVector<T> {
length = 0;
@ -23,6 +23,7 @@ export class AppendedVectors<T = any> extends FunctionalVector<T> {
constructor(startAt = 0) {
super();
this.length = startAt;
return makeArrayIndexableVector(this);
}
/**

@ -1,23 +1,14 @@
import { Vector } from '../types';
import { FunctionalVector } from './FunctionalVector';
/**
* This will force all values to be numbers
*
* @public
* @deprecated use a simple Arrays
* @deprecated use a simple Arrays. NOTE: Not used in grafana core
*/
export class AsNumberVector extends FunctionalVector<number> {
constructor(private field: Vector) {
export class AsNumberVector extends Array<number> {
constructor(field: Vector) {
super();
}
get length() {
return this.field.length;
}
get(index: number) {
return +this.field.get(index);
return field.map((v) => +v) as AsNumberVector;
}
}

@ -11,9 +11,13 @@ describe('ScaledVector', () => {
const operation = binaryOperators.get(BinaryOperationID.Multiply).operation;
const v = new BinaryOperationVector(source, new ConstantVector(scale, source.length), operation);
expect(v.length).toEqual(source.length);
// expect(v.push(10)).toEqual(source.length); // not implemented
for (let i = 0; i < 10; i++) {
// Accessed with getters
for (let i = 0; i < 4; i++) {
expect(v.get(i)).toEqual(source.get(i) * scale);
}
// Accessed with array index
for (let i = 0; i < 4; i++) {
expect(v[i]).toEqual(source[i] * scale);
}
});
});

@ -1,31 +1,18 @@
import { Vector } from '../types/vector';
import { BinaryOperation } from '../utils/binaryOperators';
import { FunctionalVector } from './FunctionalVector';
import { vectorToArray } from './vectorToArray';
/**
* @public
* @deprecated use a simple Arrays
* @deprecated use a simple Arrays. NOTE: Not used in grafana core
*/
export class BinaryOperationVector extends FunctionalVector<number> {
constructor(private left: Vector<number>, private right: Vector<number>, private operation: BinaryOperation) {
export class BinaryOperationVector extends Array<number> {
constructor(left: Vector<number>, right: Vector<number>, operation: BinaryOperation) {
super();
}
get length(): number {
return this.left.length;
}
get(index: number): number {
return this.operation(this.left.get(index), this.right.get(index));
}
toArray(): number[] {
return vectorToArray(this);
}
toJSON(): number[] {
return vectorToArray(this);
const arr = new Array(left.length);
for (let i = 0; i < arr.length; i++) {
arr[i] = operation(left[i], right[i]);
}
return arr as BinaryOperationVector;
}
}

@ -5,6 +5,10 @@ describe('Check Circular Vector', () => {
const buffer = [1, 2, 3];
const v = new CircularVector({ buffer }); // tail is default option
expect(v.toArray()).toEqual([1, 2, 3]);
expect(v[0]).toEqual(1);
expect(v[1]).toEqual(2);
expect(v[2]).toEqual(3);
expect(v[3]).toEqual(1); // loops back to one
v.add(4);
expect(v.toArray()).toEqual([2, 3, 4]);

@ -1,3 +1,5 @@
import { makeArrayIndexableVector } from '../types';
import { FunctionalVector } from './FunctionalVector';
interface CircularOptions<T> {
@ -34,6 +36,7 @@ export class CircularVector<T = any> extends FunctionalVector<T> {
if (options.capacity) {
this.setCapacity(options.capacity);
}
return makeArrayIndexableVector(this);
}
/**

@ -10,8 +10,9 @@ describe('ConstantVector', () => {
expect(v.get(1)).toEqual(value);
// Now check all of them
for (let i = 0; i < 10; i++) {
for (let i = 0; i < 7; i++) {
expect(v.get(i)).toEqual(value);
expect(v[i]).toEqual(value);
}
});
});

@ -1,28 +1,10 @@
import { FunctionalVector } from './FunctionalVector';
/**
* @public
* @deprecated use a simple Arrays
* @deprecated use a simple Arrays. NOTE: Not used in grafana core.
*/
export class ConstantVector<T = any> extends FunctionalVector<T> {
constructor(private value: T, private len: number) {
export class ConstantVector<T = any> extends Array<T> {
constructor(value: T, len: number) {
super();
}
get length() {
return this.len;
}
get(index: number): T {
return this.value;
}
toArray(): T[] {
const arr = new Array<T>(this.length);
return arr.fill(this.value);
}
toJSON(): T[] {
return this.toArray();
return new Array<T>(len).fill(value) as ConstantVector<T>;
}
}

@ -2,23 +2,13 @@ import { DisplayProcessor } from '../types';
import { Vector } from '../types/vector';
import { formattedValueToString } from '../valueFormats';
import { FunctionalVector } from './FunctionalVector';
/**
* @public
* @deprecated use a simple Arrays
* @deprecated use a simple Arrays. NOTE: not used in grafana core.
*/
export class FormattedVector<T = any> extends FunctionalVector<string> {
constructor(private source: Vector<T>, private formatter: DisplayProcessor) {
export class FormattedVector<T = any> extends Array<string> {
constructor(source: Vector<T>, formatter: DisplayProcessor) {
super();
}
get length() {
return this.source.length;
}
get(index: number): string {
const v = this.source.get(index);
return formattedValueToString(this.formatter(v));
return source.map((v) => formattedValueToString(formatter(v))) as FormattedVector<T>;
}
}

@ -1,29 +1,26 @@
import { Field, FieldType } from '../types';
import { FunctionalVector } from './FunctionalVector';
/**
* IndexVector is a simple vector implementation that returns the index value
* for each element in the vector. It is functionally equivolant a vector backed
* by an array with values: `[0,1,2,...,length-1]`
*
* @deprecated use a simple Arrays
* @deprecated use a simple Arrays. NOTE: not used in grafana core
*/
export class IndexVector extends FunctionalVector<number> {
constructor(private len: number) {
export class IndexVector extends Array<number> {
constructor(len: number) {
super();
}
get length() {
return this.len;
}
get(index: number): number {
return index;
const arr = new Array(len);
for (let i = 0; i < len; i++) {
arr[i] = i;
}
return arr as IndexVector;
}
/**
* Returns a field representing the range [0 ... length-1]
*
* @deprecated
*/
static newField(len: number): Field<number> {
return {

@ -1,33 +0,0 @@
import { Vector } from '../types';
import { FunctionalVector } from './FunctionalVector';
import { vectorToArray } from './vectorToArray';
/**
* RowVector makes the row values look like a vector
* @internal
* @deprecated use a simple Arrays
*/
export class RowVector extends FunctionalVector<number> {
constructor(private columns: Vector[]) {
super();
}
rowIndex = 0;
get length(): number {
return this.columns.length;
}
get(index: number): number {
return this.columns[index].get(this.rowIndex);
}
toArray(): number[] {
return vectorToArray(this);
}
toJSON(): number[] {
return vectorToArray(this);
}
}

@ -0,0 +1,13 @@
import { ArrayVector } from './ArrayVector';
import { SortedVector } from './SortedVector';
describe('SortedVector', () => {
it('Should support sorting', () => {
const values = new ArrayVector([1, 5, 2, 4]);
const sorted = new SortedVector(values, [0, 2, 3, 1]);
expect(sorted.toArray()).toEqual([1, 2, 4, 5]);
// The proxy should still be an instance of SortedVector (used in timeseries)
expect(sorted instanceof SortedVector).toBeTruthy();
});
});

@ -1,4 +1,4 @@
import { Vector } from '../types/vector';
import { makeArrayIndexableVector, Vector } from '../types/vector';
import { FunctionalVector } from './FunctionalVector';
import { vectorToArray } from './vectorToArray';
@ -11,6 +11,7 @@ import { vectorToArray } from './vectorToArray';
export class SortedVector<T = any> extends FunctionalVector<T> {
constructor(private source: Vector<T>, private order: number[]) {
super();
return makeArrayIndexableVector(this);
}
get length(): number {

Loading…
Cancel
Save