313 lines
8.0 KiB
TypeScript
313 lines
8.0 KiB
TypeScript
import { toDataFrame } from '../../dataframe/processDataFrame';
|
|
import { FieldType } from '../../types/dataFrame';
|
|
import { mockTransformationsRegistry } from '../../utils/tests/mockTransformationsRegistry';
|
|
import { ArrayVector } from '../../vector';
|
|
|
|
import { calculateFieldTransformer } from './calculateField';
|
|
import { isLikelyAscendingVector, outerJoinDataFrames } from './joinDataFrames';
|
|
|
|
describe('align frames', () => {
|
|
beforeAll(() => {
|
|
mockTransformationsRegistry([calculateFieldTransformer]);
|
|
});
|
|
|
|
it('by first time field', () => {
|
|
const series1 = toDataFrame({
|
|
fields: [
|
|
{ name: 'TheTime', type: FieldType.time, values: [1000, 2000] },
|
|
{ name: 'A', type: FieldType.number, values: [1, 100] },
|
|
],
|
|
});
|
|
|
|
const series2 = toDataFrame({
|
|
fields: [
|
|
{ name: '_time', type: FieldType.time, values: [1000, 1500, 2000] },
|
|
{ name: 'A', type: FieldType.number, values: [2, 20, 200] },
|
|
{ name: 'B', type: FieldType.number, values: [3, 30, 300] },
|
|
{ name: 'C', type: FieldType.string, values: ['first', 'second', 'third'] },
|
|
],
|
|
});
|
|
|
|
const out = outerJoinDataFrames({ frames: [series1, series2] })!;
|
|
expect(
|
|
out.fields.map((f) => ({
|
|
name: f.name,
|
|
values: f.values.toArray(),
|
|
}))
|
|
).toMatchInlineSnapshot(`
|
|
Array [
|
|
Object {
|
|
"name": "TheTime",
|
|
"values": Array [
|
|
1000,
|
|
1500,
|
|
2000,
|
|
],
|
|
},
|
|
Object {
|
|
"name": "A",
|
|
"values": Array [
|
|
1,
|
|
undefined,
|
|
100,
|
|
],
|
|
},
|
|
Object {
|
|
"name": "A",
|
|
"values": Array [
|
|
2,
|
|
20,
|
|
200,
|
|
],
|
|
},
|
|
Object {
|
|
"name": "B",
|
|
"values": Array [
|
|
3,
|
|
30,
|
|
300,
|
|
],
|
|
},
|
|
Object {
|
|
"name": "C",
|
|
"values": Array [
|
|
"first",
|
|
"second",
|
|
"third",
|
|
],
|
|
},
|
|
]
|
|
`);
|
|
});
|
|
|
|
it('unsorted input keep indexes', () => {
|
|
//----------
|
|
const series1 = toDataFrame({
|
|
fields: [
|
|
{ name: 'TheTime', type: FieldType.time, values: [1000, 2000, 1500] },
|
|
{ name: 'A1', type: FieldType.number, values: [1, 2, 15] },
|
|
],
|
|
});
|
|
|
|
const series3 = toDataFrame({
|
|
fields: [
|
|
{ name: 'Time', type: FieldType.time, values: [2000, 1000] },
|
|
{ name: 'A2', type: FieldType.number, values: [2, 1] },
|
|
],
|
|
});
|
|
|
|
let out = outerJoinDataFrames({ frames: [series1, series3], keepOriginIndices: true })!;
|
|
expect(
|
|
out.fields.map((f) => ({
|
|
name: f.name,
|
|
values: f.values.toArray(),
|
|
state: f.state,
|
|
}))
|
|
).toMatchInlineSnapshot(`
|
|
Array [
|
|
Object {
|
|
"name": "TheTime",
|
|
"state": Object {
|
|
"origin": Object {
|
|
"fieldIndex": 0,
|
|
"frameIndex": 0,
|
|
},
|
|
},
|
|
"values": Array [
|
|
1000,
|
|
1500,
|
|
2000,
|
|
],
|
|
},
|
|
Object {
|
|
"name": "A1",
|
|
"state": Object {
|
|
"origin": Object {
|
|
"fieldIndex": 1,
|
|
"frameIndex": 0,
|
|
},
|
|
},
|
|
"values": Array [
|
|
1,
|
|
15,
|
|
2,
|
|
],
|
|
},
|
|
Object {
|
|
"name": "A2",
|
|
"state": Object {
|
|
"origin": Object {
|
|
"fieldIndex": 1,
|
|
"frameIndex": 1,
|
|
},
|
|
},
|
|
"values": Array [
|
|
1,
|
|
undefined,
|
|
2,
|
|
],
|
|
},
|
|
]
|
|
`);
|
|
|
|
// Fast path still adds origin indecies
|
|
out = outerJoinDataFrames({ frames: [series1], keepOriginIndices: true })!;
|
|
expect(
|
|
out.fields.map((f) => ({
|
|
name: f.name,
|
|
state: f.state,
|
|
}))
|
|
).toMatchInlineSnapshot(`
|
|
Array [
|
|
Object {
|
|
"name": "TheTime",
|
|
"state": Object {
|
|
"origin": Object {
|
|
"fieldIndex": 0,
|
|
"frameIndex": 0,
|
|
},
|
|
},
|
|
},
|
|
Object {
|
|
"name": "A1",
|
|
"state": Object {
|
|
"origin": Object {
|
|
"fieldIndex": 1,
|
|
"frameIndex": 0,
|
|
},
|
|
},
|
|
},
|
|
]
|
|
`);
|
|
});
|
|
|
|
it('sort single frame as index zero', () => {
|
|
const series1 = toDataFrame({
|
|
fields: [
|
|
{ name: 'A1', type: FieldType.number, values: [1, 22, 15] },
|
|
{ name: 'TheTime', type: FieldType.time, values: [6000, 2000, 1500] },
|
|
],
|
|
});
|
|
|
|
const out = outerJoinDataFrames({ frames: [series1], keepOriginIndices: true })!;
|
|
expect(
|
|
out.fields.map((f) => ({
|
|
name: f.name,
|
|
values: f.values.toArray(),
|
|
}))
|
|
).toMatchInlineSnapshot(`
|
|
Array [
|
|
Object {
|
|
"name": "TheTime",
|
|
"values": Array [
|
|
1500,
|
|
2000,
|
|
6000,
|
|
],
|
|
},
|
|
Object {
|
|
"name": "A1",
|
|
"values": Array [
|
|
15,
|
|
22,
|
|
1,
|
|
],
|
|
},
|
|
]
|
|
`);
|
|
});
|
|
|
|
it('supports duplicate times', () => {
|
|
//----------
|
|
// NOTE!!!
|
|
// * ideally we would *keep* dupicate fields
|
|
//----------
|
|
const series1 = toDataFrame({
|
|
fields: [
|
|
{ name: 'TheTime', type: FieldType.time, values: [1000, 2000] },
|
|
{ name: 'A', type: FieldType.number, values: [1, 100] },
|
|
],
|
|
});
|
|
|
|
const series3 = toDataFrame({
|
|
fields: [
|
|
{ name: 'Time', type: FieldType.time, values: [1000, 1000, 1000] },
|
|
{ name: 'A', type: FieldType.number, values: [2, 20, 200] },
|
|
],
|
|
});
|
|
|
|
const out = outerJoinDataFrames({ frames: [series1, series3] })!;
|
|
expect(
|
|
out.fields.map((f) => ({
|
|
name: f.name,
|
|
values: f.values.toArray(),
|
|
}))
|
|
).toMatchInlineSnapshot(`
|
|
Array [
|
|
Object {
|
|
"name": "TheTime",
|
|
"values": Array [
|
|
1000,
|
|
2000,
|
|
],
|
|
},
|
|
Object {
|
|
"name": "A",
|
|
"values": Array [
|
|
1,
|
|
100,
|
|
],
|
|
},
|
|
Object {
|
|
"name": "A",
|
|
"values": Array [
|
|
200,
|
|
undefined,
|
|
],
|
|
},
|
|
]
|
|
`);
|
|
});
|
|
|
|
describe('check ascending data', () => {
|
|
it('simple ascending', () => {
|
|
const v = new ArrayVector([1, 2, 3, 4, 5]);
|
|
expect(isLikelyAscendingVector(v)).toBeTruthy();
|
|
});
|
|
it('simple ascending with null', () => {
|
|
const v = new ArrayVector([null, 2, 3, 4, null]);
|
|
expect(isLikelyAscendingVector(v)).toBeTruthy();
|
|
});
|
|
it('single value', () => {
|
|
const v = new ArrayVector([null, null, null, 4, null]);
|
|
expect(isLikelyAscendingVector(v)).toBeTruthy();
|
|
expect(isLikelyAscendingVector(new ArrayVector([4]))).toBeTruthy();
|
|
expect(isLikelyAscendingVector(new ArrayVector([]))).toBeTruthy();
|
|
});
|
|
|
|
it('middle values', () => {
|
|
const v = new ArrayVector([null, null, 5, 4, null]);
|
|
expect(isLikelyAscendingVector(v)).toBeFalsy();
|
|
});
|
|
|
|
it('decending', () => {
|
|
expect(isLikelyAscendingVector(new ArrayVector([7, 6, null]))).toBeFalsy();
|
|
expect(isLikelyAscendingVector(new ArrayVector([7, 8, 6]))).toBeFalsy();
|
|
});
|
|
|
|
it('ascending first/last', () => {
|
|
expect(isLikelyAscendingVector(new ArrayVector([10, 20, 30, 5, 15, 7, 43, 29, 11]), 3)).toBeFalsy();
|
|
expect(
|
|
isLikelyAscendingVector(new ArrayVector([null, 10, 20, 30, 5, null, 15, 7, 43, 29, 11, null]), 3)
|
|
).toBeFalsy();
|
|
});
|
|
|
|
it('null stuffs', () => {
|
|
expect(isLikelyAscendingVector(new ArrayVector([null, null, 1]), 3)).toBeTruthy();
|
|
expect(isLikelyAscendingVector(new ArrayVector([1, null, null]), 3)).toBeTruthy();
|
|
expect(isLikelyAscendingVector(new ArrayVector([null, null, null]), 3)).toBeTruthy();
|
|
expect(isLikelyAscendingVector(new ArrayVector([null, 1, null]), 3)).toBeTruthy();
|
|
});
|
|
});
|
|
});
|