fastapi-rtk 0.2.27__py3-none-any.whl → 1.0.13__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.
- fastapi_rtk/__init__.py +39 -35
- fastapi_rtk/_version.py +1 -0
- fastapi_rtk/api/model_rest_api.py +476 -221
- fastapi_rtk/auth/auth.py +0 -9
- fastapi_rtk/backends/generic/__init__.py +6 -0
- fastapi_rtk/backends/generic/column.py +21 -12
- fastapi_rtk/backends/generic/db.py +42 -7
- fastapi_rtk/backends/generic/filters.py +21 -16
- fastapi_rtk/backends/generic/interface.py +14 -8
- fastapi_rtk/backends/generic/model.py +19 -11
- fastapi_rtk/backends/sqla/__init__.py +1 -0
- fastapi_rtk/backends/sqla/db.py +77 -17
- fastapi_rtk/backends/sqla/extensions/audit/audit.py +401 -189
- fastapi_rtk/backends/sqla/extensions/geoalchemy2/filters.py +15 -12
- fastapi_rtk/backends/sqla/filters.py +50 -21
- fastapi_rtk/backends/sqla/interface.py +96 -34
- fastapi_rtk/backends/sqla/model.py +56 -39
- fastapi_rtk/bases/__init__.py +20 -0
- fastapi_rtk/bases/db.py +94 -7
- fastapi_rtk/bases/file_manager.py +47 -3
- fastapi_rtk/bases/filter.py +22 -0
- fastapi_rtk/bases/interface.py +49 -5
- fastapi_rtk/bases/model.py +3 -0
- fastapi_rtk/bases/session.py +2 -0
- fastapi_rtk/cli/cli.py +62 -9
- fastapi_rtk/cli/commands/__init__.py +23 -0
- fastapi_rtk/cli/{db.py → commands/db/__init__.py} +107 -50
- fastapi_rtk/cli/{templates → commands/db/templates}/fastapi/env.py +2 -3
- fastapi_rtk/cli/{templates → commands/db/templates}/fastapi-multidb/env.py +10 -9
- fastapi_rtk/cli/{templates → commands/db/templates}/fastapi-multidb/script.py.mako +3 -1
- fastapi_rtk/cli/{export.py → commands/export.py} +12 -10
- fastapi_rtk/cli/{security.py → commands/security.py} +73 -7
- fastapi_rtk/cli/commands/translate.py +299 -0
- fastapi_rtk/cli/decorators.py +9 -4
- fastapi_rtk/cli/utils.py +46 -0
- fastapi_rtk/config.py +41 -1
- fastapi_rtk/const.py +29 -1
- fastapi_rtk/db.py +76 -40
- fastapi_rtk/decorators.py +1 -1
- fastapi_rtk/dependencies.py +134 -62
- fastapi_rtk/exceptions.py +51 -1
- fastapi_rtk/fastapi_react_toolkit.py +186 -171
- fastapi_rtk/file_managers/file_manager.py +8 -6
- fastapi_rtk/file_managers/s3_file_manager.py +69 -33
- fastapi_rtk/globals.py +22 -12
- fastapi_rtk/lang/__init__.py +3 -0
- fastapi_rtk/lang/babel/__init__.py +4 -0
- fastapi_rtk/lang/babel/cli.py +40 -0
- fastapi_rtk/lang/babel/config.py +17 -0
- fastapi_rtk/lang/babel.cfg +1 -0
- fastapi_rtk/lang/lazy_text.py +120 -0
- fastapi_rtk/lang/messages.pot +238 -0
- fastapi_rtk/lang/translations/de/LC_MESSAGES/messages.mo +0 -0
- fastapi_rtk/lang/translations/de/LC_MESSAGES/messages.po +248 -0
- fastapi_rtk/lang/translations/en/LC_MESSAGES/messages.mo +0 -0
- fastapi_rtk/lang/translations/en/LC_MESSAGES/messages.po +244 -0
- fastapi_rtk/manager.py +355 -37
- fastapi_rtk/mixins.py +12 -0
- fastapi_rtk/routers.py +208 -72
- fastapi_rtk/schemas.py +142 -39
- fastapi_rtk/security/sqla/apis.py +39 -13
- fastapi_rtk/security/sqla/models.py +8 -23
- fastapi_rtk/security/sqla/security_manager.py +369 -11
- fastapi_rtk/setting.py +446 -88
- fastapi_rtk/types.py +94 -27
- fastapi_rtk/utils/__init__.py +8 -0
- fastapi_rtk/utils/async_task_runner.py +286 -61
- fastapi_rtk/utils/csv_json_converter.py +243 -40
- fastapi_rtk/utils/hooks.py +34 -0
- fastapi_rtk/utils/merge_schema.py +3 -3
- fastapi_rtk/utils/multiple_async_contexts.py +21 -0
- fastapi_rtk/utils/pydantic.py +46 -1
- fastapi_rtk/utils/run_utils.py +31 -1
- fastapi_rtk/utils/self_dependencies.py +1 -1
- fastapi_rtk/utils/use_default_when_none.py +1 -1
- fastapi_rtk/version.py +6 -1
- fastapi_rtk-1.0.13.dist-info/METADATA +28 -0
- fastapi_rtk-1.0.13.dist-info/RECORD +133 -0
- {fastapi_rtk-0.2.27.dist-info → fastapi_rtk-1.0.13.dist-info}/WHEEL +1 -2
- fastapi_rtk/backends/gremlinpython/__init__.py +0 -108
- fastapi_rtk/backends/gremlinpython/column.py +0 -208
- fastapi_rtk/backends/gremlinpython/db.py +0 -228
- fastapi_rtk/backends/gremlinpython/exceptions.py +0 -34
- fastapi_rtk/backends/gremlinpython/filters.py +0 -461
- fastapi_rtk/backends/gremlinpython/interface.py +0 -734
- fastapi_rtk/backends/gremlinpython/model.py +0 -364
- fastapi_rtk/backends/gremlinpython/session.py +0 -23
- fastapi_rtk/cli/commands.py +0 -295
- fastapi_rtk-0.2.27.dist-info/METADATA +0 -23
- fastapi_rtk-0.2.27.dist-info/RECORD +0 -126
- fastapi_rtk-0.2.27.dist-info/top_level.txt +0 -1
- /fastapi_rtk/cli/{templates → commands/db/templates}/fastapi/README +0 -0
- /fastapi_rtk/cli/{templates → commands/db/templates}/fastapi/alembic.ini.mako +0 -0
- /fastapi_rtk/cli/{templates → commands/db/templates}/fastapi/script.py.mako +0 -0
- /fastapi_rtk/cli/{templates → commands/db/templates}/fastapi-multidb/README +0 -0
- /fastapi_rtk/cli/{templates → commands/db/templates}/fastapi-multidb/alembic.ini.mako +0 -0
- {fastapi_rtk-0.2.27.dist-info → fastapi_rtk-1.0.13.dist-info}/entry_points.txt +0 -0
- {fastapi_rtk-0.2.27.dist-info → fastapi_rtk-1.0.13.dist-info}/licenses/LICENSE +0 -0
fastapi_rtk/auth/auth.py
CHANGED
|
@@ -142,15 +142,6 @@ class Authenticator(BaseAuthenticator):
|
|
|
142
142
|
except HTTPException as e:
|
|
143
143
|
if not default_to_none:
|
|
144
144
|
raise e
|
|
145
|
-
|
|
146
|
-
# Retrieve list of apis, that user has access to
|
|
147
|
-
if user:
|
|
148
|
-
user.permissions = []
|
|
149
|
-
for role in user.roles:
|
|
150
|
-
for permission_api in role.permissions:
|
|
151
|
-
user.permissions.append(permission_api.api.name)
|
|
152
|
-
user.permissions = list(set(user.permissions))
|
|
153
|
-
|
|
154
145
|
return user, token
|
|
155
146
|
|
|
156
147
|
|
|
@@ -8,6 +8,10 @@ from .session import *
|
|
|
8
8
|
|
|
9
9
|
__all__ = [
|
|
10
10
|
# .column
|
|
11
|
+
"GenericPKAutoIncrement",
|
|
12
|
+
"GenericUnset",
|
|
13
|
+
"PK_AUTO_INCREMENT",
|
|
14
|
+
"UNSET",
|
|
11
15
|
"GenericColumn",
|
|
12
16
|
# .db
|
|
13
17
|
"GenericQueryBuilder",
|
|
@@ -36,10 +40,12 @@ __all__ = [
|
|
|
36
40
|
"GenericFilterSmallerEqual",
|
|
37
41
|
"GenericFilterIn",
|
|
38
42
|
"GenericFilterGlobal",
|
|
43
|
+
"GenericBaseOprFilter",
|
|
39
44
|
"GenericFilterConverter",
|
|
40
45
|
# .interface
|
|
41
46
|
"GenericInterface",
|
|
42
47
|
# .model
|
|
48
|
+
"GenericMapper",
|
|
43
49
|
"GenericModel",
|
|
44
50
|
# .session
|
|
45
51
|
"GenericSession",
|
|
@@ -9,31 +9,38 @@ from pydantic import (
|
|
|
9
9
|
create_model,
|
|
10
10
|
)
|
|
11
11
|
|
|
12
|
+
from ...mixins import LoggerMixin
|
|
12
13
|
from ...utils import T
|
|
13
14
|
from .exceptions import ColumnInvalidTypeException, GenericColumnException
|
|
14
15
|
|
|
15
16
|
if typing.TYPE_CHECKING:
|
|
16
17
|
from .model import GenericModel
|
|
17
18
|
|
|
18
|
-
__all__ = [
|
|
19
|
+
__all__ = [
|
|
20
|
+
"GenericPKAutoIncrement",
|
|
21
|
+
"GenericUnset",
|
|
22
|
+
"PK_AUTO_INCREMENT",
|
|
23
|
+
"UNSET",
|
|
24
|
+
"GenericColumn",
|
|
25
|
+
]
|
|
19
26
|
|
|
20
27
|
|
|
21
|
-
class
|
|
28
|
+
class GenericCapitalClass:
|
|
22
29
|
def __repr__(self) -> str:
|
|
23
|
-
return self.__class__.__name__.
|
|
30
|
+
return self.__class__.__name__.upper()
|
|
24
31
|
|
|
25
32
|
|
|
26
|
-
class
|
|
33
|
+
class GenericPKAutoIncrement(GenericCapitalClass): ...
|
|
27
34
|
|
|
28
35
|
|
|
29
|
-
class
|
|
36
|
+
class GenericUnset(GenericCapitalClass): ...
|
|
30
37
|
|
|
31
38
|
|
|
32
|
-
PK_AUTO_INCREMENT =
|
|
33
|
-
UNSET =
|
|
39
|
+
PK_AUTO_INCREMENT = GenericPKAutoIncrement()
|
|
40
|
+
UNSET = GenericUnset()
|
|
34
41
|
|
|
35
42
|
|
|
36
|
-
class GenericColumn(typing.Generic[T]):
|
|
43
|
+
class GenericColumn(typing.Generic[T], LoggerMixin):
|
|
37
44
|
"""
|
|
38
45
|
A generic column for `GenericModel`. This works similar to a SQLAlchemy column.
|
|
39
46
|
|
|
@@ -51,7 +58,7 @@ class GenericColumn(typing.Generic[T]):
|
|
|
51
58
|
auto_increment: bool
|
|
52
59
|
unique: bool
|
|
53
60
|
nullable: bool
|
|
54
|
-
default: T | typing.Callable[["GenericModel"], T] |
|
|
61
|
+
default: T | typing.Callable[["GenericModel"], T] | GenericUnset
|
|
55
62
|
|
|
56
63
|
_validation_model: BaseModel = None
|
|
57
64
|
_col_name: str = None
|
|
@@ -67,7 +74,7 @@ class GenericColumn(typing.Generic[T]):
|
|
|
67
74
|
default: T
|
|
68
75
|
| typing.Callable[[], T]
|
|
69
76
|
| typing.Callable[["GenericModel"], T]
|
|
70
|
-
|
|
|
77
|
+
| GenericUnset = UNSET,
|
|
71
78
|
):
|
|
72
79
|
"""
|
|
73
80
|
Initializes a GenericColumn instance.
|
|
@@ -133,7 +140,9 @@ class GenericColumn(typing.Generic[T]):
|
|
|
133
140
|
if callable(default_value):
|
|
134
141
|
default_value = default_value(instance)
|
|
135
142
|
|
|
136
|
-
value: T |
|
|
143
|
+
value: T | GenericUnset = instance.__dict__.get(
|
|
144
|
+
f"_{self._col_name}", default_value
|
|
145
|
+
)
|
|
137
146
|
|
|
138
147
|
if value is default_value:
|
|
139
148
|
if self.nullable and value is UNSET:
|
|
@@ -143,7 +152,7 @@ class GenericColumn(typing.Generic[T]):
|
|
|
143
152
|
|
|
144
153
|
return value
|
|
145
154
|
|
|
146
|
-
def __set__(self, instance: "GenericModel", value: T |
|
|
155
|
+
def __set__(self, instance: "GenericModel", value: T | GenericUnset) -> None:
|
|
147
156
|
try:
|
|
148
157
|
validated = self._validation_model.model_validate({self._col_name: value})
|
|
149
158
|
except ValidationError as e:
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import typing
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import fastapi
|
|
4
4
|
|
|
5
5
|
from ...bases.db import AbstractQueryBuilder
|
|
6
|
+
from ...exceptions import HTTPWithValidationException
|
|
7
|
+
from ...lang import translate
|
|
6
8
|
from ...utils import lazy
|
|
9
|
+
from .filters import GenericBaseOprFilter
|
|
7
10
|
from .session import GenericSession
|
|
8
11
|
|
|
9
12
|
if typing.TYPE_CHECKING:
|
|
@@ -55,18 +58,50 @@ class GenericQueryBuilder(AbstractQueryBuilder[GenericSession]):
|
|
|
55
58
|
filter_class = f
|
|
56
59
|
break
|
|
57
60
|
if not filter_class:
|
|
58
|
-
raise
|
|
59
|
-
|
|
61
|
+
raise HTTPWithValidationException(
|
|
62
|
+
fastapi.status.HTTP_400_BAD_REQUEST,
|
|
63
|
+
"invalid_key",
|
|
64
|
+
"query",
|
|
65
|
+
"filters",
|
|
66
|
+
translate("Invalid filter operator: {operator}", operator=filter.opr),
|
|
67
|
+
filter.model_dump(mode="json"),
|
|
60
68
|
)
|
|
61
69
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
return self.apply_filter_class(statement, col, filter_class, value)
|
|
70
|
+
return self.apply_filter_class(
|
|
71
|
+
statement, filter.col, filter_class, filter.value
|
|
72
|
+
)
|
|
66
73
|
|
|
67
74
|
def apply_filter_class(self, statement, col, filter_class, value):
|
|
68
75
|
return filter_class.apply(statement, col, value)
|
|
69
76
|
|
|
77
|
+
def apply_opr_filter(self, statement, filter):
|
|
78
|
+
filter_class = None
|
|
79
|
+
for f in self.datamodel.opr_filters:
|
|
80
|
+
if f.arg_name == filter.opr:
|
|
81
|
+
filter_class = f
|
|
82
|
+
break
|
|
83
|
+
if not filter_class:
|
|
84
|
+
raise HTTPWithValidationException(
|
|
85
|
+
fastapi.status.HTTP_400_BAD_REQUEST,
|
|
86
|
+
"invalid_key",
|
|
87
|
+
"query",
|
|
88
|
+
"opr_filters",
|
|
89
|
+
translate(
|
|
90
|
+
"Invalid opr_filter operator: {operator}", operator=filter.opr
|
|
91
|
+
),
|
|
92
|
+
filter.model_dump(mode="json"),
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
return self.apply_opr_filter_class(statement, filter_class, filter.value)
|
|
96
|
+
|
|
97
|
+
def apply_opr_filter_class(self, statement, filter_class, value):
|
|
98
|
+
params = [statement]
|
|
99
|
+
if isinstance(filter_class, GenericBaseOprFilter):
|
|
100
|
+
params.append(value)
|
|
101
|
+
else:
|
|
102
|
+
params.extend([None, value])
|
|
103
|
+
return filter_class.apply(statement, *params)
|
|
104
|
+
|
|
70
105
|
def apply_global_filter(self, statement, columns, global_filter):
|
|
71
106
|
return self.apply_filter_class(
|
|
72
107
|
statement,
|
|
@@ -2,8 +2,9 @@ import enum
|
|
|
2
2
|
import typing
|
|
3
3
|
from datetime import date, datetime
|
|
4
4
|
|
|
5
|
-
from ...bases.filter import AbstractBaseFilter
|
|
5
|
+
from ...bases.filter import AbstractBaseFilter, AbstractBaseOprFilter
|
|
6
6
|
from ...const import logger
|
|
7
|
+
from ...lang import lazy_text
|
|
7
8
|
from .session import GenericSession
|
|
8
9
|
|
|
9
10
|
if typing.TYPE_CHECKING:
|
|
@@ -27,6 +28,7 @@ __all__ = [
|
|
|
27
28
|
"GenericFilterSmallerEqual",
|
|
28
29
|
"GenericFilterIn",
|
|
29
30
|
"GenericFilterGlobal",
|
|
31
|
+
"GenericBaseOprFilter",
|
|
30
32
|
"GenericFilterConverter",
|
|
31
33
|
]
|
|
32
34
|
|
|
@@ -76,7 +78,7 @@ class GenericBaseFilter(AbstractBaseFilter[GenericSession]):
|
|
|
76
78
|
|
|
77
79
|
|
|
78
80
|
class GenericFilterTextContains(GenericBaseFilter):
|
|
79
|
-
name = "Text contains"
|
|
81
|
+
name = lazy_text("Text contains")
|
|
80
82
|
arg_name = "tc"
|
|
81
83
|
|
|
82
84
|
def apply(self, statement, col, value):
|
|
@@ -84,7 +86,7 @@ class GenericFilterTextContains(GenericBaseFilter):
|
|
|
84
86
|
|
|
85
87
|
|
|
86
88
|
class GenericFilterEqual(GenericBaseFilter):
|
|
87
|
-
name = "Equal to"
|
|
89
|
+
name = lazy_text("Equal to")
|
|
88
90
|
arg_name = "eq"
|
|
89
91
|
|
|
90
92
|
def apply(
|
|
@@ -112,7 +114,7 @@ class GenericFilterNotEqual(GenericBaseFilter):
|
|
|
112
114
|
|
|
113
115
|
|
|
114
116
|
class GenericFilterStartsWith(GenericBaseFilter):
|
|
115
|
-
name = "Starts with"
|
|
117
|
+
name = lazy_text("Starts with")
|
|
116
118
|
arg_name = "sw"
|
|
117
119
|
|
|
118
120
|
def apply(self, statement, col: str, value):
|
|
@@ -121,7 +123,7 @@ class GenericFilterStartsWith(GenericBaseFilter):
|
|
|
121
123
|
|
|
122
124
|
|
|
123
125
|
class GenericFilterNotStartsWith(GenericBaseFilter):
|
|
124
|
-
name = "Not Starts with"
|
|
126
|
+
name = lazy_text("Not Starts with")
|
|
125
127
|
arg_name = "nsw"
|
|
126
128
|
|
|
127
129
|
def apply(self, statement, col: str, value):
|
|
@@ -130,7 +132,7 @@ class GenericFilterNotStartsWith(GenericBaseFilter):
|
|
|
130
132
|
|
|
131
133
|
|
|
132
134
|
class GenericFilterEndsWith(GenericBaseFilter):
|
|
133
|
-
name = "Ends with"
|
|
135
|
+
name = lazy_text("Ends with")
|
|
134
136
|
arg_name = "ew"
|
|
135
137
|
|
|
136
138
|
def apply(self, statement, col: str, value):
|
|
@@ -139,7 +141,7 @@ class GenericFilterEndsWith(GenericBaseFilter):
|
|
|
139
141
|
|
|
140
142
|
|
|
141
143
|
class GenericFilterNotEndsWith(GenericBaseFilter):
|
|
142
|
-
name = "Not Ends with"
|
|
144
|
+
name = lazy_text("Not Ends with")
|
|
143
145
|
arg_name = "new"
|
|
144
146
|
|
|
145
147
|
def apply(self, statement, col: str, value):
|
|
@@ -148,7 +150,7 @@ class GenericFilterNotEndsWith(GenericBaseFilter):
|
|
|
148
150
|
|
|
149
151
|
|
|
150
152
|
class GenericFilterContains(GenericBaseFilter):
|
|
151
|
-
name = "Contains"
|
|
153
|
+
name = lazy_text("Contains")
|
|
152
154
|
arg_name = "ct"
|
|
153
155
|
|
|
154
156
|
def apply(self, statement, col: str, value):
|
|
@@ -157,7 +159,7 @@ class GenericFilterContains(GenericBaseFilter):
|
|
|
157
159
|
|
|
158
160
|
|
|
159
161
|
class GenericFilterIContains(GenericBaseFilter):
|
|
160
|
-
name = "Contains (insensitive)"
|
|
162
|
+
name = lazy_text("Contains (insensitive)")
|
|
161
163
|
arg_name = "ict"
|
|
162
164
|
|
|
163
165
|
def apply(self, statement, col: str, value):
|
|
@@ -166,7 +168,7 @@ class GenericFilterIContains(GenericBaseFilter):
|
|
|
166
168
|
|
|
167
169
|
|
|
168
170
|
class GenericFilterNotContains(GenericBaseFilter):
|
|
169
|
-
name = "Not Contains"
|
|
171
|
+
name = lazy_text("Not Contains")
|
|
170
172
|
arg_name = "nct"
|
|
171
173
|
|
|
172
174
|
def apply(self, statement, col: str, value):
|
|
@@ -175,7 +177,7 @@ class GenericFilterNotContains(GenericBaseFilter):
|
|
|
175
177
|
|
|
176
178
|
|
|
177
179
|
class GenericFilterGreater(GenericBaseFilter):
|
|
178
|
-
name = "Greater than"
|
|
180
|
+
name = lazy_text("Greater than")
|
|
179
181
|
arg_name = "gt"
|
|
180
182
|
|
|
181
183
|
def apply(self, statement, col: str, value: int | date | datetime):
|
|
@@ -184,7 +186,7 @@ class GenericFilterGreater(GenericBaseFilter):
|
|
|
184
186
|
|
|
185
187
|
|
|
186
188
|
class GenericFilterSmaller(GenericBaseFilter):
|
|
187
|
-
name = "Smaller than"
|
|
189
|
+
name = lazy_text("Smaller than")
|
|
188
190
|
arg_name = "lt"
|
|
189
191
|
|
|
190
192
|
def apply(self, statement, col: str, value: int | date | datetime):
|
|
@@ -193,7 +195,7 @@ class GenericFilterSmaller(GenericBaseFilter):
|
|
|
193
195
|
|
|
194
196
|
|
|
195
197
|
class GenericFilterGreaterEqual(GenericBaseFilter):
|
|
196
|
-
name = "Greater equal"
|
|
198
|
+
name = lazy_text("Greater equal")
|
|
197
199
|
arg_name = "ge"
|
|
198
200
|
|
|
199
201
|
def apply(self, statement, col: str, value: int | date | datetime):
|
|
@@ -202,7 +204,7 @@ class GenericFilterGreaterEqual(GenericBaseFilter):
|
|
|
202
204
|
|
|
203
205
|
|
|
204
206
|
class GenericFilterSmallerEqual(GenericBaseFilter):
|
|
205
|
-
name = "Smaller equal"
|
|
207
|
+
name = lazy_text("Smaller equal")
|
|
206
208
|
arg_name = "le"
|
|
207
209
|
|
|
208
210
|
def apply(self, statement, col: str, value: int | date | datetime):
|
|
@@ -211,7 +213,7 @@ class GenericFilterSmallerEqual(GenericBaseFilter):
|
|
|
211
213
|
|
|
212
214
|
|
|
213
215
|
class GenericFilterIn(GenericBaseFilter):
|
|
214
|
-
name = "One of"
|
|
216
|
+
name = lazy_text("One of")
|
|
215
217
|
arg_name = "in"
|
|
216
218
|
|
|
217
219
|
def apply(self, statement, col: str, value: list[str | bool | int]):
|
|
@@ -220,7 +222,7 @@ class GenericFilterIn(GenericBaseFilter):
|
|
|
220
222
|
|
|
221
223
|
|
|
222
224
|
class GenericFilterGlobal(GenericBaseFilter):
|
|
223
|
-
name = "Global Filter"
|
|
225
|
+
name = lazy_text("Global Filter")
|
|
224
226
|
arg_name = "global"
|
|
225
227
|
|
|
226
228
|
def apply(self, statement, col: str, value: str):
|
|
@@ -228,6 +230,9 @@ class GenericFilterGlobal(GenericBaseFilter):
|
|
|
228
230
|
return statement.global_filter(col, value)
|
|
229
231
|
|
|
230
232
|
|
|
233
|
+
class GenericBaseOprFilter(AbstractBaseOprFilter, GenericBaseFilter): ...
|
|
234
|
+
|
|
235
|
+
|
|
231
236
|
class GenericFilterConverter:
|
|
232
237
|
"""
|
|
233
238
|
Helper class to get available filters for a generic column type.
|
|
@@ -15,11 +15,15 @@ from .session import GenericSession
|
|
|
15
15
|
|
|
16
16
|
__all__ = ["GenericInterface"]
|
|
17
17
|
|
|
18
|
+
GenericModelType = typing.TypeVar("GenericModelType", bound=GenericModel)
|
|
19
|
+
|
|
18
20
|
|
|
19
21
|
class lazy(lazy_self["GenericInterface", T]): ...
|
|
20
22
|
|
|
21
23
|
|
|
22
|
-
class GenericInterface(
|
|
24
|
+
class GenericInterface(
|
|
25
|
+
AbstractInterface[GenericModelType, GenericSession, GenericColumn]
|
|
26
|
+
):
|
|
23
27
|
"""
|
|
24
28
|
Represents an interface for a Generic model (Based on pydantic).
|
|
25
29
|
"""
|
|
@@ -33,7 +37,7 @@ class GenericInterface(AbstractInterface[GenericModel, GenericSession, GenericCo
|
|
|
33
37
|
query_count = lazy(lambda self: GenericQueryBuilder(self, self.session))
|
|
34
38
|
|
|
35
39
|
def __init__(
|
|
36
|
-
self, obj: typing.Type[
|
|
40
|
+
self, obj: typing.Type[GenericModelType], session: typing.Type[GenericSession]
|
|
37
41
|
):
|
|
38
42
|
super().__init__(obj)
|
|
39
43
|
if not isinstance(session, type):
|
|
@@ -62,23 +66,23 @@ class GenericInterface(AbstractInterface[GenericModel, GenericSession, GenericCo
|
|
|
62
66
|
relevant_params.pop("page_size", None)
|
|
63
67
|
relevant_params.pop("order_column", None)
|
|
64
68
|
relevant_params.pop("order_direction", None)
|
|
65
|
-
|
|
66
69
|
statement = await self.query_count.build_query(relevant_params)
|
|
67
70
|
return statement.count()
|
|
68
71
|
|
|
69
|
-
async def get_many(self, session, params=None):
|
|
72
|
+
async def get_many(self, session, params=None) -> list[GenericModelType]:
|
|
70
73
|
statement = await self.query.build_query(params)
|
|
71
74
|
return statement.all()
|
|
72
75
|
|
|
73
|
-
async def get_one(self, session, params=None):
|
|
76
|
+
async def get_one(self, session, params=None) -> GenericModelType | None:
|
|
74
77
|
statement = await self.query.build_query(params)
|
|
75
78
|
return statement.first()
|
|
76
79
|
|
|
77
|
-
async def yield_per(
|
|
80
|
+
async def yield_per(
|
|
81
|
+
self, session, params=None
|
|
82
|
+
) -> typing.AsyncGenerator[list[GenericModelType], None]:
|
|
78
83
|
relevant_params = params.copy() if params else DBQueryParams()
|
|
79
84
|
relevant_params.pop("page", None)
|
|
80
85
|
page_size = relevant_params.pop("page_size", 100)
|
|
81
|
-
|
|
82
86
|
statement = await self.query.build_query(relevant_params)
|
|
83
87
|
items = statement.yield_per(page_size)
|
|
84
88
|
while True:
|
|
@@ -98,7 +102,9 @@ class GenericInterface(AbstractInterface[GenericModel, GenericSession, GenericCo
|
|
|
98
102
|
session.refresh(item)
|
|
99
103
|
return item
|
|
100
104
|
|
|
101
|
-
async def edit(
|
|
105
|
+
async def edit(
|
|
106
|
+
self, session, item, *, flush=True, commit=True, refresh=False
|
|
107
|
+
) -> GenericModelType:
|
|
102
108
|
result = session.merge(item)
|
|
103
109
|
if flush:
|
|
104
110
|
session.flush()
|
|
@@ -2,7 +2,7 @@ import typing
|
|
|
2
2
|
|
|
3
3
|
from ...bases.model import BasicModel
|
|
4
4
|
from ...utils import T, lazy
|
|
5
|
-
from .column import UNSET, GenericColumn,
|
|
5
|
+
from .column import UNSET, GenericColumn, GenericPKAutoIncrement
|
|
6
6
|
from .exceptions import (
|
|
7
7
|
ColumnNotSetException,
|
|
8
8
|
MultipleColumnsException,
|
|
@@ -13,10 +13,10 @@ from .exceptions import (
|
|
|
13
13
|
if typing.TYPE_CHECKING:
|
|
14
14
|
from .session import Table
|
|
15
15
|
|
|
16
|
-
__all__ = ["GenericModel"]
|
|
16
|
+
__all__ = ["GenericMapper", "GenericModel"]
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
class
|
|
19
|
+
class GenericMapper(typing.Generic[T]):
|
|
20
20
|
"""
|
|
21
21
|
Mapper class that contains a model's definitions.
|
|
22
22
|
"""
|
|
@@ -46,8 +46,8 @@ class GenericModel(BasicModel):
|
|
|
46
46
|
GenericModel is a base class for all models that does not use SQLAlchemy, but want to behave like one.
|
|
47
47
|
"""
|
|
48
48
|
|
|
49
|
-
__mapper__:
|
|
50
|
-
lambda:
|
|
49
|
+
__mapper__: GenericMapper[GenericColumn] = lazy(
|
|
50
|
+
lambda: GenericMapper[GenericColumn](), only_instance=False
|
|
51
51
|
)
|
|
52
52
|
"""
|
|
53
53
|
A mapper that contains the primary key, properties, and columns of the model.
|
|
@@ -92,21 +92,28 @@ class GenericModel(BasicModel):
|
|
|
92
92
|
if not cls.__mapper__.pk:
|
|
93
93
|
raise PKMissingException(cls.__name__, "Primary key is missing")
|
|
94
94
|
|
|
95
|
-
def __init__(self, **kwargs):
|
|
95
|
+
def __init__(self, *, __check_on_init__=True, **kwargs):
|
|
96
|
+
"""
|
|
97
|
+
Initialize the model with the given keyword arguments.
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
__check_on_init__ (bool, optional): Whether to check the model's validity on initialization. Defaults to True.
|
|
101
|
+
"""
|
|
96
102
|
if not kwargs:
|
|
97
103
|
return
|
|
98
104
|
for key, value in kwargs.items():
|
|
99
105
|
if key not in self.__mapper__.properties.keys():
|
|
100
106
|
continue
|
|
101
107
|
setattr(self, key, value)
|
|
102
|
-
|
|
108
|
+
if __check_on_init__:
|
|
109
|
+
self.is_model_valid()
|
|
103
110
|
|
|
104
|
-
def get_pk(self) -> str | int |
|
|
111
|
+
def get_pk(self) -> str | int | GenericPKAutoIncrement:
|
|
105
112
|
"""
|
|
106
113
|
Get the primary key of the model.
|
|
107
114
|
|
|
108
115
|
Returns:
|
|
109
|
-
str | int |
|
|
116
|
+
str | int | GenericPKAutoIncrement: The primary key of the model.
|
|
110
117
|
"""
|
|
111
118
|
return getattr(self, self.__mapper__.pk)
|
|
112
119
|
|
|
@@ -122,11 +129,12 @@ class GenericModel(BasicModel):
|
|
|
122
129
|
def get_col_type(self, col_name: str):
|
|
123
130
|
return self.__mapper__.properties[col_name].col_type
|
|
124
131
|
|
|
125
|
-
def update(self, data):
|
|
132
|
+
def update(self, data, *, check=True):
|
|
126
133
|
super().update(data)
|
|
127
134
|
|
|
128
135
|
# Check if the model is valid
|
|
129
|
-
|
|
136
|
+
if check:
|
|
137
|
+
self.is_model_valid()
|
|
130
138
|
|
|
131
139
|
def is_model_valid(self):
|
|
132
140
|
"""
|