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
24.72k stars 653 forks source link

[BUG]: unclear how to correctly define mutual foreign keys (introspection creates invalid schema) #2993

Open fnimick opened 2 months ago

fnimick commented 2 months ago

What version of drizzle-orm are you using?

0.33.0

What version of drizzle-kit are you using?

0.24.2

Describe the Bug

Defining tables with foreign keys to each other causes drizzle-kit to output schema that does not type-check.

The following postgres schema:

create schema drizzle_test;

create table drizzle_test.child (
    id uuid primary key default uuid_generate_v4(),
    other_id uuid not null
);

create table drizzle_test.parent (
    id uuid primary key default uuid_generate_v4(),
    other_id uuid not null,
    child_id uuid unique references drizzle_test.child (id) on delete restrict,
    unique (other_id, child_id)
);

alter table drizzle_test.child add constraint test_key
foreign key (other_id, id)
references drizzle_test.parent (other_id, child_id);

generates the following schema from introspection:

import { sql } from "drizzle-orm";
import { foreignKey, pgSchema, pgTable, unique, uuid, type AnyPgColumn } from "drizzle-orm/pg-core";

export const drizzleTest = pgSchema("drizzle_test");

export const childInDrizzleTest = drizzleTest.table(
  "child",
  {
    id: uuid("id")
      .default(sql`uuid_generate_v4()`)
      .primaryKey()
      .notNull(),
    parentId: uuid("parent_id").notNull(),
  },
  (table) => {
    return {
      testKey: foreignKey({
        columns: [table.parentId],
        foreignColumns: [parentInDrizzleTest.id],
        name: "test_key",
      }),
    };
  },
);

export const parentInDrizzleTest = drizzleTest.table(
  "parent",
  {
    id: uuid("id")
      .default(sql`uuid_generate_v4()`)
      .primaryKey()
      .notNull(),
    childId: uuid("child_id"),
  },
  (table) => {
    return {
      parentChildIdFkey: foreignKey({
        columns: [table.childId],
        foreignColumns: [childInDrizzleTest.id],
        name: "parent_child_id_fkey",
      }),
      parentChildIdKey: unique("parent_child_id_key").on(table.childId),
    };
  },
);

This fails to type-check due to the table definitions referencing each other in the extraConfig function.

Expected behavior

Either introspect generates correct schema, or introspect does not generate foreign keys that would cause reference loops.

In addition, documentation on how to handle this when defining schema would be welcome.

Environment & setup

  System:
    OS: macOS 15.0
    CPU: (10) arm64 Apple M1 Pro
    Memory: 117.55 MB / 16.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 20.13.1 - ~/.asdf/installs/nodejs/20.13.1/bin/node
    Yarn: 1.22.19 - ~/.yarn/bin/yarn
    npm: 10.5.2 - ~/.asdf/plugins/nodejs/shims/npm
    pnpm: 9.7.0 - ~/.asdf/shims/pnpm
  npmPackages:
    drizzle-kit: ^0.24.2 => 0.24.2 
    drizzle-orm: ^0.33.0 => 0.33.0 
raikusy commented 1 month ago

Facing same issue! It was working on previous versions... :'(