diff --git a/changelogs/drizzle-kit/0.32.4.md b/changelogs/drizzle-kit/0.32.4.md new file mode 100644 index 0000000000..44cea828c5 --- /dev/null +++ b/changelogs/drizzle-kit/0.32.4.md @@ -0,0 +1,3 @@ +### PostgreSQL bug fixes + +Added columns are now created before primary keys that use them. Unique constraints and indexes are now created before dependent foreign keys. diff --git a/drizzle-kit/src/snapshotsDiffer.ts b/drizzle-kit/src/snapshotsDiffer.ts index 3a77c97623..9a727a84dc 100644 --- a/drizzle-kit/src/snapshotsDiffer.ts +++ b/drizzle-kit/src/snapshotsDiffer.ts @@ -1988,23 +1988,21 @@ export const applyPgSnapshotsDiff = async ( jsonStatements.push(...jsonDeletedCompositePKs); jsonStatements.push(...jsonTableAlternations); - jsonStatements.push(...jsonAddedCompositePKs); jsonStatements.push(...jsonAddColumnsStatemets); + jsonStatements.push(...jsonAddedCompositePKs); + jsonStatements.push(...jsonDropColumnsStatemets); + jsonStatements.push(...jsonAlteredCompositePKs); - jsonStatements.push(...jsonCreateReferencesForCreatedTables); + jsonStatements.push(...jsonAddedUniqueConstraints); + jsonStatements.push(...jsonAlteredUniqueConstraints); jsonStatements.push(...jsonCreateIndexesForCreatedTables); - - jsonStatements.push(...jsonCreatedReferencesForAlteredTables); jsonStatements.push(...jsonCreateIndexesFoAlteredTables); - jsonStatements.push(...jsonDropColumnsStatemets); - jsonStatements.push(...jsonAlteredCompositePKs); + jsonStatements.push(...jsonCreateReferencesForCreatedTables); + jsonStatements.push(...jsonCreatedReferencesForAlteredTables); - jsonStatements.push(...jsonAddedUniqueConstraints); jsonStatements.push(...jsonCreatedCheckConstraints); - jsonStatements.push(...jsonAlteredUniqueConstraints); - jsonStatements.push(...createViews); jsonStatements.push(...jsonRenamePoliciesStatements); diff --git a/drizzle-kit/tests/pg-tables.test.ts b/drizzle-kit/tests/pg-tables.test.ts index a9c47eea62..10424f14d0 100644 --- a/drizzle-kit/tests/pg-tables.test.ts +++ b/drizzle-kit/tests/pg-tables.test.ts @@ -720,6 +720,76 @@ test('add column before creating unique constraint', async () => { ]); }); +test('add column before replacing composite primary key', async () => { + const from = { + requests: pgTable('assistant_requests', { + requestId: text('request_id').primaryKey(), + }), + }; + const to = { + requests: pgTable('assistant_requests', { + requestId: text('request_id').notNull(), + userId: text('user_id').notNull(), + }, (t) => ({ + pk: primaryKey({ + name: 'assistant_requests_user_id_request_id_pk', + columns: [t.requestId, t.userId], + }), + })), + }; + + const { sqlStatements } = await diffTestSchemas(from, to, []); + const addColumn = sqlStatements.findIndex((statement) => statement.includes('ADD COLUMN "user_id"')); + const addPrimaryKey = sqlStatements.findIndex((statement) => + statement.includes('ADD CONSTRAINT "assistant_requests_user_id_request_id_pk"') + ); + + expect(addColumn).toBeGreaterThanOrEqual(0); + expect(addPrimaryKey).toBeGreaterThanOrEqual(0); + expect(addColumn).toBeLessThan(addPrimaryKey); +}); + +test('create parent unique constraint before dependent foreign key', async () => { + const parentFrom = pgTable('parent', { + id: integer('id').notNull(), + orgId: integer('org_id').notNull(), + }); + const childFrom = pgTable('child', { + parentId: integer('parent_id').notNull(), + orgId: integer('org_id').notNull(), + }); + const parentTo = pgTable('parent', { + id: integer('id').notNull(), + orgId: integer('org_id').notNull(), + }, (t) => ({ + idOrgUnique: unique('parent_id_org_unique').on(t.id, t.orgId), + })); + const childTo = pgTable('child', { + parentId: integer('parent_id').notNull(), + orgId: integer('org_id').notNull(), + }, (t) => ({ + parent: foreignKey({ + name: 'child_parent_id_org_fk', + columns: [t.parentId, t.orgId], + foreignColumns: [parentTo.id, parentTo.orgId], + }), + })); + + const { sqlStatements } = await diffTestSchemas( + { parent: parentFrom, child: childFrom }, + { parent: parentTo, child: childTo }, + [], + ); + const addUnique = sqlStatements.findIndex((statement) => statement.includes('ADD CONSTRAINT "parent_id_org_unique"')); + const addForeignKey = sqlStatements.findIndex((statement) => + statement.includes('ADD CONSTRAINT "child_parent_id_org_fk"') + ); + + expect(addUnique).toBeGreaterThanOrEqual(0); + expect(addForeignKey).toBeGreaterThanOrEqual(0); + expect(addUnique).toBeLessThan(addForeignKey); +}); + test('alter composite primary key', async () => { const from = { table: pgTable('table', { @@ -885,7 +955,7 @@ test('optional db aliases (snake case)', async () => { const st7 = `CREATE INDEX "t1_idx" ON "t1" USING btree ("t1_idx") WHERE "t1"."t1_idx" > 0;`; - expect(sqlStatements).toStrictEqual([st1, st2, st3, st4, st5, st6, st7]); + expect(sqlStatements).toStrictEqual([st1, st2, st3, st6, st7, st4, st5]); }); test('optional db aliases (camel case)', async () => { @@ -975,5 +1045,5 @@ test('optional db aliases (camel case)', async () => { const st7 = `CREATE INDEX "t1Idx" ON "t1" USING btree ("t1Idx") WHERE "t1"."t1Idx" > 0;`; - expect(sqlStatements).toStrictEqual([st1, st2, st3, st4, st5, st6, st7]); + expect(sqlStatements).toStrictEqual([st1, st2, st3, st6, st7, st4, st5]); });