dbentity 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
dbentity/__init__.py ADDED
@@ -0,0 +1,6 @@
1
+ """Lightweight Python ORM library for PostgreSQL"""
2
+
3
+ try:
4
+ from dbentity._version import version as __version__
5
+ except ImportError:
6
+ __version__ = "0.0.0"
dbentity/_version.py ADDED
@@ -0,0 +1,24 @@
1
+ # file generated by vcs-versioning
2
+ # don't change, don't track in version control
3
+ from __future__ import annotations
4
+
5
+ __all__ = [
6
+ "__version__",
7
+ "__version_tuple__",
8
+ "version",
9
+ "version_tuple",
10
+ "__commit_id__",
11
+ "commit_id",
12
+ ]
13
+
14
+ version: str
15
+ __version__: str
16
+ __version_tuple__: tuple[int | str, ...]
17
+ version_tuple: tuple[int | str, ...]
18
+ commit_id: str | None
19
+ __commit_id__: str | None
20
+
21
+ __version__ = version = '1.0.0'
22
+ __version_tuple__ = version_tuple = (1, 0, 0)
23
+
24
+ __commit_id__ = commit_id = None
dbentity/attribute.py ADDED
@@ -0,0 +1,417 @@
1
+ import time as _time
2
+ import datetime as _datetime
3
+
4
+
5
+ class AttributeException(Exception):
6
+ """General Data object error"""
7
+
8
+
9
+ class NumberOutOfRangeException(AttributeException):
10
+ """If number is out of range"""
11
+
12
+
13
+ class WrongNumberFormatException(AttributeException):
14
+ """If number is out of range"""
15
+
16
+
17
+ def last_time_to_string(secondsf):
18
+ seconds = int(secondsf)
19
+ minutes = int(seconds // 60)
20
+ hours = int(minutes // 60)
21
+ days = int(hours // 24)
22
+ seconds %= 60
23
+ minutes %= 60
24
+ hours %= 24
25
+ since_str = ''
26
+ if days:
27
+ since_str = f"{days}d {hours:02d}h {minutes:02d}m {seconds:02d}s"
28
+ elif hours:
29
+ since_str = f"{hours:02d}h {minutes:02d}m {seconds:02d}s"
30
+ elif minutes:
31
+ since_str = f"{minutes:02d}m {seconds:02d}s"
32
+ elif seconds > 10:
33
+ since_str = f"{secondsf:.1f}s"
34
+ elif seconds > 1:
35
+ since_str = f"{secondsf:.2f}s"
36
+ elif seconds > .1:
37
+ since_str = f"{secondsf:.3f}s"
38
+ else:
39
+ since_str = f"{secondsf / 1000:.1f}ms"
40
+ return since_str
41
+
42
+
43
+ class Attribute():
44
+ CREATE = True
45
+ SAVE = True
46
+ INDEX = False
47
+ CONNECTION = False
48
+ CONNECTIONS = False
49
+ FUNCTION = None
50
+
51
+ def __init__(
52
+ self,
53
+ name,
54
+ db_key=None,
55
+ form_key=None,
56
+ default=None):
57
+ self._name = name
58
+ self._db_key = db_key
59
+ self._form_key = form_key
60
+ self._default = default
61
+
62
+ def __repr__(self):
63
+ return f'{self.__class__.__name__}:{self._name}'
64
+
65
+ @property
66
+ def name(self):
67
+ return self._name
68
+
69
+ @property
70
+ def db_key(self):
71
+ if self._db_key is None:
72
+ self._db_key = self._name
73
+ return self._db_key
74
+
75
+ @property
76
+ def form_key(self):
77
+ return self._form_key
78
+
79
+ @property
80
+ def default(self):
81
+ return self._default
82
+
83
+ def is_name(self, name):
84
+ return name == self._name
85
+
86
+ def is_form_key(self, form_key):
87
+ return form_key == self._form_key
88
+
89
+ def to_template(self, value):
90
+ if value is None:
91
+ value = ''
92
+ return value
93
+
94
+ def from_form(self, value):
95
+ if value is None and self._default is not None:
96
+ value = self._default
97
+ return value
98
+
99
+ def to_value(self, value):
100
+ return value
101
+
102
+ def to_json(self, value):
103
+ return value
104
+
105
+ def from_value(self, value):
106
+ return value
107
+
108
+
109
+ class IndexAttribute(Attribute):
110
+ CREATE = False
111
+ SAVE = False
112
+ INDEX = True
113
+
114
+ def __init__(
115
+ self,
116
+ name=None,
117
+ db_key=None):
118
+ if name is None:
119
+ name = 'uid'
120
+ if db_key is None:
121
+ db_key = 'id'
122
+ super().__init__(name, db_key=db_key)
123
+
124
+
125
+ class CreateIndexAttribute(IndexAttribute):
126
+ CREATE = True
127
+
128
+
129
+ class DatetimeAttribute(Attribute):
130
+ def to_json(self, value):
131
+ if isinstance(value, _datetime.datetime):
132
+ return {
133
+ 'datetime': value.strftime('%Y-%m-%d %H:%M:%S'),
134
+ 'datetime_short': value.strftime('%Y%m%d%H%M%S'),
135
+ 'timestamp': value.timestamp(),
136
+ }
137
+ return value
138
+
139
+ def to_template(self, value):
140
+ if isinstance(value, _datetime.datetime):
141
+ return {
142
+ 'datetime': value.strftime('%Y-%m-%d %H:%M:%S'),
143
+ 'datetime_short': value.strftime('%Y%m%d%H%M%S'),
144
+ 'timestamp': value.timestamp(),
145
+ }
146
+ return value
147
+
148
+
149
+ class LastTimeAttribute(Attribute):
150
+ def to_json(self, value):
151
+ if isinstance(value, (int, float)):
152
+ return _time.time() - value
153
+
154
+ def to_value(self, value):
155
+ if isinstance(value, (int, float)):
156
+ return _time.time() - value
157
+
158
+ def to_template(self, value):
159
+ if isinstance(value, (int, float)):
160
+ secondsf = _time.time() - value
161
+ since_str = last_time_to_string(secondsf)
162
+ return {
163
+ 'timestamp': value,
164
+ 'since_sec': secondsf,
165
+ 'since_str': since_str}
166
+ return value
167
+
168
+
169
+ class MinLastTimeAttribute(Attribute):
170
+ FUNCTION = 'MIN'
171
+
172
+
173
+ class MaxLastTimeAttribute(Attribute):
174
+ FUNCTION = 'MAX'
175
+
176
+
177
+ class StringAttribute(Attribute):
178
+ pass
179
+
180
+
181
+ class BytesAttribute(Attribute):
182
+ def to_json(self, value):
183
+ if value is None:
184
+ return None
185
+ return repr(bytes(value))
186
+
187
+ def to_template(self, value):
188
+ if value is None:
189
+ return None
190
+ return repr(bytes(value))
191
+
192
+
193
+ class PasswordAttribute(Attribute):
194
+ def to_template(self, value):
195
+ return ""
196
+
197
+
198
+ class BooleanAttribute(Attribute):
199
+ def from_form(self, value):
200
+ if value is None and self._default is not None:
201
+ value = self._default
202
+ return bool(value)
203
+
204
+
205
+ class IntegerAttribute(Attribute):
206
+ def __init__(
207
+ self,
208
+ name,
209
+ db_key=None,
210
+ form_key=None,
211
+ default=None,
212
+ minimal=None,
213
+ maximal=None):
214
+ self._min = minimal
215
+ self._max = maximal
216
+ super().__init__(
217
+ name,
218
+ db_key=db_key,
219
+ form_key=form_key,
220
+ default=default)
221
+
222
+ def from_form(self, value):
223
+ if not value:
224
+ return None
225
+ if not value.lstrip('+-').isdigit():
226
+ raise WrongNumberFormatException()
227
+ value = int(value)
228
+ if self._min is not None and value < self._min:
229
+ raise NumberOutOfRangeException()
230
+ if self._max is not None and value > self._max:
231
+ raise NumberOutOfRangeException()
232
+ return value
233
+
234
+
235
+ class SumIntegerAttribute(Attribute):
236
+ FUNCTION = 'SUM'
237
+
238
+ def __init__(
239
+ self,
240
+ name,
241
+ db_key=None,
242
+ form_key=None,
243
+ default=None,
244
+ minimal=None,
245
+ maximal=None):
246
+ self._min = minimal
247
+ self._max = maximal
248
+ super().__init__(
249
+ name,
250
+ db_key=db_key,
251
+ form_key=form_key,
252
+ default=default)
253
+
254
+
255
+ class IntegerArrayAttribute(Attribute):
256
+ def __init__(
257
+ self,
258
+ name,
259
+ db_key=None,
260
+ form_key=None,
261
+ default=None,
262
+ minimal=None,
263
+ maximal=None):
264
+ self._min = minimal
265
+ self._max = maximal
266
+ super().__init__(
267
+ name,
268
+ db_key=db_key,
269
+ form_key=form_key,
270
+ default=default)
271
+
272
+ def from_form(self, values):
273
+ if not values:
274
+ return None
275
+ if not isinstance(values, (list, tuple)):
276
+ values = [values]
277
+ new_values = set()
278
+ if values:
279
+ for value in values:
280
+ if not value.lstrip('+-').isdigit():
281
+ raise WrongNumberFormatException()
282
+ new_value = int(value)
283
+ if self._min is not None and new_value < self._min:
284
+ raise NumberOutOfRangeException()
285
+ if self._max is not None and new_value > self._max:
286
+ raise NumberOutOfRangeException()
287
+ new_values.add(new_value)
288
+ return sorted(new_values)
289
+
290
+
291
+ class FixedPointAttribute(Attribute):
292
+ def __init__(
293
+ self,
294
+ name,
295
+ db_key=None,
296
+ form_key=None,
297
+ default=None,
298
+ fp=0,
299
+ minimal=None,
300
+ maximal=None):
301
+ self._fp = fp
302
+ self._min = minimal
303
+ self._max = maximal
304
+ super().__init__(
305
+ name,
306
+ db_key=db_key,
307
+ form_key=form_key,
308
+ default=default)
309
+
310
+ def from_form(self, value):
311
+ if value is None:
312
+ return None
313
+ value = value.replace(',', '.')
314
+ if not value.lstrip('+-').replace('.', '', 1).isdigit():
315
+ raise WrongNumberFormatException()
316
+ value = float(value)
317
+ if self._min is not None and value < self._min:
318
+ raise NumberOutOfRangeException()
319
+ if self._max is not None and value > self._max:
320
+ raise NumberOutOfRangeException()
321
+ return round(value * 10 ** self._fp)
322
+
323
+ def to_template(self, value):
324
+ if value is None:
325
+ return ''
326
+ return value / 10 ** self._fp
327
+
328
+ def to_value(self, value):
329
+ if value is None:
330
+ return None
331
+ return value / 10 ** self._fp
332
+
333
+ def from_value(self, value):
334
+ if value is None:
335
+ return None
336
+ return value * 10 ** self._fp
337
+
338
+
339
+ class SumFixedPointAttribute(Attribute):
340
+ FUNCTION = 'SUM'
341
+
342
+ def __init__(
343
+ self,
344
+ name,
345
+ db_key=None,
346
+ form_key=None,
347
+ default=None,
348
+ fp=0,
349
+ minimal=None,
350
+ maximal=None):
351
+ self._fp = fp
352
+ self._min = minimal
353
+ self._max = maximal
354
+ super().__init__(
355
+ name,
356
+ db_key=db_key,
357
+ form_key=form_key,
358
+ default=default)
359
+
360
+ def to_template(self, value):
361
+ if value is None:
362
+ return ''
363
+ return value / 10 ** self._fp
364
+
365
+ def to_value(self, value):
366
+ if value is None:
367
+ return None
368
+ return value / 10 ** self._fp
369
+
370
+
371
+ class ConnectionAttribute(Attribute):
372
+ SAVE = False
373
+ CONNECTION = True
374
+
375
+ def __init__(
376
+ self,
377
+ name,
378
+ sub_entity=None,
379
+ db_key=None,
380
+ conn_key=None):
381
+ self._sub_entity = sub_entity
382
+ self._conn_key = conn_key
383
+ super().__init__(name, db_key=db_key)
384
+
385
+ @property
386
+ def sub_entity(self):
387
+ return self._sub_entity
388
+
389
+ @property
390
+ def db_key(self):
391
+ if self._db_key is None:
392
+ self._db_key = f'{self._name}_id'
393
+ return self._db_key
394
+
395
+ @property
396
+ def conn_key(self):
397
+ if self._conn_key is None:
398
+ self._conn_key = 'id'
399
+ return self._conn_key
400
+
401
+ @property
402
+ def save(self):
403
+ return False
404
+
405
+
406
+ class SubElementsAttribute(Attribute):
407
+ SAVE = False
408
+ CONNECTIONS = True
409
+
410
+ def __init__(
411
+ self,
412
+ name):
413
+ super().__init__(name, db_key=False)
414
+
415
+ @property
416
+ def save(self):
417
+ return False