22
33from dataclasses import dataclass
44from enum import Enum
5- from typing import Union , Any , TYPE_CHECKING
5+ from typing import Any , TYPE_CHECKING
66
77from sqlalchemy import ForeignKey , ForeignKeyConstraint
8- from sqlalchemy .orm import Mapped , mapped_column , relationship
8+ from sqlalchemy .orm import Mapped , mapped_column , relationship , declared_attr
99
1010from .db import Base
1111from .enums import FieldTypeEnum
1212
1313if TYPE_CHECKING :
1414 from .models import Entry , Tag , LibraryField
1515
16- Field = Union ["TextField" , "TagBoxField" , "DatetimeField" ]
1716
17+ class BaseField (Base ):
18+ __abstract__ = True
1819
19- class BooleanField (Base ):
20- __tablename__ = "boolean_fields"
20+ @declared_attr
21+ def id (cls ) -> Mapped [int ]:
22+ return mapped_column (primary_key = True , autoincrement = True )
2123
22- id : Mapped [ int ] = mapped_column ( primary_key = True )
23- type_key : Mapped [str ] = mapped_column ( ForeignKey ( "library_fields.key" ))
24- type : Mapped [ LibraryField ] = relationship ( foreign_keys = [ type_key ], lazy = False )
24+ @ declared_attr
25+ def type_key ( cls ) -> Mapped [str ]:
26+ return mapped_column ( ForeignKey ( "library_fields.key" ) )
2527
26- entry_id : Mapped [int ] = mapped_column (ForeignKey ("entries.id" ))
27- entry : Mapped [Entry ] = relationship ()
28+ @declared_attr
29+ def type (cls ) -> Mapped [LibraryField ]:
30+ return relationship (foreign_keys = [cls .type_key ], lazy = False ) # type: ignore
2831
29- value : Mapped [bool ]
30- position : Mapped [int ]
32+ @declared_attr
33+ def entry_id (cls ) -> Mapped [int ]:
34+ return mapped_column (ForeignKey ("entries.id" ))
3135
32- def __key (self ):
33- return (self .type , self .value )
36+ @declared_attr
37+ def entry (cls ) -> Mapped [Entry ]:
38+ return relationship (foreign_keys = [cls .entry_id ]) # type: ignore
39+
40+ @declared_attr
41+ def position (cls ) -> Mapped [int ]:
42+ return mapped_column ()
3443
3544 def __hash__ (self ):
3645 return hash (self .__key ())
3746
47+ def __key (self ):
48+ raise NotImplementedError
49+
50+ value : Any
51+
52+
53+ class BooleanField (BaseField ):
54+ __tablename__ = "boolean_fields"
55+
56+ value : Mapped [bool ]
57+
58+ def __key (self ):
59+ return (self .type , self .value )
60+
3861 def __eq__ (self , value ) -> bool :
3962 if isinstance (value , BooleanField ):
4063 return self .__key () == value .__key ()
4164 raise NotImplementedError
4265
4366
44- class TextField (Base ):
67+ class TextField (BaseField ):
4568 __tablename__ = "text_fields"
4669 # constrain for combination of: entry_id, type_key and position
4770 __table_args__ = (
@@ -51,21 +74,10 @@ class TextField(Base):
5174 ),
5275 )
5376
54- id : Mapped [int ] = mapped_column (primary_key = True , autoincrement = True )
55- type_key : Mapped [str ] = mapped_column (ForeignKey ("library_fields.key" ))
56- type : Mapped [LibraryField ] = relationship (foreign_keys = [type_key ], lazy = False )
57-
58- entry_id : Mapped [int ] = mapped_column (ForeignKey ("entries.id" ))
59- entry : Mapped [Entry ] = relationship (foreign_keys = [entry_id ])
60-
6177 value : Mapped [str | None ]
62- position : Mapped [int ]
6378
64- def __key (self ):
65- return (self .type , self .value )
66-
67- def __hash__ (self ):
68- return hash (self .__key ())
79+ def __key (self ) -> tuple :
80+ return self .type , self .value
6981
7082 def __eq__ (self , value ) -> bool :
7183 if isinstance (value , TextField ):
@@ -75,18 +87,10 @@ def __eq__(self, value) -> bool:
7587 raise NotImplementedError
7688
7789
78- class TagBoxField (Base ):
90+ class TagBoxField (BaseField ):
7991 __tablename__ = "tag_box_fields"
8092
81- id : Mapped [int ] = mapped_column (primary_key = True )
82- type_key : Mapped [str ] = mapped_column (ForeignKey ("library_fields.key" ))
83- type : Mapped [LibraryField ] = relationship (foreign_keys = [type_key ], lazy = False )
84-
85- entry_id : Mapped [int ] = mapped_column (ForeignKey ("entries.id" ))
86- entry : Mapped [Entry ] = relationship (foreign_keys = [entry_id ])
87-
8893 tags : Mapped [set [Tag ]] = relationship (secondary = "tag_fields" )
89- position : Mapped [int ]
9094
9195 def __key (self ):
9296 return (
@@ -99,34 +103,20 @@ def value(self) -> None:
99103 """For interface compatibility with other field types."""
100104 return None
101105
102- def __hash__ (self ):
103- return hash (self .__key ())
104-
105106 def __eq__ (self , value ) -> bool :
106107 if isinstance (value , TagBoxField ):
107108 return self .__key () == value .__key ()
108109 raise NotImplementedError
109110
110111
111- class DatetimeField (Base ):
112+ class DatetimeField (BaseField ):
112113 __tablename__ = "datetime_fields"
113114
114- id : Mapped [int ] = mapped_column (primary_key = True )
115- type_key : Mapped [str ] = mapped_column (ForeignKey ("library_fields.key" ))
116- type : Mapped [LibraryField ] = relationship (foreign_keys = [type_key ], lazy = False )
117-
118- entry_id : Mapped [int ] = mapped_column (ForeignKey ("entries.id" ))
119- entry : Mapped [Entry ] = relationship (foreign_keys = [entry_id ])
120-
121115 value : Mapped [str | None ]
122- position : Mapped [int ]
123116
124117 def __key (self ):
125118 return (self .type , self .value )
126119
127- def __hash__ (self ):
128- return hash (self .__key ())
129-
130120 def __eq__ (self , value ) -> bool :
131121 if isinstance (value , DatetimeField ):
132122 return self .__key () == value .__key ()
0 commit comments