# PostgreSQL Naming Conventions

Standardized naming rules for all database objects in RelSpec PostgreSQL output.

## Quick Reference

| Object Type       | Prefix      | Format                             | Example                  |
| ----------------- | ----------- | ---------------------------------- | ------------------------ |
| Primary Key       | `pk_`       | `pk_<schema>_<table>`              | `pk_public_users`        |
| Foreign Key       | `fk_`       | `fk_<table>_<referenced_table>`    | `fk_posts_users`         |
| Unique Constraint | `uk_`       | `uk_<table>_<column>`              | `uk_users_email`         |
| Unique Index      | `uidx_`     | `uidx_<table>_<column>`            | `uidx_users_email`       |
| Regular Index     | `idx_`      | `idx_<table>_<column>`             | `idx_posts_user_id`      |
| Check Constraint  | `chk_`      | `chk_<table>_<constraint_purpose>` | `chk_users_age_positive` |
| Sequence          | `identity_` | `identity_<table>_<column>`        | `identity_users_id`      |
| Trigger           | `t_`        | `t_<purpose>_<table>`              | `t_audit_users`          |
| Trigger Function  | `tf_`       | `tf_<purpose>_<table>`             | `tf_audit_users`         |

## Naming Rules by Object Type

### Primary Keys

**Pattern:** `pk_<schema>_<table>`

- Include schema name to avoid collisions across schemas
- Use lowercase, snake_case format
- Examples:
  - `pk_public_users`
  - `pk_audit_audit_log`
  - `pk_staging_temp_data`

### Foreign Keys

**Pattern:** `fk_<table>_<referenced_table>`

- Reference the table containing the FK followed by the referenced table
- Use lowercase, snake_case format
- Do NOT include column names in standard FK constraints
- Examples:
  - `fk_posts_users` (posts.user_id → users.id)
  - `fk_comments_posts` (comments.post_id → posts.id)
  - `fk_order_items_orders` (order_items.order_id → orders.id)

### Unique Constraints

**Pattern:** `uk_<table>_<column>`

- Use `uk_` prefix strictly for database constraints (CONSTRAINT type)
- Include column name for clarity
- Examples:
  - `uk_users_email`
  - `uk_users_username`
  - `uk_products_sku`

### Unique Indexes

**Pattern:** `uidx_<table>_<column>`

- Use `uidx_` prefix strictly for index type objects
- Distinguished from constraints for clarity and implementation flexibility
- Examples:
  - `uidx_users_email`
  - `uidx_sessions_token`
  - `uidx_api_keys_key`

### Regular Indexes

**Pattern:** `idx_<table>_<column>`

- Standard indexes for query optimization
- Single column: `idx_<table>_<column>`
- Examples:
  - `idx_posts_user_id`
  - `idx_orders_created_at`
  - `idx_users_status`

### Check Constraints

**Pattern:** `chk_<table>_<constraint_purpose>`

- Describe the constraint validation purpose
- Use lowercase, snake_case for the purpose
- Examples:
  - `chk_users_age_positive` (CHECK (age > 0))
  - `chk_orders_quantity_positive` (CHECK (quantity > 0))
  - `chk_products_price_valid` (CHECK (price >= 0))
  - `chk_users_status_enum` (CHECK (status IN ('active', 'inactive')))

### Sequences

**Pattern:** `identity_<table>_<column>`

- Used for SERIAL/IDENTITY columns
- Explicitly named for clarity and management
- Examples:
  - `identity_users_id`
  - `identity_posts_id`
  - `identity_transactions_id`

### Triggers

**Pattern:** `t_<purpose>_<table>`

- Include purpose before table name
- Lowercase, snake_case format
- Examples:
  - `t_audit_users` (audit trigger on users table)
  - `t_update_timestamp_posts` (timestamp update trigger on posts)
  - `t_validate_orders` (validation trigger on orders)

### Trigger Functions

**Pattern:** `tf_<purpose>_<table>`

- Pair with trigger naming convention
- Use `tf_` prefix to distinguish from triggers themselves
- Examples:
  - `tf_audit_users` (function for t_audit_users)
  - `tf_update_timestamp_posts` (function for t_update_timestamp_posts)
  - `tf_validate_orders` (function for t_validate_orders)

## Multi-Column Objects

### Composite Primary Keys

**Pattern:** `pk_<schema>_<table>`

- Same as single-column PKs
- Example: `pk_public_order_items` (composite key on order_id + item_id)

### Composite Unique Constraints

**Pattern:** `uk_<table>_<column1>_<column2>_[...]`

- Append all column names in order
- Examples:
  - `uk_users_email_domain` (UNIQUE(email, domain))
  - `uk_inventory_warehouse_sku` (UNIQUE(warehouse_id, sku))

### Composite Unique Indexes

**Pattern:** `uidx_<table>_<column1>_<column2>_[...]`

- Append all column names in order
- Examples:
  - `uidx_users_first_name_last_name` (UNIQUE INDEX on first_name, last_name)
  - `uidx_sessions_user_id_device_id` (UNIQUE INDEX on user_id, device_id)

### Composite Regular Indexes

**Pattern:** `idx_<table>_<column1>_<column2>_[...]`

- Append all column names in order
- List columns in typical query filter order
- Examples:
  - `idx_orders_user_id_created_at` (filter by user, then sort by created_at)
  - `idx_logs_level_timestamp` (filter by level, then by timestamp)

## Special Cases & Conventions

### Audit Trail Tables

- Audit table naming: `<original_table>_audit` or `audit_<original_table>`
- Audit indexes follow standard pattern: `idx_<audit_table>_<column>`
- Examples:
  - Users table audit: `users_audit` with `idx_users_audit_tablename`, `idx_users_audit_changedate`
  - Posts table audit: `posts_audit` with `idx_posts_audit_tablename`, `idx_posts_audit_changedate`

### Temporal/Versioning Tables

- Use suffix `_history` or `_versions` if needed
- Apply standard naming rules with the full table name
- Examples:
  - `idx_users_history_user_id`
  - `uk_posts_versions_version_number`

### Schema-Specific Objects

- Always qualify with schema when needed: `pk_<schema>_<table>`
- Multiple schemas allowed: `pk_public_users`, `pk_staging_users`

### Reserved Words & Special Names

- Avoid PostgreSQL reserved keywords in object names
- If column/table names conflict, use quoted identifiers in DDL
- Naming convention rules still apply to the logical name

### Generated/Anonymous Indexes

- If an index lacks explicit naming, default to: `idx_<schema>_<table>`
- Should be replaced with explicit names following standards
- Examples (to be renamed):
  - `idx_public_users` → should be `idx_users_<column>`

## Implementation Notes

### Code Generation

- Names are always lowercase in generated SQL
- Underscore separators are required

### Migration Safety

- Do NOT rename objects after creation without explicit migration
- Names should be consistent across all schema versions
- Test generated DDL against PostgreSQL before deployment

### Testing

- Ensure consistency across all table and constraint generation
- Test with reserved words to verify escaping

## Related Documentation

- PostgreSQL Identifier Rules: https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-IDENTIFIERS
- Constraint Documentation: https://www.postgresql.org/docs/current/ddl-constraints.html
- Index Documentation: https://www.postgresql.org/docs/current/indexes.html
