From 77c542248d27ae6d5ae696a0b20631e26340318a Mon Sep 17 00:00:00 2001 From: Hand Sonic <8078023+HandSonic@users.noreply.github.com> Date: Tue, 29 Sep 2026 11:29:53 +0800 Subject: [PATCH] fix(neo4j): preserve cypher labels during query execution --- agents/drivers/neo4j-go/main_test.go | 15 ++++++++++- agents/drivers/neo4j-go/protocol_error.go | 5 +++- .../editor/EditorSettingsDialog.vue | 24 +++++++++++++++--- .../__tests__/useSqlExecution.spec.ts | 24 ++++++++++++++++++ .../lib/__tests__/sql/sqlParameters.spec.ts | 10 ++++++++ .../__tests__/sql/sqlVariableSyntax.spec.ts | 7 +++++ apps/desktop/src/lib/sql/sqlParameters.ts | 2 +- apps/desktop/src/lib/sql/sqlVariableSyntax.ts | 8 +++--- .../screenshots/neo4j-parameter-settings.png | Bin 0 -> 32947 bytes 9 files changed, 84 insertions(+), 11 deletions(-) create mode 100644 docs/public/screenshots/neo4j-parameter-settings.png diff --git a/agents/drivers/neo4j-go/main_test.go b/agents/drivers/neo4j-go/main_test.go index cc8a25a0a9..c612cb8ca9 100644 --- a/agents/drivers/neo4j-go/main_test.go +++ b/agents/drivers/neo4j-go/main_test.go @@ -6,6 +6,7 @@ import ( "errors" "net/url" "reflect" + "strings" "testing" neo4j "github.com/neo4j/neo4j-go-driver/v6/neo4j" @@ -230,9 +231,21 @@ func TestClassifyNeo4jErrors(t *testing.T) { syntax := classifyRPCError("execute_query", "session-1", &neo4jdb.Neo4jError{ Code: "Neo.ClientError.Statement.SyntaxError", Msg: "invalid input", }) - if syntax.Data.Category != "sql" || syntax.Data.SQLState == "" { + if syntax.Data.Category != "sql" || syntax.Data.SQLState != "" || syntax.Data.AgentSessionID != "session-1" { t.Fatalf("unexpected syntax classification: %#v", syntax) } + if syntax.Data.ContractVersion != 1 || syntax.Data.Stage != "execute" || syntax.Data.OperationOutcome != "unknown" { + t.Fatalf("invalid structured error contract: %#v", syntax.Data) + } + if syntax.Message == "" || !strings.Contains(syntax.Message, "Neo.ClientError.Statement.SyntaxError") { + t.Fatalf("Neo4j error code was lost: %q", syntax.Message) + } + resource := classifyRPCError("execute_query", "session-1", &neo4jdb.Neo4jError{ + Code: "Neo.TransientError.General.DatabaseUnavailable", Msg: "database unavailable", + }) + if resource.Data.Category != "resource" || resource.Data.SessionDisposition != "replace_runtime" { + t.Fatalf("invalid resource error contract: %#v", resource.Data) + } canceled := classifyRPCError("execute_query", "session-1", context.Canceled) if canceled.Data.Category != "canceled" || canceled.Data.SessionDisposition != "quarantine" { t.Fatalf("unexpected cancellation classification: %#v", canceled) diff --git a/agents/drivers/neo4j-go/protocol_error.go b/agents/drivers/neo4j-go/protocol_error.go index dfee3641ae..181cd0e269 100644 --- a/agents/drivers/neo4j-go/protocol_error.go +++ b/agents/drivers/neo4j-go/protocol_error.go @@ -50,7 +50,7 @@ func classifyRPCError(method, agentSessionID string, err error) *rpcError { var databaseError *neo4jdb.Neo4jError if errors.As(err, &databaseError) { - data.SQLState = safeRPCDiagnostic(databaseError.Code, 160) + // Neo4j error codes are not SQLSTATE values; the code remains in err.Error(). data.Retryable = neo4j.IsRetryable(err) code := strings.ToLower(databaseError.Code) switch { @@ -60,6 +60,9 @@ func classifyRPCError(method, agentSessionID string, err error) *rpcError { case strings.Contains(code, ".transienterror."), strings.Contains(code, "databaseunavailable"): data.Category = "resource" data.Retryable = true + if data.OperationOutcome == "unknown" { + data.SessionDisposition = "replace_runtime" + } case strings.Contains(code, ".statement."), strings.Contains(code, ".schema."), strings.Contains(code, ".procedure."): data.Category = "sql" default: diff --git a/apps/desktop/src/components/editor/EditorSettingsDialog.vue b/apps/desktop/src/components/editor/EditorSettingsDialog.vue index b4b16d2ad5..e1fc0e6f50 100644 --- a/apps/desktop/src/components/editor/EditorSettingsDialog.vue +++ b/apps/desktop/src/components/editor/EditorSettingsDialog.vue @@ -206,7 +206,16 @@ import { validateConfigName, generateId, type AiConfigItem, type ConfigNameValid import { currentExecutableStatementRange, type SqlTextRange } from "@/lib/sql/sqlStatementRanges"; import { executableStatementRangeCacheForDoc, executableStatementRangeStartingAt, type ExecutableStatementRangeCache } from "@/lib/sql/executableStatementRangeCache"; import { EMPTY_TABLE_COLUMN_TEMPLATE_DATA_TYPE, parseTableColumnTemplateFields, TABLE_COLUMN_TEMPLATE_DATABASE_TYPES, tableColumnTemplateRowsToSettings } from "@/lib/table/tableColumnTemplates"; -import { DEFAULT_SQL_VARIABLE_SYNTAX_TOGGLES, normalizeSqlVariableSyntaxOverrides, SQL_VARIABLE_SYNTAX_DATABASE_TYPES, SQL_VARIABLE_SYNTAX_KEYS, SQL_VARIABLE_SYNTAX_TOKENS, type SqlVariableSyntaxOverrides, type SqlVariableSyntaxToggles } from "@/lib/sql/sqlVariableSyntax"; +import { + DEFAULT_SQL_VARIABLE_SYNTAX_TOGGLES, + normalizeSqlVariableSyntaxOverrides, + resolveSqlVariableSyntaxToggles, + SQL_VARIABLE_SYNTAX_DATABASE_TYPES, + SQL_VARIABLE_SYNTAX_KEYS, + SQL_VARIABLE_SYNTAX_TOKENS, + type SqlVariableSyntaxOverrides, + type SqlVariableSyntaxToggles, +} from "@/lib/sql/sqlVariableSyntax"; import { buildMcpCherryStudioConfig, buildMcpCodexConfig, @@ -772,11 +781,12 @@ function updateExternalSqlEditorMaxMbInput(event: Event) { } function sqlVariableSyntaxToggle(key: keyof SqlVariableSyntaxToggles): boolean { - return editSqlVariableSyntaxOverrides.value[editSqlVariableSyntaxDatabaseType.value]?.[key] ?? true; + return resolveSqlVariableSyntaxToggles(editSqlVariableSyntaxOverrides.value, editSqlVariableSyntaxDatabaseType.value)[key]; } function setSqlVariableSyntaxToggle(key: keyof SqlVariableSyntaxToggles, value: boolean) { const dbType = editSqlVariableSyntaxDatabaseType.value; + if (dbType === "neo4j" && key === "named") return; const merged: SqlVariableSyntaxToggles = { ...DEFAULT_SQL_VARIABLE_SYNTAX_TOGGLES, ...editSqlVariableSyntaxOverrides.value[dbType], @@ -6798,7 +6808,7 @@ onUnmounted(() => {
{{ t("settings.sqlVariableSyntax") }}
-

+

{{ t("settings.sqlVariableSyntaxDescription") }}

@@ -6832,7 +6842,13 @@ onUnmounted(() => { {{ t(`settings.sqlVariableSyntax_${key}Description`) }}

- + diff --git a/apps/desktop/src/composables/__tests__/useSqlExecution.spec.ts b/apps/desktop/src/composables/__tests__/useSqlExecution.spec.ts index 58545a9944..5fad8d1b43 100644 --- a/apps/desktop/src/composables/__tests__/useSqlExecution.spec.ts +++ b/apps/desktop/src/composables/__tests__/useSqlExecution.spec.ts @@ -140,6 +140,30 @@ describe("useSqlExecution", () => { vi.mocked(objectMetadataCache.invalidateObjectMetadataCache).mockClear(); }); + it("executes Neo4j graph patterns without a SQL parameter dialog", async () => { + const sql = 'MATCH (p:Person)-[:WORK_IN]->(c:Company{name:"星云科技"})\nRETURN p.name, p.job, c.name'; + const activeTab = ref({ ...queryTab("neo4j"), sql }); + const activeConnection = ref(connection("neo4j")); + const activeOutputView = ref<"result" | "summary" | "explain" | "chart">("result"); + const queryStore = useQueryStore(); + const executeCurrentSql = vi.spyOn(queryStore, "executeCurrentSql").mockImplementation(async () => { + if (activeTab.value) activeTab.value.result = { columns: ["p.name"], rows: [["Ada"]], affected_rows: 0, execution_time_ms: 1 }; + }); + 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(execution.showSqlParameterDialog.value).toBe(false); + expect(executeCurrentSql).toHaveBeenCalledWith(sql, { tabId: "tab-1" }); + }); + it("invalidates object metadata after successful connection-level DDL", async () => { const sql = "CREATE DATABASE app_db"; const activeTab = ref({ ...queryTab(), sql }); diff --git a/apps/desktop/src/lib/__tests__/sql/sqlParameters.spec.ts b/apps/desktop/src/lib/__tests__/sql/sqlParameters.spec.ts index 914eee67cc..666932ceaa 100644 --- a/apps/desktop/src/lib/__tests__/sql/sqlParameters.spec.ts +++ b/apps/desktop/src/lib/__tests__/sql/sqlParameters.spec.ts @@ -34,6 +34,16 @@ describe("extractSqlParameters", () => { { key: "params", name: "params", syntax: "named", token: ":params" }, { key: "context", name: "context", syntax: "sqlserver", token: "@context" }, ]); + expect(extractSqlParameters("select :customer_id", { databaseType: "mysql" })).toEqual(["customer_id"]); + }); + + it("preserves Neo4j pattern labels and relationship types", () => { + const cypher = 'MATCH (p:Person)-[:WORK_IN]->(c:Company{name:"星云科技"})\nRETURN p.name, p.job, c.name'; + const options = { databaseType: "neo4j" as const }; + expect(extractSqlParameterDescriptors(cypher, options)).toEqual([]); + expect(substituteSqlParameters(cypher, {}, options)).toBe(cypher); + expect(extractSqlParameterDescriptors(cypher, { ...options, enabledSyntaxes: ["named"] as const })).toEqual([]); + expect(extractSqlParameters("MATCH (p:Person {name:${name}}) RETURN p", options)).toEqual(["name"]); }); it("extracts unique template parameters in order", () => { diff --git a/apps/desktop/src/lib/__tests__/sql/sqlVariableSyntax.spec.ts b/apps/desktop/src/lib/__tests__/sql/sqlVariableSyntax.spec.ts index 03ce6c92cb..c0944c726d 100644 --- a/apps/desktop/src/lib/__tests__/sql/sqlVariableSyntax.spec.ts +++ b/apps/desktop/src/lib/__tests__/sql/sqlVariableSyntax.spec.ts @@ -12,6 +12,13 @@ describe("resolveSqlVariableSyntaxToggles", () => { expect(resolveSqlVariableSyntaxToggles({ mysql: { shell: false } }, "postgres")).toEqual(DEFAULT_SQL_VARIABLE_SYNTAX_TOGGLES); }); + it("disables SQL-style named parameters for Neo4j patterns", () => { + const toggles = resolveSqlVariableSyntaxToggles(undefined, "neo4j"); + expect(toggles).toEqual({ ...DEFAULT_SQL_VARIABLE_SYNTAX_TOGGLES, named: false }); + expect(enabledSqlParameterSyntaxes(toggles)).not.toContain("named"); + expect(resolveSqlVariableSyntaxToggles({ neo4j: { shell: false } }, "neo4j")).toEqual({ ...toggles, shell: false }); + }); + it("enables every syntax when the database type is unknown", () => { expect(resolveSqlVariableSyntaxToggles({ mysql: { shell: false } }, undefined)).toEqual(DEFAULT_SQL_VARIABLE_SYNTAX_TOGGLES); }); diff --git a/apps/desktop/src/lib/sql/sqlParameters.ts b/apps/desktop/src/lib/sql/sqlParameters.ts index 6bb2fc4dd8..b2d19da228 100644 --- a/apps/desktop/src/lib/sql/sqlParameters.ts +++ b/apps/desktop/src/lib/sql/sqlParameters.ts @@ -378,7 +378,7 @@ function findSqlParameterOccurrences(sql: string, options?: SqlParameterOptions) const occurrences: ParameterOccurrence[] = []; const databaseType = options?.databaseType; const nativeSqlServerParameters = collectNativeSqlServerParameters(sql, databaseType); - const supportsNamedParameters = databaseType !== "saphana"; + const supportsNamedParameters = databaseType !== "saphana" && databaseType !== "neo4j"; const enabledSyntaxes = options?.enabledSyntaxes ? new Set(options.enabledSyntaxes) : null; const isSyntaxEnabled = (syntax: SqlParameterSyntax) => !enabledSyntaxes || enabledSyntaxes.has(syntax); const complexTypeFieldSeparators = supportsNamedParameters && isSyntaxEnabled("named") ? collectComplexTypeFieldSeparators(sql, databaseType) : new Set(); diff --git a/apps/desktop/src/lib/sql/sqlVariableSyntax.ts b/apps/desktop/src/lib/sql/sqlVariableSyntax.ts index 4761aa6d9e..8d7b0bf852 100644 --- a/apps/desktop/src/lib/sql/sqlVariableSyntax.ts +++ b/apps/desktop/src/lib/sql/sqlVariableSyntax.ts @@ -3,11 +3,11 @@ // DBX runs two client-side substitution systems before sending SQL to a backend: // the placeholder parameter dialog (`sqlParameters.ts`, five syntaxes) and the // `@set name = value;` expansion (`sqlVariables.ts`). This module lets users opt -// out of individual syntaxes per database type. Every toggle defaults to `true`, -// so an empty/absent config reproduces the historical "always substitute" behaviour. +// out of individual syntaxes per database type. SQL syntaxes default to `true`, +// except Neo4j's `:label` patterns, which are not named parameters. // // Storage is sparse: only syntaxes explicitly turned off (`false`) are persisted, -// keyed by database type. Anything not stored resolves to enabled. +// keyed by database type. Unset values use the database-specific defaults. import type { DatabaseType } from "@/types/database"; import type { SqlParameterSyntax } from "@/lib/sql/sqlParameters"; @@ -72,7 +72,7 @@ export function resolveSqlVariableSyntaxToggles(overrides: SqlVariableSyntaxOver const partial = dbType ? overrides?.[dbType] : undefined; return { positional: partial?.positional ?? true, - named: partial?.named ?? true, + named: dbType === "neo4j" ? false : (partial?.named ?? true), shell: partial?.shell ?? true, mybatis: partial?.mybatis ?? true, sqlserver: partial?.sqlserver ?? true, diff --git a/docs/public/screenshots/neo4j-parameter-settings.png b/docs/public/screenshots/neo4j-parameter-settings.png new file mode 100644 index 0000000000000000000000000000000000000000..32ba9701fc5b59563f60ca550112147c77abf71b GIT binary patch literal 32947 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 KB2_{L0sjv