Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
199fff8
Added make_migrations and migrations
emiliano-gandini-outeda Feb 3, 2026
1522a9d
Model Paths
emiliano-gandini-outeda Feb 3, 2026
295e81d
Create make_migrations.py
emiliano-gandini-outeda Feb 3, 2026
73ef033
Create model_discovery.py
emiliano-gandini-outeda Feb 3, 2026
3d4caf2
Create schema_diff.py
emiliano-gandini-outeda Feb 3, 2026
631eeb0
Create schema_introspection.py
emiliano-gandini-outeda Feb 3, 2026
8cb5d8b
Create sql_generator.py
emiliano-gandini-outeda Feb 3, 2026
3ab6a2f
Update README.md
emiliano-gandini-outeda Feb 3, 2026
cd6ff24
Tests
emiliano-gandini-outeda Feb 3, 2026
c06b9db
Auto resolve Paths
emiliano-gandini-outeda Feb 4, 2026
37bf373
Update make_migrations.py
emiliano-gandini-outeda Feb 4, 2026
1785c7c
Update new.py
emiliano-gandini-outeda Feb 4, 2026
031a551
Update rollback.py
emiliano-gandini-outeda Feb 4, 2026
44d7f71
Update status.py to allow running everywhere
emiliano-gandini-outeda Feb 4, 2026
281ee02
Update validators.py
emiliano-gandini-outeda Feb 4, 2026
8162c86
Update config.py
emiliano-gandini-outeda Feb 4, 2026
bdef28b
Added Async Support
emiliano-gandini-outeda Feb 4, 2026
6eab29d
Create jetbase_locator.py
emiliano-gandini-outeda Feb 4, 2026
69f8e56
Update model_discovery.py
emiliano-gandini-outeda Feb 4, 2026
533b888
Auto path
emiliano-gandini-outeda Feb 4, 2026
7b8e68b
Update lock_repo.py
emiliano-gandini-outeda Feb 4, 2026
59e108b
Update migrations_repo.py
emiliano-gandini-outeda Feb 4, 2026
45b216c
tests
emiliano-gandini-outeda Feb 4, 2026
a385fd9
Update README.md
emiliano-gandini-outeda Feb 4, 2026
39f4cc8
Create test_connection.py
emiliano-gandini-outeda Feb 4, 2026
ded403b
Update make_migrations.py
emiliano-gandini-outeda Feb 4, 2026
91a0593
Update config.py
emiliano-gandini-outeda Feb 4, 2026
e712f17
Update connection.py
emiliano-gandini-outeda Feb 4, 2026
3949dad
Update pyproject.toml
emiliano-gandini-outeda Feb 4, 2026
b789cef
Fixed SQL query
emiliano-gandini-outeda Feb 4, 2026
1d9c89b
Docs update!
emiliano-gandini-outeda Feb 4, 2026
609fd3e
Better env.py handling
emiliano-gandini-outeda Feb 4, 2026
fe11d54
Doc update!
emiliano-gandini-outeda Feb 4, 2026
bc8b1c6
Forgot to remove upgrade from --help and docs
emiliano-gandini-outeda Feb 4, 2026
7755bc7
Fixed migrations folder creating elsewhere
emiliano-gandini-outeda Feb 4, 2026
f560983
SQLite FK limitation fix
emiliano-gandini-outeda Feb 4, 2026
b61e8bf
Updated Dependencies
emiliano-gandini-outeda Feb 4, 2026
3e196d7
Fix
emiliano-gandini-outeda Feb 5, 2026
cdb6a5f
Fixed a bug
emiliano-gandini-outeda Feb 5, 2026
759b11b
fix: sync is_async_enabled() with async_mode from env.py
emiliano-gandini-outeda Feb 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
417 changes: 406 additions & 11 deletions README.md

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions docs/advanced/migration-locking.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
# Migration Locking

Suppose two developers or AI agents both run `jetbase upgrade` at the same time.
Suppose two developers or AI agents both run `jetbase migrate` at the same time.

Without any locking, both processes could try to change the database together. This might cause errors, data corruption, or broken migrations.

Jetbase solves this with **automatic migration locking**. Only one process can run migrations at a time.
Jetbase solves this with **automatic migration locking**. Only one process can run migrations at a time.

## What Is Migration Locking?

When you run `jetbase upgrade`, Jetbase grabs a lock before touching your database. Think of it like putting a "Do Not Disturb" sign on your migrations. No other process can run migrations until the first one finishes.
When you run `jetbase migrate`, Jetbase grabs a lock before touching your database. Think of it like putting a "Do Not Disturb" sign on your migrations. No other process can run migrations until the first one finishes.

Jetbase automatically acquires a lock whenever you run any command that might modify the `jetbase_migrations` table. This includes commands like `jetbase upgrade`, `jetbase rollback`, and all `fix` operations. By doing this, Jetbase ensures that your migrations always run safely without any risk of collision.
Jetbase automatically acquires a lock whenever you run any command that might modify the `jetbase_migrations` table. This includes commands like `jetbase migrate`, `jetbase rollback`, and all `fix` operations. By doing this, Jetbase ensures that your migrations always run safely without any risk of collision.

You shouldn't need to think about locking at all! With Jetbase, it just works out of the box!

Expand Down Expand Up @@ -119,10 +119,10 @@ Unlock successful.

```bash
# Server 1
jetbase upgrade # Acquires lock, runs migrations...
jetbase migrate # Acquires lock, runs migrations...

# Server 2 (at the same time)
jetbase upgrade # Fails immediately with "Lock is already held"
jetbase migrate # Fails immediately with "Lock is already held"
```

Server 2 gets a clear error. No corruption, no race conditions.
Expand Down
4 changes: 2 additions & 2 deletions docs/advanced/migration-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -211,14 +211,14 @@ ROC__order_functions.sql # Just edit this file

## Execution Order

When you run `jetbase upgrade`, migrations execute in this order:
When you run `jetbase migrate`, migrations execute in this order:

1. **Versioned migrations** — In version order (oldest first)
2. **Repeatable On Change** — Files that have changed
3. **Repeatable Always** — All RA files

```
[Upgrade Start]
[Migrate Start]
├── V20251225.100000__create_users.sql
├── V20251225.110000__create_orders.sql
Expand Down
44 changes: 31 additions & 13 deletions docs/commands/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,20 @@ Jetbase provides a set of intuitive commands to manage your database migrations.
| Command | Description |
| --------------------------------------------- | ------------------------------------------------------------------ |
| [`init`](init.md) | Initialize Jetbase in current directory |
| [`new`](new.md) | Create a new migration file |
| [`upgrade`](upgrade.md) | Apply pending migrations |
| [`rollback`](rollback.md) | Undo migrations |
| [`new`](new.md) | Create a new manual migration file |
| [`make-migrations`](make-migrations.md) | Auto-generate SQL from SQLAlchemy models |
| [`migrate`](upgrade.md) | Apply pending migrations |
| [`rollback`](rollback.md) | Undo migrations |
| [`status`](status.md) | Show migration status of all migration files (applied vs. pending) |
| [`history`](history.md) | Show migration history |
| [`current`](current.md) | Show latest version migrated |
| [`lock-status`](lock-status.md) | Check if migrations are locked |
| [`unlock`](unlock.md) | Remove migration lock |
| [`history`](history.md) | Show migration history |
| [`current`](current.md) | Show latest version migrated |
| [`lock-status`](lock-status.md) | Check if migrations are locked |
| [`unlock`](unlock.md) | Remove migration lock |
| [`validate-checksums`](validate-checksums.md) | Verify migration file integrity |
| [`validate-files`](validate-files.md) | Check for missing migration files |
| [`fix`](fix.md) | Fix migration issues |
| [`fix`](fix.md) | Fix migration issues |
| [`fix-files`](validate-files.md) | Fix missing migration files (same as `validate-files --fix`) |
| [`fix-checksums`](validate-checksums.md) | Fix migration file checksums (same as `validate-checksums --fix`) |
| [`fix-checksums`](validate-checksums.md) | Fix migration file checksums (same as `validate-checksums --fix`) |

## Command Categories

Expand All @@ -33,8 +34,9 @@ Commands to initialize and set up your migration environment:

Commands to create and run migrations:

- **[`new`](new.md)** — Generate a new migration file
- **[`upgrade`](upgrade.md)** — Apply pending migrations to the database
- **[`new`](new.md)** — Generate a new manual migration file
- **[`make-migrations`](make-migrations.md)** — Auto-generate SQL from SQLAlchemy models
- **[`migrate`](upgrade.md)** — Apply pending migrations to the database
- **[`rollback`](rollback.md)** — Undo one or more migrations

### 📊 Status Commands
Expand Down Expand Up @@ -66,6 +68,22 @@ Every command has a `--help` option:

```bash
jetbase --help # General help
jetbase upgrade --help # Help for upgrade command
jetbase rollback --help # Help for rollback command
jetbase migrate --help # Help for migrate command
jetbase make-migrations --help # Help for make-migrations command
```

!!! tip "Running Jetbase"
If you encounter errors, run Jetbase using your project's Python environment:
```bash
uv run jetbase migrate
```

## Choosing the Right Command

| Scenario | Recommended Command |
|----------|---------------------|
| Manual SQL migration | [`new`](new.md) |
| Generate from SQLAlchemy models | [`make-migrations`](make-migrations.md) |
| Apply pending migrations | [`migrate`](upgrade.md) |
| Undo last migration | [`rollback`](rollback.md) |
| See what's been applied | [`status`](status.md) |
2 changes: 1 addition & 1 deletion docs/commands/init.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ cd jetbase
jetbase new "create users table" -v 1

# 5. Apply migrations
jetbase upgrade
jetbase migrate
```

## Notes
Expand Down
261 changes: 261 additions & 0 deletions docs/commands/make-migrations.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,261 @@
# jetbase make-migrations

Automatically generate SQL migration files from your SQLAlchemy model definitions.

## Usage

```bash
jetbase make-migrations [OPTIONS]
```

## Description

The `make-migrations` command automatically generates SQL migration files by:

1. **Discovering models** - Finds SQLAlchemy models from configured paths
2. **Introspecting database** - Reads your current database schema
3. **Comparing schemas** - Identifies differences between models and database
4. **Generating SQL** - Creates upgrade and rollback statements
5. **Writing migration file** - Saves the migration to `jetbase/migrations/`

## Options

| Option | Required | Description |
|--------|----------|-------------|
| `-d`, `--description` | No | Description for the migration (default: "auto_generated") |

## Arguments

This command has no positional arguments.

## How It Works

### Step 1: Model Discovery

Jetbase finds your SQLAlchemy models using one of these methods:

**Auto-discovery** (recommended):
```
your-project/
├── models/
│ ├── user.py
│ ├── post.py
│ └── __init__.py
└── jetbase/
```

**Explicit configuration** via `JETBASE_MODELS`:
```bash
export JETBASE_MODELS="./models/user.py,./models/post.py"
```

**Or in env.py**:
```python
# jetbase/env.py
model_paths = ["./models/user.py", "./models/post.py"]
```

### Step 2: Database Introspection

Jetbase connects to your database and reads the current schema.

### Step 3: Schema Comparison

Jetbase compares your models against the database to detect:
- New tables to create
- New columns to add
- Tables/columns to remove
- New indexes
- New foreign keys

### Step 4: SQL Generation

Jetbase generates appropriate SQL for each change.

### Step 5: File Creation

Creates a migration file in `jetbase/migrations/`.

## Prerequisites

### Create SQLAlchemy Models

Your models must use declarative base:

```python
# models.py
from sqlalchemy import Column, Integer, String, ForeignKey
from sqlalchemy.orm import declarative_base

Base = declarative_base()

class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True)
email = Column(String(255), nullable=False, unique=True)
name = Column(String(100))


class Post(Base):
__tablename__ = "posts"
id = Column(Integer, primary_key=True)
title = Column(String(255), nullable=False)
user_id = Column(Integer, ForeignKey("users.id"), nullable=False)
```

## Supported Operations

| Operation | Upgrade SQL | Rollback SQL |
|-----------|-------------|--------------|
| New table | `CREATE TABLE` | `DROP TABLE` |
| New column | `ALTER TABLE ADD COLUMN` | `ALTER TABLE DROP COLUMN` |
| New index | `CREATE INDEX` | `DROP INDEX` |
| New unique index | `CREATE UNIQUE INDEX` | `DROP INDEX` |
| New foreign key | `ALTER TABLE ADD CONSTRAINT` | `ALTER TABLE DROP CONSTRAINT` |

## Examples

### Basic Usage

```bash
jetbase make-migrations
```

Output:

```
Created migration file: V20260204.120000__auto_generated.sql
```

### With Custom Description

```bash
jetbase make-migrations --description "add user profile"
```

Output:

```
Created migration file: V20260204.120000__add_user_profile.sql
```

## Generated File Example

Input models:

```python
class Category(Base):
__tablename__ = "categories"
id = Column(Integer, primary_key=True)
name = Column(String(100), nullable=False)
slug = Column(String(100), unique=True)


class Article(Base):
__tablename__ = "articles"
id = Column(Integer, primary_key=True)
title = Column(String(255), nullable=False)
content = Column(String)
category_id = Column(Integer, ForeignKey("categories.id"), nullable=False)
```

Generated migration:

```sql
-- upgrade

CREATE TABLE categories (
id INTEGER NOT NULL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
slug VARCHAR(100)
);

CREATE UNIQUE INDEX uniq_categories_slug ON categories (slug);

CREATE TABLE articles (
id INTEGER NOT NULL PRIMARY KEY,
title VARCHAR(255) NOT NULL,
content TEXT,
category_id INTEGER NOT NULL,
CONSTRAINT fk_article_category FOREIGN KEY (category_id) REFERENCES categories (id)
);

CREATE INDEX ix_articles_category_id ON articles (category_id);


-- rollback

DROP INDEX ix_articles_category_id ON articles;

DROP TABLE articles;

DROP UNIQUE INDEX uniq_categories_slug ON categories;

DROP TABLE categories;
```

## Apply the Migration

```bash
jetbase migrate
```

## Configuration

### Environment Variables

| Variable | Description |
|----------|-------------|
| `JETBASE_MODELS` | Comma-separated paths to SQLAlchemy model files |
| `ASYNC` | Enable async mode (`true`/`false`, default: `false`) |

### Model Path Configuration

=== "Auto-discovery (Recommended)"
Place your models in `models/` or `model/` directory:
```
your-project/
├── models/
│ ├── user.py
│ └── post.py
└── jetbase/
```

=== "Environment Variable"
```bash
export JETBASE_MODELS="./models/user.py,./models/post.py"
```

=== "env.py Configuration"
```python
# jetbase/env.py
model_paths = ["./models/user.py", "./models/post.py"]
```

## Async Mode

The `make-migrations` command respects the `ASYNC` environment variable:

```bash
# Sync mode (default)
jetbase make-migrations

# Async mode
ASYNC=true jetbase make-migrations
```

When `ASYNC=true`, Jetbase uses async database connections for introspection.

## Notes

- Jetbase compares models against the **actual database**, not against previous migrations
- Models must use `declarative_base()` from SQLAlchemy
- The `__tablename__` attribute is required
- Foreign keys require `ForeignKey` imports from SQLAlchemy
- Migration files are saved to `jetbase/migrations/`

## See Also

- [Writing Migrations](../migrations/writing-migrations.md)
- [Commands Reference](index.md)
- [Configuration](../configuration.md)
Loading