diff --git a/__fixtures__/generated/generated.json b/__fixtures__/generated/generated.json index 202a463f..e9c00d69 100644 --- a/__fixtures__/generated/generated.json +++ b/__fixtures__/generated/generated.json @@ -21413,6 +21413,18 @@ "misc/indexes-11.sql": "DROP INDEX CONCURRENTLY IF EXISTS my_index CASCADE", "misc/indexes-12.sql": "CREATE UNIQUE INDEX new_unique_idx ON new_example(a, b) INCLUDE (c)", "misc/indexes-13.sql": "CREATE INDEX CONCURRENTLY idx_with_operator ON boom.merkle_tree USING GIN ( name gin_trgm_ops ( param1 = 32, param2 = true) )", + "misc/index-clause-ordering-1.sql": "CREATE UNIQUE INDEX u1 ON t (a) NULLS NOT DISTINCT", + "misc/index-clause-ordering-2.sql": "CREATE UNIQUE INDEX u2 ON t (a, b) NULLS NOT DISTINCT WHERE c IS NULL", + "misc/index-clause-ordering-3.sql": "CREATE UNIQUE INDEX u3 ON t (a) INCLUDE (b) NULLS NOT DISTINCT", + "misc/index-clause-ordering-4.sql": "CREATE UNIQUE INDEX u4 ON t (a) INCLUDE (b) NULLS NOT DISTINCT WITH (fillfactor = 70) WHERE c IS NULL", + "misc/index-clause-ordering-5.sql": "CREATE UNIQUE INDEX u5 ON t (a) NULLS NOT DISTINCT WITH (fillfactor = 70) TABLESPACE pg_default WHERE c IS NULL", + "misc/index-clause-ordering-6.sql": "CREATE UNIQUE INDEX u6 ON s.t (a, b) WITH (fillfactor = 70) WHERE c IS NULL", + "misc/index-clause-ordering-7.sql": "CREATE UNIQUE INDEX u7 ON t (a) WHERE c IS NULL", + "misc/index-clause-ordering-8.sql": "CREATE INDEX u8 ON t USING btree (a) WITH (fillfactor = 70) TABLESPACE pg_default WHERE c IS NULL", + "misc/index-clause-ordering-9.sql": "CREATE UNIQUE INDEX platform_secrets_namespace_id_name_realm_idx\n ON \"constructive-store-private\".platform_secrets ( namespace_id, name, realm )\n NULLS NOT DISTINCT WHERE retired_at IS NULL", + "misc/index-clause-ordering-10.sql": "CREATE UNIQUE INDEX secrets_database_id_namespace_id_name_realm_idx\n ON \"constructive-store-private\".secrets ( database_id, namespace_id, name, realm )\n NULLS NOT DISTINCT WHERE retired_at IS NULL", + "misc/index-clause-ordering-11.sql": "ALTER TABLE t ADD CONSTRAINT c UNIQUE NULLS NOT DISTINCT (a, b)", + "misc/index-clause-ordering-12.sql": "CREATE TABLE nnd (a int, b int, UNIQUE NULLS NOT DISTINCT (a, b))", "misc/generated-columns-1.sql": "CREATE TABLE generated_misc_test (\n a INT,\n b INT,\n c INT GENERATED ALWAYS AS (a + b) STORED\n)", "misc/generated-columns-2.sql": "CREATE TABLE generated_func_test (\n name TEXT,\n name_upper TEXT GENERATED ALWAYS AS (upper(name)) STORED\n)", "misc/generated-columns-3.sql": "CREATE TABLE generated_numeric_test (\n quantity INT,\n unit_price NUMERIC(10, 2),\n total_price NUMERIC(10, 2) GENERATED ALWAYS AS (quantity * unit_price) STORED NOT NULL UNIQUE\n)", diff --git a/__fixtures__/kitchen-sink/misc/index-clause-ordering.sql b/__fixtures__/kitchen-sink/misc/index-clause-ordering.sql new file mode 100644 index 00000000..f7aaea4b --- /dev/null +++ b/__fixtures__/kitchen-sink/misc/index-clause-ordering.sql @@ -0,0 +1,23 @@ +-- CREATE INDEX trailing-clause ordering: the grammar requires +-- ( params ) INCLUDE ... NULLS NOT DISTINCT WITH ... TABLESPACE ... WHERE ... +-- Ref: constructive-io/constructive-planning#1382 +CREATE UNIQUE INDEX u1 ON t (a) NULLS NOT DISTINCT; +CREATE UNIQUE INDEX u2 ON t (a, b) NULLS NOT DISTINCT WHERE c IS NULL; +CREATE UNIQUE INDEX u3 ON t (a) INCLUDE (b) NULLS NOT DISTINCT; +CREATE UNIQUE INDEX u4 ON t (a) INCLUDE (b) NULLS NOT DISTINCT WITH (fillfactor = 70) WHERE c IS NULL; +CREATE UNIQUE INDEX u5 ON t (a) NULLS NOT DISTINCT WITH (fillfactor = 70) TABLESPACE pg_default WHERE c IS NULL; +CREATE UNIQUE INDEX u6 ON s.t (a, b) WITH (fillfactor = 70) WHERE c IS NULL; +CREATE UNIQUE INDEX u7 ON t (a) WHERE c IS NULL; +CREATE INDEX u8 ON t USING btree (a) WITH (fillfactor = 70) TABLESPACE pg_default WHERE c IS NULL; + +CREATE UNIQUE INDEX platform_secrets_namespace_id_name_realm_idx + ON "constructive-store-private".platform_secrets ( namespace_id, name, realm ) + NULLS NOT DISTINCT WHERE retired_at IS NULL; + +CREATE UNIQUE INDEX secrets_database_id_namespace_id_name_realm_idx + ON "constructive-store-private".secrets ( database_id, namespace_id, name, realm ) + NULLS NOT DISTINCT WHERE retired_at IS NULL; + +-- table-constraint path, which already emitted NULLS NOT DISTINCT before the key list +ALTER TABLE t ADD CONSTRAINT c UNIQUE NULLS NOT DISTINCT (a, b); +CREATE TABLE nnd (a int, b int, UNIQUE NULLS NOT DISTINCT (a, b)); diff --git a/packages/deparser/__tests__/kitchen-sink/misc-index-clause-ordering.test.ts b/packages/deparser/__tests__/kitchen-sink/misc-index-clause-ordering.test.ts new file mode 100644 index 00000000..2671e813 --- /dev/null +++ b/packages/deparser/__tests__/kitchen-sink/misc-index-clause-ordering.test.ts @@ -0,0 +1,20 @@ + +import { FixtureTestUtils } from '../../test-utils'; +const fixtures = new FixtureTestUtils(); + +it('misc-index-clause-ordering', async () => { + await fixtures.runFixtureTests([ + "misc/index-clause-ordering-1.sql", + "misc/index-clause-ordering-2.sql", + "misc/index-clause-ordering-3.sql", + "misc/index-clause-ordering-4.sql", + "misc/index-clause-ordering-5.sql", + "misc/index-clause-ordering-6.sql", + "misc/index-clause-ordering-7.sql", + "misc/index-clause-ordering-8.sql", + "misc/index-clause-ordering-9.sql", + "misc/index-clause-ordering-10.sql", + "misc/index-clause-ordering-11.sql", + "misc/index-clause-ordering-12.sql" +]); +}); diff --git a/packages/deparser/src/deparser.ts b/packages/deparser/src/deparser.ts index 23b0d124..78502858 100644 --- a/packages/deparser/src/deparser.ts +++ b/packages/deparser/src/deparser.ts @@ -3808,9 +3808,8 @@ export class Deparser implements DeparserVisitor { output.push(context.parens(includeStrs.join(', '))); } - if (node.whereClause) { - output.push('WHERE'); - output.push(this.visit(node.whereClause, context)); + if (node.nulls_not_distinct) { + output.push('NULLS NOT DISTINCT'); } if (node.options && node.options.length > 0) { @@ -3820,15 +3819,16 @@ export class Deparser implements DeparserVisitor { output.push(context.parens(optionStrs.join(', '))); } - if (node.nulls_not_distinct) { - output.push('NULLS NOT DISTINCT'); - } - if (node.tableSpace) { output.push('TABLESPACE'); output.push(QuoteUtils.quoteIdentifier(node.tableSpace)); } + if (node.whereClause) { + output.push('WHERE'); + output.push(this.visit(node.whereClause, context)); + } + return output.join(' '); }