// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ // ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃ // ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃ // ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃ // ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃ // ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫ // ┃ 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);