fdc-shared-kernel 0.0.190__tar.gz → 0.0.192__tar.gz
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.
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/PKG-INFO +1 -1
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/fdc_shared_kernel.egg-info/PKG-INFO +1 -1
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/fdc_shared_kernel.egg-info/SOURCES.txt +3 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/pyproject.toml +1 -1
- fdc_shared_kernel-0.0.192/shared_kernel/data_warehouse_handlers/connections/fabric_sql_warehouse_connection.py +218 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/data_warehouse_handlers/connections/mssql_warehouse_connection.py +3 -0
- fdc_shared_kernel-0.0.192/shared_kernel/data_warehouse_handlers/fabric_sql_handler.py +75 -0
- fdc_shared_kernel-0.0.192/shared_kernel/data_warehouse_handlers/query_executors/fabric_sql_query_executor.py +142 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/data_warehouse_handlers/query_executors/mssql_query_executor.py +2 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/data_warehouse_handlers/warehouse_handlers_map.py +2 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/dataclasses/warehouse_configs.py +13 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/enums/connection_engine.py +1 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/README.md +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/README_pypi.md +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/fdc_shared_kernel.egg-info/dependency_links.txt +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/fdc_shared_kernel.egg-info/requires.txt +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/fdc_shared_kernel.egg-info/top_level.txt +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/requirements.txt +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/setup.cfg +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/__init__.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/agent_communication_channel/__init__.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/agent_communication_channel/agent_channel.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/agent_communication_channel/contexts.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/agent_communication_channel/event_channel.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/ai_audit_log/__init__.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/ai_chat_persistence/__init__.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/ai_chat_persistence/chat_persistence.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/async_task_executor/__init__.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/async_task_executor/async_task_executor.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/auth/__init__.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/auth/jwt_helper.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/auth/token_handler.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/auth/workbook_permission_handler.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/batch_job/__init__.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/batch_job/batch_job_status_tracker/container_job_status_tracker.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/batch_job/job_handlers/__init__.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/batch_job/job_handlers/aws_batch_job_handler.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/batch_job/job_handlers/azure_apps_job_handler.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/batch_job/job_handlers/job_handler_factory.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/batch_job/job_handlers/job_status_mapper.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/batch_job/job_storage_managers/__init__.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/batch_job/job_storage_managers/azure_blob_storage_manager.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/batch_job/job_storage_managers/job_storage_manager_factory.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/batch_job/job_storage_managers/s3_job_storage_manager.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/config/__init__.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/constants/constants.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/data_warehouse_handlers/__init__.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/data_warehouse_handlers/connections/databricks_warehouse_connection.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/data_warehouse_handlers/connections/jdbc_warehouse_connection.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/data_warehouse_handlers/connections/mysql_warehouse_connection.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/data_warehouse_handlers/connections/postgresql_warehouse_connection.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/data_warehouse_handlers/connections/redshift_warehouse_connection.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/data_warehouse_handlers/connections/snowflake_warehouse_connection.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/data_warehouse_handlers/custom_query_builders/databricks_query.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/data_warehouse_handlers/databricks_handler.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/data_warehouse_handlers/factory.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/data_warehouse_handlers/jdbc_driver_registry.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/data_warehouse_handlers/jdbc_handler.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/data_warehouse_handlers/mssql_handler.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/data_warehouse_handlers/mysql_handler.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/data_warehouse_handlers/odbc_handler.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/data_warehouse_handlers/postgresql_handler.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/data_warehouse_handlers/query_executors/databricks_query_executor.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/data_warehouse_handlers/query_executors/jdbc_query_executor.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/data_warehouse_handlers/query_executors/mysql_query_executor.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/data_warehouse_handlers/query_executors/postgresql_query_executor.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/data_warehouse_handlers/query_executors/redshift_query_executor.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/data_warehouse_handlers/query_executors/snowflake_query_executor.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/data_warehouse_handlers/redshift_handler.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/data_warehouse_handlers/snowflake_handler.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/data_warehouse_handlers/utils.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/database/__init__.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/dataclasses/__init__.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/dataclasses/aws_batch_job_context.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/dataclasses/azure_container_app_job_context.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/dataclasses/event_executor.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/dataclasses/job_context.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/dataclasses/job_record_dataclasses.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/datatype_mappings/__init__.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/datatype_mappings/connectors_to_system/__init__.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/datatype_mappings/connectors_to_system/csv.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/datatype_mappings/connectors_to_system/databricks.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/datatype_mappings/connectors_to_system/db2.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/datatype_mappings/connectors_to_system/jdbc.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/datatype_mappings/connectors_to_system/jira.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/datatype_mappings/connectors_to_system/mssql.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/datatype_mappings/connectors_to_system/mysql.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/datatype_mappings/connectors_to_system/oracle.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/datatype_mappings/connectors_to_system/postgres.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/datatype_mappings/connectors_to_system/redshift.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/datatype_mappings/connectors_to_system/salesforce.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/datatype_mappings/connectors_to_system/snowflake.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/datatype_mappings/connectors_to_system/sqlalchemy.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/datatype_mappings/system_to_warehouse/__init__.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/datatype_mappings/system_to_warehouse/postgres.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/datatype_mappings/system_to_warehouse/redshift.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/enums/__init__.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/enums/async_task_executor.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/enums/status_tracker.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/event_executor/__init__.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/event_executor/event_executor.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/event_executor/job_executor.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/event_executor/utils.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/exceptions/__init__.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/exceptions/batch_job_exceptions.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/exceptions/configuration_exceptions.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/exceptions/custom_exceptions.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/exceptions/data_validation_exceptions.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/exceptions/http_exceptions.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/exceptions/infrastructure_exceptions.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/exceptions/operational_exceptions.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/exceptions/security_exceptions.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/exceptions/user_intervention_exception.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/http/__init__.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/http/httpx_http_client.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/http/request_http_client.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/interfaces/__init__.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/interfaces/base_job_handler.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/interfaces/data_warehouse_handler.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/interfaces/databus.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/interfaces/encryption.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/interfaces/http.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/interfaces/keyvault.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/interfaces/query_executor.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/interfaces/storage_manager.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/interfaces/warehouse_connection.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/logger/__init__.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/messaging/__init__.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/messaging/aws_databus.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/messaging/azure_databus.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/messaging/http_databus.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/messaging/nats_databus.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/messaging/nats_publisher.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/messaging/nats_test.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/messaging/utils/aws_utility.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/messaging/utils/azure_utility.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/messaging/utils/event_messages.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/metrics/__init__.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/metrics/status_tracker.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/models/__init__.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/registries/__init__.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/registries/schema_onboarding_event_registry.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/registries/service_event_registry.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/schema_onboarding_tracker/__init__.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/schema_onboarding_tracker/base_tracker.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/schema_onboarding_tracker/enums.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/schema_onboarding_tracker/exceptions.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/schema_onboarding_tracker/run_manager.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/schema_onboarding_tracker/schema_onboarding_tracker.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/schema_onboarding_tracker/shared_helpers.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/schema_onboarding_tracker/task_determination.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/schema_onboarding_tracker/task_helpers.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/schema_onboarding_tracker/task_manager.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/schema_onboarding_tracker/template_manager.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/schema_onboarding_tracker/utility_manager.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/security/__init__.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/security/encryption/__init__.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/security/encryption/manager.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/security/encryption/providers.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/security/key_vault/__init__.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/security/key_vault/aws_secret_manager.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/security/key_vault/azure_keyvault.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/status_tracker/__init__.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/status_tracker/status_tracker.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/storage_handlers/__init__.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/storage_handlers/blob_file_handler.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/storage_handlers/s3_storage_handler.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/tests/__init__.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/tests/config/__init__.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/tests/config/test_config.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/tests/logger/__init__.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/tests/logger/test_logger.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/tests/messaging/__init__.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/tests/messaging/test_aws_databus.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/tests/messaging/test_event_executor.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/tests/messaging/test_nats_interface.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/tests/security/test_encryption.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/tests/utils/__init__.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/tests/utils/test_data_validators.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/tests/utils/test_date_format_utils.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/tests/utils/test_string_utils.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/traceability/__init__.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/traceability/traceability_handler.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/utils/__init__.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/utils/data_validators_utils.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/utils/date_format_utils.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/utils/date_utils.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/utils/string_utils.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/utils/template_renderer.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/utils/thread_debug_utils.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/utils/thread_local_storage.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/utils/thread_log_traker.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/tests/__init__.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/tests/messaging/__init__.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/tests/messaging/utils/__init__.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/tests/messaging/utils/test_aws_utility.py +0 -0
- {fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/tests/test_job_executor.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fdc_shared_kernel
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.192
|
|
4
4
|
Summary: Shared library for microservice
|
|
5
5
|
Author-email: Shikhil S <shikhil.s@dbizsolution.com>, Ahammed Akdham N <ahammedakdham.n@dbizsolution.com>
|
|
6
6
|
Classifier: Programming Language :: Python :: 3
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fdc_shared_kernel
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.192
|
|
4
4
|
Summary: Shared library for microservice
|
|
5
5
|
Author-email: Shikhil S <shikhil.s@dbizsolution.com>, Ahammed Akdham N <ahammedakdham.n@dbizsolution.com>
|
|
6
6
|
Classifier: Programming Language :: Python :: 3
|
{fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/fdc_shared_kernel.egg-info/SOURCES.txt
RENAMED
|
@@ -36,6 +36,7 @@ shared_kernel/config/__init__.py
|
|
|
36
36
|
shared_kernel/constants/constants.py
|
|
37
37
|
shared_kernel/data_warehouse_handlers/__init__.py
|
|
38
38
|
shared_kernel/data_warehouse_handlers/databricks_handler.py
|
|
39
|
+
shared_kernel/data_warehouse_handlers/fabric_sql_handler.py
|
|
39
40
|
shared_kernel/data_warehouse_handlers/factory.py
|
|
40
41
|
shared_kernel/data_warehouse_handlers/jdbc_driver_registry.py
|
|
41
42
|
shared_kernel/data_warehouse_handlers/jdbc_handler.py
|
|
@@ -48,6 +49,7 @@ shared_kernel/data_warehouse_handlers/snowflake_handler.py
|
|
|
48
49
|
shared_kernel/data_warehouse_handlers/utils.py
|
|
49
50
|
shared_kernel/data_warehouse_handlers/warehouse_handlers_map.py
|
|
50
51
|
shared_kernel/data_warehouse_handlers/connections/databricks_warehouse_connection.py
|
|
52
|
+
shared_kernel/data_warehouse_handlers/connections/fabric_sql_warehouse_connection.py
|
|
51
53
|
shared_kernel/data_warehouse_handlers/connections/jdbc_warehouse_connection.py
|
|
52
54
|
shared_kernel/data_warehouse_handlers/connections/mssql_warehouse_connection.py
|
|
53
55
|
shared_kernel/data_warehouse_handlers/connections/mysql_warehouse_connection.py
|
|
@@ -56,6 +58,7 @@ shared_kernel/data_warehouse_handlers/connections/redshift_warehouse_connection.
|
|
|
56
58
|
shared_kernel/data_warehouse_handlers/connections/snowflake_warehouse_connection.py
|
|
57
59
|
shared_kernel/data_warehouse_handlers/custom_query_builders/databricks_query.py
|
|
58
60
|
shared_kernel/data_warehouse_handlers/query_executors/databricks_query_executor.py
|
|
61
|
+
shared_kernel/data_warehouse_handlers/query_executors/fabric_sql_query_executor.py
|
|
59
62
|
shared_kernel/data_warehouse_handlers/query_executors/jdbc_query_executor.py
|
|
60
63
|
shared_kernel/data_warehouse_handlers/query_executors/mssql_query_executor.py
|
|
61
64
|
shared_kernel/data_warehouse_handlers/query_executors/mysql_query_executor.py
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import hashlib
|
|
2
|
+
import time
|
|
3
|
+
import threading
|
|
4
|
+
|
|
5
|
+
from contextlib import contextmanager
|
|
6
|
+
from typing import Dict
|
|
7
|
+
|
|
8
|
+
from sqlalchemy import create_engine, text
|
|
9
|
+
from sqlalchemy.engine import Engine
|
|
10
|
+
from sqlalchemy.exc import InterfaceError, OperationalError, ProgrammingError
|
|
11
|
+
|
|
12
|
+
from shared_kernel.dataclasses.warehouse_configs import FabricSQLConfig
|
|
13
|
+
from shared_kernel.exceptions.http_exceptions import BadRequest
|
|
14
|
+
from shared_kernel.interfaces.warehouse_connection import DataWarehouseConnection
|
|
15
|
+
from shared_kernel.data_warehouse_handlers.utils import extract_sql_server_error_message
|
|
16
|
+
from shared_kernel.logger import Logger
|
|
17
|
+
from shared_kernel.config import Config
|
|
18
|
+
|
|
19
|
+
config = Config()
|
|
20
|
+
logger = Logger(config.get("APP_NAME"))
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class FabricSQLWarehouseConnection(DataWarehouseConnection):
|
|
24
|
+
|
|
25
|
+
_engines: Dict[str, Engine] = {}
|
|
26
|
+
_tokens: Dict[str, dict] = {}
|
|
27
|
+
_lock = threading.Lock()
|
|
28
|
+
|
|
29
|
+
def __init__(
|
|
30
|
+
self,
|
|
31
|
+
source_config: FabricSQLConfig,
|
|
32
|
+
set_default_schema: bool = True,
|
|
33
|
+
):
|
|
34
|
+
if source_config is None:
|
|
35
|
+
raise ValueError("Missing required parameter: source_config (FabricSQLConfig)")
|
|
36
|
+
|
|
37
|
+
self._fabric_config = source_config
|
|
38
|
+
self.org_schema = source_config.schema if source_config.schema else None
|
|
39
|
+
self.set_default_schema = set_default_schema
|
|
40
|
+
|
|
41
|
+
pagination = getattr(source_config, "pagination", None) or {}
|
|
42
|
+
self.page = pagination.get("page") if isinstance(pagination, dict) else None
|
|
43
|
+
self.limit = pagination.get("limit") if isinstance(pagination, dict) else None
|
|
44
|
+
self.search = pagination.get("search") if isinstance(pagination, dict) else None
|
|
45
|
+
|
|
46
|
+
def _engine_key(self, cfg: FabricSQLConfig) -> str:
|
|
47
|
+
h = hashlib.md5(f"{cfg.host}:{cfg.port}:{cfg.database}:{cfg.username}".encode()).hexdigest()
|
|
48
|
+
return h
|
|
49
|
+
|
|
50
|
+
def _get_fabric_connection_params(self, cfg: FabricSQLConfig) -> str:
|
|
51
|
+
"""
|
|
52
|
+
Builds the base connection parameters for Microsoft Fabric SQL.
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
str: Connection string
|
|
56
|
+
"""
|
|
57
|
+
import urllib.parse
|
|
58
|
+
# Build ODBC params. We omit UID and Password fields entirely from the connection string.
|
|
59
|
+
# Authentication is handled solely by injecting the access token into the connection handle.
|
|
60
|
+
odbc_params = urllib.parse.quote_plus(
|
|
61
|
+
f"DRIVER={{ODBC Driver 18 for SQL Server}};"
|
|
62
|
+
f"SERVER={cfg.host},{int(cfg.port)};"
|
|
63
|
+
f"DATABASE={cfg.database};"
|
|
64
|
+
"Encrypt=yes;"
|
|
65
|
+
"TrustServerCertificate=no;"
|
|
66
|
+
)
|
|
67
|
+
# We use odbc_connect query param to prevent SQLAlchemy dialect from auto-injecting
|
|
68
|
+
# conflicting credentials/parameters (avoiding error FA005).
|
|
69
|
+
connection_string = f"mssql+pyodbc:///?odbc_connect={odbc_params}"
|
|
70
|
+
return connection_string
|
|
71
|
+
|
|
72
|
+
def _get_engine(self) -> Engine:
|
|
73
|
+
cfg = self._fabric_config
|
|
74
|
+
key = self._engine_key(cfg)
|
|
75
|
+
|
|
76
|
+
if key not in self._engines:
|
|
77
|
+
with self.__class__._lock: # thread-safe
|
|
78
|
+
if key not in self._engines: # recheck
|
|
79
|
+
from sqlalchemy import event
|
|
80
|
+
|
|
81
|
+
connection_string = self._get_fabric_connection_params(cfg)
|
|
82
|
+
|
|
83
|
+
engine = create_engine(
|
|
84
|
+
connection_string,
|
|
85
|
+
pool_size=10,
|
|
86
|
+
max_overflow=5,
|
|
87
|
+
pool_timeout=30,
|
|
88
|
+
pool_recycle=1800,
|
|
89
|
+
pool_pre_ping=True,
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
# Ensure a thread-safe token cache structure exists for this database key.
|
|
93
|
+
# Each unique database configuration gets its own token cache, expiration tracker, and lock.
|
|
94
|
+
if key not in self._tokens:
|
|
95
|
+
self._tokens[key] = {
|
|
96
|
+
"token": None, # Stores the packed binary token structure
|
|
97
|
+
"expires_at": 0, # Unix timestamp indicating token expiration time
|
|
98
|
+
"lock": threading.Lock() # Lock to synchronize concurrent token refreshes
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
# Register an event listener on the engine to intercept connection establishment.
|
|
102
|
+
# Every time SQLAlchemy checks out or opens a new raw DBAPI connection from the pool,
|
|
103
|
+
# this listener executes to inject a valid, fresh Entra ID access token.
|
|
104
|
+
@event.listens_for(engine, "do_connect")
|
|
105
|
+
def provide_token(dialect, conn_rec, cargs, cparams):
|
|
106
|
+
now = time.time()
|
|
107
|
+
token_info = self._tokens[key]
|
|
108
|
+
|
|
109
|
+
# Check if the token is missing or near expiration (within 5 minutes / 300 seconds).
|
|
110
|
+
# This buffer ensures we don't send a token that is about to expire.
|
|
111
|
+
if token_info["token"] is None or now >= token_info["expires_at"] - 300:
|
|
112
|
+
# Acquire the database-specific lock to serialize token generation.
|
|
113
|
+
# If 10 threads try to connect concurrently when a token expires,
|
|
114
|
+
# only the first thread executes the token fetch; others block here.
|
|
115
|
+
with token_info["lock"]:
|
|
116
|
+
# Double-checked locking pattern: once the lock is acquired,
|
|
117
|
+
# re-verify if another thread updated the token while we were waiting.
|
|
118
|
+
if token_info["token"] is None or now >= token_info["expires_at"] - 300:
|
|
119
|
+
tenant_id = getattr(cfg, "tenant_id", None)
|
|
120
|
+
if not tenant_id:
|
|
121
|
+
raise ValueError(
|
|
122
|
+
"tenant_id is required in FabricSQLConfig for authenticating to Microsoft Fabric via Active Directory Service Principal."
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
from azure.identity import ClientSecretCredential
|
|
126
|
+
import struct
|
|
127
|
+
|
|
128
|
+
logger.info("Fetching fresh Entra ID access token for Fabric SQL connection...")
|
|
129
|
+
# Instantiate the credential to retrieve a token for the Azure SQL Endpoint
|
|
130
|
+
cred = ClientSecretCredential(
|
|
131
|
+
tenant_id=tenant_id,
|
|
132
|
+
client_id=cfg.username,
|
|
133
|
+
client_secret=cfg.password
|
|
134
|
+
)
|
|
135
|
+
token_obj = cred.get_token("https://database.windows.net/.default")
|
|
136
|
+
|
|
137
|
+
# Encode the OAuth token to UTF-16-LE bytes.
|
|
138
|
+
# Pack the payload into the binary structure required by ODBC Driver 18:
|
|
139
|
+
# [4 bytes representing the length of the token string] followed by [the token string bytes].
|
|
140
|
+
token_bytes = token_obj.token.encode("utf-16-le")
|
|
141
|
+
token_info["token"] = struct.pack(f"<I{len(token_bytes)}s", len(token_bytes), token_bytes)
|
|
142
|
+
token_info["expires_at"] = token_obj.expires_on
|
|
143
|
+
logger.info("Successfully fetched and cached fresh Entra ID access token.")
|
|
144
|
+
|
|
145
|
+
# Inject the packed binary token structure into pyodbc's attrs_before connection attribute list.
|
|
146
|
+
# Attribute ID 1256 maps to SQL_COPT_SS_ACCESS_TOKEN.
|
|
147
|
+
cparams["attrs_before"] = {1256: token_info["token"]}
|
|
148
|
+
|
|
149
|
+
self._engines[key] = engine
|
|
150
|
+
logger.info(
|
|
151
|
+
f"Created new Fabric SQL engine for {cfg.host}:{cfg.port}/{cfg.database} with dynamic token provider"
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
return self._engines[key]
|
|
155
|
+
|
|
156
|
+
@contextmanager
|
|
157
|
+
def get_connection(self, retries: int = 3, delay: int = 5, query_timeout: int = 30):
|
|
158
|
+
"""Context manager for database connections with retry mechanism"""
|
|
159
|
+
engine = self._get_engine()
|
|
160
|
+
last_exception = None
|
|
161
|
+
|
|
162
|
+
for attempt in range(retries):
|
|
163
|
+
conn = None
|
|
164
|
+
try:
|
|
165
|
+
conn = engine.connect()
|
|
166
|
+
yield conn
|
|
167
|
+
return
|
|
168
|
+
|
|
169
|
+
except (OperationalError, InterfaceError, ProgrammingError) as e:
|
|
170
|
+
last_exception = e
|
|
171
|
+
if conn is not None:
|
|
172
|
+
conn.close()
|
|
173
|
+
conn = None
|
|
174
|
+
|
|
175
|
+
error_message = extract_sql_server_error_message(str(e))
|
|
176
|
+
logger.warning(
|
|
177
|
+
f"Fabric SQL connection failed (attempt {attempt + 1}/{retries}): {error_message}"
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
if attempt < retries - 1:
|
|
181
|
+
time.sleep(delay)
|
|
182
|
+
delay += 5
|
|
183
|
+
continue
|
|
184
|
+
|
|
185
|
+
break
|
|
186
|
+
|
|
187
|
+
finally:
|
|
188
|
+
if conn is not None:
|
|
189
|
+
conn.close()
|
|
190
|
+
|
|
191
|
+
raise BadRequest(
|
|
192
|
+
f"Failed to connect to Fabric SQL after {retries} attempts"
|
|
193
|
+
) from last_exception
|
|
194
|
+
|
|
195
|
+
def close_connection(self):
|
|
196
|
+
"""Dispose all pooled engines managed by this class."""
|
|
197
|
+
for engine in self._engines.values():
|
|
198
|
+
engine.dispose()
|
|
199
|
+
self._engines.clear()
|
|
200
|
+
self._tokens.clear()
|
|
201
|
+
logger.info("All Fabric SQL engine pools disposed.")
|
|
202
|
+
|
|
203
|
+
def is_valid_connection(self) -> bool:
|
|
204
|
+
"""Pool health is managed by pool_pre_ping; no manual check needed."""
|
|
205
|
+
return True
|
|
206
|
+
|
|
207
|
+
def test_connection(self) -> bool:
|
|
208
|
+
"""Verify the connection is reachable. Raises on failure."""
|
|
209
|
+
try:
|
|
210
|
+
with self.get_connection() as conn:
|
|
211
|
+
conn.execute(text("SELECT 1"))
|
|
212
|
+
return True
|
|
213
|
+
except OperationalError as e:
|
|
214
|
+
if "authentication failed" in str(e).lower():
|
|
215
|
+
raise ValueError("Invalid username or password")
|
|
216
|
+
raise ConnectionError(f"Database error: {str(e)}")
|
|
217
|
+
except InterfaceError:
|
|
218
|
+
raise ConnectionError("Cannot connect to database server")
|
|
@@ -56,12 +56,15 @@ class MSSQLWarehouseConnection(DataWarehouseConnection):
|
|
|
56
56
|
with self.__class__._lock: # thread-safe
|
|
57
57
|
if key not in self._engines: # recheck
|
|
58
58
|
password = quote(cfg.password)
|
|
59
|
+
logger.info(f"Using MSSQL connector (pyodbc native) for standard SQL Server connection on {cfg.host}")
|
|
59
60
|
connection_string = get_constant("mssql", "CONNECTION_STRING").format(
|
|
60
61
|
cfg.username, password, cfg.host, int(cfg.port), cfg.database
|
|
61
62
|
)
|
|
63
|
+
connect_args = {}
|
|
62
64
|
|
|
63
65
|
self._engines[key] = create_engine(
|
|
64
66
|
connection_string,
|
|
67
|
+
connect_args=connect_args,
|
|
65
68
|
pool_size=10,
|
|
66
69
|
max_overflow=5,
|
|
67
70
|
pool_timeout=30,
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
from pypika import MSSQLQuery
|
|
2
|
+
|
|
3
|
+
from shared_kernel.data_warehouse_handlers.connections.fabric_sql_warehouse_connection import (
|
|
4
|
+
FabricSQLWarehouseConnection,
|
|
5
|
+
)
|
|
6
|
+
from shared_kernel.data_warehouse_handlers.query_executors.fabric_sql_query_executor import (
|
|
7
|
+
FabricSQLQueryExecutor,
|
|
8
|
+
)
|
|
9
|
+
from shared_kernel.dataclasses.warehouse_configs import FabricSQLConfig
|
|
10
|
+
from shared_kernel.interfaces.data_warehouse_handler import WarehouseHandler
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class FabricSQLWarehouseHandler(WarehouseHandler):
|
|
14
|
+
|
|
15
|
+
def __init__(self, payload: dict = None):
|
|
16
|
+
super().__init__(payload)
|
|
17
|
+
self.set_default_schema = self.payload.get("set_default_schema", True)
|
|
18
|
+
|
|
19
|
+
def get_config(self) -> FabricSQLConfig:
|
|
20
|
+
source_config: FabricSQLConfig = self.payload.get("source_config")
|
|
21
|
+
if source_config and isinstance(source_config, FabricSQLConfig):
|
|
22
|
+
return source_config
|
|
23
|
+
|
|
24
|
+
required = ("host", "user", "password", "database", "tenant_id")
|
|
25
|
+
missing = [f for f in required if not self.payload.get(f)]
|
|
26
|
+
if missing:
|
|
27
|
+
raise ValueError(f"Fabric SQL payload is missing required fields: {missing}.")
|
|
28
|
+
|
|
29
|
+
return FabricSQLConfig(
|
|
30
|
+
username=str(self.payload.get("user")).strip(),
|
|
31
|
+
password=str(self.payload.get("password")).strip(),
|
|
32
|
+
host=str(self.payload.get("host")).strip(),
|
|
33
|
+
database=str(self.payload.get("database")).strip(),
|
|
34
|
+
tenant_id=str(self.payload.get("tenant_id")).strip(),
|
|
35
|
+
port=str(self.payload.get("port", "1433")).strip(),
|
|
36
|
+
schema=(
|
|
37
|
+
str(self.payload.get("schema")).strip()
|
|
38
|
+
if self.payload.get("schema")
|
|
39
|
+
else None
|
|
40
|
+
),
|
|
41
|
+
schema_list=self.payload.get("schema_list"),
|
|
42
|
+
pagination=self.pagination,
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
def _build_connection(self) -> FabricSQLWarehouseConnection:
|
|
46
|
+
return FabricSQLWarehouseConnection(
|
|
47
|
+
source_config=self.get_config(),
|
|
48
|
+
set_default_schema=self.set_default_schema,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
def get_executor(self) -> FabricSQLQueryExecutor:
|
|
52
|
+
connection = self._build_connection()
|
|
53
|
+
return FabricSQLQueryExecutor(warehouse_connection=connection)
|
|
54
|
+
|
|
55
|
+
def get_query_object(self) -> MSSQLQuery:
|
|
56
|
+
return MSSQLQuery
|
|
57
|
+
|
|
58
|
+
def create_records_and_count_query(
|
|
59
|
+
self,
|
|
60
|
+
query: str,
|
|
61
|
+
limit: str,
|
|
62
|
+
page: str,
|
|
63
|
+
) -> tuple[str, str]:
|
|
64
|
+
count_query = f"SELECT COUNT(*) FROM ({query}) AS _count"
|
|
65
|
+
|
|
66
|
+
if limit:
|
|
67
|
+
offset = (int(page) - 1) * int(limit) if page else 0
|
|
68
|
+
query = (
|
|
69
|
+
f"{query} "
|
|
70
|
+
f"ORDER BY (SELECT NULL) "
|
|
71
|
+
f"OFFSET {offset} ROWS "
|
|
72
|
+
f"FETCH NEXT {int(limit)} ROWS ONLY"
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
return count_query, query
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import time
|
|
2
|
+
|
|
3
|
+
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
4
|
+
from typing import Any, Dict, List, Optional, Tuple
|
|
5
|
+
|
|
6
|
+
from sqlalchemy import text
|
|
7
|
+
from sqlalchemy.exc import InterfaceError, OperationalError, ProgrammingError
|
|
8
|
+
|
|
9
|
+
from shared_kernel.config import Config
|
|
10
|
+
from shared_kernel.data_warehouse_handlers.utils import extract_error_message
|
|
11
|
+
from shared_kernel.interfaces.query_executor import DataWarehouseQueryExecutor
|
|
12
|
+
from shared_kernel.interfaces.warehouse_connection import DataWarehouseConnection
|
|
13
|
+
from shared_kernel.logger import Logger
|
|
14
|
+
|
|
15
|
+
config = Config()
|
|
16
|
+
logger = Logger(config.get("APP_NAME"))
|
|
17
|
+
MAX_QUERY_CONCURRENCY = 5
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class FabricSQLQueryExecutor(DataWarehouseQueryExecutor):
|
|
21
|
+
"""
|
|
22
|
+
Query executor for Microsoft Fabric SQL Server
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def __init__(self, warehouse_connection: DataWarehouseConnection) -> None:
|
|
26
|
+
self.warehouse_connection = warehouse_connection
|
|
27
|
+
|
|
28
|
+
def execute_query(
|
|
29
|
+
self,
|
|
30
|
+
query: str,
|
|
31
|
+
params: Optional[tuple] = None,
|
|
32
|
+
) -> List[Dict[str, Any]]:
|
|
33
|
+
"""
|
|
34
|
+
Execute a single SQL query and return all rows as a list of dicts.
|
|
35
|
+
"""
|
|
36
|
+
with self.warehouse_connection.get_connection() as conn:
|
|
37
|
+
try:
|
|
38
|
+
logger.info(f"Executing query: {query}")
|
|
39
|
+
start = time.perf_counter()
|
|
40
|
+
|
|
41
|
+
result = (
|
|
42
|
+
conn.execute(text(query), params)
|
|
43
|
+
if params
|
|
44
|
+
else conn.execute(text(query))
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
elapsed = time.perf_counter() - start
|
|
48
|
+
logger.info(f"Query executed in {elapsed:.6f}s")
|
|
49
|
+
|
|
50
|
+
# Check if the query returns rows
|
|
51
|
+
if result.returns_rows:
|
|
52
|
+
# Optimize fetch performance for Microsoft Fabric by batching
|
|
53
|
+
result.cursor.arraysize = 5000
|
|
54
|
+
columns = [col for col in result.keys()]
|
|
55
|
+
return [dict(zip(columns, row)) for row in result.fetchall()]
|
|
56
|
+
else:
|
|
57
|
+
# Return an empty list for DDL queries
|
|
58
|
+
return []
|
|
59
|
+
|
|
60
|
+
except (OperationalError, ProgrammingError, InterfaceError) as e:
|
|
61
|
+
logger.error(f"Query failed: {query} — {e}", exc_info=True)
|
|
62
|
+
user_msg = extract_error_message(str(e))
|
|
63
|
+
raise Exception(f"Query execution failed: {user_msg}") from e
|
|
64
|
+
except Exception as e:
|
|
65
|
+
user_msg = extract_error_message(str(e))
|
|
66
|
+
raise Exception(f"Query execution failed: {user_msg}") from e
|
|
67
|
+
|
|
68
|
+
def execute_queries(
|
|
69
|
+
self,
|
|
70
|
+
queries: List[str],
|
|
71
|
+
) -> List[List[Dict[str, Any]]]:
|
|
72
|
+
"""
|
|
73
|
+
Execute multiple SQL queries in parallel and return results in input order.
|
|
74
|
+
"""
|
|
75
|
+
if not queries:
|
|
76
|
+
return []
|
|
77
|
+
|
|
78
|
+
indexed: List[Tuple[int, str]] = list(enumerate(queries))
|
|
79
|
+
results: List[Optional[List[Dict[str, Any]]]] = [None] * len(queries)
|
|
80
|
+
|
|
81
|
+
with ThreadPoolExecutor(max_workers=MAX_QUERY_CONCURRENCY) as pool:
|
|
82
|
+
future_to_index = {
|
|
83
|
+
pool.submit(self.execute_query, query): idx
|
|
84
|
+
for idx, query in indexed
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
for future in as_completed(future_to_index):
|
|
88
|
+
idx = future_to_index[future]
|
|
89
|
+
try:
|
|
90
|
+
results[idx] = future.result()
|
|
91
|
+
except Exception as e:
|
|
92
|
+
# Cancel all pending futures
|
|
93
|
+
for pending in future_to_index:
|
|
94
|
+
if not pending.done():
|
|
95
|
+
pending.cancel()
|
|
96
|
+
raise Exception(
|
|
97
|
+
f"Parallel query execution failed on query index {idx}: {e}"
|
|
98
|
+
) from e
|
|
99
|
+
|
|
100
|
+
return results
|
|
101
|
+
|
|
102
|
+
def execute_query_with_column_types(
|
|
103
|
+
self,
|
|
104
|
+
query: str,
|
|
105
|
+
params: Optional[tuple] = None,
|
|
106
|
+
) -> Tuple[List[Dict[str, Any]], List[Tuple]]:
|
|
107
|
+
"""
|
|
108
|
+
Execute a query and return both rows and raw DBAPI cursor description.
|
|
109
|
+
"""
|
|
110
|
+
with self.warehouse_connection.get_connection() as conn:
|
|
111
|
+
try:
|
|
112
|
+
logger.info(f"Executing query with column types: {query}")
|
|
113
|
+
start = time.perf_counter()
|
|
114
|
+
|
|
115
|
+
result = (
|
|
116
|
+
conn.execute(text(query), params)
|
|
117
|
+
if params
|
|
118
|
+
else conn.execute(text(query))
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
elapsed = time.perf_counter() - start
|
|
122
|
+
logger.info(f"Query executed in {elapsed:.6f}s")
|
|
123
|
+
|
|
124
|
+
# Check if the query returns rows
|
|
125
|
+
if result.returns_rows:
|
|
126
|
+
# Optimize fetch performance for Microsoft Fabric by batching
|
|
127
|
+
result.cursor.arraysize = 5000
|
|
128
|
+
description = result.cursor.description
|
|
129
|
+
columns = [col for col in result.keys()]
|
|
130
|
+
rows = [dict(zip(columns, row)) for row in result.fetchall()]
|
|
131
|
+
return rows, description
|
|
132
|
+
else:
|
|
133
|
+
# Return empty rows and description for DDL queries
|
|
134
|
+
return [], []
|
|
135
|
+
|
|
136
|
+
except (OperationalError, ProgrammingError, InterfaceError) as e:
|
|
137
|
+
logger.error(f"Query failed: {query} — {e}", exc_info=True)
|
|
138
|
+
user_msg = extract_error_message(str(e))
|
|
139
|
+
raise Exception(f"Query execution failed: {user_msg}") from e
|
|
140
|
+
except Exception as e:
|
|
141
|
+
user_msg = extract_error_message(str(e))
|
|
142
|
+
raise Exception(f"Query execution failed: {user_msg}") from e
|
|
@@ -49,6 +49,7 @@ class MSSQLQueryExecutor(DataWarehouseQueryExecutor):
|
|
|
49
49
|
|
|
50
50
|
# Check if the query returns rows
|
|
51
51
|
if result.returns_rows:
|
|
52
|
+
result.cursor.arraysize = 5000
|
|
52
53
|
columns = [col for col in result.keys()]
|
|
53
54
|
return [dict(zip(columns, row)) for row in result.fetchall()]
|
|
54
55
|
else:
|
|
@@ -128,6 +129,7 @@ class MSSQLQueryExecutor(DataWarehouseQueryExecutor):
|
|
|
128
129
|
|
|
129
130
|
# Check if the query returns rows
|
|
130
131
|
if result.returns_rows:
|
|
132
|
+
result.cursor.arraysize = 5000
|
|
131
133
|
description = result.cursor.description
|
|
132
134
|
columns = [col for col in result.keys()]
|
|
133
135
|
rows = [dict(zip(columns, row)) for row in result.fetchall()]
|
|
@@ -7,6 +7,7 @@ from shared_kernel.data_warehouse_handlers.postgresql_handler import PostgreSQLW
|
|
|
7
7
|
from shared_kernel.data_warehouse_handlers.redshift_handler import RedshiftWarehouseHandler
|
|
8
8
|
from shared_kernel.data_warehouse_handlers.snowflake_handler import SnowflakeWarehouseHandler
|
|
9
9
|
from shared_kernel.data_warehouse_handlers.jdbc_handler import JDBCWarehouseHandler
|
|
10
|
+
from shared_kernel.data_warehouse_handlers.fabric_sql_handler import FabricSQLWarehouseHandler
|
|
10
11
|
from shared_kernel.enums.connection_engine import ConnectionEngine
|
|
11
12
|
|
|
12
13
|
|
|
@@ -20,4 +21,5 @@ warehouse_handlers = {
|
|
|
20
21
|
ConnectionEngine.AZURESQL.value: MSSQLWarehouseHandler,
|
|
21
22
|
ConnectionEngine.DATABRICKS.value: DatabricksWarehouseHandler,
|
|
22
23
|
ConnectionEngine.JDBC.value: JDBCWarehouseHandler,
|
|
24
|
+
ConnectionEngine.FABRIC_SQL.value: FabricSQLWarehouseHandler,
|
|
23
25
|
}
|
|
@@ -46,6 +46,19 @@ class MSSQLConfig(BaseConfig):
|
|
|
46
46
|
default_schema: str = "dbo"
|
|
47
47
|
|
|
48
48
|
|
|
49
|
+
@dataclass
|
|
50
|
+
class FabricSQLConfig(BaseConfig):
|
|
51
|
+
"""Configuration for Microsoft Fabric SQL Server connections."""
|
|
52
|
+
|
|
53
|
+
username: str
|
|
54
|
+
password: str
|
|
55
|
+
host: str
|
|
56
|
+
database: str
|
|
57
|
+
tenant_id: str
|
|
58
|
+
port: str = "1433"
|
|
59
|
+
default_schema: str = "dbo"
|
|
60
|
+
|
|
61
|
+
|
|
49
62
|
@dataclass
|
|
50
63
|
class DatabricksConfig(BaseConfig):
|
|
51
64
|
"""Configuration for Databricks connections."""
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/fdc_shared_kernel.egg-info/requires.txt
RENAMED
|
File without changes
|
{fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/fdc_shared_kernel.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/ai_audit_log/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fdc_shared_kernel-0.0.190 → fdc_shared_kernel-0.0.192}/shared_kernel/constants/constants.py
RENAMED
|
File without changes
|
|
File without changes
|