amsdal 0.5.34__cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.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.
- amsdal/Third-Party Materials - AMSDAL Dependencies - License Notices.md +1362 -0
- amsdal/__about__.py +4 -0
- amsdal/__about__.pyi +1 -0
- amsdal/__init__.py +23 -0
- amsdal/__init__.pyi +9 -0
- amsdal/__migrations__/0000_initial.py +36 -0
- amsdal/__migrations__/0001_create_class_file.py +61 -0
- amsdal/__migrations__/0002_create_class_file.py +109 -0
- amsdal/__migrations__/0003_update_class_file.py +91 -0
- amsdal/__migrations__/0004_update_class_file.py +45 -0
- amsdal/cloud/__init__.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/__init__.pyi +0 -0
- amsdal/cloud/client.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/client.pyi +57 -0
- amsdal/cloud/constants.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/constants.pyi +13 -0
- amsdal/cloud/enums.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/enums.pyi +68 -0
- amsdal/cloud/models/__init__.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/models/__init__.pyi +0 -0
- amsdal/cloud/models/base.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/models/base.pyi +247 -0
- amsdal/cloud/services/__init__.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/__init__.pyi +0 -0
- amsdal/cloud/services/actions/__init__.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/actions/__init__.pyi +0 -0
- amsdal/cloud/services/actions/add_allowlist_ip.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/actions/add_allowlist_ip.pyi +19 -0
- amsdal/cloud/services/actions/add_basic_auth.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/actions/add_basic_auth.pyi +21 -0
- amsdal/cloud/services/actions/add_dependency.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/actions/add_dependency.pyi +19 -0
- amsdal/cloud/services/actions/add_secret.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/actions/add_secret.pyi +20 -0
- amsdal/cloud/services/actions/base.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/actions/base.pyi +122 -0
- amsdal/cloud/services/actions/create_deploy.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/actions/create_deploy.pyi +41 -0
- amsdal/cloud/services/actions/create_env.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/actions/create_env.pyi +19 -0
- amsdal/cloud/services/actions/create_session.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/actions/create_session.pyi +17 -0
- amsdal/cloud/services/actions/delete_allowlist_ip.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/actions/delete_allowlist_ip.pyi +19 -0
- amsdal/cloud/services/actions/delete_basic_auth.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/actions/delete_basic_auth.pyi +20 -0
- amsdal/cloud/services/actions/delete_dependency.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/actions/delete_dependency.pyi +21 -0
- amsdal/cloud/services/actions/delete_env.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/actions/delete_env.pyi +21 -0
- amsdal/cloud/services/actions/delete_secret.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/actions/delete_secret.pyi +21 -0
- amsdal/cloud/services/actions/destroy_deploy.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/actions/destroy_deploy.pyi +18 -0
- amsdal/cloud/services/actions/expose_db.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/actions/expose_db.pyi +22 -0
- amsdal/cloud/services/actions/get_basic_auth_credentials.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/actions/get_basic_auth_credentials.pyi +21 -0
- amsdal/cloud/services/actions/get_monitoring_info.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/actions/get_monitoring_info.pyi +21 -0
- amsdal/cloud/services/actions/list_dependencies.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/actions/list_dependencies.pyi +21 -0
- amsdal/cloud/services/actions/list_deploys.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/actions/list_deploys.pyi +19 -0
- amsdal/cloud/services/actions/list_envs.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/actions/list_envs.pyi +20 -0
- amsdal/cloud/services/actions/list_secrets.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/actions/list_secrets.pyi +22 -0
- amsdal/cloud/services/actions/manager.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/actions/manager.pyi +278 -0
- amsdal/cloud/services/actions/signup_action.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/actions/signup_action.pyi +20 -0
- amsdal/cloud/services/actions/update_deploy.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/actions/update_deploy.pyi +19 -0
- amsdal/cloud/services/auth/__init__.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/auth/__init__.pyi +0 -0
- amsdal/cloud/services/auth/base.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/auth/base.pyi +6 -0
- amsdal/cloud/services/auth/credentials.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/auth/credentials.pyi +30 -0
- amsdal/cloud/services/auth/manager.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/auth/manager.pyi +26 -0
- amsdal/cloud/services/auth/signup_service.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/auth/signup_service.pyi +32 -0
- amsdal/cloud/services/auth/token.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/auth/token.pyi +27 -0
- amsdal/configs/__init__.py +0 -0
- amsdal/configs/__init__.pyi +0 -0
- amsdal/configs/constants.py +33 -0
- amsdal/configs/constants.pyi +22 -0
- amsdal/configs/main.py +274 -0
- amsdal/configs/main.pyi +178 -0
- amsdal/context/__init__.py +0 -0
- amsdal/context/__init__.pyi +0 -0
- amsdal/context/manager.py +69 -0
- amsdal/context/manager.pyi +50 -0
- amsdal/contrib/__init__.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/contrib/__init__.pyi +0 -0
- amsdal/contrib/app_config.py +7 -0
- amsdal/contrib/app_config.pyi +6 -0
- amsdal/contrib/auth/__init__.py +0 -0
- amsdal/contrib/auth/__init__.pyi +0 -0
- amsdal/contrib/auth/app.py +27 -0
- amsdal/contrib/auth/app.pyi +15 -0
- amsdal/contrib/auth/decorators/__init__.py +35 -0
- amsdal/contrib/auth/decorators/__init__.pyi +6 -0
- amsdal/contrib/auth/errors.py +43 -0
- amsdal/contrib/auth/errors.pyi +16 -0
- amsdal/contrib/auth/fixtures/basic_permissions.json +64 -0
- amsdal/contrib/auth/lifecycle/__init__.py +0 -0
- amsdal/contrib/auth/lifecycle/__init__.pyi +0 -0
- amsdal/contrib/auth/lifecycle/consumer.py +394 -0
- amsdal/contrib/auth/lifecycle/consumer.pyi +108 -0
- amsdal/contrib/auth/migrations/0000_initial.py +87 -0
- amsdal/contrib/auth/migrations/0001_add_mfa_support.py +188 -0
- amsdal/contrib/auth/models/__init__.py +1 -0
- amsdal/contrib/auth/models/backup_code.py +85 -0
- amsdal/contrib/auth/models/email_mfa_device.py +108 -0
- amsdal/contrib/auth/models/login_session.py +235 -0
- amsdal/contrib/auth/models/mfa_device.py +86 -0
- amsdal/contrib/auth/models/permission.py +23 -0
- amsdal/contrib/auth/models/sms_device.py +113 -0
- amsdal/contrib/auth/models/totp_device.py +58 -0
- amsdal/contrib/auth/models/user.py +156 -0
- amsdal/contrib/auth/services/__init__.py +1 -0
- amsdal/contrib/auth/services/__init__.pyi +0 -0
- amsdal/contrib/auth/services/mfa_device_service.py +544 -0
- amsdal/contrib/auth/services/mfa_device_service.pyi +216 -0
- amsdal/contrib/auth/services/totp_service.py +358 -0
- amsdal/contrib/auth/services/totp_service.pyi +158 -0
- amsdal/contrib/auth/settings.py +44 -0
- amsdal/contrib/auth/settings.pyi +34 -0
- amsdal/contrib/auth/transactions/__init__.py +1 -0
- amsdal/contrib/auth/transactions/__init__.pyi +0 -0
- amsdal/contrib/auth/transactions/mfa_device_transactions.py +458 -0
- amsdal/contrib/auth/transactions/mfa_device_transactions.pyi +226 -0
- amsdal/contrib/auth/transactions/totp_transactions.py +203 -0
- amsdal/contrib/auth/transactions/totp_transactions.pyi +113 -0
- amsdal/contrib/auth/utils/__init__.py +0 -0
- amsdal/contrib/auth/utils/__init__.pyi +0 -0
- amsdal/contrib/auth/utils/mfa.py +257 -0
- amsdal/contrib/auth/utils/mfa.pyi +119 -0
- amsdal/contrib/frontend_configs/__init__.py +0 -0
- amsdal/contrib/frontend_configs/__init__.pyi +0 -0
- amsdal/contrib/frontend_configs/app.py +24 -0
- amsdal/contrib/frontend_configs/app.pyi +19 -0
- amsdal/contrib/frontend_configs/constants.py +1 -0
- amsdal/contrib/frontend_configs/constants.pyi +1 -0
- amsdal/contrib/frontend_configs/conversion/__init__.py +5 -0
- amsdal/contrib/frontend_configs/conversion/__init__.pyi +3 -0
- amsdal/contrib/frontend_configs/conversion/convert.py +310 -0
- amsdal/contrib/frontend_configs/conversion/convert.pyi +22 -0
- amsdal/contrib/frontend_configs/lifecycle/__init__.py +0 -0
- amsdal/contrib/frontend_configs/lifecycle/__init__.pyi +0 -0
- amsdal/contrib/frontend_configs/lifecycle/consumer.py +306 -0
- amsdal/contrib/frontend_configs/lifecycle/consumer.pyi +98 -0
- amsdal/contrib/frontend_configs/migrations/0000_initial.py +227 -0
- amsdal/contrib/frontend_configs/migrations/0001_update_frontend_control_config.py +245 -0
- amsdal/contrib/frontend_configs/migrations/0002_add_button_and_invoke_actions.py +352 -0
- amsdal/contrib/frontend_configs/migrations/0003_create_class_frontendconfigdashboardelement.py +145 -0
- amsdal/contrib/frontend_configs/models/__init__.py +0 -0
- amsdal/contrib/frontend_configs/models/frontend_activator_config.py +22 -0
- amsdal/contrib/frontend_configs/models/frontend_config_async_validator.py +11 -0
- amsdal/contrib/frontend_configs/models/frontend_config_control_action.py +110 -0
- amsdal/contrib/frontend_configs/models/frontend_config_dashboard.py +51 -0
- amsdal/contrib/frontend_configs/models/frontend_config_group_validator.py +21 -0
- amsdal/contrib/frontend_configs/models/frontend_config_option.py +12 -0
- amsdal/contrib/frontend_configs/models/frontend_config_skip_none_base.py +17 -0
- amsdal/contrib/frontend_configs/models/frontend_config_slider_option.py +13 -0
- amsdal/contrib/frontend_configs/models/frontend_config_text_mask.py +14 -0
- amsdal/contrib/frontend_configs/models/frontend_config_validator.py +28 -0
- amsdal/contrib/frontend_configs/models/frontend_control_config.py +110 -0
- amsdal/contrib/frontend_configs/models/frontend_model_config.py +14 -0
- amsdal/contrib/frontend_configs/utils.py +29 -0
- amsdal/contrib/frontend_configs/utils.pyi +17 -0
- amsdal/errors.py +31 -0
- amsdal/errors.pyi +12 -0
- amsdal/fixtures/__init__.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/fixtures/__init__.pyi +0 -0
- amsdal/fixtures/manager.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/fixtures/manager.pyi +170 -0
- amsdal/fixtures/utils.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/fixtures/utils.pyi +9 -0
- amsdal/manager.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/manager.pyi +265 -0
- amsdal/mixins/__init__.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/mixins/__init__.pyi +0 -0
- amsdal/mixins/class_versions_mixin.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/mixins/class_versions_mixin.pyi +12 -0
- amsdal/models/__init__.py +19 -0
- amsdal/models/core/__init__.py +0 -0
- amsdal/models/core/class_object.py +38 -0
- amsdal/models/core/class_property.py +26 -0
- amsdal/models/core/file.py +243 -0
- amsdal/models/core/fixture.py +25 -0
- amsdal/models/core/option.py +11 -0
- amsdal/models/core/storage_metadata.py +15 -0
- amsdal/models/core/validator.py +12 -0
- amsdal/models/mixins.py +31 -0
- amsdal/models/types/__init__.py +0 -0
- amsdal/models/types/object.py +26 -0
- amsdal/py.typed +0 -0
- amsdal/queryset/__init__.py +21 -0
- amsdal/queryset/__init__.pyi +6 -0
- amsdal/schemas/__init__.py +0 -0
- amsdal/schemas/__init__.pyi +0 -0
- amsdal/schemas/core/class_object/model.json +51 -0
- amsdal/schemas/core/class_object/properties/display_name.py +9 -0
- amsdal/schemas/core/class_property/model.json +41 -0
- amsdal/schemas/core/file/hooks/pre_create.py +24 -0
- amsdal/schemas/core/file/hooks/pre_update.py +24 -0
- amsdal/schemas/core/file/model.json +23 -0
- amsdal/schemas/core/file/properties/from_file.py +34 -0
- amsdal/schemas/core/file/properties/mimetype.py +13 -0
- amsdal/schemas/core/file/properties/str.py +6 -0
- amsdal/schemas/core/file/properties/to_file.py +24 -0
- amsdal/schemas/core/file/properties/validate_data.py +31 -0
- amsdal/schemas/core/fixture/model.json +35 -0
- amsdal/schemas/core/option/model.json +19 -0
- amsdal/schemas/core/storage_metadata/model.json +52 -0
- amsdal/schemas/core/validator/model.json +19 -0
- amsdal/schemas/interfaces.py +25 -0
- amsdal/schemas/interfaces.pyi +20 -0
- amsdal/schemas/manager.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/schemas/manager.py +0 -0
- amsdal/schemas/manager.pyi +0 -0
- amsdal/schemas/mixins/__init__.py +0 -0
- amsdal/schemas/mixins/__init__.pyi +0 -0
- amsdal/schemas/mixins/check_dependencies_mixin.py +130 -0
- amsdal/schemas/mixins/check_dependencies_mixin.pyi +45 -0
- amsdal/schemas/mixins/verify_schemas_mixin.py +96 -0
- amsdal/schemas/mixins/verify_schemas_mixin.pyi +33 -0
- amsdal/schemas/repository.py +84 -0
- amsdal/schemas/repository.pyi +22 -0
- amsdal/schemas/types/anything/model.json +7 -0
- amsdal/schemas/types/array/model.json +7 -0
- amsdal/schemas/types/binary/model.json +7 -0
- amsdal/schemas/types/boolean/model.json +17 -0
- amsdal/schemas/types/date/model.json +7 -0
- amsdal/schemas/types/datetime/model.json +7 -0
- amsdal/schemas/types/dictionary/model.json +8 -0
- amsdal/schemas/types/number/model.json +8 -0
- amsdal/schemas/types/object/model.json +53 -0
- amsdal/schemas/types/string/model.json +8 -0
- amsdal/schemas/utils.py +16 -0
- amsdal/schemas/utils.pyi +10 -0
- amsdal/services/__init__.py +11 -0
- amsdal/services/__init__.pyi +4 -0
- amsdal/services/external_connections.py +262 -0
- amsdal/services/external_connections.pyi +190 -0
- amsdal/services/external_model_generator.py +350 -0
- amsdal/services/external_model_generator.pyi +134 -0
- amsdal/services/transaction_execution.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/services/transaction_execution.pyi +93 -0
- amsdal/storages/__init__.py +20 -0
- amsdal/storages/__init__.pyi +8 -0
- amsdal/storages/file_system.py +214 -0
- amsdal/storages/file_system.pyi +36 -0
- amsdal/transactions/__init__.py +13 -0
- amsdal/transactions/__init__.pyi +4 -0
- amsdal/utils/__init__.py +0 -0
- amsdal/utils/__init__.pyi +0 -0
- amsdal/utils/contrib_paths.py +23 -0
- amsdal/utils/contrib_paths.pyi +14 -0
- amsdal/utils/rollback/__init__.py +440 -0
- amsdal/utils/rollback/__init__.pyi +38 -0
- amsdal/utils/tests/__init__.py +0 -0
- amsdal/utils/tests/enums.py +16 -0
- amsdal/utils/tests/factories.py +49 -0
- amsdal/utils/tests/helpers.py +331 -0
- amsdal/utils/tests/migrations.py +157 -0
- amsdal-0.5.34.dist-info/METADATA +375 -0
- amsdal-0.5.34.dist-info/RECORD +276 -0
- amsdal-0.5.34.dist-info/WHEEL +6 -0
- amsdal-0.5.34.dist-info/licenses/LICENSE.txt +107 -0
- amsdal-0.5.34.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
"""
|
|
2
|
+
External Connection Manager for accessing external services and databases.
|
|
3
|
+
|
|
4
|
+
This module provides a high-level interface for working with external connections
|
|
5
|
+
such as read-only databases, email services, storage services, etc.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from typing import Any
|
|
9
|
+
from typing import TypeVar
|
|
10
|
+
|
|
11
|
+
from amsdal_data.application import AsyncDataApplication
|
|
12
|
+
from amsdal_data.application import DataApplication
|
|
13
|
+
from amsdal_utils.utils.singleton import Singleton
|
|
14
|
+
|
|
15
|
+
T = TypeVar('T')
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ExternalConnectionManager(metaclass=Singleton):
|
|
19
|
+
"""
|
|
20
|
+
Manager for accessing external service connections.
|
|
21
|
+
|
|
22
|
+
Provides a convenient interface to access external connections configured
|
|
23
|
+
in the application, such as read-only databases, email services, etc.
|
|
24
|
+
|
|
25
|
+
Example usage:
|
|
26
|
+
manager = ExternalConnectionManager()
|
|
27
|
+
|
|
28
|
+
# Get read-only database connection
|
|
29
|
+
external_db = manager.get_connection('external_users_db')
|
|
30
|
+
rows = external_db.fetch_all('SELECT * FROM users WHERE active = 1')
|
|
31
|
+
|
|
32
|
+
# Get email service
|
|
33
|
+
email = manager.get_connection('email_service')
|
|
34
|
+
email.send_email(...)
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
def __init__(self) -> None:
|
|
38
|
+
self._data_application: DataApplication | None = None
|
|
39
|
+
self._async_data_application: AsyncDataApplication | None = None
|
|
40
|
+
|
|
41
|
+
def setup(
|
|
42
|
+
self,
|
|
43
|
+
data_application: DataApplication | None = None,
|
|
44
|
+
async_data_application: AsyncDataApplication | None = None,
|
|
45
|
+
) -> None:
|
|
46
|
+
"""
|
|
47
|
+
Set up the manager with the data application instance.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
data_application: Sync DataApplication instance
|
|
51
|
+
async_data_application: Async DataApplication instance
|
|
52
|
+
"""
|
|
53
|
+
self._data_application = data_application
|
|
54
|
+
self._async_data_application = async_data_application
|
|
55
|
+
|
|
56
|
+
def get_connection(self, name: str) -> Any:
|
|
57
|
+
"""
|
|
58
|
+
Get an external service connection by name.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
name: Name of the external connection (as configured in resources)
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
The external connection object
|
|
65
|
+
|
|
66
|
+
Raises:
|
|
67
|
+
RuntimeError: If manager is not set up
|
|
68
|
+
KeyError: If connection not found
|
|
69
|
+
"""
|
|
70
|
+
if self._data_application is None and self._async_data_application is None:
|
|
71
|
+
msg = 'ExternalConnectionManager not set up. Call setup() first.'
|
|
72
|
+
raise RuntimeError(msg)
|
|
73
|
+
|
|
74
|
+
app = self._data_application or self._async_data_application
|
|
75
|
+
if app is None: # Shouldn't happen due to check above, but satisfy mypy
|
|
76
|
+
msg = 'No data application available'
|
|
77
|
+
raise RuntimeError(msg)
|
|
78
|
+
return app.get_external_service_connection(name)
|
|
79
|
+
|
|
80
|
+
def has_connection(self, name: str) -> bool:
|
|
81
|
+
"""
|
|
82
|
+
Check if an external connection exists.
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
name: Name of the external connection
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
bool: True if connection exists, False otherwise
|
|
89
|
+
"""
|
|
90
|
+
if self._data_application is None and self._async_data_application is None:
|
|
91
|
+
return False
|
|
92
|
+
|
|
93
|
+
try:
|
|
94
|
+
self.get_connection(name)
|
|
95
|
+
return True
|
|
96
|
+
except KeyError:
|
|
97
|
+
return False
|
|
98
|
+
|
|
99
|
+
def list_connections(self) -> list[str]:
|
|
100
|
+
"""
|
|
101
|
+
List all available external connection names.
|
|
102
|
+
|
|
103
|
+
Returns:
|
|
104
|
+
list[str]: List of connection names
|
|
105
|
+
"""
|
|
106
|
+
if self._data_application:
|
|
107
|
+
return list(self._data_application._external_service_connections.keys()) # noqa: SLF001
|
|
108
|
+
if self._async_data_application:
|
|
109
|
+
return list(self._async_data_application._external_service_connections.keys()) # noqa: SLF001
|
|
110
|
+
return []
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
class ExternalDatabaseReader:
|
|
114
|
+
"""
|
|
115
|
+
Helper class for reading from external read-only databases.
|
|
116
|
+
|
|
117
|
+
Provides a convenient interface for querying external databases
|
|
118
|
+
with common patterns like filtering, mapping results, etc.
|
|
119
|
+
|
|
120
|
+
Example usage:
|
|
121
|
+
reader = ExternalDatabaseReader('external_users_db')
|
|
122
|
+
|
|
123
|
+
# Fetch all users
|
|
124
|
+
users = reader.fetch_all('SELECT * FROM users')
|
|
125
|
+
|
|
126
|
+
# Fetch with parameters
|
|
127
|
+
active_users = reader.fetch_all(
|
|
128
|
+
'SELECT * FROM users WHERE active = ?',
|
|
129
|
+
(1,)
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
# Fetch one record
|
|
133
|
+
user = reader.fetch_one('SELECT * FROM users WHERE id = ?', (user_id,))
|
|
134
|
+
|
|
135
|
+
# Get as dictionaries
|
|
136
|
+
user_dicts = reader.fetch_all_as_dicts('SELECT * FROM users LIMIT 10')
|
|
137
|
+
"""
|
|
138
|
+
|
|
139
|
+
def __init__(self, connection_name: str):
|
|
140
|
+
"""
|
|
141
|
+
Initialize the reader with a connection name.
|
|
142
|
+
|
|
143
|
+
Args:
|
|
144
|
+
connection_name: Name of the external database connection
|
|
145
|
+
"""
|
|
146
|
+
self.connection_name = connection_name
|
|
147
|
+
self._manager = ExternalConnectionManager()
|
|
148
|
+
|
|
149
|
+
@property
|
|
150
|
+
def connection(self) -> Any:
|
|
151
|
+
"""Get the underlying connection object."""
|
|
152
|
+
return self._manager.get_connection(self.connection_name)
|
|
153
|
+
|
|
154
|
+
def fetch_all(self, query: str, parameters: tuple[Any, ...] | None = None) -> list[Any]:
|
|
155
|
+
"""
|
|
156
|
+
Execute query and fetch all results.
|
|
157
|
+
|
|
158
|
+
Args:
|
|
159
|
+
query: SQL query to execute
|
|
160
|
+
parameters: Query parameters (optional)
|
|
161
|
+
|
|
162
|
+
Returns:
|
|
163
|
+
list: List of result rows
|
|
164
|
+
"""
|
|
165
|
+
return self.connection.fetch_all(query, parameters)
|
|
166
|
+
|
|
167
|
+
def fetch_one(self, query: str, parameters: tuple[Any, ...] | None = None) -> Any | None:
|
|
168
|
+
"""
|
|
169
|
+
Execute query and fetch one result.
|
|
170
|
+
|
|
171
|
+
Args:
|
|
172
|
+
query: SQL query to execute
|
|
173
|
+
parameters: Query parameters (optional)
|
|
174
|
+
|
|
175
|
+
Returns:
|
|
176
|
+
Single result row or None
|
|
177
|
+
"""
|
|
178
|
+
return self.connection.fetch_one(query, parameters)
|
|
179
|
+
|
|
180
|
+
def fetch_all_as_dicts(self, query: str, parameters: tuple[Any, ...] | None = None) -> list[dict[str, Any]]:
|
|
181
|
+
"""
|
|
182
|
+
Execute query and fetch all results as dictionaries.
|
|
183
|
+
|
|
184
|
+
Args:
|
|
185
|
+
query: SQL query to execute
|
|
186
|
+
parameters: Query parameters (optional)
|
|
187
|
+
|
|
188
|
+
Returns:
|
|
189
|
+
list[dict]: List of result dictionaries
|
|
190
|
+
"""
|
|
191
|
+
rows = self.fetch_all(query, parameters)
|
|
192
|
+
return [dict(row) for row in rows]
|
|
193
|
+
|
|
194
|
+
def fetch_one_as_dict(self, query: str, parameters: tuple[Any, ...] | None = None) -> dict[str, Any] | None:
|
|
195
|
+
"""
|
|
196
|
+
Execute query and fetch one result as dictionary.
|
|
197
|
+
|
|
198
|
+
Args:
|
|
199
|
+
query: SQL query to execute
|
|
200
|
+
parameters: Query parameters (optional)
|
|
201
|
+
|
|
202
|
+
Returns:
|
|
203
|
+
dict | None: Result dictionary or None
|
|
204
|
+
"""
|
|
205
|
+
row = self.fetch_one(query, parameters)
|
|
206
|
+
return dict(row) if row else None
|
|
207
|
+
|
|
208
|
+
def get_table_names(self) -> list[str]:
|
|
209
|
+
"""
|
|
210
|
+
Get list of all tables in the database.
|
|
211
|
+
|
|
212
|
+
Returns:
|
|
213
|
+
list[str]: List of table names
|
|
214
|
+
"""
|
|
215
|
+
return self.connection.get_table_names()
|
|
216
|
+
|
|
217
|
+
def get_table_schema(self, table_name: str) -> list[dict[str, Any]]:
|
|
218
|
+
"""
|
|
219
|
+
Get schema information for a table.
|
|
220
|
+
|
|
221
|
+
Args:
|
|
222
|
+
table_name: Name of the table
|
|
223
|
+
|
|
224
|
+
Returns:
|
|
225
|
+
list[dict]: List of column information dictionaries
|
|
226
|
+
"""
|
|
227
|
+
return self.connection.get_table_schema(table_name)
|
|
228
|
+
|
|
229
|
+
def count(self, table: str, where_clause: str = '', parameters: tuple[Any, ...] | None = None) -> int:
|
|
230
|
+
"""
|
|
231
|
+
Count rows in a table.
|
|
232
|
+
|
|
233
|
+
Args:
|
|
234
|
+
table: Table name
|
|
235
|
+
where_clause: Optional WHERE clause (without WHERE keyword)
|
|
236
|
+
parameters: Query parameters for WHERE clause
|
|
237
|
+
|
|
238
|
+
Returns:
|
|
239
|
+
int: Number of rows
|
|
240
|
+
"""
|
|
241
|
+
query = f'SELECT COUNT(*) as count FROM {table}' # noqa: S608
|
|
242
|
+
if where_clause:
|
|
243
|
+
query += f' WHERE {where_clause}'
|
|
244
|
+
|
|
245
|
+
result = self.fetch_one(query, parameters)
|
|
246
|
+
return result['count'] if result else 0
|
|
247
|
+
|
|
248
|
+
def exists(self, table: str, where_clause: str, parameters: tuple[Any, ...]) -> bool:
|
|
249
|
+
"""
|
|
250
|
+
Check if a record exists.
|
|
251
|
+
|
|
252
|
+
Args:
|
|
253
|
+
table: Table name
|
|
254
|
+
where_clause: WHERE clause (without WHERE keyword)
|
|
255
|
+
parameters: Query parameters
|
|
256
|
+
|
|
257
|
+
Returns:
|
|
258
|
+
bool: True if record exists, False otherwise
|
|
259
|
+
"""
|
|
260
|
+
query = f'SELECT 1 FROM {table} WHERE {where_clause} LIMIT 1' # noqa: S608
|
|
261
|
+
result = self.fetch_one(query, parameters)
|
|
262
|
+
return result is not None
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
from _typeshed import Incomplete
|
|
2
|
+
from amsdal_data.application import AsyncDataApplication, DataApplication
|
|
3
|
+
from amsdal_utils.utils.singleton import Singleton
|
|
4
|
+
from typing import Any, TypeVar
|
|
5
|
+
|
|
6
|
+
T = TypeVar('T')
|
|
7
|
+
|
|
8
|
+
class ExternalConnectionManager(metaclass=Singleton):
|
|
9
|
+
"""
|
|
10
|
+
Manager for accessing external service connections.
|
|
11
|
+
|
|
12
|
+
Provides a convenient interface to access external connections configured
|
|
13
|
+
in the application, such as read-only databases, email services, etc.
|
|
14
|
+
|
|
15
|
+
Example usage:
|
|
16
|
+
manager = ExternalConnectionManager()
|
|
17
|
+
|
|
18
|
+
# Get read-only database connection
|
|
19
|
+
external_db = manager.get_connection('external_users_db')
|
|
20
|
+
rows = external_db.fetch_all('SELECT * FROM users WHERE active = 1')
|
|
21
|
+
|
|
22
|
+
# Get email service
|
|
23
|
+
email = manager.get_connection('email_service')
|
|
24
|
+
email.send_email(...)
|
|
25
|
+
"""
|
|
26
|
+
_data_application: DataApplication | None
|
|
27
|
+
_async_data_application: AsyncDataApplication | None
|
|
28
|
+
def __init__(self) -> None: ...
|
|
29
|
+
def setup(self, data_application: DataApplication | None = None, async_data_application: AsyncDataApplication | None = None) -> None:
|
|
30
|
+
"""
|
|
31
|
+
Set up the manager with the data application instance.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
data_application: Sync DataApplication instance
|
|
35
|
+
async_data_application: Async DataApplication instance
|
|
36
|
+
"""
|
|
37
|
+
def get_connection(self, name: str) -> Any:
|
|
38
|
+
"""
|
|
39
|
+
Get an external service connection by name.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
name: Name of the external connection (as configured in resources)
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
The external connection object
|
|
46
|
+
|
|
47
|
+
Raises:
|
|
48
|
+
RuntimeError: If manager is not set up
|
|
49
|
+
KeyError: If connection not found
|
|
50
|
+
"""
|
|
51
|
+
def has_connection(self, name: str) -> bool:
|
|
52
|
+
"""
|
|
53
|
+
Check if an external connection exists.
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
name: Name of the external connection
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
bool: True if connection exists, False otherwise
|
|
60
|
+
"""
|
|
61
|
+
def list_connections(self) -> list[str]:
|
|
62
|
+
"""
|
|
63
|
+
List all available external connection names.
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
list[str]: List of connection names
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
class ExternalDatabaseReader:
|
|
70
|
+
"""
|
|
71
|
+
Helper class for reading from external read-only databases.
|
|
72
|
+
|
|
73
|
+
Provides a convenient interface for querying external databases
|
|
74
|
+
with common patterns like filtering, mapping results, etc.
|
|
75
|
+
|
|
76
|
+
Example usage:
|
|
77
|
+
reader = ExternalDatabaseReader('external_users_db')
|
|
78
|
+
|
|
79
|
+
# Fetch all users
|
|
80
|
+
users = reader.fetch_all('SELECT * FROM users')
|
|
81
|
+
|
|
82
|
+
# Fetch with parameters
|
|
83
|
+
active_users = reader.fetch_all(
|
|
84
|
+
'SELECT * FROM users WHERE active = ?',
|
|
85
|
+
(1,)
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
# Fetch one record
|
|
89
|
+
user = reader.fetch_one('SELECT * FROM users WHERE id = ?', (user_id,))
|
|
90
|
+
|
|
91
|
+
# Get as dictionaries
|
|
92
|
+
user_dicts = reader.fetch_all_as_dicts('SELECT * FROM users LIMIT 10')
|
|
93
|
+
"""
|
|
94
|
+
connection_name: Incomplete
|
|
95
|
+
_manager: Incomplete
|
|
96
|
+
def __init__(self, connection_name: str) -> None:
|
|
97
|
+
"""
|
|
98
|
+
Initialize the reader with a connection name.
|
|
99
|
+
|
|
100
|
+
Args:
|
|
101
|
+
connection_name: Name of the external database connection
|
|
102
|
+
"""
|
|
103
|
+
@property
|
|
104
|
+
def connection(self) -> Any:
|
|
105
|
+
"""Get the underlying connection object."""
|
|
106
|
+
def fetch_all(self, query: str, parameters: tuple[Any, ...] | None = None) -> list[Any]:
|
|
107
|
+
"""
|
|
108
|
+
Execute query and fetch all results.
|
|
109
|
+
|
|
110
|
+
Args:
|
|
111
|
+
query: SQL query to execute
|
|
112
|
+
parameters: Query parameters (optional)
|
|
113
|
+
|
|
114
|
+
Returns:
|
|
115
|
+
list: List of result rows
|
|
116
|
+
"""
|
|
117
|
+
def fetch_one(self, query: str, parameters: tuple[Any, ...] | None = None) -> Any | None:
|
|
118
|
+
"""
|
|
119
|
+
Execute query and fetch one result.
|
|
120
|
+
|
|
121
|
+
Args:
|
|
122
|
+
query: SQL query to execute
|
|
123
|
+
parameters: Query parameters (optional)
|
|
124
|
+
|
|
125
|
+
Returns:
|
|
126
|
+
Single result row or None
|
|
127
|
+
"""
|
|
128
|
+
def fetch_all_as_dicts(self, query: str, parameters: tuple[Any, ...] | None = None) -> list[dict[str, Any]]:
|
|
129
|
+
"""
|
|
130
|
+
Execute query and fetch all results as dictionaries.
|
|
131
|
+
|
|
132
|
+
Args:
|
|
133
|
+
query: SQL query to execute
|
|
134
|
+
parameters: Query parameters (optional)
|
|
135
|
+
|
|
136
|
+
Returns:
|
|
137
|
+
list[dict]: List of result dictionaries
|
|
138
|
+
"""
|
|
139
|
+
def fetch_one_as_dict(self, query: str, parameters: tuple[Any, ...] | None = None) -> dict[str, Any] | None:
|
|
140
|
+
"""
|
|
141
|
+
Execute query and fetch one result as dictionary.
|
|
142
|
+
|
|
143
|
+
Args:
|
|
144
|
+
query: SQL query to execute
|
|
145
|
+
parameters: Query parameters (optional)
|
|
146
|
+
|
|
147
|
+
Returns:
|
|
148
|
+
dict | None: Result dictionary or None
|
|
149
|
+
"""
|
|
150
|
+
def get_table_names(self) -> list[str]:
|
|
151
|
+
"""
|
|
152
|
+
Get list of all tables in the database.
|
|
153
|
+
|
|
154
|
+
Returns:
|
|
155
|
+
list[str]: List of table names
|
|
156
|
+
"""
|
|
157
|
+
def get_table_schema(self, table_name: str) -> list[dict[str, Any]]:
|
|
158
|
+
"""
|
|
159
|
+
Get schema information for a table.
|
|
160
|
+
|
|
161
|
+
Args:
|
|
162
|
+
table_name: Name of the table
|
|
163
|
+
|
|
164
|
+
Returns:
|
|
165
|
+
list[dict]: List of column information dictionaries
|
|
166
|
+
"""
|
|
167
|
+
def count(self, table: str, where_clause: str = '', parameters: tuple[Any, ...] | None = None) -> int:
|
|
168
|
+
"""
|
|
169
|
+
Count rows in a table.
|
|
170
|
+
|
|
171
|
+
Args:
|
|
172
|
+
table: Table name
|
|
173
|
+
where_clause: Optional WHERE clause (without WHERE keyword)
|
|
174
|
+
parameters: Query parameters for WHERE clause
|
|
175
|
+
|
|
176
|
+
Returns:
|
|
177
|
+
int: Number of rows
|
|
178
|
+
"""
|
|
179
|
+
def exists(self, table: str, where_clause: str, parameters: tuple[Any, ...]) -> bool:
|
|
180
|
+
"""
|
|
181
|
+
Check if a record exists.
|
|
182
|
+
|
|
183
|
+
Args:
|
|
184
|
+
table: Table name
|
|
185
|
+
where_clause: WHERE clause (without WHERE keyword)
|
|
186
|
+
parameters: Query parameters
|
|
187
|
+
|
|
188
|
+
Returns:
|
|
189
|
+
bool: True if record exists, False otherwise
|
|
190
|
+
"""
|