From 2697e0be151887bccbfa5b89bd2458d3c4fc971b Mon Sep 17 00:00:00 2001 From: Armolas Date: Fri, 19 Jul 2024 00:19:14 +0100 Subject: [PATCH] applied requested changes --- alembic.ini | 2 +- alembic/env.py | 7 +++- ...s.py => 5a2dc9cc9735_initial_migration.py} | 42 +++++++++---------- .../ba7a518767c3_initial_migration.py | 30 +++++++++++++ api/db/database.py | 8 ++-- api/v1/models/base.py | 7 ++-- api/v1/models/org.py | 16 +++---- api/v1/models/product.py | 4 +- api/v1/models/profile.py | 6 ++- api/v1/models/user.py | 13 +++--- db_test.py | 10 ++--- 11 files changed, 95 insertions(+), 50 deletions(-) rename alembic/versions/{9670771a11f9_initial_migrations.py => 5a2dc9cc9735_initial_migration.py} (69%) create mode 100644 alembic/versions/ba7a518767c3_initial_migration.py diff --git a/alembic.ini b/alembic.ini index ae1dc8be9..484de57fd 100644 --- a/alembic.ini +++ b/alembic.ini @@ -60,7 +60,7 @@ version_path_separator = os # Use os.pathsep. Default configuration used for ne # are written from script.py.mako # output_encoding = utf-8 -sqlalchemy.url = sqlite:///./database.db +sqlalchemy.url = [post_write_hooks] diff --git a/alembic/env.py b/alembic/env.py index b98bf4f22..0caf842ca 100644 --- a/alembic/env.py +++ b/alembic/env.py @@ -2,8 +2,9 @@ from sqlalchemy import engine_from_config from sqlalchemy import pool from alembic import context +from decouple import config as decouple_config from api.v1.models.user import User -from api.v1.models.org import Organisation +from api.v1.models.org import Organization from api.v1.models.profile import Profile from api.v1.models.product import Product from api.v1.models.base import Base @@ -17,6 +18,10 @@ if config.config_file_name is not None: fileConfig(config.config_file_name) +database_url = decouple_config('DATABASE_URL') + +# Set the SQLAlchemy URL dynamically +config.set_main_option('sqlalchemy.url', database_url) # add your model's MetaData object here # for 'autogenerate' support # from myapp import mymodel diff --git a/alembic/versions/9670771a11f9_initial_migrations.py b/alembic/versions/5a2dc9cc9735_initial_migration.py similarity index 69% rename from alembic/versions/9670771a11f9_initial_migrations.py rename to alembic/versions/5a2dc9cc9735_initial_migration.py index 644c854c6..37de63911 100644 --- a/alembic/versions/9670771a11f9_initial_migrations.py +++ b/alembic/versions/5a2dc9cc9735_initial_migration.py @@ -1,8 +1,8 @@ -"""Initial migrations +"""initial migration -Revision ID: 9670771a11f9 +Revision ID: 5a2dc9cc9735 Revises: -Create Date: 2024-07-18 20:08:23.466008 +Create Date: 2024-07-19 00:08:59.055052 """ from typing import Sequence, Union @@ -12,7 +12,7 @@ # revision identifiers, used by Alembic. -revision: str = '9670771a11f9' +revision: str = '5a2dc9cc9735' down_revision: Union[str, None] = None branch_labels: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None @@ -20,17 +20,17 @@ def upgrade() -> None: # ### commands auto generated by Alembic - please adjust! ### - op.create_table('organisations', - sa.Column('id', sa.Integer(), autoincrement=True, nullable=False), + op.create_table('organizations', + sa.Column('id', sa.UUID(), nullable=False), sa.Column('name', sa.String(length=50), nullable=False), sa.Column('description', sa.Text(), nullable=True), - sa.Column('created_at', sa.DateTime(), server_default=sa.text('(CURRENT_TIMESTAMP)'), nullable=True), - sa.Column('updated_at', sa.DateTime(), server_default=sa.text('(CURRENT_TIMESTAMP)'), nullable=True), + sa.Column('created_at', sa.DateTime(), server_default=sa.text('now()'), nullable=True), + sa.Column('updated_at', sa.DateTime(), server_default=sa.text('now()'), nullable=True), sa.PrimaryKeyConstraint('id'), sa.UniqueConstraint('name') ) op.create_table('products', - sa.Column('id', sa.Integer(), autoincrement=True, nullable=False), + sa.Column('id', sa.UUID(), nullable=False), sa.Column('name', sa.String(), nullable=False), sa.Column('description', sa.Text(), nullable=True), sa.Column('price', sa.Numeric(), nullable=False), @@ -38,21 +38,21 @@ def upgrade() -> None: sa.PrimaryKeyConstraint('id') ) op.create_table('users', - sa.Column('id', sa.Integer(), autoincrement=True, nullable=False), + sa.Column('id', sa.UUID(), nullable=False), sa.Column('username', sa.String(length=50), nullable=False), sa.Column('email', sa.String(length=100), nullable=False), sa.Column('password', sa.String(length=255), nullable=False), sa.Column('first_name', sa.String(length=50), nullable=True), sa.Column('last_name', sa.String(length=50), nullable=True), - sa.Column('created_at', sa.DateTime(), server_default=sa.text('(CURRENT_TIMESTAMP)'), nullable=True), - sa.Column('updated_at', sa.DateTime(), server_default=sa.text('(CURRENT_TIMESTAMP)'), nullable=True), + sa.Column('created_at', sa.DateTime(), server_default=sa.text('now()'), nullable=True), + sa.Column('updated_at', sa.DateTime(), server_default=sa.text('now()'), nullable=True), sa.PrimaryKeyConstraint('id'), sa.UniqueConstraint('email'), sa.UniqueConstraint('username') ) op.create_table('profiles', - sa.Column('id', sa.Integer(), autoincrement=True, nullable=False), - sa.Column('user_id', sa.Integer(), nullable=False), + sa.Column('id', sa.UUID(), nullable=False), + sa.Column('user_id', sa.UUID(), nullable=False), sa.Column('bio', sa.Text(), nullable=True), sa.Column('phone_number', sa.String(length=50), nullable=True), sa.Column('avatar_url', sa.String(length=100), nullable=True), @@ -61,21 +61,21 @@ def upgrade() -> None: sa.ForeignKeyConstraint(['user_id'], ['users.id'], ), sa.PrimaryKeyConstraint('id') ) - op.create_table('user_organisation', - sa.Column('user_id', sa.Integer(), nullable=False), - sa.Column('organisation_id', sa.Integer(), nullable=False), - sa.ForeignKeyConstraint(['organisation_id'], ['organisations.id'], ), + op.create_table('user_organization', + sa.Column('user_id', sa.UUID(), nullable=False), + sa.Column('organization_id', sa.UUID(), nullable=False), + sa.ForeignKeyConstraint(['organization_id'], ['organizations.id'], ), sa.ForeignKeyConstraint(['user_id'], ['users.id'], ), - sa.PrimaryKeyConstraint('user_id', 'organisation_id') + sa.PrimaryKeyConstraint('user_id', 'organization_id') ) # ### end Alembic commands ### def downgrade() -> None: # ### commands auto generated by Alembic - please adjust! ### - op.drop_table('user_organisation') + op.drop_table('user_organization') op.drop_table('profiles') op.drop_table('users') op.drop_table('products') - op.drop_table('organisations') + op.drop_table('organizations') # ### end Alembic commands ### diff --git a/alembic/versions/ba7a518767c3_initial_migration.py b/alembic/versions/ba7a518767c3_initial_migration.py new file mode 100644 index 000000000..25812cb5f --- /dev/null +++ b/alembic/versions/ba7a518767c3_initial_migration.py @@ -0,0 +1,30 @@ +"""initial migration + +Revision ID: ba7a518767c3 +Revises: 5a2dc9cc9735 +Create Date: 2024-07-19 00:15:15.551494 + +""" +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision: str = 'ba7a518767c3' +down_revision: Union[str, None] = '5a2dc9cc9735' +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + pass + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + pass + # ### end Alembic commands ### diff --git a/api/db/database.py b/api/db/database.py index d53709632..acb90c6f7 100644 --- a/api/db/database.py +++ b/api/db/database.py @@ -11,12 +11,12 @@ def get_db_engine(): - DB_TYPE = config("DB_TYPE", "") - DB_NAME = config("DB_NAME", "") + DB_TYPE = config("DB_TYPE", "postgresql") + DB_NAME = config("DB_NAME", "hng_fast_api") DB_USER = config("DB_USER", "") DB_PASSWORD = config("DB_PASSWORD", "") - DB_HOST = config("DB_HOST", "") - DB_PORT = config("DB_PORT", "") + DB_HOST = config("DB_HOST", "localhost") + DB_PORT = config("DB_PORT", "5432") MYSQL_DRIVER = config("MYSQL_DRIVER", "") DATABASE_URL = "" diff --git a/api/v1/models/base.py b/api/v1/models/base.py index cf75a1544..92c0327ee 100644 --- a/api/v1/models/base.py +++ b/api/v1/models/base.py @@ -10,11 +10,12 @@ from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import relationship from datetime import datetime +from sqlalchemy.dialects.postgresql import UUID Base = declarative_base() -user_organisation_association = Table('user_organisation', Base.metadata, - Column('user_id', Integer, ForeignKey('users.id'), primary_key=True), - Column('organisation_id', Integer, ForeignKey('organisations.id'), primary_key=True) +user_organization_association = Table('user_organization', Base.metadata, + Column('user_id', UUID(as_uuid=True), ForeignKey('users.id'), primary_key=True), + Column('organization_id', UUID(as_uuid=True), ForeignKey('organizations.id'), primary_key=True) ) diff --git a/api/v1/models/org.py b/api/v1/models/org.py index 1d3554f75..6178427ef 100644 --- a/api/v1/models/org.py +++ b/api/v1/models/org.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -""" The Organisation model +""" The Organization model """ from sqlalchemy import ( Column, @@ -14,13 +14,15 @@ ) from sqlalchemy.orm import relationship from datetime import datetime -from api.v1.models.base import Base, user_organisation_association +from api.v1.models.base import Base, user_organization_association +from sqlalchemy.dialects.postgresql import UUID +from uuid_extensions import uuid7 -class Organisation(Base): - __tablename__ = 'organisations' +class Organization(Base): + __tablename__ = 'organizations' - id = Column(Integer, primary_key=True, autoincrement=True) + id = Column(UUID(as_uuid=True), primary_key=True, default=uuid7) name = Column(String(50), unique=True, nullable=False) description = Column(Text, nullable=True) created_at = Column(DateTime, server_default=func.now()) @@ -28,8 +30,8 @@ class Organisation(Base): users = relationship( "User", - secondary=user_organisation_association, - back_populates="organisations" + secondary=user_organization_association, + back_populates="organizations" ) def __str__(self): diff --git a/api/v1/models/product.py b/api/v1/models/product.py index 3b7e8509e..b3a09490f 100644 --- a/api/v1/models/product.py +++ b/api/v1/models/product.py @@ -12,12 +12,14 @@ ) from datetime import datetime from api.v1.models.base import Base +from sqlalchemy.dialects.postgresql import UUID +from uuid_extensions import uuid7 class Product(Base): __tablename__ = 'products' - id = Column(Integer, primary_key=True, autoincrement=True) + id = Column(UUID(as_uuid=True), primary_key=True, default=uuid7) name = Column(String, nullable=False) description = Column(Text, nullable=True) price = Column(Numeric, nullable=False) diff --git a/api/v1/models/profile.py b/api/v1/models/profile.py index ed9bb94ad..0a780546d 100644 --- a/api/v1/models/profile.py +++ b/api/v1/models/profile.py @@ -12,15 +12,17 @@ func, ) from sqlalchemy.orm import relationship +from sqlalchemy.dialects.postgresql import UUID from datetime import datetime from api.v1.models.base import Base +from uuid_extensions import uuid7 class Profile(Base): __tablename__ = 'profiles' - id = Column(Integer, primary_key=True, autoincrement=True) - user_id = Column(Integer, ForeignKey('users.id'), nullable=False) + id = Column(UUID(as_uuid=True), primary_key=True, default=uuid7) + user_id = Column(UUID(as_uuid=True), ForeignKey('users.id'), nullable=False) bio = Column(Text, nullable=True) phone_number = Column(String(50), nullable=True) avatar_url = Column(String(100), nullable=True) diff --git a/api/v1/models/user.py b/api/v1/models/user.py index 81d45c080..2d47ff881 100644 --- a/api/v1/models/user.py +++ b/api/v1/models/user.py @@ -16,8 +16,11 @@ ) from sqlalchemy.orm import relationship from datetime import datetime -from api.v1.models.base import Base, user_organisation_association +from api.v1.models.base import Base, user_organization_association import bcrypt +from uuid_extensions import uuid7 +from sqlalchemy.dialects.postgresql import UUID + def hash_password(password: str) -> bytes: """ Hashes the user password for security @@ -30,7 +33,7 @@ def hash_password(password: str) -> bytes: class User(Base): __tablename__ = 'users' - id = Column(Integer, primary_key=True, autoincrement=True) + id = Column(UUID(as_uuid=True), primary_key=True, default=uuid7) username = Column(String(50), unique=True, nullable=False) email = Column(String(100), unique=True, nullable=False) password = Column(String(255), nullable=False) @@ -40,9 +43,9 @@ class User(Base): updated_at = Column(DateTime, server_default=func.now(), onupdate=func.now()) profile = relationship("Profile", uselist=False) - organisations = relationship( - "Organisation", - secondary=user_organisation_association, + organizations = relationship( + "Organization", + secondary=user_organization_association, back_populates="users" ) diff --git a/db_test.py b/db_test.py index dc5a11b6a..75773dace 100644 --- a/db_test.py +++ b/db_test.py @@ -3,7 +3,7 @@ """ from api.db.database import create_database, get_db from api.v1.models.user import User -from api.v1.models.org import Organisation +from api.v1.models.org import Organization from api.v1.models.profile import Profile from api.v1.models.product import Product @@ -16,9 +16,9 @@ db.add_all([user_1, user_2, user_3]) -org_1 = Organisation(name="Python Org", description="An organisation for python develoers") -org_2 = Organisation(name="Django Org", description="An organisation of django devs") -org_3 = Organisation(name="FastAPI Devs", description="An organisation of Fast API devs") +org_1 = Organization(name="Python Org", description="An organization for python develoers") +org_2 = Organization(name="Django Org", description="An organization of django devs") +org_3 = Organization(name="FastAPI Devs", description="An organization of Fast API devs") db.add_all([org_1, org_2, org_3]) @@ -34,7 +34,7 @@ db.add_all([product_1, product_2]) db.commit() -users = db.query(Organisation).first().users +users = db.query(Organization).first().users for user in users: print(user.password) print(profile_1.user_id)