home / skills / odjaramillo / custom-rules / style-guide

style-guide skill

/packages/cli/.agent/skills/style-guide

npx playbooks add skill odjaramillo/custom-rules --skill style-guide

Review the files below or copy the command above to add this skill to your agents.

Files (1)
SKILL.md
6.2 KB
---
name: style-guide
description: >
  SQL Naming, Formatting, and Style Guide
  Trigger: When following database naming conventions.
license: Apache-2.0
metadata:
  author: poletron
  version: "1.0"
  scope: [root]
  auto_invoke: "Working with style guide"

## When to Use

Use this skill when:
- Writing SQL scripts or migrations
- Naming database objects (tables, columns, indexes)
- Formatting queries for readability
- Creating reference implementations

---

## Decision Tree

```
Need table name?           → UPPER_SNAKE_CASE, singular
Need column name?          → lower_snake_case
Need boolean column?       → Prefix with is_, has_, can_
Need index name?           → idx_table_columns
Need constraint name?      → pk_, fk_, uq_, ck_ prefixes
```

---

# SQL Style Guide

To ensure maintainability, readability, and consistency across database projects, follow these styling and naming conventions.

## 1. Naming Conventions

### 1.1 Tables
- **Case:** Use `UPPER_SNAKE_CASE` or `PascalCase` consistently. (Standard: `UPPER_SNAKE_CASE` for SQL compatibility).
- **Plurality:** Use **Singular** names for entities to represent the definition of a single record (e.g., `USER`, `ORDER`, not `USERS`).
- **Prefixes:** Avoid Hungarian notation (e.g., `tbl_User`).
- **Junction Tables:** Combine names of related tables (e.g., `USER_ROLE`).

### 1.2 Columns
- **Case:** Use `lower_snake_case`.
- **Clarity:** Names should be descriptive (e.g., `created_at` instead of `date`).
- **Booleans:** Prefix with `is_`, `has_`, or `can_` (e.g., `is_active`).
- **Foreign Keys:** Use `fk_<target_table_id>` or `<target_table>_id` consistently.

### 1.3 Keys & Constraints
Explicitly name all constraints to facilitate debugging.
- **Primary Keys:** `pk_<table_name>`
- **Foreign Keys:** `fk_<source>_<target>`
- **Unique:** `uq_<table_name>_<columns>`
- **Check:** `ck_<table_name>_<condition_description>`

### 1.4 Database Objects
- **Views:** Prefix with `v_` or `vw_`.
- **Materialized Views:** Prefix with `mv_`.
- **Functions:** Prefix with `fn_` (e.g., `fn_calculate_tax`).
- **Procedures:** Prefix with `sp_` (Stored Procedure) (e.g., `sp_archive_orders`).
- **Triggers:** Prefix with `trg_` followed by timing (e.g., `trg_users_before_insert`).
- **Indexes:** Prefix with `idx_` followed by table and columns (e.g., `idx_employee_organization_id`).

## 2. Formatting

### 2.1 Keywords
- Write all SQL keywords in **UPPERCASE** (e.g., `SELECT`, `FROM`, `WHERE`).

### 2.2 Indentation
- Use 4 spaces for indentation.
- Align clauses for readability.

```sql
SELECT
    u.id,
    u.email,
    COUNT(o.id) AS total_orders
FROM USER u
LEFT JOIN ORDER o ON u.id = o.user_id
WHERE
    u.is_active = TRUE
GROUP BY
    u.id,
    u.email;
```

### 2.3 Comments
- Use `--` for single-line comments.
- Use `/* ... */` for multi-line block comments.
- **Header:** Every script/procedure must have a header documenting Author, Date, and Purpose.

```sql
-- =============================================================================
-- PURPOSE: Calculates monthly recurring revenue
-- AUTHOR:  [Name]
-- DATE:    YYYY-MM-DD
-- =============================================================================
```

## 3. Best Practices
- **No `SELECT *`:** Always specify columns explicitly to avoid breaking changes when schemas evolve.
- **Aliases:** Use short, meaningful aliases for tables (e.g., `u` for `USER`).
- **Termination:** Always terminate statements with a semicolon `;`.

## 4. Reference Implementation

Below is an example schema that demonstrates the application of these Style, Design, and Security rules.

```sql
-- =============================================================================
-- SCRIPT: Example Schema
-- PURPOSE: Demonstrates the application of custom-rules/database standards.
-- =============================================================================

-- 1. Table Creation (Style Guide: UPPER_SNAKE_CASE, Singular)
-- Design Pattern: Surrogate PK, text type usage.
CREATE TABLE ORGANIZATION (
    id SERIAL PRIMARY KEY,
    name TEXT NOT NULL,
    tax_id VARCHAR(50) NOT NULL,
    is_active BOOLEAN DEFAULT TRUE,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    
    -- Explicit Constraint Naming
    CONSTRAINT uq_organization_tax_id UNIQUE (tax_id),
    CONSTRAINT ck_organization_name_len CHECK (LENGTH(name) > 0)
);

-- 2. Child Table with Foreign Key
CREATE TABLE EMPLOYEE (
    id SERIAL PRIMARY KEY,
    organization_id INT NOT NULL,
    email VARCHAR(255) NOT NULL,
    full_name TEXT NOT NULL,
    salary DECIMAL(10, 2) CHECK (salary >= 0),
    
    -- Foreign Key with Indexing (to be added below)
    CONSTRAINT fk_employee_organization FOREIGN KEY (organization_id) REFERENCES ORGANIZATION(id)
);

-- 3. Indexing (Efficiency Pattern)
-- Index FKs
CREATE INDEX idx_employee_organization_id ON EMPLOYEE(organization_id);
-- Index Searchable fields
CREATE INDEX idx_employee_email ON EMPLOYEE(email);

-- 4. Junction Table (N:M Relationship)
CREATE TABLE PROJECT (
    id SERIAL PRIMARY KEY,
    name TEXT NOT NULL
);

CREATE TABLE EMPLOYEE_ASSIGNMENT (
    employee_id INT NOT NULL,
    project_id INT NOT NULL,
    assigned_at TIMESTAMP DEFAULT NOW(),
    
    PRIMARY KEY (employee_id, project_id),
    CONSTRAINT fk_assignment_employee FOREIGN KEY (employee_id) REFERENCES EMPLOYEE(id),
    CONSTRAINT fk_assignment_project FOREIGN KEY (project_id) REFERENCES PROJECT(id)
);

-- 5. Stored Procedure (Logic Guidelines)
-- Header, idempotent, error handling
CREATE OR REPLACE PROCEDURE sp_register_employee(
    p_org_id INT,
    p_email VARCHAR,
    p_name VARCHAR
)
LANGUAGE plpgsql
AS $$
BEGIN
    -- Validation
    IF NOT EXISTS (SELECT 1 FROM ORGANIZATION WHERE id = p_org_id) THEN
        RAISE EXCEPTION 'Organization % does not exist', p_org_id;
    END IF;

    -- Insertion
    INSERT INTO EMPLOYEE (organization_id, email, full_name)
    VALUES (p_org_id, p_email, p_name);
    
    -- Transaction control is implicit in procedures if needed, or controlled by caller.
    
EXCEPTION
    WHEN unique_violation THEN
        RAISE NOTICE 'Employee % already registered.', p_email;
END;
$$;

-- 6. RLS (Security Guidelines)
ALTER TABLE EMPLOYEE ENABLE ROW LEVEL SECURITY;

CREATE POLICY employee_isolation_policy ON EMPLOYEE
FOR ALL
USING (organization_id = current_setting('app.current_org_id')::INT);
```