drizzle-orm icon indicating copy to clipboard operation
drizzle-orm copied to clipboard

[BUG]: drizzle-kit generates incorrect foreign key references to a table from a different schema when using pgSchema

Open cs-clarence opened this issue 2 years ago • 1 comments

What version of drizzle-orm are you using?

0.26.1

What version of drizzle-kit are you using?

0.18.1

Describe the Bug

I have this file that has two schemas, iam and chat. The iam scheme has users table and chat schema has chatRooms table. That chatRooms table has a foreign key that references the primary key for users.

import { bigserial, pgSchema, uniqueIndex, varchar } from "drizzle-orm/pg-core";

export const iamSchema = pgSchema("iam");
const iamTable = iamSchema.table;

export const users = iamTable(
  "users",
  {
    id: bigserial("id", { mode: "bigint" }).primaryKey(),
    username: varchar("username").notNull(),
    emailAddress: varchar("email_address").notNull(),
    passwordHash: varchar("password_hash").notNull(),
  },
  (users) => {
    return {
      usernameIndex: uniqueIndex("username_idx").on(users.username),
      emailAddressIndex: uniqueIndex("email_address_idx").on(
        users.emailAddress,
      ),
    };
  },
);

export const chatSchema = pgSchema("chat");

export const chatTable = chatSchema.table;

export const chatRooms = chatTable("chat_rooms", {
  id: bigserial("id", { mode: "bigint" }).primaryKey(),
});

export const chatRoomMemberships = chatTable("chat_room_memberships", {
  chatRoomID: bigserial("chat_room_id", { mode: "bigint" })
    .notNull()
    .references(() => chatRooms.id),
  userID: bigserial("user_id", { mode: "bigint" })
    .notNull()
    .references(() => users.id),
});

Using drizzle-kit generate:pg generates the following sql:

-- snipped
--> statement-breakpoint
DO $$ BEGIN
 ALTER TABLE "chat"."chat_room_memberships" ADD CONSTRAINT "chat_room_memberships_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "chat"."users"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
 WHEN duplicate_object THEN null;
END $$;

The foreign key references "chat"."users"("id") instead of "iam"."users"("id").

Expected behavior

The migration file generated by drizzle-kit should correctly reference table and columns from another schema in foreign keys.

Environment & setup

Postgres Fedora Linux

cs-clarence avatar May 26 '23 10:05 cs-clarence

Thanks! Going to fix it

AndriiSherman avatar May 26 '23 10:05 AndriiSherman

Having the same issue, are there any updates on this so far?

xprnio avatar Jul 08 '23 05:07 xprnio

Same issue here.

lucianogreiner avatar Jul 26 '23 13:07 lucianogreiner

Would like this as well

austinm911 avatar Aug 10 '23 03:08 austinm911

Having the same issue, any updates on this?

Using drizzle-kit 0.19.13 and drizzle-orm 0.28.2

thiagoferolla avatar Aug 29 '23 15:08 thiagoferolla

I also just came across this issue.

@AndriiSherman How much longer until you're ready to open source drizzle-kit so we can help fixing these issues?

avanderbergh avatar Sep 20 '23 10:09 avanderbergh

FWIW, I've resorted to solving this with a patch until it's fixed 😅

diff --git a/index.cjs b/index.cjs
index d6085807f138fca830a8fb8bf9470779f091fa61..7518cfa82962ca53498bf194c19fe0394e59def1 100755
--- a/index.cjs
+++ b/index.cjs
@@ -4903,6 +4903,7 @@ var init_pgSchema = __esm({
       name: stringType(),
       tableFrom: stringType(),
       columnsFrom: stringType().array(),
+      schemaTo: stringType().optional(),
       tableTo: stringType(),
       columnsTo: stringType().array(),
       onUpdate: stringType().optional(),
@@ -5061,7 +5062,7 @@ var init_pgSchema = __esm({
         return result;
       },
       squashFK: (fk4) => {
-        return `${fk4.name};${fk4.tableFrom};${fk4.columnsFrom.join(",")};${fk4.tableTo};${fk4.columnsTo.join(",")};${fk4.onUpdate ?? ""};${fk4.onDelete ?? ""}`;
+        return `${fk4.name};${fk4.tableFrom};${fk4.columnsFrom.join(",")};${fk4.schemaTo || ""};${fk4.tableTo};${fk4.columnsTo.join(",")};${fk4.onUpdate ?? ""};${fk4.onDelete ?? ""}`;
       },
       squashPK: (pk) => {
         return `${pk.columns.join(",")}`;
@@ -5085,6 +5086,7 @@ var init_pgSchema = __esm({
           name,
           tableFrom,
           columnsFromStr,
+          schemaTo,
           tableTo,
           columnsToStr,
           onUpdate,
@@ -5094,6 +5096,7 @@ var init_pgSchema = __esm({
           name,
           tableFrom,
           columnsFrom: columnsFromStr.split(","),
+          schemaTo,
           tableTo,
           columnsTo: columnsToStr.split(","),
           onUpdate,
@@ -12210,12 +12213,15 @@ ${withStyle.errorWarning(`We've found duplicated unique constraint names in ${so
           const onUpdate = fk4.onUpdate;
           const reference = fk4.reference();
           const tableTo = (0, import_drizzle_orm6.getTableName)(reference.foreignTable);
+          // Patched
+          const schemaTo = reference.foreignTable[Symbol.for("drizzle:Schema")];
           const columnsFrom = reference.columns.map((it) => it.name);
           const columnsTo = reference.foreignColumns.map((it) => it.name);
           return {
             name,
             tableFrom,
             tableTo,
+            schemaTo,
             columnsFrom,
             columnsTo,
             onDelete,
@@ -15963,6 +15969,7 @@ ${BREAKPOINT}ALTER TABLE ${tableNameWithSchema} ADD CONSTRAINT ${statement.newCo
       convert(statement) {
         const {
           name,
+          schemaTo,
           tableFrom,
           tableTo,
           columnsFrom,
@@ -15975,7 +15982,7 @@ ${BREAKPOINT}ALTER TABLE ${tableNameWithSchema} ADD CONSTRAINT ${statement.newCo
         const fromColumnsString = columnsFrom.map((it) => `"${it}"`).join(",");
         const toColumnsString = columnsTo.map((it) => `"${it}"`).join(",");
         const tableNameWithSchema = statement.schema ? `"${statement.schema}"."${tableFrom}"` : `"${tableFrom}"`;
-        const tableToNameWithSchema = statement.schema ? `"${statement.schema}"."${tableTo}"` : `"${tableTo}"`;
+        const tableToNameWithSchema = schemaTo ? `"${schemaTo}"."${tableTo}"` : `"${tableTo}"`;
         const alterStatement = `ALTER TABLE ${tableNameWithSchema} ADD CONSTRAINT "${name}" FOREIGN KEY (${fromColumnsString}) REFERENCES ${tableToNameWithSchema}(${toColumnsString})${onDeleteStatement}${onUpdateStatement}`;
         let sql = "DO $$ BEGIN\n";
         sql += " " + alterStatement + ";\n";

Only fixes PostgreSQL...

avanderbergh avatar Sep 21 '23 10:09 avanderbergh

Coming here to bump this issue.

The patch work with well with pnpm thanks @avanderbergh

vafanassieff avatar Sep 22 '23 17:09 vafanassieff

Any update on this? It's a bit tedious to have to reapply the patch with every update.

louneskmt avatar Nov 13 '23 13:11 louneskmt

This is incredible? How can a bug like this be open for 6 months? I'm looking into drizzle for our team but this is a show stopper for us and a HUGE turn off?

fergalmoran avatar Nov 27 '23 20:11 fergalmoran

I don't understand why this has been moved to the public roadmap's backlog when there is a fix already identified by community users. Unless there's some complexity I am not understanding, this is a clear low hanging fruit and eliminating the burden of having to re-patch after each update would improve DX for a few of us.

emmnull avatar Nov 27 '23 20:11 emmnull

@AndriiSherman I see you're assigned to this, any news?

louneskmt avatar Nov 28 '23 09:11 louneskmt

the patch is no longer working for the current drizzle-kit version and i've spent too much time trying to update the patch without luck. instead i'm resulting to change both the schema and snapshot manually (not sure if snapshot is necessary) as a more permanent solution

0000_x.sql

< ALTER TABLE "profiles" ADD CONSTRAINT "profiles_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE cascade ON UPDATE no action;
---
> ALTER TABLE "profiles" ADD CONSTRAINT "profiles_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "auth"."users"("id") ON DELETE cascade ON UPDATE no action;

0000_snapshot.json

< "tableTo": "users",
---
> "tableTo": "auth.users",

for anyone else encountering this more-than-mildly infuriating issue

hexcowboy avatar Dec 08 '23 19:12 hexcowboy

the patch is no longer working for the current drizzle-kit version and i've spent too much time trying to update the patch without luck. instead i'm resulting to change both the schema and snapshot manually (not sure if snapshot is necessary) as a more permanent solution

0000_x.sql

< ALTER TABLE "profiles" ADD CONSTRAINT "profiles_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE cascade ON UPDATE no action;
---
> ALTER TABLE "profiles" ADD CONSTRAINT "profiles_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "auth"."users"("id") ON DELETE cascade ON UPDATE no action;

0000_snapshot.json

< "tableTo": "users",
---
> "tableTo": "auth.users",

for anyone else encountering this more-than-mildly infuriating issue

Hmmm, the patch seems to work on my side. What breakage are you observing, is it successfully generating migrations with wrong schema names or is it throwing a malformed migration error when you attempt to run drizzle-kit generate ?

emmnull avatar Dec 08 '23 20:12 emmnull

Hmmm, the patch seems to work on my side.

are you using [email protected]? most of the code was moved to util.js and there are pretty significant changes there from the patch file.

the issue is the same as described in the OP. the schema is not being prepended to the table name so the migration is not successful.

hexcowboy avatar Dec 11 '23 14:12 hexcowboy

Hmmm, the patch seems to work on my side.

are you using [email protected]? most of the code was moved to util.js and there are pretty significant changes there from the patch file.

the issue is the same as described in the OP. the schema is not being prepended to the table name so the migration is not successful.

Yes, I am using @0.20.6. Unless I'm mistaken, the code you need to patch is now in bin.cjs, not utils.js.

Edit: updated for 0.20.7 (this is getting really annoying).

diff --git a/bin.cjs b/bin.cjs
index 8e30f3c742f58d349be800a0cd107d8cd597b540..9daa5f490fbf50563fb200c6a0bf759833975ce3 100755
--- a/bin.cjs
+++ b/bin.cjs
@@ -4906,6 +4906,7 @@ var init_pgSchema = __esm({
       name: stringType(),
       tableFrom: stringType(),
       columnsFrom: stringType().array(),
+      schemaTo: stringType().optional(),
       tableTo: stringType(),
       columnsTo: stringType().array(),
       onUpdate: stringType().optional(),
@@ -5064,7 +5065,7 @@ var init_pgSchema = __esm({
         return result;
       },
       squashFK: (fk4) => {
-        return `${fk4.name};${fk4.tableFrom};${fk4.columnsFrom.join(",")};${fk4.tableTo};${fk4.columnsTo.join(",")};${fk4.onUpdate ?? ""};${fk4.onDelete ?? ""}`;
+        return `${fk4.name};${fk4.tableFrom};${fk4.columnsFrom.join(",")};${fk4.schemaTo || ""};${fk4.tableTo};${fk4.columnsTo.join(",")};${fk4.onUpdate ?? ""};${fk4.onDelete ?? ""}`
       },
       squashPK: (pk) => {
         return `${pk.columns.join(",")};${pk.name}`;
@@ -5089,6 +5090,7 @@ var init_pgSchema = __esm({
           name,
           tableFrom,
           columnsFromStr,
+          schemaTo,
           tableTo,
           columnsToStr,
           onUpdate,
@@ -5098,6 +5100,7 @@ var init_pgSchema = __esm({
           name,
           tableFrom,
           columnsFrom: columnsFromStr.split(","),
+          schemaTo,
           tableTo,
           columnsTo: columnsToStr.split(","),
           onUpdate,
@@ -12303,12 +12306,14 @@ ${withStyle.errorWarning(`We've found duplicated unique constraint names in ${so
           const onUpdate = fk4.onUpdate;
           const reference = fk4.reference();
           const tableTo = (0, import_drizzle_orm5.getTableName)(reference.foreignTable);
+          const schemaTo = reference.foreignTable[Symbol.for("drizzle:Schema")];
           const columnsFrom = reference.columns.map((it) => it.name);
           const columnsTo = reference.foreignColumns.map((it) => it.name);
           return {
             name,
             tableFrom,
             tableTo,
+            schemaTo,
             columnsFrom,
             columnsTo,
             onDelete,
@@ -16289,7 +16294,7 @@ ${BREAKPOINT}ALTER TABLE ${tableNameWithSchema} ADD CONSTRAINT ${statement.newCo
         const fromColumnsString = columnsFrom.map((it) => `"${it}"`).join(",");
         const toColumnsString = columnsTo.map((it) => `"${it}"`).join(",");
         const tableNameWithSchema = statement.schema ? `"${statement.schema}"."${tableFrom}"` : `"${tableFrom}"`;
-        const tableToNameWithSchema = statement.schema ? `"${statement.schema}"."${tableTo}"` : `"${tableTo}"`;
+        const tableToNameWithSchema = schemaTo ? `"${schemaTo}"."${tableTo}"` : `"${tableTo}"`
         const alterStatement = `ALTER TABLE ${tableNameWithSchema} ADD CONSTRAINT "${name}" FOREIGN KEY (${fromColumnsString}) REFERENCES ${tableToNameWithSchema}(${toColumnsString})${onDeleteStatement}${onUpdateStatement}`;
         let sql2 = "DO $$ BEGIN\n";
         sql2 += " " + alterStatement + ";\n";

emmnull avatar Dec 11 '23 16:12 emmnull

8 months and still not fixed, i think i need to switch to another orm

pawanmkr avatar Dec 29 '23 08:12 pawanmkr

@AndriiSherman what is the problem here? Why is this bug so long standing? This is really annoying. Community already made a few patches yet Drizzle is complete ignoring here. Unacceptable!!

codeagencybe avatar Dec 29 '23 17:12 codeagencybe

@pawanmkr @codeagencybe Although I feel just as both of you (and everybody else that's here waiting), let's give them the benefit of the doubt and assume that the current issue is related to the holidays. Let's give them a bit of a breather, for example a week or so, and hope they'll start the new year off with working with the community instead of against it.

xprnio avatar Dec 29 '23 20:12 xprnio

@pawanmkr @codeagencybe Although I feel just as both of you (and everybody else that's here waiting), let's give them the benefit of the doubt and assume that the current issue is related to the holidays. Let's give them a bit of a breather, for example a week or so, and hope they'll start the new year off with working with the community instead of against it.

Holidays?? This bug is ongoing for 8+ months lol. This is not related to holidays. And besides the community already gave working solutions in the past, they could have easy picked it up and make sure it gets vetted in the official releases and updates.

8 months later: nothing, nada, zero engagement... This is not some small futile problem, it causes real serious problems if your migrations get screwed up.

Problems like this that keep being ignored is what pushes people back to Prisma and others.

codeagencybe avatar Dec 29 '23 20:12 codeagencybe

There very well could be some complexity to this issue that is being overlooked by discussions in this thread while being silently acknowledged by the core team (things like ensuring backward/forward compatibility of generated metadata, migrations scripts to patch erroneous upstream migrations, etc.). I would give them benefit of the doubt, but what is justifiably bothersome is how there's been a longstanding unfulfilled promise of open-sourcing drizzle-kit leaving the community completely unequipped to help identify and approach this issue and others more rigorously or even make PRs that could offload some work and improve our DX. There's a distinct problem of communication that - although it could be attributed to lack of time - is starting to feel like an intentional lack of transparency from the outside.

emmnull avatar Dec 29 '23 20:12 emmnull

Whatever the reason is, there is no communication at all. Not even a simple ack "we are aware and working on it" or whatever. It's completely ghosted, that bothers me most. I can understand sometimes bugs can be hard and take time. But at least communicate back with your community. Where are we at now? Nobody knows.

And as you say, it's completely closed black box now. So nobody from community can even do something to get a minimal progress. It's already a miracle some smart people here managed to get some quick patch in the past so we all can continue...

codeagencybe avatar Dec 29 '23 20:12 codeagencybe

There very well could be some complexity to this issue that is being overlooked by discussions in this thread while being silently acknowledged by the core team....

I'm not sure you're correct here as there have been numerous patches submitted to resolve this issue, but with the best will in the world it's still egregious that we have had precisely zero feedback from the drizzle team on this.

fergalmoran avatar Dec 29 '23 21:12 fergalmoran

I'm not sure you're correct here as there have been numerous patches submitted to resolve this issue

As far as i know, there was only a single patch proposed (targeting different lines depending on the patched package version), and after it is used once, omitting its added schemaTo keys or simply changing its name in subsequent patches leads to failures when generating new migrations. This to me sounds like there's at least some more work needed to handle errors or ensure better lateral compatibility. But again, I totally agree that how this issue is unfolding highlights a bigger communication problem.

emmnull avatar Dec 29 '23 22:12 emmnull

I would not be surprised if this issue was ignored just for the sake of the meme 😀 it is already starting on X

thefrana avatar Dec 30 '23 12:12 thefrana

Should be fixed in drizzle-kit@beta. Please confirm that it works for you so I can release it to the latest version. I also fixed the issue with introspection and push, so now both introspect and push should work for these cases.

Note: The only thing that is not fixed and is a different issue is when you name tables the same across schemas, but that was not the case for this specific issue.

AndriiSherman avatar Jan 02 '24 18:01 AndriiSherman

See, @codeagencybe. I told you, just give the guys some breathing room for the holidays. All is well that ends well

xprnio avatar Jan 02 '24 18:01 xprnio

See, @codeagencybe. I told you, just give the guys some breathing room for the holidays. All is well that ends well

lol no, they just picked it up because I ranted it on Twitter and other people complained about the same. This is not about "the holidays". I know a lot devs that decided to drop Drizzle and go back to Prisma or others, myself included if this wasn't picked up fast. This is a serious show stopper for many people that actually build production software. I'm not toying around with the next shiny AI playground.

Anyways, it's good that it's now finally got attention and fixed. That's the end result that matters. But they could have done much better effort in communicating with their community or better open source the kit so the community could have fixed it months ago.

codeagencybe avatar Jan 02 '24 19:01 codeagencybe

Open-sourcing drizzle-kit won't expedite the fixing process. I still need time to review pull requests and merge them. It's primarily a matter of time and receiving support, both in terms of time and donations, from companies utilizing Drizzle in a production environment and relying on it.

I can say the same about better communication. As core library developers, we are grappling with numerous issues/feature requests, addressing and fixing them while juggling our main jobs. I believe every library developer has had these types of conversations at least once

AndriiSherman avatar Jan 02 '24 19:01 AndriiSherman

Should be fixed in drizzle-kit@beta. Please confirm that it works for you so I can release it to the latest version. I also fixed the issue with introspection and push, so now both introspect and push should work for these cases.

Note: The only thing that is not fixed and is a different issue is when you name tables the same across schemas, but that was not the case for this specific issue.

Hey, I was about to give up on this. I can confirm switching this beta version did in fact fix my issue.

maietta avatar Jan 03 '24 04:01 maietta