feat(query): 新建查询继承当前表上下文

This commit is contained in:
kunghim
2026-08-07 16:45:31 +08:00
parent c3d3f89561
commit e1bc2839c5
3 changed files with 80 additions and 2 deletions

View File

@@ -102,6 +102,8 @@ import {
import { downloadBrowserTextFile } from './utils/browserFileTransfer';
import { buildDataSyncWorkbenchTab } from './utils/dataSyncTab';
import { buildSqlAuditWorkbenchTab } from './utils/sqlAuditTab';
import { resolveDataSourceType } from './utils/dataSourceCapabilities';
import { buildContextualNewQueryTemplate } from './utils/objectQueryTemplates';
import {
extractCustomThemeAntTokens,
} from './utils/customTheme';
@@ -2723,6 +2725,7 @@ function App() {
const handleNewQuery = useCallback(() => {
let connId = '';
let db = '';
let tableName = '';
// Priority: Active Tab Context (if connection still valid) > Sidebar Selection (activeContext)
if (activeTabId) {
@@ -2730,6 +2733,9 @@ function App() {
if (currentTab && currentTab.connectionId && connections.some(c => c.id === currentTab.connectionId)) {
connId = currentTab.connectionId;
db = currentTab.dbName || '';
if (currentTab.type === 'table' || currentTab.type === 'design') {
tableName = String(currentTab.tableName || '').trim();
}
}
}
@@ -2739,15 +2745,24 @@ function App() {
db = activeContext.dbName || '';
}
const connection = connections.find(c => c.id === connId);
const contextualQuery = tableName && connection
? buildContextualNewQueryTemplate({
dbType: resolveDataSourceType(connection.config),
tableName,
customTemplate: appearance.newQuerySqlTemplate,
})
: null;
addTab({
id: `query-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
title: t('query.new'),
type: 'query',
connectionId: connId,
dbName: db,
query: ''
query: contextualQuery ?? ''
});
}, [activeTabId, tabs, connections, activeContext, addTab, t]);
}, [activeTabId, tabs, connections, activeContext, addTab, appearance.newQuerySqlTemplate, t]);
const switchActiveTabByOffset = useCallback((offset: 1 | -1) => {
if (tabs.length < 2) return;

View File

@@ -9,12 +9,47 @@ vi.mock('../../wailsjs/go/app/App', () => ({
}));
import {
buildContextualNewQueryTemplate,
buildTableSelectQuery,
extractTableSelectColumnNames,
isElasticsearchDbType,
resolveTableSelectQuery,
} from './objectQueryTemplates';
describe('buildContextualNewQueryTemplate', () => {
it('builds a dialect-aware select for the active table with the default template', () => {
expect(buildContextualNewQueryTemplate({
dbType: 'mysql',
tableName: 'Order Items',
customTemplate: null,
})).toBe('SELECT * FROM `Order Items`;');
});
it('appends the active table when a custom template ends with FROM', () => {
expect(buildContextualNewQueryTemplate({
dbType: 'postgres',
tableName: 'public.OrderItems',
customTemplate: 'SELECT id, total FROM ',
})).toBe('SELECT id, total FROM public."OrderItems"');
});
it('preserves custom templates that do not expose a table insertion point', () => {
expect(buildContextualNewQueryTemplate({
dbType: 'mysql',
tableName: 'users',
customTemplate: 'SELECT CURRENT_TIMESTAMP;',
})).toBeNull();
});
it('builds the native query format for an active Elasticsearch index', () => {
expect(buildContextualNewQueryTemplate({
dbType: 'elasticsearch',
tableName: 'orders-v1',
customTemplate: null,
})).toBe('GET /orders-v1/_search\n{\n "query": {\n "match_all": {}\n }\n}\n');
});
});
describe('buildTableSelectQuery', () => {
it('quotes uppercase postgres table names in new query templates', () => {
expect(buildTableSelectQuery('postgres', 'public.MyTable')).toBe('SELECT * FROM public."MyTable";');

View File

@@ -59,6 +59,34 @@ export const buildTableSelectQuery = (
return `SELECT\n ${selectList}\nFROM ${quotedTable}${limitSuffix};`;
};
type BuildContextualNewQueryTemplateOptions = {
dbType: string;
tableName: string;
customTemplate?: string | null;
};
/**
* Build the initial query for a new tab opened while a table-like data tab is active.
* A custom template is only augmented when it explicitly ends at a FROM insertion point.
*/
export const buildContextualNewQueryTemplate = ({
dbType,
tableName,
customTemplate,
}: BuildContextualNewQueryTemplateOptions): string | null => {
const normalizedTableName = String(tableName || '').trim();
if (!normalizedTableName) return null;
if (isElasticsearchDbType(dbType) || customTemplate === null || customTemplate === undefined) {
return buildTableSelectQuery(dbType, normalizedTableName);
}
const template = String(customTemplate)
.replace(/\r\n/g, '\n')
.replace(/\r/g, '\n');
if (!/\bfrom\s*$/i.test(template)) return null;
return `${template}${quoteQualifiedIdent(dbType, normalizedTableName)}`;
};
type ResolveTableSelectQueryOptions = {
dbType: string;
tableName: string;