name the over-long foreign keys so db:push can be a no-op
Drizzle generates names past Postgres's 63-character identifier limit. Postgres stores the truncated form, drizzle compares against its own longer one, and every push on every host drops and re-adds constraints that are already identical. Deferred as harmless noise since 2026-08-19. What ended that was a deploy plan saying "expect no changes, stop if it wants to alter something" — which this made impossible to satisfy, so the deploy agent had to overrule its own instructions. Verified by pushing twice against a scratch database: the fleet-wide second-push churn went from ten statements to two, and the two that remain are a composite primary key that cannot be fixed either way. Naming a foreign key means removing the inline .references() or drizzle creates both. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { pgTable, uuid, text, timestamp, index, primaryKey } from 'drizzle-orm/pg-core';
|
import { pgTable, uuid, text, timestamp, index, primaryKey, foreignKey} from 'drizzle-orm/pg-core';
|
||||||
import { generations } from '../generations/schema';
|
import { generations } from '../generations/schema';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -29,15 +29,30 @@ export const collections = pgTable('atelier_collections', {
|
|||||||
*/
|
*/
|
||||||
export const collectionItems = pgTable('atelier_collection_items',
|
export const collectionItems = pgTable('atelier_collection_items',
|
||||||
{
|
{
|
||||||
collectionId: uuid('collection_id')
|
collectionId: uuid('collection_id').notNull(),
|
||||||
.notNull()
|
generationId: uuid('generation_id').notNull(),
|
||||||
.references(() => collections.id, { onDelete: 'cascade' }),
|
|
||||||
generationId: uuid('generation_id')
|
|
||||||
.notNull()
|
|
||||||
.references(() => generations.id, { onDelete: 'cascade' }),
|
|
||||||
addedAt: timestamp('added_at', { withTimezone: true }).notNull().defaultNow(),
|
addedAt: timestamp('added_at', { withTimezone: true }).notNull().defaultNow(),
|
||||||
},
|
},
|
||||||
(table) => [
|
(table) => [
|
||||||
|
/*
|
||||||
|
Both foreign keys are NAMED, because drizzle generates names over Postgres's 63-character identifier
|
||||||
|
limit — 65 and 64. Postgres stores the truncated form, drizzle keeps comparing against its own longer
|
||||||
|
one, and every `db:push` drops and re-adds constraints that are already identical. Four statements per
|
||||||
|
push, on every host, for ever.
|
||||||
|
|
||||||
|
It read as harmless noise until a deploy plan said "expect no changes" and this made that impossible
|
||||||
|
to satisfy on all five hosts, forcing the deploy agent to overrule its own instructions.
|
||||||
|
*/
|
||||||
|
foreignKey({
|
||||||
|
name: 'fk_atelier_collection_items_collection',
|
||||||
|
columns: [table.collectionId],
|
||||||
|
foreignColumns: [collections.id],
|
||||||
|
}).onDelete('cascade'),
|
||||||
|
foreignKey({
|
||||||
|
name: 'fk_atelier_collection_items_generation',
|
||||||
|
columns: [table.generationId],
|
||||||
|
foreignColumns: [generations.id],
|
||||||
|
}).onDelete('cascade'),
|
||||||
// The composite key is what makes adding an image twice a no-op instead of a duplicate.
|
// The composite key is what makes adding an image twice a no-op instead of a duplicate.
|
||||||
primaryKey({ columns: [table.collectionId, table.generationId] }),
|
primaryKey({ columns: [table.collectionId, table.generationId] }),
|
||||||
index('atelier_collection_items_generation_idx').on(table.generationId),
|
index('atelier_collection_items_generation_idx').on(table.generationId),
|
||||||
|
|||||||
Reference in New Issue
Block a user