2176 lines
76 KiB
JavaScript
2176 lines
76 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";
|
|
|
|
import moment from "moment";
|
|
import * as arrows from "./test_arrows.js";
|
|
|
|
const data = [
|
|
{ x: 1, y: "a", z: true },
|
|
{ x: 2, y: "b", z: false },
|
|
{ x: 3, y: "c", z: true },
|
|
{ x: 4, y: "d", z: false },
|
|
];
|
|
|
|
const col_data = {
|
|
x: [1, 2, 3, 4],
|
|
y: ["a", "b", "c", "d"],
|
|
z: [true, false, true, false],
|
|
};
|
|
|
|
const meta = {
|
|
x: "integer",
|
|
y: "string",
|
|
z: "boolean",
|
|
};
|
|
|
|
const data_3 = [
|
|
{ w: 1.5, x: 1, y: "a", z: true },
|
|
{ w: 2.5, x: 2, y: "b", z: false },
|
|
{ w: 3.5, x: 3, y: "c", z: true },
|
|
{ w: 4.5, x: 4, y: "d", z: false },
|
|
];
|
|
|
|
const data_7 = {
|
|
w: [1.5, 2.5, 3.5, 4.5],
|
|
x: [1, 2, 3, 4],
|
|
y: ["a", "b", "c", "d"],
|
|
z: [true, false, true, false],
|
|
};
|
|
|
|
const int_in_string = [{ a: "1" }, { a: "2" }, { a: "12345" }];
|
|
|
|
const float_in_string = [{ a: "1.5" }, { a: "2.5" }, { a: "12345.56789" }];
|
|
|
|
const meta_3 = {
|
|
w: "float",
|
|
x: "integer",
|
|
y: "string",
|
|
z: "boolean",
|
|
};
|
|
|
|
const arrow_result = [
|
|
{
|
|
f32: 1.5,
|
|
f64: 1.5,
|
|
i64: 1,
|
|
i32: 1,
|
|
i16: 1,
|
|
i8: 1,
|
|
bool: true,
|
|
char: "a",
|
|
dict: "a",
|
|
"datetime(ms)": +new Date("2018-01-25"),
|
|
"datetime(us)": +new Date("2018-01-25"),
|
|
"datetime(ns)": +new Date("2018-01-25"),
|
|
},
|
|
{
|
|
f32: 2.5,
|
|
f64: 2.5,
|
|
i64: 2,
|
|
i32: 2,
|
|
i16: 2,
|
|
i8: 2,
|
|
bool: false,
|
|
char: "b",
|
|
dict: "b",
|
|
"datetime(ms)": +new Date("2018-01-26"),
|
|
"datetime(us)": +new Date("2018-01-26"),
|
|
"datetime(ns)": +new Date("2018-01-26"),
|
|
},
|
|
{
|
|
f32: 3.5,
|
|
f64: 3.5,
|
|
i64: 3,
|
|
i32: 3,
|
|
i16: 3,
|
|
i8: 3,
|
|
bool: true,
|
|
char: "c",
|
|
dict: "c",
|
|
"datetime(ms)": +new Date("2018-01-27"),
|
|
"datetime(us)": +new Date("2018-01-27"),
|
|
"datetime(ns)": +new Date("2018-01-27"),
|
|
},
|
|
{
|
|
f32: 4.5,
|
|
f64: 4.5,
|
|
i64: 4,
|
|
i32: 4,
|
|
i16: 4,
|
|
i8: 4,
|
|
bool: false,
|
|
char: "",
|
|
dict: "",
|
|
"datetime(ms)": +new Date("2018-01-28"),
|
|
"datetime(us)": +new Date("2018-01-28"),
|
|
"datetime(ns)": +new Date("2018-01-28"),
|
|
},
|
|
{
|
|
f32: null,
|
|
f64: null,
|
|
i64: null,
|
|
i32: null,
|
|
i16: null,
|
|
i8: null,
|
|
bool: null,
|
|
char: null,
|
|
dict: null,
|
|
"datetime(ms)": null,
|
|
"datetime(us)": null,
|
|
"datetime(ns)": null,
|
|
},
|
|
];
|
|
|
|
let arrow_lists_data = {
|
|
uint32_arr: ["[1,2,3,4]", "[5]", "[43215]", "[]"],
|
|
string_arr: [
|
|
`["#1","second","third","fourth"]`,
|
|
`["fifth"]`,
|
|
`[]`,
|
|
`["Last!"]`,
|
|
],
|
|
bool_arr: [
|
|
"[true,false,false,true,true,false,false,true,true]",
|
|
"[]",
|
|
"[true]",
|
|
"[false]",
|
|
],
|
|
float_arr: [
|
|
"[]",
|
|
"[3.14,3.141592653589793,6.283185307179586,1.4142135623730951]",
|
|
"[12.00001]",
|
|
"[100000000.0,100000000.0,100000000.0,100000000.0]",
|
|
],
|
|
};
|
|
|
|
let arrow_date_data = {
|
|
"jan-2019": [
|
|
"2019-01-01",
|
|
"2019-01-02",
|
|
"2019-01-03",
|
|
"2019-01-04",
|
|
"2019-01-05",
|
|
"2019-01-06",
|
|
"2019-01-07",
|
|
"2019-01-08",
|
|
"2019-01-09",
|
|
"2019-01-10",
|
|
"2019-01-11",
|
|
"2019-01-12",
|
|
"2019-01-13",
|
|
"2019-01-14",
|
|
"2019-01-15",
|
|
"2019-01-16",
|
|
"2019-01-17",
|
|
"2019-01-18",
|
|
"2019-01-19",
|
|
"2019-01-20",
|
|
"2019-01-21",
|
|
"2019-01-22",
|
|
"2019-01-23",
|
|
"2019-01-24",
|
|
"2019-01-25",
|
|
"2019-01-26",
|
|
"2019-01-27",
|
|
"2019-01-28",
|
|
"2019-01-29",
|
|
"2019-01-30",
|
|
"2019-01-31",
|
|
],
|
|
"feb-2020": [
|
|
"2020-02-01",
|
|
"2020-02-02",
|
|
"2020-02-03",
|
|
"2020-02-04",
|
|
"2020-02-05",
|
|
"2020-02-06",
|
|
"2020-02-07",
|
|
"2020-02-08",
|
|
"2020-02-09",
|
|
"2020-02-10",
|
|
"2020-02-11",
|
|
"2020-02-12",
|
|
"2020-02-13",
|
|
"2020-02-14",
|
|
"2020-02-15",
|
|
"2020-02-16",
|
|
"2020-02-17",
|
|
"2020-02-18",
|
|
"2020-02-19",
|
|
"2020-02-20",
|
|
"2020-02-21",
|
|
"2020-02-22",
|
|
"2020-02-23",
|
|
"2020-02-24",
|
|
"2020-02-25",
|
|
"2020-02-26",
|
|
"2020-02-27",
|
|
"2020-02-28",
|
|
"2020-02-29",
|
|
null,
|
|
null,
|
|
],
|
|
"mar-2019": [
|
|
"2019-03-01",
|
|
"2019-03-02",
|
|
"2019-03-03",
|
|
"2019-03-04",
|
|
"2019-03-05",
|
|
"2019-03-06",
|
|
"2019-03-07",
|
|
"2019-03-08",
|
|
"2019-03-09",
|
|
"2019-03-10",
|
|
"2019-03-11",
|
|
"2019-03-12",
|
|
"2019-03-13",
|
|
"2019-03-14",
|
|
"2019-03-15",
|
|
"2019-03-16",
|
|
"2019-03-17",
|
|
"2019-03-18",
|
|
"2019-03-19",
|
|
"2019-03-20",
|
|
"2019-03-21",
|
|
"2019-03-22",
|
|
"2019-03-23",
|
|
"2019-03-24",
|
|
"2019-03-25",
|
|
"2019-03-26",
|
|
"2019-03-27",
|
|
"2019-03-28",
|
|
"2019-03-29",
|
|
"2019-03-30",
|
|
"2019-03-31",
|
|
],
|
|
"apr-2020": [
|
|
"2020-04-01",
|
|
"2020-04-02",
|
|
"2020-04-03",
|
|
"2020-04-04",
|
|
"2020-04-05",
|
|
"2020-04-06",
|
|
"2020-04-07",
|
|
"2020-04-08",
|
|
"2020-04-09",
|
|
"2020-04-10",
|
|
"2020-04-11",
|
|
"2020-04-12",
|
|
"2020-04-13",
|
|
"2020-04-14",
|
|
"2020-04-15",
|
|
"2020-04-16",
|
|
"2020-04-17",
|
|
"2020-04-18",
|
|
"2020-04-19",
|
|
"2020-04-20",
|
|
"2020-04-21",
|
|
"2020-04-22",
|
|
"2020-04-23",
|
|
"2020-04-24",
|
|
"2020-04-25",
|
|
"2020-04-26",
|
|
"2020-04-27",
|
|
"2020-04-28",
|
|
"2020-04-29",
|
|
"2020-04-30",
|
|
null,
|
|
],
|
|
};
|
|
|
|
// transform arrow strings into timestamps
|
|
for (const k in arrow_date_data) {
|
|
arrow_date_data[k] = arrow_date_data[k].map((d) =>
|
|
d ? new Date(d).getTime() : null,
|
|
);
|
|
}
|
|
|
|
const dt = () => {
|
|
let dt = new Date();
|
|
dt.setHours(4);
|
|
dt.setMinutes(12);
|
|
return dt;
|
|
};
|
|
|
|
const data_4 = [{ v: dt() }];
|
|
|
|
const data_5 = [{ v: "11-09-2017" }];
|
|
|
|
const meta_4 = { v: "datetime" };
|
|
|
|
const csv = "x,y,z\n1,a,true\n2,b,false\n3,c,true\n4,d,false";
|
|
|
|
const data_6 = [{ x: "š" }];
|
|
|
|
const int_float_data = [
|
|
{ int: 1, float: 2.25 },
|
|
{ int: 2, float: 3.5 },
|
|
{ int: 3, float: 4.75 },
|
|
{ int: 4, float: 5.25 },
|
|
];
|
|
const int_float_string_data = [
|
|
{ int: 1, float: 2.25, string: "a" },
|
|
{ int: 2, float: 3.5, string: "b" },
|
|
{ int: 3, float: 4.75, string: "c" },
|
|
{ int: 4, float: 5.25, string: "d" },
|
|
];
|
|
|
|
// out of order to make sure we can read out of perspective in insertion
|
|
// order, not pkey order.
|
|
const all_types_data = [
|
|
{
|
|
int: 4,
|
|
float: 5.25,
|
|
string: "d",
|
|
date: new Date(2020, 3, 15),
|
|
datetime: new Date(2020, 0, 15, 23, 30),
|
|
boolean: true,
|
|
},
|
|
{
|
|
int: 3,
|
|
float: 4.75,
|
|
string: "c",
|
|
date: new Date(2020, 2, 15),
|
|
datetime: new Date(2020, 0, 15, 18, 30),
|
|
boolean: false,
|
|
},
|
|
{
|
|
int: 2,
|
|
float: 3.5,
|
|
string: "b",
|
|
date: new Date(2020, 1, 15),
|
|
datetime: new Date(2020, 0, 15, 12, 30),
|
|
boolean: true,
|
|
},
|
|
{
|
|
int: 1,
|
|
float: 2.25,
|
|
string: "a",
|
|
date: new Date(2020, 0, 15),
|
|
datetime: new Date(2020, 0, 15, 6, 30),
|
|
boolean: false,
|
|
},
|
|
// values above should be replaced with these values below, due to
|
|
// indexing
|
|
{
|
|
int: 4,
|
|
float: 5.25,
|
|
string: "d",
|
|
date: new Date(2020, 3, 15),
|
|
datetime: new Date(2020, 0, 15, 23, 30),
|
|
boolean: true,
|
|
},
|
|
{
|
|
int: 3,
|
|
float: 4.75,
|
|
string: "c",
|
|
date: new Date(2020, 2, 15),
|
|
datetime: new Date(2020, 0, 15, 18, 30),
|
|
boolean: false,
|
|
},
|
|
{
|
|
int: 2,
|
|
float: 3.5,
|
|
string: "b",
|
|
date: new Date(2020, 1, 15),
|
|
datetime: new Date(2020, 0, 15, 12, 30),
|
|
boolean: true,
|
|
},
|
|
{
|
|
int: 1,
|
|
float: 2.25,
|
|
string: "a",
|
|
date: new Date(2020, 0, 15),
|
|
datetime: new Date(2020, 0, 15, 6, 30),
|
|
boolean: false,
|
|
},
|
|
];
|
|
|
|
const datetime_data = [
|
|
{ datetime: new Date(), int: 1 },
|
|
{ datetime: new Date(), int: 1 },
|
|
{ datetime: new Date(), int: 2 },
|
|
{ datetime: new Date(), int: 2 },
|
|
];
|
|
|
|
// utility for checking typed arrays
|
|
function validate_typed_array(typed_array, column_data) {
|
|
let is_valid = true;
|
|
for (let i = 0; i < typed_array.length; i++) {
|
|
if (column_data[i] !== null) {
|
|
if (typed_array[i] !== column_data[i]) {
|
|
is_valid = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return is_valid;
|
|
}
|
|
|
|
((perspective) => {
|
|
// test.describe("Execute", function () {
|
|
// test.skip("serialized functions in a worker", async function () {
|
|
// var table = await perspective.table({
|
|
// x: "integer",
|
|
// y: "string",
|
|
// z: "boolean",
|
|
// });
|
|
// table.execute((t) => {
|
|
// t.update([
|
|
// { x: 1, y: "a", z: true },
|
|
// { x: 2, y: "b", z: false },
|
|
// { x: 3, y: "c", z: true },
|
|
// { x: 4, y: "d", z: false },
|
|
// ]);
|
|
// });
|
|
// let view = await table.view({});
|
|
// let js = await view.to_json();
|
|
// expect(js).toEqual([
|
|
// { x: 1, y: "a", z: true },
|
|
// { x: 2, y: "b", z: false },
|
|
// { x: 3, y: "c", z: true },
|
|
// { x: 4, y: "d", z: false },
|
|
// ]);
|
|
// view.delete();
|
|
// table.delete();
|
|
// });
|
|
// });
|
|
|
|
test.describe("Destructors", function () {
|
|
test("calls delete() on table with no views", async function () {
|
|
let table = await perspective.table(data);
|
|
await table.delete();
|
|
expect(true).toEqual(true);
|
|
});
|
|
|
|
test("calls delete on a view, then a table", async function () {
|
|
var table = await perspective.table(data);
|
|
var view = await table.view();
|
|
await view.delete();
|
|
await table.delete();
|
|
expect(true).toEqual(true);
|
|
});
|
|
|
|
test("calls delete on multiple views, then a table", async function () {
|
|
var table = await perspective.table(data);
|
|
var view1 = await table.view();
|
|
var view2 = await table.view();
|
|
await view1.delete();
|
|
await view2.delete();
|
|
await table.delete();
|
|
expect(true).toEqual(true);
|
|
});
|
|
});
|
|
|
|
test.describe("Schema", function () {
|
|
test("0-sided view", async function () {
|
|
const table = await perspective.table(int_float_string_data);
|
|
const view = await table.view();
|
|
const schema = await view.schema();
|
|
expect(schema).toEqual({
|
|
int: "integer",
|
|
float: "float",
|
|
string: "string",
|
|
});
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("0-sided view with columns selection", async function () {
|
|
const table = await perspective.table(int_float_string_data);
|
|
const view = await table.view({ columns: ["float", "string"] });
|
|
const schema = await view.schema();
|
|
expect(schema).toEqual({ float: "float", string: "string" });
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
});
|
|
|
|
test.describe.skip("Typed Arrays", function () {
|
|
test("Respects start/end rows", async function () {
|
|
var table = await perspective.table(int_float_data);
|
|
var view = await table.view();
|
|
const result = await view.col_to_js_typed_array("int", {
|
|
start_row: 1,
|
|
end_row: 2,
|
|
});
|
|
expect(result[0].byteLength).toEqual(4);
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("Int, 0-sided view", async function () {
|
|
var table = await perspective.table(int_float_data);
|
|
var view = await table.view();
|
|
const result = await view.col_to_js_typed_array("int");
|
|
expect(result[0].byteLength).toEqual(16);
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("Float, 0-sided view", async function () {
|
|
var table = await perspective.table(int_float_data);
|
|
var view = await table.view();
|
|
const result = await view.col_to_js_typed_array("float");
|
|
expect(result[0].byteLength).toEqual(32);
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("Datetime, 0-sided view", async function () {
|
|
var table = await perspective.table(datetime_data);
|
|
var view = await table.view();
|
|
var schema = await view.schema();
|
|
expect(schema).toEqual({ datetime: "datetime", int: "integer" });
|
|
const result = await view.col_to_js_typed_array("datetime");
|
|
expect(result[0].byteLength).toEqual(32);
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("Int, 1-sided view", async function () {
|
|
var table = await perspective.table(int_float_data);
|
|
var view = await table.view({
|
|
group_by: ["int"],
|
|
columns: ["int", "float"],
|
|
});
|
|
const result = await view.col_to_js_typed_array("int");
|
|
// should include aggregate row
|
|
expect(result[0].byteLength).toEqual(20);
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("Float, 1-sided view", async function () {
|
|
var table = await perspective.table(int_float_data);
|
|
var view = await table.view({
|
|
group_by: ["int"],
|
|
columns: ["int", "float"],
|
|
});
|
|
const result = await view.col_to_js_typed_array("float");
|
|
expect(result[0].byteLength).toEqual(40);
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("Datetime, 1-sided view", async function () {
|
|
var table = await perspective.table(datetime_data);
|
|
var view = await table.view({
|
|
group_by: ["int"],
|
|
columns: ["datetime"],
|
|
aggregates: { datetime: "high" },
|
|
});
|
|
const result = await view.col_to_js_typed_array("datetime");
|
|
expect(result[0].byteLength).toEqual(24);
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("Int, 2-sided view with group by", async function () {
|
|
var table = await perspective.table(int_float_data);
|
|
var view = await table.view({
|
|
split_by: ["float"],
|
|
group_by: ["int"],
|
|
columns: ["int", "float"],
|
|
});
|
|
const result = await view.col_to_js_typed_array("3.5|int");
|
|
expect(result[0].byteLength).toEqual(20);
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("Float, 2-sided view with group by", async function () {
|
|
var table = await perspective.table(int_float_data);
|
|
var view = await table.view({
|
|
split_by: ["float"],
|
|
group_by: ["int"],
|
|
columns: ["int", "float"],
|
|
});
|
|
const result = await view.col_to_js_typed_array("3.5|float");
|
|
expect(result[0].byteLength).toEqual(40);
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("Int, 2-sided view, no group by", async function () {
|
|
var table = await perspective.table(int_float_data);
|
|
var view = await table.view({ split_by: ["float"] });
|
|
const result = await view.col_to_js_typed_array("3.5|int");
|
|
// bytelength should not include the aggregate row
|
|
expect(result[0].byteLength).toEqual(16);
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("Float, 2-sided view, no group by", async function () {
|
|
var table = await perspective.table(int_float_data);
|
|
var view = await table.view({ split_by: ["float"] });
|
|
const result = await view.col_to_js_typed_array("3.5|float");
|
|
expect(result[0].byteLength).toEqual(32);
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("Symmetric output with to_columns, 0-sided", async function () {
|
|
let table = await perspective.table(int_float_data);
|
|
let view = await table.view();
|
|
let cols = await view.to_columns();
|
|
|
|
for (let col in cols) {
|
|
let ta = await view.col_to_js_typed_array(col);
|
|
let column = cols[col];
|
|
if (ta !== undefined && column !== undefined) {
|
|
expect(ta[0].length).toEqual(cols[col].length);
|
|
expect(validate_typed_array(ta[0], cols[col])).toEqual(
|
|
true,
|
|
);
|
|
}
|
|
}
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("Symmetric output with to_columns, 1-sided", async function () {
|
|
let table = await perspective.table(int_float_string_data);
|
|
let view = await table.view({
|
|
group_by: ["int"],
|
|
columns: ["int", "float"],
|
|
});
|
|
let cols = await view.to_columns();
|
|
|
|
for (let col in cols) {
|
|
let ta = await view.col_to_js_typed_array(col);
|
|
let column = cols[col];
|
|
if (ta !== undefined && column !== undefined) {
|
|
expect(ta[0].length).toEqual(cols[col].length);
|
|
expect(validate_typed_array(ta[0], cols[col])).toEqual(
|
|
true,
|
|
);
|
|
}
|
|
}
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
});
|
|
|
|
test.describe("Other `View`s", function () {
|
|
test("Construct a table from another view", async function () {
|
|
const table = await perspective.table(int_float_string_data);
|
|
const view = await table.view();
|
|
const table2 = await perspective.table(view);
|
|
const view2 = await table2.view();
|
|
const data = await view2.to_json();
|
|
expect(data).toEqual(int_float_string_data);
|
|
view2.delete();
|
|
table2.delete();
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
});
|
|
|
|
test.describe("Errors", function () {
|
|
test("Table constructor should throw an exception and reject promise", async function () {
|
|
expect.assertions(1);
|
|
perspective.table([1, 2, 3]).catch((error) => {
|
|
expect(error.message).toContain(
|
|
"Abort(): Cannot determine data types without column names!\n",
|
|
);
|
|
});
|
|
});
|
|
|
|
test("View constructor should throw an exception and reject promise", async function () {
|
|
expect.assertions(1);
|
|
const table = await perspective.table(int_float_string_data);
|
|
table
|
|
.view({
|
|
group_by: ["abcd"],
|
|
})
|
|
.catch((error) => {
|
|
expect(error.message).toContain(
|
|
"Abort(): Invalid column 'abcd' found in View group_by.\n",
|
|
);
|
|
table.delete();
|
|
});
|
|
});
|
|
|
|
test("Table constructor should throw an exception on await", async function () {
|
|
expect.assertions(1);
|
|
|
|
try {
|
|
await perspective.table([1, 2, 3]);
|
|
} catch (error) {
|
|
expect(error.message).toContain(
|
|
"Abort(): Cannot determine data types without column names!\n",
|
|
);
|
|
}
|
|
});
|
|
|
|
test("View constructor should throw an exception on await", async function () {
|
|
expect.assertions(1);
|
|
const table = await perspective.table(int_float_string_data);
|
|
|
|
try {
|
|
await table.view({
|
|
group_by: ["abcd"],
|
|
});
|
|
} catch (error) {
|
|
expect(error.message).toContain(
|
|
"Abort(): Invalid column 'abcd' found in View group_by.\n",
|
|
);
|
|
table.delete();
|
|
}
|
|
});
|
|
|
|
test("Table constructor pads short trailing columns with null", async function () {
|
|
const table = await perspective.table({
|
|
overflow: [1, 2, 3, 4, 5, 6, 7, 8, 9],
|
|
short: [1],
|
|
});
|
|
const view = await table.view();
|
|
const result = await view.to_columns();
|
|
expect(result).toEqual({
|
|
overflow: [1, 2, 3, 4, 5, 6, 7, 8, 9],
|
|
short: [1, null, null, null, null, null, null, null, null],
|
|
});
|
|
await view.delete();
|
|
await table.delete();
|
|
});
|
|
|
|
test("Table constructor pads short leading columns with null", async function () {
|
|
const table = await perspective.table({
|
|
short: [1],
|
|
overflow: [1, 2, 3, 4, 5, 6, 7, 8, 9],
|
|
});
|
|
const view = await table.view();
|
|
const result = await view.to_columns();
|
|
expect(result).toEqual({
|
|
short: [1, null, null, null, null, null, null, null, null],
|
|
overflow: [1, 2, 3, 4, 5, 6, 7, 8, 9],
|
|
});
|
|
await view.delete();
|
|
await table.delete();
|
|
});
|
|
|
|
test("Table constructor handles columns of equal length", async function () {
|
|
const table = await perspective.table({
|
|
a: [1, 2, 3],
|
|
b: ["x", "y", "z"],
|
|
});
|
|
const view = await table.view();
|
|
const result = await view.to_columns();
|
|
expect(result).toEqual({
|
|
a: [1, 2, 3],
|
|
b: ["x", "y", "z"],
|
|
});
|
|
await view.delete();
|
|
await table.delete();
|
|
});
|
|
|
|
test("Table update pads short columns with null", async function () {
|
|
const table = await perspective.table({
|
|
a: "integer",
|
|
b: "integer",
|
|
});
|
|
await table.update({
|
|
a: [1, 2, 3, 4, 5],
|
|
b: [1],
|
|
});
|
|
const view = await table.view();
|
|
const result = await view.to_columns();
|
|
expect(result).toEqual({
|
|
a: [1, 2, 3, 4, 5],
|
|
b: [1, null, null, null, null],
|
|
});
|
|
|
|
// The table must remain usable for subsequent updates.
|
|
await table.update({ a: [10], b: [20] });
|
|
const result2 = await view.to_columns();
|
|
expect(result2).toEqual({
|
|
a: [1, 2, 3, 4, 5, 10],
|
|
b: [1, null, null, null, null, 20],
|
|
});
|
|
await view.delete();
|
|
await table.delete();
|
|
});
|
|
});
|
|
|
|
test.describe("Formatters", function () {
|
|
test("Serializes a simple view to CSV", async function () {
|
|
var table = await perspective.table(data);
|
|
var view = await table.view({});
|
|
var answer = `"x","y","z"\n1,"a",true\n2,"b",false\n3,"c",true\n4,"d",false\n`;
|
|
let result = await view.to_csv();
|
|
expect(result).toEqual(answer);
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("Serializes 1 sided view to CSV", async function () {
|
|
var table = await perspective.table(data);
|
|
var view = await table.view({
|
|
group_by: ["z"],
|
|
columns: ["x"],
|
|
});
|
|
var answer = `"z (Group by 1)","x"\n,10\nfalse,6\ntrue,4\n`;
|
|
let result = await view.to_csv();
|
|
expect(result).toEqual(answer);
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("Serializes a 2 sided view to CSV", async function () {
|
|
var table = await perspective.table(data);
|
|
var view = await table.view({
|
|
group_by: ["z"],
|
|
split_by: ["y"],
|
|
columns: ["x"],
|
|
});
|
|
var answer = `"z (Group by 1)","a|x","b|x","c|x","d|x"\n,1,2,3,4\nfalse,,2,,4\ntrue,1,,3,\n`;
|
|
let result = await view.to_csv();
|
|
expect(result).toEqual(answer);
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("Serializes a simple view to column-oriented JSON", async function () {
|
|
var table = await perspective.table(data_3);
|
|
var view = await table.view({});
|
|
let result = await view.to_columns();
|
|
expect(result).toEqual(data_7);
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
});
|
|
|
|
test.describe("CSV parsing", function () {
|
|
test("Does not lose leading 0's when a CSV column is declared as a string", async function () {
|
|
let table = await perspective.table({ x: "string", y: "integer" });
|
|
await table.update("x,y\n000123,000123");
|
|
let view = await table.view();
|
|
let result = await view.to_json();
|
|
expect(result).toEqual([{ x: "000123", y: 123 }]);
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
// Added
|
|
test("Does not lose leading 0's when a CSV column is declared as a string (async)", async function () {
|
|
let table = await perspective.table({ x: "string", y: "integer" });
|
|
await table.update("x,y\n000123,000123");
|
|
let view = await table.view();
|
|
let result = await view.to_json();
|
|
expect(result).toEqual([{ x: "000123", y: 123 }]);
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("Handles duplicate column names with different types", async function () {
|
|
const csv = "A,A\ntest,1";
|
|
let table = await perspective.table(csv);
|
|
let view = await table.view();
|
|
let csv2 = await view.to_json();
|
|
expect(csv2).toEqual([{ A: "test", "A*": 1 }]);
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("Handles duplicate column names with rename collisions", async function () {
|
|
const csv = "A,A,A*\ntest,1,2";
|
|
let table = await perspective.table(csv);
|
|
let view = await table.view();
|
|
let csv2 = await view.to_json();
|
|
expect(csv2).toEqual([{ A: "test", "A*": 1, "A**": 2 }]);
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("Handles strings with quotation characters and commas", async function () {
|
|
let table = await perspective.table({ x: "string", y: "integer" });
|
|
await table.update([
|
|
{ x: "Test, hello!", y: 1 },
|
|
{ x: 'Test2"', y: 2 },
|
|
{ x: 'Test3, Hello!"', y: 3 },
|
|
]);
|
|
let view = await table.view();
|
|
let result = await view.to_csv();
|
|
expect(result).toEqual(
|
|
`"x","y"\n"Test, hello!",1\n"Test2""",2\n"Test3, Hello!""",3\n`,
|
|
);
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
// Added
|
|
test("Handles strings with quotation characters and commas (async)", async function () {
|
|
let table = await perspective.table({ x: "string", y: "integer" });
|
|
await table.update([
|
|
{ x: "Test, hello!", y: 1 },
|
|
{ x: 'Test2"', y: 2 },
|
|
{ x: 'Test3, Hello!"', y: 3 },
|
|
]);
|
|
let view = await table.view();
|
|
let result = await view.to_csv();
|
|
expect(result).toEqual(
|
|
`"x","y"\n"Test, hello!",1\n"Test2""",2\n"Test3, Hello!""",3\n`,
|
|
);
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("Transitively loads a CSV created from `to_csv()` on a table with a datetime column", async function () {
|
|
// Assert that the CSV parser can handle POSIX timestamps.
|
|
let table = await perspective.table(arrow_date_data);
|
|
let view = await table.view();
|
|
let schema = await table.schema();
|
|
let csv = await view.to_csv();
|
|
let table2 = await perspective.table(csv);
|
|
let schema2 = await table2.schema();
|
|
let view2 = await table2.view();
|
|
let csv2 = await view2.to_csv();
|
|
expect(schema2).toEqual(schema);
|
|
expect(csv2).toEqual(csv);
|
|
view2.delete();
|
|
table2.delete();
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
});
|
|
|
|
test.describe("ndjson", function () {
|
|
test("basic constructor", async function () {
|
|
var table = await perspective.table(`{"x":1}\n{"x":2}`, {
|
|
format: "ndjson",
|
|
});
|
|
var view = await table.view();
|
|
let result = await view.to_json();
|
|
expect(result).toEqual([{ x: 1 }, { x: 2 }]);
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("date types", async function () {
|
|
const ndjson = [];
|
|
for (const row of data_4) {
|
|
ndjson.push(row);
|
|
}
|
|
var table = await perspective.table(
|
|
ndjson.map(JSON.stringify).join("\n"),
|
|
{
|
|
format: "ndjson",
|
|
},
|
|
);
|
|
var view = await table.view();
|
|
let result = await view.to_json();
|
|
expect(result).toEqual([{ v: +data_4[0]["v"] }]);
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("Handles dates when provided a schema", async function () {
|
|
var table = await perspective.table(meta_4);
|
|
await table.update(data_4.map(JSON.stringify).join("\n"), {
|
|
format: "ndjson",
|
|
});
|
|
|
|
let view = await table.view();
|
|
let result = await view.to_json();
|
|
expect(result).toEqual([{ v: +data_4[0]["v"] }]);
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("Handles many objects without newline separators", async function () {
|
|
const expected = [];
|
|
for (let i = 0; i < 64; i++) {
|
|
expected.push({ a: `row-${i}` });
|
|
}
|
|
const data = expected.map(JSON.stringify).join("");
|
|
const table = await perspective.table(data, { format: "ndjson" });
|
|
const view = await table.view();
|
|
expect(await table.size()).toEqual(64);
|
|
expect(await view.to_json()).toEqual(expected);
|
|
await view.delete();
|
|
await table.delete();
|
|
});
|
|
});
|
|
|
|
test.describe("Constructors", function () {
|
|
test("JSON constructor", async function () {
|
|
var table = await perspective.table(data);
|
|
var view = await table.view();
|
|
let result = await view.to_json();
|
|
expect(result).toEqual(data);
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("JSON column oriented constructor", async function () {
|
|
var table = await perspective.table(col_data);
|
|
var view = await table.view();
|
|
let result = await view.to_json();
|
|
expect(result).toEqual(data);
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("Arrow constructor", async function () {
|
|
var table = await perspective.table(arrows.test_null_arrow.slice());
|
|
var view = await table.view();
|
|
let result = await view.to_json();
|
|
expect(result).toEqual(arrow_result);
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test.skip("Arrow (chunked format) constructor", async function () {
|
|
var table = await perspective.table(arrows.chunked_arrow.slice());
|
|
var view = await table.view();
|
|
let result = await view.to_json();
|
|
expect(result.length).toEqual(10);
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("Arrow date32 constructor", async function () {
|
|
const table = await perspective.table(arrows.date32_arrow.slice());
|
|
const view = await table.view();
|
|
const result = await view.to_columns();
|
|
expect(result).toEqual(arrow_date_data);
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("Arrow float32 constructor", async function () {
|
|
const table = await perspective.table(arrows.float32_arrow.slice());
|
|
const view = await table.view();
|
|
const result = await view.to_columns();
|
|
expect(result).toEqual({
|
|
id: [1, 2, 3],
|
|
name: ["Alice", "Bob", "Charlie"],
|
|
score: [92.5, 87.30000305175781, 95.80000305175781],
|
|
});
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("Arrow date64 constructor", async function () {
|
|
const table = await perspective.table(arrows.date64_arrow.slice());
|
|
const view = await table.view();
|
|
const result = await view.to_columns();
|
|
expect(result).toEqual(arrow_date_data);
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("Arrow Lists constructor", async function () {
|
|
const table = await perspective.table(arrows.lists_arrow.slice());
|
|
const view = await table.view();
|
|
const result = await view.to_columns();
|
|
expect(result).toEqual(arrow_lists_data);
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("Arrow dictionary constructor", async function () {
|
|
const table = await perspective.table(arrows.dict_arrow.slice());
|
|
const view = await table.view();
|
|
const result = await view.to_columns();
|
|
expect(result).toEqual({
|
|
a: ["abc", "def", "def", null, "abc"],
|
|
b: ["klm", "hij", null, "hij", "klm"],
|
|
});
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("CSV constructor with null columns", async function () {
|
|
const table = await perspective.table("x,y\n1,");
|
|
const view = await table.view();
|
|
expect(await table.schema()).toEqual({
|
|
x: "integer",
|
|
y: "string",
|
|
});
|
|
const result = await view.to_columns();
|
|
expect(result).toEqual({
|
|
x: [1],
|
|
y: [null],
|
|
});
|
|
await view.delete();
|
|
await table.delete();
|
|
});
|
|
|
|
test("CSV constructor indexed, with null columns, and update", async function () {
|
|
const table = await perspective.table("x,y\n1,", { index: "x" });
|
|
const view = await table.view();
|
|
expect(await table.schema()).toEqual({
|
|
x: "integer",
|
|
y: "string",
|
|
});
|
|
const result = await view.to_columns();
|
|
expect(result).toEqual({
|
|
x: [1],
|
|
y: [null],
|
|
});
|
|
await table.update("x,y\n1,abc\n2,123");
|
|
const result2 = await view.to_columns();
|
|
expect(result2).toEqual({
|
|
x: [1, 2],
|
|
y: ["abc", "123"],
|
|
});
|
|
await view.delete();
|
|
await table.delete();
|
|
});
|
|
|
|
test("Meta constructor", async function () {
|
|
var table = await perspective.table(meta);
|
|
var view = await table.view();
|
|
let result = await view.to_json();
|
|
expect(result).toEqual([]);
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("Handles floats", async function () {
|
|
var table = await perspective.table(data_3);
|
|
var view = await table.view();
|
|
let result = await view.to_json();
|
|
expect(result).toEqual(data_3);
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("Infers ints wrapped in strings", async function () {
|
|
var table = await perspective.table(int_in_string);
|
|
var view = await table.view();
|
|
let result = await view.schema();
|
|
expect(result).toEqual({ a: "integer" });
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("Infers floats wrapped in strings", async function () {
|
|
var table = await perspective.table(float_in_string);
|
|
var view = await table.view();
|
|
let result = await view.schema();
|
|
expect(result).toEqual({ a: "float" });
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("Infers correct type for empty string columns", async function () {
|
|
var table = await perspective.table([
|
|
{ x: "", y: 1 },
|
|
{ x: "", y: 2 },
|
|
{ x: "", y: 3 },
|
|
{ x: "", y: 4 },
|
|
]);
|
|
var view = await table.view();
|
|
let result = await view.schema();
|
|
expect(result).toEqual({ x: "string", y: "integer" });
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("Returns the correct number of rows for column-only views", async function () {
|
|
var table = await perspective.table(data);
|
|
var view = await table.view();
|
|
var num_rows = await view.num_rows();
|
|
var view2 = await table.view({
|
|
split_by: ["x"],
|
|
});
|
|
var num_rows_col_only = await view2.num_rows();
|
|
expect(num_rows_col_only).toEqual(num_rows);
|
|
view.delete();
|
|
view2.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test.skip("Handles inconsistent rows with same width", async function () {
|
|
const int_to_float = [
|
|
{ x: 1, y: 2 },
|
|
{ y: 2, z: 3 },
|
|
];
|
|
var table = await perspective.table(int_to_float);
|
|
var view = await table.view();
|
|
var json = await view.to_json();
|
|
expect(json).toEqual([
|
|
{ x: 1, y: 2, z: null },
|
|
{ x: null, y: 2, z: 3 },
|
|
]);
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test.skip("Handles inconsistent rows", async function () {
|
|
const int_to_float = [{ x: 1 }, { y: 2, z: 3 }];
|
|
var table = await perspective.table(int_to_float);
|
|
var schema = await table.schema();
|
|
expect(schema).toEqual({
|
|
x: "integer",
|
|
y: "integer",
|
|
z: "integer",
|
|
});
|
|
var view = await table.view();
|
|
var json = await view.to_json();
|
|
expect(json).toEqual([
|
|
{ x: 1, y: null, z: null },
|
|
{ x: null, y: 2, z: 3 },
|
|
]);
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("Upgrades integer columns to strings", async function () {
|
|
const int_to_float = {
|
|
a: [1, 2, 3, "x", "y"],
|
|
};
|
|
|
|
var table = await perspective.table(int_to_float);
|
|
var schema_1 = await table.schema();
|
|
expect(schema_1["a"]).toEqual("string");
|
|
var view = await table.view();
|
|
var json = await view.to_json();
|
|
expect(json).toEqual([
|
|
{ a: "1" },
|
|
{ a: "2" },
|
|
{ a: "3" },
|
|
{ a: "x" },
|
|
{ a: "y" },
|
|
]);
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("Upgrades integer columns with values beyond max/min_int to float", async function () {
|
|
const int_to_float = {
|
|
a: [1, 2, 3, 2147483667, 5],
|
|
};
|
|
|
|
var table = await perspective.table(int_to_float);
|
|
var view = await table.view();
|
|
var json = await view.to_columns();
|
|
expect(json).toEqual(int_to_float);
|
|
var schema_2 = await table.schema();
|
|
expect(schema_2["a"]).toEqual("float");
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
// This currently won't work, and I'm unclear we want it to - upgrading
|
|
// ths column in place is easy, but once the gnode and potentially
|
|
// contexts have been created, this becomes much more difficult.
|
|
test.skip("Upgrades integer columns with values beyond max/min_int to float old", async function () {
|
|
const schema = {
|
|
a: "integer",
|
|
};
|
|
|
|
const int_to_float = {
|
|
a: [1, 2, 3, 2147483667, 5],
|
|
};
|
|
|
|
var table = await perspective.table(schema);
|
|
var schema_1 = await table.schema();
|
|
expect(schema_1["a"]).toEqual("integer");
|
|
|
|
await table.update(int_to_float);
|
|
|
|
var schema_2 = await table.schema();
|
|
expect(schema_2["a"]).toEqual("float");
|
|
table.delete();
|
|
});
|
|
|
|
test("Does not infer float column as integers", async function () {
|
|
const int_to_float = [];
|
|
for (let x = 0; x < 200; x++) {
|
|
int_to_float.push({ a: 1 });
|
|
}
|
|
int_to_float.push({ a: 2147483667 });
|
|
|
|
var table = await perspective.table(int_to_float);
|
|
var schema_1 = await table.schema();
|
|
expect(schema_1["a"]).toEqual("float");
|
|
let view = await table.view();
|
|
var data = await view.to_json();
|
|
expect(data).toEqual(int_to_float);
|
|
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("has correct size", async function () {
|
|
var table = await perspective.table(data);
|
|
let result = await table.size();
|
|
expect(result).toEqual(4);
|
|
table.delete();
|
|
});
|
|
|
|
test("has a schema", async function () {
|
|
var table = await perspective.table(data);
|
|
let result = await table.schema();
|
|
expect(result).toEqual(meta);
|
|
table.delete();
|
|
});
|
|
|
|
test("has columns", async function () {
|
|
var table = await perspective.table(data);
|
|
let result = await table.columns();
|
|
expect(result).toEqual(["x", "y", "z"]);
|
|
table.delete();
|
|
});
|
|
|
|
test("Handles floats schemas", async function () {
|
|
var table = await perspective.table(data_3);
|
|
let result = await table.schema();
|
|
expect(result).toEqual(meta_3);
|
|
table.delete();
|
|
});
|
|
|
|
test("Generates correct date schemas", async function () {
|
|
var table = await perspective.table(data_4);
|
|
let result = await table.schema();
|
|
expect(result).toEqual(meta_4);
|
|
table.delete();
|
|
});
|
|
|
|
test("Handles date updates when constructed from a schema", async function () {
|
|
var table = await perspective.table(meta_4);
|
|
await table.update(data_4);
|
|
let view = await table.view();
|
|
let result = await view.to_json();
|
|
expect(result).toEqual([{ v: +data_4[0]["v"] }]);
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("Handles datetime values", async function () {
|
|
var table = await perspective.table(data_4);
|
|
let view = await table.view();
|
|
let result = await view.to_json();
|
|
expect(result).toEqual([{ v: +data_4[0]["v"] }]);
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("Handles datetime strings", async function () {
|
|
var table = await perspective.table(data_5);
|
|
let view = await table.view();
|
|
let result = await view.to_json();
|
|
expect(result).toEqual([
|
|
{ v: +moment(data_5[0]["v"], "MM-DD-YYYY") },
|
|
]);
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("Handles datetime strings in US locale string old", async function () {
|
|
// FIXME: 1/1/2020, 12:30:45 PM = 1/1/2020, 7:30:45 AM UTC, but
|
|
// because C++ strptime in Emscripten parses the time as 12:30:45AM,
|
|
// the output is 12/31/2019 19:30:45 PM UTC. This is clearly wrong.
|
|
const data = {
|
|
x: [
|
|
"1/1/2020, 12:30:45 PM",
|
|
"1/1/2020, 12:30:45 AM",
|
|
"03/15/2020, 11:30:45 AM",
|
|
"06/30/2020, 01:30:45 AM",
|
|
"06/30/2020, 01:30:45 PM",
|
|
"12/31/2020, 11:59:59 PM",
|
|
],
|
|
};
|
|
const table = await perspective.table(data);
|
|
const schema = await table.schema();
|
|
|
|
expect(schema).toEqual({
|
|
x: "datetime",
|
|
});
|
|
|
|
const view = await table.view();
|
|
const result = await view.to_columns();
|
|
|
|
const expected = {
|
|
x: [
|
|
"1/1/2020, 12:30:45 PM",
|
|
"1/1/2020, 12:30:45 AM",
|
|
"03/15/2020, 11:30:45 AM",
|
|
"06/30/2020, 01:30:45 AM",
|
|
"06/30/2020, 01:30:45 PM",
|
|
"12/31/2020, 11:59:59 PM",
|
|
].map((v) => new Date(v).getTime()),
|
|
};
|
|
|
|
expect(result).toEqual(expected);
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("Handles datetime strings in US locale string", async function () {
|
|
const data = {
|
|
x: [
|
|
"1/1/2020, 05:30:45 AM",
|
|
"03/15/2020, 11:30:45 AM",
|
|
"06/30/2020, 01:30:45 AM",
|
|
"12/31/2020, 11:59:59 PM",
|
|
],
|
|
};
|
|
const table = await perspective.table(data);
|
|
const schema = await table.schema();
|
|
|
|
expect(schema).toEqual({
|
|
x: "datetime",
|
|
});
|
|
|
|
const view = await table.view();
|
|
const result = await view.to_columns();
|
|
|
|
const expected = {
|
|
x: [
|
|
"1/1/2020, 05:30:45 AM",
|
|
"03/15/2020, 11:30:45 AM",
|
|
"06/30/2020, 01:30:45 AM",
|
|
"12/31/2020, 11:59:59 PM",
|
|
].map((v) => new Date(v).getTime()),
|
|
};
|
|
|
|
expect(result).toEqual(expected);
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("Handles datetime values with mixed formats", async function () {
|
|
var table = await perspective.table({ datetime: "datetime" });
|
|
await table.update([
|
|
{ datetime: new Date(1549257586108) },
|
|
{ datetime: "2019-01-30" },
|
|
{ datetime: 11 },
|
|
]);
|
|
let view = await table.view();
|
|
let result = await view.to_json();
|
|
expect(result).toEqual([
|
|
{ datetime: 1549257586108 },
|
|
{ datetime: 1548806400000 },
|
|
{ datetime: 11 },
|
|
]);
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("Handles date values", async function () {
|
|
var table = await perspective.table({ v: "date" });
|
|
await table.update(data_4);
|
|
let view = await table.view();
|
|
let result = await view.to_json();
|
|
let d = new Date(data_4[0]["v"]);
|
|
d.setHours(0);
|
|
d.setMinutes(0);
|
|
d.setSeconds(0);
|
|
d.setMilliseconds(0);
|
|
expect(result).toEqual([{ v: +d }]);
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("CSV Parses an ISO-8601 formatted string with milliseconds and timezone", async function () {
|
|
let table = await perspective.table(
|
|
"d\n2008-09-15T10:00:00.123+05:45",
|
|
);
|
|
let view = await table.view();
|
|
let result = await view.to_csv();
|
|
expect(result).toEqual('"d"\n2008-09-15 04:15:00.123\n');
|
|
await view.delete();
|
|
await table.delete();
|
|
});
|
|
|
|
test("JSON Parses an ISO-8601 formatted string with milliseconds and timezone", async function () {
|
|
let table = await perspective.table({
|
|
d: ["2008-09-15T10:00:00.123+05:45"],
|
|
});
|
|
let view = await table.view();
|
|
let result = await view.to_csv();
|
|
expect(result).toEqual('"d"\n2008-09-15 04:15:00.123\n');
|
|
await view.delete();
|
|
await table.delete();
|
|
});
|
|
|
|
test("CSV Updates an ISO-8601 formatted string with milliseconds and timezone", async function () {
|
|
let table = await perspective.table({ d: "datetime" });
|
|
await table.update("d\n2008-09-15T10:00:00.123+05:45");
|
|
let view = await table.view();
|
|
let result = await view.to_csv();
|
|
expect(result).toEqual('"d"\n2008-09-15 04:15:00.123\n');
|
|
await view.delete();
|
|
await table.delete();
|
|
});
|
|
|
|
test("JSON Updates an ISO-8601 formatted string with milliseconds and timezone", async function () {
|
|
let table = await perspective.table({ d: "datetime" });
|
|
await table.update({
|
|
d: ["2008-09-15T10:00:00.123+05:45"],
|
|
});
|
|
let view = await table.view();
|
|
let result = await view.to_csv();
|
|
expect(result).toEqual('"d"\n2008-09-15 04:15:00.123\n');
|
|
await view.delete();
|
|
await table.delete();
|
|
});
|
|
|
|
test("CSV Parses an ISO-8601 formatted string with microseconds and timezone", async function () {
|
|
let table = await perspective.table(
|
|
"d\n2008-09-15T15:30:00.123456+05:30",
|
|
);
|
|
let view = await table.view();
|
|
let result = await view.to_csv();
|
|
expect(result).toEqual('"d"\n2008-09-15 10:00:00.123\n');
|
|
await view.delete();
|
|
await table.delete();
|
|
});
|
|
|
|
test("JSON Parses an ISO-8601 formatted string with microseconds and timezone", async function () {
|
|
let table = await perspective.table({
|
|
d: ["2008-09-15T15:30:00.123456+05:30"],
|
|
});
|
|
let view = await table.view();
|
|
let result = await view.to_csv();
|
|
expect(result).toEqual('"d"\n2008-09-15 10:00:00.123\n');
|
|
await view.delete();
|
|
await table.delete();
|
|
});
|
|
|
|
test("CSV Updates an ISO-8601 formatted string with microseconds and timezone", async function () {
|
|
let table = await perspective.table({ d: "datetime" });
|
|
await table.update("d\n2008-09-15T15:30:00.123456+05:30");
|
|
let view = await table.view();
|
|
let result = await view.to_csv();
|
|
expect(result).toEqual('"d"\n2008-09-15 10:00:00.123\n');
|
|
await view.delete();
|
|
await table.delete();
|
|
});
|
|
|
|
test("JSON Updates an ISO-8601 formatted string with microseconds and timezone", async function () {
|
|
let table = await perspective.table({ d: "datetime" });
|
|
await table.update({
|
|
d: ["2008-09-15T15:30:00.123456+05:30"],
|
|
});
|
|
let view = await table.view();
|
|
let result = await view.to_csv();
|
|
expect(result).toEqual('"d"\n2008-09-15 10:00:00.123\n');
|
|
await view.delete();
|
|
await table.delete();
|
|
});
|
|
|
|
test("CSV Parses an ISO-8601 formatted string with nanoseconds and timezone", async function () {
|
|
let table = await perspective.table(
|
|
"d\n2008-09-15T15:15:00.123456789-05:15",
|
|
);
|
|
let view = await table.view();
|
|
let result = await view.to_csv();
|
|
expect(result).toEqual('"d"\n2008-09-15 20:30:00.123\n');
|
|
await view.delete();
|
|
await table.delete();
|
|
});
|
|
|
|
test("JSON Parses an ISO-8601 formatted string with nanoseconds and timezone", async function () {
|
|
let table = await perspective.table({
|
|
d: ["2008-09-15T15:15:00.123456789-05:15"],
|
|
});
|
|
let view = await table.view();
|
|
let result = await view.to_csv();
|
|
expect(result).toEqual('"d"\n2008-09-15 20:30:00.123\n');
|
|
await view.delete();
|
|
await table.delete();
|
|
});
|
|
|
|
test("CSV Updates an ISO-8601 formatted string with nanoseconds and timezone", async function () {
|
|
let table = await perspective.table({ d: "datetime" });
|
|
await table.update("d\n2008-09-15T15:15:00.123456789-05:15");
|
|
let view = await table.view();
|
|
let result = await view.to_csv();
|
|
expect(result).toEqual('"d"\n2008-09-15 20:30:00.123\n');
|
|
await view.delete();
|
|
await table.delete();
|
|
});
|
|
|
|
test("JSON Updates an ISO-8601 formatted string with nanoseconds and timezone", async function () {
|
|
let table = await perspective.table({ d: "datetime" });
|
|
await table.update({
|
|
d: ["2008-09-15T15:15:00.123456789-05:15"],
|
|
});
|
|
let view = await table.view();
|
|
let result = await view.to_csv();
|
|
expect(result).toEqual('"d"\n2008-09-15 20:30:00.123\n');
|
|
await view.delete();
|
|
await table.delete();
|
|
});
|
|
|
|
test("CSV Reader parses milliseconds", async function () {
|
|
const a = '"start"\n2024-08-14T14:06:07.826Z';
|
|
const table = await perspective.table(a);
|
|
const view = await table.view();
|
|
const csv1 = await view.to_csv();
|
|
expect(csv1).toEqual('"start"\n2024-08-14 14:06:07.826\n');
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("CSV Reader update parses milliseconds", async function () {
|
|
const a = '"d"\n2024-08-14T14:06:07.826Z';
|
|
const table = await perspective.table({
|
|
d: "datetime",
|
|
});
|
|
await table.update(a);
|
|
const view = await table.view();
|
|
const csv1 = await view.to_csv();
|
|
expect(csv1).toEqual('"d"\n2024-08-14 14:06:07.826\n');
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("CSV Reader update updates microseconds", async function () {
|
|
const a = '"d"\n2024-08-14T14:06:07.826789Z';
|
|
const table = await perspective.table({
|
|
d: "datetime",
|
|
});
|
|
await table.update(a);
|
|
const view = await table.view();
|
|
const csv1 = await view.to_csv();
|
|
expect(csv1).toEqual('"d"\n2024-08-14 14:06:07.826\n');
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("CSV Reader update updates nanoseconds", async function () {
|
|
const a = '"d"\n2024-08-14T14:06:07.826789789Z';
|
|
const table = await perspective.table({
|
|
d: "datetime",
|
|
});
|
|
await table.update(a);
|
|
const view = await table.view();
|
|
const csv1 = await view.to_csv();
|
|
expect(csv1).toEqual('"d"\n2024-08-14 14:06:07.826\n');
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("CSV Reader update parses microseconds", async function () {
|
|
const a = '"d"\n2024-08-14T14:06:07.826789Z';
|
|
const table = await perspective.table(a);
|
|
const view = await table.view();
|
|
const csv1 = await view.to_csv();
|
|
expect(csv1).toEqual('"d"\n2024-08-14 14:06:07.826\n');
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("CSV Reader update parses nanoseconds", async function () {
|
|
const a = '"d"\n2024-08-14T14:06:07.826789789Z';
|
|
const table = await perspective.table(a);
|
|
const view = await table.view();
|
|
const csv1 = await view.to_csv();
|
|
expect(csv1).toEqual('"d"\n2024-08-14 14:06:07.826\n');
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("JSON Reader parses milliseconds", async function () {
|
|
const a = "2024-08-14T14:06:07.826Z";
|
|
const table = await perspective.table({
|
|
d: "datetime",
|
|
});
|
|
await table.update({ d: [a] });
|
|
const view = await table.view();
|
|
const csv1 = await view.to_csv();
|
|
expect(csv1).toEqual('"d"\n2024-08-14 14:06:07.826\n');
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("Handles utf16 column names", async function () {
|
|
var table = await perspective.table({ š: [1, 2, 3] });
|
|
let view = await table.view({});
|
|
let result = await view.schema();
|
|
expect(result).toEqual({ š: "integer" });
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test("Handles utf16", async function () {
|
|
var table = await perspective.table(data_6);
|
|
let view = await table.view({});
|
|
let result = await view.to_json();
|
|
expect(result).toEqual(data_6);
|
|
view.delete();
|
|
table.delete();
|
|
});
|
|
|
|
test.describe("Datetime constructors", function () {
|
|
test("Correctly parses an ISO-8601 formatted string", async function () {
|
|
let table = await perspective.table({
|
|
d: ["2011-10-05T14:48:00"],
|
|
});
|
|
let view = await table.view({});
|
|
let result = await view.schema();
|
|
expect(result["d"]).toEqual("datetime");
|
|
await view.delete();
|
|
await table.delete();
|
|
});
|
|
|
|
test("Correctly parses an ISO-8601 formatted string 2", async function () {
|
|
let table = await perspective.table({
|
|
d: ["2011-10-05T14:48:00.000"],
|
|
});
|
|
let view = await table.view({});
|
|
let result = await view.schema();
|
|
expect(result["d"]).toEqual("datetime");
|
|
await view.delete();
|
|
await table.delete();
|
|
});
|
|
|
|
test("Correctly parses an ISO-8601 formatted string 3", async function () {
|
|
let table = await perspective.table({
|
|
d: ["2011-10-05T14:48:00Z"],
|
|
});
|
|
let view = await table.view({});
|
|
let result = await view.schema();
|
|
expect(result["d"]).toEqual("datetime");
|
|
await view.delete();
|
|
await table.delete();
|
|
});
|
|
|
|
test("Correctly parses an ISO-8601 formatted string 4", async function () {
|
|
let table = await perspective.table({
|
|
d: ["2011-10-05T14:48:00.000Z"],
|
|
});
|
|
let view = await table.view({});
|
|
let result = await view.schema();
|
|
expect(result["d"]).toEqual("datetime");
|
|
await view.delete();
|
|
await table.delete();
|
|
});
|
|
|
|
test("Correctly parses an ISO-8601 formatted string with timezone", async function () {
|
|
let table = await perspective.table({
|
|
d: ["2008-09-15T15:53:00+05:00"],
|
|
});
|
|
let view = await table.view({});
|
|
let result = await view.schema();
|
|
expect(result["d"]).toEqual("datetime");
|
|
await view.delete();
|
|
await table.delete();
|
|
});
|
|
|
|
test.skip("Correctly parses an RFC 2822 formatted string", async function () {
|
|
let table = await perspective.table({
|
|
d: ["Wed, 05 Oct 2011 22:26:12 -0400"],
|
|
});
|
|
let view = await table.view({});
|
|
let result = await view.schema();
|
|
expect(result["d"]).toEqual("datetime");
|
|
await view.delete();
|
|
await table.delete();
|
|
});
|
|
|
|
// Not all formats covered by JS parser, test intended for C++ parser
|
|
test.skip("Correctly parses all m-d-y formatted strings", async function () {
|
|
let datestrings = [
|
|
"08-15-2009",
|
|
"08/15/2009",
|
|
"08-15-2009",
|
|
"02 28 2009",
|
|
"08/15/10",
|
|
"31 08 2009",
|
|
];
|
|
for (let str of datestrings) {
|
|
let table = await perspective.table({ d: [str] });
|
|
let view = await table.view({});
|
|
let result = await view.schema();
|
|
expect(result["d"]).toEqual("datetime");
|
|
await view.delete();
|
|
await table.delete();
|
|
}
|
|
});
|
|
|
|
// Only implemented in the C++ date parser - skip
|
|
test.skip("Correctly parses a 'dd mm yyyy' formatted string", async function () {
|
|
let table = await perspective.table({ d: ["15 08 08"] });
|
|
let view = await table.view({});
|
|
let result = await view.schema();
|
|
expect(result["d"]).toEqual("datetime");
|
|
await view.delete();
|
|
await table.delete();
|
|
});
|
|
|
|
test("Does parse a date string in non-US formatting", async function () {
|
|
let table = await perspective.table({ d: ["2018/07/30"] });
|
|
let view = await table.view({});
|
|
let result = await view.schema();
|
|
expect(result["d"]).toEqual("date");
|
|
await view.delete();
|
|
await table.delete();
|
|
});
|
|
|
|
test("Does not mistakenly parse a date-like string", async function () {
|
|
let table = await perspective.table({ d: ["Jan 14, 14"] });
|
|
let view = await table.view({});
|
|
let result = await view.schema();
|
|
expect(result["d"]).toEqual("string");
|
|
await view.delete();
|
|
await table.delete();
|
|
});
|
|
});
|
|
|
|
test("allocates a large tables", async function () {
|
|
function makeid() {
|
|
var text = "";
|
|
var possible = Array.from(Array(26).keys()).map((x) =>
|
|
String.fromCharCode(x + 65),
|
|
);
|
|
for (var i = 0; i < 15; i++)
|
|
text +=
|
|
possible[Math.floor(Math.random() * possible.length)];
|
|
return text;
|
|
}
|
|
let data = [];
|
|
for (let i = 0; i < 35000; i++) {
|
|
data.push({
|
|
a: makeid(),
|
|
b: makeid(),
|
|
c: makeid(),
|
|
d: makeid(),
|
|
w: i + 0.5,
|
|
x: i,
|
|
y: makeid(),
|
|
});
|
|
}
|
|
let table = await perspective.table(data);
|
|
let view = await table.view();
|
|
let result = await view.to_json();
|
|
expect(result.length).toEqual(35000);
|
|
view.delete();
|
|
table.delete();
|
|
}, 3000);
|
|
|
|
test.describe("get_index/get_limit", function () {
|
|
test("get_index() on unindexed table", async function () {
|
|
const table = await perspective.table(data);
|
|
expect(await table.get_index()).toBeUndefined();
|
|
await table.delete();
|
|
});
|
|
|
|
test("get_index() on an indexed table", async function () {
|
|
const table = await perspective.table(data, { index: "x" });
|
|
expect(await table.get_index()).toEqual("x");
|
|
await table.delete();
|
|
});
|
|
|
|
test("get_limit() on table without limit", async function () {
|
|
const table = await perspective.table(data);
|
|
expect(await table.get_limit()).toBeUndefined();
|
|
await table.delete();
|
|
});
|
|
|
|
test("get_limit() on table with limit", async function () {
|
|
const table = await perspective.table(data, { limit: 2 });
|
|
expect(await table.get_limit()).toEqual(2);
|
|
await table.delete();
|
|
});
|
|
});
|
|
|
|
test.describe("Limit table constructors", function () {
|
|
// This is a better version of the OG but still questionable.
|
|
// IMO we should not allow this without an explicit `__INDEX__`.
|
|
test("Should not apply partial updates on limit tables when index wraps", async function () {
|
|
const table = await perspective.table(
|
|
{ a: "float", b: "float" },
|
|
{
|
|
limit: 3,
|
|
},
|
|
);
|
|
|
|
await table.update([
|
|
{ a: 10, b: 1 },
|
|
{ a: 20, b: 2 },
|
|
]);
|
|
|
|
await table.update([{ a: 30 }, { a: 40 }]);
|
|
const view = await table.view();
|
|
const records = await view.to_json();
|
|
await view.delete();
|
|
await table.delete();
|
|
expect(records).toEqual([
|
|
{ a: 20, b: 2 },
|
|
{ a: 30, b: null },
|
|
{ a: 40, b: null },
|
|
]);
|
|
});
|
|
|
|
// We don' tsupport mixed-partial updates anymore!
|
|
test.skip("OG - Should not apply partial updates on limit tables when index wraps", async function () {
|
|
const table = await perspective.table(
|
|
{ a: "float", b: "float" },
|
|
{
|
|
limit: 3,
|
|
},
|
|
);
|
|
|
|
await table.update([
|
|
{ a: 10 },
|
|
{ b: 1 },
|
|
{ a: 20 },
|
|
{ a: null, b: 2 },
|
|
]);
|
|
const view = await table.view();
|
|
const records = await view.to_json();
|
|
await view.delete();
|
|
await table.delete();
|
|
|
|
const table2 = await perspective.table(
|
|
{ a: "float", b: "float" },
|
|
{
|
|
limit: 3,
|
|
},
|
|
);
|
|
|
|
table2.update([{ a: 10 }, { b: 1 }, { a: 20 }, { b: 2 }]);
|
|
const view2 = await table2.view();
|
|
const records2 = await view2.to_json();
|
|
await view2.delete();
|
|
await table2.delete();
|
|
|
|
expect(records).toEqual(records2);
|
|
});
|
|
});
|
|
|
|
test.describe("Indexed table constructors", function () {
|
|
test("Should index on an integer column", async function () {
|
|
const table = await perspective.table(all_types_data, {
|
|
index: "int",
|
|
});
|
|
const view = await table.view();
|
|
expect(await table.size()).toEqual(4);
|
|
expect(await view.to_json()).toEqual([
|
|
{
|
|
int: 1,
|
|
float: 2.25,
|
|
string: "a",
|
|
date: 1579046400000,
|
|
datetime: 1579069800000,
|
|
boolean: false,
|
|
},
|
|
{
|
|
int: 2,
|
|
float: 3.5,
|
|
string: "b",
|
|
date: 1581724800000,
|
|
datetime: 1579091400000,
|
|
boolean: true,
|
|
},
|
|
{
|
|
int: 3,
|
|
float: 4.75,
|
|
string: "c",
|
|
date: 1584230400000,
|
|
datetime: 1579113000000,
|
|
boolean: false,
|
|
},
|
|
{
|
|
int: 4,
|
|
float: 5.25,
|
|
string: "d",
|
|
date: 1586908800000,
|
|
datetime: 1579131000000,
|
|
boolean: true,
|
|
},
|
|
]);
|
|
await view.delete();
|
|
await table.delete();
|
|
});
|
|
|
|
test("Should index on a float column", async function () {
|
|
const table = await perspective.table(all_types_data, {
|
|
index: "float",
|
|
});
|
|
const view = await table.view();
|
|
expect(await table.size()).toEqual(4);
|
|
expect(await view.to_json()).toEqual([
|
|
{
|
|
int: 1,
|
|
float: 2.25,
|
|
string: "a",
|
|
date: 1579046400000,
|
|
datetime: 1579069800000,
|
|
boolean: false,
|
|
},
|
|
{
|
|
int: 2,
|
|
float: 3.5,
|
|
string: "b",
|
|
date: 1581724800000,
|
|
datetime: 1579091400000,
|
|
boolean: true,
|
|
},
|
|
{
|
|
int: 3,
|
|
float: 4.75,
|
|
string: "c",
|
|
date: 1584230400000,
|
|
datetime: 1579113000000,
|
|
boolean: false,
|
|
},
|
|
{
|
|
int: 4,
|
|
float: 5.25,
|
|
string: "d",
|
|
date: 1586908800000,
|
|
datetime: 1579131000000,
|
|
boolean: true,
|
|
},
|
|
]);
|
|
await view.delete();
|
|
await table.delete();
|
|
});
|
|
|
|
test("Should index on a string column", async function () {
|
|
const table = await perspective.table(all_types_data, {
|
|
index: "string",
|
|
});
|
|
const view = await table.view();
|
|
expect(await table.size()).toEqual(4);
|
|
expect(await view.to_json()).toEqual([
|
|
{
|
|
int: 1,
|
|
float: 2.25,
|
|
string: "a",
|
|
date: 1579046400000,
|
|
datetime: 1579069800000,
|
|
boolean: false,
|
|
},
|
|
{
|
|
int: 2,
|
|
float: 3.5,
|
|
string: "b",
|
|
date: 1581724800000,
|
|
datetime: 1579091400000,
|
|
boolean: true,
|
|
},
|
|
{
|
|
int: 3,
|
|
float: 4.75,
|
|
string: "c",
|
|
date: 1584230400000,
|
|
datetime: 1579113000000,
|
|
boolean: false,
|
|
},
|
|
{
|
|
int: 4,
|
|
float: 5.25,
|
|
string: "d",
|
|
date: 1586908800000,
|
|
datetime: 1579131000000,
|
|
boolean: true,
|
|
},
|
|
]);
|
|
await view.delete();
|
|
await table.delete();
|
|
});
|
|
|
|
test("Should index on a date column", async function () {
|
|
const table = await perspective.table(all_types_data, {
|
|
index: "date",
|
|
});
|
|
const view = await table.view();
|
|
expect(await table.size()).toEqual(4);
|
|
expect(await view.to_json()).toEqual([
|
|
{
|
|
int: 1,
|
|
float: 2.25,
|
|
string: "a",
|
|
date: 1579046400000,
|
|
datetime: 1579069800000,
|
|
boolean: false,
|
|
},
|
|
{
|
|
int: 2,
|
|
float: 3.5,
|
|
string: "b",
|
|
date: 1581724800000,
|
|
datetime: 1579091400000,
|
|
boolean: true,
|
|
},
|
|
{
|
|
int: 3,
|
|
float: 4.75,
|
|
string: "c",
|
|
date: 1584230400000,
|
|
datetime: 1579113000000,
|
|
boolean: false,
|
|
},
|
|
{
|
|
int: 4,
|
|
float: 5.25,
|
|
string: "d",
|
|
date: 1586908800000,
|
|
datetime: 1579131000000,
|
|
boolean: true,
|
|
},
|
|
]);
|
|
await view.delete();
|
|
await table.delete();
|
|
});
|
|
|
|
test("Should index on a datetime column", async function () {
|
|
const table = await perspective.table(all_types_data, {
|
|
index: "datetime",
|
|
});
|
|
const view = await table.view();
|
|
expect(await table.size()).toEqual(4);
|
|
expect(await view.to_json()).toEqual([
|
|
{
|
|
int: 1,
|
|
float: 2.25,
|
|
string: "a",
|
|
date: 1579046400000,
|
|
datetime: 1579069800000,
|
|
boolean: false,
|
|
},
|
|
{
|
|
int: 2,
|
|
float: 3.5,
|
|
string: "b",
|
|
date: 1581724800000,
|
|
datetime: 1579091400000,
|
|
boolean: true,
|
|
},
|
|
{
|
|
int: 3,
|
|
float: 4.75,
|
|
string: "c",
|
|
date: 1584230400000,
|
|
datetime: 1579113000000,
|
|
boolean: false,
|
|
},
|
|
{
|
|
int: 4,
|
|
float: 5.25,
|
|
string: "d",
|
|
date: 1586908800000,
|
|
datetime: 1579131000000,
|
|
boolean: true,
|
|
},
|
|
]);
|
|
await view.delete();
|
|
await table.delete();
|
|
});
|
|
});
|
|
});
|
|
})(perspective);
|