From 4a50bab389f00687ef673a77bdecbc8a1d7aad6f Mon Sep 17 00:00:00 2001 From: Matt Date: Sat, 9 May 2026 19:17:58 +0200 Subject: [PATCH] fix(documents): wire folder Drizzle .references() + relations Code-review followups on 5bed62d. Adds the missing .references() on documents.folder_id (lazy AnyPgColumn form to forward-reference documentFolders, which is declared later in the same file) so a future db:generate run doesn't silently drift the schema. Adds documentFoldersRelations and a folder leg on documentsRelations so Task 2's service layer can use Drizzle's relational query API for parent/children/documents traversal. Inline WHY comment on the parentId column. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/lib/db/schema/documents.ts | 8 +++++++- src/lib/db/schema/relations.ts | 19 +++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/lib/db/schema/documents.ts b/src/lib/db/schema/documents.ts index 0242f2d3..acfb9f16 100644 --- a/src/lib/db/schema/documents.ts +++ b/src/lib/db/schema/documents.ts @@ -8,6 +8,7 @@ import { jsonb, index, uniqueIndex, + type AnyPgColumn, } from 'drizzle-orm/pg-core'; import { sql } from 'drizzle-orm'; import { ports } from './ports'; @@ -63,7 +64,9 @@ export const documents = pgTable( reservationId: text('reservation_id').references(() => berthReservations.id, { onDelete: 'set null', }), - folderId: text('folder_id'), + folderId: text('folder_id').references((): AnyPgColumn => documentFolders.id, { + onDelete: 'set null', + }), documentType: text('document_type').notNull(), // eoi, contract, nda, reservation_agreement, other title: text('title').notNull(), status: text('status').notNull().default('draft'), // draft, sent, partially_signed, completed, expired, cancelled @@ -282,6 +285,9 @@ export const documentFolders = pgTable( portId: text('port_id') .notNull() .references(() => ports.id), + // Null = root. ON DELETE NO ACTION on the FK (added by migration + // 0050) — the service bubbles children up to the deleted folder's + // parent in a transaction instead of cascading. parentId: text('parent_id'), name: text('name').notNull(), createdBy: text('created_by').notNull(), diff --git a/src/lib/db/schema/relations.ts b/src/lib/db/schema/relations.ts index bedbf24a..357dbfb8 100644 --- a/src/lib/db/schema/relations.ts +++ b/src/lib/db/schema/relations.ts @@ -50,6 +50,7 @@ import { berthReservations } from './reservations'; import { files, documents, + documentFolders, documentSigners, documentEvents, documentTemplates, @@ -569,6 +570,10 @@ export const documentsRelations = relations(documents, ({ one, many }) => ({ fields: [documents.reservationId], references: [berthReservations.id], }), + folder: one(documentFolders, { + fields: [documents.folderId], + references: [documentFolders.id], + }), signers: many(documentSigners), events: many(documentEvents), watchers: many(documentWatchers), @@ -634,6 +639,20 @@ export const formSubmissionsRelations = relations(formSubmissions, ({ one }) => }), })); +export const documentFoldersRelations = relations(documentFolders, ({ one, many }) => ({ + port: one(ports, { + fields: [documentFolders.portId], + references: [ports.id], + }), + parent: one(documentFolders, { + fields: [documentFolders.parentId], + references: [documentFolders.id], + relationName: 'parent_child', + }), + children: many(documentFolders, { relationName: 'parent_child' }), + documents: many(documents), +})); + // ─── Financial ──────────────────────────────────────────────────────────────── export const expensesRelations = relations(expenses, ({ one, many }) => ({