Skip to content

Schema Reference ​

This page provides a complete reference for defining database schemas in FlashORM.

Overview ​

FlashORM uses SQL DDL (Data Definition Language) to define your database schema. Schema files are stored in the db/schema/ directory with .sql extension.

Supported Databases ​

FlashORM supports schema definition for:

  • PostgreSQL
  • MySQL
  • SQLite
  • MongoDB (limited schema support)

Basic Table Creation ​

PostgreSQL/MySQL/SQLite ​

sql
CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    email VARCHAR(255) UNIQUE NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

SQLite Specific ​

sql
CREATE TABLE users (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    email TEXT UNIQUE NOT NULL,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

Data Types ​

PostgreSQL ​

SQL TypeGo TypeDescription
SERIALint32Auto-incrementing integer
BIGSERIALint64Auto-incrementing big integer
INTEGERint32Integer
BIGINTint64Big integer
VARCHAR(n)stringVariable length string
TEXTstringUnlimited text
BOOLEANboolTrue/false
TIMESTAMPtime.TimeDate and time
TIMESTAMPTZtime.TimeTimestamp with timezone
DATEtime.TimeDate only
UUIDstringUUID string
JSONinterface{}JSON data
JSONBinterface{}Binary JSON
BYTEA[]byteBinary data

MySQL ​

SQL TypeGo TypeDescription
INT AUTO_INCREMENTint32Auto-incrementing integer
BIGINT AUTO_INCREMENTint64Auto-incrementing big integer
INTint32Integer
BIGINTint64Big integer
VARCHAR(n)stringVariable length string
TEXTstringUnlimited text
TINYINT(1)boolBoolean
DATETIMEtime.TimeDate and time
TIMESTAMPtime.TimeTimestamp
DATEtime.TimeDate only
JSONinterface{}JSON data
BLOB[]byteBinary data

SQLite ​

SQL TypeGo TypeDescription
INTEGER PRIMARY KEYint64Auto-incrementing integer
INTEGERint64Integer
TEXTstringString/text
REALfloat64Floating point
BLOB[]byteBinary data

Constraints ​

Primary Keys ​

sql
-- Single column
CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    name VARCHAR(255)
);

-- Composite primary key
CREATE TABLE user_permissions (
    user_id INTEGER,
    permission_id INTEGER,
    PRIMARY KEY (user_id, permission_id)
);

Foreign Keys ​

sql
CREATE TABLE posts (
    id SERIAL PRIMARY KEY,
    user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
    title VARCHAR(255) NOT NULL,
    content TEXT
);

Unique Constraints ​

sql
-- Single column
CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    email VARCHAR(255) UNIQUE
);

-- Multiple columns
CREATE TABLE user_follows (
    follower_id INTEGER,
    following_id INTEGER,
    UNIQUE(follower_id, following_id)
);

Check Constraints ​

sql
CREATE TABLE products (
    id SERIAL PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    price DECIMAL(10,2) CHECK (price > 0),
    quantity INTEGER CHECK (quantity >= 0)
);

Indexes ​

sql
-- Single column index
CREATE INDEX idx_users_email ON users(email);

-- Composite index
CREATE INDEX idx_posts_user_created ON posts(user_id, created_at);

-- Unique index
CREATE UNIQUE INDEX idx_users_username ON users(username);

-- Partial index
CREATE INDEX idx_active_users ON users(created_at) WHERE active = true;

Enums ​

PostgreSQL ​

sql
CREATE TYPE user_role AS ENUM ('admin', 'moderator', 'user');
CREATE TYPE post_status AS ENUM ('draft', 'published', 'archived');

CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    role user_role NOT NULL DEFAULT 'user'
);

CREATE TABLE posts (
    id SERIAL PRIMARY KEY,
    status post_status NOT NULL DEFAULT 'draft'
);

MySQL ​

sql
CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    role ENUM('admin', 'moderator', 'user') NOT NULL DEFAULT 'user'
);

Views ​

sql
CREATE VIEW active_users AS
SELECT id, name, email
FROM users
WHERE active = true;

CREATE VIEW post_summary AS
SELECT
    p.id,
    p.title,
    u.name as author,
    COUNT(c.id) as comment_count
FROM posts p
JOIN users u ON p.user_id = u.id
LEFT JOIN comments c ON p.id = c.post_id
GROUP BY p.id, p.title, u.name;

Triggers ​

sql
-- PostgreSQL
CREATE OR REPLACE FUNCTION update_updated_at()
RETURNS TRIGGER AS $$
BEGIN
    NEW.updated_at = CURRENT_TIMESTAMP;
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER users_updated_at
    BEFORE UPDATE ON users
    FOR EACH ROW
    EXECUTE FUNCTION update_updated_at();

Schema Organization ​

Multiple Files ​

You can split your schema across multiple files:

db/schema/
├── 001_users.sql
├── 002_posts.sql
├── 003_comments.sql
└── 004_indexes.sql

Naming Convention ​

  • Use descriptive names for tables and columns
  • Use snake_case for SQL identifiers
  • Prefix related tables (e.g., user_posts, user_profiles)
  • Use consistent naming patterns

Advanced Features ​

Partitioning (PostgreSQL) ​

sql
CREATE TABLE logs (
    id SERIAL,
    level VARCHAR(10),
    message TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) PARTITION BY RANGE (created_at);

CREATE TABLE logs_2024_01 PARTITION OF logs
    FOR VALUES FROM ('2024-01-01') TO ('2024-02-01');

Inheritance (PostgreSQL) ​

sql
CREATE TABLE person (
    id SERIAL PRIMARY KEY,
    name VARCHAR(255) NOT NULL
);

CREATE TABLE employee (
    salary DECIMAL(10,2),
    department VARCHAR(100)
) INHERITS (person);

Generated Columns (PostgreSQL/MySQL) ​

sql
CREATE TABLE products (
    id SERIAL PRIMARY KEY,
    name VARCHAR(255),
    price DECIMAL(10,2),
    tax_rate DECIMAL(3,2) DEFAULT 0.08,
    total_price DECIMAL(10,2) GENERATED ALWAYS AS (price * (1 + tax_rate)) STORED
);

Migration Considerations ​

When writing schemas that will be migrated:

  1. Add defaults for new columns
  2. Make columns nullable initially if needed
  3. Use safe operations that can be rolled back
  4. Test migrations on copies of production data

Examples ​

Blog Schema ​

sql
-- Users
CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    username VARCHAR(50) UNIQUE NOT NULL,
    email VARCHAR(255) UNIQUE NOT NULL,
    password_hash VARCHAR(255) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- Categories
CREATE TABLE categories (
    id SERIAL PRIMARY KEY,
    name VARCHAR(100) UNIQUE NOT NULL,
    slug VARCHAR(100) UNIQUE NOT NULL,
    description TEXT
);

-- Posts
CREATE TABLE posts (
    id SERIAL PRIMARY KEY,
    title VARCHAR(255) NOT NULL,
    slug VARCHAR(255) UNIQUE NOT NULL,
    content TEXT NOT NULL,
    excerpt TEXT,
    author_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
    category_id INTEGER REFERENCES categories(id) ON DELETE SET NULL,
    published BOOLEAN DEFAULT FALSE,
    published_at TIMESTAMP,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- Comments
CREATE TABLE comments (
    id SERIAL PRIMARY KEY,
    post_id INTEGER REFERENCES posts(id) ON DELETE CASCADE,
    author_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
    content TEXT NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- Indexes
CREATE INDEX idx_posts_author ON posts(author_id);
CREATE INDEX idx_posts_category ON posts(category_id);
CREATE INDEX idx_posts_published ON posts(published, published_at);
CREATE INDEX idx_comments_post ON comments(post_id);
CREATE INDEX idx_comments_author ON comments(author_id);

E-commerce Schema ​

sql
-- Products
CREATE TABLE products (
    id SERIAL PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    description TEXT,
    price DECIMAL(10,2) NOT NULL CHECK (price > 0),
    sku VARCHAR(100) UNIQUE,
    stock_quantity INTEGER DEFAULT 0 CHECK (stock_quantity >= 0),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- Customers
CREATE TABLE customers (
    id SERIAL PRIMARY KEY,
    email VARCHAR(255) UNIQUE NOT NULL,
    first_name VARCHAR(100),
    last_name VARCHAR(100),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- Orders
CREATE TABLE orders (
    id SERIAL PRIMARY KEY,
    customer_id INTEGER REFERENCES customers(id),
    total_amount DECIMAL(10,2) NOT NULL,
    status VARCHAR(20) DEFAULT 'pending',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- Order Items
CREATE TABLE order_items (
    id SERIAL PRIMARY KEY,
    order_id INTEGER REFERENCES orders(id) ON DELETE CASCADE,
    product_id INTEGER REFERENCES products(id),
    quantity INTEGER NOT NULL CHECK (quantity > 0),
    unit_price DECIMAL(10,2) NOT NULL,
    total_price DECIMAL(10,2) NOT NULL
);

Released under the MIT License.