Improved workplan dependency management facilities
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import uuid
|
||||
|
||||
from sqlalchemy import ForeignKey, Text, UniqueConstraint
|
||||
from sqlalchemy import CheckConstraint, ForeignKey, Index, String, Text, text
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
@@ -8,16 +8,36 @@ from api.models.base import Base, TimestampMixin, new_uuid
|
||||
|
||||
|
||||
class WorkstreamDependency(Base, TimestampMixin):
|
||||
"""Directed dependency edge: `from_workstream` depends on `to_workstream`.
|
||||
"""Directed dependency edge: `from_workstream` depends on a workstream or task.
|
||||
|
||||
Semantics: `to_workstream` must reach a satisfactory state before
|
||||
`from_workstream` can fully proceed. Hard deletes are intentional —
|
||||
Semantics: the target must reach a satisfactory state before `from_workstream`
|
||||
can fully proceed. Hard deletes are intentional —
|
||||
removing an edge removes a constraint, not information.
|
||||
"""
|
||||
|
||||
__tablename__ = "workstream_dependencies"
|
||||
__table_args__ = (
|
||||
UniqueConstraint("from_workstream_id", "to_workstream_id", name="uq_ws_dep_pair"),
|
||||
CheckConstraint(
|
||||
"(to_workstream_id IS NOT NULL AND to_task_id IS NULL) "
|
||||
"OR (to_workstream_id IS NULL AND to_task_id IS NOT NULL)",
|
||||
name="ck_ws_dep_exactly_one_target",
|
||||
),
|
||||
Index(
|
||||
"uq_ws_dep_workstream_target",
|
||||
"from_workstream_id",
|
||||
"to_workstream_id",
|
||||
"relationship_type",
|
||||
unique=True,
|
||||
postgresql_where=text("to_workstream_id IS NOT NULL"),
|
||||
),
|
||||
Index(
|
||||
"uq_ws_dep_task_target",
|
||||
"from_workstream_id",
|
||||
"to_task_id",
|
||||
"relationship_type",
|
||||
unique=True,
|
||||
postgresql_where=text("to_task_id IS NOT NULL"),
|
||||
),
|
||||
)
|
||||
|
||||
id: Mapped[uuid.UUID] = mapped_column(
|
||||
@@ -29,17 +49,27 @@ class WorkstreamDependency(Base, TimestampMixin):
|
||||
nullable=False,
|
||||
index=True,
|
||||
)
|
||||
to_workstream_id: Mapped[uuid.UUID] = mapped_column(
|
||||
to_workstream_id: Mapped[uuid.UUID | None] = mapped_column(
|
||||
UUID(as_uuid=True),
|
||||
ForeignKey("workstreams.id", ondelete="CASCADE"),
|
||||
nullable=False,
|
||||
nullable=True,
|
||||
index=True,
|
||||
)
|
||||
to_task_id: Mapped[uuid.UUID | None] = mapped_column(
|
||||
UUID(as_uuid=True),
|
||||
ForeignKey("tasks.id", ondelete="CASCADE"),
|
||||
nullable=True,
|
||||
index=True,
|
||||
)
|
||||
relationship_type: Mapped[str] = mapped_column(
|
||||
String(40), nullable=False, default="blocks", server_default="blocks", index=True
|
||||
)
|
||||
description: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
|
||||
from_workstream: Mapped["Workstream"] = relationship( # noqa: F821
|
||||
"Workstream", foreign_keys=[from_workstream_id]
|
||||
)
|
||||
to_workstream: Mapped["Workstream"] = relationship( # noqa: F821
|
||||
to_workstream: Mapped["Workstream | None"] = relationship( # noqa: F821
|
||||
"Workstream", foreign_keys=[to_workstream_id]
|
||||
)
|
||||
to_task: Mapped["Task | None"] = relationship("Task", foreign_keys=[to_task_id]) # noqa: F821
|
||||
|
||||
Reference in New Issue
Block a user