Skip to content

Commit 83f2115

Browse files
authored
Merge pull request #79 from grillazz/36-add-performance-tests-with-locust
refactor alembic migrations
2 parents 1e3c301 + d274b0b commit 83f2115

8 files changed

+157
-182
lines changed

Dockerfile

+5-3
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,11 @@ RUN apt-get purge -y curl git build-essential \
2929

3030
FROM install as app-image
3131

32-
COPY tests tests
33-
COPY app app
34-
COPY alembic alembic
32+
ENV PYTHONPATH=/home/code/ PYTHONHASHSEED=0
33+
34+
COPY tests/ tests/
35+
COPY app/ app/
36+
COPY alembic/ alembic/
3537
COPY .env alembic.ini ./
3638

3739
# create a non-root user and switch to it, for security.

Makefile

+3-2
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,9 @@ migrate-apply: ## apply alembic migrations to database/schema
2121
docker-compose run --rm app alembic upgrade head
2222

2323
.PHONY: migrate-create
24-
migrate-create: ## create new alembic migration
25-
docker-compose run --rm app alembic revision --autogenerate
24+
migrate-create: ## Create new alembic database migration aka database revision.
25+
docker-compose up -d db | true
26+
docker-compose run --no-deps app alembic revision --autogenerate -m "$(msg)"
2627

2728
.PHONY: test
2829
test: ## Run project tests

alembic.ini

+17-7
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
script_location = alembic
66

77
# template used to generate migration files
8-
# file_template = %%(rev)s_%%(slug)s
8+
file_template = %%(year)d%%(month).2d%%(day).2d_%%(hour).2d%%(minute).2d_%%(rev)s_%%(slug)s
99

1010
# timezone to use when rendering the date
1111
# within the migration file as well as the filename.
@@ -15,7 +15,7 @@ script_location = alembic
1515

1616
# max length of characters to apply to the
1717
# "slug" field
18-
#truncate_slug_length = 40
18+
# truncate_slug_length = 40
1919

2020
# set to 'true' to run the environment during
2121
# the 'revision' command, regardless of autogenerate
@@ -27,14 +27,24 @@ script_location = alembic
2727
# sourceless = false
2828

2929
# version location specification; this defaults
30-
# to alembic/versions. When using multiple version
30+
# to app/alembic/versions. When using multiple version
3131
# directories, initial revisions must be specified with --version-path
32-
# version_locations = %(here)s/bar %(here)s/bat alembic/versions
32+
# version_locations = %(here)s/bar %(here)s/bat app/alembic/versions
3333

3434
# the output encoding used when revision files
3535
# are written from script.py.mako
3636
# output_encoding = utf-8
3737

38+
[post_write_hooks]
39+
# post_write_hooks defines scripts or Python functions that are run
40+
# on newly generated revision scripts. See the documentation for further
41+
# detail and examples
42+
43+
# format using "black" - use the console_scripts runner, against the "black" entrypoint
44+
# hooks=black
45+
# black.type=console_scripts
46+
# black.entrypoint=black
47+
# black.options=-l 79
3848

3949
# Logging configuration
4050
[loggers]
@@ -52,12 +62,12 @@ handlers = console
5262
qualname =
5363

5464
[logger_sqlalchemy]
55-
level = DEBUG
65+
level = WARN
5666
handlers =
5767
qualname = sqlalchemy.engine
5868

5969
[logger_alembic]
60-
level = DEBUG
70+
level = INFO
6171
handlers =
6272
qualname = alembic
6373

@@ -68,5 +78,5 @@ level = NOTSET
6878
formatter = generic
6979

7080
[formatter_generic]
71-
format = %(asctime)s %(levelname)-8s %(thread)d <%(name)s> %(message)r
81+
format = %(levelname)-5.5s [%(name)s] %(message)s
7282
datefmt = %H:%M:%S

alembic/env.py

+7-9
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,22 @@
11
import asyncio
2-
import os
3-
import sys
42

53
from alembic import context
64
from sqlalchemy.ext.asyncio import create_async_engine
75

8-
parent_dir = os.path.abspath(os.path.join(os.getcwd()))
9-
sys.path.append(parent_dir)
6+
from app.config import settings
7+
from app.models.base import Base
108

11-
from app.models.base import Base as app_base
12-
13-
target_metadata = app_base.metadata
9+
target_metadata = Base.metadata
1410

1511

1612
def do_run_migrations(connection):
1713
context.configure(
14+
compare_type=True,
15+
dialect_opts={"paramstyle": "named"},
1816
connection=connection,
1917
target_metadata=target_metadata,
2018
include_schemas=True,
19+
# literal_binds=True,
2120
version_table_schema=target_metadata.schema,
2221
)
2322

@@ -32,8 +31,7 @@ async def run_migrations_online():
3231
and associate a connection with the context.
3332
3433
"""
35-
url = f"postgresql+asyncpg://user:secret@db:5432/devdb"
36-
connectable = create_async_engine(url)
34+
connectable = create_async_engine(settings.asyncpg_url, future=True)
3735

3836
async with connectable.connect() as connection:
3937
await connection.run_sync(do_run_migrations)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
"""init migrations
2+
3+
Revision ID: 0d1ee3949d21
4+
Revises:
5+
Create Date: 2023-03-11 20:08:07.362613
6+
7+
"""
8+
from alembic import op
9+
import sqlalchemy as sa
10+
from sqlalchemy.dialects import postgresql
11+
12+
# revision identifiers, used by Alembic.
13+
revision = '0d1ee3949d21'
14+
down_revision = None
15+
branch_labels = None
16+
depends_on = None
17+
18+
19+
def upgrade():
20+
# ### commands auto generated by Alembic - please adjust! ###
21+
op.create_table('nonsense',
22+
sa.Column('id', sa.UUID(), autoincrement=True, nullable=True),
23+
sa.Column('name', sa.String(), nullable=False),
24+
sa.Column('description', sa.String(), nullable=False),
25+
sa.PrimaryKeyConstraint('name'),
26+
sa.UniqueConstraint('id'),
27+
sa.UniqueConstraint('name'),
28+
schema='happy_hog'
29+
)
30+
op.create_table('stuff',
31+
sa.Column('id', sa.UUID(), autoincrement=True, nullable=True),
32+
sa.Column('name', sa.String(), nullable=False),
33+
sa.Column('description', sa.String(), nullable=False),
34+
sa.PrimaryKeyConstraint('name'),
35+
sa.UniqueConstraint('id'),
36+
sa.UniqueConstraint('name'),
37+
schema='happy_hog'
38+
)
39+
op.create_table('character',
40+
sa.Column('id', sa.String(length=32), nullable=False),
41+
sa.Column('name', sa.String(length=64), nullable=False),
42+
sa.Column('speech_count', sa.Integer(), nullable=False),
43+
sa.Column('abbrev', sa.String(length=32), nullable=True),
44+
sa.Column('description', sa.String(length=2056), nullable=True),
45+
sa.PrimaryKeyConstraint('id', name='character_pkey'),
46+
schema='shakespeare'
47+
)
48+
op.create_table('wordform',
49+
sa.Column('id', sa.Integer(), nullable=False),
50+
sa.Column('plain_text', sa.String(length=64), nullable=False),
51+
sa.Column('phonetic_text', sa.String(length=64), nullable=False),
52+
sa.Column('stem_text', sa.String(length=64), nullable=False),
53+
sa.Column('occurences', sa.Integer(), nullable=False),
54+
sa.PrimaryKeyConstraint('id', name='wordform_pkey'),
55+
schema='shakespeare'
56+
)
57+
op.create_table('work',
58+
sa.Column('id', sa.String(length=32), nullable=False),
59+
sa.Column('title', sa.String(length=32), nullable=False),
60+
sa.Column('long_title', sa.String(length=64), nullable=False),
61+
sa.Column('year', sa.Integer(), nullable=False),
62+
sa.Column('genre_type', sa.String(length=1), nullable=False),
63+
sa.Column('source', sa.String(length=16), nullable=False),
64+
sa.Column('total_words', sa.Integer(), nullable=False),
65+
sa.Column('total_paragraphs', sa.Integer(), nullable=False),
66+
sa.Column('notes', sa.Text(), nullable=True),
67+
sa.PrimaryKeyConstraint('id', name='work_pkey'),
68+
schema='shakespeare'
69+
)
70+
op.create_table('chapter',
71+
sa.Column('id', sa.Integer(), nullable=False),
72+
sa.Column('work_id', sa.String(length=32), nullable=False),
73+
sa.Column('section_number', sa.Integer(), nullable=False),
74+
sa.Column('chapter_number', sa.Integer(), nullable=False),
75+
sa.Column('description', sa.String(length=256), nullable=False),
76+
sa.ForeignKeyConstraint(['work_id'], ['shakespeare.work.id'], name='chapter_work_id_fkey'),
77+
sa.PrimaryKeyConstraint('id', name='chapter_pkey'),
78+
sa.UniqueConstraint('work_id', 'section_number', 'chapter_number', name='chapter_work_id_section_number_chapter_number_key'),
79+
schema='shakespeare'
80+
)
81+
op.create_table('character_work',
82+
sa.Column('character_id', sa.String(length=32), nullable=False),
83+
sa.Column('work_id', sa.String(length=32), nullable=False),
84+
sa.ForeignKeyConstraint(['character_id'], ['shakespeare.character.id'], name='character_work_character_id_fkey'),
85+
sa.ForeignKeyConstraint(['work_id'], ['shakespeare.work.id'], name='character_work_work_id_fkey'),
86+
sa.PrimaryKeyConstraint('character_id', 'work_id', name='character_work_pkey'),
87+
schema='shakespeare'
88+
)
89+
op.create_table('paragraph',
90+
sa.Column('id', sa.Integer(), nullable=False),
91+
sa.Column('work_id', sa.String(length=32), nullable=False),
92+
sa.Column('paragraph_num', sa.Integer(), nullable=False),
93+
sa.Column('character_id', sa.String(length=32), nullable=False),
94+
sa.Column('plain_text', sa.Text(), nullable=False),
95+
sa.Column('phonetic_text', sa.Text(), nullable=False),
96+
sa.Column('stem_text', sa.Text(), nullable=False),
97+
sa.Column('paragraph_type', sa.String(length=1), nullable=False),
98+
sa.Column('section_number', sa.Integer(), nullable=False),
99+
sa.Column('chapter_number', sa.Integer(), nullable=False),
100+
sa.Column('char_count', sa.Integer(), nullable=False),
101+
sa.Column('word_count', sa.Integer(), nullable=False),
102+
sa.ForeignKeyConstraint(['character_id'], ['shakespeare.character.id'], name='paragraph_character_id_fkey'),
103+
sa.ForeignKeyConstraint(['work_id', 'section_number', 'chapter_number'], ['shakespeare.chapter.work_id', 'shakespeare.chapter.section_number', 'shakespeare.chapter.chapter_number'], name='paragraph_chapter_fkey'),
104+
sa.ForeignKeyConstraint(['work_id'], ['shakespeare.work.id'], name='paragraph_work_id_fkey'),
105+
sa.PrimaryKeyConstraint('id', name='paragraph_pkey'),
106+
schema='shakespeare'
107+
)
108+
# ### end Alembic commands ###
109+
110+
111+
def downgrade():
112+
# ### commands auto generated by Alembic - please adjust! ###
113+
op.drop_table('paragraph', schema='shakespeare')
114+
op.drop_table('character_work', schema='shakespeare')
115+
op.drop_table('chapter', schema='shakespeare')
116+
op.drop_table('work', schema='shakespeare')
117+
op.drop_table('wordform', schema='shakespeare')
118+
op.drop_table('character', schema='shakespeare')
119+
op.drop_table('stuff', schema='happy_hog')
120+
op.drop_table('nonsense', schema='happy_hog')
121+
# ### end Alembic commands ###

0 commit comments

Comments
 (0)