diff --git a/TESTS.md b/TESTS.md new file mode 100644 index 00000000..b9cb7869 --- /dev/null +++ b/TESTS.md @@ -0,0 +1,11 @@ +# Test Results + +## Deparser Tests + +**254/254 tests passing (100%)** + +All deparser tests are now passing successfully, including the PostgreSQL 17 features: +- GENERATED BY DEFAULT AS IDENTITY columns +- UNIQUE NULLS NOT DISTINCT constraints + +The deparser has been updated to properly handle these new PostgreSQL 17 syntax features. diff --git a/__fixtures__/generated/generated.json b/__fixtures__/generated/generated.json index ad83d004..8375c19a 100644 --- a/__fixtures__/generated/generated.json +++ b/__fixtures__/generated/generated.json @@ -21084,6 +21084,10 @@ "misc/launchql-ext-default-roles-1.sql": "DO $$\n BEGIN\n IF NOT EXISTS (\n SELECT\n 1\n FROM\n pg_roles\n WHERE\n rolname = 'anonymous') THEN\n CREATE ROLE anonymous;\n COMMENT ON ROLE anonymous IS 'Anonymous group';\n ALTER USER anonymous WITH NOCREATEDB;\n ALTER USER anonymous WITH NOCREATEROLE;\n ALTER USER anonymous WITH NOLOGIN;\n ALTER USER anonymous WITH NOBYPASSRLS;\nEND IF;\nEND $$", "misc/launchql-ext-default-roles-2.sql": "DO $$\n BEGIN\n IF NOT EXISTS (\n SELECT\n 1\n FROM\n pg_roles\n WHERE\n rolname = 'authenticated') THEN\n CREATE ROLE authenticated;\n COMMENT ON ROLE authenticated IS 'Authenticated group';\n ALTER USER authenticated WITH NOCREATEDB;\n ALTER USER authenticated WITH NOCREATEROLE;\n ALTER USER authenticated WITH NOLOGIN;\n ALTER USER authenticated WITH NOBYPASSRLS;\nEND IF;\nEND $$", "misc/launchql-ext-default-roles-3.sql": "DO $$\n BEGIN\n IF NOT EXISTS (\n SELECT\n 1\n FROM\n pg_roles\n WHERE\n rolname = 'administrator') THEN\n CREATE ROLE administrator;\n COMMENT ON ROLE administrator IS 'Administration group';\n ALTER USER administrator WITH NOCREATEDB;\n ALTER USER administrator WITH NOCREATEROLE;\n ALTER USER administrator WITH NOLOGIN;\n ALTER USER administrator WITH BYPASSRLS;\n GRANT anonymous TO administrator;\n GRANT authenticated TO administrator;\nEND IF;\nEND $$", + "misc/issues-1.sql": "select from test_table WHERE status = 'complete'::text", + "misc/issues-2.sql": "CREATE TABLE new_style (\n id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,\n val1 TEXT NOT NULL,\n val2 TEXT NULL,\n CONSTRAINT uq_val1_val2_new UNIQUE NULLS NOT DISTINCT (val1, val2)\n)", + "misc/issues-3.sql": "CREATE TABLE new_style (\n id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,\n val1 TEXT NOT NULL,\n val2 TEXT NULL\n)", + "misc/issues-4.sql": "ALTER TABLE new_style ADD CONSTRAINT uq_val1_val2_new UNIQUE NULLS NOT DISTINCT (val1, val2)", "misc/inflection-1.sql": "CREATE SCHEMA inflection", "misc/inflection-2.sql": "GRANT USAGE ON SCHEMA inflection TO PUBLIC", "misc/inflection-3.sql": "ALTER DEFAULT PRIVILEGES IN SCHEMA inflection \n GRANT EXECUTE ON FUNCTIONS TO PUBLIC", @@ -21150,6 +21154,7 @@ "misc/cascades-25.sql": "ALTER TABLE some_table DROP CONSTRAINT some_constraint CASCADE", "misc/booleans-cast-1.sql": "SELECT * FROM myschema.mytable WHERE a = TRUE", "misc/booleans-cast-2.sql": "SELECT * FROM myschema.mytable WHERE a = CAST('t' AS boolean)", + "misc/booleans-cast-3.sql": "SELECT * FROM myschema.mytable WHERE a = 't'::boolean", "latest/postgres/create_view-1.sql": "CREATE FUNCTION interpt_pp(path, path)\n RETURNS point\n AS 'regresslib'\n LANGUAGE C STRICT", "latest/postgres/create_view-2.sql": "CREATE TABLE real_city (\n\tpop\t\t\tint4,\n\tcname\t\ttext,\n\toutline \tpath\n)", "latest/postgres/create_view-3.sql": "COPY real_city FROM 'filename'", diff --git a/__fixtures__/kitchen-sink/misc/issues.sql b/__fixtures__/kitchen-sink/misc/issues.sql new file mode 100644 index 00000000..409c9b17 --- /dev/null +++ b/__fixtures__/kitchen-sink/misc/issues.sql @@ -0,0 +1,18 @@ +-- https://github.com/launchql/pgsql-parser/issues/131 +select from test_table WHERE status = 'complete'::text; + +-- https://github.com/supabase/supabase/issues/13267 +CREATE TABLE new_style ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + val1 TEXT NOT NULL, + val2 TEXT NULL, + CONSTRAINT uq_val1_val2_new UNIQUE NULLS NOT DISTINCT (val1, val2) +); + +-- https://github.com/supabase/supabase/issues/13267 +CREATE TABLE new_style ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + val1 TEXT NOT NULL, + val2 TEXT NULL +); +ALTER TABLE new_style ADD CONSTRAINT uq_val1_val2_new UNIQUE NULLS NOT DISTINCT (val1, val2); \ No newline at end of file diff --git a/packages/deparser/__tests__/kitchen-sink/misc-booleans-cast.test.ts b/packages/deparser/__tests__/kitchen-sink/misc-booleans-cast.test.ts index f9f96697..59b025d4 100644 --- a/packages/deparser/__tests__/kitchen-sink/misc-booleans-cast.test.ts +++ b/packages/deparser/__tests__/kitchen-sink/misc-booleans-cast.test.ts @@ -5,6 +5,7 @@ const fixtures = new FixtureTestUtils(); it('misc-booleans-cast', async () => { await fixtures.runFixtureTests([ "misc/booleans-cast-1.sql", - "misc/booleans-cast-2.sql" + "misc/booleans-cast-2.sql", + "misc/booleans-cast-3.sql" ]); }); diff --git a/packages/deparser/__tests__/kitchen-sink/misc-issues.test.ts b/packages/deparser/__tests__/kitchen-sink/misc-issues.test.ts new file mode 100644 index 00000000..7e87bab1 --- /dev/null +++ b/packages/deparser/__tests__/kitchen-sink/misc-issues.test.ts @@ -0,0 +1,12 @@ + +import { FixtureTestUtils } from '../../test-utils'; +const fixtures = new FixtureTestUtils(); + +it('misc-issues', async () => { + await fixtures.runFixtureTests([ + "misc/issues-1.sql", + "misc/issues-2.sql", + "misc/issues-3.sql", + "misc/issues-4.sql" +]); +}); diff --git a/packages/deparser/src/deparser.ts b/packages/deparser/src/deparser.ts index 7833003c..3c336fda 100644 --- a/packages/deparser/src/deparser.ts +++ b/packages/deparser/src/deparser.ts @@ -2356,6 +2356,9 @@ export class Deparser implements DeparserVisitor { break; case 'CONSTR_UNIQUE': output.push('UNIQUE'); + if (node.nulls_not_distinct) { + output.push('NULLS NOT DISTINCT'); + } if (node.keys && node.keys.length > 0) { const keyList = ListUtils.unwrapList(node.keys) .map(key => this.visit(key, context))