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) <noreply@anthropic.com>
This commit is contained in:
2026-05-09 19:17:58 +02:00
parent 5bed62dc72
commit 4a50bab389
2 changed files with 26 additions and 1 deletions

View File

@@ -8,6 +8,7 @@ import {
jsonb, jsonb,
index, index,
uniqueIndex, uniqueIndex,
type AnyPgColumn,
} from 'drizzle-orm/pg-core'; } from 'drizzle-orm/pg-core';
import { sql } from 'drizzle-orm'; import { sql } from 'drizzle-orm';
import { ports } from './ports'; import { ports } from './ports';
@@ -63,7 +64,9 @@ export const documents = pgTable(
reservationId: text('reservation_id').references(() => berthReservations.id, { reservationId: text('reservation_id').references(() => berthReservations.id, {
onDelete: 'set null', 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 documentType: text('document_type').notNull(), // eoi, contract, nda, reservation_agreement, other
title: text('title').notNull(), title: text('title').notNull(),
status: text('status').notNull().default('draft'), // draft, sent, partially_signed, completed, expired, cancelled 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') portId: text('port_id')
.notNull() .notNull()
.references(() => ports.id), .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'), parentId: text('parent_id'),
name: text('name').notNull(), name: text('name').notNull(),
createdBy: text('created_by').notNull(), createdBy: text('created_by').notNull(),

View File

@@ -50,6 +50,7 @@ import { berthReservations } from './reservations';
import { import {
files, files,
documents, documents,
documentFolders,
documentSigners, documentSigners,
documentEvents, documentEvents,
documentTemplates, documentTemplates,
@@ -569,6 +570,10 @@ export const documentsRelations = relations(documents, ({ one, many }) => ({
fields: [documents.reservationId], fields: [documents.reservationId],
references: [berthReservations.id], references: [berthReservations.id],
}), }),
folder: one(documentFolders, {
fields: [documents.folderId],
references: [documentFolders.id],
}),
signers: many(documentSigners), signers: many(documentSigners),
events: many(documentEvents), events: many(documentEvents),
watchers: many(documentWatchers), 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 ──────────────────────────────────────────────────────────────── // ─── Financial ────────────────────────────────────────────────────────────────
export const expensesRelations = relations(expenses, ({ one, many }) => ({ export const expensesRelations = relations(expenses, ({ one, many }) => ({