diff --git a/Makefile b/Makefile index 7267d2e..a9e666e 100644 --- a/Makefile +++ b/Makefile @@ -4,20 +4,20 @@ configure: venv venv: python -m venv venv -format: venv - source ./venv/bin/activate && autoflake -r --in-place --remove-all-unused-imports ./profcomff_definitions - source ./venv/bin/activate && isort ./profcomff_definitions - source ./venv/bin/activate && black ./profcomff_definitions +format: + autoflake -r --in-place --remove-all-unused-imports ./profcomff_definitions + isort ./profcomff_definitions + black ./profcomff_definitions - source ./venv/bin/activate && autoflake -r --in-place --remove-all-unused-imports ./migrations - source ./venv/bin/activate && isort ./migrations - source ./venv/bin/activate && black ./migrations + autoflake -r --in-place --remove-all-unused-imports ./migrations + isort ./migrations + black ./migrations test: venv migrate python3 -m pytest --verbosity=2 --showlocals --log-level=DEBUG migrate: venv - source ./venv/bin/activate && alembic upgrade head + alembic upgrade head # ex. make sampler func=upload_sample class_name=Info sampler: venv diff --git a/migrations/versions/20241212_1543_f62898bb3315_uids_to_dims.py b/migrations/versions/20241212_1543_f62898bb3315_uids_to_dims.py index a193cda..f85a517 100644 --- a/migrations/versions/20241212_1543_f62898bb3315_uids_to_dims.py +++ b/migrations/versions/20241212_1543_f62898bb3315_uids_to_dims.py @@ -7,8 +7,6 @@ """ from alembic import op -import sqlalchemy as sa -import os # revision identifiers, used by Alembic. @@ -47,4 +45,4 @@ def downgrade(): op.execute('ALTER TABLE "DM_TIMETABLE".dim_lecturer_act add COLUMN IF not EXISTS id INTEGER') # dim_room_act op.execute('ALTER TABLE "DM_TIMETABLE".dim_room_act drop COLUMN IF EXISTS id') - op.execute('ALTER TABLE "DM_TIMETABLE".dim_room_act add COLUMN IF not EXISTS id INTEGER') \ No newline at end of file + op.execute('ALTER TABLE "DM_TIMETABLE".dim_room_act add COLUMN IF not EXISTS id INTEGER') diff --git a/migrations/versions/20241214_1341_d079efc107f5_dm_timetable.py b/migrations/versions/20241214_1341_d079efc107f5_dm_timetable.py new file mode 100644 index 0000000..e1bc41e --- /dev/null +++ b/migrations/versions/20241214_1341_d079efc107f5_dm_timetable.py @@ -0,0 +1,185 @@ +"""dm_timetable + +Revision ID: d079efc107f5 +Revises: f62898bb3315 +Create Date: 2024-12-14 13:41:34.642251 + +""" + +import sqlalchemy as sa +from alembic import op + + +# revision identifiers, used by Alembic. +revision = 'd079efc107f5' +down_revision = 'f62898bb3315' +branch_labels = None +depends_on = None + + +def upgrade(): + op.create_table( + 'dm_timetable_act', + sa.Column( + 'event_id', + sa.UUID(), + nullable=False, + comment='Идентификатор события, из таблицы ODS_TIMETABLE.ods_timetable_act', + ), + sa.Column('name', sa.String(), nullable=False, comment='Название события'), + sa.Column('odd', sa.Boolean(), nullable=False, comment='Флаг: событие относится к нечетной неделе'), + sa.Column('even', sa.Boolean(), nullable=False, comment='Флаг: событие относится к четной неделе'), + sa.Column('weekday', sa.Integer(), nullable=False, comment='Номер недели'), + sa.Column('num', sa.Integer(), nullable=False, comment='Номер события'), + sa.Column('start', sa.String(), nullable=False, comment='Время начала события (в строке)'), + sa.Column('end', sa.String(), nullable=False, comment='Время конца события (в строке)'), + sa.Column('group', sa.String(), nullable=False, comment='Академическая группа, к которой относится событие'), + sa.Column( + 'event_name', sa.String(), nullable=True, comment='Название события из справочника. Заполняется всегда' + ), + sa.Column( + 'group_name', + sa.String(), + nullable=True, + comment='Название группы из справочника. Заполняется если в событии есть информация о группе', + ), + sa.Column( + 'lecturer_name', + sa.String(), + nullable=True, + comment='Имя преподавателя из справочника. Заполняется если в событии есть информация о преподавателе', + ), + sa.Column( + 'room_name', + sa.String(), + nullable=True, + comment='Название аудитори из справочника. Заполняется если в событии есть информация об аудитории', + ), + sa.PrimaryKeyConstraint('event_id'), + schema='DM_TIMETABLE', + comment='\n Витрина событий расписания.\n Строится на справочниках групп, предметов, преподавателей и аудиторий.\n Гранулярность витрины - event_id - идентична гранулярности источника ODS_TIMETABLE.ods_timetable_act\n ', + ) + op.add_column( + 'dim_event_act', + sa.Column( + 'timetable_alias', + sa.String(), + nullable=True, + comment='Техническое поле для построения пайплайна сборки расписания', + ), + schema='DM_TIMETABLE', + ) + op.alter_column('dim_event_act', 'id', existing_type=sa.UUID(), nullable=False, schema='DM_TIMETABLE') + op.create_table_comment( + 'dim_event_act', '\n Справочник событий в расписании\n ', existing_comment=None, schema='DM_TIMETABLE' + ) + op.add_column( + 'dim_group_act', + sa.Column( + 'timetable_alias', + sa.String(), + nullable=True, + comment='Техническое поле для построения пайплайна сборки расписания', + ), + schema='DM_TIMETABLE', + ) + op.alter_column('dim_group_act', 'id', existing_type=sa.UUID(), nullable=False, schema='DM_TIMETABLE') + op.create_table_comment( + 'dim_group_act', '\n Справочник групп\n ', existing_comment=None, schema='DM_TIMETABLE' + ) + op.add_column( + 'dim_lecturer_act', + sa.Column( + 'timetable_alias', + sa.String(), + nullable=True, + comment='Техническое поле для построения пайплайна сборки расписания', + ), + schema='DM_TIMETABLE', + ) + op.alter_column('dim_lecturer_act', 'id', existing_type=sa.UUID(), nullable=False, schema='DM_TIMETABLE') + op.create_table_comment( + 'dim_lecturer_act', '\n Справочник преподавателей\n ', existing_comment=None, schema='DM_TIMETABLE' + ) + op.add_column( + 'dim_room_act', + sa.Column( + 'timetable_alias', + sa.String(), + nullable=True, + comment='Техническое поле для построения пайплайна сборки расписания', + ), + schema='DM_TIMETABLE', + ) + op.alter_column('dim_room_act', 'id', existing_type=sa.UUID(), nullable=False, schema='DM_TIMETABLE') + op.create_table_comment( + 'dim_room_act', '\n Справочник аудиторий\n ', existing_comment=None, schema='DM_TIMETABLE' + ) + op.drop_column('ods_link_timetable_group', 'timetable_alias', schema='ODS_TIMETABLE') + op.drop_column('ods_link_timetable_lesson', 'timetable_alias', schema='ODS_TIMETABLE') + op.drop_column('ods_link_timetable_room', 'timetable_alias', schema='ODS_TIMETABLE') + op.drop_column('ods_link_timetable_teacher', 'timetable_alias', schema='ODS_TIMETABLE') + + +def downgrade(): + op.add_column( + 'ods_link_timetable_teacher', + sa.Column( + 'timetable_alias', + sa.VARCHAR(), + autoincrement=False, + nullable=False, + comment='Техническое поле для построения пайплайна сборки расписания', + ), + schema='ODS_TIMETABLE', + ) + op.add_column( + 'ods_link_timetable_room', + sa.Column( + 'timetable_alias', + sa.VARCHAR(), + autoincrement=False, + nullable=True, + comment='Техническое поле для построения пайплайна сборки расписания', + ), + schema='ODS_TIMETABLE', + ) + op.add_column( + 'ods_link_timetable_lesson', + sa.Column( + 'timetable_alias', + sa.VARCHAR(), + autoincrement=False, + nullable=False, + comment='Техническое поле для построения пайплайна сборки расписания', + ), + schema='ODS_TIMETABLE', + ) + op.add_column( + 'ods_link_timetable_group', + sa.Column( + 'timetable_alias', + sa.VARCHAR(), + autoincrement=False, + nullable=True, + comment='Техническое поле для построения пайплайна сборки расписания', + ), + schema='ODS_TIMETABLE', + ) + op.drop_table_comment('dim_room_act', existing_comment='\n Справочник аудиторий\n ', schema='DM_TIMETABLE') + op.alter_column('dim_room_act', 'id', existing_type=sa.UUID(), nullable=True, schema='DM_TIMETABLE') + op.drop_column('dim_room_act', 'timetable_alias', schema='DM_TIMETABLE') + op.drop_table_comment( + 'dim_lecturer_act', existing_comment='\n Справочник преподавателей\n ', schema='DM_TIMETABLE' + ) + op.alter_column('dim_lecturer_act', 'id', existing_type=sa.UUID(), nullable=True, schema='DM_TIMETABLE') + op.drop_column('dim_lecturer_act', 'timetable_alias', schema='DM_TIMETABLE') + op.drop_table_comment('dim_group_act', existing_comment='\n Справочник групп\n ', schema='DM_TIMETABLE') + op.alter_column('dim_group_act', 'id', existing_type=sa.UUID(), nullable=True, schema='DM_TIMETABLE') + op.drop_column('dim_group_act', 'timetable_alias', schema='DM_TIMETABLE') + op.drop_table_comment( + 'dim_event_act', existing_comment='\n Справочник событий в расписании\n ', schema='DM_TIMETABLE' + ) + op.alter_column('dim_event_act', 'id', existing_type=sa.UUID(), nullable=True, schema='DM_TIMETABLE') + op.drop_column('dim_event_act', 'timetable_alias', schema='DM_TIMETABLE') + op.drop_table('dm_timetable_act', schema='DM_TIMETABLE') diff --git a/profcomff_definitions/DM/timetable.py b/profcomff_definitions/DM/timetable.py index bb020f3..aa0d888 100644 --- a/profcomff_definitions/DM/timetable.py +++ b/profcomff_definitions/DM/timetable.py @@ -1,4 +1,3 @@ - import uuid from sqlalchemy import UUID, String @@ -8,7 +7,16 @@ class DimRoomAct(Base): + """ + Справочник аудиторий + """ + id: Mapped[uuid.UUID] = mapped_column(UUID, primary_key=True, default=uuid.uuid4) + timetable_alias: Mapped[str] = mapped_column( + String, + comment="Техническое поле для построения пайплайна сборки расписания", + nullable=True, + ) room_api_id: Mapped[int] room_name: Mapped[str | None] room_direction_text_type: Mapped[str | None] @@ -17,7 +25,16 @@ class DimRoomAct(Base): class DimLecturerAct(Base): + """ + Справочник преподавателей + """ + id: Mapped[uuid.UUID] = mapped_column(UUID, primary_key=True, default=uuid.uuid4) + timetable_alias: Mapped[str] = mapped_column( + String, + comment="Техническое поле для построения пайплайна сборки расписания", + nullable=True, + ) lecturer_api_id: Mapped[int] lecturer_first_name: Mapped[str | None] lecturer_middle_name: Mapped[str | None] @@ -28,7 +45,16 @@ class DimLecturerAct(Base): class DimGroupAct(Base): + """ + Справочник групп + """ + id: Mapped[uuid.UUID] = mapped_column(UUID, primary_key=True, default=uuid.uuid4) + timetable_alias: Mapped[str] = mapped_column( + String, + comment="Техническое поле для построения пайплайна сборки расписания", + nullable=True, + ) group_api_id: Mapped[int] group_name_text: Mapped[str | None] group_number: Mapped[str | None] @@ -36,7 +62,46 @@ class DimGroupAct(Base): class DimEventAct(Base): + """ + Справочник событий в расписании + """ + id: Mapped[uuid.UUID] = mapped_column(UUID, primary_key=True, default=uuid.uuid4) + timetable_alias: Mapped[str] = mapped_column( + String, + comment="Техническое поле для построения пайплайна сборки расписания", + nullable=True, + ) event_api_id: Mapped[int | None] event_name_text: Mapped[str | None] source_name: Mapped[str] + + +class DmTimetableAct(Base): + """ + Витрина событий расписания. + Строится на справочниках групп, предметов, преподавателей и аудиторий. + Гранулярность витрины - event_id - идентична гранулярности источника ODS_TIMETABLE.ods_timetable_act + """ + + event_id: Mapped[uuid.UUID] = mapped_column( + UUID, comment="Идентификатор события, из таблицы ODS_TIMETABLE.ods_timetable_act", primary_key=True + ) + name: Mapped[str] = mapped_column(comment="Название события") + odd: Mapped[bool] = mapped_column(comment="Флаг: событие относится к нечетной неделе") + even: Mapped[bool] = mapped_column(comment="Флаг: событие относится к четной неделе") + weekday: Mapped[int] = mapped_column(comment="Номер недели") + num: Mapped[int] = mapped_column(comment="Номер события") + start: Mapped[str] = mapped_column(comment="Время начала события (в строке)") + end: Mapped[str] = mapped_column(comment="Время конца события (в строке)") + group: Mapped[str] = mapped_column(comment="Академическая группа, к которой относится событие") + event_name: Mapped[str | None] = mapped_column(comment="Название события из справочника. Заполняется всегда") + group_name: Mapped[str | None] = mapped_column( + comment="Название группы из справочника. Заполняется если в событии есть информация о группе" + ) + lecturer_name: Mapped[str | None] = mapped_column( + comment="Имя преподавателя из справочника. Заполняется если в событии есть информация о преподавателе" + ) + room_name: Mapped[str | None] = mapped_column( + comment="Название аудитори из справочника. Заполняется если в событии есть информация об аудитории" + ) diff --git a/profcomff_definitions/ODS/timetable.py b/profcomff_definitions/ODS/timetable.py index 157ae70..80ef590 100644 --- a/profcomff_definitions/ODS/timetable.py +++ b/profcomff_definitions/ODS/timetable.py @@ -1,6 +1,6 @@ import uuid -from sqlalchemy import UUID, String +from sqlalchemy import UUID from sqlalchemy.orm import Mapped, mapped_column from profcomff_definitions.base import Base @@ -25,9 +25,6 @@ class OdsTimetableAct(Base): class OdsLinkTimetableTeacher(Base): id: Mapped[uuid.UUID] = mapped_column(UUID, primary_key=True, default=uuid.uuid4) - timetable_alias: Mapped[str] = mapped_column( - String, comment="Техническое поле для построения пайплайна сборки расписания" - ) event_id: Mapped[uuid.UUID] = mapped_column( UUID, comment="Идентификатор события, полученного в результате парсинга ras.phys.msu", @@ -38,9 +35,6 @@ class OdsLinkTimetableTeacher(Base): class OdsLinkTimetableLesson(Base): id: Mapped[uuid.UUID] = mapped_column(UUID, primary_key=True, default=uuid.uuid4) - timetable_alias: Mapped[str] = mapped_column( - String, comment="Техническое поле для построения пайплайна сборки расписания" - ) event_id: Mapped[uuid.UUID] = mapped_column( UUID, comment="Идентификатор события, полученного в результате парсинга ras.phys.msu", @@ -51,11 +45,6 @@ class OdsLinkTimetableLesson(Base): class OdsLinkTimetableGroup(Base): id: Mapped[uuid.UUID] = mapped_column(UUID, primary_key=True, default=uuid.uuid4) - timetable_alias: Mapped[str] = mapped_column( - String, - comment="Техническое поле для построения пайплайна сборки расписания", - nullable=True, - ) event_id: Mapped[uuid.UUID] = mapped_column( UUID, comment="Идентификатор события, полученного в результате парсинга ras.phys.msu", @@ -66,11 +55,6 @@ class OdsLinkTimetableGroup(Base): class OdsLinkTimetableRoom(Base): id: Mapped[uuid.UUID] = mapped_column(UUID, primary_key=True, default=uuid.uuid4) - timetable_alias: Mapped[str] = mapped_column( - String, - comment="Техническое поле для построения пайплайна сборки расписания", - nullable=True, - ) event_id: Mapped[uuid.UUID] = mapped_column( UUID, comment="Идентификатор события, полученного в результате парсинга ras.phys.msu",