diff --git a/.betterer.results b/.betterer.results index 83032798feb..2e2644ad9aa 100644 --- a/.betterer.results +++ b/.betterer.results @@ -439,6 +439,11 @@ exports[`better eslint`] = { [0, 0, 0, "Unexpected any. Specify a different type.", "3"], [0, 0, 0, "Unexpected any. Specify a different type.", "4"] ], + "packages/grafana-data/src/vector/ArrayVector.ts:5381": [ + [0, 0, 0, "Unexpected any. Specify a different type.", "0"], + [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/CircularVector.ts:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"] ], diff --git a/packages/grafana-data/src/vector/ArrayVector.test.ts b/packages/grafana-data/src/vector/ArrayVector.test.ts new file mode 100644 index 00000000000..3d9ae35fc5f --- /dev/null +++ b/packages/grafana-data/src/vector/ArrayVector.test.ts @@ -0,0 +1,45 @@ +import { Field, FieldType } from '../types'; + +import { ArrayVector } from './ArrayVector'; + +describe('ArrayVector', () => { + beforeEach(() => { + jest.spyOn(console, 'warn').mockImplementation(); + }); + + it('should init 150k with 65k Array.push() chonking', () => { + const arr = Array.from({ length: 150e3 }, (v, i) => i); + const av = new ArrayVector(arr); + + expect(av.toArray()).toEqual(arr); + }); + + it('should support add and push', () => { + const av = new ArrayVector(); + av.add(1); + av.push(2); + av.push(3, 4); + + expect(av.toArray()).toEqual([1, 2, 3, 4]); + }); + + it('typescript should not re-define the ArrayVector based on input to the constructor', () => { + const field: Field = { + name: 'test', + config: {}, + type: FieldType.number, + values: new ArrayVector(), // this defaults to `new ArrayVector()` + }; + expect(field).toBeDefined(); + + // Before collapsing Vector, ReadWriteVector, and MutableVector these all worked fine + field.values = new ArrayVector(); + field.values = new ArrayVector(undefined); + field.values = new ArrayVector([1, 2, 3]); + field.values = new ArrayVector([]); + field.values = new ArrayVector([1, undefined]); + field.values = new ArrayVector([null]); + field.values = new ArrayVector(['a', 'b', 'c']); + expect(field.values.length).toBe(3); + }); +}); diff --git a/packages/grafana-data/src/vector/ArrayVector.ts b/packages/grafana-data/src/vector/ArrayVector.ts new file mode 100644 index 00000000000..01b615162b7 --- /dev/null +++ b/packages/grafana-data/src/vector/ArrayVector.ts @@ -0,0 +1,46 @@ +const notice = 'ArrayVector is deprecated and will be removed in Grafana 11. Please use plain arrays for field.values.'; +let notified = false; + +/** + * @public + * + * @deprecated use a simple Array + */ +export class ArrayVector extends Array { + get buffer() { + return this; + } + + set buffer(values: any[]) { + this.length = 0; + + const len = values?.length; + + if (len) { + let chonkSize = 65e3; + let numChonks = Math.ceil(len / chonkSize); + + for (let chonkIdx = 0; chonkIdx < numChonks; chonkIdx++) { + this.push.apply(this, values.slice(chonkIdx * chonkSize, (chonkIdx + 1) * chonkSize)); + } + } + } + + /** + * This any type is here to make the change type changes in v10 non breaking for plugins. + * Before you could technically assign field.values any typed ArrayVector no matter what the Field T type was. + */ + constructor(buffer?: any[]) { + super(); + this.buffer = buffer ?? []; + + if (!notified) { + console.warn(notice); + notified = true; + } + } + + toJSON(): T[] { + return [...this]; // copy to avoid circular reference (only for jest) + } +}