feat: add schema-constraints reference for safe migration patterns (#30)

* feat: add schema-constraints reference for safe migration patterns

Documents correct approaches for adding constraints in PostgreSQL migrations,
since ADD CONSTRAINT IF NOT EXISTS is not supported and causes syntax errors.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* Remove additional correct options

---------

Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Tomás Pozo
2026-02-10 12:14:38 -05:00
committed by GitHub
parent 0d88c8a3e4
commit 9b236f3ebd
2 changed files with 82 additions and 1 deletions

View File

@@ -74,6 +74,7 @@ Reference files are named `{prefix}-{topic}.md` (e.g., `query-missing-indexes.md
- `references/query-partial-indexes.md`
**Schema Design** (`schema-`):
- `references/schema-constraints.md`
- `references/schema-data-types.md`
- `references/schema-foreign-key-indexes.md`
- `references/schema-lowercase-identifiers.md`
@@ -87,4 +88,4 @@ Reference files are named `{prefix}-{topic}.md` (e.g., `query-missing-indexes.md
---
*30 reference files across 8 categories*
*31 reference files across 8 categories*

View File

@@ -0,0 +1,80 @@
---
title: Add Constraints Safely in Migrations
impact: HIGH
impactDescription: Prevents migration failures and enables idempotent schema changes
tags: constraints, migrations, schema, alter-table
---
## Add Constraints Safely in Migrations
PostgreSQL does not support `ADD CONSTRAINT IF NOT EXISTS`. Migrations using this syntax will fail.
**Incorrect (causes syntax error):**
```sql
-- ERROR: syntax error at or near "not" (SQLSTATE 42601)
alter table public.profiles
add constraint if not exists profiles_birthchart_id_unique unique (birthchart_id);
```
**Correct (idempotent constraint creation):**
```sql
-- Use DO block to check before adding
do $$
begin
if not exists (
select 1 from pg_constraint
where conname = 'profiles_birthchart_id_unique'
and conrelid = 'public.profiles'::regclass
) then
alter table public.profiles
add constraint profiles_birthchart_id_unique unique (birthchart_id);
end if;
end $$;
```
For all constraint types:
```sql
-- Check constraints
do $$
begin
if not exists (
select 1 from pg_constraint
where conname = 'check_age_positive'
) then
alter table users add constraint check_age_positive check (age > 0);
end if;
end $$;
-- Foreign keys
do $$
begin
if not exists (
select 1 from pg_constraint
where conname = 'profiles_birthchart_id_fkey'
) then
alter table profiles
add constraint profiles_birthchart_id_fkey
foreign key (birthchart_id) references birthcharts(id);
end if;
end $$;
```
Check if constraint exists:
```sql
-- Query to check constraint existence
select conname, contype, pg_get_constraintdef(oid)
from pg_constraint
where conrelid = 'public.profiles'::regclass;
-- contype values:
-- 'p' = PRIMARY KEY
-- 'f' = FOREIGN KEY
-- 'u' = UNIQUE
-- 'c' = CHECK
```
Reference: [Constraints](https://www.postgresql.org/docs/current/ddl-constraints.html)