# DuckDB Flyway (migration manager)
A simple migration manager for DuckDB databases. It's called flyway to follow the obligatory duck-oriented naming conventions.
## Features
- Simple and lightweight Python-based migrations
- Automatic migration discovery from directory
- Transaction safety - each migration runs in its own transaction
- Migration version validation ensures correct ordering
- Customizable logging via standard Python logging
## Installation
```sh
pip install duckdb-flyway
```
## Usage
1. Create a migrations directory in your project. Migration files must:
- Start with 'm'
- End with '.py'
- Export a 'migration' object
- Have unique, sortable IDs (typically timestamps)
```
migrations/
m20240320000001_create_users.py
m20240320000002_add_email.py
```
2. Each migration file should export a `migration` object:
```python
from duckdb_flyway import Migration
from duckdb import DuckDBPyConnection
def run(con: DuckDBPyConnection) -> None:
"""Create the users table.
Args:
con: DuckDB connection to use for the migration.
Transaction management is handled automatically.
"""
con.execute("""
CREATE TABLE users (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
created_at TIMESTAMP DEFAULT now()
);
""")
# ID must be unique and sortable (typically a timestamp)
migration = Migration("20240320000001", run)
```
3. Run migrations in your app:
```python
import duckdb
from duckdb_flyway import DuckDBFlyway, MigrationError
try:
# Connect to your database
con = duckdb.connect("path/to/db.duckdb")
# Create migrations service - migrations_dir is required
flyway = DuckDBFlyway(con, migrations_dir="path/to/migrations")
# Find and run all pending migrations
flyway.find_and_run_migrations()
except MigrationError as e:
print(f"Migration failed: {e}")
# Handle migration failure
```
## How it Works
- Migrations are discovered from Python files in the migrations directory
- Each migration runs in its own transaction for safety
- Migrations are tracked in a `schema_migrations` table
- New migrations must have higher IDs than previously applied ones
- Failed migrations are rolled back automatically
## Development
1. Clone the repository and install dependencies:
```sh
git clone https://github.com/aluxian/duckdb-flyway.git
cd duckdb-flyway
uv venv
source .venv/bin/activate
uv sync
```
2. Run linting checks:
```sh
uv run ruff check .
```
3. Run tests:
```sh
uv run pytest
```
4. Start Aider:
```sh
uvx --python 3.12 --from 'aider-chat[playwright]' --with 'aider-chat[help]' aider
```
Raw data
{
"_id": null,
"home_page": null,
"name": "duckdb-flyway",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.12",
"maintainer_email": null,
"keywords": "database, duckdb, flyway, migrations",
"author": null,
"author_email": "Alexandru Rosianu <me@aluxian.com>",
"download_url": "https://files.pythonhosted.org/packages/fd/21/29be6493d8bec3ec34150a0a62df7e9141ea6a1d41ab54c6501c9a224a65/duckdb_flyway-0.1.1.tar.gz",
"platform": null,
"description": "# DuckDB Flyway (migration manager)\n\nA simple migration manager for DuckDB databases. It's called flyway to follow the obligatory duck-oriented naming conventions.\n\n## Features\n\n- Simple and lightweight Python-based migrations\n- Automatic migration discovery from directory\n- Transaction safety - each migration runs in its own transaction\n- Migration version validation ensures correct ordering\n- Customizable logging via standard Python logging\n\n## Installation\n\n```sh\npip install duckdb-flyway\n```\n\n## Usage\n\n1. Create a migrations directory in your project. Migration files must:\n - Start with 'm'\n - End with '.py'\n - Export a 'migration' object\n - Have unique, sortable IDs (typically timestamps)\n\n```\nmigrations/\n m20240320000001_create_users.py\n m20240320000002_add_email.py\n```\n\n2. Each migration file should export a `migration` object:\n\n```python\nfrom duckdb_flyway import Migration\nfrom duckdb import DuckDBPyConnection\n\ndef run(con: DuckDBPyConnection) -> None:\n \"\"\"Create the users table.\n\n Args:\n con: DuckDB connection to use for the migration.\n Transaction management is handled automatically.\n \"\"\"\n con.execute(\"\"\"\n CREATE TABLE users (\n id INTEGER PRIMARY KEY,\n name TEXT NOT NULL,\n created_at TIMESTAMP DEFAULT now()\n );\n \"\"\")\n\n# ID must be unique and sortable (typically a timestamp)\nmigration = Migration(\"20240320000001\", run)\n```\n\n3. Run migrations in your app:\n\n```python\nimport duckdb\nfrom duckdb_flyway import DuckDBFlyway, MigrationError\n\ntry:\n # Connect to your database\n con = duckdb.connect(\"path/to/db.duckdb\")\n\n # Create migrations service - migrations_dir is required\n flyway = DuckDBFlyway(con, migrations_dir=\"path/to/migrations\")\n\n # Find and run all pending migrations\n flyway.find_and_run_migrations()\n\nexcept MigrationError as e:\n print(f\"Migration failed: {e}\")\n # Handle migration failure\n```\n\n## How it Works\n\n- Migrations are discovered from Python files in the migrations directory\n- Each migration runs in its own transaction for safety\n- Migrations are tracked in a `schema_migrations` table\n- New migrations must have higher IDs than previously applied ones\n- Failed migrations are rolled back automatically\n\n## Development\n\n1. Clone the repository and install dependencies:\n\n```sh\ngit clone https://github.com/aluxian/duckdb-flyway.git\ncd duckdb-flyway\nuv venv\nsource .venv/bin/activate\nuv sync\n```\n\n2. Run linting checks:\n\n```sh\nuv run ruff check .\n```\n\n3. Run tests:\n\n```sh\nuv run pytest\n```\n\n4. Start Aider:\n\n```sh\nuvx --python 3.12 --from 'aider-chat[playwright]' --with 'aider-chat[help]' aider\n```\n",
"bugtrack_url": null,
"license": null,
"summary": "DuckDB migrations tool",
"version": "0.1.1",
"project_urls": {
"Changelog": "https://github.com/aluxian/duckdb-flyway/releases",
"Homepage": "https://github.com/aluxian/duckdb-flyway",
"Issues": "https://github.com/aluxian/duckdb-flyway/issues",
"Repository": "https://github.com/aluxian/duckdb-flyway.git"
},
"split_keywords": [
"database",
" duckdb",
" flyway",
" migrations"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "50559dab36dde33af416270a32192fa222f59d08c7fa09752ac64a5f0e8b54a3",
"md5": "e0490b80e90e7fd99085a9e1967907b2",
"sha256": "4d7e5b0b9ae7b590ed8b55ececaa8ce79c7e1be66bf7c0e1c4c7f74cdfb99229"
},
"downloads": -1,
"filename": "duckdb_flyway-0.1.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "e0490b80e90e7fd99085a9e1967907b2",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.12",
"size": 8312,
"upload_time": "2024-12-22T18:34:44",
"upload_time_iso_8601": "2024-12-22T18:34:44.545011Z",
"url": "https://files.pythonhosted.org/packages/50/55/9dab36dde33af416270a32192fa222f59d08c7fa09752ac64a5f0e8b54a3/duckdb_flyway-0.1.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "fd2129be6493d8bec3ec34150a0a62df7e9141ea6a1d41ab54c6501c9a224a65",
"md5": "04ef94680241d02234e3dc210d689d5d",
"sha256": "266f77737c0f4eaa1697a4c4325882bb795cd4b29f8f4af078a6cbd2968a806f"
},
"downloads": -1,
"filename": "duckdb_flyway-0.1.1.tar.gz",
"has_sig": false,
"md5_digest": "04ef94680241d02234e3dc210d689d5d",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.12",
"size": 13992,
"upload_time": "2024-12-22T18:34:49",
"upload_time_iso_8601": "2024-12-22T18:34:49.434265Z",
"url": "https://files.pythonhosted.org/packages/fd/21/29be6493d8bec3ec34150a0a62df7e9141ea6a1d41ab54c6501c9a224a65/duckdb_flyway-0.1.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-12-22 18:34:49",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "aluxian",
"github_project": "duckdb-flyway",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "duckdb-flyway"
}