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 types

8 import typing

9

10 from pydal.objects import Table

11

12 from .core import TypeDAL, TypedFieldType, TypedTable

13

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

15

16

17## general

18

19

20 def TypedField(

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

22 **kwargs: typing.Any,

23) -> T:

24 """

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

26

27 and the return type (T) is the input type in _type

28

29 Example:

30 age: TypedField(int, default=18)

31 """

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

33

34

35## specific

36 def StringField(**kw: typing.Any) -> str:

37 """

38 Pydal type is string, Python type is str.

39 """

40 kw["type"] = "string"

41 return TypedField(str, **kw)

42

43

44 String = StringField

45

46

47 def TextField(**kw: typing.Any) -> str:

48 """

49 Pydal type is text, Python type is str.

50 """

51 kw["type"] = "text"

52 return TypedField(str, **kw)

53

54

55 Text = TextField

56

57

58 def BlobField(**kw: typing.Any) -> bytes:

59 """

60 Pydal type is blob, Python type is bytes.

61 """

62 kw["type"] = "blob"

63 return TypedField(bytes, **kw)

64

65

66 Blob = BlobField

67

68

69 def BooleanField(**kw: typing.Any) -> bool:

70 """

71 Pydal type is boolean, Python type is bool.

72 """

73 kw["type"] = "boolean"

74 return TypedField(bool, **kw)

75

76

77 Boolean = BooleanField

78

79

80 def IntegerField(**kw: typing.Any) -> int:

81 """

82 Pydal type is integer, Python type is int.

83 """

84 kw["type"] = "integer"

85 return TypedField(int, **kw)

86

87

88 Integer = IntegerField

89

90

91 def DoubleField(**kw: typing.Any) -> float:

92 """

93 Pydal type is double, Python type is float.

94 """

95 kw["type"] = "double"

96 return TypedField(float, **kw)

97

98

99 Double = DoubleField

100

101

102 def DecimalField(n: int, m: int, **kw: typing.Any) -> decimal.Decimal:

103 """

104 Pydal type is decimal, Python type is Decimal.

105 """

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

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

108

109

110 Decimal = DecimalField

111

112

113 def DateField(**kw: typing.Any) -> dt.date:

114 """

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

116 """

117 kw["type"] = "date"

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

119

120

121 Date = DateField

122

123

124 def TimeField(**kw: typing.Any) -> dt.time:

125 """

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

127 """

128 kw["type"] = "time"

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

130

131

132 Time = TimeField

133

134

135 def DatetimeField(**kw: typing.Any) -> dt.datetime:

136 """

137 Pydal type is datetime, Python type is datetime.datetime.

138 """

139 kw["type"] = "datetime"

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

141

142

143 Datetime = DatetimeField

144

145

146 def PasswordField(**kw: typing.Any) -> str:

147 """

148 Pydal type is password, Python type is str.

149 """

150 kw["type"] = "password"

151 return TypedField(str, **kw)

152

153

154 Password = PasswordField

155

156

157 def UploadField(**kw: typing.Any) -> str:

158 """

159 Pydal type is upload, Python type is str.

160 """

161 kw["type"] = "upload"

162 return TypedField(str, **kw)

163

164

165 Upload = UploadField

166

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

168

169

170 def ReferenceField(other_table: str | TypedTable | Table | T_subclass, **kw: typing.Any) -> int:

171 """

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

173 """

174 if isinstance(other_table, str):

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

176 elif isinstance(other_table, Table):

177 # db.table

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

179 elif issubclass(type(other_table), type) and issubclass(other_table, TypedTable):

180 # SomeTable

181 snakename = TypeDAL._to_snake(other_table.__name__)

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

183 else:

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

185

186 return TypedField(int, **kw)

187

188

189 Reference = ReferenceField

190

191

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

193 """

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

195 """

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

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

198

199

200 ListString = ListStringField

201

202

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

204 """

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

206 """

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

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

209

210

211 ListInteger = ListIntegerField

212

213

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

215 """

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

217 """

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

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

220

221

222 ListReference = ListReferenceField

223

224

225 def JSONField(**kw: typing.Any) -> object:

226 """

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

228 """

229 kw["type"] = "json"

230 return TypedField(object, **kw)

231

232

233 def BigintField(**kw: typing.Any) -> int:

234 """

235 Pydal type is bigint, Python type is int.

236 """

237 kw["type"] = "bigint"

238 return TypedField(int, **kw)

239

240

241 Bigint = BigintField