Coverage for dj/models/tag.py: 100%

27 statements  

« prev     ^ index     » next       coverage.py v7.2.3, created at 2023-04-17 20:05 -0700

1""" 

2Models for tags. 

3""" 

4from typing import TYPE_CHECKING, Any, Dict, List, Optional 

5 

6from pydantic import Extra 

7from sqlalchemy import String 

8from sqlalchemy.sql.schema import Column as SqlaColumn 

9from sqlmodel import JSON, Field, Relationship 

10 

11from dj.models.base import BaseSQLModel, generate_display_name 

12 

13if TYPE_CHECKING: 

14 from dj.models.node import Node 

15 

16 

17class MutableTagFields(BaseSQLModel): 

18 """ 

19 Tag fields that can be changed. 

20 """ 

21 

22 description: str 

23 tag_metadata: Dict[str, Any] = Field(default={}, sa_column=SqlaColumn(JSON)) 

24 

25 class Config: # pylint: disable=too-few-public-methods 

26 """ 

27 Allow types for tag metadata. 

28 """ 

29 

30 arbitrary_types_allowed = True 

31 

32 

33class ImmutableTagFields(BaseSQLModel): 

34 """ 

35 Tag fields that cannot be changed. 

36 """ 

37 

38 name: str = Field(sa_column=SqlaColumn("name", String, unique=True)) 

39 display_name: Optional[str] = Field( 

40 sa_column=SqlaColumn( 

41 "display_name", 

42 String, 

43 default=generate_display_name("name"), 

44 ), 

45 ) 

46 tag_type: str 

47 

48 

49class TagNodeRelationship(BaseSQLModel, table=True): # type: ignore 

50 """ 

51 Join table between tags and nodes 

52 """ 

53 

54 tag_id: Optional[int] = Field( 

55 default=None, 

56 foreign_key="tag.id", 

57 primary_key=True, 

58 ) 

59 node_id: Optional[int] = Field( 

60 default=None, 

61 foreign_key="node.id", 

62 primary_key=True, 

63 ) 

64 

65 

66class Tag(ImmutableTagFields, MutableTagFields, table=True): # type: ignore 

67 """ 

68 A tag. 

69 """ 

70 

71 id: Optional[int] = Field(default=None, primary_key=True) 

72 nodes: List["Node"] = Relationship( 

73 back_populates="tags", 

74 link_model=TagNodeRelationship, 

75 sa_relationship_kwargs={ 

76 "primaryjoin": "TagNodeRelationship.tag_id==Tag.id", 

77 "secondaryjoin": "TagNodeRelationship.node_id==Node.id", 

78 }, 

79 ) 

80 

81 

82class CreateTag(ImmutableTagFields, MutableTagFields): 

83 """ 

84 Create tag model. 

85 """ 

86 

87 

88class TagOutput(ImmutableTagFields, MutableTagFields): 

89 """ 

90 Output tag model. 

91 """ 

92 

93 

94class UpdateTag(MutableTagFields): 

95 """ 

96 Update tag model. Only works on mutable fields. 

97 """ 

98 

99 __annotations__ = { 

100 k: Optional[v] 

101 for k, v in { 

102 **MutableTagFields.__annotations__, # pylint: disable=E1101 

103 }.items() 

104 } 

105 

106 class Config: # pylint: disable=too-few-public-methods 

107 """ 

108 Do not allow fields other than the ones defined here. 

109 """ 

110 

111 extra = Extra.forbid