fix(cassandra): report materialized views and skip db-side sort
This commit is contained in:
1 parent
eea3faa224
commit
0938b6bee0
11 files changed
+296
-42
No files matched your search
@@ -350,7 +350,7 @@ import { useTheme } from "@/composables/useTheme";
|
||||
import { useConnectionStore } from "@/stores/connectionStore";
|
||||
import { useQueryStore } from "@/stores/queryStore";
|
||||
import { useSettingsStore } from "@/stores/settingsStore";
|
||||
import { simpleDataGridOrderByMatchesSort, simpleDataGridOrderByReferencesMissingColumn, type DataGridSortDirection, type DataGridSortMode } from "@/lib/dataGrid/dataGridSort";
|
||||
import { databaseSortSupportedForDatabase, simpleDataGridOrderByMatchesSort, simpleDataGridOrderByReferencesMissingColumn, type DataGridSortDirection, type DataGridSortMode } from "@/lib/dataGrid/dataGridSort";
|
||||
import { resolveGridFocusRestoreTarget } from "@/lib/dataGrid/dataGridFocusRestore";
|
||||
import { buildOrderedGridRows, type GridInsertRowPosition, type GridNewRowPlacement } from "@/lib/dataGrid/gridNewRowPlacement";
|
||||
import {
|
||||
@@ -848,6 +848,7 @@ function sortMenuItems(column: string, columnIndex: number) {
|
||||
column,
|
||||
columnIndex,
|
||||
state: currentColumnSortState(),
|
||||
databaseSortEnabled: databaseSortSupportedForDatabase(resolvedDatabaseType.value),
|
||||
labels: {
|
||||
databaseAscending: t("grid.sortDatabaseAscending"),
|
||||
databaseDescending: t("grid.sortDatabaseDescending"),
|
||||
@@ -12514,6 +12515,7 @@ const gridContextMenuItems = computed<ContextMenuItem[]>(() => {
|
||||
canFilter: canUseWhereSearch.value,
|
||||
hasSort: !!sortCol.value,
|
||||
sortMode: sortMode.value,
|
||||
databaseSortEnabled: databaseSortSupportedForDatabase(resolvedDatabaseType.value),
|
||||
frozenColumnCount: frozenColumnCount.value,
|
||||
contextVisibleColIdx: contextHeaderVisibleColIdx.value ?? undefined,
|
||||
hasColumnSelection: hasColumnSelection.value,
|
||||
|
||||
@@ -18,6 +18,46 @@ describe("dataGridContextMenu", () => {
|
||||
expect(dataGridSelectedSortMenuValue(state, "id", 0)).toBe("local-desc");
|
||||
});
|
||||
|
||||
it("omits database sort entries from the sort menu when database sort is unsupported", () => {
|
||||
const state = { column: "id", columnIndex: 0, direction: "desc" as const, mode: "local" as const };
|
||||
const items = createDataGridSortMenuItems({
|
||||
column: "id",
|
||||
columnIndex: 0,
|
||||
state,
|
||||
databaseSortEnabled: false,
|
||||
labels: { databaseAscending: "db asc", databaseDescending: "db desc", currentPageAscending: "page asc", currentPageDescending: "page desc", clear: "clear" },
|
||||
icons: { database: icon, ascending: icon, descending: icon, clear: icon },
|
||||
});
|
||||
expect(items.map((item) => item.value)).toEqual(["local-asc", "local-desc", "clear"]);
|
||||
expect(items[0]?.separatorBefore).toBeFalsy();
|
||||
expect(dataGridSelectedSortMenuValue(state, "id", 0)).toBe("local-desc");
|
||||
});
|
||||
|
||||
it("omits database sort entries from the column context menu when database sort is unsupported", () => {
|
||||
const action = vi.fn();
|
||||
const filter = createDataGridFilterSubmenu({
|
||||
label: "filter",
|
||||
icon,
|
||||
labels: { equals: "equals", notEquals: "not equals", like: "like", notLike: "not like", lessThan: "less", greaterThan: "greater", isNull: "null", isNotNull: "not null", clear: "clear" },
|
||||
apply: action,
|
||||
clear: action,
|
||||
});
|
||||
const items = createDataGridColumnContextMenuItems({
|
||||
headerColumn: false,
|
||||
contextColumn: true,
|
||||
canCopyAlterSql: false,
|
||||
canFilter: true,
|
||||
hasSort: true,
|
||||
sortMode: "database",
|
||||
databaseSortEnabled: false,
|
||||
labels: { copyName: "copy name", copyNames: "copy names", details: "details", copyAlterSql: "alter", databaseAscending: "db asc", databaseDescending: "db desc", localAscending: "local asc", localDescending: "local desc", clearSort: "clear sort" },
|
||||
icons: { copy: icon, columnDetails: icon, database: icon, ascending: icon, descending: icon, clearSort: icon },
|
||||
actions: { copyName: action, copyNames: action, details: action, copyAlterSql: action, sort: action },
|
||||
filterSubmenu: filter,
|
||||
});
|
||||
expect(items.map((item) => item.label)).toEqual(["local asc", "local desc", "clear sort", "", "filter"]);
|
||||
});
|
||||
|
||||
it("omits unavailable server actions and disables unavailable formatter", () => {
|
||||
const items = createDataGridCompactColumnActionItems({
|
||||
labels: { formatter: "formatter", clearFormatter: "clear formatter", localFilter: "local", serverFilter: "server" },
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { compareDataGridValues, simpleDataGridOrderByColumn, simpleDataGridOrderByMatchesSort, simpleDataGridOrderByReferencesMissingColumn } from "@/lib/dataGrid/dataGridSort";
|
||||
import { compareDataGridValues, databaseSortSupportedForDatabase, simpleDataGridOrderByColumn, simpleDataGridOrderByMatchesSort, simpleDataGridOrderByReferencesMissingColumn } from "@/lib/dataGrid/dataGridSort";
|
||||
|
||||
describe("databaseSortSupportedForDatabase", () => {
|
||||
it("keeps database-side sorting for databases that support ORDER BY", () => {
|
||||
expect(databaseSortSupportedForDatabase("postgres")).toBe(true);
|
||||
expect(databaseSortSupportedForDatabase("mysql")).toBe(true);
|
||||
expect(databaseSortSupportedForDatabase(undefined)).toBe(true);
|
||||
});
|
||||
|
||||
it("disables database-side sorting for Cassandra browse queries", () => {
|
||||
expect(databaseSortSupportedForDatabase("cassandra")).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("simpleDataGridOrderByColumn", () => {
|
||||
it.each([
|
||||
|
||||
@@ -77,6 +77,7 @@ export function createDataGridColumnContextMenuItems(options: {
|
||||
canFilter: boolean;
|
||||
hasSort: boolean;
|
||||
sortMode: "database" | "local";
|
||||
databaseSortEnabled?: boolean;
|
||||
frozenColumnCount?: number;
|
||||
contextVisibleColIdx?: number;
|
||||
hasColumnSelection?: boolean;
|
||||
@@ -94,13 +95,14 @@ export function createDataGridColumnContextMenuItems(options: {
|
||||
}
|
||||
if (!options.contextColumn && !options.headerColumn) return items;
|
||||
if (options.contextColumn) {
|
||||
items.push(
|
||||
{ label: options.labels.databaseAscending, action: () => options.actions.sort("asc", "database"), icon: options.icons.database },
|
||||
{ label: options.labels.databaseDescending, action: () => options.actions.sort("desc", "database"), icon: options.icons.database },
|
||||
{ label: "", separator: true },
|
||||
{ label: options.labels.localAscending, action: () => options.actions.sort("asc", "local"), icon: options.icons.ascending },
|
||||
{ label: options.labels.localDescending, action: () => options.actions.sort("desc", "local"), icon: options.icons.descending },
|
||||
);
|
||||
if (options.databaseSortEnabled !== false) {
|
||||
items.push(
|
||||
{ label: options.labels.databaseAscending, action: () => options.actions.sort("asc", "database"), icon: options.icons.database },
|
||||
{ label: options.labels.databaseDescending, action: () => options.actions.sort("desc", "database"), icon: options.icons.database },
|
||||
{ label: "", separator: true },
|
||||
);
|
||||
}
|
||||
items.push({ label: options.labels.localAscending, action: () => options.actions.sort("asc", "local"), icon: options.icons.ascending }, { label: options.labels.localDescending, action: () => options.actions.sort("desc", "local"), icon: options.icons.descending });
|
||||
if (options.hasSort) items.push({ label: options.labels.clearSort, action: () => options.actions.sort(null, options.sortMode), icon: options.icons.clearSort });
|
||||
if (options.canFilter) items.push({ label: "", separator: true }, options.filterSubmenu);
|
||||
}
|
||||
@@ -210,13 +212,17 @@ export function dataGridSelectedSortMenuValue(state: DataGridColumnSortState, co
|
||||
return dataGridColumnIsSorted(state, column, columnIndex) ? `${state.mode}-${state.direction}` : undefined;
|
||||
}
|
||||
|
||||
export function createDataGridSortMenuItems(options: { column: string; columnIndex: number; state: DataGridColumnSortState; labels: SortMenuLabels; icons: SortMenuIcons }): DataGridColumnMenuItem[] {
|
||||
const { column, columnIndex, state, labels, icons } = options;
|
||||
export function createDataGridSortMenuItems(options: { column: string; columnIndex: number; state: DataGridColumnSortState; labels: SortMenuLabels; icons: SortMenuIcons; databaseSortEnabled?: boolean }): DataGridColumnMenuItem[] {
|
||||
const { column, columnIndex, state, labels, icons, databaseSortEnabled = true } = options;
|
||||
const sorted = dataGridColumnIsSorted(state, column, columnIndex);
|
||||
return [
|
||||
{ label: labels.databaseAscending, value: "database-asc", icon: icons.database, checked: sorted && state.direction === "asc" && state.mode === "database" },
|
||||
{ label: labels.databaseDescending, value: "database-desc", icon: icons.database, checked: sorted && state.direction === "desc" && state.mode === "database" },
|
||||
{ label: labels.currentPageAscending, value: "local-asc", icon: icons.ascending, checked: sorted && state.direction === "asc" && state.mode === "local", separatorBefore: true },
|
||||
...(databaseSortEnabled
|
||||
? [
|
||||
{ label: labels.databaseAscending, value: "database-asc", icon: icons.database, checked: sorted && state.direction === "asc" && state.mode === "database" },
|
||||
{ label: labels.databaseDescending, value: "database-desc", icon: icons.database, checked: sorted && state.direction === "desc" && state.mode === "database" },
|
||||
]
|
||||
: []),
|
||||
{ label: labels.currentPageAscending, value: "local-asc", icon: icons.ascending, checked: sorted && state.direction === "asc" && state.mode === "local", separatorBefore: databaseSortEnabled },
|
||||
{ label: labels.currentPageDescending, value: "local-desc", icon: icons.descending, checked: sorted && state.direction === "desc" && state.mode === "local" },
|
||||
{ label: labels.clear, value: "clear", icon: icons.clear, disabled: !sorted, separatorBefore: true },
|
||||
];
|
||||
|
||||
@@ -1,8 +1,18 @@
|
||||
import type { DatabaseType } from "@/types/database";
|
||||
import { isNumericColumnType } from "@/lib/dataGrid/dataGridColumnType";
|
||||
|
||||
export type DataGridSortDirection = "asc" | "desc";
|
||||
export type DataGridSortMode = "database" | "local";
|
||||
|
||||
/**
|
||||
* Cassandra rejects ORDER BY unless the partition key is restricted by an
|
||||
* equality filter, so a browse query can never be sorted database-side there
|
||||
* and the sort would keep failing on every refresh or page jump while applied.
|
||||
*/
|
||||
export function databaseSortSupportedForDatabase(databaseType?: DatabaseType): boolean {
|
||||
return databaseType !== "cassandra";
|
||||
}
|
||||
|
||||
export interface DataGridSortState {
|
||||
column: string | null;
|
||||
columnIndex: number | null;
|
||||
|
||||
Reference in new issue
Block a user