diff --git a/apps/desktop/src/lib/__tests__/sql/sqlSelectionCase.spec.ts b/apps/desktop/src/lib/__tests__/sql/sqlSelectionCase.spec.ts index 3b27863176..f692bfd2bc 100644 --- a/apps/desktop/src/lib/__tests__/sql/sqlSelectionCase.spec.ts +++ b/apps/desktop/src/lib/__tests__/sql/sqlSelectionCase.spec.ts @@ -14,11 +14,18 @@ describe("convertSqlSelectionCase", () => { expect(convertSqlSelectionCase(sql, { from: 0, to: sql.length }, "upper")).toBe("SELECT CODE FROM ORDERS WHERE CODE = 'abc001'"); }); - it("preserves the selected fragment when the selection is inside a string literal", () => { + it("converts a selection that is fully contained inside a string literal", () => { const sql = "select * from orders where code = 'AbC001'"; const from = sql.indexOf("bC"); - expect(convertSqlSelectionCase(sql, { from, to: from + 2 }, "lower")).toBe("bC"); + expect(convertSqlSelectionCase(sql, { from, to: from + 2 }, "lower")).toBe("bc"); + }); + + it("still protects a string literal when the selection extends beyond it", () => { + const sql = "select code from orders where code = 'abc001'"; + const from = sql.indexOf("code ="); + + expect(convertSqlSelectionCase(sql, { from, to: sql.length }, "upper")).toBe("CODE = 'abc001'"); }); it("preserves PostgreSQL dollar-quoted string literals", () => { diff --git a/apps/desktop/src/lib/sql/sqlSelectionCase.ts b/apps/desktop/src/lib/sql/sqlSelectionCase.ts index b910be0b44..195be1034a 100644 --- a/apps/desktop/src/lib/sql/sqlSelectionCase.ts +++ b/apps/desktop/src/lib/sql/sqlSelectionCase.ts @@ -23,6 +23,14 @@ export function convertSqlSelectionCase(sql: string, range: SqlSelectionRange, m }); if (protectedTokens.length === 0) return convertCase(sql.slice(from, to), mode); + // A selection fully contained inside one protected token (e.g. the user selected only + // text inside a string literal) carries no risk of collateral damage to surrounding SQL, + // so honor the explicit request instead of silently no-oping it. + const [only] = protectedTokens; + if (protectedTokens.length === 1 && only.span.start <= from && to <= only.span.end) { + return convertCase(sql.slice(from, to), mode); + } + let converted = ""; let cursor = from; for (const item of protectedTokens) {