Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
192 changes: 56 additions & 136 deletions js/src/components/rowcount/RowCountDiffResultView.tsx
Original file line number Diff line number Diff line change
@@ -1,83 +1,37 @@
import { Center, Flex } from "@chakra-ui/react";
import { isNumber } from "lodash";
import { forwardRef, Ref } from "react";
import { forwardRef, Ref, useMemo } from "react";
import { DataGridHandle } from "react-data-grid";
import {
isRowCountDiffRun,
isRowCountRun,
RowObjectType,
} from "@/lib/api/types";
import { isRowCountDiffRun, isRowCountRun, Run } from "@/lib/api/types";
import { createDataGrid } from "@/lib/dataGrid/dataGridFactory";
import {
EmptyRowsRenderer,
ScreenshotDataGrid,
} from "../data-grid/ScreenshotDataGrid";
import { RunResultViewProps } from "../run/types";
import { deltaPercentageString } from "./delta";

type RowCountDiffResultViewProp = RunResultViewProps;
// ============================================================================
// Shared Component
// ============================================================================

interface RowCountDiffRow extends RowObjectType {
name: string;
base: number | string;
current: number | string;
interface RowCountGridViewProps {
run: Run;
typeGuard: (run: Run) => boolean;
expectedType: string;
}

function _RowCountDiffResultView(
{ run }: RowCountDiffResultViewProp,
function _RowCountGridView(
{ run, typeGuard, expectedType }: RowCountGridViewProps,
ref: Ref<DataGridHandle>,
) {
if (!isRowCountDiffRun(run)) {
throw new Error("Run type must be row_count_diff");
if (!typeGuard(run)) {
throw new Error(`Run type must be ${expectedType}`);
}
function columnCellClass(row: RowObjectType) {
const typedRow = row as unknown as RowCountDiffRow;
if (typedRow.base === typedRow.current) {
return "column-body-normal";
} else if (typedRow.base < typedRow.current || typedRow.base === "N/A") {
return "column-body-added";
} else if (typedRow.base > typedRow.current || typedRow.current === "N/A") {
return "column-body-removed";
}
return "column-body-normal";
}

const runResult = run.result ?? {};

const columns = [
{ key: "name", name: "Name", cellClass: columnCellClass },
{ key: "base", name: "Base Rows", cellClass: columnCellClass },
{ key: "current", name: "Current Rows", cellClass: columnCellClass },
{ key: "delta", name: "Delta", cellClass: columnCellClass },
];
const gridData = useMemo(() => {
return createDataGrid(run) ?? { columns: [], rows: [] };
}, [run]);

const rows: RowCountDiffRow[] = Object.keys(run.result ?? {}).map((key) => {
const result = runResult[key];
const base = isNumber(result.base) ? result.base : null;
const current = isNumber(result.curr) ? result.curr : null;
let delta = "=";

if (base !== null && current !== null) {
delta = base !== current ? deltaPercentageString(base, current) : "=";
} else {
if (base === current) {
delta = "N/A";
} else if (base === null) {
delta = "Added";
} else if (current === null) {
delta = "Removed";
}
}

return {
name: key,
base: base ?? "N/A",
current: current ?? "N/A",
delta: delta,
__status: undefined,
};
});

if (rows.length === 0) {
if (gridData.rows.length === 0) {
return (
<Center bg="rgb(249,249,249)" height="100%">
No nodes matched
Expand All @@ -87,89 +41,55 @@ function _RowCountDiffResultView(

return (
<Flex direction="column">
{Object.keys(runResult).length > 0 && (
<>
<ScreenshotDataGrid
ref={ref}
style={{
blockSize: "auto",
maxHeight: "100%",
overflow: "auto",

fontSize: "10pt",
borderWidth: 1,
}}
columns={columns}
rows={rows}
renderers={{ noRowsFallback: <EmptyRowsRenderer /> }}
className="rdg-light"
/>
</>
)}
<ScreenshotDataGrid
ref={ref}
style={{
blockSize: "auto",
maxHeight: "100%",
overflow: "auto",
fontSize: "0.875rem",
borderWidth: 1,
}}
columns={gridData.columns}
rows={gridData.rows}
renderers={{ noRowsFallback: <EmptyRowsRenderer /> }}
className="rdg-light"
/>
</Flex>
);
}

type RowCountResultViewProp = RunResultViewProps;
const RowCountGridView = forwardRef(_RowCountGridView);

interface RowCountRow extends RowObjectType {
name: string;
current: number | string;
// ============================================================================
// Exported Components
// ============================================================================

function _RowCountDiffResultView(
{ run }: RunResultViewProps,
ref: Ref<DataGridHandle>,
) {
return (
<RowCountGridView
ref={ref}
run={run}
typeGuard={isRowCountDiffRun}
expectedType="row_count_diff"
/>
);
}

function _RowCountResultView(
{ run }: RowCountResultViewProp,
{ run }: RunResultViewProps,
ref: Ref<DataGridHandle>,
) {
if (!isRowCountRun(run)) {
throw new Error("Run type must be row_count");
}
const runResult = run.result ?? {};

const columns = [
{ key: "name", name: "Name" },
{ key: "current", name: "Row Count" },
];

const rows: RowCountRow[] = Object.keys(run.result ?? {}).map((key) => {
const result = runResult[key];
const current = isNumber(result.curr) ? result.curr : null;

return {
name: key,
current: current ?? "N/A",
__status: undefined,
};
});

if (rows.length === 0) {
return (
<Center bg="rgb(249,249,249)" height="100%">
No nodes matched
</Center>
);
}

return (
<Flex direction="column">
{Object.keys(runResult).length > 0 && (
<ScreenshotDataGrid
ref={ref}
style={{
blockSize: "auto",
maxHeight: "100%",
overflow: "auto",

fontSize: "10pt",
borderWidth: 1,
}}
columns={columns}
rows={rows}
renderers={{ noRowsFallback: <EmptyRowsRenderer /> }}
className="rdg-light"
/>
)}
</Flex>
<RowCountGridView
ref={ref}
run={run}
typeGuard={isRowCountRun}
expectedType="row_count"
/>
);
}

Expand Down
118 changes: 94 additions & 24 deletions js/src/lib/dataGrid/dataGridFactory.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -859,30 +859,6 @@ describe("createDataGrid - unsupported run types", () => {
expect(result).toBeNull();
});

test("returns null for row_count run type", () => {
const run = createBaseRun("row_count", {
// @ts-expect-error Testing invalid data
result: { base: 100, current: 100 },
params: { model: "test" },
}) as Run;

const result = createDataGrid(run);

expect(result).toBeNull();
});

test("returns null for row_count_diff run type", () => {
const run = createBaseRun("row_count_diff", {
// @ts-expect-error Testing invalid data
result: { base: 100, current: 110 },
params: { model: "test" },
}) as Run;

const result = createDataGrid(run);

expect(result).toBeNull();
});

test("returns null for lineage_diff run type", () => {
const run = createBaseRun("lineage_diff", {
result: {},
Expand Down Expand Up @@ -2066,4 +2042,98 @@ describe("createDataGrid - regression tests", () => {
expect(result.rows.length).toBe(2);
});
});

// ============================================================================
// createDataGrid - Row Count Run Tests
// ============================================================================

describe("createDataGrid - row_count run", () => {
test("returns grid data for row_count run with result", () => {
const run = createBaseRun("row_count", {
result: {
orders: { curr: 100 },
customers: { curr: 50 },
},
params: { node_names: ["orders", "customers"] },
}) as Run;

const result = createDataGrid(run);

expect(result).not.toBeNull();
expect(result?.columns).toHaveLength(2);
expect(result?.rows).toHaveLength(2);
});

test("returns null for row_count run without result", () => {
const run = createBaseRun("row_count", {
result: undefined,
params: { node_names: ["orders"] },
}) as Run;

const result = createDataGrid(run);

expect(result).toBeNull();
});
});

// ============================================================================
// createDataGrid - Row Count Diff Run Tests
// ============================================================================

describe("createDataGrid - row_count_diff run", () => {
test("returns grid data for row_count_diff run with result", () => {
const run = createBaseRun("row_count_diff", {
result: {
orders: { base: 100, curr: 150 },
customers: { base: 50, curr: 50 },
},
params: { node_names: ["orders", "customers"] },
}) as Run;

const result = createDataGrid(run);

expect(result).not.toBeNull();
expect(result?.columns).toHaveLength(4);
expect(result?.rows).toHaveLength(2);
});

test("returns null for row_count_diff run without result", () => {
const run = createBaseRun("row_count_diff", {
result: undefined,
params: { node_names: ["orders"] },
}) as Run;

const result = createDataGrid(run);

expect(result).toBeNull();
});

test("handles added models (null base)", () => {
const run = createBaseRun("row_count_diff", {
result: {
new_model: { base: null, curr: 100 },
},
params: { node_names: ["new_model"] },
}) as Run;

const result = createDataGrid(run);

expect(result).not.toBeNull();
expect(result?.rows[0].__status).toBe("added");
});

test("handles removed models (null current)", () => {
const run = createBaseRun("row_count_diff", {
result: {
old_model: { base: 100, curr: null },
},
params: { node_names: ["old_model"] },
}) as Run;

const result = createDataGrid(run);

expect(result).not.toBeNull();
expect(result?.rows[0].__status).toBe("removed");
});
});
});
Loading
Loading