diff --git a/README.md b/README.md index 5620a3fbe..5a538d749 100644 --- a/README.md +++ b/README.md @@ -209,6 +209,45 @@ To run black: black . ``` +### Run migration Scripts +#### If this is you first time running migration: +Run the below command to attach the current alembic version number on the repo to your local db. +* Note: For new contributors who just completed environment setup, run the following command **AFTER** running the application for the first time. + +``` +flask db stamp head +``` + +#### If you have run migration before and have just pulled the latest update from upstream that includes newer version/s of migration script. + +Confirm you have the same version number as the second last one on the repo (if there're multiple versions). To do this, run the below commmand +``` +flask db history // to check the list of version history on the repo +flask db current // to check your latest version on the local db +``` +If you're missing other updates listed beside the latest version, run the below command **IN SEQUENTIAL ORDER** one command at a time from the first update you've missed. If you are up to date and only need to update to the latest version, you don't need to specify the `missing version number`. + +``` +flask db upgrade +``` + +#### If you are making changes to db model/s +##### By adding attribute/s to an existing db model +1. make sure you have the latest version as per the upstream repo +2. make the necessary schema changes on your db model/s +3. run the following command to add the update onto the migration version history +``` +flask db migrate -m "" +``` +where `` is a clear message what the change was about. This will be your alembic version title. +You should see the new version inside the `versions` folder +3. run the following command to apply the update to your local db +``` +flask db upgrade +``` + +##### TO DO - Altering existing attribute/s of an existing db model + ## Documentation Documentation for the project is hosted [here](https://anitab-org.github.io/mentorship-backend/). We use Docusaurus for maintaining the documentation of the project. diff --git a/migrations/env.py b/migrations/env.py index d766af808..b896f2ca9 100644 --- a/migrations/env.py +++ b/migrations/env.py @@ -25,7 +25,7 @@ config.set_main_option( "sqlalchemy.url", - current_app.config.get("SQLALCHEMY_DATABASE_URI").replace("%", "%%"), + str(current_app.extensions["migrate"].db.engine.url).replace("%", "%%"), ) target_metadata = current_app.extensions["migrate"].db.metadata diff --git a/migrations/versions/0541c68e5b13_initial_migration.py b/migrations/versions/0541c68e5b13_initial_migration.py new file mode 100644 index 000000000..159a534c6 --- /dev/null +++ b/migrations/versions/0541c68e5b13_initial_migration.py @@ -0,0 +1,129 @@ +"""Initial migration + +Revision ID: 0541c68e5b13 +Revises: +Create Date: 2021-07-07 12:20:10.523552 + +""" +from alembic import op +from app.database.db_types.JsonCustomType import JsonCustomType +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = "0541c68e5b13" +down_revision = None +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table( + "tasks_list", + sa.Column("id", sa.Integer(), nullable=False), + sa.Column("tasks", JsonCustomType, nullable=True), + sa.Column("next_task_id", sa.Integer(), nullable=True), + sa.PrimaryKeyConstraint("id"), + ) + op.create_table( + "users", + sa.Column("id", sa.Integer(), nullable=False), + sa.Column("name", sa.String(length=30), nullable=True), + sa.Column("username", sa.String(length=30), nullable=True), + sa.Column("email", sa.String(length=254), nullable=True), + sa.Column("password_hash", sa.String(length=100), nullable=True), + sa.Column("registration_date", sa.Float(), nullable=True), + sa.Column("terms_and_conditions_checked", sa.Boolean(), nullable=True), + sa.Column("is_admin", sa.Boolean(), nullable=True), + sa.Column("is_email_verified", sa.Boolean(), nullable=True), + sa.Column("email_verification_date", sa.DateTime(), nullable=True), + sa.Column("current_mentorship_role", sa.Integer(), nullable=True), + sa.Column("membership_status", sa.Integer(), nullable=True), + sa.Column("bio", sa.String(length=500), nullable=True), + sa.Column("location", sa.String(length=80), nullable=True), + sa.Column("occupation", sa.String(length=80), nullable=True), + sa.Column("organization", sa.String(length=80), nullable=True), + sa.Column("slack_username", sa.String(length=80), nullable=True), + sa.Column("social_media_links", sa.String(length=500), nullable=True), + sa.Column("skills", sa.String(length=500), nullable=True), + sa.Column("interests", sa.String(length=200), nullable=True), + sa.Column("resume_url", sa.String(length=200), nullable=True), + sa.Column("photo_url", sa.String(length=200), nullable=True), + sa.Column("need_mentoring", sa.Boolean(), nullable=True), + sa.Column("available_to_mentor", sa.Boolean(), nullable=True), + sa.PrimaryKeyConstraint("id"), + sa.UniqueConstraint("email"), + sa.UniqueConstraint("username"), + ) + op.create_table( + "mentorship_relations", + sa.Column("id", sa.Integer(), nullable=False), + sa.Column("mentor_id", sa.Integer(), nullable=True), + sa.Column("mentee_id", sa.Integer(), nullable=True), + sa.Column("action_user_id", sa.Integer(), nullable=False), + sa.Column("creation_date", sa.Float(), nullable=False), + sa.Column("accept_date", sa.Float(), nullable=True), + sa.Column("start_date", sa.Float(), nullable=True), + sa.Column("end_date", sa.Float(), nullable=True), + sa.Column( + "state", + sa.Enum( + "PENDING", + "ACCEPTED", + "REJECTED", + "CANCELLED", + "COMPLETED", + name="mentorshiprelationstate", + ), + nullable=False, + ), + sa.Column("notes", sa.String(length=400), nullable=True), + sa.Column("tasks_list_id", sa.Integer(), nullable=True), + sa.ForeignKeyConstraint( + ["mentee_id"], + ["users.id"], + ), + sa.ForeignKeyConstraint( + ["mentor_id"], + ["users.id"], + ), + sa.ForeignKeyConstraint( + ["tasks_list_id"], + ["tasks_list.id"], + ), + sa.PrimaryKeyConstraint("id"), + ) + op.create_table( + "tasks_comments", + sa.Column("id", sa.Integer(), nullable=False), + sa.Column("user_id", sa.Integer(), nullable=True), + sa.Column("task_id", sa.Integer(), nullable=True), + sa.Column("relation_id", sa.Integer(), nullable=True), + sa.Column("creation_date", sa.Float(), nullable=False), + sa.Column("modification_date", sa.Float(), nullable=True), + sa.Column("comment", sa.String(length=400), nullable=False), + sa.ForeignKeyConstraint( + ["relation_id"], + ["mentorship_relations.id"], + ), + sa.ForeignKeyConstraint( + ["task_id"], + ["tasks_list.id"], + ), + sa.ForeignKeyConstraint( + ["user_id"], + ["users.id"], + ), + sa.PrimaryKeyConstraint("id"), + ) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table("tasks_comments") + op.drop_table("mentorship_relations") + op.drop_table("users") + op.drop_table("tasks_list") + # ### end Alembic commands ### diff --git a/run.py b/run.py index 6f7ab83fe..ac5289642 100644 --- a/run.py +++ b/run.py @@ -14,7 +14,7 @@ def create_app(config_filename: str) -> Flask: db.init_app(app) - migrate = Migrate(app, db) + migrate = Migrate(app, db, render_as_batch=True) from app.api.jwt_extension import jwt