Coverage for postrfp/model/tags.py: 100%

17 statements  

« prev     ^ index     » next       coverage.py v7.11.0, created at 2025-10-22 21:34 +0000

1from typing import Optional 

2 

3from sqlalchemy import ( 

4 Table, 

5 UniqueConstraint, 

6 Integer, 

7 ForeignKey, 

8 Column, 

9 CheckConstraint, 

10) 

11from sqlalchemy.orm import Mapped, mapped_column, relationship 

12from sqlalchemy.types import VARCHAR 

13 

14from .humans import Organisation 

15from .questionnaire.nodes import QuestionInstance 

16from .meta import Base 

17 

18tags_qinstances_table = Table( 

19 "tags_qinstances", 

20 Base.metadata, 

21 Column("tag_id", Integer, ForeignKey("tags.id", ondelete="CASCADE"), index=True), 

22 Column( 

23 "question_instance_id", 

24 Integer, 

25 ForeignKey(QuestionInstance.id, ondelete="CASCADE"), 

26 index=True, 

27 ), 

28 UniqueConstraint("tag_id", "question_instance_id"), 

29) 

30 

31 

32class Tag(Base): 

33 __tablename__ = "tags" 

34 __table_args__ = ( 

35 UniqueConstraint("org_id", "name"), 

36 # MariaDB/MySQL regex 

37 CheckConstraint("colour REGEXP '^#[0-9A-Fa-f]{6}$'", name="ck_tag_colour_hex6"), 

38 ) 

39 

40 org_id: Mapped[Optional[str]] = mapped_column( 

41 VARCHAR(length=50), 

42 ForeignKey("organisations.id", ondelete="CASCADE", onupdate="CASCADE"), 

43 nullable=True, 

44 ) 

45 name: Mapped[str] = mapped_column(VARCHAR(length=128), nullable=False) 

46 description: Mapped[Optional[str]] = mapped_column( 

47 VARCHAR(length=256), nullable=True 

48 ) 

49 colour: Mapped[Optional[str]] = mapped_column( 

50 VARCHAR(length=7), 

51 nullable=True, 

52 comment="Hex color code (#RRGGBB)", 

53 ) 

54 

55 organisation: Mapped[Organisation] = relationship( 

56 Organisation, primaryjoin=org_id == Organisation.id, back_populates="tags" 

57 ) 

58 

59 question_instances = relationship( 

60 QuestionInstance, 

61 secondary=tags_qinstances_table, 

62 passive_deletes=True, 

63 lazy="dynamic", 

64 )