337 lines
13 KiB
JavaScript
337 lines
13 KiB
JavaScript
// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
|
// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
|
|
// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
|
|
// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
|
|
// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
|
|
// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
|
// ┃ Copyright (c) 2017, the Perspective Authors. ┃
|
|
// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
|
|
// ┃ This file is part of the Perspective library, distributed under the terms ┃
|
|
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
|
|
import { test, expect } from "@perspective-dev/test";
|
|
import perspective from "./perspective_client";
|
|
|
|
((perspective) => {
|
|
test.describe("Pivotting with nulls", function () {
|
|
test.describe("last aggregate", function () {
|
|
test("preserves null when it is the last element in a leaf", async function () {
|
|
const DATA = {
|
|
a: ["a", "a", "a", "b", "b", "b", "c", "c", "c"],
|
|
b: [1, 2, null, 3, 4, 5, null, null, null],
|
|
};
|
|
var table = await perspective.table(DATA);
|
|
var view = await table.view({
|
|
group_by: ["a"],
|
|
columns: ["b"],
|
|
aggregates: { b: "last" },
|
|
});
|
|
var answer = [
|
|
{ __ROW_PATH__: [], b: null },
|
|
{ __ROW_PATH__: ["a"], b: null },
|
|
{ __ROW_PATH__: ["b"], b: 5 },
|
|
{ __ROW_PATH__: ["c"], b: null },
|
|
];
|
|
let result = await view.to_json();
|
|
expect(result).toEqual(answer);
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("preserves null when it is the last element in a leaf under 2 levels", async function () {
|
|
const DATA = {
|
|
a: [
|
|
"a",
|
|
"a",
|
|
"a",
|
|
"b",
|
|
"b",
|
|
"b",
|
|
"c",
|
|
"c",
|
|
"c",
|
|
"a",
|
|
"a",
|
|
"a",
|
|
"b",
|
|
"b",
|
|
"b",
|
|
"c",
|
|
"c",
|
|
"c",
|
|
],
|
|
b: [
|
|
1,
|
|
2,
|
|
null,
|
|
3,
|
|
4,
|
|
5,
|
|
null,
|
|
null,
|
|
null,
|
|
1,
|
|
2,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
3,
|
|
4,
|
|
5,
|
|
],
|
|
c: [
|
|
"x",
|
|
"x",
|
|
"x",
|
|
"x",
|
|
"x",
|
|
"x",
|
|
"x",
|
|
"x",
|
|
"x",
|
|
"y",
|
|
"y",
|
|
"y",
|
|
"y",
|
|
"y",
|
|
"y",
|
|
"y",
|
|
"y",
|
|
"y",
|
|
],
|
|
};
|
|
var table = await perspective.table(DATA);
|
|
var view = await table.view({
|
|
group_by: ["c", "a"],
|
|
columns: ["b"],
|
|
aggregates: { b: "last" },
|
|
});
|
|
var answer = [
|
|
{ __ROW_PATH__: [], b: 5 },
|
|
{ __ROW_PATH__: ["x"], b: null },
|
|
{ __ROW_PATH__: ["x", "a"], b: null },
|
|
{ __ROW_PATH__: ["x", "b"], b: 5 },
|
|
{ __ROW_PATH__: ["x", "c"], b: null },
|
|
{ __ROW_PATH__: ["y"], b: 5 },
|
|
{ __ROW_PATH__: ["y", "a"], b: null },
|
|
{ __ROW_PATH__: ["y", "b"], b: null },
|
|
{ __ROW_PATH__: ["y", "c"], b: 5 },
|
|
];
|
|
let result = await view.to_json();
|
|
expect(result).toEqual(answer);
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("preserves null when it is the last element in a leaf under 2 levels when grand total is null", async function () {
|
|
const DATA = {
|
|
a: [
|
|
"a",
|
|
"a",
|
|
"a",
|
|
"b",
|
|
"b",
|
|
"b",
|
|
"c",
|
|
"c",
|
|
"c",
|
|
"a",
|
|
"a",
|
|
"a",
|
|
"b",
|
|
"b",
|
|
"b",
|
|
"c",
|
|
"c",
|
|
"c",
|
|
],
|
|
b: [
|
|
1,
|
|
2,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
3,
|
|
4,
|
|
5,
|
|
1,
|
|
2,
|
|
null,
|
|
3,
|
|
4,
|
|
5,
|
|
null,
|
|
null,
|
|
null,
|
|
],
|
|
c: [
|
|
"x",
|
|
"x",
|
|
"x",
|
|
"x",
|
|
"x",
|
|
"x",
|
|
"x",
|
|
"x",
|
|
"x",
|
|
"y",
|
|
"y",
|
|
"y",
|
|
"y",
|
|
"y",
|
|
"y",
|
|
"y",
|
|
"y",
|
|
"y",
|
|
],
|
|
};
|
|
var table = await perspective.table(DATA);
|
|
var view = await table.view({
|
|
group_by: ["c", "a"],
|
|
columns: ["b"],
|
|
aggregates: { b: "last" },
|
|
});
|
|
var answer = [
|
|
{ __ROW_PATH__: [], b: null },
|
|
{ __ROW_PATH__: ["x"], b: 5 },
|
|
{ __ROW_PATH__: ["x", "a"], b: null },
|
|
{ __ROW_PATH__: ["x", "b"], b: null },
|
|
{ __ROW_PATH__: ["x", "c"], b: 5 },
|
|
{ __ROW_PATH__: ["y"], b: null },
|
|
{ __ROW_PATH__: ["y", "a"], b: null },
|
|
{ __ROW_PATH__: ["y", "b"], b: 5 },
|
|
{ __ROW_PATH__: ["y", "c"], b: null },
|
|
];
|
|
let result = await view.to_json();
|
|
expect(result).toEqual(answer);
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
});
|
|
|
|
test("shows one pivot for the nulls on initial load", async function () {
|
|
const dataWithNulls = [
|
|
{ name: "Homer", value: 1 },
|
|
{ name: null, value: 1 },
|
|
{ name: null, value: 1 },
|
|
{ name: "Krusty", value: 1 },
|
|
];
|
|
|
|
var table = await perspective.table(dataWithNulls);
|
|
|
|
var view = await table.view({
|
|
group_by: ["name"],
|
|
aggregates: { name: "distinct count" },
|
|
});
|
|
|
|
const answer = [
|
|
{ __ROW_PATH__: [], name: 3, value: 4 },
|
|
{ __ROW_PATH__: [null], name: 1, value: 2 },
|
|
{ __ROW_PATH__: ["Homer"], name: 1, value: 1 },
|
|
{ __ROW_PATH__: ["Krusty"], name: 1, value: 1 },
|
|
];
|
|
|
|
let results = await view.to_json();
|
|
expect(results).toEqual(answer);
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("shows one pivot for the nulls after updating with a null", async function () {
|
|
const dataWithNull1 = [
|
|
{ name: "Homer", value: 1 },
|
|
{ name: null, value: 1 },
|
|
];
|
|
const dataWithNull2 = [
|
|
{ name: null, value: 1 },
|
|
{ name: "Krusty", value: 1 },
|
|
];
|
|
|
|
var table = await perspective.table(dataWithNull1);
|
|
await table.update(dataWithNull2);
|
|
|
|
var view = await table.view({
|
|
group_by: ["name"],
|
|
aggregates: { name: "distinct count" },
|
|
});
|
|
|
|
const answer = [
|
|
{ __ROW_PATH__: [], name: 3, value: 4 },
|
|
{ __ROW_PATH__: [null], name: 1, value: 2 },
|
|
{ __ROW_PATH__: ["Homer"], name: 1, value: 1 },
|
|
{ __ROW_PATH__: ["Krusty"], name: 1, value: 1 },
|
|
];
|
|
|
|
let results = await view.to_json();
|
|
expect(results).toEqual(answer);
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("aggregates that return NaN render correctly", async function () {
|
|
const dataWithNull1 = [
|
|
{ name: "Homer", value: 3 },
|
|
{ name: "Homer", value: 1 },
|
|
{ name: "Marge", value: null },
|
|
{ name: "Marge", value: null },
|
|
];
|
|
|
|
var table = await perspective.table(dataWithNull1);
|
|
|
|
var view = await table.view({
|
|
group_by: ["name"],
|
|
aggregates: { value: "avg" },
|
|
});
|
|
|
|
const answer = [
|
|
{ __ROW_PATH__: [], name: 4, value: 2 },
|
|
{ __ROW_PATH__: ["Homer"], name: 2, value: 2 },
|
|
{ __ROW_PATH__: ["Marge"], name: 2, value: null },
|
|
];
|
|
|
|
let results = await view.to_json();
|
|
expect(results).toEqual(answer);
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("aggregates nulls correctly", async function () {
|
|
const data = [
|
|
{ x: "AAAAAAAAAAAAAA" },
|
|
{ x: "AAAAAAAAAAAAAA" },
|
|
{ x: "AAAAAAAAAAAAAA" },
|
|
{ x: null },
|
|
{ x: null },
|
|
{ x: "BBBBBBBBBBBBBB" },
|
|
{ x: "BBBBBBBBBBBBBB" },
|
|
{ x: "BBBBBBBBBBBBBB" },
|
|
];
|
|
const tbl = await perspective.table(data);
|
|
const view = await tbl.view({ group_by: ["x"] });
|
|
|
|
const result = await view.to_json();
|
|
expect(result).toEqual([
|
|
{
|
|
__ROW_PATH__: [],
|
|
x: 8,
|
|
},
|
|
{
|
|
__ROW_PATH__: [null],
|
|
x: 2,
|
|
},
|
|
{
|
|
__ROW_PATH__: ["AAAAAAAAAAAAAA"],
|
|
x: 3,
|
|
},
|
|
{
|
|
__ROW_PATH__: ["BBBBBBBBBBBBBB"],
|
|
x: 3,
|
|
},
|
|
]);
|
|
});
|
|
});
|
|
})(perspective);
|