sqlobjects 0.1.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.
- sqlobjects/__init__.py +38 -0
- sqlobjects/config.py +519 -0
- sqlobjects/database.py +586 -0
- sqlobjects/exceptions.py +538 -0
- sqlobjects/expressions.py +1054 -0
- sqlobjects/fields.py +1866 -0
- sqlobjects/history.py +101 -0
- sqlobjects/metadata.py +1130 -0
- sqlobjects/model.py +1009 -0
- sqlobjects/objects.py +812 -0
- sqlobjects/queries.py +1059 -0
- sqlobjects/relations.py +843 -0
- sqlobjects/session.py +389 -0
- sqlobjects/signals.py +464 -0
- sqlobjects/utils/__init__.py +5 -0
- sqlobjects/utils/naming.py +53 -0
- sqlobjects/utils/pattern.py +644 -0
- sqlobjects/validators.py +294 -0
- sqlobjects-0.1.0.dist-info/METADATA +29 -0
- sqlobjects-0.1.0.dist-info/RECORD +23 -0
- sqlobjects-0.1.0.dist-info/WHEEL +5 -0
- sqlobjects-0.1.0.dist-info/licenses/LICENSE +21 -0
- sqlobjects-0.1.0.dist-info/top_level.txt +1 -0
sqlobjects/validators.py
ADDED
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
"""SQLObjects Validators Module - Field validation system"""
|
|
2
|
+
|
|
3
|
+
from abc import ABC, abstractmethod
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from .exceptions import ValidationError
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"FieldValidator",
|
|
11
|
+
"LengthValidator",
|
|
12
|
+
"RangeValidator",
|
|
13
|
+
"EmailValidator",
|
|
14
|
+
"validate_field_value",
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class FieldValidator(ABC):
|
|
19
|
+
"""Base class for field validators.
|
|
20
|
+
|
|
21
|
+
This abstract base class defines the interface for all field validators
|
|
22
|
+
in the SQLObjects system. Validators are used to ensure data integrity
|
|
23
|
+
and enforce business rules on model fields.
|
|
24
|
+
|
|
25
|
+
Examples:
|
|
26
|
+
>>> class CustomValidator(FieldValidator):
|
|
27
|
+
... def validate(self, value: Any, field_name: str) -> Any:
|
|
28
|
+
... if value and len(str(value)) < 3:
|
|
29
|
+
... raise ValidationError(self.get_error_message(field_name, value))
|
|
30
|
+
... return value
|
|
31
|
+
...
|
|
32
|
+
... def get_error_message(self, field_name: str, value: Any) -> str:
|
|
33
|
+
... return f"Field '{field_name}' must be at least 3 characters long"
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
@abstractmethod
|
|
37
|
+
def validate(self, value: Any, field_name: str) -> Any:
|
|
38
|
+
"""Validate and return the processed value.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
value: The value to validate
|
|
42
|
+
field_name: Name of the field being validated
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
The validated (and potentially transformed) value
|
|
46
|
+
|
|
47
|
+
Raises:
|
|
48
|
+
ValidationError: If validation fails
|
|
49
|
+
"""
|
|
50
|
+
pass
|
|
51
|
+
|
|
52
|
+
@abstractmethod
|
|
53
|
+
def get_error_message(self, field_name: str, value: Any) -> str:
|
|
54
|
+
"""Get the error message for validation failure.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
field_name: Name of the field that failed validation
|
|
58
|
+
value: The value that failed validation
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
Human-readable error message
|
|
62
|
+
"""
|
|
63
|
+
pass
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class LengthValidator(FieldValidator):
|
|
67
|
+
"""Validator for string/value length constraints.
|
|
68
|
+
|
|
69
|
+
This validator ensures that the string representation of a value
|
|
70
|
+
meets minimum and/or maximum length requirements.
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
min_length: Minimum required length (default: 0)
|
|
74
|
+
max_length: Maximum allowed length (optional)
|
|
75
|
+
|
|
76
|
+
Examples:
|
|
77
|
+
>>> # Username must be 3-20 characters
|
|
78
|
+
>>> username_validator = LengthValidator(min_length=3, max_length=20)
|
|
79
|
+
>>> username_validator.validate("john", "username") # Valid
|
|
80
|
+
>>> username_validator.validate("jo", "username") # Raises ValidationError
|
|
81
|
+
|
|
82
|
+
>>> # Description must be at least 10 characters
|
|
83
|
+
>>> desc_validator = LengthValidator(min_length=10)
|
|
84
|
+
>>> desc_validator.validate("Short desc", "description") # Valid
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
def __init__(self, min_length: int = 0, max_length: int | None = None):
|
|
88
|
+
self.min_length = min_length
|
|
89
|
+
self.max_length = max_length
|
|
90
|
+
|
|
91
|
+
def validate(self, value: Any, field_name: str) -> Any:
|
|
92
|
+
"""Validate the length of the value.
|
|
93
|
+
|
|
94
|
+
Args:
|
|
95
|
+
value: The value to validate
|
|
96
|
+
field_name: Name of the field being validated
|
|
97
|
+
|
|
98
|
+
Returns:
|
|
99
|
+
The original value if validation passes
|
|
100
|
+
|
|
101
|
+
Raises:
|
|
102
|
+
ValidationError: If the value length is outside the allowed range
|
|
103
|
+
"""
|
|
104
|
+
if value is None:
|
|
105
|
+
return value
|
|
106
|
+
|
|
107
|
+
length = len(str(value))
|
|
108
|
+
if length < self.min_length:
|
|
109
|
+
raise ValidationError(self.get_error_message(field_name, value))
|
|
110
|
+
if self.max_length and length > self.max_length:
|
|
111
|
+
raise ValidationError(self.get_error_message(field_name, value))
|
|
112
|
+
|
|
113
|
+
return value
|
|
114
|
+
|
|
115
|
+
def get_error_message(self, field_name: str, value: Any) -> str:
|
|
116
|
+
"""Get the error message for length validation failure.
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
field_name: Name of the field that failed validation
|
|
120
|
+
value: The value that failed validation
|
|
121
|
+
|
|
122
|
+
Returns:
|
|
123
|
+
Human-readable error message describing the length requirement
|
|
124
|
+
"""
|
|
125
|
+
if self.max_length:
|
|
126
|
+
return f"Field '{field_name}' length must be between {self.min_length} and {self.max_length}"
|
|
127
|
+
return f"Field '{field_name}' length must be at least {self.min_length}"
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
class RangeValidator(FieldValidator):
|
|
131
|
+
"""Validator for numeric range constraints.
|
|
132
|
+
|
|
133
|
+
This validator ensures that numeric values fall within specified
|
|
134
|
+
minimum and/or maximum bounds. The value is converted to float
|
|
135
|
+
for comparison.
|
|
136
|
+
|
|
137
|
+
Args:
|
|
138
|
+
min_value: Minimum allowed value (optional)
|
|
139
|
+
max_value: Maximum allowed value (optional)
|
|
140
|
+
|
|
141
|
+
Examples:
|
|
142
|
+
>>> # Age must be between 0 and 150
|
|
143
|
+
>>> age_validator = RangeValidator(min_value=0, max_value=150)
|
|
144
|
+
>>> age_validator.validate(25, "age") # Valid
|
|
145
|
+
>>> age_validator.validate(-5, "age") # Raises ValidationError
|
|
146
|
+
|
|
147
|
+
>>> # Price must be at least 0
|
|
148
|
+
>>> price_validator = RangeValidator(min_value=0)
|
|
149
|
+
>>> price_validator.validate(19.99, "price") # Valid
|
|
150
|
+
"""
|
|
151
|
+
|
|
152
|
+
def __init__(self, min_value: float | None = None, max_value: float | None = None):
|
|
153
|
+
self.min_value = min_value
|
|
154
|
+
self.max_value = max_value
|
|
155
|
+
|
|
156
|
+
def validate(self, value: Any, field_name: str) -> Any:
|
|
157
|
+
"""Validate the numeric range of the value.
|
|
158
|
+
|
|
159
|
+
Args:
|
|
160
|
+
value: The value to validate
|
|
161
|
+
field_name: Name of the field being validated
|
|
162
|
+
|
|
163
|
+
Returns:
|
|
164
|
+
The original value if validation passes
|
|
165
|
+
|
|
166
|
+
Raises:
|
|
167
|
+
ValidationError: If the value is not numeric or outside the allowed range
|
|
168
|
+
"""
|
|
169
|
+
if value is None:
|
|
170
|
+
return value
|
|
171
|
+
|
|
172
|
+
try:
|
|
173
|
+
num_value = float(value)
|
|
174
|
+
except (ValueError, TypeError) as e:
|
|
175
|
+
raise ValidationError(f"Field '{field_name}' must be a number") from e
|
|
176
|
+
|
|
177
|
+
if self.min_value is not None and num_value < self.min_value:
|
|
178
|
+
raise ValidationError(self.get_error_message(field_name, value))
|
|
179
|
+
if self.max_value is not None and num_value > self.max_value:
|
|
180
|
+
raise ValidationError(self.get_error_message(field_name, value))
|
|
181
|
+
|
|
182
|
+
return value
|
|
183
|
+
|
|
184
|
+
def get_error_message(self, field_name: str, value: Any) -> str:
|
|
185
|
+
"""Get the error message for range validation failure.
|
|
186
|
+
|
|
187
|
+
Args:
|
|
188
|
+
field_name: Name of the field that failed validation
|
|
189
|
+
value: The value that failed validation
|
|
190
|
+
|
|
191
|
+
Returns:
|
|
192
|
+
Human-readable error message describing the range requirement
|
|
193
|
+
"""
|
|
194
|
+
if self.min_value is not None and self.max_value is not None:
|
|
195
|
+
return f"Field '{field_name}' must be between {self.min_value} and {self.max_value}"
|
|
196
|
+
elif self.min_value is not None:
|
|
197
|
+
return f"Field '{field_name}' must be at least {self.min_value}"
|
|
198
|
+
else:
|
|
199
|
+
return f"Field '{field_name}' must be at most {self.max_value}"
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
class EmailValidator(FieldValidator):
|
|
203
|
+
"""Validator for email address format.
|
|
204
|
+
|
|
205
|
+
This validator performs basic email format validation by checking
|
|
206
|
+
for the presence of '@' symbol and a dot in the domain part.
|
|
207
|
+
For production use, consider using more comprehensive email
|
|
208
|
+
validation libraries.
|
|
209
|
+
|
|
210
|
+
Examples:
|
|
211
|
+
>>> email_validator = EmailValidator()
|
|
212
|
+
>>> email_validator.validate("user@example.com", "email") # Valid
|
|
213
|
+
>>> email_validator.validate("invalid-email", "email") # Raises ValidationError
|
|
214
|
+
>>> email_validator.validate("user@domain", "email") # Raises ValidationError
|
|
215
|
+
"""
|
|
216
|
+
|
|
217
|
+
def validate(self, value: Any, field_name: str) -> Any:
|
|
218
|
+
"""Validate the email address format.
|
|
219
|
+
|
|
220
|
+
Args:
|
|
221
|
+
value: The value to validate
|
|
222
|
+
field_name: Name of the field being validated
|
|
223
|
+
|
|
224
|
+
Returns:
|
|
225
|
+
The original value if validation passes
|
|
226
|
+
|
|
227
|
+
Raises:
|
|
228
|
+
ValidationError: If the value is not a valid email format
|
|
229
|
+
"""
|
|
230
|
+
if value is None:
|
|
231
|
+
return value
|
|
232
|
+
|
|
233
|
+
email_str = str(value)
|
|
234
|
+
if "@" not in email_str or "." not in email_str.split("@")[-1]:
|
|
235
|
+
raise ValidationError(self.get_error_message(field_name, value))
|
|
236
|
+
|
|
237
|
+
return value
|
|
238
|
+
|
|
239
|
+
def get_error_message(self, field_name: str, value: Any) -> str:
|
|
240
|
+
"""Get the error message for email validation failure.
|
|
241
|
+
|
|
242
|
+
Args:
|
|
243
|
+
field_name: Name of the field that failed validation
|
|
244
|
+
value: The value that failed validation
|
|
245
|
+
|
|
246
|
+
Returns:
|
|
247
|
+
Human-readable error message for invalid email format
|
|
248
|
+
"""
|
|
249
|
+
return f"Field '{field_name}' must be a valid email address"
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
def validate_field_value(validators: list[Any], value: Any, field_name: str) -> Any:
|
|
253
|
+
"""Validate a field value using a list of validators.
|
|
254
|
+
|
|
255
|
+
This function applies multiple validators to a field value in sequence.
|
|
256
|
+
It supports both FieldValidator instances and simple callable functions.
|
|
257
|
+
|
|
258
|
+
Args:
|
|
259
|
+
validators: List of validators to apply
|
|
260
|
+
value: The value to validate
|
|
261
|
+
field_name: Name of the field being validated
|
|
262
|
+
|
|
263
|
+
Returns:
|
|
264
|
+
The validated (and potentially transformed) value
|
|
265
|
+
|
|
266
|
+
Raises:
|
|
267
|
+
ValidationError: If any validator fails
|
|
268
|
+
|
|
269
|
+
Examples:
|
|
270
|
+
>>> validators = [LengthValidator(min_length=3, max_length=50), EmailValidator()]
|
|
271
|
+
>>> validate_field_value(validators, "user@example.com", "email")
|
|
272
|
+
'user@example.com'
|
|
273
|
+
|
|
274
|
+
>>> # Using simple function validator
|
|
275
|
+
>>> def no_spaces(value):
|
|
276
|
+
... if " " in str(value):
|
|
277
|
+
... raise ValueError("No spaces allowed")
|
|
278
|
+
... return value
|
|
279
|
+
>>> validate_field_value([no_spaces], "username", "username")
|
|
280
|
+
'username'
|
|
281
|
+
"""
|
|
282
|
+
for validator in validators:
|
|
283
|
+
if isinstance(validator, FieldValidator):
|
|
284
|
+
value = validator.validate(value, field_name)
|
|
285
|
+
elif callable(validator):
|
|
286
|
+
# Support for simple function validators
|
|
287
|
+
try:
|
|
288
|
+
result = validator(value)
|
|
289
|
+
if result is not None:
|
|
290
|
+
value = result
|
|
291
|
+
except Exception as e:
|
|
292
|
+
raise ValidationError(f"Validation failed for {field_name}: {e}") from e
|
|
293
|
+
|
|
294
|
+
return value
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: sqlobjects
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Django-style async ORM library based on SQLAlchemy with chainable queries, Q objects, and relationship loading
|
|
5
|
+
Author-email: XtraVisions <gitadmin@xtravisions.com>, Chen Hao <chenhao@xtravisions.com>
|
|
6
|
+
Maintainer-email: XtraVisions <gitadmin@xtravisions.com>, Chen Hao <chenhao@xtravisions.com>
|
|
7
|
+
License: MIT
|
|
8
|
+
Project-URL: Homepage, https://github.com/XtraVisionsAI/sqlobjects
|
|
9
|
+
Project-URL: Repository, https://github.com/XtraVisionsAI/sqlobjects.git
|
|
10
|
+
Project-URL: Documentation, https://github.com/XtraVisionsAI/sqlobjects#readme
|
|
11
|
+
Project-URL: Bug Tracker, https://github.com/XtraVisionsAI/sqlobjects/issues
|
|
12
|
+
Project-URL: Changelog, https://github.com/XtraVisionsAI/sqlobjects/blob/main/CHANGELOG.md
|
|
13
|
+
Keywords: python,orm,async,django-style,database,query
|
|
14
|
+
Classifier: Development Status :: 4 - Beta
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
21
|
+
Classifier: Topic :: Database
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
|
+
Classifier: Framework :: AsyncIO
|
|
24
|
+
Classifier: Typing :: Typed
|
|
25
|
+
Requires-Python: >=3.12
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
License-File: LICENSE
|
|
28
|
+
Requires-Dist: sqlalchemy[asyncio]>=2.0.43
|
|
29
|
+
Dynamic: license-file
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
sqlobjects/__init__.py,sha256=ptVLnrTySBdIHFl9Nj3oVDpY_2ssu8riX3pg-_h3T50,1165
|
|
2
|
+
sqlobjects/config.py,sha256=WW8Dzf-8IY0j3i0kwzVt19rELXENSkBi1fpRl6Us5l0,19295
|
|
3
|
+
sqlobjects/database.py,sha256=Vciywb0FWb1ChGYEfbqtBjopyiIR3KDHtH4p7bePc8g,19848
|
|
4
|
+
sqlobjects/exceptions.py,sha256=J0mKk77JhJmJ28Gv80DckstB9rM_ky61Cq1ZwO4kbkE,18212
|
|
5
|
+
sqlobjects/expressions.py,sha256=QyK3k_q4UaA5OLKu-fDkdiAc9dKHdplJd49OABCDzjk,38218
|
|
6
|
+
sqlobjects/fields.py,sha256=5_vi31Bix7OSH0zp16WGjcbeT0f8x7iR7EA-gM8kj6k,56822
|
|
7
|
+
sqlobjects/history.py,sha256=hcO-P3XcgdUF2zTL9IBv-2rfo0LKIZqdDAuIqSN6TA8,3742
|
|
8
|
+
sqlobjects/metadata.py,sha256=PL1ow7xptGzVaXUQ6aqv2lS1MFCf1eP_bK3GnUqMQ_8,40459
|
|
9
|
+
sqlobjects/model.py,sha256=-qnDZm9DMtE23tzcKNrVjHMJBO2dqIH11FtnD0tBO78,35014
|
|
10
|
+
sqlobjects/objects.py,sha256=DkjdIzlkO2JFhY5C34U0wAXPoy9gk_k2GFIkfJ6GBbg,29546
|
|
11
|
+
sqlobjects/queries.py,sha256=UysAA3Zmi0_sm0DTfHLotkKe7vXNJuTiQ64VyFnYMIQ,39992
|
|
12
|
+
sqlobjects/relations.py,sha256=oY4Wt3jxCJokATvQ5ukF79-f8yKU46Y7JrzbwxxFF-Y,27684
|
|
13
|
+
sqlobjects/session.py,sha256=-F6ia0DMWL2DPRw7aizBvzt7XNrz9aPZJYunvdkj2G4,13743
|
|
14
|
+
sqlobjects/signals.py,sha256=ybUFi5KD7kve8jHtr8QJuqLxg-opCoLDsDl5QJtkqT8,17680
|
|
15
|
+
sqlobjects/validators.py,sha256=cWZOVYw__No5YetGAFe4RBpXY14EKFxb7OkZoERyeAk,10114
|
|
16
|
+
sqlobjects/utils/__init__.py,sha256=NsJ52Fl_PaB-2WlOIJVGNPmgOnqPmvYRmp7uaq5zfYs,192
|
|
17
|
+
sqlobjects/utils/naming.py,sha256=PmfNuEz-Twly2qREjKfMNulJt8TmOUJaxzFTuts3COg,1411
|
|
18
|
+
sqlobjects/utils/pattern.py,sha256=FGCgobTpnmKjdAtQidHIg4Xa2CQLeP35F0VuX_1T1dk,14740
|
|
19
|
+
sqlobjects-0.1.0.dist-info/licenses/LICENSE,sha256=ScFR7nvWIhar0d32Y-LA4vqp9zNmy1HSJia7UX7jU6c,1068
|
|
20
|
+
sqlobjects-0.1.0.dist-info/METADATA,sha256=DzDRI2_FR9FtvYD-9b7m_JydZC54TKwu1IchBXNGKks,1466
|
|
21
|
+
sqlobjects-0.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
22
|
+
sqlobjects-0.1.0.dist-info/top_level.txt,sha256=brO5vDtCpn4L9dpX0EHpehbu4kcHaK_2Bbnwze35YKc,11
|
|
23
|
+
sqlobjects-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 XtraVisions
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
sqlobjects
|