From 01b666216a08ff3e78160972591213b029ca2199 Mon Sep 17 00:00:00 2001 From: Syngnat Date: Tue, 28 Jul 2026 19:40:45 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20fix(sql-editor):=20=E4=BF=9D?= =?UTF-8?q?=E7=95=99=20PostgreSQL=20JSONB=20=E9=97=AE=E5=8F=B7=E8=BF=90?= =?UTF-8?q?=E7=AE=97=E7=AC=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 仅对 OceanBase Oracle 启用问号位置占位符,避免格式化 PostgreSQL JSONB ?| 与 ?& 运算符时插入空格。 Refs #762 --- .../QueryEditor.external-sql-save.test.tsx | 34 +++++++++++++++++++ frontend/src/components/QueryEditor.tsx | 6 ++-- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/QueryEditor.external-sql-save.test.tsx b/frontend/src/components/QueryEditor.external-sql-save.test.tsx index 7fd745b2..23f8a43a 100644 --- a/frontend/src/components/QueryEditor.external-sql-save.test.tsx +++ b/frontend/src/components/QueryEditor.external-sql-save.test.tsx @@ -4590,6 +4590,40 @@ describe('QueryEditor external SQL save', () => { ); }); + it('preserves postgres JSONB question-mark operators while formatting', async () => { + let renderer!: ReactTestRenderer; + storeState.connections[0].config.type = 'postgres'; + storeState.connections[0].config.database = 'main'; + const pgSql = "select * from items where data ?| array['a','b'] and data ?& array['c']"; + + await act(async () => { + renderer = create(); + }); + + const formatButton = findButton(renderer, '美化'); + await act(async () => { + await formatButton.props.onClick(); + }); + + expect(messageApi.error).not.toHaveBeenCalled(); + expect(editorState.editor.executeEdits).toHaveBeenCalledWith( + 'gonavi-format-sql', + expect.arrayContaining([ + expect.objectContaining({ + text: expect.stringContaining("data ?| ARRAY['a', 'b']"), + }), + ]), + ); + expect(editorState.editor.executeEdits).toHaveBeenCalledWith( + 'gonavi-format-sql', + expect.arrayContaining([ + expect.objectContaining({ + text: expect.stringContaining("data ?& ARRAY['c']"), + }), + ]), + ); + }); + it('formats postgres window-function SQL with cast syntax through Monaco edits', async () => { let renderer!: ReactTestRenderer; storeState.connections[0].config.type = 'postgres'; diff --git a/frontend/src/components/QueryEditor.tsx b/frontend/src/components/QueryEditor.tsx index d7806573..305cf6ea 100644 --- a/frontend/src/components/QueryEditor.tsx +++ b/frontend/src/components/QueryEditor.tsx @@ -222,7 +222,6 @@ const QUERY_EDITOR_AI_INLINE_DEBOUNCE_MS = 220; const QUERY_EDITOR_AI_INLINE_CONTEXT_KEY = 'gonaviAiInlineSuggestionVisible'; const QUERY_EDITOR_IME_FALLBACK_DELAY_MS = 80; const QUERY_EDITOR_FORMAT_PARAM_TYPES = { - positional: true, custom: [ { regex: String.raw`#\{[^{}]+\}` }, { regex: String.raw`\$\{[^{}]+\}` }, @@ -6192,7 +6191,10 @@ const QueryEditor: React.FC<{ tab: TabData; isActive?: boolean }> = ({ tab, isAc const formatted = format(sourceSql, { language: formatterLanguage, keywordCase: sqlFormatOptions.keywordCase, - paramTypes: QUERY_EDITOR_FORMAT_PARAM_TYPES, + paramTypes: { + ...QUERY_EDITOR_FORMAT_PARAM_TYPES, + ...(isOceanBaseOracleConnection(conn?.config) ? { positional: true } : {}), + }, }); if (sourceSql === formatted) { return;