feat(grid): inherit physical column formatting in query results

This commit is contained in:
二丫讲梵 authored and GitHub committed 2026-09-01 11:19:46 +08:00
1 parent 8be503bf40
commit c7cea5a047
19 files changed
+329 -53

No files matched your search

@@ -115,7 +115,7 @@ describe("queryStore grouped-result column comments", () => {
// Only the directly projected physical column carries its comment; the
// aggregate expression resolves to nothing and must not guess.
expect(tab.resultColumnComments).toEqual(["所属部门", undefined]);
expect(tab.queryDisplaySourceColumns).toEqual([{ sourceKey: "users:0", sourceColumn: "department" }, undefined]);
expect(tab.queryDisplaySourceColumns).toEqual([{ sourceKey: "users:0", sourceColumn: "department", database: "app", schema: "app", tableName: "users" }, undefined]);
});
it("resolves aliased grouped columns back to their physical column (T2)", async () => {
@@ -139,7 +139,7 @@ describe("queryStore grouped-result column comments", () => {
await vi.waitFor(() => expect(tab.resultColumnComments).toBeDefined());
expect(tab.queryEditabilityReason).toBe("aggregation");
expect(tab.resultColumnComments).toEqual(["所属部门", undefined]);
expect(tab.queryDisplaySourceColumns).toEqual([{ sourceKey: "users:0", sourceColumn: "department" }, undefined]);
expect(tab.queryDisplaySourceColumns).toEqual([{ sourceKey: "users:0", sourceColumn: "department", database: "app", schema: "app", tableName: "users" }, undefined]);
});
it("keeps comments for HAVING queries (T3)", async () => {
@@ -186,7 +186,7 @@ describe("queryStore grouped-result column comments", () => {
await vi.waitFor(() => expect(tab.resultColumnComments).toBeDefined());
expect(tab.queryEditabilityReason).toBe("aggregation");
expect(tab.resultColumnComments).toEqual(["所属部门", undefined]);
expect(tab.queryDisplaySourceColumns).toEqual([{ sourceKey: "u:0", sourceColumn: "department" }, undefined]);
expect(tab.queryDisplaySourceColumns).toEqual([{ sourceKey: "u:0", sourceColumn: "department", database: "app", schema: "app", tableName: "users" }, undefined]);
});
it("maps multiple grouped physical columns (T5)", async () => {
@@ -236,7 +236,7 @@ describe("queryStore grouped-result column comments", () => {
expect(tab.queryDisplaySourceColumns).toEqual([undefined, undefined]);
});
it("keeps ordinary editable queries free of the new display fields (T10)", async () => {
it("stores physical source identities for ordinary editable queries (T10)", async () => {
analyzeEditableQueryEditability.mockResolvedValue({
editable: true,
analysis: {
@@ -268,7 +268,10 @@ describe("queryStore grouped-result column comments", () => {
const tab = store.tabs.find((item) => item.id === tabId)!;
await vi.waitFor(() => expect(tab.tableMeta?.tableName).toBe("users"));
expect(tab.resultColumnComments).toBeUndefined();
expect(tab.queryDisplaySourceColumns).toBeUndefined();
expect(tab.queryDisplaySourceColumns).toEqual([
{ sourceKey: "users:0", sourceColumn: "id", database: "app", schema: "app", tableName: "users" },
{ sourceKey: "users:0", sourceColumn: "department", database: "app", schema: "app", tableName: "users" },
]);
expect(tab.querySourceColumns).toEqual(["id", "department"]);
});
@@ -137,12 +137,13 @@ describe("queryStore multi-source result column comments", () => {
// keeps its own comment instead of first-source-wins on the name.
expect(tab.resultColumnComments).toEqual(["订单ID", "下单用户", "用户ID", "用户名"]);
// The display mapping carries source identity per ordinal.
// The display mapping carries both source identity and physical table
// identity per ordinal, so display-only features can share table settings.
expect(tab.queryDisplaySourceColumns).toEqual([
{ sourceKey: "a", sourceColumn: "id" },
{ sourceKey: "a", sourceColumn: "user_id" },
{ sourceKey: "b", sourceColumn: "id" },
{ sourceKey: "b", sourceColumn: "name" },
{ sourceKey: "a", sourceColumn: "id", database: "app", schema: "app", tableName: "orders" },
{ sourceKey: "a", sourceColumn: "user_id", database: "app", schema: "app", tableName: "orders" },
{ sourceKey: "b", sourceColumn: "id", database: "app", schema: "app", tableName: "users" },
{ sourceKey: "b", sourceColumn: "name", database: "app", schema: "app", tableName: "users" },
]);
});
@@ -187,8 +188,8 @@ describe("queryStore multi-source result column comments", () => {
await vi.waitFor(() => expect(tab.resultColumnComments).toBeDefined());
expect(tab.resultColumnComments).toEqual(["订单ID", "用户名"]);
expect(tab.queryDisplaySourceColumns).toEqual([
{ sourceKey: "a", sourceColumn: "id" },
{ sourceKey: "b", sourceColumn: "name" },
{ sourceKey: "a", sourceColumn: "id", database: "app", schema: "app", tableName: "orders" },
{ sourceKey: "b", sourceColumn: "name", database: "app", schema: "app", tableName: "users" },
]);
});
@@ -279,9 +280,9 @@ describe("queryStore multi-source result column comments", () => {
// of the previous map would have collapsed them.
expect(tab.resultColumnComments).toEqual(["订单ID", "大写ID", "大写Name"]);
expect(tab.queryDisplaySourceColumns).toEqual([
{ sourceKey: "a", sourceColumn: "id" },
{ sourceKey: "a", sourceColumn: "ID" },
{ sourceKey: "b", sourceColumn: "Name" },
{ sourceKey: "a", sourceColumn: "id", database: "app", schema: undefined, tableName: "orders" },
{ sourceKey: "a", sourceColumn: "ID", database: "app", schema: undefined, tableName: "orders" },
{ sourceKey: "b", sourceColumn: "Name", database: "app", schema: undefined, tableName: "users" },
]);
});
@@ -326,12 +327,12 @@ describe("queryStore multi-source result column comments", () => {
await vi.waitFor(() => expect(tab.resultColumnComments).toBeDefined());
expect(tab.resultColumnComments).toEqual(["订单ID", "用户ID"]);
expect(tab.queryDisplaySourceColumns).toEqual([
{ sourceKey: "a", sourceColumn: "id" },
{ sourceKey: "b", sourceColumn: "id" },
{ sourceKey: "a", sourceColumn: "id", database: "app", schema: "app", tableName: "orders" },
{ sourceKey: "b", sourceColumn: "id", database: "app", schema: "app", tableName: "users" },
]);
});
it("keeps single-source results free of multi-source comment fields", async () => {
it("stores physical source identities for single-source result columns", async () => {
analyzeEditableQueryEditability.mockResolvedValue({
editable: true,
analysis: {
@@ -363,7 +364,10 @@ describe("queryStore multi-source result column comments", () => {
const tab = store.tabs.find((item) => item.id === tabId)!;
await vi.waitFor(() => expect(tab.tableMeta?.tableName).toBe("orders"));
expect(tab.resultColumnComments).toBeUndefined();
expect(tab.queryDisplaySourceColumns).toBeUndefined();
expect(tab.queryDisplaySourceColumns).toEqual([
{ sourceKey: "orders:0", sourceColumn: "id", database: "app", schema: "app", tableName: "orders" },
{ sourceKey: "orders:0", sourceColumn: "amount", database: "app", schema: "app", tableName: "orders" },
]);
expect(tab.querySourceColumns).toEqual(["id", "amount"]);
});
@@ -102,7 +102,7 @@ describe("queryStore MySQL grouped-result editing", () => {
expect(tab.querySourceColumns).toEqual(["id", "department", undefined]);
expect(tab.tableMeta).toMatchObject({ tableName: "users", primaryKeys: ["id"] });
expect(tab.resultColumnComments).toEqual(["user id", "department", undefined]);
expect(tab.queryDisplaySourceColumns).toEqual([{ sourceKey: "u:0", sourceColumn: "id" }, { sourceKey: "u:0", sourceColumn: "department" }, undefined]);
expect(tab.queryDisplaySourceColumns).toEqual([{ sourceKey: "u:0", sourceColumn: "id", database: "app", schema: "app", tableName: "users" }, { sourceKey: "u:0", sourceColumn: "department", database: "app", schema: "app", tableName: "users" }, undefined]);
expect(listIndexes).not.toHaveBeenCalled();
});
@@ -124,7 +124,12 @@ describe("queryStore MySQL grouped-result editing", () => {
expect(tab.queryEditabilityReason).toBeUndefined();
expect(tab.querySourceColumns).toEqual(["id", "department", undefined, undefined]);
expect(tab.queryDisplaySourceColumns).toEqual([{ sourceKey: "u:0", sourceColumn: "id" }, { sourceKey: "u:0", sourceColumn: "department" }, { sourceKey: "o:1", sourceColumn: "user_id" }, undefined]);
expect(tab.queryDisplaySourceColumns).toEqual([
{ sourceKey: "u:0", sourceColumn: "id", database: "app", schema: "app", tableName: "users" },
{ sourceKey: "u:0", sourceColumn: "department", database: "app", schema: "app", tableName: "users" },
{ sourceKey: "o:1", sourceColumn: "user_id", database: "app", schema: "app", tableName: "orders" },
undefined,
]);
});
it("keeps a non-root source read-only even when its complete primary key is grouped", async () => {
@@ -199,7 +204,14 @@ describe("queryStore MySQL grouped-result editing", () => {
expect(tab.queryEditabilityReason).toBeUndefined();
expect(tab.querySourceColumns).toEqual(["id", "department", undefined, undefined, undefined, undefined]);
expect(tab.queryDisplaySourceColumns).toEqual([{ sourceKey: "u:0", sourceColumn: "id" }, { sourceKey: "u:0", sourceColumn: "department" }, { sourceKey: "u:0", sourceColumn: "display_label" }, { sourceKey: "u:0", sourceColumn: "stored_label" }, undefined, undefined]);
expect(tab.queryDisplaySourceColumns).toEqual([
{ sourceKey: "u:0", sourceColumn: "id", database: "app", schema: "app", tableName: "users" },
{ sourceKey: "u:0", sourceColumn: "department", database: "app", schema: "app", tableName: "users" },
{ sourceKey: "u:0", sourceColumn: "display_label", database: "app", schema: "app", tableName: "users" },
{ sourceKey: "u:0", sourceColumn: "stored_label", database: "app", schema: "app", tableName: "users" },
undefined,
undefined,
]);
});
it("accepts a complete composite primary key only when it is the exact grouping key", async () => {
+13 -4
View File
@@ -3844,7 +3844,12 @@ export const useQueryStore = defineStore("query", () => {
const loaded = loadedSources.find((entry) => entry.source.key === ref.sourceKey);
const comment = loaded?.tableMeta.columns.find((column) => column.name === ref.sourceColumn)?.comment?.trim();
comments.push(comment || undefined);
mapping.push(ref);
mapping.push({
...ref,
database: loaded?.tableMeta.database,
schema: loaded?.tableMeta.schema,
tableName: loaded?.tableMeta.tableName,
});
}
return { comments, mapping };
}
@@ -4335,7 +4340,7 @@ export const useQueryStore = defineStore("query", () => {
const metadataAnalysis = expandStarProjectionColumnsForSource(bindColumnsForSource(dbType, loaded.analysis, loaded.source, loaded.tableMeta.columns, allSourceColumns), loaded.source, loaded.tableMeta.columns);
const syntheticRowIdProjection = hiddenPrimaryKeys.find((projection) => projection.sourceName.toUpperCase() === DBX_ROWID_COLUMN);
const primaryKeys = loaded.tableMeta.primaryKeys.length === 0 && syntheticRowIdProjection ? [DBX_ROWID_COLUMN] : loaded.tableMeta.primaryKeys;
const keylessResultInfo = primaryKeys.length === 0 ? resolveResultColumnInfo(dbType, analysis, tab.result.columns, loadedSources) : undefined;
const displaySourceInfo = resolveResultColumnInfo(dbType, analysis, tab.result.columns, loadedSources);
const sourceColumns = sourceColumnsForResult(metadataAnalysis, tab.result.columns, loaded.source.key);
if (sourceColumns && syntheticRowIdProjection) {
const resultIndex = tab.result.columns.findIndex((column) => column.toLowerCase() === syntheticRowIdProjection.alias.toLowerCase());
@@ -4347,7 +4352,8 @@ export const useQueryStore = defineStore("query", () => {
querySourceColumns: undefined,
queryEditabilityReason: "no-primary-key",
tableMeta: loaded.tableMeta,
resultColumnComments: keylessResultInfo?.comments,
resultColumnComments: displaySourceInfo.comments,
queryDisplaySourceColumns: displaySourceInfo.mapping,
};
}
@@ -4358,6 +4364,7 @@ export const useQueryStore = defineStore("query", () => {
querySourceColumns: undefined,
queryEditabilityReason: "primary-key-not-returned",
tableMeta: loaded.tableMeta,
queryDisplaySourceColumns: displaySourceInfo.mapping,
};
}
@@ -4367,6 +4374,7 @@ export const useQueryStore = defineStore("query", () => {
querySourceColumns: undefined,
queryEditabilityReason: "aliased-columns",
tableMeta: loaded.tableMeta,
queryDisplaySourceColumns: displaySourceInfo.mapping,
};
}
@@ -4375,7 +4383,8 @@ export const useQueryStore = defineStore("query", () => {
querySourceColumns: sourceColumns,
queryEditabilityReason: undefined,
tableMeta: primaryKeys === loaded.tableMeta.primaryKeys ? loaded.tableMeta : { ...loaded.tableMeta, primaryKeys },
resultColumnComments: keylessResultInfo?.comments,
resultColumnComments: primaryKeys.length === 0 ? displaySourceInfo.comments : undefined,
queryDisplaySourceColumns: displaySourceInfo.mapping,
};
}