From e32c9b1ce250661f28bab02a40abb91e2e68cf3d Mon Sep 17 00:00:00 2001 From: Dan Lynch Date: Thu, 25 Dec 2025 13:27:52 +0000 Subject: [PATCH] demo: add test fixtures showing type-name quoting bug (DO NOT MERGE) This PR demonstrates the bug where user-defined schema-qualified types with keyword names are over-quoted. The snapshots show: - myschema."json" (should be myschema.json) - custom."int" (should be custom.int) - myapp."boolean" (should be myapp.boolean) See PR #248 for the fix. --- __fixtures__/generated/generated.json | 9 ++++ __fixtures__/kitchen-sink/pretty/quoting.sql | 34 +++++++++++++++ .../__snapshots__/quoting-pretty.test.ts.snap | 41 +++++++++++++++++++ .../__tests__/pretty/quoting-pretty.test.ts | 9 ++++ 4 files changed, 93 insertions(+) diff --git a/__fixtures__/generated/generated.json b/__fixtures__/generated/generated.json index a2a04ff9..22d5b189 100644 --- a/__fixtures__/generated/generated.json +++ b/__fixtures__/generated/generated.json @@ -60,6 +60,15 @@ "pretty/quoting-5.sql": "CREATE FUNCTION faker.boolean() RETURNS boolean AS $EOFCODE$\nBEGIN\n RETURN random() < 0.5;\nEND;\n$EOFCODE$ LANGUAGE plpgsql", "pretty/quoting-6.sql": "CREATE FUNCTION faker.\"boolean\"() RETURNS boolean AS $EOFCODE$\nBEGIN\n RETURN random() < 0.5;\nEND;\n$EOFCODE$ LANGUAGE plpgsql", "pretty/quoting-7.sql": "CREATE DOMAIN origin AS text CHECK (value = pg_catalog.\"substring\"(value, '^(https?://[^/]*)'))", + "pretty/quoting-8.sql": "SELECT '{\"a\":1}'::json", + "pretty/quoting-9.sql": "SELECT '{\"b\":2}'::jsonb", + "pretty/quoting-10.sql": "SELECT true::boolean", + "pretty/quoting-11.sql": "SELECT '1 day'::interval", + "pretty/quoting-12.sql": "SELECT 42::int", + "pretty/quoting-13.sql": "INSERT INTO test_table (data) VALUES ('{\"c\":3}'::json)", + "pretty/quoting-14.sql": "SELECT '{\"d\":4}'::myschema.json", + "pretty/quoting-15.sql": "SELECT 100::custom.int", + "pretty/quoting-16.sql": "SELECT true::myapp.boolean", "pretty/procedures-1.sql": "SELECT handle_insert('TYPE_A')", "pretty/procedures-2.sql": "SELECT \"HandleInsert\"('TYPE_A', 'Region-1')", "pretty/procedures-3.sql": "SELECT compute_score(42, TRUE)", diff --git a/__fixtures__/kitchen-sink/pretty/quoting.sql b/__fixtures__/kitchen-sink/pretty/quoting.sql index 869e5fb7..f9681610 100644 --- a/__fixtures__/kitchen-sink/pretty/quoting.sql +++ b/__fixtures__/kitchen-sink/pretty/quoting.sql @@ -45,3 +45,37 @@ $EOFCODE$ LANGUAGE plpgsql; -- Note: SUBSTRING(value FROM 'pattern') SQL syntax gets deparsed to pg_catalog."substring"(value, 'pattern') -- The SQL syntax form cannot be tested here due to AST round-trip differences (COERCE_SQL_SYNTAX vs COERCE_EXPLICIT_CALL) CREATE DOMAIN origin AS text CHECK (value = pg_catalog."substring"(value, '^(https?://[^/]*)')); + +-- 8-16: Type name quoting test cases +-- These demonstrate the BUG where user-defined schema-qualified types with keyword names +-- are over-quoted (e.g., myschema."json" instead of myschema.json) + +-- 8. Type name quoting: json type should NOT be quoted (COL_NAME_KEYWORD in type position) +SELECT '{"a":1}'::json; + +-- 9. Type name quoting: jsonb type should NOT be quoted +SELECT '{"b":2}'::jsonb; + +-- 10. Type name quoting: boolean type should NOT be quoted (TYPE_FUNC_NAME_KEYWORD in type position) +SELECT true::boolean; + +-- 11. Type name quoting: interval type should NOT be quoted (TYPE_FUNC_NAME_KEYWORD in type position) +SELECT '1 day'::interval; + +-- 12. Type name quoting: int type should NOT be quoted (COL_NAME_KEYWORD in type position) +SELECT 42::int; + +-- 13. Type cast in INSERT VALUES - json type should NOT be quoted +INSERT INTO test_table (data) VALUES ('{"c":3}'::json); + +-- 14. User-defined schema-qualified type with keyword name - BUG: currently quotes the type name +-- Expected: myschema.json, Actual (buggy): myschema."json" +SELECT '{"d":4}'::myschema.json; + +-- 15. User-defined schema-qualified type with keyword name 'int' - BUG: currently quotes +-- Expected: custom.int, Actual (buggy): custom."int" +SELECT 100::custom.int; + +-- 16. User-defined schema-qualified type with keyword name 'boolean' - BUG: currently quotes +-- Expected: myapp.boolean, Actual (buggy): myapp."boolean" +SELECT true::myapp.boolean; diff --git a/packages/deparser/__tests__/pretty/__snapshots__/quoting-pretty.test.ts.snap b/packages/deparser/__tests__/pretty/__snapshots__/quoting-pretty.test.ts.snap index 5eee750a..f20472ef 100644 --- a/packages/deparser/__tests__/pretty/__snapshots__/quoting-pretty.test.ts.snap +++ b/packages/deparser/__tests__/pretty/__snapshots__/quoting-pretty.test.ts.snap @@ -50,6 +50,24 @@ $$ LANGUAGE plpgsql" exports[`non-pretty: pretty/quoting-7.sql 1`] = `"CREATE DOMAIN origin AS text CHECK (value = pg_catalog.substring(value, '^(https?://[^/]*)'))"`; +exports[`non-pretty: pretty/quoting-8.sql 1`] = `"SELECT '{"a":1}'::json"`; + +exports[`non-pretty: pretty/quoting-9.sql 1`] = `"SELECT '{"b":2}'::jsonb"`; + +exports[`non-pretty: pretty/quoting-10.sql 1`] = `"SELECT CAST(true AS boolean)"`; + +exports[`non-pretty: pretty/quoting-11.sql 1`] = `"SELECT '1 day'::interval"`; + +exports[`non-pretty: pretty/quoting-12.sql 1`] = `"SELECT 42::int"`; + +exports[`non-pretty: pretty/quoting-13.sql 1`] = `"INSERT INTO test_table (data) VALUES ('{"c":3}'::json)"`; + +exports[`non-pretty: pretty/quoting-14.sql 1`] = `"SELECT CAST('{"d":4}' AS myschema."json")"`; + +exports[`non-pretty: pretty/quoting-15.sql 1`] = `"SELECT CAST(100 AS custom."int")"`; + +exports[`non-pretty: pretty/quoting-16.sql 1`] = `"SELECT CAST(true AS myapp."boolean")"`; + exports[`pretty: pretty/quoting-1.sql 1`] = ` "CREATE FUNCTION faker.float(min double precision DEFAULT 0, max double precision DEFAULT 100) RETURNS double precision AS $$ BEGIN @@ -102,3 +120,26 @@ exports[`pretty: pretty/quoting-7.sql 1`] = ` "CREATE DOMAIN origin AS text CHECK (value = pg_catalog.substring(value, '^(https?://[^/]*)'))" `; + +exports[`pretty: pretty/quoting-8.sql 1`] = `"SELECT '{"a":1}'::json"`; + +exports[`pretty: pretty/quoting-9.sql 1`] = `"SELECT '{"b":2}'::jsonb"`; + +exports[`pretty: pretty/quoting-10.sql 1`] = `"SELECT CAST(true AS boolean)"`; + +exports[`pretty: pretty/quoting-11.sql 1`] = `"SELECT '1 day'::interval"`; + +exports[`pretty: pretty/quoting-12.sql 1`] = `"SELECT 42::int"`; + +exports[`pretty: pretty/quoting-13.sql 1`] = ` +"INSERT INTO test_table ( + data +) VALUES + ('{"c":3}'::json)" +`; + +exports[`pretty: pretty/quoting-14.sql 1`] = `"SELECT CAST('{"d":4}' AS myschema."json")"`; + +exports[`pretty: pretty/quoting-15.sql 1`] = `"SELECT CAST(100 AS custom."int")"`; + +exports[`pretty: pretty/quoting-16.sql 1`] = `"SELECT CAST(true AS myapp."boolean")"`; diff --git a/packages/deparser/__tests__/pretty/quoting-pretty.test.ts b/packages/deparser/__tests__/pretty/quoting-pretty.test.ts index 1d663374..aa88c812 100644 --- a/packages/deparser/__tests__/pretty/quoting-pretty.test.ts +++ b/packages/deparser/__tests__/pretty/quoting-pretty.test.ts @@ -7,6 +7,15 @@ const prettyTest = new PrettyTest([ 'pretty/quoting-5.sql', 'pretty/quoting-6.sql', 'pretty/quoting-7.sql', + 'pretty/quoting-8.sql', + 'pretty/quoting-9.sql', + 'pretty/quoting-10.sql', + 'pretty/quoting-11.sql', + 'pretty/quoting-12.sql', + 'pretty/quoting-13.sql', + 'pretty/quoting-14.sql', + 'pretty/quoting-15.sql', + 'pretty/quoting-16.sql', ]); prettyTest.generateTests();