Skip to content

Commit

Permalink
[WIP] FRAAND-T-29_tags
Browse files Browse the repository at this point in the history
Merge remote-tracking branch 'origin/FRAAND-T-29_tags' into FRAAND-T-29_tags

Slightly updated (docstrings) Mako template for migrations...

Solved the double dynamic models import by moving the functionality from models/__init__.py to models/util.py and execution to /alembic/env.py...

Fixed a typo for ItemsTags
Removed meta in db.md
Added dynamic models importing for Alembic...

Moved get_user_db() to users/dependencies.py...

Made ERD code clearer...

Updated ERD with Tags, ItemsTags and fields...

Moved all models to Mapped-version; added Items-Tags association table; added tags migration...

Changed declarative_base to DeclarativeBase in Base model...

Added Tag model frame...

Added Tag model frame...

Fixed a typo in entrypoint.sh...

Changed all `uid`s to `id`s in models and schemas; added tables names for User model; made Alembic's autogenerate() pick-up the changes...

Added schema and data upgrade/downgrade for migrations template...

Added Items and Images migrations...

Updated Alembic-migrations with SQLAlchemy 2.0 version, added schema and data sections for them...

Merge branch 'master' of https://git.jetbrains.space/uno/fraand/FRAAND


Co-authored-by: Ernest Umerov <[email protected]>

Merge-request: FRAAND-MR-7
Merged-by: Willhelm Hawk <[email protected]>
  • Loading branch information
UnoYakshi authored and Space Cloud committed May 16, 2023
1 parent b117234 commit 9b08322
Show file tree
Hide file tree
Showing 17 changed files with 443 additions and 50 deletions.
2 changes: 2 additions & 0 deletions alembic/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from alembic import context
from src.fraand_core.config import settings
from src.fraand_core.models.base import Base
from src.fraand_core.models.utils import import_domains_models

# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
Expand All @@ -21,6 +22,7 @@

# Add 'autogenerate' support, target the metadata of the base models class.
target_metadata = Base.metadata # type: ignore
import_domains_models()


def run_migrations_offline() -> None:
Expand Down
20 changes: 20 additions & 0 deletions alembic/script.py.mako
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,23 @@ def upgrade() -> None:

def downgrade() -> None:
${downgrades if downgrades else "pass"}


def schema_upgrades():
"""Schema upgrade migrations go here..."""
${upgrades if upgrades else "pass"}


def schema_downgrades():
"""schema downgrade migrations go here..."""
${downgrades if downgrades else "pass"}


def data_upgrades():
"""Add any optional data upgrade migrations here!"""
pass


def data_downgrades():
"""Add any optional data downgrade migrations here!"""
pass
58 changes: 47 additions & 11 deletions alembic/versions/2023-05-06__added_user_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = '8fc39660ddf4'
down_revision = '58ea474ac818'
Expand All @@ -19,21 +18,58 @@
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.create_table(
'user',
'users',
sa.Column('id', sa.UUID(), autoincrement=False, nullable=False),
sa.Column('email', sa.VARCHAR(length=320), autoincrement=False, nullable=False),
sa.Column('hashed_password', sa.VARCHAR(length=1024), autoincrement=False, nullable=False),
sa.Column('is_active', sa.BOOLEAN(), autoincrement=False, nullable=False),
sa.Column('is_superuser', sa.BOOLEAN(), autoincrement=False, nullable=False),
sa.Column('is_verified', sa.BOOLEAN(), autoincrement=False, nullable=False),
sa.PrimaryKeyConstraint('id', name='user_pkey'),
sa.Column('email', sa.String(length=320), nullable=False),
sa.Column('hashed_password', sa.String(length=1024), nullable=False),
sa.Column('is_active', sa.Boolean(), nullable=False),
sa.Column('is_superuser', sa.Boolean(), nullable=False),
sa.Column('is_verified', sa.Boolean(), nullable=False),
sa.PrimaryKeyConstraint('id', name=op.f('users_pkey')),
)
op.create_index('user_email_idx', 'user', ['email'], unique=False)
op.create_index(op.f('users_email_idx'), 'users', ['email'], unique=True)
# ### end Alembic commands ###


def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_index('user_email_idx', table_name='user')
op.drop_table('user')
op.drop_index(op.f('users_email_idx'), table_name='users')
op.drop_table('users')
# ### end Alembic commands ###


def schema_upgrades():
"""schema upgrade migrations go here."""
# ### commands auto generated by Alembic - please adjust! ###
op.create_table(
'users',
sa.Column('id', sa.UUID(), nullable=False),
sa.Column('email', sa.String(length=320), nullable=False),
sa.Column('hashed_password', sa.String(length=1024), nullable=False),
sa.Column('is_active', sa.Boolean(), nullable=False),
sa.Column('is_superuser', sa.Boolean(), nullable=False),
sa.Column('is_verified', sa.Boolean(), nullable=False),
sa.PrimaryKeyConstraint('id', name=op.f('users_pkey')),
)
op.create_index(op.f('users_email_idx'), 'users', ['email'], unique=True)
# ### end Alembic commands ###


def schema_downgrades():
"""schema downgrade migrations go here."""
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table('images')
op.drop_index(op.f('users_email_idx'), table_name='users')
op.drop_table('users')
op.drop_table('items')
# ### end Alembic commands ###


def data_upgrades():
"""Add any optional data upgrade migrations here!"""
pass


def data_downgrades():
"""Add any optional data downgrade migrations here!"""
pass
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
"""Added Items and Images (frame) models...
Revision ID: 720d958185d7
Revises: 8fc39660ddf4
Create Date: 2023-05-16 00:38:55.652063
"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = '720d958185d7'
down_revision = '8fc39660ddf4'
branch_labels = None
depends_on = None


def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.create_table(
'items',
sa.Column('id', sa.UUID(), nullable=False),
sa.Column('name', sa.String(), nullable=False),
sa.Column('description', sa.String(), nullable=True),
sa.Column('is_published', sa.Boolean(), nullable=True),
sa.Column('city', sa.String(), nullable=True),
sa.PrimaryKeyConstraint('id', name=op.f('items_pkey')),
)

op.create_table(
'images',
sa.Column('id', sa.UUID(), nullable=False),
sa.Column('image', sa.LargeBinary(), nullable=False),
sa.Column('item_id', sa.UUID(), nullable=False),
sa.ForeignKeyConstraint(['item_id'], ['items.id'], name=op.f('images_item_id_fkey')),
sa.PrimaryKeyConstraint('id', name=op.f('images_pkey')),
)
# ### end Alembic commands ###


def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table('images')
op.drop_table('items')
# ### end Alembic commands ###


def schema_upgrades():
"""schema upgrade migrations go here."""
# ### commands auto generated by Alembic - please adjust! ###
op.create_table(
'items',
sa.Column('id', sa.UUID(), nullable=False),
sa.Column('name', sa.String(), nullable=False),
sa.Column('description', sa.String(), nullable=True),
sa.Column('is_published', sa.Boolean(), nullable=True),
sa.Column('city', sa.String(), nullable=True),
sa.PrimaryKeyConstraint('id', name=op.f('items_pkey')),
)

op.create_table(
'images',
sa.Column('id', sa.UUID(), nullable=False),
sa.Column('image', sa.LargeBinary(), nullable=False),
sa.Column('item_id', sa.UUID(), nullable=False),
sa.ForeignKeyConstraint(['item_id'], ['items.id'], name=op.f('images_item_id_fkey')),
sa.PrimaryKeyConstraint('id', name=op.f('images_pkey')),
)
# ### end Alembic commands ###


def schema_downgrades():
"""schema downgrade migrations go here."""
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table('images')
op.drop_table('items')
# ### end Alembic commands ###


def data_upgrades():
"""Add any optional data upgrade migrations here!"""
pass


def data_downgrades():
"""Add any optional data downgrade migrations here!"""
pass
80 changes: 80 additions & 0 deletions alembic/versions/2023-05-16__added_tag_itemtag_models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
"""Added Tag, ItemTag models...
Revision ID: 062796a52532
Revises: 720d958185d7
Create Date: 2023-05-16 02:29:59.569509
"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = '062796a52532'
down_revision = '720d958185d7'
branch_labels = None
depends_on = None


def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.create_table(
'tags',
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.Column('name', sa.String(), nullable=False),
sa.PrimaryKeyConstraint('id', name=op.f('tags_pkey')),
)
op.create_table(
'items_tags_at',
sa.Column('tag_id', sa.Integer(), nullable=False),
sa.Column('item_id', sa.UUID(), nullable=False),
sa.ForeignKeyConstraint(['item_id'], ['items.id'], name=op.f('items_tags_at_item_id_fkey')),
sa.ForeignKeyConstraint(['tag_id'], ['tags.id'], name=op.f('items_tags_at_tag_id_fkey')),
sa.PrimaryKeyConstraint('tag_id', 'item_id', name=op.f('items_tags_at_pkey')),
)
# ### end Alembic commands ###


def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table('items_tags_at')
op.drop_table('tags')
# ### end Alembic commands ###


def schema_upgrades():
"""Schema upgrade migrations go here..."""
# ### commands auto generated by Alembic - please adjust! ###
op.create_table(
'tags',
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.Column('name', sa.String(), nullable=False),
sa.PrimaryKeyConstraint('id', name=op.f('tags_pkey')),
)
op.create_table(
'items_tags_at',
sa.Column('tag_id', sa.Integer(), nullable=False),
sa.Column('item_id', sa.UUID(), nullable=False),
sa.ForeignKeyConstraint(['item_id'], ['items.id'], name=op.f('items_tags_at_item_id_fkey')),
sa.ForeignKeyConstraint(['tag_id'], ['tags.id'], name=op.f('items_tags_at_tag_id_fkey')),
sa.PrimaryKeyConstraint('tag_id', 'item_id', name=op.f('items_tags_at_pkey')),
)
# ### end Alembic commands ###


def schema_downgrades():
"""schema downgrade migrations go here..."""
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table('items_tags_at')
op.drop_table('tags')
# ### end Alembic commands ###


def data_upgrades():
"""Add any optional data upgrade migrations here!"""
pass


def data_downgrades():
"""Add any optional data downgrade migrations here!"""
pass
48 changes: 45 additions & 3 deletions docs/architecture/db.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,49 @@
# Entity-Relationship Diagram (ERD)

```mermaid
erDiagram
USER ||--o{ ITEM : has
ITEM ||--o{ ITEM_IMAGE: has
ITEM }|--|| CITY : is_published_in
USERS {
UUID id PK
string email
string hashed_password
bool is_active
bool is_verified
bool is_superuser
}
ITEMS {
UUID id PK
string name
string description
bool is_published
}
ITEMS_TAGS {
UUID item_id PK, FK
int tag_id PK, FK
}
TAGS {
int id PK
string name
}
IMAGES {
UUID id PK
binary image
UUID item_id FK
}
CITIES {
UUID id PK
string name "Will be some geo-based service/DB"
}
USERS || -- o{ ITEMS : has
ITEMS || -- o{ IMAGES: has
ITEMS }| -- || CITIES : is_published_in
ITEMS || -- |{ ITEMS_TAGS : has
ITEMS_TAGS }| -- || TAGS : has
```
2 changes: 1 addition & 1 deletion scripts/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/bin/bash

# set bash fail on errors or unset varraibles
# set bash fail on errors or unset variables
set -o errexit
set -o pipefail
set -o nounset
Expand Down
6 changes: 6 additions & 0 deletions src/fraand_core/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@
MAIN_APP_DIR = Path(__file__).parent.absolute()
SRC_DIR = Path(MAIN_APP_DIR).parent.absolute()

DOMAINS_PATH = MAIN_APP_DIR / 'domains'

IGNORED_ALEMBIC_SEARCH_DIR_NAMES = ['__pycache__', 'schemas']
MODELS_DIRNAME = 'models'
MODELS_FILENAME = 'models.py'

TEMPLATES_DIR_NAME = 'templates'
TEMPLATES_ABS_FILE_PATH = Path(MAIN_APP_DIR) / TEMPLATES_DIR_NAME

Expand Down
2 changes: 1 addition & 1 deletion src/fraand_core/crud/annotations.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from pydantic import BaseModel

from src.fraand_core.models import Base
from src.fraand_core.models.base import Base

ModelType = TypeVar('ModelType', bound=Base)
CreateSchemaType = TypeVar('CreateSchemaType', bound=BaseModel)
Expand Down
2 changes: 1 addition & 1 deletion src/fraand_core/crud/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Custom exceptions for CRUD managers..."""

from fraand_core.crud.annotations import ModelType
from src.fraand_core.crud.annotations import ModelType


class NotImplementedUniqueKeysError(NotImplementedError):
Expand Down
Loading

0 comments on commit 9b08322

Please sign in to comment.