fix: 修复 SQL Server 列注释显示
This commit is contained in:
6 files changed
+186
-35
No files matched your search
@@ -9,7 +9,7 @@ import { tableMetaForDataTab } from "@/lib/tableDataTabMeta";
|
|||||||
import * as api from "@/lib/api";
|
import * as api from "@/lib/api";
|
||||||
import type { QueryTab } from "@/types/database";
|
import type { QueryTab } from "@/types/database";
|
||||||
import { useToast } from "@/composables/useToast";
|
import { useToast } from "@/composables/useToast";
|
||||||
import { connectionObjectTreeQuerySchema, effectiveDatabaseTypeForConnection } from "@/lib/jdbcDialect";
|
import { effectiveDatabaseTypeForConnection, metadataSchemaForConnection } from "@/lib/jdbcDialect";
|
||||||
import { uuid } from "@/lib/utils";
|
import { uuid } from "@/lib/utils";
|
||||||
import type { DataGridSortMode } from "@/lib/dataGridSort";
|
import type { DataGridSortMode } from "@/lib/dataGridSort";
|
||||||
|
|
||||||
@@ -55,7 +55,7 @@ export function useDataGridActions(activeTab: ComputedRef<QueryTab | undefined>)
|
|||||||
await connectionStore.ensureConnected(tab.connectionId);
|
await connectionStore.ensureConnected(tab.connectionId);
|
||||||
console.info("[DBX][reloadData:metadata:ensure-connected:done]", { traceId: trace?.traceId, elapsed: trace?.elapsed() });
|
console.info("[DBX][reloadData:metadata:ensure-connected:done]", { traceId: trace?.traceId, elapsed: trace?.elapsed() });
|
||||||
const config = connectionStore.getConfig(tab.connectionId);
|
const config = connectionStore.getConfig(tab.connectionId);
|
||||||
const querySchema = connectionObjectTreeQuerySchema(config, tab.database, tableMeta.schema);
|
const querySchema = metadataSchemaForConnection(config, tab.database, tableMeta.schema);
|
||||||
console.info("[DBX][reloadData:metadata:get-columns:start]", { traceId: trace?.traceId, elapsed: trace?.elapsed(), schema: querySchema, table: tableMeta.tableName });
|
console.info("[DBX][reloadData:metadata:get-columns:start]", { traceId: trace?.traceId, elapsed: trace?.elapsed(), schema: querySchema, table: tableMeta.tableName });
|
||||||
const columns = await api.getColumns(tab.connectionId, tab.database, querySchema, tableMeta.tableName);
|
const columns = await api.getColumns(tab.connectionId, tab.database, querySchema, tableMeta.tableName);
|
||||||
const indexes = await api.listIndexes(tab.connectionId, tab.database, querySchema, tableMeta.tableName).catch(() => []);
|
const indexes = await api.listIndexes(tab.connectionId, tab.database, querySchema, tableMeta.tableName).catch(() => []);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import * as api from "@/lib/api";
|
import * as api from "@/lib/api";
|
||||||
import { connectionObjectTreeQuerySchema, effectiveDatabaseTypeForConnection } from "@/lib/jdbcDialect";
|
import { effectiveDatabaseTypeForConnection, metadataSchemaForConnection } from "@/lib/jdbcDialect";
|
||||||
import { buildTableSelectSql } from "@/lib/tableSelectSql";
|
import { buildTableSelectSql } from "@/lib/tableSelectSql";
|
||||||
import { editableRowIdentifierColumns, usesSyntheticRowIdKey } from "@/lib/tableEditing";
|
import { editableRowIdentifierColumns, usesSyntheticRowIdKey } from "@/lib/tableEditing";
|
||||||
import { useConnectionStore } from "@/stores/connectionStore";
|
import { useConnectionStore } from "@/stores/connectionStore";
|
||||||
@@ -52,7 +52,7 @@ async function openTableTarget(target: NavigationTarget, options: { tableInfoTab
|
|||||||
await connectionStore.ensureConnected(target.connectionId);
|
await connectionStore.ensureConnected(target.connectionId);
|
||||||
if (!config) throw new Error("Connection config not found");
|
if (!config) throw new Error("Connection config not found");
|
||||||
const effectiveDbType = effectiveDatabaseTypeForConnection(config);
|
const effectiveDbType = effectiveDatabaseTypeForConnection(config);
|
||||||
const querySchema = connectionObjectTreeQuerySchema(config, target.database, target.schema);
|
const querySchema = metadataSchemaForConnection(config, target.database, target.schema);
|
||||||
if (config.db_type === "neo4j") {
|
if (config.db_type === "neo4j") {
|
||||||
const columns = await api.getColumns(target.connectionId, target.database, querySchema, target.tableName);
|
const columns = await api.getColumns(target.connectionId, target.database, querySchema, target.tableName);
|
||||||
const primaryKeys = editableRowIdentifierColumns(effectiveDbType, columns);
|
const primaryKeys = editableRowIdentifierColumns(effectiveDbType, columns);
|
||||||
@@ -157,7 +157,7 @@ export function useNavigationTargets(dialogs: { showFieldLineageDialog: { value:
|
|||||||
for (const tab of matchingDataTabs) {
|
for (const tab of matchingDataTabs) {
|
||||||
try {
|
try {
|
||||||
const connection = connectionStore.getConfig(tab.connectionId);
|
const connection = connectionStore.getConfig(tab.connectionId);
|
||||||
const metadataSchema = connectionObjectTreeQuerySchema(connection, tab.database, tab.tableMeta?.schema);
|
const metadataSchema = metadataSchemaForConnection(connection, tab.database, tab.tableMeta?.schema);
|
||||||
const columns = await api.getColumns(tab.connectionId, tab.database, metadataSchema, tab.tableMeta!.tableName);
|
const columns = await api.getColumns(tab.connectionId, tab.database, metadataSchema, tab.tableMeta!.tableName);
|
||||||
const indexes = await api.listIndexes(tab.connectionId, tab.database, metadataSchema, tab.tableMeta!.tableName).catch(() => []);
|
const indexes = await api.listIndexes(tab.connectionId, tab.database, metadataSchema, tab.tableMeta!.tableName).catch(() => []);
|
||||||
queryStore.setTableMeta(tab.id, {
|
queryStore.setTableMeta(tab.id, {
|
||||||
|
|||||||
@@ -62,6 +62,12 @@ export function connectionObjectTreeQuerySchema(connection: JdbcDialectConnectio
|
|||||||
return schema || database;
|
return schema || database;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function metadataSchemaForConnection(connection: JdbcDialectConnection | undefined, database: string, schema?: string): string {
|
||||||
|
const type = effectiveDatabaseTypeForConnection(connection);
|
||||||
|
if (type === "sqlserver") return schema || "dbo";
|
||||||
|
return connectionObjectTreeQuerySchema(connection, database, schema);
|
||||||
|
}
|
||||||
|
|
||||||
export function connectionObjectTreeNodeSchema(connection: JdbcDialectConnection | undefined, database: string, schema?: string): string | undefined {
|
export function connectionObjectTreeNodeSchema(connection: JdbcDialectConnection | undefined, database: string, schema?: string): string | undefined {
|
||||||
if (connection?.db_type === "jdbc" && inferJdbcDialect(connection) === "databend") return schema || database;
|
if (connection?.db_type === "jdbc" && inferJdbcDialect(connection) === "databend") return schema || database;
|
||||||
if (connection?.db_type === "jdbc" && inferJdbcDialect(connection) === "databend") return schema || database;
|
if (connection?.db_type === "jdbc" && inferJdbcDialect(connection) === "databend") return schema || database;
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ import { canUseKeylessRowPredicate, editableRowIdentifierColumns } from "@/lib/t
|
|||||||
import { TABLE_DATA_EXPORT_PAGE_SIZE } from "@/lib/tableDataExport";
|
import { TABLE_DATA_EXPORT_PAGE_SIZE } from "@/lib/tableDataExport";
|
||||||
import { tableMetaForDataTab } from "@/lib/tableDataTabMeta";
|
import { tableMetaForDataTab } from "@/lib/tableDataTabMeta";
|
||||||
import { quoteTableIdentifier } from "@/lib/tableSelectSql";
|
import { quoteTableIdentifier } from "@/lib/tableSelectSql";
|
||||||
import { connectionUsesDatabaseObjectTreeMode, connectionUsesSchemaExecutionContext, effectiveDatabaseTypeForConnection } from "@/lib/jdbcDialect";
|
import { connectionUsesDatabaseObjectTreeMode, connectionUsesSchemaExecutionContext, effectiveDatabaseTypeForConnection, metadataSchemaForConnection } from "@/lib/jdbcDialect";
|
||||||
import { queryTimeoutSecsForConnection } from "@/lib/queryTimeout";
|
import { queryTimeoutSecsForConnection } from "@/lib/queryTimeout";
|
||||||
import { sortDataGridRows, type DataGridSortDirection } from "@/lib/dataGridSort";
|
import { sortDataGridRows, type DataGridSortDirection } from "@/lib/dataGridSort";
|
||||||
import { normalizeResultPageSize } from "@/lib/paginationPageSize";
|
import { normalizeResultPageSize } from "@/lib/paginationPageSize";
|
||||||
@@ -1288,7 +1288,8 @@ export const useQueryStore = defineStore("query", () => {
|
|||||||
if (dbType === "postgres" || dbType === "kwdb") schema = "public";
|
if (dbType === "postgres" || dbType === "kwdb") schema = "public";
|
||||||
else schema = "";
|
else schema = "";
|
||||||
}
|
}
|
||||||
const metadataSchema = normalizeOracleLikeMetadataIdentifier(dbType, schema || undefined, analysis.schema ? analysis.schemaQuoted : false) || "";
|
const resolvedSchema = metadataSchemaForConnection(conn, tab.database, schema || undefined);
|
||||||
|
const metadataSchema = normalizeOracleLikeMetadataIdentifier(dbType, resolvedSchema || undefined, analysis.schema ? analysis.schemaQuoted : false) || "";
|
||||||
const metadataTableName = normalizeOracleLikeMetadataIdentifier(dbType, analysis.tableName, analysis.tableNameQuoted)!;
|
const metadataTableName = normalizeOracleLikeMetadataIdentifier(dbType, analysis.tableName, analysis.tableNameQuoted)!;
|
||||||
const metadataAnalysis = normalizeOracleLikeQueryAnalysis(dbType, analysis, metadataSchema || undefined, metadataTableName);
|
const metadataAnalysis = normalizeOracleLikeQueryAnalysis(dbType, analysis, metadataSchema || undefined, metadataTableName);
|
||||||
|
|
||||||
|
|||||||
@@ -1366,19 +1366,36 @@ fn sqlserver_columns_sql(schema: &str, table: &str) -> String {
|
|||||||
let s = schema.replace('\'', "''");
|
let s = schema.replace('\'', "''");
|
||||||
let t = table.replace('\'', "''");
|
let t = table.replace('\'', "''");
|
||||||
format!(
|
format!(
|
||||||
"SELECT c.COLUMN_NAME, c.DATA_TYPE, c.IS_NULLABLE, c.COLUMN_DEFAULT, \
|
"SELECT c.name AS COLUMN_NAME, \
|
||||||
CASE WHEN kcu.COLUMN_NAME IS NOT NULL THEN 1 ELSE 0 END AS IS_PK, \
|
ty.name AS DATA_TYPE, \
|
||||||
c.NUMERIC_PRECISION, c.NUMERIC_SCALE, c.CHARACTER_MAXIMUM_LENGTH, c.DATETIME_PRECISION, \
|
CASE WHEN c.is_nullable = 1 THEN 'YES' ELSE 'NO' END AS IS_NULLABLE, \
|
||||||
ident.extra AS COLUMN_EXTRA, \
|
dc.definition AS COLUMN_DEFAULT, \
|
||||||
|
CASE WHEN pk.column_id IS NOT NULL THEN 1 ELSE 0 END AS IS_PK, \
|
||||||
|
CONVERT(INT, c.precision) AS NUMERIC_PRECISION, \
|
||||||
|
CONVERT(INT, c.scale) AS NUMERIC_SCALE, \
|
||||||
|
CASE \
|
||||||
|
WHEN ty.name IN ('nchar','nvarchar') AND c.max_length > 0 THEN CONVERT(INT, c.max_length / 2) \
|
||||||
|
WHEN c.max_length = -1 THEN -1 \
|
||||||
|
ELSE CONVERT(INT, c.max_length) \
|
||||||
|
END AS CHARACTER_MAXIMUM_LENGTH, \
|
||||||
|
CONVERT(INT, c.scale) AS DATETIME_PRECISION, \
|
||||||
|
CASE WHEN ic.column_id IS NOT NULL THEN 'identity(' + CONVERT(VARCHAR(38), ic.seed_value) + ',' + CONVERT(VARCHAR(38), ic.increment_value) + ')' ELSE NULL END AS COLUMN_EXTRA, \
|
||||||
ep.value AS COLUMN_COMMENT \
|
ep.value AS COLUMN_COMMENT \
|
||||||
FROM INFORMATION_SCHEMA.COLUMNS c \
|
FROM sys.objects o \
|
||||||
LEFT JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu \
|
JOIN sys.schemas s ON s.schema_id = o.schema_id \
|
||||||
ON c.TABLE_SCHEMA = kcu.TABLE_SCHEMA AND c.TABLE_NAME = kcu.TABLE_NAME AND c.COLUMN_NAME = kcu.COLUMN_NAME \
|
JOIN sys.columns c ON c.object_id = o.object_id \
|
||||||
AND kcu.CONSTRAINT_NAME IN (SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE CONSTRAINT_TYPE = 'PRIMARY KEY' AND TABLE_SCHEMA = '{s}' AND TABLE_NAME = '{t}') \
|
JOIN sys.types ty ON ty.user_type_id = c.user_type_id \
|
||||||
OUTER APPLY (SELECT 'identity(' + CONVERT(VARCHAR(38), ic.seed_value) + ',' + CONVERT(VARCHAR(38), ic.increment_value) + ')' AS extra FROM sys.identity_columns ic WHERE ic.object_id = OBJECT_ID(QUOTENAME('{s}') + '.' + QUOTENAME('{t}')) AND ic.name = c.COLUMN_NAME) ident \
|
LEFT JOIN sys.default_constraints dc ON dc.object_id = c.default_object_id \
|
||||||
OUTER APPLY (SELECT CAST(ep.value AS NVARCHAR(MAX)) AS value FROM sys.extended_properties ep WHERE ep.major_id = OBJECT_ID(QUOTENAME('{s}') + '.' + QUOTENAME('{t}')) AND ep.minor_id = COLUMNPROPERTY(OBJECT_ID(QUOTENAME('{s}') + '.' + QUOTENAME('{t}')), c.COLUMN_NAME, 'ColumnId') AND ep.name = N'MS_Description') ep \
|
LEFT JOIN sys.identity_columns ic ON ic.object_id = c.object_id AND ic.column_id = c.column_id \
|
||||||
WHERE c.TABLE_SCHEMA = '{s}' AND c.TABLE_NAME = '{t}' \
|
LEFT JOIN ( \
|
||||||
ORDER BY c.ORDINAL_POSITION"
|
SELECT ic.object_id, ic.column_id \
|
||||||
|
FROM sys.indexes i \
|
||||||
|
JOIN sys.index_columns ic ON ic.object_id = i.object_id AND ic.index_id = i.index_id \
|
||||||
|
WHERE i.is_primary_key = 1 \
|
||||||
|
) pk ON pk.object_id = c.object_id AND pk.column_id = c.column_id \
|
||||||
|
OUTER APPLY (SELECT CAST(ep.value AS NVARCHAR(MAX)) AS value FROM sys.extended_properties ep WHERE ep.major_id = c.object_id AND ep.minor_id = c.column_id AND ep.name = N'MS_Description') ep \
|
||||||
|
WHERE s.name = '{s}' AND o.name = '{t}' AND o.type IN ('U','V') \
|
||||||
|
ORDER BY c.column_id"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1875,6 +1892,18 @@ mod tests {
|
|||||||
assert!(sql.contains("MS_Description"));
|
assert!(sql.contains("MS_Description"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sqlserver_columns_sql_reads_column_comment_by_column_id() {
|
||||||
|
let sql = sqlserver_columns_sql("dbo", "orders");
|
||||||
|
|
||||||
|
assert!(sql.contains("FROM sys.objects o"));
|
||||||
|
assert!(sql.contains("JOIN sys.columns c ON c.object_id = o.object_id"));
|
||||||
|
assert!(sql.contains("sys.extended_properties ep"));
|
||||||
|
assert!(sql.contains("ep.major_id = c.object_id"));
|
||||||
|
assert!(sql.contains("ep.minor_id = c.column_id"));
|
||||||
|
assert!(sql.contains("MS_Description"));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn sqlserver_table_comment_sql_queries_extended_properties() {
|
fn sqlserver_table_comment_sql_queries_extended_properties() {
|
||||||
let sql = sqlserver_table_comment_sql("dbo", "users");
|
let sql = sqlserver_table_comment_sql("dbo", "users");
|
||||||
@@ -1891,8 +1920,8 @@ mod tests {
|
|||||||
let columns_sql = sqlserver_columns_sql("d'bo", "t'able");
|
let columns_sql = sqlserver_columns_sql("d'bo", "t'able");
|
||||||
let indexes_sql = sqlserver_indexes_sql("d'bo", "t'able");
|
let indexes_sql = sqlserver_indexes_sql("d'bo", "t'able");
|
||||||
|
|
||||||
assert!(columns_sql.contains("TABLE_SCHEMA = 'd''bo'"));
|
assert!(columns_sql.contains("s.name = 'd''bo'"));
|
||||||
assert!(columns_sql.contains("TABLE_NAME = 't''able'"));
|
assert!(columns_sql.contains("o.name = 't''able'"));
|
||||||
assert!(columns_sql.contains("sys.identity_columns"));
|
assert!(columns_sql.contains("sys.identity_columns"));
|
||||||
assert!(indexes_sql.contains("OBJECT_ID('d''bo.t''able')"));
|
assert!(indexes_sql.contains("OBJECT_ID('d''bo.t''able')"));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,6 +47,15 @@ function oracleConn(id: string): ConnectionConfig {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function sqlServerConn(id: string): ConnectionConfig {
|
||||||
|
return {
|
||||||
|
...conn(id),
|
||||||
|
db_type: "sqlserver",
|
||||||
|
port: 1433,
|
||||||
|
username: "sa",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function withConnectionHealthMock(handler: typeof fetch): typeof fetch {
|
function withConnectionHealthMock(handler: typeof fetch): typeof fetch {
|
||||||
return async (input, init) => {
|
return async (input, init) => {
|
||||||
if (String(input) === "/api/connection/check-health") {
|
if (String(input) === "/api/connection/check-health") {
|
||||||
@@ -826,6 +835,106 @@ test("normalizes unquoted Oracle query identifiers before loading editable metad
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("uses dbo as SQL Server metadata schema when query omits schema", async () => {
|
||||||
|
const restoreStorage = installMemoryStorage();
|
||||||
|
setActivePinia(createPinia());
|
||||||
|
const connectionStore = useConnectionStore();
|
||||||
|
const store = useQueryStore();
|
||||||
|
const originalFetch = globalThis.fetch;
|
||||||
|
const columnRequests: Array<{ schema: string | null; table: string | null }> = [];
|
||||||
|
|
||||||
|
connectionStore.addEphemeralConnection(sqlServerConn("sqlserver-1"));
|
||||||
|
|
||||||
|
globalThis.fetch = withConnectionHealthMock(async (input, init) => {
|
||||||
|
const url = String(input);
|
||||||
|
if (url === "/api/query/execute-multi") {
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify([
|
||||||
|
{
|
||||||
|
columns: ["ID", "NAME"],
|
||||||
|
rows: [[1, "Ada"]],
|
||||||
|
affected_rows: 0,
|
||||||
|
execution_time_ms: 1,
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
{ status: 200, headers: { "Content-Type": "application/json" } },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (url === "/api/query/analyze-editability") {
|
||||||
|
const body = JSON.parse(String(init?.body ?? "{}"));
|
||||||
|
assert.equal(body.sql, "select id, name from users");
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({
|
||||||
|
editable: true,
|
||||||
|
analysis: {
|
||||||
|
schema: undefined,
|
||||||
|
schemaQuoted: false,
|
||||||
|
tableName: "users",
|
||||||
|
tableNameQuoted: false,
|
||||||
|
tableAlias: undefined,
|
||||||
|
selectStar: false,
|
||||||
|
columns: [
|
||||||
|
{ sourceName: "id", sourceNameQuoted: false, resultName: "ID", expression: "id" },
|
||||||
|
{ sourceName: "name", sourceNameQuoted: false, resultName: "NAME", expression: "name" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
{ status: 200, headers: { "Content-Type": "application/json" } },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (url.startsWith("/api/schema/columns?")) {
|
||||||
|
const params = new URL(url, "http://localhost").searchParams;
|
||||||
|
columnRequests.push({ schema: params.get("schema"), table: params.get("table") });
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify([
|
||||||
|
{
|
||||||
|
name: "ID",
|
||||||
|
data_type: "int",
|
||||||
|
is_nullable: false,
|
||||||
|
column_default: null,
|
||||||
|
is_primary_key: true,
|
||||||
|
extra: null,
|
||||||
|
comment: "编号",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "NAME",
|
||||||
|
data_type: "nvarchar(100)",
|
||||||
|
is_nullable: true,
|
||||||
|
column_default: null,
|
||||||
|
is_primary_key: false,
|
||||||
|
extra: null,
|
||||||
|
comment: "姓名",
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
{ status: 200, headers: { "Content-Type": "application/json" } },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (url === "/api/query/prepare-pagination-plan") {
|
||||||
|
const body = JSON.parse(String(init?.body ?? "{}"));
|
||||||
|
return new Response(JSON.stringify({ sqlToExecute: body.options.sql, useAgentResultSession: false }), {
|
||||||
|
status: 200,
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return new Response("unexpected request", { status: 500 });
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const tabId = store.createTab("sqlserver-1", "app", "Query 1", "query");
|
||||||
|
await store.executeTabSql(tabId, "select id, name from users");
|
||||||
|
|
||||||
|
const tab = store.tabs.find((item) => item.id === tabId);
|
||||||
|
await waitFor(() => columnRequests.length > 0 && tab?.tableMeta?.tableName === "users");
|
||||||
|
assert.deepEqual(columnRequests, [{ schema: "dbo", table: "users" }]);
|
||||||
|
assert.equal(tab?.tableMeta?.schema, "dbo");
|
||||||
|
assert.equal(tab?.tableMeta?.columns[0]?.comment, "编号");
|
||||||
|
assert.equal(tab?.tableMeta?.columns[1]?.comment, "姓名");
|
||||||
|
} finally {
|
||||||
|
globalThis.fetch = originalFetch;
|
||||||
|
restoreStorage();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
test("evicting cached tab results releases multi-result payloads and sessions", async () => {
|
test("evicting cached tab results releases multi-result payloads and sessions", async () => {
|
||||||
const restoreStorage = installMemoryStorage();
|
const restoreStorage = installMemoryStorage();
|
||||||
setActivePinia(createPinia());
|
setActivePinia(createPinia());
|
||||||
@@ -2500,14 +2609,14 @@ test("query results keep readable table source labels with active database conte
|
|||||||
{ columns: ["id"], rows: [[1]], affected_rows: 0, execution_time_ms: 1 },
|
{ columns: ["id"], rows: [[1]], affected_rows: 0, execution_time_ms: 1 },
|
||||||
{ columns: ["id"], rows: [[2]], affected_rows: 0, execution_time_ms: 1 },
|
{ columns: ["id"], rows: [[2]], affected_rows: 0, execution_time_ms: 1 },
|
||||||
]
|
]
|
||||||
: currentSql === "select * from public.users"
|
: currentSql === "select * from public.users"
|
||||||
? [{ columns: ["id"], rows: [[1]], affected_rows: 0, execution_time_ms: 1 }]
|
|
||||||
: currentSql === "select u.id from users u join orders o on o.user_id = u.id"
|
|
||||||
? [{ columns: ["id"], rows: [[1]], affected_rows: 0, execution_time_ms: 1 }]
|
? [{ columns: ["id"], rows: [[1]], affected_rows: 0, execution_time_ms: 1 }]
|
||||||
: [
|
: currentSql === "select u.id from users u join orders o on o.user_id = u.id"
|
||||||
{ columns: [], rows: [], affected_rows: 1, execution_time_ms: 1 },
|
? [{ columns: ["id"], rows: [[1]], affected_rows: 0, execution_time_ms: 1 }]
|
||||||
{ columns: ["id"], rows: [[1]], affected_rows: 0, execution_time_ms: 1 },
|
: [
|
||||||
];
|
{ columns: [], rows: [], affected_rows: 1, execution_time_ms: 1 },
|
||||||
|
{ columns: ["id"], rows: [[1]], affected_rows: 0, execution_time_ms: 1 },
|
||||||
|
];
|
||||||
return new Response(JSON.stringify(results), { status: 200, headers: { "Content-Type": "application/json" } });
|
return new Response(JSON.stringify(results), { status: 200, headers: { "Content-Type": "application/json" } });
|
||||||
}
|
}
|
||||||
if (url === "/api/query/analyze-editability") {
|
if (url === "/api/query/analyze-editability") {
|
||||||
@@ -2522,15 +2631,21 @@ test("query results keep readable table source labels with active database conte
|
|||||||
try {
|
try {
|
||||||
await store.executeTabSql(tabId, "select * from users; select * from orders");
|
await store.executeTabSql(tabId, "select * from users; select * from orders");
|
||||||
let tab = store.tabs.find((item) => item.id === tabId);
|
let tab = store.tabs.find((item) => item.id === tabId);
|
||||||
assert.deepEqual(tab?.results?.map((result) => result.sourceLabel), ["db.users", "db.orders"]);
|
assert.deepEqual(
|
||||||
assert.deepEqual(tab?.results?.map((result) => result.sourceStatement), ["select * from users", "select * from orders"]);
|
tab?.results?.map((result) => result.sourceLabel),
|
||||||
|
["db.users", "db.orders"],
|
||||||
await store.executeTabSql(
|
|
||||||
defaultDatabaseTabId,
|
|
||||||
"SELECT *\nFROM apis AS ap\nLIMIT 10;\n\nSELECT *\nFROM menus AS mn\nLIMIT 10;",
|
|
||||||
);
|
);
|
||||||
|
assert.deepEqual(
|
||||||
|
tab?.results?.map((result) => result.sourceStatement),
|
||||||
|
["select * from users", "select * from orders"],
|
||||||
|
);
|
||||||
|
|
||||||
|
await store.executeTabSql(defaultDatabaseTabId, "SELECT *\nFROM apis AS ap\nLIMIT 10;\n\nSELECT *\nFROM menus AS mn\nLIMIT 10;");
|
||||||
tab = store.tabs.find((item) => item.id === defaultDatabaseTabId);
|
tab = store.tabs.find((item) => item.id === defaultDatabaseTabId);
|
||||||
assert.deepEqual(tab?.results?.map((result) => result.sourceLabel), ["aaa.apis", "aaa.menus"]);
|
assert.deepEqual(
|
||||||
|
tab?.results?.map((result) => result.sourceLabel),
|
||||||
|
["aaa.apis", "aaa.menus"],
|
||||||
|
);
|
||||||
|
|
||||||
await store.executeTabSql(tabId, "select * from public.users");
|
await store.executeTabSql(tabId, "select * from public.users");
|
||||||
tab = store.tabs.find((item) => item.id === tabId);
|
tab = store.tabs.find((item) => item.id === tabId);
|
||||||
|
|||||||
Reference in new issue
Block a user