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

88 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-06-27 17:35 +0200

1""" 

2This file contains available Field types. 

3""" 

4 

5import datetime as dt 

6import decimal 

7import types 

8import typing 

9 

10from pydal.objects import Table 

11 

12from .core import TypeDAL, TypedFieldType, TypedTable 

13 

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

15 

16 

17## general 

18 

19 

20def 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 

36def 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 

44String = StringField 

45 

46 

47def 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 

55Text = TextField 

56 

57 

58def 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 

66Blob = BlobField 

67 

68 

69def 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 

77Boolean = BooleanField 

78 

79 

80def 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 

88Integer = IntegerField 

89 

90 

91def 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 

99Double = DoubleField 

100 

101 

102def 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 

110Decimal = DecimalField 

111 

112 

113def 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 

121Date = DateField 

122 

123 

124def 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 

132Time = TimeField 

133 

134 

135def 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 

143Datetime = DatetimeField 

144 

145 

146def 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 

154Password = PasswordField 

155 

156 

157def 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 

165Upload = UploadField 

166 

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

168 

169 

170def 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 

189Reference = ReferenceField 

190 

191 

192def 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 

200ListString = ListStringField 

201 

202 

203def 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 

211ListInteger = ListIntegerField 

212 

213 

214def 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 

222ListReference = ListReferenceField 

223 

224 

225def 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 

233def 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 

241Bigint = BigintField