feat: modules dependencies
This commit is contained in:
@@ -12,8 +12,16 @@ if TYPE_CHECKING:
|
|||||||
project_module = Table(
|
project_module = Table(
|
||||||
'project_module',
|
'project_module',
|
||||||
BaseModel.metadata,
|
BaseModel.metadata,
|
||||||
Column('project_id', ForeignKey('projects.id')),
|
Column('project_id', ForeignKey('projects.id'), primary_key=True),
|
||||||
Column('module_id', ForeignKey('modules.id')),
|
Column('module_id', ForeignKey('modules.id'), primary_key=True),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
module_dependencies = Table(
|
||||||
|
'module_dependencies',
|
||||||
|
BaseModel.metadata,
|
||||||
|
Column('module_id', ForeignKey('modules.id'), primary_key=True),
|
||||||
|
Column('depends_on_id', ForeignKey('modules.id'), primary_key=True),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -26,6 +34,24 @@ class Module(BaseModel):
|
|||||||
icon_name: Mapped[Optional[str]] = mapped_column(unique=True, nullable=False)
|
icon_name: Mapped[Optional[str]] = mapped_column(unique=True, nullable=False)
|
||||||
is_deleted: Mapped[bool] = mapped_column(default=False)
|
is_deleted: Mapped[bool] = mapped_column(default=False)
|
||||||
|
|
||||||
|
depends_on: Mapped[list['Module']] = relationship(
|
||||||
|
'Module',
|
||||||
|
secondary=module_dependencies,
|
||||||
|
primaryjoin='Module.id == module_dependencies.c.module_id',
|
||||||
|
secondaryjoin='Module.id == module_dependencies.c.depends_on_id',
|
||||||
|
back_populates='depended_on_by',
|
||||||
|
lazy='immediate',
|
||||||
|
)
|
||||||
|
|
||||||
|
depended_on_by: Mapped[list['Module']] = relationship(
|
||||||
|
'Module',
|
||||||
|
secondary='module_dependencies',
|
||||||
|
primaryjoin='Module.id == module_dependencies.c.depends_on_id',
|
||||||
|
secondaryjoin='Module.id == module_dependencies.c.module_id',
|
||||||
|
back_populates='depends_on',
|
||||||
|
lazy='noload',
|
||||||
|
)
|
||||||
|
|
||||||
projects: Mapped[list['Project']] = relationship(
|
projects: Mapped[list['Project']] = relationship(
|
||||||
'Project',
|
'Project',
|
||||||
uselist=True,
|
uselist=True,
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ class ModuleSchema(BaseSchema):
|
|||||||
label: str
|
label: str
|
||||||
icon_name: Optional[str] = None
|
icon_name: Optional[str] = None
|
||||||
is_deleted: bool
|
is_deleted: bool
|
||||||
|
depends_on: list["ModuleSchema"] = []
|
||||||
|
|
||||||
|
|
||||||
class ProjectSchema(ProjectGeneralInfoSchema):
|
class ProjectSchema(ProjectGeneralInfoSchema):
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from sqlalchemy import select, update, func, delete
|
from sqlalchemy import select, update, func, delete
|
||||||
from sqlalchemy.orm import selectinload
|
from sqlalchemy.orm import selectinload, immediateload
|
||||||
|
|
||||||
from card_attributes import CardAttributesCommandHandler
|
from card_attributes import CardAttributesCommandHandler
|
||||||
from models import Project, Board, Module
|
from models import Project, Board, Module
|
||||||
@@ -27,7 +27,8 @@ class ProjectService(BaseService):
|
|||||||
.outerjoin(board_count_sub, Project.id == board_count_sub.c.project_id)
|
.outerjoin(board_count_sub, Project.id == board_count_sub.c.project_id)
|
||||||
.options(
|
.options(
|
||||||
selectinload(Project.attributes),
|
selectinload(Project.attributes),
|
||||||
selectinload(Project.modules),
|
selectinload(Project.modules)
|
||||||
|
.selectinload(Module.depends_on),
|
||||||
)
|
)
|
||||||
.where(Project.is_deleted == False)
|
.where(Project.is_deleted == False)
|
||||||
.order_by(Project.id)
|
.order_by(Project.id)
|
||||||
@@ -90,22 +91,48 @@ class ProjectService(BaseService):
|
|||||||
stmt = (
|
stmt = (
|
||||||
select(Module)
|
select(Module)
|
||||||
.where(Module.is_deleted == False)
|
.where(Module.is_deleted == False)
|
||||||
|
.options(
|
||||||
|
selectinload(Module.depends_on),
|
||||||
|
)
|
||||||
)
|
)
|
||||||
modules = await self.session.scalars(stmt)
|
modules = await self.session.scalars(stmt)
|
||||||
return GetAllModulesResponse(modules=modules.all())
|
return GetAllModulesResponse(modules=modules.all())
|
||||||
|
|
||||||
|
def get_module_with_dependencies(self, module: Module, visited_ids: set[int]) -> set[Module]:
|
||||||
|
result_modules = {module}
|
||||||
|
|
||||||
|
for dependency in module.depends_on:
|
||||||
|
if dependency.id not in visited_ids:
|
||||||
|
visited_ids.add(dependency.id)
|
||||||
|
result_modules.update(
|
||||||
|
self.get_module_with_dependencies(dependency, visited_ids)
|
||||||
|
)
|
||||||
|
|
||||||
|
return result_modules
|
||||||
|
|
||||||
async def update_project_modules(self, request: UpdateModulesRequest) -> UpdateModulesResponse:
|
async def update_project_modules(self, request: UpdateModulesRequest) -> UpdateModulesResponse:
|
||||||
project: Optional[Project] = await self.session.get(Project, request.project_id)
|
project: Optional[Project] = await self.session.get(Project, request.project_id)
|
||||||
if not project:
|
if not project:
|
||||||
return UpdateModulesResponse(ok=False, message=f"Проект с ID {request.project_id} не найден")
|
return UpdateModulesResponse(ok=False, message=f"Проект с ID {request.project_id} не найден")
|
||||||
|
|
||||||
|
load_dependencies = immediateload(Module.depends_on)
|
||||||
|
for i in range(5):
|
||||||
|
load_dependencies = load_dependencies.immediateload(Module.depends_on)
|
||||||
|
|
||||||
modules_stmt = (
|
modules_stmt = (
|
||||||
select(Module)
|
select(Module)
|
||||||
.where(Module.id.in_(request.module_ids))
|
.where(Module.id.in_(request.module_ids))
|
||||||
|
.options(load_dependencies)
|
||||||
)
|
)
|
||||||
modules = (await self.session.scalars(modules_stmt)).all()
|
modules = (await self.session.scalars(modules_stmt)).all()
|
||||||
|
|
||||||
project.modules = modules
|
result_modules = set()
|
||||||
|
visited_module_ids = set(request.module_ids)
|
||||||
|
for module in modules:
|
||||||
|
result_modules.update(
|
||||||
|
self.get_module_with_dependencies(module, visited_module_ids)
|
||||||
|
)
|
||||||
|
project.modules = list(result_modules)
|
||||||
await self.session.commit()
|
await self.session.commit()
|
||||||
|
|
||||||
return UpdateModulesResponse(ok=True, message="Модули успешно обновлены")
|
return UpdateModulesResponse(ok=True, message="Модули успешно обновлены")
|
||||||
|
|||||||
Reference in New Issue
Block a user