// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ // ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃ // ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃ // ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃ // ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃ // ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫ // ┃ 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"; import { STD_DATE, int_float_string_data, pivoted_output } from "./_shared"; ((perspective) => { test.describe("to_arrow()", function () { test("serializes boolean arrays correctly", async function () { // prevent regression in boolean parsing let table = await perspective.table({ bool: [true, false, true, false, true, false, false], }); let view = await table.view(); let arrow = await view.to_arrow(); let json = await view.to_json(); expect(json).toEqual([ { bool: true }, { bool: false }, { bool: true }, { bool: false }, { bool: true }, { bool: false }, { bool: false }, ]); let table2 = await perspective.table(arrow); let view2 = await table2.view(); let json2 = await view2.to_json(); expect(json2).toEqual(json); view2.delete(); table2.delete(); view.delete(); table.delete(); }); test("does not break when booleans are undefined", async function () { let table = await perspective.table([ { int: 1, bool: true }, { int: 2, bool: false }, { int: 3, bool: true }, { int: 4, bool: undefined }, ]); let view = await table.view(); let arrow = await view.to_arrow(); let json = await view.to_json(); expect(json).toEqual([ { int: 1, bool: true }, { int: 2, bool: false }, { int: 3, bool: true }, { int: 4, bool: null }, ]); let table2 = await perspective.table(arrow); let view2 = await table2.view(); let json2 = await view2.to_json(); expect(json2).toEqual(json); view2.delete(); table2.delete(); view.delete(); table.delete(); }); test("arrow output respects start/end rows", async function () { let table = await perspective.table(int_float_string_data); let view = await table.view(); let arrow = await view.to_arrow({ start_row: 1, end_row: 2, }); let json2 = await view.to_json(); //expect(arrow.byteLength).toEqual(1010); let table2 = await perspective.table(arrow); let view2 = await table2.view(); let json = await view2.to_json(); expect(json).toEqual(json2.slice(1, 2)); view2.delete(); table2.delete(); view.delete(); table.delete(); }); test("Transitive arrow output 0-sided", async function () { let table = await perspective.table(int_float_string_data); let view = await table.view(); let arrow = await view.to_arrow(); let json2 = await view.to_json(); //expect(arrow.byteLength).toEqual(1010); let table2 = await perspective.table(arrow); let view2 = await table2.view(); let json = await view2.to_json(); expect(json).toEqual(json2); view2.delete(); table2.delete(); view.delete(); table.delete(); }); test("Transitive arrow output 0-sided hidden sort", async function () { let table = await perspective.table(int_float_string_data); let view = await table.view({ columns: ["float"], sort: [["string", "desc"]], }); let arrow = await view.to_arrow(); let json2 = await view.to_json(); //expect(arrow.byteLength).toEqual(1010); let table2 = await perspective.table(arrow); let view2 = await table2.view(); let json = await view2.to_json(); expect(json).toEqual(json2); view2.delete(); table2.delete(); view.delete(); table.delete(); }); test("Transitive arrow output 0-sided, with row range", async function () { let table = await perspective.table(int_float_string_data); let view = await table.view(); let arrow = await view.to_arrow({ start_row: 1, end_row: 3 }); let json2 = await view.to_json({ start_row: 1, end_row: 3 }); // expect(arrow.byteLength).toEqual(908); let table2 = await perspective.table(arrow); let view2 = await table2.view(); let json = await view2.to_json(); expect(json).toEqual(json2); expect(json.length).toEqual(2); view2.delete(); table2.delete(); view.delete(); table.delete(); }); test("Transitive arrow output 0-sided, with col range", async function () { let table = await perspective.table(int_float_string_data); let view = await table.view(); let arrow = await view.to_arrow({ start_col: 1, end_col: 3 }); let json2 = await view.to_json({ start_col: 1, end_col: 3 }); // expect(arrow.byteLength).toEqual(908); let table2 = await perspective.table(arrow); let view2 = await table2.view(); let json = await view2.to_json(); expect(json).toEqual(json2); expect(json.length).toEqual(4); view2.delete(); table2.delete(); view.delete(); table.delete(); }); test("Transitive arrow output 1-sided", async function () { let table = await perspective.table(int_float_string_data); let view = await table.view({ group_by: ["string"] }); let json = await view.to_json(); let arrow = await view.to_arrow(); let table2 = await perspective.table(arrow); let view2 = await table2.view(); let json2 = await view2.to_json(); expect(json).toEqual( json2.map((x) => { x.__ROW_PATH__ = [x["string (Group by 1)"]].filter( (x) => x, ); delete x["string (Group by 1)"]; return x; }), ); view2.delete(); table2.delete(); view.delete(); table.delete(); }); test("Arrow output 1-sided mean", async function () { let table = await perspective.table({ float: [1.25, 2.25, 3.25, 4.25], string: ["a", "a", "b", "b"], }); let view = await table.view({ group_by: ["string"], aggregates: { float: "mean" }, }); let arrow = await view.to_arrow(); let table2 = await perspective.table(arrow); let view2 = await table2.view(); let result = await view2.to_columns(); expect(result).toEqual({ "string (Group by 1)": [null, "a", "b"], float: [2.75, 1.75, 3.75], string: [4, 2, 2], }); await view2.delete(); await table2.delete(); await view.delete(); await table.delete(); }); test("Transitive arrow output 1-sided mean", async function () { let table = await perspective.table(int_float_string_data); let view = await table.view({ group_by: ["string"], aggregates: { float: "mean" }, }); let json = await view.to_json(); let arrow = await view.to_arrow(); let table2 = await perspective.table(arrow); let view2 = await table2.view(); let json2 = await view2.to_json(); expect(json).toEqual( json2.map((x) => { x.__ROW_PATH__ = [x["string (Group by 1)"]].filter( (x) => x, ); delete x["string (Group by 1)"]; return x; }), ); view2.delete(); table2.delete(); view.delete(); table.delete(); }); test("Transitive arrow output 1-sided sorted mean", async function () { let table = await perspective.table(int_float_string_data); let view = await table.view({ group_by: ["string"], aggregates: { float: "mean" }, sort: [["string", "desc"]], }); let json = await view.to_json(); let arrow = await view.to_arrow(); let table2 = await perspective.table(arrow); let view2 = await table2.view(); let json2 = await view2.to_json(); expect(json).toEqual( json2.map((x) => { x.__ROW_PATH__ = [x["string (Group by 1)"]].filter( (x) => x, ); delete x["string (Group by 1)"]; return x; }), ); view2.delete(); table2.delete(); view.delete(); table.delete(); }); test("Transitive arrow output 1-sided hidden sort mean", async function () { let table = await perspective.table(int_float_string_data); let view = await table.view({ group_by: ["string"], aggregates: { float: "mean" }, columns: ["float", "int"], sort: [["string", "desc"]], }); let json = await view.to_json(); let arrow = await view.to_arrow(); let table2 = await perspective.table(arrow); let view2 = await table2.view(); let json2 = await view2.to_json(); expect(json).toEqual( json2.map((x) => { x.__ROW_PATH__ = [x["string (Group by 1)"]].filter( (x) => x, ); delete x["string (Group by 1)"]; return x; }), ); view2.delete(); table2.delete(); view.delete(); table.delete(); }); test("Transitive arrow output 1-sided with row range", async function () { let table = await perspective.table(int_float_string_data); let view = await table.view({ group_by: ["string"] }); let json = await view.to_json({ start_row: 1, end_row: 3 }); let arrow = await view.to_arrow({ start_row: 1, end_row: 3 }); let table2 = await perspective.table(arrow); let view2 = await table2.view(); let json2 = await view2.to_json(); expect(json).toEqual( json2.map((x) => { x.__ROW_PATH__ = [x["string (Group by 1)"]].filter( (x) => x, ); delete x["string (Group by 1)"]; return x; }), ); view2.delete(); table2.delete(); view.delete(); table.delete(); }); test("Transitive arrow output 1-sided with col range", async function () { let table = await perspective.table(int_float_string_data); let view = await table.view({ group_by: ["string"] }); let json = await view.to_json({ start_col: 1, end_col: 3 }); let arrow = await view.to_arrow({ start_col: 1, end_col: 3 }); let table2 = await perspective.table(arrow); let view2 = await table2.view(); let json2 = await view2.to_json(); expect(json).toEqual( json2.map((x) => { x.__ROW_PATH__ = [x["string (Group by 1)"]].filter( (x) => x, ); delete x["string (Group by 1)"]; return x; }), ); view2.delete(); table2.delete(); view.delete(); table.delete(); }); test("Transitive arrow output 2-sided", async function () { let table = await perspective.table(int_float_string_data); let view = await table.view({ group_by: ["string"], split_by: ["int"], }); let json = await view.to_json(); let arrow = await view.to_arrow(); let table2 = await perspective.table(arrow); let view2 = await table2.view(); let json2 = await view2.to_json(); expect(json).toEqual( json2.map((x) => { x.__ROW_PATH__ = [x["string (Group by 1)"]].filter( (x) => x, ); delete x["string (Group by 1)"]; return x; }), ); view2.delete(); table2.delete(); view.delete(); table.delete(); }); test("Transitive arrow output 2-sided sorted", async function () { let table = await perspective.table(int_float_string_data); let view = await table.view({ group_by: ["string"], split_by: ["int"], sort: [["int", "desc"]], }); let json = await view.to_json(); let arrow = await view.to_arrow(); let table2 = await perspective.table(arrow); let view2 = await table2.view(); let json2 = await view2.to_json(); expect(json).toEqual( json2.map((x) => { x.__ROW_PATH__ = [x["string (Group by 1)"]].filter( (x) => x, ); delete x["string (Group by 1)"]; return x; }), ); view2.delete(); table2.delete(); view.delete(); table.delete(); }); test("Transitive arrow output 2-sided with row range", async function () { let table = await perspective.table(int_float_string_data); let view = await table.view({ group_by: ["string"], split_by: ["int"], }); let json = await view.to_json({ start_row: 1, end_row: 3 }); let arrow = await view.to_arrow({ start_row: 1, end_row: 3 }); let table2 = await perspective.table(arrow); let view2 = await table2.view(); let json2 = await view2.to_json(); expect(json).toEqual( json2.map((x) => { x.__ROW_PATH__ = [x["string (Group by 1)"]].filter( (x) => x, ); delete x["string (Group by 1)"]; return x; }), ); view2.delete(); table2.delete(); view.delete(); table.delete(); }); test("Transitive arrow output 2-sided with col range", async function () { let table = await perspective.table(int_float_string_data); let view = await table.view({ group_by: ["string"], split_by: ["int"], }); let json = await view.to_json({ start_col: 1, end_col: 3 }); let arrow = await view.to_arrow({ start_col: 1, end_col: 3 }); let table2 = await perspective.table(arrow); let view2 = await table2.view(); let json2 = await view2.to_json(); expect(json).toEqual( json2.map((x) => { x.__ROW_PATH__ = [x["string (Group by 1)"]].filter( (x) => x, ); delete x["string (Group by 1)"]; return x; }), ); view2.delete(); table2.delete(); view.delete(); table.delete(); }); test("Transitive arrow output 2-sided column only", async function () { let table = await perspective.table(int_float_string_data); let view = await table.view({ split_by: ["string"] }); let json = await view.to_json(); let arrow = await view.to_arrow(); let table2 = await perspective.table(arrow); let view2 = await table2.view(); let json2 = await view2.to_json(); expect(json).toEqual(json2); view2.delete(); table2.delete(); view.delete(); table.delete(); }); test("Transitive arrow output 2-sided column only hidden sort", async function () { let table = await perspective.table(int_float_string_data); let view = await table.view({ split_by: ["string"], columns: ["float"], sort: [["int", "desc"]], }); let json = await view.to_json(); let arrow = await view.to_arrow(); let table2 = await perspective.table(arrow); let view2 = await table2.view(); let json2 = await view2.to_json(); expect(json).toEqual(json2); view2.delete(); table2.delete(); view.delete(); table.delete(); }); test("Transitive arrow output 2-sided column only sorted", async function () { let table = await perspective.table(int_float_string_data); let view = await table.view({ split_by: ["string"], sort: [["int", "desc"]], }); let json = await view.to_json(); let arrow = await view.to_arrow(); let table2 = await perspective.table(arrow); let view2 = await table2.view(); let json2 = await view2.to_json(); expect(json).toEqual(json2); view2.delete(); table2.delete(); view.delete(); table.delete(); }); test("Transitive arrow output 2-sided column only row range", async function () { let table = await perspective.table(int_float_string_data); let view = await table.view({ split_by: ["string"] }); let json = await view.to_json({ start_row: 1, end_row: 3 }); let arrow = await view.to_arrow({ start_row: 1, end_row: 3 }); let table2 = await perspective.table(arrow); let view2 = await table2.view(); let json2 = await view2.to_json(); expect(json).toEqual(json2); view2.delete(); table2.delete(); view.delete(); table.delete(); }); test("Transitive arrow output 2-sided column only col range", async function () { let table = await perspective.table(int_float_string_data); let view = await table.view({ split_by: ["string"] }); let json = await view.to_json({ start_col: 1, end_col: 3 }); let arrow = await view.to_arrow({ start_col: 1, end_col: 3 }); let table2 = await perspective.table(arrow); let view2 = await table2.view(); let json2 = await view2.to_json(); expect(json).toEqual(json2); view2.delete(); table2.delete(); view.delete(); table.delete(); }); test.describe("to_format with index", function () { test.describe("0-sided", function () { test("should return correct pkey for unindexed table", async function () { let table = await perspective.table(int_float_string_data); let view = await table.view(); let json = await view.to_json({ start_row: 0, end_row: 1, start_col: 1, end_col: 2, index: true, }); expect(json).toEqual([{ float: 2.25, __INDEX__: [0] }]); view.delete(); table.delete(); }); test("should return correct pkey for float indexed table", async function () { let table = await perspective.table(int_float_string_data, { index: "float", }); let view = await table.view(); let json = await view.to_json({ start_row: 0, end_row: 1, start_col: 1, end_col: 2, index: true, }); expect(json).toEqual([{ float: 2.25, __INDEX__: [2.25] }]); view.delete(); table.delete(); }); test("should return correct pkey for string indexed table", async function () { let table = await perspective.table(int_float_string_data, { index: "string", }); let view = await table.view(); let json = await view.to_json({ start_row: 0, end_row: 1, start_col: 1, end_col: 2, index: true, }); expect(json).toEqual([{ float: 2.25, __INDEX__: ["a"] }]); view.delete(); table.delete(); }); test("should return correct pkey for date indexed table", async function () { // default data generates the same datetime for each row, thus pkeys get collapsed const data = [ { int: 1, datetime: new Date() }, { int: 2, datetime: new Date() }, ]; data[1].datetime.setDate(data[1].datetime.getDate() + 1); let table = await perspective.table(data, { index: "datetime", }); let view = await table.view(); let json = await view.to_json({ start_row: 1, end_row: 2, index: true, }); expect(json).toEqual([ { int: 2, datetime: data[1].datetime.getTime(), __INDEX__: [data[1].datetime.getTime()], }, ]); view.delete(); table.delete(); }); test("should return correct pkey for all rows + columns on an unindexed table", async function () { let table = await perspective.table(int_float_string_data); let view = await table.view(); let json = await view.to_json({ index: true, }); for (let i = 0; i < json.length; i++) { expect(json[i].__INDEX__).toEqual([i]); } view.delete(); table.delete(); }); test("should return correct pkey for all rows + columns on an indexed table", async function () { let table = await perspective.table(int_float_string_data, { index: "string", }); let view = await table.view(); let json = await view.to_json({ index: true, }); let pkeys = ["a", "b", "c", "d"]; for (let i = 0; i < json.length; i++) { expect(json[i].__INDEX__).toEqual([pkeys[i]]); } view.delete(); table.delete(); }); }); }); test.describe("0-sided column subset", function () { test("should return correct pkey for unindexed table", async function () { let table = await perspective.table(int_float_string_data); let view = await table.view({ columns: ["int", "datetime"], }); let json = await view.to_json({ start_row: 0, end_row: 1, start_col: 1, end_col: 2, index: true, }); expect(json).toEqual([ { datetime: int_float_string_data[0]["datetime"].getTime(), __INDEX__: [0], }, ]); view.delete(); table.delete(); }); test("should return correct pkey for float indexed table", async function () { let table = await perspective.table(int_float_string_data, { index: "float", }); let view = await table.view({ columns: ["float", "int"], }); let json = await view.to_json({ start_row: 0, end_row: 1, start_col: 1, end_col: 2, index: true, }); expect(json).toEqual([{ int: 1, __INDEX__: [2.25] }]); view.delete(); table.delete(); }); test("should return correct pkey for string indexed table", async function () { let table = await perspective.table(int_float_string_data, { index: "string", }); let view = await table.view({ columns: ["string", "datetime"], }); let json = await view.to_json({ start_row: 0, end_row: 1, start_col: 1, end_col: 2, index: true, }); expect(json).toEqual([ { datetime: int_float_string_data[0]["datetime"].getTime(), __INDEX__: ["a"], }, ]); view.delete(); table.delete(); }); test("should return correct pkey for date indexed table", async function () { // default data generates the same datetime for each row, thus pkeys get collapsed const data = [ { int: 1, datetime: new Date() }, { int: 2, datetime: new Date() }, ]; data[1].datetime.setDate(data[1].datetime.getDate() + 1); let table = await perspective.table(data, { index: "datetime", }); let view = await table.view({ columns: ["int"], }); let json = await view.to_json({ start_row: 1, end_row: 2, index: true, }); expect(json).toEqual([ { int: 2, __INDEX__: [data[1].datetime.getTime()] }, ]); view.delete(); table.delete(); }); test("should return correct pkey for all rows + columns on an unindexed table", async function () { let table = await perspective.table(int_float_string_data); let view = await table.view({ columns: ["int"], }); let json = await view.to_json({ index: true, }); for (let i = 0; i < json.length; i++) { expect(json[i].__INDEX__).toEqual([i]); } view.delete(); table.delete(); }); test("should return correct pkey for all rows + columns on an indexed table", async function () { let table = await perspective.table(int_float_string_data, { index: "string", }); let view = await table.view(); let json = await view.to_json({ index: true, }); let pkeys = ["a", "b", "c", "d"]; for (let i = 0; i < json.length; i++) { expect(json[i].__INDEX__).toEqual([pkeys[i]]); } view.delete(); table.delete(); }); }); test.describe("0-sided column subset invalid bounds", function () { test("should return correct pkey for unindexed table, invalid column", async function () { let table = await perspective.table(int_float_string_data); let view = await table.view({ columns: ["int"], }); let json = await view.to_json({ start_row: 0, end_row: 1, start_col: 1, end_col: 2, index: true, }); expect(json).toEqual([{ __INDEX__: [0] }]); view.delete(); table.delete(); }); test("should not return pkey for unindexed table, invalid row", async function () { let table = await perspective.table(int_float_string_data); let view = await table.view({ columns: ["int"], }); let json = await view.to_json({ start_row: 10, end_row: 15, index: true, }); expect(json).toEqual([]); view.delete(); table.delete(); }); test("should return correct pkey for float indexed table, invalid column", async function () { let table = await perspective.table(int_float_string_data, { index: "float", }); let view = await table.view({ columns: ["float"], }); let json = await view.to_json({ start_row: 0, end_row: 1, start_col: 1, end_col: 2, index: true, }); expect(json).toEqual([{ __INDEX__: [2.25] }]); view.delete(); table.delete(); }); test("should not return pkey for float indexed table, invalid row", async function () { let table = await perspective.table(int_float_string_data, { index: "float", }); let view = await table.view({ columns: ["float"], }); let json = await view.to_json({ start_row: 10, end_row: 15, start_col: 1, end_col: 2, index: true, }); expect(json).toEqual([]); view.delete(); table.delete(); }); test("should return correct pkey for string indexed table, invalid column", async function () { let table = await perspective.table(int_float_string_data, { index: "string", }); let view = await table.view({ columns: ["string"], }); let json = await view.to_json({ start_row: 0, end_row: 1, start_col: 1, end_col: 2, index: true, }); expect(json).toEqual([{ __INDEX__: ["a"] }]); view.delete(); table.delete(); }); test("should not return pkey for string indexed table, invalid row", async function () { let table = await perspective.table(int_float_string_data, { index: "string", }); let view = await table.view({ columns: ["string"], }); let json = await view.to_json({ start_row: 10, end_row: 11, start_col: 1, end_col: 2, index: true, }); expect(json).toEqual([]); view.delete(); table.delete(); }); test("should return correct pkey for date indexed table, invalid column", async function () { // default data generates the same datetime for each row, thus pkeys get collapsed const data = [ { int: 1, datetime: new Date() }, { int: 2, datetime: new Date() }, ]; data[1].datetime.setDate(data[1].datetime.getDate() + 1); let table = await perspective.table(data, { index: "datetime", }); let view = await table.view({ columns: ["int"], }); let json = await view.to_json({ start_col: 2, index: true, }); expect(json).toEqual([ { __INDEX__: [data[0].datetime.getTime()], }, { __INDEX__: [data[1].datetime.getTime()], }, ]); view.delete(); table.delete(); }); test("should not return pkey for date indexed table, invalid row", async function () { // default data generates the same datetime for each row, thus pkeys get collapsed const data = [ { int: 1, datetime: new Date() }, { int: 2, datetime: new Date() }, ]; data[1].datetime.setDate(data[1].datetime.getDate() + 1); let table = await perspective.table(data, { index: "datetime", }); let view = await table.view({ columns: ["int"], }); let json = await view.to_json({ start_row: 11, start_row: 12, index: true, }); expect(json).toEqual([]); view.delete(); table.delete(); }); }); test.describe("0-sided sorted", function () { test("should return correct pkey for unindexed table", async function () { let table = await perspective.table(int_float_string_data); let view = await table.view({ sort: [["float", "desc"]], }); let json = await view.to_json({ start_row: 0, end_row: 1, start_col: 1, end_col: 2, index: true, }); expect(json).toEqual([{ float: 5.25, __INDEX__: [3] }]); view.delete(); table.delete(); }); test("should return correct pkey for float indexed table", async function () { let table = await perspective.table(int_float_string_data, { index: "float", }); let view = await table.view({ sort: [["float", "desc"]], }); let json = await view.to_json({ start_row: 0, end_row: 1, start_col: 1, end_col: 2, index: true, }); expect(json).toEqual([{ float: 5.25, __INDEX__: [5.25] }]); view.delete(); table.delete(); }); test("should return correct pkey for string indexed table", async function () { let table = await perspective.table(int_float_string_data, { index: "string", }); let view = await table.view({ sort: [["float", "desc"]], }); let json = await view.to_json({ start_row: 0, end_row: 1, start_col: 1, end_col: 2, index: true, }); expect(json).toEqual([{ float: 5.25, __INDEX__: ["d"] }]); view.delete(); table.delete(); }); test("should return correct pkey for date indexed table", async function () { // default data generates the same datetime for each row, // thus pkeys get collapsed const data = [ { int: 200, datetime: new Date() }, { int: 100, datetime: new Date() }, ]; data[1].datetime.setDate(data[1].datetime.getDate() + 1); let table = await perspective.table(data, { index: "datetime", }); let view = await table.view({ sort: [["int", "desc"]], }); let json = await view.to_json({ index: true, }); expect(json).toEqual([ { int: 200, datetime: data[0].datetime.getTime(), __INDEX__: [data[0].datetime.getTime()], }, { int: 100, datetime: data[1].datetime.getTime(), __INDEX__: [data[1].datetime.getTime()], }, ]); view.delete(); table.delete(); }); test("should return correct pkey for all rows + columns on an unindexed table", async function () { let table = await perspective.table(int_float_string_data); let view = await table.view({ sort: [["float", "asc"]], }); let json = await view.to_json({ index: true, }); for (let i = 0; i < json.length; i++) { expect(json[i].__INDEX__).toEqual([i]); } view.delete(); table.delete(); }); test("should return correct pkey for all rows + columns on an indexed table", async function () { let table = await perspective.table(int_float_string_data, { index: "string", }); let view = await table.view({ sort: [["float", "desc"]], }); let json = await view.to_json({ index: true, }); let pkeys = ["d", "c", "b", "a"]; for (let i = 0; i < json.length; i++) { expect(json[i].__INDEX__).toEqual([pkeys[i]]); } view.delete(); table.delete(); }); }); test.describe("1-sided", function () { test("should generate pkeys of aggregated rows for 1-sided", async function () { let table = await perspective.table(int_float_string_data); let view = await table.view({ group_by: ["int"], }); let json = await view.to_json({ index: true, }); // total row contains all pkeys for underlying rows; each aggregated row should have pkeys for the rows that belong to it expect(json).toEqual(pivoted_output); view.delete(); table.delete(); }); }); test.describe("2-sided", function () { test.skip("should generate pkey for 2-sided", async function () { // 2-sided implicit pkeys do not work let table = await perspective.table(int_float_string_data); let view = await table.view({ group_by: ["int"], split_by: ["float"], }); let json = await view.to_json({ index: true, }); expect(json[0]["__INDEX__"]).toEqual([0, 1]); // total row should have indices for every row inside it let idx = 0; for (let item of json.slice(1)) { expect(item["__INDEX__"]).toEqual([idx]); idx++; } }); }); }); })(perspective);