Skip to content

Commit bc915a3

Browse files
Add test structure for Alembic migrations (#399)
### Description Testing migrations will allow to: - make sure that our migrations are valid, and usable with sqlite - see if SQLAlchemy models differ from the database structure constructed by running all migrations - make sure we don't have diverging head ### Checklist - [x] Created tests which fail without the change (if possible) - [x] All tests passing - [x] Extended the documentation, if necessary
1 parent ae39dbf commit bc915a3

20 files changed

+588
-462
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,7 @@ logs/
2727

2828
# Pytest-cov
2929
.coverage
30+
31+
# Migration tests
32+
test_migration.db
33+
test_migration.db-journal

README.md

Lines changed: 1 addition & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -120,35 +120,7 @@ uvicorn app.main:app --reload
120120

121121
## Use Alembic migrations
122122

123-
The project use Alembic migrations to manage database structure evolutions.
124-
125-
When the database does not exist, SQLAlchemy will create a new database with an up to date structure. When the database already exist, migrations must be run to update the structure.
126-
127-
### Run migrations
128-
129-
These [migration files](./migrations/versions/) are automatically run before Hyperion startup.
130-
131-
They can also be run manually using the following command:
132-
133-
```bash
134-
alembic upgrade head
135-
```
136-
137-
> If you want to force Alembic to consider your database structure is up to date, you can use the following command:
138-
>
139-
> ```bash
140-
> alembic stamp head
141-
> ```
142-
143-
### Write migration files
144-
145-
To create a new migration file, use the following command:
146-
147-
```bash
148-
alembic revision --autogenerate -m "Your message"
149-
```
150-
151-
Files must be names with the following convention: `number-message.py
123+
See [migrations README](./migrations/README)
152124

153125
## OpenAPI specification
154126

migrations/README

Lines changed: 0 additions & 6 deletions
This file was deleted.

migrations/README.md

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Generating migrations
2+
3+
The project use Alembic migrations to manage database structure evolutions.
4+
5+
When the database does not exist, SQLAlchemy will create a new database with an up to date structure. When the database already exist, migrations must be run to update the structure.
6+
7+
### Run migrations
8+
9+
These [migration files](./migrations/versions/) are automatically run before Hyperion startup.
10+
11+
They can also be run manually using the following command:
12+
13+
```bash
14+
alembic upgrade head
15+
```
16+
17+
> If you want to force Alembic to consider your database structure is up to date, you can use the following command:
18+
>
19+
> ```bash
20+
> alembic stamp head
21+
> ```
22+
>
23+
> If the database stamp is a migration that does not exist anymore, you can use the following command to
24+
> force Alembic to consider your database structure is up to date
25+
>
26+
> ```bash
27+
> alembic stamp --purge head
28+
> ```
29+
30+
### Write migration files
31+
32+
To create a new migration file, use the following command:
33+
34+
```bash
35+
alembic revision --autogenerate -m "Your message"
36+
```
37+
38+
Files must be names with the following convention: `number-message.py
39+
40+
## Best practices
41+
42+
For migrations to be compatible with SQLite, `alter` commands should be wrapped in a [`batch_alter_table` context manager](https://alembic.sqlalchemy.org/en/latest/batch.html).
43+
44+
## Code snippets
45+
46+
### Add a value to an Enum
47+
48+
```python
49+
with op.batch_alter_table("table_name") as batch_op:
50+
batch_op.alter_column(
51+
"field_name",
52+
existing_type=sa.VARCHAR(length=23),
53+
type_=sa.Enum(
54+
"value1",
55+
"value2",
56+
"newvalue1",
57+
"newvalue2",
58+
name="enum_name",
59+
),
60+
existing_nullable=False,
61+
)
62+
```
63+
64+
### Server default
65+
66+
**Boolean**
67+
You need to use `server_default=sa.sql.false()`

migrations/script.py.mako

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22

33
Create Date: ${create_date}
44
"""
5-
from collections.abc import Sequence
5+
from typing import Sequence, Union, TYPE_CHECKING
6+
7+
if TYPE_CHECKING:
8+
from pytest_alembic import MigrationContext
69

710
import sqlalchemy as sa
811
from alembic import op
@@ -24,3 +27,17 @@ def upgrade() -> None:
2427

2528
def downgrade() -> None:
2629
${downgrades if downgrades else "pass"}
30+
31+
32+
def pre_test_upgrade(
33+
alembic_runner: "MigrationContext",
34+
alembic_connection: sa.Connection,
35+
) -> None:
36+
pass
37+
38+
39+
def test_upgrade(
40+
alembic_runner: "MigrationContext",
41+
alembic_connection: sa.Connection,
42+
) -> None:
43+
pass

0 commit comments

Comments
 (0)