1700 lines
68 KiB
JavaScript
1700 lines
68 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 _ from "lodash";
|
|
|
|
let 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 },
|
|
];
|
|
|
|
let partial_change_y = [
|
|
{ x: 1, y: "string1" },
|
|
{ x: 2, y: "string2" },
|
|
];
|
|
let partial_change_z = [
|
|
{ x: 1, z: false },
|
|
{ x: 2, z: true },
|
|
];
|
|
let partial_change_y_z = [
|
|
{ x: 1, y: "string1", z: false },
|
|
{ x: 2, y: "string2", z: true },
|
|
];
|
|
let partial_change_nonseq = [
|
|
{ x: 1, y: "string1", z: false },
|
|
{ x: 4, y: "string2", z: true },
|
|
];
|
|
|
|
async function match_delta(
|
|
perspective,
|
|
delta,
|
|
expected,
|
|
formatter = "to_json",
|
|
) {
|
|
const table = await perspective.table(delta);
|
|
const view = await table.view();
|
|
const result = await view[formatter]();
|
|
expect(result).toEqual(expected);
|
|
await view.delete();
|
|
await table.delete();
|
|
}
|
|
|
|
function it_old_behavior(name, capture) {
|
|
test(name, async function () {
|
|
let done;
|
|
let result = new Promise((x) => {
|
|
done = x;
|
|
});
|
|
|
|
await capture(done);
|
|
await result;
|
|
});
|
|
}
|
|
|
|
((perspective) => {
|
|
test.describe("Row delta", function () {
|
|
test.describe("0-sided row delta", function () {
|
|
it_old_behavior("returns changed rows", async function (done) {
|
|
let table = await perspective.table(data, { index: "x" });
|
|
let view = await table.view();
|
|
view.on_update(
|
|
async function (updated) {
|
|
const expected = [
|
|
{ x: 1, y: "string1", z: true },
|
|
{ x: 2, y: "string2", z: false },
|
|
];
|
|
await match_delta(perspective, updated.delta, expected);
|
|
view.delete();
|
|
table.delete();
|
|
done();
|
|
},
|
|
{ mode: "row" },
|
|
);
|
|
await table.update(partial_change_y);
|
|
});
|
|
|
|
it_old_behavior(
|
|
"returns changed rows, hidden sort",
|
|
async function (done) {
|
|
let table = await perspective.table(data, { index: "x" });
|
|
let view = await table.view({
|
|
columns: ["x"],
|
|
sort: [["y", "desc"]],
|
|
});
|
|
console.log(await view.to_json());
|
|
view.on_update(
|
|
async function (updated) {
|
|
const expected = [{ x: 2 }, { x: 1 }];
|
|
await match_delta(
|
|
perspective,
|
|
updated.delta,
|
|
expected,
|
|
);
|
|
view.delete();
|
|
table.delete();
|
|
done();
|
|
},
|
|
{ mode: "row" },
|
|
);
|
|
await table.update(partial_change_y);
|
|
},
|
|
);
|
|
|
|
it_old_behavior(
|
|
"returns changed rows from schema",
|
|
async function (done) {
|
|
let table = await perspective.table(
|
|
{
|
|
x: "integer",
|
|
y: "string",
|
|
z: "boolean",
|
|
},
|
|
{ index: "x" },
|
|
);
|
|
let view = await table.view();
|
|
view.on_update(
|
|
async function (updated) {
|
|
const expected = [
|
|
{ x: 1, y: "d", z: false },
|
|
{ x: 2, y: "b", z: false },
|
|
{ x: 3, y: "c", z: true },
|
|
];
|
|
await match_delta(
|
|
perspective,
|
|
updated.delta,
|
|
expected,
|
|
);
|
|
view.delete();
|
|
table.delete();
|
|
done();
|
|
},
|
|
{ mode: "row" },
|
|
);
|
|
await table.update([
|
|
{ x: 1, y: "a", z: true },
|
|
{ x: 2, y: "b", z: false },
|
|
{ x: 3, y: "c", z: true },
|
|
{ x: 1, y: "d", z: false },
|
|
]);
|
|
},
|
|
);
|
|
|
|
it_old_behavior("returns added rows", async function (done) {
|
|
let table = await perspective.table(data);
|
|
let view = await table.view();
|
|
view.on_update(
|
|
async function (updated) {
|
|
const expected = [
|
|
{ x: 1, y: "string1", z: null },
|
|
{ x: 2, y: "string2", z: null },
|
|
];
|
|
await match_delta(perspective, updated.delta, expected);
|
|
view.delete();
|
|
table.delete();
|
|
done();
|
|
},
|
|
{ mode: "row" },
|
|
);
|
|
await table.update(partial_change_y);
|
|
});
|
|
|
|
it_old_behavior(
|
|
"returns added rows from schema",
|
|
async function (done) {
|
|
let table = await perspective.table({
|
|
x: "integer",
|
|
y: "string",
|
|
z: "boolean",
|
|
});
|
|
let view = await table.view();
|
|
view.on_update(
|
|
async function (updated) {
|
|
await match_delta(perspective, updated.delta, data);
|
|
view.delete();
|
|
table.delete();
|
|
done();
|
|
},
|
|
{ mode: "row" },
|
|
);
|
|
await table.update(data);
|
|
},
|
|
);
|
|
|
|
it_old_behavior("returns deleted columns", async function (done) {
|
|
let table = await perspective.table(data, { index: "x" });
|
|
let view = await table.view();
|
|
view.on_update(
|
|
async function (updated) {
|
|
const expected = [
|
|
{ x: 1, y: null, z: true },
|
|
{ x: 4, y: null, z: false },
|
|
];
|
|
await match_delta(perspective, updated.delta, expected);
|
|
view.delete();
|
|
table.delete();
|
|
done();
|
|
},
|
|
{ mode: "row" },
|
|
);
|
|
await table.update([
|
|
{ x: 1, y: null },
|
|
{ x: 4, y: null },
|
|
]);
|
|
});
|
|
|
|
it_old_behavior(
|
|
"returns changed rows in sorted context",
|
|
async function (done) {
|
|
let table = await perspective.table(data, { index: "x" });
|
|
let view = await table.view({
|
|
sort: [["x", "desc"]],
|
|
});
|
|
view.on_update(
|
|
async function (updated) {
|
|
const expected = [
|
|
{ x: 2, y: "string2", z: false },
|
|
{ x: 1, y: "string1", z: true },
|
|
];
|
|
await match_delta(
|
|
perspective,
|
|
updated.delta,
|
|
expected,
|
|
);
|
|
view.delete();
|
|
table.delete();
|
|
done();
|
|
},
|
|
{ mode: "row" },
|
|
);
|
|
await table.update(partial_change_y);
|
|
},
|
|
);
|
|
|
|
it_old_behavior(
|
|
"returns changed rows in sorted context from schema",
|
|
async function (done) {
|
|
let table = await perspective.table(
|
|
{
|
|
x: "integer",
|
|
y: "string",
|
|
z: "boolean",
|
|
},
|
|
{ index: "x" },
|
|
);
|
|
let view = await table.view({
|
|
sort: [["x", "desc"]],
|
|
});
|
|
view.on_update(
|
|
async function (updated) {
|
|
const expected = [
|
|
{ x: 4, y: "a", z: true },
|
|
{ x: 3, y: "c", z: true },
|
|
{ x: 2, y: "b", z: false },
|
|
{ x: 1, y: "d", z: false },
|
|
];
|
|
await match_delta(
|
|
perspective,
|
|
updated.delta,
|
|
expected,
|
|
);
|
|
view.delete();
|
|
table.delete();
|
|
done();
|
|
},
|
|
{ mode: "row" },
|
|
);
|
|
await table.update([
|
|
{ x: 1, y: "a", z: true },
|
|
{ x: 2, y: "b", z: false },
|
|
{ x: 3, y: "c", z: true },
|
|
{ x: 1, y: "d", z: false },
|
|
{ x: 4, y: "a", z: true },
|
|
]);
|
|
},
|
|
);
|
|
|
|
it_old_behavior(
|
|
"returns added rows in filtered context from schema",
|
|
async function (done) {
|
|
let table = await perspective.table({
|
|
x: "integer",
|
|
y: "string",
|
|
z: "boolean",
|
|
});
|
|
let view = await table.view({
|
|
filter: [["x", ">", 3]],
|
|
});
|
|
view.on_update(
|
|
async function (updated) {
|
|
await match_delta(perspective, updated.delta, [
|
|
{ x: 4, y: "d", z: false },
|
|
]);
|
|
view.delete();
|
|
table.delete();
|
|
done();
|
|
},
|
|
{ mode: "row" },
|
|
);
|
|
await table.update(data);
|
|
},
|
|
);
|
|
|
|
it_old_behavior(
|
|
"returns changed rows in non-sequential update",
|
|
async function (done) {
|
|
let table = await perspective.table(data, { index: "x" });
|
|
let view = await table.view();
|
|
view.on_update(
|
|
async function (updated) {
|
|
const expected = partial_change_nonseq;
|
|
await match_delta(
|
|
perspective,
|
|
updated.delta,
|
|
expected,
|
|
);
|
|
view.delete();
|
|
table.delete();
|
|
done();
|
|
},
|
|
{ mode: "row" },
|
|
);
|
|
await table.update(partial_change_nonseq);
|
|
},
|
|
);
|
|
});
|
|
|
|
test.describe("0-sided row delta, randomized column order", function () {
|
|
it_old_behavior("returns changed rows", async function (done) {
|
|
let table = await perspective.table(data, { index: "x" });
|
|
let columns = _.shuffle(await table.columns());
|
|
let view = await table.view({
|
|
columns: columns,
|
|
});
|
|
view.on_update(
|
|
async function (updated) {
|
|
const expected = [
|
|
{ x: 1, y: "string1", z: true },
|
|
{ x: 2, y: "string2", z: false },
|
|
];
|
|
await match_delta(perspective, updated.delta, expected);
|
|
view.delete();
|
|
table.delete();
|
|
done();
|
|
},
|
|
{ mode: "row" },
|
|
);
|
|
await table.update(partial_change_y);
|
|
});
|
|
|
|
it_old_behavior(
|
|
"returns changed rows from schema",
|
|
async function (done) {
|
|
let table = await perspective.table(
|
|
{
|
|
x: "integer",
|
|
y: "string",
|
|
z: "boolean",
|
|
},
|
|
{ index: "x" },
|
|
);
|
|
let columns = _.shuffle(await table.columns());
|
|
let view = await table.view({
|
|
columns: columns,
|
|
});
|
|
view.on_update(
|
|
async function (updated) {
|
|
const expected = [
|
|
{ x: 1, y: "d", z: false },
|
|
{ x: 2, y: "b", z: false },
|
|
{ x: 3, y: "c", z: true },
|
|
];
|
|
await match_delta(
|
|
perspective,
|
|
updated.delta,
|
|
expected,
|
|
);
|
|
view.delete();
|
|
table.delete();
|
|
done();
|
|
},
|
|
{ mode: "row" },
|
|
);
|
|
await table.update([
|
|
{ x: 1, y: "a", z: true },
|
|
{ x: 2, y: "b", z: false },
|
|
{ x: 3, y: "c", z: true },
|
|
{ x: 1, y: "d", z: false },
|
|
]);
|
|
},
|
|
);
|
|
|
|
it_old_behavior("returns added rows", async function (done) {
|
|
let table = await perspective.table(data);
|
|
let columns = _.shuffle(await table.columns());
|
|
let view = await table.view({
|
|
columns: columns,
|
|
});
|
|
view.on_update(
|
|
async function (updated) {
|
|
const expected = [
|
|
{ x: 1, y: "string1", z: null },
|
|
{ x: 2, y: "string2", z: null },
|
|
];
|
|
await match_delta(perspective, updated.delta, expected);
|
|
view.delete();
|
|
table.delete();
|
|
done();
|
|
},
|
|
{ mode: "row" },
|
|
);
|
|
await table.update(partial_change_y);
|
|
});
|
|
|
|
it_old_behavior(
|
|
"returns added rows, hidden sort",
|
|
async function (done) {
|
|
let table = await perspective.table(data);
|
|
let view = await table.view({
|
|
columns: ["x"],
|
|
sort: [["y", "desc"]],
|
|
});
|
|
view.on_update(
|
|
async function (updated) {
|
|
const expected = [{ x: 2 }, { x: 1 }];
|
|
await match_delta(
|
|
perspective,
|
|
updated.delta,
|
|
expected,
|
|
);
|
|
view.delete();
|
|
table.delete();
|
|
done();
|
|
},
|
|
{ mode: "row" },
|
|
);
|
|
await table.update(partial_change_y);
|
|
},
|
|
);
|
|
|
|
it_old_behavior(
|
|
"returns added rows from schema",
|
|
async function (done) {
|
|
let table = await perspective.table({
|
|
x: "integer",
|
|
y: "string",
|
|
z: "boolean",
|
|
});
|
|
let columns = _.shuffle(await table.columns());
|
|
let view = await table.view({
|
|
columns: columns,
|
|
});
|
|
view.on_update(
|
|
async function (updated) {
|
|
await match_delta(perspective, updated.delta, data);
|
|
view.delete();
|
|
table.delete();
|
|
done();
|
|
},
|
|
{ mode: "row" },
|
|
);
|
|
await table.update(data);
|
|
},
|
|
);
|
|
|
|
it_old_behavior("returns deleted columns", async function (done) {
|
|
let table = await perspective.table(data, { index: "x" });
|
|
let columns = _.shuffle(await table.columns());
|
|
let view = await table.view({
|
|
columns: columns,
|
|
});
|
|
view.on_update(
|
|
async function (updated) {
|
|
const expected = [
|
|
{ x: 1, y: null, z: true },
|
|
{ x: 4, y: null, z: false },
|
|
];
|
|
await match_delta(perspective, updated.delta, expected);
|
|
view.delete();
|
|
table.delete();
|
|
done();
|
|
},
|
|
{ mode: "row" },
|
|
);
|
|
await table.update([
|
|
{ x: 1, y: null },
|
|
{ x: 4, y: null },
|
|
]);
|
|
});
|
|
|
|
it_old_behavior(
|
|
"returns changed rows in non-sequential update",
|
|
async function (done) {
|
|
let table = await perspective.table(data, { index: "x" });
|
|
let columns = _.shuffle(await table.columns());
|
|
let view = await table.view({
|
|
columns: columns,
|
|
});
|
|
view.on_update(
|
|
async function (updated) {
|
|
const expected = partial_change_nonseq;
|
|
await match_delta(
|
|
perspective,
|
|
updated.delta,
|
|
expected,
|
|
);
|
|
view.delete();
|
|
table.delete();
|
|
done();
|
|
},
|
|
{ mode: "row" },
|
|
);
|
|
await table.update(partial_change_nonseq);
|
|
},
|
|
);
|
|
});
|
|
|
|
test.describe("0-sided row delta, column order subset", function () {
|
|
it_old_behavior("returns changed rows", async function (done) {
|
|
let table = await perspective.table(data, { index: "x" });
|
|
let view = await table.view({
|
|
columns: ["y"],
|
|
});
|
|
view.on_update(
|
|
async function (updated) {
|
|
const expected = [{ y: "string1" }, { y: "string2" }];
|
|
await match_delta(perspective, updated.delta, expected);
|
|
view.delete();
|
|
table.delete();
|
|
done();
|
|
},
|
|
{ mode: "row" },
|
|
);
|
|
await table.update(partial_change_y);
|
|
});
|
|
|
|
it_old_behavior(
|
|
"returns changed rows from schema",
|
|
async function (done) {
|
|
let table = await perspective.table(
|
|
{
|
|
x: "integer",
|
|
y: "string",
|
|
z: "boolean",
|
|
},
|
|
{ index: "x" },
|
|
);
|
|
let view = await table.view({
|
|
columns: ["z"],
|
|
});
|
|
view.on_update(
|
|
async function (updated) {
|
|
const expected = [
|
|
{ z: false },
|
|
{ z: false },
|
|
{ z: true },
|
|
];
|
|
await match_delta(
|
|
perspective,
|
|
updated.delta,
|
|
expected,
|
|
);
|
|
view.delete();
|
|
table.delete();
|
|
done();
|
|
},
|
|
{ mode: "row" },
|
|
);
|
|
await table.update([
|
|
{ x: 1, y: "a", z: true },
|
|
{ x: 2, y: "b", z: false },
|
|
{ x: 3, y: "c", z: true },
|
|
{ x: 1, y: "d", z: false },
|
|
]);
|
|
},
|
|
);
|
|
|
|
it_old_behavior("returns added rows", async function (done) {
|
|
let table = await perspective.table(data);
|
|
let view = await table.view({
|
|
columns: ["y"],
|
|
});
|
|
view.on_update(
|
|
async function (updated) {
|
|
const expected = [{ y: "string1" }, { y: "string2" }];
|
|
await match_delta(perspective, updated.delta, expected);
|
|
view.delete();
|
|
table.delete();
|
|
done();
|
|
},
|
|
{ mode: "row" },
|
|
);
|
|
await table.update(partial_change_y);
|
|
});
|
|
|
|
it_old_behavior(
|
|
"returns added rows from schema",
|
|
async function (done) {
|
|
let table = await perspective.table({
|
|
x: "integer",
|
|
y: "string",
|
|
z: "boolean",
|
|
});
|
|
let view = await table.view({
|
|
columns: ["z"],
|
|
});
|
|
view.on_update(
|
|
async function (updated) {
|
|
await match_delta(perspective, updated.delta, [
|
|
{ z: true },
|
|
{ z: false },
|
|
{ z: true },
|
|
{ z: false },
|
|
]);
|
|
view.delete();
|
|
table.delete();
|
|
done();
|
|
},
|
|
{ mode: "row" },
|
|
);
|
|
await table.update(data);
|
|
},
|
|
);
|
|
|
|
it_old_behavior("returns deleted rows", async function (done) {
|
|
let table = await perspective.table(data, { index: "x" });
|
|
let view = await table.view({
|
|
columns: ["y"],
|
|
});
|
|
view.on_update(
|
|
async function (updated) {
|
|
const expected = [{ y: null }, { y: null }];
|
|
await match_delta(perspective, updated.delta, expected);
|
|
view.delete();
|
|
table.delete();
|
|
done();
|
|
},
|
|
{ mode: "row" },
|
|
);
|
|
await table.update([
|
|
{ x: 1, y: null },
|
|
{ x: 4, y: null },
|
|
]);
|
|
});
|
|
|
|
it_old_behavior(
|
|
"returns changed rows in non-sequential update",
|
|
async function (done) {
|
|
let table = await perspective.table(data, { index: "x" });
|
|
let view = await table.view({
|
|
columns: ["y"],
|
|
});
|
|
view.on_update(
|
|
async function (updated) {
|
|
await match_delta(perspective, updated.delta, [
|
|
{ y: "string1" },
|
|
{ y: "string2" },
|
|
]);
|
|
view.delete();
|
|
table.delete();
|
|
done();
|
|
},
|
|
{ mode: "row" },
|
|
);
|
|
await table.update(partial_change_nonseq);
|
|
},
|
|
);
|
|
});
|
|
|
|
test.describe("1-sided row delta", function () {
|
|
it_old_behavior("returns changed rows", async function (done) {
|
|
let table = await perspective.table(data, { index: "x" });
|
|
let view = await table.view({
|
|
group_by: ["y"],
|
|
aggregates: { y: "distinct count", z: "distinct count" },
|
|
});
|
|
view.on_update(
|
|
async function (updated) {
|
|
const expected = [
|
|
{ x: 1, y: 1, z: 1 },
|
|
{ x: 2, y: 1, z: 1 },
|
|
];
|
|
await match_delta(perspective, updated.delta, expected);
|
|
view.delete();
|
|
table.delete();
|
|
done();
|
|
},
|
|
{ mode: "row" },
|
|
);
|
|
await table.update(partial_change_y);
|
|
});
|
|
|
|
test.skip("returns changed rows, unique", async function () {
|
|
// FIXME: the delta doesn't seem to trigger if the
|
|
// cell is invalidated, only if the actual values are
|
|
// different. This feels off behavior-wise.
|
|
const table = await perspective.table(
|
|
{
|
|
x: [1, 2, 3, 4],
|
|
y: ["a", "a", "a", "a"],
|
|
z: [100, 200, 100, 200],
|
|
},
|
|
{ index: "x" },
|
|
);
|
|
|
|
const view = await table.view({
|
|
group_by: ["z"],
|
|
aggregates: { y: "unique" },
|
|
});
|
|
|
|
expect(await view.to_columns()).toEqual({
|
|
__ROW_PATH__: [[], [100], [200]],
|
|
x: [10, 4, 6],
|
|
y: ["a", "a", "a"],
|
|
z: [600, 200, 400],
|
|
});
|
|
|
|
view.on_update(
|
|
async function (updated) {
|
|
console.log(await view.to_columns());
|
|
const expected = [
|
|
{ x: 10, y: null, z: 600 }, // total
|
|
{ x: 6, y: null, z: 400 },
|
|
];
|
|
await match_delta(perspective, updated.delta, expected);
|
|
await view.delete();
|
|
await table.delete();
|
|
done();
|
|
},
|
|
{ mode: "row" },
|
|
);
|
|
|
|
await table.update({
|
|
x: [4],
|
|
y: ["a"],
|
|
z: [200],
|
|
});
|
|
});
|
|
|
|
it_old_behavior(
|
|
"returns changed rows, column range",
|
|
async function (done) {
|
|
let table = await perspective.table(data, { index: "x" });
|
|
let view = await table.view({
|
|
group_by: ["y"],
|
|
columns: ["x"],
|
|
aggregates: {
|
|
y: "distinct count",
|
|
z: "distinct count",
|
|
},
|
|
});
|
|
view.on_update(
|
|
async function (updated) {
|
|
const expected = [{ x: 1 }, { x: 2 }];
|
|
await match_delta(
|
|
perspective,
|
|
updated.delta,
|
|
expected,
|
|
);
|
|
view.delete();
|
|
table.delete();
|
|
done();
|
|
},
|
|
{ mode: "row" },
|
|
);
|
|
await table.update(partial_change_y);
|
|
},
|
|
);
|
|
|
|
it_old_behavior(
|
|
"returns nothing when updated data is not in pivot",
|
|
async function (done) {
|
|
let table = await perspective.table(data, { index: "x" });
|
|
let view = await table.view({
|
|
group_by: ["y"],
|
|
aggregates: {
|
|
y: "distinct count",
|
|
z: "distinct count",
|
|
},
|
|
});
|
|
view.on_update(
|
|
async function (updated) {
|
|
await match_delta(perspective, updated.delta, []);
|
|
view.delete();
|
|
table.delete();
|
|
done();
|
|
},
|
|
{ mode: "row" },
|
|
);
|
|
await table.update(partial_change_z);
|
|
},
|
|
);
|
|
|
|
it_old_behavior("returns added rows", async function (done) {
|
|
let table = await perspective.table(data);
|
|
let view = await table.view({
|
|
group_by: ["y"],
|
|
aggregates: { y: "distinct count", z: "distinct count" },
|
|
});
|
|
view.on_update(
|
|
async function (updated) {
|
|
const expected = [
|
|
{ x: 13, y: 6, z: 3 },
|
|
{ x: 1, y: 1, z: 1 },
|
|
{ x: 2, y: 1, z: 1 },
|
|
];
|
|
await match_delta(perspective, updated.delta, expected);
|
|
view.delete();
|
|
table.delete();
|
|
done();
|
|
},
|
|
{ mode: "row" },
|
|
);
|
|
await table.update(partial_change_y);
|
|
});
|
|
|
|
it_old_behavior(
|
|
"returns added rows, column range",
|
|
async function (done) {
|
|
let table = await perspective.table(data);
|
|
let view = await table.view({
|
|
group_by: ["y"],
|
|
columns: ["z"],
|
|
aggregates: {
|
|
y: "distinct count",
|
|
z: "distinct count",
|
|
},
|
|
});
|
|
view.on_update(
|
|
async function (updated) {
|
|
const expected = [{ z: 3 }, { z: 1 }, { z: 1 }];
|
|
await match_delta(
|
|
perspective,
|
|
updated.delta,
|
|
expected,
|
|
);
|
|
view.delete();
|
|
table.delete();
|
|
done();
|
|
},
|
|
{ mode: "row" },
|
|
);
|
|
await table.update(partial_change_y);
|
|
},
|
|
);
|
|
|
|
it_old_behavior("returns deleted columns", async function (done) {
|
|
let table = await perspective.table(data, { index: "x" });
|
|
let view = await table.view({
|
|
group_by: ["y"],
|
|
aggregates: { y: "distinct count", z: "distinct count" },
|
|
});
|
|
view.on_update(
|
|
async function (updated) {
|
|
// underlying data changes, but only total aggregate row is affected
|
|
const expected = [{ x: 10, y: 3, z: 2 }];
|
|
await match_delta(perspective, updated.delta, expected);
|
|
view.delete();
|
|
table.delete();
|
|
done();
|
|
},
|
|
{ mode: "row" },
|
|
);
|
|
await table.update([
|
|
{ x: 1, y: null },
|
|
{ x: 4, y: null },
|
|
]);
|
|
});
|
|
|
|
it_old_behavior(
|
|
"returns changed rows in non-sequential update",
|
|
async function (done) {
|
|
let table = await perspective.table(data, { index: "x" });
|
|
let view = await table.view({
|
|
group_by: ["y"],
|
|
aggregates: {
|
|
y: "distinct count",
|
|
z: "distinct count",
|
|
},
|
|
});
|
|
view.on_update(
|
|
async function (updated) {
|
|
// aggregates are sorted, in this case by string comparator - "string1" and "string2" are at the end
|
|
const expected = [
|
|
{ x: 1, y: 1, z: 1 },
|
|
{ x: 4, y: 1, z: 1 },
|
|
];
|
|
await match_delta(
|
|
perspective,
|
|
updated.delta,
|
|
expected,
|
|
);
|
|
view.delete();
|
|
table.delete();
|
|
done();
|
|
},
|
|
{ mode: "row" },
|
|
);
|
|
await table.update(partial_change_nonseq);
|
|
},
|
|
);
|
|
|
|
it_old_behavior(
|
|
"Returns appended rows, hidden sort",
|
|
async function (done) {
|
|
const table = await perspective.table({
|
|
x: [1, 2, 3, 4],
|
|
y: ["A", "B", "C", "D"],
|
|
});
|
|
const view = await table.view({
|
|
group_by: ["y"],
|
|
sort: [["y", "desc"]],
|
|
columns: ["x"],
|
|
});
|
|
|
|
view.on_update(
|
|
async function (updated) {
|
|
const expected = [{ x: 13 }, { x: 2 }, { x: 1 }];
|
|
await match_delta(
|
|
perspective,
|
|
updated.delta,
|
|
expected,
|
|
);
|
|
await view.delete();
|
|
await table.delete();
|
|
done();
|
|
},
|
|
{ mode: "row" },
|
|
);
|
|
|
|
await table.update(partial_change_y);
|
|
},
|
|
);
|
|
});
|
|
|
|
test.describe("2-sided row delta", function () {
|
|
it_old_behavior(
|
|
"returns changed rows when updated data in group by",
|
|
async function (done) {
|
|
let table = await perspective.table(data, { index: "y" });
|
|
let view = await table.view({
|
|
group_by: ["y"],
|
|
split_by: ["x"],
|
|
});
|
|
view.on_update(
|
|
async function (updated) {
|
|
const json = await view.to_json();
|
|
json.map((d) => {
|
|
delete d["__ROW_PATH__"];
|
|
});
|
|
const expected = json.slice(0, 3);
|
|
await match_delta(
|
|
perspective,
|
|
updated.delta,
|
|
expected,
|
|
);
|
|
view.delete();
|
|
table.delete();
|
|
done();
|
|
},
|
|
{ mode: "row" },
|
|
);
|
|
await table.update(partial_change_y);
|
|
},
|
|
);
|
|
|
|
it_old_behavior(
|
|
"returns changed rows when updated data in group by, column range",
|
|
async function (done) {
|
|
let table = await perspective.table(data, { index: "y" });
|
|
let view = await table.view({
|
|
group_by: ["y"],
|
|
split_by: ["x"],
|
|
columns: ["x"],
|
|
});
|
|
view.on_update(
|
|
async function (updated) {
|
|
const json = await view.to_json();
|
|
json.map((d) => {
|
|
delete d["__ROW_PATH__"];
|
|
});
|
|
const expected = json.slice(0, 3);
|
|
await match_delta(
|
|
perspective,
|
|
updated.delta,
|
|
expected,
|
|
);
|
|
view.delete();
|
|
table.delete();
|
|
done();
|
|
},
|
|
{ mode: "row" },
|
|
);
|
|
await table.update(partial_change_y);
|
|
},
|
|
);
|
|
|
|
it_old_behavior(
|
|
"returns changed rows when updated data in group by, hidden sort",
|
|
async function (done) {
|
|
let table = await perspective.table(data, { index: "y" });
|
|
let view = await table.view({
|
|
group_by: ["y"],
|
|
split_by: ["x"],
|
|
sort: [["y", "desc"]],
|
|
columns: ["x"],
|
|
});
|
|
view.on_update(
|
|
async function (updated) {
|
|
const expected = await view.to_json();
|
|
await match_delta(
|
|
perspective,
|
|
updated.delta,
|
|
expected.slice(0, 3).map((x) => {
|
|
delete x.__ROW_PATH__;
|
|
return x;
|
|
}),
|
|
);
|
|
view.delete();
|
|
table.delete();
|
|
done();
|
|
},
|
|
{ mode: "row" },
|
|
);
|
|
await table.update(partial_change_y);
|
|
},
|
|
);
|
|
|
|
test.skip("returns changed rows when updated data in group by multi, hidden sort", async function () {
|
|
let table = await perspective.table(data, { index: "y" });
|
|
let view = await table.view({
|
|
group_by: ["y", "x", "z"],
|
|
split_by: ["x"],
|
|
sort: [["y", "desc"]],
|
|
columns: ["x"],
|
|
});
|
|
view.on_update(
|
|
async function (updated) {
|
|
const expected = {
|
|
"1|x": [14, 0, 0],
|
|
"1|y": ["-", null, null],
|
|
"2|x": [2, 3, null],
|
|
"2|y": ["-", "WORLD", null],
|
|
"3|x": [2, null, 1],
|
|
"3|y": ["b", null, "HELLO"],
|
|
"4|x": [6, null, 1],
|
|
"4|y": ["-", null, "HELLO"],
|
|
};
|
|
await match_delta(
|
|
perspective,
|
|
updated.delta,
|
|
expected,
|
|
"to_columns",
|
|
);
|
|
view.delete();
|
|
table.delete();
|
|
done();
|
|
},
|
|
{ mode: "row" },
|
|
);
|
|
await table.update(partial_change_y);
|
|
});
|
|
|
|
it_old_behavior(
|
|
"returns changed rows when updated data in split by",
|
|
async function (done) {
|
|
let table = await perspective.table(data, { index: "x" });
|
|
let view = await table.view({
|
|
group_by: ["y"],
|
|
split_by: ["z"],
|
|
});
|
|
view.on_update(
|
|
async function (updated) {
|
|
const json = await view.to_json();
|
|
json.map((d) => {
|
|
delete d["__ROW_PATH__"];
|
|
});
|
|
const expected = json.slice(0, 3);
|
|
await match_delta(
|
|
perspective,
|
|
updated.delta,
|
|
expected,
|
|
);
|
|
view.delete();
|
|
table.delete();
|
|
done();
|
|
},
|
|
{ mode: "row" },
|
|
);
|
|
await table.update(partial_change_z);
|
|
},
|
|
);
|
|
|
|
it_old_behavior(
|
|
"returns changed rows when updated data in split by, column range",
|
|
async function (done) {
|
|
let table = await perspective.table(data, { index: "x" });
|
|
let view = await table.view({
|
|
group_by: ["y"],
|
|
split_by: ["z"],
|
|
columns: ["y"],
|
|
});
|
|
view.on_update(
|
|
async function (updated) {
|
|
const json = await view.to_json();
|
|
json.map((d) => {
|
|
delete d["__ROW_PATH__"];
|
|
});
|
|
const expected = json.slice(0, 3);
|
|
await match_delta(
|
|
perspective,
|
|
updated.delta,
|
|
expected,
|
|
);
|
|
view.delete();
|
|
table.delete();
|
|
done();
|
|
},
|
|
{ mode: "row" },
|
|
);
|
|
await table.update(partial_change_z);
|
|
},
|
|
);
|
|
|
|
it_old_behavior(
|
|
"returns changed rows when updated data in row and split by",
|
|
async function (done) {
|
|
let table = await perspective.table(data, { index: "x" });
|
|
let view = await table.view({
|
|
group_by: ["y"],
|
|
split_by: ["z"],
|
|
});
|
|
view.on_update(
|
|
async function (updated) {
|
|
const json = await view.to_json();
|
|
json.map((d) => {
|
|
delete d["__ROW_PATH__"];
|
|
});
|
|
const expected = [json[0], json[3], json[4]];
|
|
await match_delta(
|
|
perspective,
|
|
updated.delta,
|
|
expected,
|
|
);
|
|
view.delete();
|
|
table.delete();
|
|
done();
|
|
},
|
|
{ mode: "row" },
|
|
);
|
|
await table.update(partial_change_y_z);
|
|
},
|
|
);
|
|
|
|
it_old_behavior(
|
|
"returns changed rows when updated data in row and split by, column range",
|
|
async function (done) {
|
|
let table = await perspective.table(data, { index: "x" });
|
|
let view = await table.view({
|
|
group_by: ["y"],
|
|
split_by: ["z"],
|
|
columns: ["x"],
|
|
});
|
|
view.on_update(
|
|
async function (updated) {
|
|
const json = await view.to_json();
|
|
json.map((d) => {
|
|
delete d["__ROW_PATH__"];
|
|
});
|
|
const expected = [json[0], json[3], json[4]];
|
|
await match_delta(
|
|
perspective,
|
|
updated.delta,
|
|
expected,
|
|
);
|
|
view.delete();
|
|
table.delete();
|
|
done();
|
|
},
|
|
{ mode: "row" },
|
|
);
|
|
await table.update(partial_change_y_z);
|
|
},
|
|
);
|
|
|
|
it_old_behavior(
|
|
"returns nothing when updated data is not in pivot",
|
|
async function (done) {
|
|
let table = await perspective.table(data, { index: "x" });
|
|
let view = await table.view({
|
|
group_by: ["y"],
|
|
split_by: ["x"],
|
|
aggregates: {
|
|
y: "distinct count",
|
|
z: "distinct count",
|
|
},
|
|
});
|
|
view.on_update(
|
|
async function (updated) {
|
|
await match_delta(perspective, updated.delta, []);
|
|
view.delete();
|
|
table.delete();
|
|
done();
|
|
},
|
|
{ mode: "row" },
|
|
);
|
|
await table.update(partial_change_z);
|
|
},
|
|
);
|
|
|
|
it_old_behavior("returns added rows", async function (done) {
|
|
let table = await perspective.table(data);
|
|
let view = await table.view({
|
|
group_by: ["y"],
|
|
split_by: ["x"],
|
|
});
|
|
view.on_update(
|
|
async function (updated) {
|
|
const json = await view.to_json();
|
|
json.map((d) => {
|
|
delete d["__ROW_PATH__"];
|
|
});
|
|
const expected = json.slice(0, 3);
|
|
await match_delta(perspective, updated.delta, expected);
|
|
view.delete();
|
|
table.delete();
|
|
done();
|
|
},
|
|
{ mode: "row" },
|
|
);
|
|
await table.update(partial_change_y);
|
|
});
|
|
|
|
it_old_behavior("returns deleted columns", async function (done) {
|
|
let table = await perspective.table(data, { index: "x" });
|
|
let view = await table.view({
|
|
group_by: ["y"],
|
|
split_by: ["x"],
|
|
aggregates: { y: "unique" },
|
|
columns: ["x", "y", "z"],
|
|
});
|
|
view.on_update(
|
|
async function (updated) {
|
|
// underlying data changes, but only total aggregate row is affected
|
|
const expected = await view.to_json();
|
|
expected.splice(3, 1);
|
|
expected.map((d) => {
|
|
delete d["__ROW_PATH__"];
|
|
});
|
|
await match_delta(perspective, updated.delta, expected);
|
|
view.delete();
|
|
table.delete();
|
|
done();
|
|
},
|
|
{ mode: "row" },
|
|
);
|
|
await table.update([
|
|
{ x: 1, y: null },
|
|
{ x: 2, y: null },
|
|
{ x: 4, y: null },
|
|
]);
|
|
});
|
|
|
|
it_old_behavior(
|
|
"returns deleted columns, column range",
|
|
async function (done) {
|
|
let table = await perspective.table(data, { index: "x" });
|
|
let view = await table.view({
|
|
group_by: ["y"],
|
|
split_by: ["x"],
|
|
aggregates: { y: "unique" },
|
|
columns: ["y"],
|
|
});
|
|
view.on_update(
|
|
async function (updated) {
|
|
// underlying data changes, but only total aggregate row is affected
|
|
const expected = await view.to_json();
|
|
expected.splice(3, 1);
|
|
expected.map((d) => {
|
|
delete d["__ROW_PATH__"];
|
|
});
|
|
await match_delta(
|
|
perspective,
|
|
updated.delta,
|
|
expected,
|
|
);
|
|
view.delete();
|
|
table.delete();
|
|
done();
|
|
},
|
|
{ mode: "row" },
|
|
);
|
|
await table.update([
|
|
{ x: 1, y: null },
|
|
{ x: 2, y: null },
|
|
{ x: 4, y: null },
|
|
]);
|
|
},
|
|
);
|
|
|
|
it_old_behavior(
|
|
"returns changed rows in non-sequential update",
|
|
async function (done) {
|
|
let table = await perspective.table(data, { index: "x" });
|
|
let view = await table.view({
|
|
group_by: ["y"],
|
|
split_by: ["x"],
|
|
aggregates: {
|
|
y: "distinct count",
|
|
z: "distinct count",
|
|
},
|
|
});
|
|
view.on_update(
|
|
async function (updated) {
|
|
// aggregates are sorted, in this case by string comparator - "string1" and "string2" are at the end
|
|
const json = await view.to_json();
|
|
json.map((d) => {
|
|
delete d["__ROW_PATH__"];
|
|
});
|
|
const expected = [json[3], json[4]];
|
|
await match_delta(
|
|
perspective,
|
|
updated.delta,
|
|
expected,
|
|
);
|
|
view.delete();
|
|
table.delete();
|
|
done();
|
|
},
|
|
{ mode: "row" },
|
|
);
|
|
await table.update(partial_change_nonseq);
|
|
},
|
|
);
|
|
|
|
it_old_behavior(
|
|
"returns changed rows in column-only pivots",
|
|
async function (done) {
|
|
let table = await perspective.table(data, { index: "x" });
|
|
let view = await table.view({
|
|
split_by: ["x"],
|
|
});
|
|
view.on_update(
|
|
async function (updated) {
|
|
const json = await view.to_json();
|
|
const expected = [
|
|
{
|
|
"1|x": 1,
|
|
"1|y": "string1",
|
|
"1|z": false,
|
|
"2|x": 2,
|
|
"2|y": "b",
|
|
"2|z": false,
|
|
"3|x": 3,
|
|
"3|y": "c",
|
|
"3|z": true,
|
|
"4|x": 4,
|
|
"4|y": "string2",
|
|
"4|z": true,
|
|
},
|
|
json[0],
|
|
json[3],
|
|
];
|
|
await match_delta(
|
|
perspective,
|
|
updated.delta,
|
|
expected,
|
|
);
|
|
view.delete();
|
|
table.delete();
|
|
done();
|
|
},
|
|
{ mode: "row" },
|
|
);
|
|
await table.update(partial_change_nonseq);
|
|
},
|
|
);
|
|
|
|
it_old_behavior(
|
|
"returns changed rows, col only",
|
|
async function (done) {
|
|
let table = await perspective.table(data, {
|
|
index: "x",
|
|
});
|
|
let view = await table.view({
|
|
split_by: ["y"],
|
|
});
|
|
view.on_update(
|
|
async function (updated) {
|
|
const expected = [
|
|
{
|
|
"c|x": 3,
|
|
"c|y": "c",
|
|
"c|z": true,
|
|
"d|x": 4,
|
|
"d|y": "d",
|
|
"d|z": false,
|
|
"string1|x": 1,
|
|
"string1|y": "string1",
|
|
"string1|z": true,
|
|
"string2|x": 2,
|
|
"string2|y": "string2",
|
|
"string2|z": false,
|
|
},
|
|
{
|
|
"c|x": null,
|
|
"c|y": null,
|
|
"c|z": null,
|
|
"d|x": null,
|
|
"d|y": null,
|
|
"d|z": null,
|
|
"string1|x": 1,
|
|
"string1|y": "string1",
|
|
"string1|z": true,
|
|
"string2|x": null,
|
|
"string2|y": null,
|
|
"string2|z": null,
|
|
},
|
|
{
|
|
"c|x": null,
|
|
"c|y": null,
|
|
"c|z": null,
|
|
"d|x": null,
|
|
"d|y": null,
|
|
"d|z": null,
|
|
"string1|x": null,
|
|
"string1|y": null,
|
|
"string1|z": null,
|
|
"string2|x": 2,
|
|
"string2|y": "string2",
|
|
"string2|z": false,
|
|
},
|
|
];
|
|
await match_delta(
|
|
perspective,
|
|
updated.delta,
|
|
expected,
|
|
);
|
|
view.delete();
|
|
table.delete();
|
|
done();
|
|
},
|
|
{
|
|
mode: "row",
|
|
},
|
|
);
|
|
await table.update(partial_change_y);
|
|
},
|
|
);
|
|
|
|
it_old_behavior(
|
|
"returns changed rows, col only agg",
|
|
async function (done) {
|
|
const table = await perspective.table(data, {
|
|
index: "x",
|
|
});
|
|
|
|
const view = await table.view({
|
|
split_by: ["x"],
|
|
sort: [["y", "desc"]],
|
|
columns: ["y"],
|
|
aggregates: { y: "last" },
|
|
});
|
|
|
|
view.on_update(
|
|
async function (updated) {
|
|
// TODO: deltas return a total row for column only
|
|
// which they probably shouldn't.
|
|
const expected = [
|
|
{
|
|
"1|y": "string1",
|
|
"2|y": "string2",
|
|
"3|y": "c",
|
|
"4|y": "d",
|
|
},
|
|
{
|
|
"1|y": null,
|
|
"2|y": "string2",
|
|
"3|y": null,
|
|
"4|y": null,
|
|
},
|
|
{
|
|
"1|y": "string1",
|
|
"2|y": null,
|
|
"3|y": null,
|
|
"4|y": null,
|
|
},
|
|
];
|
|
await match_delta(
|
|
perspective,
|
|
updated.delta,
|
|
expected,
|
|
);
|
|
await view.delete();
|
|
await table.delete();
|
|
done();
|
|
},
|
|
{ mode: "row" },
|
|
);
|
|
|
|
await table.update(partial_change_y);
|
|
},
|
|
);
|
|
|
|
it_old_behavior(
|
|
"returns changed rows, col only col range",
|
|
async function (done) {
|
|
let table = await perspective.table(data, {
|
|
index: "x",
|
|
});
|
|
let view = await table.view({
|
|
split_by: ["y"],
|
|
columns: ["x"],
|
|
});
|
|
view.on_update(
|
|
async function (updated) {
|
|
const expected = [
|
|
{
|
|
"c|x": 3,
|
|
"d|x": 4,
|
|
"string1|x": 1,
|
|
"string2|x": 2,
|
|
},
|
|
{
|
|
"c|x": null,
|
|
"d|x": null,
|
|
"string1|x": 1,
|
|
"string2|x": null,
|
|
},
|
|
{
|
|
"c|x": null,
|
|
"d|x": null,
|
|
"string1|x": null,
|
|
"string2|x": 2,
|
|
},
|
|
];
|
|
await match_delta(
|
|
perspective,
|
|
updated.delta,
|
|
expected,
|
|
);
|
|
view.delete();
|
|
table.delete();
|
|
done();
|
|
},
|
|
{
|
|
mode: "row",
|
|
},
|
|
);
|
|
await table.update(partial_change_y);
|
|
},
|
|
);
|
|
|
|
it_old_behavior(
|
|
"returns changed rows, col only sorted",
|
|
async function (done) {
|
|
const table = await perspective.table(data, {
|
|
index: "x",
|
|
});
|
|
const view = await table.view({
|
|
split_by: ["y"],
|
|
columns: ["x"],
|
|
sort: [["x", "desc"]],
|
|
});
|
|
console.log(await view.to_json());
|
|
view.on_update(
|
|
async function (updated) {
|
|
const expected = [
|
|
{
|
|
"c|x": 3,
|
|
"d|x": 4,
|
|
"string1|x": 1,
|
|
"string2|x": 2,
|
|
},
|
|
{
|
|
"c|x": null,
|
|
"d|x": null,
|
|
"string1|x": null,
|
|
"string2|x": 2,
|
|
},
|
|
{
|
|
"c|x": null,
|
|
"d|x": null,
|
|
"string1|x": 1,
|
|
"string2|x": null,
|
|
},
|
|
];
|
|
await match_delta(
|
|
perspective,
|
|
updated.delta,
|
|
expected,
|
|
);
|
|
await view.delete();
|
|
await table.delete();
|
|
done();
|
|
},
|
|
{
|
|
mode: "row",
|
|
},
|
|
);
|
|
await table.update(partial_change_y);
|
|
},
|
|
);
|
|
|
|
it_old_behavior(
|
|
"returns changed rows, col only sorted change not in pivot",
|
|
async function (done) {
|
|
let table = await perspective.table(
|
|
{ x: [1], y: [100] },
|
|
{
|
|
index: "x",
|
|
},
|
|
);
|
|
let view = await table.view({
|
|
split_by: ["y"],
|
|
columns: ["x"],
|
|
sort: [["x", "desc"]],
|
|
});
|
|
console.log(await view.to_json());
|
|
view.on_update(
|
|
async function (updated) {
|
|
const expected = [{ "100|x": 3 }];
|
|
await match_delta(
|
|
perspective,
|
|
updated.delta,
|
|
expected,
|
|
);
|
|
view.delete();
|
|
table.delete();
|
|
done();
|
|
},
|
|
{
|
|
mode: "row",
|
|
},
|
|
);
|
|
await table.update([{ x: 3, y: 100 }]);
|
|
},
|
|
);
|
|
|
|
it_old_behavior(
|
|
"returns changed rows, col only hidden sort",
|
|
async function (done) {
|
|
const table = await perspective.table(data, { index: "x" });
|
|
const view = await table.view({
|
|
split_by: ["y"],
|
|
columns: ["x"],
|
|
sort: [["y", "desc"]],
|
|
});
|
|
view.on_update(
|
|
async function (updated) {
|
|
const expected = [
|
|
{
|
|
"c|x": 3,
|
|
"d|x": 4,
|
|
"string1|x": 1,
|
|
"string2|x": 2,
|
|
},
|
|
{
|
|
"c|x": null,
|
|
"d|x": null,
|
|
"string1|x": null,
|
|
"string2|x": 2,
|
|
},
|
|
{
|
|
"c|x": null,
|
|
"d|x": null,
|
|
"string1|x": 1,
|
|
"string2|x": null,
|
|
},
|
|
];
|
|
await match_delta(
|
|
perspective,
|
|
updated.delta,
|
|
expected,
|
|
);
|
|
await view.delete();
|
|
await table.delete();
|
|
done();
|
|
},
|
|
{ mode: "row" },
|
|
);
|
|
await table.update(partial_change_y);
|
|
},
|
|
);
|
|
});
|
|
});
|
|
})(perspective);
|