Coverage for src/typedal/fields.py: 100%

1"""

2 This file contains available Field types.

3"""

4

5 import datetime as dt

6 import decimal

7 import typing

8

9 from pydal.objects import Table

10

11 from .core import TypeDAL, TypedField, TypedTable

12

13 T = typing.TypeVar("T", bound=typing.Any)

14

15

16## general

17

18

19# def TypedField(

20# _type: typing.Type[T] | types.UnionType,

21# **kwargs: typing.Any,

22# ) -> T:

23# """

24# sneaky: its a function and not a class, because there's a return type.

25#

26# and the return type (T) is the input type in _type

27#

28# Example:

29# age: TypedField(int, default=18)

30# """

31# return typing.cast(T, TypedFieldType(_type, **kwargs))

32

33

34## specific

35 def StringField(**kw: typing.Any) -> TypedField[str]:

36 """

37 Pydal type is string, Python type is str.

38 """

39 kw["type"] = "string"

40 return TypedField(str, **kw)

41

42

43 String = StringField

44

45

46 def TextField(**kw: typing.Any) -> TypedField[str]:

47 """

48 Pydal type is text, Python type is str.

49 """

50 kw["type"] = "text"

51 return TypedField(str, **kw)

52

53

54 Text = TextField

55

56

57 def BlobField(**kw: typing.Any) -> TypedField[bytes]:

58 """

59 Pydal type is blob, Python type is bytes.

60 """

61 kw["type"] = "blob"

62 return TypedField(bytes, **kw)

63

64

65 Blob = BlobField

66

67

68 def BooleanField(**kw: typing.Any) -> TypedField[bool]:

69 """

70 Pydal type is boolean, Python type is bool.

71 """

72 kw["type"] = "boolean"

73 return TypedField(bool, **kw)

74

75

76 Boolean = BooleanField

77

78

79 def IntegerField(**kw: typing.Any) -> TypedField[int]:

80 """

81 Pydal type is integer, Python type is int.

82 """

83 kw["type"] = "integer"

84 return TypedField(int, **kw)

85

86

87 Integer = IntegerField

88

89

90 def DoubleField(**kw: typing.Any) -> TypedField[float]:

91 """

92 Pydal type is double, Python type is float.

93 """

94 kw["type"] = "double"

95 return TypedField(float, **kw)

96

97

98 Double = DoubleField

99

100

101 def DecimalField(n: int, m: int, **kw: typing.Any) -> TypedField[decimal.Decimal]:

102 """

103 Pydal type is decimal, Python type is Decimal.

104 """

105 kw["type"] = f"decimal({n}, {m})"

106 return TypedField(decimal.Decimal, **kw)

107

108

109 Decimal = DecimalField

110

111

112 def DateField(**kw: typing.Any) -> TypedField[dt.date]:

113 """

114 Pydal type is date, Python type is datetime.date.

115 """

116 kw["type"] = "date"

117 return TypedField(dt.date, **kw)

118

119

120 Date = DateField

121

122

123 def TimeField(**kw: typing.Any) -> TypedField[dt.time]:

124 """

125 Pydal type is time, Python type is datetime.time.

126 """

127 kw["type"] = "time"

128 return TypedField(dt.time, **kw)

129

130

131 Time = TimeField

132

133

134 def DatetimeField(**kw: typing.Any) -> TypedField[dt.datetime]:

135 """

136 Pydal type is datetime, Python type is datetime.datetime.

137 """

138 kw["type"] = "datetime"

139 return TypedField(dt.datetime, **kw)

140

141

142 Datetime = DatetimeField

143

144

145 def PasswordField(**kw: typing.Any) -> TypedField[str]:

146 """

147 Pydal type is password, Python type is str.

148 """

149 kw["type"] = "password"

150 return TypedField(str, **kw)

151

152

153 Password = PasswordField

154

155

156 def UploadField(**kw: typing.Any) -> TypedField[str]:

157 """

158 Pydal type is upload, Python type is str.

159 """

160 kw["type"] = "upload"

161 return TypedField(str, **kw)

162

163

164 Upload = UploadField

165

166 T_subclass = typing.TypeVar("T_subclass", TypedTable, Table)

167

168

169 def ReferenceField(

170 other_table: str | typing.Type[TypedTable] | TypedTable | Table | T_subclass, **kw: typing.Any

171) -> TypedField[int]:

172 """

173 Pydal type is reference, Python type is int (id).

174 """

175 if isinstance(other_table, str):

176 kw["type"] = f"reference {other_table}"

177 elif isinstance(other_table, Table):

178 # db.table

179 kw["type"] = f"reference {other_table._tablename}"

180 elif isinstance(other_table, type) and issubclass(other_table, TypedTable):

181 # SomeTable

182 snakename = TypeDAL.to_snake(other_table.__name__)

183 kw["type"] = f"reference {snakename}"

184 else:

185 raise ValueError(f"Don't know what to do with {type(other_table)}")

186

187 return TypedField(int, **kw)

188

189

190 Reference = ReferenceField

191

192

193 def ListStringField(**kw: typing.Any) -> TypedField[list[str]]:

194 """

195 Pydal type is list:string, Python type is list of str.

196 """

197 kw["type"] = "list:string"

198 return TypedField(list[str], **kw)

199

200

201 ListString = ListStringField

202

203

204 def ListIntegerField(**kw: typing.Any) -> TypedField[list[int]]:

205 """

206 Pydal type is list:integer, Python type is list of int.

207 """

208 kw["type"] = "list:integer"

209 return TypedField(list[int], **kw)

210

211

212 ListInteger = ListIntegerField

213

214

215 def ListReferenceField(other_table: str, **kw: typing.Any) -> TypedField[list[int]]:

216 """

217 Pydal type is list:reference, Python type is list of int (id).

218 """

219 kw["type"] = f"list:reference {other_table}"

220 return TypedField(list[int], **kw)

221

222

223 ListReference = ListReferenceField

224

225

226 def JSONField(**kw: typing.Any) -> TypedField[object]:

227 """

228 Pydal type is json, Python type is object (can be anything JSON-encodable).

229 """

230 kw["type"] = "json"

231 return TypedField(object, **kw)

232

233

234 def BigintField(**kw: typing.Any) -> TypedField[int]:

235 """

236 Pydal type is bigint, Python type is int.

237 """

238 kw["type"] = "bigint"

239 return TypedField(int, **kw)

240

241

242 Bigint = BigintField