Label.py 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. from __future__ import annotations
  2. from datetime import datetime
  3. from pycs import db
  4. from pycs.database.base import NamedBaseModel
  5. from pycs.database.util import commit_on_return
  6. def compare_children(start_label: Label, id: int) -> bool:
  7. """ check for cyclic relationships """
  8. labels_to_check = [start_label]
  9. while labels_to_check:
  10. label = labels_to_check.pop(0)
  11. if label.id == id:
  12. return False
  13. labels_to_check.extend(label.children)
  14. return True
  15. def _Label_id():
  16. return Label.id
  17. class Label(NamedBaseModel):
  18. id = db.Column(db.Integer, primary_key=True)
  19. project_id = db.Column(
  20. db.Integer,
  21. db.ForeignKey("project.id", ondelete="CASCADE"),
  22. nullable=False)
  23. parent_id = db.Column(
  24. db.Integer,
  25. db.ForeignKey("label.id", ondelete="SET NULL"))
  26. created = db.Column(db.DateTime, default=datetime.utcnow,
  27. index=True, nullable=False)
  28. reference = db.Column(db.String)
  29. # contraints
  30. __table_args__ = (
  31. db.UniqueConstraint('project_id', 'reference'),
  32. )
  33. # relationships to other models
  34. parent = db.relationship("Label",
  35. backref="children",
  36. remote_side=_Label_id)
  37. results = db.relationship("Result",
  38. backref="label",
  39. passive_deletes=True,
  40. lazy="dynamic",
  41. )
  42. serialize_only = NamedBaseModel.serialize_only + (
  43. "project_id",
  44. "parent_id",
  45. "reference",
  46. "children",
  47. )
  48. @commit_on_return
  49. def set_parent(self, parent: T.Optional[T.Union[int, str, Label]] = None) -> None:
  50. """
  51. set this labels parent
  52. :param parent: parent label. Can be a reference, an id or a Label instance
  53. :return:
  54. """
  55. parent_id = None
  56. if parent is not None:
  57. if isinstance(parent, Label):
  58. parent_id = parent.id
  59. elif isinstance(parent, str):
  60. parent_id = Label.query.filter(Label.reference == parent).one().id
  61. elif isinstance(parent, int):
  62. parent_id = parent
  63. if not compare_children(self, parent_id):
  64. raise ValueError('Cyclic relationship detected!')
  65. self.parent_id = parent_id