quadkit-sql 0.0.42__tar.gz → 0.0.43__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.
- quadkit_sql-0.0.43/.gitignore +24 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/PKG-INFO +1 -1
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/pyproject.toml +1 -7
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/admin/audit_store.py +1 -1
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/cli/generators/seeder.py +1 -1
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/cli/generators/type_map.py +1 -1
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/cli/templates/database_repository.py.jinja2 +5 -4
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/cli/templates/entity_model.py.jinja2 +3 -6
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/cli/templates/seeder.py.jinja2 +3 -3
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/di/_registration.py +2 -2
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/di/provider.py +1 -1
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/migrations/manager/_alembic.py +36 -7
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/migrations/orchestrator.py +1 -1
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/providers/database_service.py +1 -1
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/query/builder.py +1 -1
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/resilience/__init__.py +1 -1
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/resilience/core.py +7 -7
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/conftest.py +6 -6
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/integration/test_migrations.py +14 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/backends/test_cockroachdb_backend.py +11 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/backends/test_postgres_connection.py +3 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/cli/test_entity_model_generator.py +1 -1
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/cli/test_type_map.py +2 -2
- quadkit_sql-0.0.43/tests/unit/migrations/test_alembic_config_path_separator.py +107 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_mysql_backend_scenario.py +8 -5
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_round25_hardening.py +1 -0
- quadkit_sql-0.0.42/.gitignore +0 -214
- quadkit_sql-0.0.42/docs/ARCHITECTURE.md +0 -337
- quadkit_sql-0.0.42/docs/BACKENDS.md +0 -151
- quadkit_sql-0.0.42/docs/CONFIGURATION.md +0 -169
- quadkit_sql-0.0.42/docs/GUIDE.md +0 -288
- quadkit_sql-0.0.42/docs/HOWTOS.md +0 -208
- quadkit_sql-0.0.42/docs/QUICKSTART.md +0 -77
- quadkit_sql-0.0.42/docs/TROUBLESHOOTING.md +0 -155
- quadkit_sql-0.0.42/tests/unit/test_db_search_backends.py +0 -350
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/LICENSE +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/NOTICE +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/README.md +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/alembic.ini +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/example.yaml +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/py.typed +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/__init__.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/abstractions/__init__.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/abstractions/connection.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/abstractions/py.typed +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/admin/__init__.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/admin/contributor.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/admin/handlers/__init__.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/admin/handlers/migration_status.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/admin/handlers/pool_utilization.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/admin/handlers/query_stats.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/admin/pages/__init__.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/admin/pages/migrations.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/admin/pages/overview.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/admin/pages/queries.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/admin/widgets/__init__.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/api/__init__.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/api/engine.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/api/protocols.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/audit/__init__.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/audit/mixin.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/audit/py.typed +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/backends/__init__.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/backends/_postgres_connection.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/backends/_ssl.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/backends/cockroachdb.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/backends/mysql/__init__.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/backends/mysql/_connection.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/backends/mysql/_pool.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/backends/mysql/_shims.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/backends/postgres.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/backends/py.typed +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/backends/sqlite/__init__.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/backends/sqlite/_connection.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/backends/sqlite/_pool.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/backends/sqlite/_shims.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/backup/__init__.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/backup/backup_manager.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/backup/maintenance.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/backup/py.typed +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/cli/__init__.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/cli/checks.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/cli/commands.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/cli/contributor.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/cli/doctor.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/cli/generators/__init__.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/cli/generators/base.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/cli/generators/database_repository.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/cli/generators/entity_migration.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/cli/generators/entity_model.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/cli/generators/filter.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/cli/generators/health_check.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/cli/generators/service.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/cli/manager.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/cli/shell.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/cli/templates/entity_migration.py.jinja2 +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/cli/templates/filter.py.jinja2 +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/cli/templates/health_check.py.jinja2 +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/cli/templates/service.py.jinja2 +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/config.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/constants.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/context/__init__.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/context/db_context.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/context/keys.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/context/manager.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/context/tasks.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/decorators.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/di/__init__.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/di/py.typed +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/events.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/exceptions.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/hooks.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/identifiers.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/lib/__init__.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/lib/helpers.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/lib/retry.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/logging/__init__.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/logging/loggers.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/managers/__init__.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/managers/manager.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/mappers/__init__.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/mappers/base.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/mappers/domain_mapper.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/mappers/py.typed +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/middleware/__init__.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/middleware/base.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/middleware/builtins.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/middleware/models.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/middleware/pipeline.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/migrations/__init__.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/migrations/api.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/migrations/base.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/migrations/engine.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/migrations/generator.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/migrations/introspector.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/migrations/manager/__init__.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/migrations/manager/_simple.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/migrations/model_analyzer.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/migrations/py.typed +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/migrations/runner.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/migrations/types.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/module.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/monitoring/__init__.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/monitoring/database_monitor/__init__.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/monitoring/database_monitor/facade.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/monitoring/database_monitor/health.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/monitoring/database_monitor/pool.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/monitoring/database_monitor/query.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/monitoring/database_monitor/transaction.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/monitoring/metrics.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/monitoring/py.typed +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/monitoring/query_analyzer.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/orm.pyi +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/outbox/__init__.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/outbox/publisher.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/outbox/store.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/pagination/__init__.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/pagination/cursor.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/pagination/offset.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/performance/__init__.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/performance/batch_processor.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/performance/engine_pragmas.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/performance/statement_cache.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/pool/__init__.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/pool/connection.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/pool/py.typed +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/pool/replica.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/protocols.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/providers/__init__.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/providers/_connection_mixin.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/providers/_health_mixin.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/providers/_lazy.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/providers/_query_mixin.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/providers/base_provider.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/providers/connection_manager.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/providers/crud_operations.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/providers/health_monitor.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/providers/mysql_provider.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/providers/postgres_provider.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/providers/py.typed +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/providers/query_builder_manager.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/providers/query_executor.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/providers/schema_manager.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/providers/sqlite_provider.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/providers/transaction_manager.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/py.typed +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/query/__init__.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/query/_sql_build_mixin.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/query/_sql_core_mixin.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/query/_sql_join_aggregate_mixin.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/query/_sql_where_mixin.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/query/admin_builder.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/query/compiler.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/query/cursor.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/query/operators.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/query/sql_builder.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/query/sql_types.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/repositories/__init__.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/repositories/_advanced_mixin.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/repositories/_filter_mixin.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/repositories/_read_mixin.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/repositories/_rls_mixin.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/repositories/_write_mixin.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/repositories/append_log.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/repositories/base.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/repositories/cached.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/repositories/cursor.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/repositories/decorators.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/repositories/filter_objects.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/repositories/filters.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/repositories/generic_repository.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/repositories/py.typed +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/repositories/scopes.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/row_level_security.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/schema/__init__.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/schema/descriptors.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/schema/field_types.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/schema/hooks.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/schema/model.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/search/__init__.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/search/full_text.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/seeds/__init__.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/seeds/api.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/seeds/factory.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/seeds/manager.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/seeds/py.typed +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/specification/__init__.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/specification/memory.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/specification/sql.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/storage/__init__.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/storage/postgres.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/stores/__init__.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/stores/locks.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/stores/secrets.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/stores/state.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/types.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/unit_of_work/__init__.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/unit_of_work/base.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/unit_of_work/decorators.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/unit_of_work/identity_map.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/unit_of_work/manager.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/unit_of_work/py.typed +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/unit_of_work/simple/__init__.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/unit_of_work/simple/_operations.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/unit_of_work/simple/_uow.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/validation/__init__.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/validation/protocols.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/validation/py.typed +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/fixtures/test.db +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/integration/test_add_previous_passwords_migration.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/integration/test_apply_previous_passwords_migration.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/integration/test_monitoring_metrics.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/integration/test_monitoring_slow_query.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/integration/test_postgres_provider_lifecycle.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/integration/test_postgres_repository_compliance.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/integration/test_provider_resilience_integration.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/integration/test_sqlite_provider_integration.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/admin/__init__.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/admin/handlers/__init__.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/admin/handlers/test_migration_status.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/admin/handlers/test_pool_utilization.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/admin/handlers/test_query_stats.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/admin/test_audit_store.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/admin/test_queries_page.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/admin/test_sql_contributor.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/audit/test_audit_repository_mixin.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/cli/__init__.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/cli/test_entity_migration_generator.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/cli/test_generators_contract.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/cli/test_health_generator.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/cli/test_repository_generator_staged.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/cli/test_service_generator.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/context/test_db_context.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/di/test_config_alignment.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/migrations/test_migration_model_analyzer.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/migrations/test_simple_migration_manager.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/outbox/__init__.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/outbox/test_outbox_publisher.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/outbox/test_outbox_store.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/performance/test_batch_processor.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/performance/test_engine_pragmas.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/providers/test_connection_mixin.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/providers/test_health_monitor.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/providers/test_query_builder_manager.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/providers/test_query_mixin.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/query/__init__.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/query/test_async_builder_identifier_safety.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/query/test_core_mixin_dml.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/query/test_join_aggregate_rendering.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/query/test_predicate_compiler.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/query/test_query_operators.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/query/test_sort_whitelist.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/query/test_sql_build_mixin.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/query/test_sql_query_builder.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/repositories/__init__.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/repositories/test_advanced_mixin.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/repositories/test_filter_mixin.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/repositories/test_filter_objects.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/repositories/test_read_mixin.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/repositories/test_rls_mixin.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/repositories/test_tenant_scoping_read.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/repositories/test_write_mixin_core.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/repositories/test_write_mixin_optimistic.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/repositories/test_write_mixin_tenant_scoping.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/schema/test_descriptors.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/schema/test_field_types.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/stores/test_db_lock_secret_stores.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_api.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_append_log.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_backup_manager.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_backup_models.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_backup_strategy.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_base_provider_pool.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_base_provider_query.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_base_provider_table_exists.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_base_provider_transaction_rollback_logging.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_cached_repository.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_cli_contributor.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_config_quadkit_db.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_connection_lifecycle_regressions.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_connection_pool_base.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_connection_pool_validation.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_crud_json_binding.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_database_maintenance.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_database_monitor_connection_pool.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_database_monitor_facade.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_database_monitor_health.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_database_monitor_health_checker.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_database_monitor_more.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_database_monitor_pool.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_database_monitor_query.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_database_monitor_transactions.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_database_provider.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_database_provider_multi.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_db_constants.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_db_context_propagation.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_db_exceptions.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_db_full_text.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_db_module.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_db_protocols.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_db_query_types.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_db_types.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_domain_mapper.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_domain_mapper_extended.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_domain_mapper_more.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_driver_errors.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_driver_monitoring_integration.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_drivers_smoke.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_exception_hierarchy_scenario.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_exceptions_quadkit_db.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_execute_commit_regression.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_filter_objects.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_generic_repository_counts.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_generic_repository_mapping.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_generic_repository_reads.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_generic_repository_writes.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_identity_map.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_instrumentation_db.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_mappers.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_mappers_base.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_mappers_simple.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_metrics_collector.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_migration_definitions.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_migration_generator.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_migration_generator_extra.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_migration_manager.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_migration_manager_behaviour.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_migration_runner.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_migrations_api.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_migrations_apply_migration.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_migrations_manager.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_migrations_rollback_recording_logs.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_model_analyzer.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_mysql_driver_connection.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_mysql_driver_health.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_mysql_driver_pool.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_mysql_driver_resilience.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_named_database_config.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_package_hooks_p2.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_package_structure_p0.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_package_structure_p1.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_pool.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_postgres_driver_connection.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_postgres_driver_health.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_postgres_driver_pool.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_postgres_driver_resilience.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_protocol_validation.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_provider_connection.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_provider_health_check_error_logs.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_provider_instrumentation_edgecases.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_provider_resilience.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_provider_scoped_cleanup.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_query.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_query_log_single_emission.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_query_logger_backends.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_query_logger_entry_base.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_query_logger_integration.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_query_middleware.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_redis_lock.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_redis_secrets.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_redis_state.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_replica_pool.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_repository_failures.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_repository_hooks.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_repository_reads.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_repository_uuid_params.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_repository_writes.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_request_context_query_logging.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_resilience.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_round41_hardening.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_schema_model.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_scoped_unit_of_work.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_seed_manager.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_simple_connection_pool.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_simple_transaction_manager.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_smoke_sqlalchemy.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_sort_whitelist.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_specification_identifier_safety.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_specification_memory_scenario.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_sql_config.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_sql_constants.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_sql_exceptions.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_sql_hooks_runtime.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_sql_types.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_sqlite_driver_connection.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_sqlite_driver_detailed.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_sqlite_driver_health.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_sqlite_driver_pool.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_sqlite_driver_resilience.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_sqlite_provider.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_sqlite_provider_fixture.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_sqlite_stale_file.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_statement_cache.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_testing.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_threads_teardown.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_transaction_manager_task_isolation.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_unit_of_work_commit.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_unit_of_work_operations.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_uow_base.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/test_uow_lifecycle_hooks.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/unit_of_work/__init__.py +0 -0
- {quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/tests/unit/unit_of_work/test_uow_outbox.py +0 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Generated public-repository ignore rules.
|
|
2
|
+
# Private monorepo paths are intentionally not referenced here.
|
|
3
|
+
|
|
4
|
+
__pycache__/
|
|
5
|
+
*.py[cod]
|
|
6
|
+
*.so
|
|
7
|
+
*.egg-info/
|
|
8
|
+
.venv/
|
|
9
|
+
venv/
|
|
10
|
+
.env
|
|
11
|
+
.env.*
|
|
12
|
+
!.env.example
|
|
13
|
+
.pytest_cache/
|
|
14
|
+
.ruff_cache/
|
|
15
|
+
.mypy_cache/
|
|
16
|
+
.coverage
|
|
17
|
+
coverage.xml
|
|
18
|
+
htmlcov/
|
|
19
|
+
build/
|
|
20
|
+
dist/
|
|
21
|
+
*.log
|
|
22
|
+
.DS_Store
|
|
23
|
+
.idea/
|
|
24
|
+
.vscode/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: quadkit-sql
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.43
|
|
4
4
|
Summary: SQL database abstractions for Quadkit Framework — Postgres, MySQL, SQLite with migrations, repositories, and query building
|
|
5
5
|
Project-URL: Homepage, https://dbtinoy-.github.io/quadkit
|
|
6
6
|
Project-URL: Repository, https://github.com/dbtinoy-/quadkit
|
|
@@ -6,7 +6,7 @@ build-backend = "hatchling.build"
|
|
|
6
6
|
|
|
7
7
|
[project]
|
|
8
8
|
name = "quadkit-sql"
|
|
9
|
-
version = "0.0.
|
|
9
|
+
version = "0.0.43"
|
|
10
10
|
description = "SQL database abstractions for Quadkit Framework — Postgres, MySQL, SQLite with migrations, repositories, and query building"
|
|
11
11
|
readme = "README.md"
|
|
12
12
|
requires-python = ">=3.11"
|
|
@@ -99,9 +99,6 @@ Documentation = "https://dbtinoy-.github.io/quadkit"
|
|
|
99
99
|
Issues = "https://github.com/dbtinoy-/quadkit/issues"
|
|
100
100
|
Changelog = "https://github.com/dbtinoy-/quadkit/blob/main/CHANGELOG.md"
|
|
101
101
|
|
|
102
|
-
[project.entry-points."quadkit.admin.contributors"]
|
|
103
|
-
sql = "quadkit.sql.admin.contributor:SqlAdminContributor"
|
|
104
|
-
|
|
105
102
|
[project.entry-points."quadkit.providers"]
|
|
106
103
|
database = "quadkit.sql.di.provider:DatabaseProvider"
|
|
107
104
|
|
|
@@ -181,9 +178,6 @@ overrides = [
|
|
|
181
178
|
[tool.uv.sources.quadkit]
|
|
182
179
|
workspace = true
|
|
183
180
|
|
|
184
|
-
[tool.uv.sources.quadkit-admin]
|
|
185
|
-
workspace = true
|
|
186
|
-
|
|
187
181
|
[tool.uv.sources.quadkit-testing]
|
|
188
182
|
workspace = true
|
|
189
183
|
|
|
@@ -60,7 +60,7 @@ class SqlAdminAuditLogStore:
|
|
|
60
60
|
session is registered), and it does not commit — commit semantics
|
|
61
61
|
belong to the session owner (e.g. the request pipeline or unit of
|
|
62
62
|
work). For transactional audit entries, defer writes to the UoW's
|
|
63
|
-
commit via :class:`~
|
|
63
|
+
commit via :class:`~the optional provider module`.
|
|
64
64
|
|
|
65
65
|
Usage (opt-in at app level): register a provider that binds
|
|
66
66
|
``AdminAuditLoggerProtocol`` to this store with an injected session,
|
|
@@ -120,7 +120,7 @@ class SeederGenerator(GeneratorBase):
|
|
|
120
120
|
if lowered_type in {"bool", "boolean"}:
|
|
121
121
|
return "True"
|
|
122
122
|
if lowered_type in {"date", "datetime"}:
|
|
123
|
-
return "
|
|
123
|
+
return "clock.now()"
|
|
124
124
|
if lowered_type == "uuid":
|
|
125
125
|
return '"550e8400-e29b-41d4-a716-446655440000"'
|
|
126
126
|
if "json" in lowered_type:
|
|
@@ -156,7 +156,7 @@ def sa_type(field_type: str) -> str:
|
|
|
156
156
|
#: Imports every generated model needs, merged with annotation-driven ones so
|
|
157
157
|
#: the rendered module never repeats a module on two lines.
|
|
158
158
|
BASE_IMPORTS: tuple[tuple[str, tuple[str, ...]], ...] = (
|
|
159
|
-
("datetime", ("datetime",
|
|
159
|
+
("datetime", ("datetime",)),
|
|
160
160
|
("pydantic", ("BaseModel", "ConfigDict", "Field")),
|
|
161
161
|
)
|
|
162
162
|
|
|
@@ -4,8 +4,9 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
from typing import Any
|
|
6
6
|
import uuid as _uuid
|
|
7
|
-
from datetime import datetime
|
|
8
|
-
|
|
7
|
+
{% if needs_datetime %}from datetime import datetime
|
|
8
|
+
{% endif %}
|
|
9
|
+
from quadkit import clock
|
|
9
10
|
from quadkit.contracts import DatabaseProviderProtocol
|
|
10
11
|
|
|
11
12
|
from quadkit.sql.repositories.generic_repository import GenericRepository
|
|
@@ -53,7 +54,7 @@ class {{ repo_name }}Repository:
|
|
|
53
54
|
def _prepare(self, data: dict[str, Any]) -> dict[str, Any]:
|
|
54
55
|
row = dict(data)
|
|
55
56
|
row.setdefault("{{ key_field }}", _uuid.uuid4().hex)
|
|
56
|
-
now =
|
|
57
|
+
now = clock.now().isoformat()
|
|
57
58
|
row.setdefault("created_at", now)
|
|
58
59
|
row["updated_at"] = now
|
|
59
60
|
return row
|
|
@@ -84,7 +85,7 @@ class {{ repo_name }}Repository:
|
|
|
84
85
|
row = {
|
|
85
86
|
**data,
|
|
86
87
|
"{{ key_field }}": key,
|
|
87
|
-
"updated_at":
|
|
88
|
+
"updated_at": clock.now().isoformat(),
|
|
88
89
|
}
|
|
89
90
|
await self._provider.execute_update(
|
|
90
91
|
"{{ table_name }}", row, '"{{ key_field }}" = ?', [key]
|
{quadkit_sql-0.0.42 → quadkit_sql-0.0.43}/src/quadkit/sql/cli/templates/entity_model.py.jinja2
RENAMED
|
@@ -10,6 +10,7 @@ from __future__ import annotations
|
|
|
10
10
|
import uuid
|
|
11
11
|
{% for line in import_lines %}{{ line }}
|
|
12
12
|
{% endfor %}
|
|
13
|
+
from quadkit import clock
|
|
13
14
|
|
|
14
15
|
class {{ entity_name }}(BaseModel):
|
|
15
16
|
"""{{ entity_name }} entity."""
|
|
@@ -17,12 +18,8 @@ class {{ entity_name }}(BaseModel):
|
|
|
17
18
|
model_config = ConfigDict(from_attributes=True)
|
|
18
19
|
|
|
19
20
|
id: str = Field(default_factory=lambda: uuid.uuid4().hex)
|
|
20
|
-
created_at: datetime = Field(
|
|
21
|
-
|
|
22
|
-
)
|
|
23
|
-
updated_at: datetime = Field(
|
|
24
|
-
default_factory=lambda: datetime.now(timezone.utc)
|
|
25
|
-
)
|
|
21
|
+
created_at: datetime = Field(default_factory=clock.now)
|
|
22
|
+
updated_at: datetime = Field(default_factory=clock.now)
|
|
26
23
|
{%- for field in fields %}
|
|
27
24
|
{{ field.name }}: {{ field.py_type }}{% if not field.required %} | None = None{% endif %}
|
|
28
25
|
{%- endfor %}
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
from datetime import datetime, timezone
|
|
6
5
|
from typing import Any
|
|
7
6
|
|
|
7
|
+
from quadkit import clock
|
|
8
8
|
from quadkit.contracts import DatabaseProviderProtocol
|
|
9
9
|
from quadkit.sql import SimpleUnitOfWork
|
|
10
10
|
|
|
@@ -14,8 +14,8 @@ SEED_DATA: list[dict[str, Any]] = [
|
|
|
14
14
|
{%- for field in fields %}
|
|
15
15
|
"{{ field.name }}": {{ field.sample_value }},
|
|
16
16
|
{%- endfor %}
|
|
17
|
-
"created_at":
|
|
18
|
-
"updated_at":
|
|
17
|
+
"created_at": clock.now(),
|
|
18
|
+
"updated_at": clock.now(),
|
|
19
19
|
},
|
|
20
20
|
]
|
|
21
21
|
|
|
@@ -186,8 +186,8 @@ class _DatabaseRegistrationMixin:
|
|
|
186
186
|
|
|
187
187
|
_warn_alembic_missing()
|
|
188
188
|
|
|
189
|
-
# Database-backed search backends have moved to
|
|
190
|
-
# (`
|
|
189
|
+
# Database-backed search backends have moved to the optional provider
|
|
190
|
+
# (`the optional provider module` / `the optional provider module`).
|
|
191
191
|
# SearchProvider is responsible for
|
|
192
192
|
# resolving DatabaseProviderProtocol from the container and registering
|
|
193
193
|
# the appropriate DatabaseSearchBackendProtocol singleton. DatabaseProvider
|
|
@@ -178,7 +178,7 @@ class DatabaseProvider(_DatabaseRegistrationMixin, Provider):
|
|
|
178
178
|
except Exception: # noqa: BLE001 — optional tracing wiring degrades on any resolution failure
|
|
179
179
|
logger.debug("trace_provider_unavailable")
|
|
180
180
|
|
|
181
|
-
# Wire optional resilience pipeline factory (provided by
|
|
181
|
+
# Wire optional resilience pipeline factory (provided by the optional provider).
|
|
182
182
|
resilience = self._db_provider.resilience_handler
|
|
183
183
|
if resilience._pipeline_factory is None:
|
|
184
184
|
from quadkit.contracts.infra.resilience import (
|
|
@@ -56,6 +56,20 @@ except ImportError: # pragma: no cover - availability checked at runtime
|
|
|
56
56
|
ALEMBIC_AVAILABLE = False
|
|
57
57
|
|
|
58
58
|
|
|
59
|
+
def _packaged_alembic_ini() -> Path:
|
|
60
|
+
"""Return the ``alembic.ini`` that sits beside the package source.
|
|
61
|
+
|
|
62
|
+
An installed wheel carries no such file, so callers fall back to a path
|
|
63
|
+
they own when this is absent.
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
Path to the workspace ``alembic.ini`` (which need not exist).
|
|
67
|
+
"""
|
|
68
|
+
# parents[4] lands in src/, where `command.init()` writes a template ini;
|
|
69
|
+
# parents[5] is the package root that ships the real file.
|
|
70
|
+
return Path(__file__).resolve().parents[5] / "alembic.ini"
|
|
71
|
+
|
|
72
|
+
|
|
59
73
|
class AlembicManager:
|
|
60
74
|
"""Alembic migration manager facade for Quadkit DB.
|
|
61
75
|
|
|
@@ -129,14 +143,17 @@ class AlembicManager:
|
|
|
129
143
|
|
|
130
144
|
def _create_alembic_config(self) -> Config:
|
|
131
145
|
"""Create and configure Alembic Config object."""
|
|
132
|
-
# Package root (packages/quadkit-sql/) — parents[4] would land in
|
|
133
|
-
# src/, where `command.init()` then writes a template alembic.ini.
|
|
134
|
-
package_root = Path(__file__).resolve().parents[5]
|
|
135
146
|
config = Config()
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
147
|
+
packaged_ini = _packaged_alembic_ini()
|
|
148
|
+
if packaged_ini.exists():
|
|
149
|
+
config.config_file_name = str(packaged_ini)
|
|
150
|
+
else:
|
|
151
|
+
# Installed wheel: `alembic.ini` lives at the package root, which
|
|
152
|
+
# sits outside the wheel, so there is no packaged ini to reference.
|
|
153
|
+
# `command.init()` asserts on `config_file_name`, so point it at
|
|
154
|
+
# the directory this manager already owns; `init()` writes the
|
|
155
|
+
# generated ini there, and only while that directory is empty.
|
|
156
|
+
config.config_file_name = str(self.migrations_path / "alembic.ini")
|
|
140
157
|
config.set_main_option("script_location", str(self.migrations_path))
|
|
141
158
|
# Strip +aiosqlite/+asyncpg for Alembic which is sync
|
|
142
159
|
self.connection_string = self.database_url
|
|
@@ -147,6 +164,18 @@ class AlembicManager:
|
|
|
147
164
|
|
|
148
165
|
config.set_main_option("sqlalchemy.url", self.connection_string)
|
|
149
166
|
config.set_main_option("version_locations", str(self.script_location))
|
|
167
|
+
# `path_separator` must be set in the same breath as
|
|
168
|
+
# `version_locations`: alembic >= 1.16 deprecates splitting the value
|
|
169
|
+
# without it, and this manager sets `version_locations`
|
|
170
|
+
# programmatically. The packaged `alembic.ini` carries
|
|
171
|
+
# `path_separator = os`, so a *workspace* checkout never saw the
|
|
172
|
+
# warning -- but an *installed* layout resolves without that file and
|
|
173
|
+
# hit the legacy fallback on every boot. Setting it here makes the
|
|
174
|
+
# two layouts behave identically instead of leaving the guarantee to a
|
|
175
|
+
# file that ships only in the repo.
|
|
176
|
+
config.set_main_option("path_separator", "os")
|
|
177
|
+
# User overrides last, so `alembic_config={"path_separator": ":"}`
|
|
178
|
+
# still wins for a project that needs the legacy character.
|
|
150
179
|
for key, value in self.alembic_config.items():
|
|
151
180
|
config.set_main_option(key, str(value))
|
|
152
181
|
return config
|
|
@@ -204,7 +204,7 @@ class DatabaseService(_ConnectionMixin, _QueryMixin, _HealthMixin):
|
|
|
204
204
|
|
|
205
205
|
raise ConfigurationError(
|
|
206
206
|
"MongoDB URLs are not supported by quadkit-sql. "
|
|
207
|
-
"Use
|
|
207
|
+
"Use the optional provider instead: from the optional provider module import NoSQLProvider"
|
|
208
208
|
)
|
|
209
209
|
|
|
210
210
|
from quadkit.sql.lib import infer_provider_type_from_url
|
|
@@ -189,7 +189,7 @@ class SearchQueryBuilder(QueryBuilder):
|
|
|
189
189
|
makes the intent of passing a raw :data:`FilterExpression` explicit
|
|
190
190
|
(rather than letting callers use the more generic :meth:`filter` alias).
|
|
191
191
|
|
|
192
|
-
Search-extension packages (``
|
|
192
|
+
Search-extension packages (``the optional provider``, ``quadkit-sql``) accept
|
|
193
193
|
a :class:`SearchQueryBuilder` or a plain :class:`QueryBuilder` and compile
|
|
194
194
|
the resulting :class:`Query` to backend-specific query syntax via
|
|
195
195
|
``FilterCompilerProtocol``.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""Resilience primitives for database operations.
|
|
2
2
|
|
|
3
3
|
Provides a resilience handler that wraps database operations with circuit
|
|
4
|
-
breaker, retry with backoff, and timeout when ``
|
|
4
|
+
breaker, retry with backoff, and timeout when ``the optional provider`` is
|
|
5
5
|
installed. Falls back to a no-op pass-through when absent.
|
|
6
6
|
"""
|
|
7
7
|
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
"""Database resilience primitives.
|
|
2
2
|
|
|
3
3
|
When a :class:`~quadkit.contracts.resilience.ResiliencePipelineFactory` is
|
|
4
|
-
injected (provided by ``
|
|
4
|
+
injected (provided by ``the optional provider``), builds real circuit-breaker /
|
|
5
5
|
retry pipelines with database-specific defaults. When ``None`` is injected
|
|
6
|
-
(or ``
|
|
6
|
+
(or ``the optional provider`` is not installed), a lightweight no-op pass-through
|
|
7
7
|
is used instead — so ``quadkit-sql`` has **no** hard runtime dependency on the
|
|
8
8
|
resilience extension.
|
|
9
9
|
|
|
10
10
|
Cross-extension communication follows the contracts + DI pattern from
|
|
11
|
-
``AGENTS.md``. ``quadkit-sql`` never imports from ``
|
|
11
|
+
``AGENTS.md``. ``quadkit-sql`` never imports from ``the optional provider``
|
|
12
12
|
directly; it only consumes the :class:`~quadkit.contracts.resilience.ResiliencePipelineFactory`
|
|
13
13
|
protocol resolved through the container.
|
|
14
14
|
"""
|
|
@@ -51,7 +51,7 @@ DB_RETRYABLE_EXCEPTIONS = (
|
|
|
51
51
|
|
|
52
52
|
|
|
53
53
|
class _NoOpPipeline:
|
|
54
|
-
"""Pass-through pipeline used when
|
|
54
|
+
"""Pass-through pipeline used when the optional provider is not installed."""
|
|
55
55
|
|
|
56
56
|
async def execute(
|
|
57
57
|
self, func: Callable[..., Awaitable[T]], *args: Any, **kwargs: Any
|
|
@@ -67,7 +67,7 @@ class DatabaseResilienceHandler:
|
|
|
67
67
|
injected by the DI container. When a factory is present it builds real
|
|
68
68
|
circuit-breaker / retry pipelines with database-specific defaults. When
|
|
69
69
|
``None`` is passed a lightweight no-op pipeline is used, so ``quadkit-sql``
|
|
70
|
-
has no hard runtime dependency on ``
|
|
70
|
+
has no hard runtime dependency on ``the optional provider``.
|
|
71
71
|
"""
|
|
72
72
|
|
|
73
73
|
def __init__(
|
|
@@ -77,7 +77,7 @@ class DatabaseResilienceHandler:
|
|
|
77
77
|
"""Initialise the resilience handler.
|
|
78
78
|
|
|
79
79
|
Args:
|
|
80
|
-
pipeline_factory: Optional factory provided by ``
|
|
80
|
+
pipeline_factory: Optional factory provided by ``the optional provider``
|
|
81
81
|
via the DI container. Pass ``None`` for no-op behaviour.
|
|
82
82
|
"""
|
|
83
83
|
self._pipeline_factory = pipeline_factory
|
|
@@ -194,7 +194,7 @@ async def retry_call(
|
|
|
194
194
|
The return value of *func* on a successful attempt.
|
|
195
195
|
|
|
196
196
|
Raises:
|
|
197
|
-
:class:`~
|
|
197
|
+
:class:`~the optional provider module`: When all
|
|
198
198
|
attempts are exhausted.
|
|
199
199
|
Any exception raised by *func* that is not in ``config.retry_on``.
|
|
200
200
|
"""
|
|
@@ -14,17 +14,17 @@ BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
|
14
14
|
|
|
15
15
|
# ensure local packages are importable when running tests directly
|
|
16
16
|
# this mirrors the similar logic in other quadkit packages and is
|
|
17
|
-
# intentionally simple so that pytest can find `quadkit.sql
|
|
18
|
-
# `quadkit.contracts`
|
|
19
|
-
#
|
|
17
|
+
# intentionally simple so that pytest can find `quadkit.sql` and
|
|
18
|
+
# `quadkit.contracts` even though they live outside the tests
|
|
19
|
+
# directory during development.
|
|
20
20
|
PROJECT_ROOT = os.path.abspath(os.path.join(BASE_DIR, ".."))
|
|
21
21
|
sys.path.insert(0, os.path.join(PROJECT_ROOT, "src"))
|
|
22
22
|
sys.path.insert(0, os.path.join(PROJECT_ROOT, "..", "quadkit-contracts", "src"))
|
|
23
23
|
|
|
24
24
|
# Import TestEnvironment lazily inside the fixture to avoid importing
|
|
25
25
|
# optional test utilities (e.g., admin mocks) at module import time which
|
|
26
|
-
# may pull in optional packages
|
|
27
|
-
#
|
|
26
|
+
# may pull in optional packages that are not available in all test
|
|
27
|
+
# environments.
|
|
28
28
|
|
|
29
29
|
# The fixtures the test suite expects (clean_database, seeded_database, etc.)
|
|
30
30
|
# are provided by quadkit.testing.fixtures.db; import them lazily below in
|
|
@@ -87,7 +87,7 @@ async def test_bed():
|
|
|
87
87
|
|
|
88
88
|
Importing `TestEnvironment` lazily ensures we don't try to import heavy
|
|
89
89
|
admin/testing modules at collection time (which can pull optional
|
|
90
|
-
dependencies
|
|
90
|
+
dependencies that are not installed). If `quadkit.testing` isn't
|
|
91
91
|
available in this environment, skip the dependent tests gracefully.
|
|
92
92
|
"""
|
|
93
93
|
try:
|
|
@@ -230,6 +230,20 @@ class TestAlembicManager:
|
|
|
230
230
|
assert "issues" in result
|
|
231
231
|
assert isinstance(result["issues"], list)
|
|
232
232
|
|
|
233
|
+
def test_config_names_the_migrations_dir_without_a_packaged_ini(
|
|
234
|
+
self, connection_string, temp_dir, monkeypatch
|
|
235
|
+
):
|
|
236
|
+
"""An installed wheel ships no `alembic.ini`, so the config names the
|
|
237
|
+
directory the manager owns instead of leaving the name unset."""
|
|
238
|
+
from quadkit.sql.migrations.manager import _alembic
|
|
239
|
+
|
|
240
|
+
monkeypatch.setattr(
|
|
241
|
+
_alembic, "_packaged_alembic_ini", lambda: temp_dir / "alembic.ini"
|
|
242
|
+
)
|
|
243
|
+
manager = AlembicManager(connection_string, temp_dir)
|
|
244
|
+
|
|
245
|
+
assert manager.config.config_file_name == str(temp_dir / "alembic.ini")
|
|
246
|
+
|
|
233
247
|
|
|
234
248
|
@pytest.mark.skipif(not ALEMBIC_AVAILABLE, reason="Alembic is not installed")
|
|
235
249
|
class TestMigrationUtilities:
|
|
@@ -2,8 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import importlib.util
|
|
5
6
|
from unittest.mock import AsyncMock, patch
|
|
6
7
|
|
|
8
|
+
import pytest
|
|
9
|
+
|
|
7
10
|
from quadkit.contracts.core import HealthCheckResult, HealthStatus
|
|
8
11
|
from quadkit.sql.backends.cockroachdb import (
|
|
9
12
|
CockroachDBConnection,
|
|
@@ -11,7 +14,12 @@ from quadkit.sql.backends.cockroachdb import (
|
|
|
11
14
|
)
|
|
12
15
|
from quadkit.sql.backends.postgres import PostgresConnectionPool
|
|
13
16
|
|
|
17
|
+
requires_asyncpg = pytest.mark.skipif(
|
|
18
|
+
importlib.util.find_spec("asyncpg") is None, reason="asyncpg is not installed"
|
|
19
|
+
)
|
|
20
|
+
|
|
14
21
|
|
|
22
|
+
@requires_asyncpg
|
|
15
23
|
class TestDefaults:
|
|
16
24
|
def test_constructor_defaults(self) -> None:
|
|
17
25
|
conn = CockroachDBConnection()
|
|
@@ -45,6 +53,7 @@ class TestDsnNormalisation:
|
|
|
45
53
|
assert CockroachDBConnection._normalize_dsn(dsn) == dsn # noqa: SLF001
|
|
46
54
|
|
|
47
55
|
|
|
56
|
+
@requires_asyncpg
|
|
48
57
|
class TestCreatePool:
|
|
49
58
|
async def test_server_settings_injected(self) -> None:
|
|
50
59
|
captured: dict[str, object] = {}
|
|
@@ -91,6 +100,7 @@ class TestCreatePool:
|
|
|
91
100
|
assert captured["server_settings"]["application_name"] == "quadkit-cockroachdb"
|
|
92
101
|
|
|
93
102
|
|
|
103
|
+
@requires_asyncpg
|
|
94
104
|
class TestHealthCheckComponent:
|
|
95
105
|
async def test_component_replaced(self) -> None:
|
|
96
106
|
conn = CockroachDBConnection()
|
|
@@ -115,6 +125,7 @@ class TestHealthCheckComponent:
|
|
|
115
125
|
assert fake_result.component == "database"
|
|
116
126
|
|
|
117
127
|
|
|
128
|
+
@requires_asyncpg
|
|
118
129
|
class TestFactory:
|
|
119
130
|
def test_defaults_without_dsn(self) -> None:
|
|
120
131
|
pool = create_cockroachdb_pool()
|
|
@@ -97,11 +97,13 @@ class TestExecute:
|
|
|
97
97
|
await pc.execute("BROKEN")
|
|
98
98
|
|
|
99
99
|
async def test_generic_error_becomes_connection_error(self) -> None:
|
|
100
|
+
pytest.importorskip("asyncpg")
|
|
100
101
|
pc, _ = _conn_results({("execute", "X"): OSError("socket gone")})
|
|
101
102
|
with pytest.raises(DatabaseConnectionError, match="Connection error"):
|
|
102
103
|
await pc.execute("X")
|
|
103
104
|
|
|
104
105
|
async def test_timeout_maps_to_connection_error(self) -> None:
|
|
106
|
+
pytest.importorskip("asyncpg")
|
|
105
107
|
pc, _ = _conn_results({("execute", "X"): DatabaseTimeoutError("slow")})
|
|
106
108
|
with pytest.raises(DatabaseConnectionError, match="Connection error"):
|
|
107
109
|
await pc.execute("X")
|
|
@@ -127,6 +129,7 @@ class TestFetchOne:
|
|
|
127
129
|
await pc.fetch_one("B")
|
|
128
130
|
|
|
129
131
|
async def test_generic_error_becomes_query_error(self) -> None:
|
|
132
|
+
pytest.importorskip("asyncpg")
|
|
130
133
|
pc, _ = _conn_results({("fetchrow", "B"): OSError("down")})
|
|
131
134
|
with pytest.raises(QueryError, match="Unexpected Postgres error"):
|
|
132
135
|
await pc.fetch_one("B")
|
|
@@ -82,7 +82,7 @@ def test_unknown_type_falls_back_to_str(tmp_path: Path) -> None:
|
|
|
82
82
|
def test_required_imports_are_emitted_and_merged(tmp_path: Path) -> None:
|
|
83
83
|
"""Constrained annotations bring their imports, each module once."""
|
|
84
84
|
source = _render(tmp_path, "day:date,at:time,meta:json,email:email,site:url")
|
|
85
|
-
assert "from datetime import date, datetime, time
|
|
85
|
+
assert "from datetime import date, datetime, time" in source
|
|
86
86
|
assert "from typing import Any" in source
|
|
87
87
|
assert "from pydantic import AnyHttpUrl, BaseModel, ConfigDict, EmailStr, Field" in (
|
|
88
88
|
source
|
|
@@ -44,7 +44,7 @@ def test_render_imports_merges_base_and_annotation_imports() -> None:
|
|
|
44
44
|
"""Base imports are always present and each module appears once."""
|
|
45
45
|
lines = render_imports(["date", "time", "dict[str, Any]", "EmailStr"])
|
|
46
46
|
|
|
47
|
-
assert "from datetime import date, datetime, time
|
|
47
|
+
assert "from datetime import date, datetime, time" in lines
|
|
48
48
|
assert "from pydantic import AnyHttpUrl" not in lines
|
|
49
49
|
assert "from pydantic import BaseModel, ConfigDict, EmailStr, Field" in lines
|
|
50
50
|
assert "from typing import Any" in lines
|
|
@@ -54,7 +54,7 @@ def test_render_imports_merges_base_and_annotation_imports() -> None:
|
|
|
54
54
|
def test_render_imports_without_annotations() -> None:
|
|
55
55
|
"""A plain entity needs only the base imports."""
|
|
56
56
|
assert render_imports([]) == [
|
|
57
|
-
"from datetime import datetime
|
|
57
|
+
"from datetime import datetime",
|
|
58
58
|
"from pydantic import BaseModel, ConfigDict, Field",
|
|
59
59
|
]
|
|
60
60
|
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"""`AlembicManager` builds a config alembic does not deprecate.
|
|
2
|
+
|
|
3
|
+
These tests use the **real** ``alembic.config.Config`` on purpose.
|
|
4
|
+
``tests/unit/test_migrations_manager.py`` patches ``Config`` out, so it can
|
|
5
|
+
assert which options the manager *asks* for but never what alembic *does*
|
|
6
|
+
with them -- which is why the regression below survived there.
|
|
7
|
+
|
|
8
|
+
The regression: the manager sets ``version_locations`` programmatically, and
|
|
9
|
+
alembic >= 1.16 deprecates splitting that value unless ``path_separator`` is
|
|
10
|
+
also set. A workspace checkout hid it, because ``_create_alembic_config``
|
|
11
|
+
finds the packaged ``alembic.ini`` (which carries ``path_separator = os``)
|
|
12
|
+
and sets ``config_file_name``. An installed layout -- the wheel a generated
|
|
13
|
+
project resolves from PyPI -- has no packaged ini, so every boot fell back to
|
|
14
|
+
legacy splitting and emitted the deprecation.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
import pathlib
|
|
20
|
+
import warnings
|
|
21
|
+
|
|
22
|
+
from alembic.script import ScriptDirectory
|
|
23
|
+
import pytest
|
|
24
|
+
|
|
25
|
+
from quadkit.sql.migrations.manager import AlembicManager
|
|
26
|
+
from quadkit.sql.migrations.manager._alembic import _packaged_alembic_ini
|
|
27
|
+
|
|
28
|
+
_DEPRECATION = "path_separator"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@pytest.fixture
|
|
32
|
+
def migrations_dir(tmp_path: pathlib.Path) -> pathlib.Path:
|
|
33
|
+
"""A directory shaped enough for ``ScriptDirectory`` to load it."""
|
|
34
|
+
root = tmp_path / "migrations"
|
|
35
|
+
(root / "versions").mkdir(parents=True)
|
|
36
|
+
(root / "env.py").write_text("")
|
|
37
|
+
(root / "script.py.mako").write_text("")
|
|
38
|
+
return root
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@pytest.fixture
|
|
42
|
+
def installed_layout(monkeypatch: pytest.MonkeyPatch):
|
|
43
|
+
"""Hide the packaged ``alembic.ini``, as an installed wheel does.
|
|
44
|
+
|
|
45
|
+
Only that filename is hidden; every other path answers normally, so the
|
|
46
|
+
manager still finds the migrations directory under ``tmp_path``.
|
|
47
|
+
"""
|
|
48
|
+
real_exists = pathlib.Path.exists
|
|
49
|
+
|
|
50
|
+
def fake_exists(self: pathlib.Path) -> bool:
|
|
51
|
+
if self.name == "alembic.ini":
|
|
52
|
+
return False
|
|
53
|
+
return real_exists(self)
|
|
54
|
+
|
|
55
|
+
monkeypatch.setattr(pathlib.Path, "exists", fake_exists)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def test_installed_layout_emits_no_path_separator_deprecation(
|
|
59
|
+
migrations_dir: pathlib.Path, installed_layout: None
|
|
60
|
+
) -> None:
|
|
61
|
+
"""The case a generated project actually runs: no packaged ini."""
|
|
62
|
+
assert not _packaged_alembic_ini().exists(), (
|
|
63
|
+
"fixture did not hide the packaged ini; the test would pass vacuously"
|
|
64
|
+
)
|
|
65
|
+
manager = AlembicManager("sqlite:///x.db", migrations_path=str(migrations_dir))
|
|
66
|
+
|
|
67
|
+
with warnings.catch_warnings(record=True) as caught:
|
|
68
|
+
warnings.simplefilter("always")
|
|
69
|
+
ScriptDirectory.from_config(manager.config)
|
|
70
|
+
|
|
71
|
+
offenders = [str(w.message) for w in caught if _DEPRECATION in str(w.message)]
|
|
72
|
+
assert not offenders, f"alembic still deprecates the config: {offenders}"
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def test_version_locations_still_resolves_in_both_layouts(
|
|
76
|
+
migrations_dir: pathlib.Path,
|
|
77
|
+
) -> None:
|
|
78
|
+
"""``path_separator`` must not cost us the value it governs.
|
|
79
|
+
|
|
80
|
+
Guards the near-miss this fix had: setting the separator while dropping
|
|
81
|
+
``version_locations`` leaves alembic with *no* version path at all, and
|
|
82
|
+
the deprecation assertion above would still pass -- silently, because
|
|
83
|
+
there is then nothing to split.
|
|
84
|
+
"""
|
|
85
|
+
manager = AlembicManager("sqlite:///x.db", migrations_path=str(migrations_dir))
|
|
86
|
+
script = ScriptDirectory.from_config(manager.config)
|
|
87
|
+
|
|
88
|
+
assert script.version_locations == (str(migrations_dir / "versions"),) or list(
|
|
89
|
+
script.version_locations
|
|
90
|
+
) == [str(migrations_dir / "versions")]
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def test_path_separator_defaults_to_os(migrations_dir: pathlib.Path) -> None:
|
|
94
|
+
manager = AlembicManager("sqlite:///x.db", migrations_path=str(migrations_dir))
|
|
95
|
+
assert manager.config.get_main_option("path_separator") == "os"
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def test_explicit_alembic_config_overrides_the_default(
|
|
99
|
+
migrations_dir: pathlib.Path,
|
|
100
|
+
) -> None:
|
|
101
|
+
"""The default is a floor, not a ceiling -- callers keep the last word."""
|
|
102
|
+
manager = AlembicManager(
|
|
103
|
+
"sqlite:///x.db",
|
|
104
|
+
migrations_path=str(migrations_dir),
|
|
105
|
+
alembic_config={"path_separator": ":"},
|
|
106
|
+
)
|
|
107
|
+
assert manager.config.get_main_option("path_separator") == ":"
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"""Scenario coverage for the MySQL backend with an injected fake driver.
|
|
2
2
|
|
|
3
|
-
The
|
|
4
|
-
pool/connection logic is exercised against an in-memory
|
|
5
|
-
(injected into the module-level ``aiomysql`` references) so no
|
|
6
|
-
server is required. Covers pool creation (success, failure, retry
|
|
3
|
+
The optional ``aiomysql`` driver is imported when present (the module skips
|
|
4
|
+
otherwise), and the pool/connection logic is exercised against an in-memory
|
|
5
|
+
fake client (injected into the module-level ``aiomysql`` references) so no
|
|
6
|
+
database server is required. Covers pool creation (success, failure, retry
|
|
7
7
|
exhaustion), connection acquisition (plain + circuit breaker), health
|
|
8
8
|
checks (healthy/cached/unhealthy paths), statistics, shutdown, and the
|
|
9
9
|
``MySQLConnection`` query surface with error mapping and monitoring.
|
|
@@ -15,9 +15,12 @@ import asyncio
|
|
|
15
15
|
from contextlib import asynccontextmanager
|
|
16
16
|
from typing import Any, Self
|
|
17
17
|
|
|
18
|
-
import aiomysql
|
|
19
18
|
import pytest
|
|
20
19
|
|
|
20
|
+
pytest.importorskip("aiomysql")
|
|
21
|
+
|
|
22
|
+
import aiomysql
|
|
23
|
+
|
|
21
24
|
from quadkit.contracts.core import HealthStatus
|
|
22
25
|
from quadkit.contracts.exceptions.resilience import RetryExhaustedError
|
|
23
26
|
from quadkit.contracts.infra.resilience import RetryConfig
|
|
@@ -286,6 +286,7 @@ class TestHealthCheckerNeverRaises:
|
|
|
286
286
|
class TestPostgresAutoCreate:
|
|
287
287
|
@pytest.mark.asyncio
|
|
288
288
|
async def test_autocreate_driver_error_wrapped(self, monkeypatch: pytest.MonkeyPatch) -> None:
|
|
289
|
+
pytest.importorskip("asyncpg")
|
|
289
290
|
import asyncpg
|
|
290
291
|
|
|
291
292
|
from quadkit.sql.providers.postgres_provider import PostgresProvider
|