feat(query): show database server messages in query results
This commit is contained in:
1 parent
4c7ddd266b
commit
a5e46fd659
45 files changed
+1401
-51
No files matched your search
@@ -264,6 +264,108 @@ SELECT @value AS Message;`;
|
||||
expect(activeTab.value?.result?.rows).toEqual([["x"]]);
|
||||
});
|
||||
|
||||
it("opens the messages view for a message-only result", async () => {
|
||||
const sql = "DO $$ BEGIN RAISE NOTICE 'hello'; END $$;";
|
||||
const activeTab = ref<QueryTab | undefined>({ ...queryTab("app"), sql });
|
||||
const activeConnection = ref<ConnectionConfig | undefined>(connection("postgres"));
|
||||
const activeOutputView = ref<"result" | "summary" | "explain" | "chart" | "messages">("result");
|
||||
const queryStore = useQueryStore();
|
||||
vi.spyOn(queryStore, "executeCurrentSql").mockImplementation(async () => {
|
||||
if (activeTab.value) activeTab.value.result = { columns: [], rows: [], affected_rows: 0, execution_time_ms: 1, messages: [{ severity: "NOTICE", message: "hello", code: "00000" }] };
|
||||
});
|
||||
vi.spyOn(useHistoryStore(), "add").mockResolvedValue(undefined);
|
||||
|
||||
const execution = useSqlExecution({
|
||||
activeTab: computed(() => activeTab.value),
|
||||
activeConnection: computed(() => activeConnection.value),
|
||||
executableSql: computed(() => sql),
|
||||
activeOutputView,
|
||||
});
|
||||
|
||||
await execution.tryExecute();
|
||||
|
||||
expect(activeOutputView.value).toBe("messages");
|
||||
});
|
||||
|
||||
it("keeps the summary view for a MySQL INSERT that carries an INFO message", async () => {
|
||||
const sql = "INSERT INTO users (name) VALUES ('a'), ('b')";
|
||||
const activeTab = ref<QueryTab | undefined>({ ...queryTab("app"), sql });
|
||||
const activeConnection = ref<ConnectionConfig | undefined>(connection("mysql"));
|
||||
const activeOutputView = ref<"result" | "summary" | "explain" | "chart" | "messages">("result");
|
||||
const queryStore = useQueryStore();
|
||||
vi.spyOn(queryStore, "executeCurrentSql").mockImplementation(async () => {
|
||||
if (activeTab.value) activeTab.value.result = { columns: [], rows: [], affected_rows: 2, execution_time_ms: 1, messages: [{ severity: "Note", message: "Records: 2 Duplicates: 0 Warnings: 0" }] };
|
||||
});
|
||||
vi.spyOn(useHistoryStore(), "add").mockResolvedValue(undefined);
|
||||
|
||||
const execution = useSqlExecution({
|
||||
activeTab: computed(() => activeTab.value),
|
||||
activeConnection: computed(() => activeConnection.value),
|
||||
executableSql: computed(() => sql),
|
||||
activeOutputView,
|
||||
});
|
||||
|
||||
await execution.tryExecute();
|
||||
|
||||
expect(activeOutputView.value).toBe("summary");
|
||||
});
|
||||
|
||||
it("keeps the summary view for a batch whose statements emit messages", async () => {
|
||||
const sql = "DO $$ BEGIN RAISE NOTICE 'one'; END $$;\nDO $$ BEGIN RAISE NOTICE 'two'; END $$;";
|
||||
const activeTab = ref<QueryTab | undefined>({ ...queryTab("app"), sql });
|
||||
const activeConnection = ref<ConnectionConfig | undefined>(connection("postgres"));
|
||||
const activeOutputView = ref<"result" | "summary" | "explain" | "chart" | "messages">("result");
|
||||
const queryStore = useQueryStore();
|
||||
vi.spyOn(queryStore, "executeCurrentSql").mockImplementation(async () => {
|
||||
if (activeTab.value)
|
||||
activeTab.value.result = {
|
||||
columns: [],
|
||||
rows: [],
|
||||
affected_rows: 0,
|
||||
execution_time_ms: 1,
|
||||
messages: [
|
||||
{ severity: "NOTICE", message: "one" },
|
||||
{ severity: "NOTICE", message: "two" },
|
||||
],
|
||||
};
|
||||
});
|
||||
vi.spyOn(useHistoryStore(), "add").mockResolvedValue(undefined);
|
||||
|
||||
const execution = useSqlExecution({
|
||||
activeTab: computed(() => activeTab.value),
|
||||
activeConnection: computed(() => activeConnection.value),
|
||||
executableSql: computed(() => sql),
|
||||
activeOutputView,
|
||||
});
|
||||
|
||||
await execution.tryExecute();
|
||||
|
||||
expect(activeOutputView.value).toBe("summary");
|
||||
});
|
||||
|
||||
it("keeps the result view when messages accompany a tabular result", async () => {
|
||||
const sql = "SELECT 1";
|
||||
const activeTab = ref<QueryTab | undefined>({ ...queryTab("app"), sql });
|
||||
const activeConnection = ref<ConnectionConfig | undefined>(connection("postgres"));
|
||||
const activeOutputView = ref<"result" | "summary" | "explain" | "chart" | "messages">("result");
|
||||
const queryStore = useQueryStore();
|
||||
vi.spyOn(queryStore, "executeCurrentSql").mockImplementation(async () => {
|
||||
if (activeTab.value) activeTab.value.result = { columns: ["value"], rows: [[1]], affected_rows: 0, execution_time_ms: 1, messages: [{ severity: "NOTICE", message: "hello" }] };
|
||||
});
|
||||
vi.spyOn(useHistoryStore(), "add").mockResolvedValue(undefined);
|
||||
|
||||
const execution = useSqlExecution({
|
||||
activeTab: computed(() => activeTab.value),
|
||||
activeConnection: computed(() => activeConnection.value),
|
||||
executableSql: computed(() => sql),
|
||||
activeOutputView,
|
||||
});
|
||||
|
||||
await execution.tryExecute();
|
||||
|
||||
expect(activeOutputView.value).toBe("result");
|
||||
});
|
||||
|
||||
it("forwards execute-in-new-result-tab intent to the query store", async () => {
|
||||
const sql = "SELECT * FROM users";
|
||||
const activeTab = ref<QueryTab | undefined>({ ...queryTab("app"), sql });
|
||||
|
||||
@@ -9,6 +9,7 @@ import { isSingleDatabase, usesTreeSchemaMode } from "@/lib/database/databaseCap
|
||||
import { supportsConnectionLevelSqlExecution } from "@/lib/connection/connectionLevelDatabaseBootstrap";
|
||||
import { classifySqlActivityKind } from "@/lib/history/historyActivityKind";
|
||||
import { sqlMetadataRefreshTarget } from "@/lib/sql/sqlMetadataRefresh";
|
||||
import { defaultViewForResult } from "@/lib/query/queryResultDefaultView";
|
||||
import { isQueryExecutionErrorResult } from "@/lib/query/queryResultError";
|
||||
import { classifyRedisCommandSafety } from "@/lib/redis/redisCommandSafety";
|
||||
import { isSqlExecutionSnapshot, resolveExecutableSql, type SqlExecutionOverride, type SqlExecutionSnapshot } from "@/lib/sql/sqlExecutionTarget";
|
||||
@@ -76,7 +77,7 @@ export function useSqlExecution(deps: {
|
||||
activeConnection: ComputedRef<ConnectionConfig | undefined>;
|
||||
executableSql: ComputedRef<string>;
|
||||
resolveExecutableSql?: (snapshot?: SqlExecutionSnapshot) => Promise<string>;
|
||||
activeOutputView: Ref<"result" | "summary" | "explain" | "chart">;
|
||||
activeOutputView: Ref<"result" | "summary" | "explain" | "chart" | "messages">;
|
||||
blockDangerousRedisCommands?: Ref<boolean>;
|
||||
onMissingDatabase?: () => void;
|
||||
}) {
|
||||
@@ -235,7 +236,7 @@ export function useSqlExecution(deps: {
|
||||
} else if (executionDatabaseType === "sqlserver" && tab.result?.server_message === true) {
|
||||
deps.activeOutputView.value = "result";
|
||||
} else if (tab.result && !tab.result.columns.length && !tab.results?.some((result) => result.columns.length > 0)) {
|
||||
deps.activeOutputView.value = "summary";
|
||||
deps.activeOutputView.value = statementCount === 1 ? defaultViewForResult(tab.result) : "summary";
|
||||
}
|
||||
const elapsed = Date.now() - start;
|
||||
const failure = firstQueryExecutionError(tab);
|
||||
|
||||
Reference in new issue
Block a user