drizzle-team / drizzle-orm

Headless TypeScript ORM with a head. Runs on Node, Bun and Deno. Lives on the Edge and yes, it's a JavaScript ORM too đŸ˜…
https://orm.drizzle.team
Apache License 2.0
21.57k stars 490 forks source link

[BUG]: multiple constraints not added (only the first one is generated) #2341

Closed noook closed 1 month ago

noook commented 1 month ago

What version of drizzle-orm are you using?

0.30.10

What version of drizzle-kit are you using?

0.20.18

Describe the Bug

When adding multiple constraints on a table, only the first one is generated in the migration:

export const T_orders = pgTable('orders', {
  id: serial('id').primaryKey(),
  requesterId: uuid('requester_id').notNull().references(() => T_userInfos.id, { onDelete: 'cascade' }),
  companyInfoId: uuid('company_info_id').references(() => T_companyInfos.id, { onDelete: 'set null' }),
  prestationId: uuid('prestation_id').notNull().references(() => T_prestations.id, { onDelete: 'cascade' }),
  formId: uuid('form_id').notNull(),
  createdAt: timestamp('created_at', { mode: 'string', withTimezone: true }).notNull().defaultNow(),
})

export const T_prestations = pgTable('prestations', {
  id: uuid('id').primaryKey().defaultRandom(),
  title: text('title').notNull(),
  description: text('description').notNull(),
  externalLink: text('external_link'),
  type: E_prestationType('type').notNull(),
})

export const T_userInfos = pgTable('user_infos', {
  id: uuid('id').primaryKey().defaultRandom(),
  firstName: text('first_name').notNull(),
  lastName: text('last_name').notNull(),
  email: text('email').notNull(),
  role: text('role').notNull(),
})

export const T_companyInfos = pgTable('company_infos', {
  id: uuid('id').primaryKey().defaultRandom(),
  name: text('name').notNull(),
  address: text('address').notNull(),
  siren: text('siren').notNull(),
})

Diff:

 export const T_orders = pgTable('orders', {
   id: serial('id').primaryKey(),
-  requesterId: uuid('requester_id').notNull().references(() => T_userInfos.id),
-  companyInfoId: uuid('company_info_id').references(() => T_companyInfos.id),
-  prestationId: uuid('prestation_id').notNull().references(() => T_prestations.id),
+  requesterId: uuid('requester_id').notNull().references(() => T_userInfos.id, { onDelete: 'cascade' }),
+  companyInfoId: uuid('company_info_id').references(() => T_companyInfos.id, { onDelete: 'set null' }),
+  prestationId: uuid('prestation_id').notNull().references(() => T_prestations.id, { onDelete: 'cascade' }),
   formId: uuid('form_id').notNull(),
   createdAt: timestamp('created_at', { mode: 'string', withTimezone: true }).notNull().defaultNow(),
 })
@@ -32,7 +32,7 @@ export const T_courseOrders = pgTable('course_orders', {
   id: uuid('id').primaryKey().defaultRandom(),
   modality: text('modality').notNull(),
   context: text('context').notNull().default(''),
-  signatoryId: uuid('signatory_id').references(() => T_userInfos.id),
+  signatoryId: uuid('signatory_id').references(() => T_userInfos.id, { onDelete: 'cascade' }),
 })

 export const R_courseOrdersRelations = relations(T_courseOrders, ({ one }) => ({
diff --git a/server/database/schemas/prestations.ts b/server/database/schemas/prestations.ts
index c603901..875cf09 100644
--- a/server/database/schemas/prestations.ts
+++ b/server/database/schemas/prestations.ts
@@ -30,10 +30,10 @@ export const T_tags = pgTable('tags', {
 export const T_prestationTags = pgTable('prestation_tags', {
   prestationId: uuid('prestation_id')
     .notNull()
-    .references(() => T_prestations.id),
+    .references(() => T_prestations.id, { onDelete: 'cascade' }),
   tagId: text('tag_id')
     .notNull()
-    .references(() => T_tags.id),
+    .references(() => T_tags.id, { onDelete: 'cascade' }),
 }, table => ({
   pk: primaryKey({ columns: [table.prestationId, table.tagId] }),
 }))

Migration generated:

ALTER TABLE "course_orders" DROP CONSTRAINT "course_orders_signatory_id_user_infos_id_fk";
--> statement-breakpoint
ALTER TABLE "orders" DROP CONSTRAINT "orders_requester_id_user_infos_id_fk";
--> statement-breakpoint
ALTER TABLE "prestation_tags" DROP CONSTRAINT "prestation_tags_prestation_id_prestations_id_fk";
--> statement-breakpoint
DO $$ BEGIN
 ALTER TABLE "course_orders" ADD CONSTRAINT "course_orders_signatory_id_user_infos_id_fk" FOREIGN KEY ("signatory_id") REFERENCES "user_infos"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
 WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
 ALTER TABLE "orders" ADD CONSTRAINT "orders_requester_id_user_infos_id_fk" FOREIGN KEY ("requester_id") REFERENCES "user_infos"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
 WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
 ALTER TABLE "prestation_tags" ADD CONSTRAINT "prestation_tags_prestation_id_prestations_id_fk" FOREIGN KEY ("prestation_id") REFERENCES "prestations"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
 WHEN duplicate_object THEN null;
END $$;

Expected behavior

All the constraints are added in the migration (Missing constraints on companyInfo + prestationId

Environment & setup

Mac OS Node: v20.11.0 Supabase database (Postgres) Driver: pg: "^8.11.5"

AlexBlokh commented 1 month ago

we've checked locally and it works as expected, we think it's related to your drizzle.config.ts file and seems like schema path does not include b/server/database/schemas/prestations.ts file

if you can provide a minimal repro example - would be perfect

noook commented 1 month ago

I have a barrel file reexporting every schema files that can't be it, I'll try to provide the reproduction asap

noook commented 1 month ago

@AlexBlokh You can check the reproduction here: https://github.com/noook/drizzle-fk-reproduction

I have documented the steps in the README, feel free to reach me if something doesn't work as expected. I could reproduce with this repository.

AndriiSherman commented 1 month ago

fixed in drizzle-kit@0.22.0

noook commented 1 month ago

Is drizzle-kit public ? I can't find it, I'm curious about the change