Many-to-Many Relations in Drizzle ORM
Convert SQL many-to-many junction tables with composite primary keys to Drizzle ORM schema definitions with primaryKey constraints and references.
Detailed Explanation
Many-to-Many Tables in Drizzle
Many-to-many relationships in SQL use a junction table (also called a join table or bridge table) with foreign keys to both related tables. The converter handles these by generating a Drizzle table with composite primary keys and references.
Example SQL
CREATE TABLE students (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL
);
CREATE TABLE courses (
id SERIAL PRIMARY KEY,
title VARCHAR(200) NOT NULL
);
CREATE TABLE enrollments (
student_id INTEGER NOT NULL REFERENCES students(id),
course_id INTEGER NOT NULL REFERENCES courses(id),
enrolled_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (student_id, course_id)
);
Generated Drizzle Schema
import { integer, pgTable, primaryKey, serial, timestamp, varchar } from "drizzle-orm/pg-core";
import { sql } from "drizzle-orm";
export const students = pgTable("students", {
id: serial("id").primaryKey(),
name: varchar("name", { length: 100 }).notNull(),
});
export const courses = pgTable("courses", {
id: serial("id").primaryKey(),
title: varchar("title", { length: 200 }).notNull(),
});
export const enrollments = pgTable("enrollments", {
studentId: integer("student_id").notNull().references(() => students.id),
courseId: integer("course_id").notNull().references(() => courses.id),
enrolledAt: timestamp("enrolled_at").default(sql`CURRENT_TIMESTAMP`),
}, (table) => [
primaryKey({ columns: [table.studentId, table.courseId] }),
]);
Key Points
Composite Primary Key: The
PRIMARY KEY (student_id, course_id)becomes aprimaryKey()constraint in the table's third argument (the constraints callback). TheprimaryKeyfunction must be imported from the dialect module.Foreign Keys: Both foreign key columns get
.references()chains pointing to their respective parent tables.No individual
.primaryKey(): When a composite primary key exists, individual columns do not get the.primaryKey()chain. Instead, the composite constraint is used.Extra columns: Junction tables often have additional columns like
enrolled_atorrole. These are handled normally alongside the key columns.
Adding the Relations API
To use Drizzle's relational query API with many-to-many tables, you would add separate relations() definitions. This is beyond what the SQL converter generates but is the recommended next step after conversion.
Use Case
You have a database with many-to-many relationships implemented through junction tables and need to convert them to Drizzle ORM while preserving the composite primary keys and foreign key references.