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
|
@@ -1,228 +0,0 @@
|
|
|
1
|
-
import contextlib
|
|
2
|
-
|
|
3
|
-
import fastapi
|
|
4
|
-
import gremlin_python.driver.driver_remote_connection
|
|
5
|
-
import gremlin_python.process.anonymous_traversal
|
|
6
|
-
import gremlin_python.process.graph_traversal
|
|
7
|
-
import gremlin_python.process.traversal
|
|
8
|
-
|
|
9
|
-
from ...bases.db import AbstractQueryBuilder
|
|
10
|
-
from ...const import logger
|
|
11
|
-
from ...setting import Setting
|
|
12
|
-
from ...utils import lazy
|
|
13
|
-
from .model import UNSPECIFIED_LABEL
|
|
14
|
-
|
|
15
|
-
try:
|
|
16
|
-
import janusgraph_python.driver.serializer
|
|
17
|
-
|
|
18
|
-
serializer = janusgraph_python.driver.serializer
|
|
19
|
-
except ImportError:
|
|
20
|
-
logger.warning(
|
|
21
|
-
"janusgraph_python is not installed. Some Gremlin features may not work as expected."
|
|
22
|
-
)
|
|
23
|
-
serializer = None
|
|
24
|
-
|
|
25
|
-
__all__ = ["GremlinQueryBuilder", "graph_db"]
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
class GremlinQueryBuilder(
|
|
29
|
-
AbstractQueryBuilder[gremlin_python.process.graph_traversal.GraphTraversal]
|
|
30
|
-
):
|
|
31
|
-
"""
|
|
32
|
-
A class that builds Gremlin queries for a graph database.
|
|
33
|
-
"""
|
|
34
|
-
|
|
35
|
-
build_steps = list(reversed(AbstractQueryBuilder.DEFAULT_BUILD_STEPS))
|
|
36
|
-
|
|
37
|
-
def __init__(self, datamodel, statement=None):
|
|
38
|
-
try:
|
|
39
|
-
super().__init__(datamodel, statement)
|
|
40
|
-
except RuntimeError:
|
|
41
|
-
pass
|
|
42
|
-
|
|
43
|
-
def apply_list_columns(self, statement, list_columns):
|
|
44
|
-
list_columns = list(
|
|
45
|
-
dict.fromkeys(
|
|
46
|
-
x.split(".")[0]
|
|
47
|
-
for x in list_columns
|
|
48
|
-
if x != self.datamodel.obj.__mapper__.pk
|
|
49
|
-
and x != self.datamodel.obj.__mapper__.lk
|
|
50
|
-
and x not in self.datamodel.get_property_column_list()
|
|
51
|
-
)
|
|
52
|
-
)
|
|
53
|
-
relation_columns = [
|
|
54
|
-
x for x in self.datamodel.get_relation_columns() if x in list_columns
|
|
55
|
-
]
|
|
56
|
-
list_columns = [x for x in list_columns if x not in relation_columns]
|
|
57
|
-
|
|
58
|
-
statement = statement.project(
|
|
59
|
-
self.datamodel.obj.__label__ or UNSPECIFIED_LABEL, *relation_columns
|
|
60
|
-
).by(gremlin_python.process.graph_traversal.__.valueMap(True, *list_columns))
|
|
61
|
-
|
|
62
|
-
for rel_col in relation_columns:
|
|
63
|
-
direction = self.datamodel.list_properties[rel_col].direction
|
|
64
|
-
sub_statement = gremlin_python.process.graph_traversal.__
|
|
65
|
-
match direction:
|
|
66
|
-
case "in":
|
|
67
|
-
sub_statement = sub_statement.inE
|
|
68
|
-
case "out":
|
|
69
|
-
sub_statement = sub_statement.outE
|
|
70
|
-
case "both":
|
|
71
|
-
sub_statement = sub_statement.bothE
|
|
72
|
-
if self.datamodel.list_properties[rel_col].name:
|
|
73
|
-
sub_statement = sub_statement(
|
|
74
|
-
self.datamodel.list_properties[rel_col].name
|
|
75
|
-
)
|
|
76
|
-
else:
|
|
77
|
-
sub_statement = sub_statement()
|
|
78
|
-
if self.datamodel.list_properties[rel_col].properties:
|
|
79
|
-
for key, value in self.datamodel.list_properties[
|
|
80
|
-
rel_col
|
|
81
|
-
].properties.items():
|
|
82
|
-
sub_statement = sub_statement.has(key, value)
|
|
83
|
-
sub_other_v_statement = (
|
|
84
|
-
sub_statement.otherV()
|
|
85
|
-
if not self.datamodel.list_properties[rel_col].with_edge
|
|
86
|
-
else gremlin_python.process.graph_traversal.__.otherV()
|
|
87
|
-
)
|
|
88
|
-
if self.datamodel.list_properties[rel_col].obj_properties:
|
|
89
|
-
for key, value in self.datamodel.list_properties[
|
|
90
|
-
rel_col
|
|
91
|
-
].obj_properties.items():
|
|
92
|
-
sub_other_v_statement = sub_other_v_statement.has(key, value)
|
|
93
|
-
sub_other_v_statement = sub_other_v_statement.valueMap(True)
|
|
94
|
-
if self.datamodel.list_properties[rel_col].with_edge:
|
|
95
|
-
sub_statement = (
|
|
96
|
-
sub_statement.project("edge", rel_col)
|
|
97
|
-
.by(gremlin_python.process.graph_traversal.__.valueMap(True))
|
|
98
|
-
.by(sub_other_v_statement)
|
|
99
|
-
)
|
|
100
|
-
else:
|
|
101
|
-
sub_statement = sub_other_v_statement
|
|
102
|
-
sub_statement = sub_statement.fold()
|
|
103
|
-
statement = statement.by(sub_statement)
|
|
104
|
-
|
|
105
|
-
return statement
|
|
106
|
-
|
|
107
|
-
def apply_pagination(self, statement, page, page_size):
|
|
108
|
-
lower_range = page_size * (page or 0)
|
|
109
|
-
return statement.range_(lower_range, lower_range + page_size)
|
|
110
|
-
|
|
111
|
-
def apply_order_by(self, statement, order_column, order_direction):
|
|
112
|
-
return statement.order().by(
|
|
113
|
-
order_column,
|
|
114
|
-
gremlin_python.process.traversal.Order.asc
|
|
115
|
-
if order_direction == "asc"
|
|
116
|
-
else gremlin_python.process.traversal.Order.desc,
|
|
117
|
-
)
|
|
118
|
-
|
|
119
|
-
def apply_where(self, statement, column, value):
|
|
120
|
-
args = [column, value]
|
|
121
|
-
func = statement.has
|
|
122
|
-
if column.lower() == self.datamodel.obj.__mapper__.pk:
|
|
123
|
-
func = statement.hasId
|
|
124
|
-
args = args[1:]
|
|
125
|
-
elif column.lower() == self.datamodel.obj.__mapper__.lk:
|
|
126
|
-
func = statement.hasLabel
|
|
127
|
-
args = args[1:]
|
|
128
|
-
return func(*args)
|
|
129
|
-
|
|
130
|
-
def apply_where_in(self, statement, column, values):
|
|
131
|
-
args = [column, gremlin_python.process.traversal.within(values)]
|
|
132
|
-
func = statement.has
|
|
133
|
-
if column.lower() == self.datamodel.obj.__mapper__.pk:
|
|
134
|
-
func = statement.hasId
|
|
135
|
-
args = args[1:]
|
|
136
|
-
elif column.lower() == self.datamodel.obj.__mapper__.lk:
|
|
137
|
-
func = statement.hasLabel
|
|
138
|
-
args = args[1:]
|
|
139
|
-
return func(*args)
|
|
140
|
-
|
|
141
|
-
def apply_filter(self, statement, filter):
|
|
142
|
-
filter_classes = self.datamodel.filters.get(filter.col)
|
|
143
|
-
filter_class = None
|
|
144
|
-
for f in filter_classes:
|
|
145
|
-
if f.arg_name == filter.opr:
|
|
146
|
-
filter_class = f
|
|
147
|
-
break
|
|
148
|
-
if not filter_class:
|
|
149
|
-
raise fastapi.HTTPException(
|
|
150
|
-
status_code=400, detail=f"Invalid filter opr: {filter.opr}"
|
|
151
|
-
)
|
|
152
|
-
|
|
153
|
-
col = filter.col
|
|
154
|
-
value = filter.value
|
|
155
|
-
|
|
156
|
-
return self.apply_filter_class(statement, col, filter_class, value)
|
|
157
|
-
|
|
158
|
-
def apply_filter_class(self, statement, col, filter_class, value):
|
|
159
|
-
return filter_class.apply(statement, col, value)
|
|
160
|
-
|
|
161
|
-
def apply_global_filter(self, statement, columns, global_filter):
|
|
162
|
-
return super().apply_global_filter(statement, columns, global_filter)
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
class GremlinDatabaseSessionManager:
|
|
166
|
-
gremlin_connection = lazy(lambda: Setting.GREMLIN_CONNECTION)
|
|
167
|
-
|
|
168
|
-
@contextlib.contextmanager
|
|
169
|
-
def connect(self, bind: str | None = None, keep_open=False):
|
|
170
|
-
"""
|
|
171
|
-
Establishes a connection to the graph database.
|
|
172
|
-
|
|
173
|
-
Args:
|
|
174
|
-
bind (str | None, optional): The bind key to retrieve the connection for. If None, the default connection is returned. Defaults to None. UNUSED FOR NOW.
|
|
175
|
-
keep_open (bool, optional): Whether to keep the connection open after use. Defaults to False.
|
|
176
|
-
|
|
177
|
-
Yields:
|
|
178
|
-
gremlin_python.driver.driver_remote_connection.DriverRemoteConnection: The graph database connection.
|
|
179
|
-
"""
|
|
180
|
-
url, graph_object = self.gremlin_connection
|
|
181
|
-
connection = (
|
|
182
|
-
gremlin_python.driver.driver_remote_connection.DriverRemoteConnection(
|
|
183
|
-
url,
|
|
184
|
-
graph_object,
|
|
185
|
-
# session=True, #! When true, can not add Edge
|
|
186
|
-
message_serializer=serializer.JanusGraphSONSerializersV3d0()
|
|
187
|
-
if serializer
|
|
188
|
-
else None,
|
|
189
|
-
**Setting.GREMLIN_CONNECTION_OPTIONS,
|
|
190
|
-
)
|
|
191
|
-
)
|
|
192
|
-
try:
|
|
193
|
-
if keep_open:
|
|
194
|
-
logger.warning(
|
|
195
|
-
f"Connection {connection} is kept open. Make sure to close it manually when done."
|
|
196
|
-
)
|
|
197
|
-
yield connection
|
|
198
|
-
except Exception:
|
|
199
|
-
connection.rollback()
|
|
200
|
-
raise
|
|
201
|
-
finally:
|
|
202
|
-
if keep_open:
|
|
203
|
-
return
|
|
204
|
-
connection.close()
|
|
205
|
-
|
|
206
|
-
@contextlib.contextmanager
|
|
207
|
-
def session(self, bind: str | None = None, keep_open=False):
|
|
208
|
-
"""
|
|
209
|
-
Provides a graph database session for performing database operations.
|
|
210
|
-
|
|
211
|
-
Args:
|
|
212
|
-
bind (str | None, optional): The bind key to retrieve the session for. If None, the default session is returned. Defaults to None. UNUSED FOR NOW.
|
|
213
|
-
keep_open (bool, optional): Whether to keep the connection open after use. Defaults to False.
|
|
214
|
-
|
|
215
|
-
Yields:
|
|
216
|
-
gremlin_python.process.graph_traversal.GraphTraversal: A graph traversal object for executing queries.
|
|
217
|
-
"""
|
|
218
|
-
with self.connect(bind, keep_open) as connection:
|
|
219
|
-
traversal = (
|
|
220
|
-
gremlin_python.process.anonymous_traversal.traversal().withRemote(
|
|
221
|
-
connection
|
|
222
|
-
)
|
|
223
|
-
)
|
|
224
|
-
traversal.remote_connection = connection
|
|
225
|
-
yield traversal
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
graph_db = GremlinDatabaseSessionManager()
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
__all__ = ["GremlinMissingLabelException", "LKMultipleException"]
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
class BaseGremlinException(Exception):
|
|
5
|
-
"""
|
|
6
|
-
Base exception for all Gremlin-related errors.
|
|
7
|
-
"""
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
class GremlinMissingLabelException(BaseGremlinException):
|
|
11
|
-
"""
|
|
12
|
-
Exception raised when a Gremlin model is missing a label.
|
|
13
|
-
"""
|
|
14
|
-
|
|
15
|
-
def __init__(self, model_name: str):
|
|
16
|
-
super().__init__(f"Model {model_name} is missing a label.")
|
|
17
|
-
self.model_name = model_name
|
|
18
|
-
|
|
19
|
-
def __repr__(self):
|
|
20
|
-
return f"Gremlin model '{self.model_name}' must have a label defined."
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
class LKMultipleException(BaseGremlinException):
|
|
24
|
-
"""
|
|
25
|
-
Exception raised when a Gremlin model has multiple label keys defined.
|
|
26
|
-
"""
|
|
27
|
-
|
|
28
|
-
def __init__(self, model_name: str, message: str):
|
|
29
|
-
super().__init__(f"{model_name}: {message}")
|
|
30
|
-
self.model_name = model_name
|
|
31
|
-
self.message = message
|
|
32
|
-
|
|
33
|
-
def __repr__(self):
|
|
34
|
-
return f"Gremlin model '{self.model_name}' has multiple label keys defined: {self.message}"
|