quadkit-sql 0.0.44__tar.gz → 0.0.46__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.
Files changed (444) hide show
  1. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/PKG-INFO +6 -6
  2. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/README.md +1 -1
  3. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/pyproject.toml +5 -5
  4. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/__init__.py +2 -0
  5. quadkit_sql-0.0.46/src/quadkit/sql/admin/registration.py +84 -0
  6. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/cli/generators/database_repository.py +12 -0
  7. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/cli/generators/service.py +28 -0
  8. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/cli/templates/database_repository.py.jinja2 +50 -18
  9. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/cli/templates/entity_migration.py.jinja2 +3 -0
  10. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/cli/templates/entity_model.py.jinja2 +5 -1
  11. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/cli/templates/health_check.py.jinja2 +6 -1
  12. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/cli/templates/seeder.py.jinja2 +6 -1
  13. quadkit_sql-0.0.46/src/quadkit/sql/cli/templates/service.py.jinja2 +159 -0
  14. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/di/_registration.py +56 -0
  15. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/di/provider.py +29 -22
  16. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/migrations/introspector.py +23 -3
  17. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/migrations/runner.py +31 -8
  18. quadkit_sql-0.0.46/src/quadkit/sql/orm/__init__.py +14 -0
  19. quadkit_sql-0.0.46/src/quadkit/sql/orm/executor.py +98 -0
  20. quadkit_sql-0.0.46/src/quadkit/sql/orm/session.py +180 -0
  21. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/outbox/publisher.py +70 -5
  22. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/outbox/store.py +17 -1
  23. quadkit_sql-0.0.46/src/quadkit/sql/pool/engine.py +321 -0
  24. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/providers/base_provider.py +0 -14
  25. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/providers/crud_operations.py +9 -11
  26. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/cli/test_repository_generator_staged.py +38 -0
  27. quadkit_sql-0.0.46/tests/unit/cli/test_service_generator.py +116 -0
  28. quadkit_sql-0.0.46/tests/unit/migrations/test_pending_on_unstamped_database.py +126 -0
  29. quadkit_sql-0.0.46/tests/unit/outbox/test_outbox_transactional_relay.py +165 -0
  30. quadkit_sql-0.0.46/tests/unit/test_engine_pool.py +148 -0
  31. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_generic_repository_mapping.py +33 -6
  32. quadkit_sql-0.0.46/tests/unit/test_orm_session_factory.py +156 -0
  33. quadkit_sql-0.0.44/src/quadkit/sql/cli/templates/service.py.jinja2 +0 -104
  34. quadkit_sql-0.0.44/tests/unit/cli/test_service_generator.py +0 -29
  35. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/.gitignore +0 -0
  36. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/LICENSE +0 -0
  37. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/NOTICE +0 -0
  38. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/alembic.ini +0 -0
  39. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/example.yaml +0 -0
  40. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/py.typed +0 -0
  41. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/abstractions/__init__.py +0 -0
  42. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/abstractions/connection.py +0 -0
  43. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/abstractions/py.typed +0 -0
  44. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/admin/__init__.py +0 -0
  45. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/admin/audit_store.py +0 -0
  46. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/admin/contributor.py +0 -0
  47. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/admin/handlers/__init__.py +0 -0
  48. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/admin/handlers/migration_status.py +0 -0
  49. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/admin/handlers/pool_utilization.py +0 -0
  50. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/admin/handlers/query_stats.py +0 -0
  51. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/admin/pages/__init__.py +0 -0
  52. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/admin/pages/migrations.py +0 -0
  53. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/admin/pages/overview.py +0 -0
  54. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/admin/pages/queries.py +0 -0
  55. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/admin/widgets/__init__.py +0 -0
  56. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/api/__init__.py +0 -0
  57. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/api/engine.py +0 -0
  58. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/api/protocols.py +0 -0
  59. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/audit/__init__.py +0 -0
  60. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/audit/mixin.py +0 -0
  61. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/audit/py.typed +0 -0
  62. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/backends/__init__.py +0 -0
  63. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/backends/_postgres_connection.py +0 -0
  64. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/backends/_ssl.py +0 -0
  65. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/backends/cockroachdb.py +0 -0
  66. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/backends/mysql/__init__.py +0 -0
  67. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/backends/mysql/_connection.py +0 -0
  68. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/backends/mysql/_pool.py +0 -0
  69. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/backends/mysql/_shims.py +0 -0
  70. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/backends/postgres.py +0 -0
  71. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/backends/py.typed +0 -0
  72. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/backends/sqlite/__init__.py +0 -0
  73. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/backends/sqlite/_connection.py +0 -0
  74. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/backends/sqlite/_pool.py +0 -0
  75. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/backends/sqlite/_shims.py +0 -0
  76. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/backup/__init__.py +0 -0
  77. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/backup/backup_manager.py +0 -0
  78. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/backup/maintenance.py +0 -0
  79. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/backup/py.typed +0 -0
  80. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/cli/__init__.py +0 -0
  81. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/cli/checks.py +0 -0
  82. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/cli/commands.py +0 -0
  83. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/cli/contributor.py +0 -0
  84. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/cli/doctor.py +0 -0
  85. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/cli/generators/__init__.py +0 -0
  86. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/cli/generators/base.py +0 -0
  87. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/cli/generators/entity_migration.py +0 -0
  88. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/cli/generators/entity_model.py +0 -0
  89. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/cli/generators/filter.py +0 -0
  90. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/cli/generators/health_check.py +0 -0
  91. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/cli/generators/seeder.py +0 -0
  92. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/cli/generators/type_map.py +0 -0
  93. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/cli/manager.py +0 -0
  94. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/cli/shell.py +0 -0
  95. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/cli/templates/filter.py.jinja2 +0 -0
  96. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/config.py +0 -0
  97. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/constants.py +0 -0
  98. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/context/__init__.py +0 -0
  99. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/context/db_context.py +0 -0
  100. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/context/keys.py +0 -0
  101. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/context/manager.py +0 -0
  102. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/context/tasks.py +0 -0
  103. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/decorators.py +0 -0
  104. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/di/__init__.py +0 -0
  105. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/di/py.typed +0 -0
  106. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/events.py +0 -0
  107. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/exceptions.py +0 -0
  108. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/hooks.py +0 -0
  109. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/identifiers.py +0 -0
  110. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/lib/__init__.py +0 -0
  111. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/lib/helpers.py +0 -0
  112. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/lib/retry.py +0 -0
  113. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/logging/__init__.py +0 -0
  114. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/logging/loggers.py +0 -0
  115. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/managers/__init__.py +0 -0
  116. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/managers/manager.py +0 -0
  117. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/mappers/__init__.py +0 -0
  118. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/mappers/base.py +0 -0
  119. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/mappers/domain_mapper.py +0 -0
  120. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/mappers/py.typed +0 -0
  121. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/middleware/__init__.py +0 -0
  122. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/middleware/base.py +0 -0
  123. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/middleware/builtins.py +0 -0
  124. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/middleware/models.py +0 -0
  125. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/middleware/pipeline.py +0 -0
  126. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/migrations/__init__.py +0 -0
  127. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/migrations/api.py +0 -0
  128. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/migrations/base.py +0 -0
  129. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/migrations/engine.py +0 -0
  130. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/migrations/generator.py +0 -0
  131. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/migrations/manager/__init__.py +0 -0
  132. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/migrations/manager/_alembic.py +0 -0
  133. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/migrations/manager/_simple.py +0 -0
  134. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/migrations/model_analyzer.py +0 -0
  135. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/migrations/orchestrator.py +0 -0
  136. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/migrations/py.typed +0 -0
  137. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/migrations/types.py +0 -0
  138. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/module.py +0 -0
  139. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/monitoring/__init__.py +0 -0
  140. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/monitoring/database_monitor/__init__.py +0 -0
  141. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/monitoring/database_monitor/facade.py +0 -0
  142. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/monitoring/database_monitor/health.py +0 -0
  143. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/monitoring/database_monitor/pool.py +0 -0
  144. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/monitoring/database_monitor/query.py +0 -0
  145. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/monitoring/database_monitor/transaction.py +0 -0
  146. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/monitoring/metrics.py +0 -0
  147. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/monitoring/py.typed +0 -0
  148. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/monitoring/query_analyzer.py +0 -0
  149. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/orm.pyi +0 -0
  150. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/outbox/__init__.py +0 -0
  151. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/pagination/__init__.py +0 -0
  152. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/pagination/cursor.py +0 -0
  153. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/pagination/offset.py +0 -0
  154. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/performance/__init__.py +0 -0
  155. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/performance/batch_processor.py +0 -0
  156. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/performance/engine_pragmas.py +0 -0
  157. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/performance/statement_cache.py +0 -0
  158. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/pool/__init__.py +0 -0
  159. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/pool/connection.py +0 -0
  160. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/pool/py.typed +0 -0
  161. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/pool/replica.py +0 -0
  162. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/protocols.py +0 -0
  163. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/providers/__init__.py +0 -0
  164. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/providers/_connection_mixin.py +0 -0
  165. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/providers/_health_mixin.py +0 -0
  166. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/providers/_lazy.py +0 -0
  167. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/providers/_query_mixin.py +0 -0
  168. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/providers/connection_manager.py +0 -0
  169. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/providers/database_service.py +0 -0
  170. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/providers/health_monitor.py +0 -0
  171. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/providers/mysql_provider.py +0 -0
  172. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/providers/postgres_provider.py +0 -0
  173. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/providers/py.typed +0 -0
  174. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/providers/query_builder_manager.py +0 -0
  175. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/providers/query_executor.py +0 -0
  176. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/providers/schema_manager.py +0 -0
  177. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/providers/sqlite_provider.py +0 -0
  178. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/providers/transaction_manager.py +0 -0
  179. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/py.typed +0 -0
  180. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/query/__init__.py +0 -0
  181. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/query/_sql_build_mixin.py +0 -0
  182. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/query/_sql_core_mixin.py +0 -0
  183. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/query/_sql_join_aggregate_mixin.py +0 -0
  184. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/query/_sql_where_mixin.py +0 -0
  185. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/query/admin_builder.py +0 -0
  186. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/query/builder.py +0 -0
  187. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/query/compiler.py +0 -0
  188. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/query/cursor.py +0 -0
  189. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/query/operators.py +0 -0
  190. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/query/sql_builder.py +0 -0
  191. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/query/sql_types.py +0 -0
  192. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/repositories/__init__.py +0 -0
  193. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/repositories/_advanced_mixin.py +0 -0
  194. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/repositories/_filter_mixin.py +0 -0
  195. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/repositories/_read_mixin.py +0 -0
  196. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/repositories/_rls_mixin.py +0 -0
  197. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/repositories/_write_mixin.py +0 -0
  198. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/repositories/append_log.py +0 -0
  199. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/repositories/base.py +0 -0
  200. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/repositories/cached.py +0 -0
  201. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/repositories/cursor.py +0 -0
  202. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/repositories/decorators.py +0 -0
  203. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/repositories/filter_objects.py +0 -0
  204. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/repositories/filters.py +0 -0
  205. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/repositories/generic_repository.py +0 -0
  206. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/repositories/py.typed +0 -0
  207. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/repositories/scopes.py +0 -0
  208. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/resilience/__init__.py +0 -0
  209. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/resilience/core.py +0 -0
  210. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/row_level_security.py +0 -0
  211. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/schema/__init__.py +0 -0
  212. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/schema/descriptors.py +0 -0
  213. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/schema/field_types.py +0 -0
  214. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/schema/hooks.py +0 -0
  215. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/schema/model.py +0 -0
  216. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/search/__init__.py +0 -0
  217. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/search/full_text.py +0 -0
  218. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/seeds/__init__.py +0 -0
  219. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/seeds/api.py +0 -0
  220. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/seeds/factory.py +0 -0
  221. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/seeds/manager.py +0 -0
  222. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/seeds/py.typed +0 -0
  223. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/specification/__init__.py +0 -0
  224. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/specification/memory.py +0 -0
  225. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/specification/sql.py +0 -0
  226. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/storage/__init__.py +0 -0
  227. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/storage/postgres.py +0 -0
  228. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/stores/__init__.py +0 -0
  229. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/stores/locks.py +0 -0
  230. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/stores/secrets.py +0 -0
  231. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/stores/state.py +0 -0
  232. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/types.py +0 -0
  233. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/unit_of_work/__init__.py +0 -0
  234. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/unit_of_work/base.py +0 -0
  235. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/unit_of_work/decorators.py +0 -0
  236. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/unit_of_work/identity_map.py +0 -0
  237. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/unit_of_work/manager.py +0 -0
  238. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/unit_of_work/py.typed +0 -0
  239. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/unit_of_work/simple/__init__.py +0 -0
  240. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/unit_of_work/simple/_operations.py +0 -0
  241. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/unit_of_work/simple/_uow.py +0 -0
  242. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/validation/__init__.py +0 -0
  243. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/validation/protocols.py +0 -0
  244. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/src/quadkit/sql/validation/py.typed +0 -0
  245. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/conftest.py +0 -0
  246. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/fixtures/test.db +0 -0
  247. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/integration/test_add_previous_passwords_migration.py +0 -0
  248. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/integration/test_apply_previous_passwords_migration.py +0 -0
  249. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/integration/test_migrations.py +0 -0
  250. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/integration/test_monitoring_metrics.py +0 -0
  251. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/integration/test_monitoring_slow_query.py +0 -0
  252. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/integration/test_postgres_provider_lifecycle.py +0 -0
  253. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/integration/test_postgres_repository_compliance.py +0 -0
  254. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/integration/test_provider_resilience_integration.py +0 -0
  255. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/integration/test_sqlite_provider_integration.py +0 -0
  256. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/admin/__init__.py +0 -0
  257. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/admin/handlers/__init__.py +0 -0
  258. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/admin/handlers/test_migration_status.py +0 -0
  259. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/admin/handlers/test_pool_utilization.py +0 -0
  260. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/admin/handlers/test_query_stats.py +0 -0
  261. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/admin/test_audit_store.py +0 -0
  262. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/admin/test_queries_page.py +0 -0
  263. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/admin/test_sql_contributor.py +0 -0
  264. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/audit/test_audit_repository_mixin.py +0 -0
  265. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/backends/test_cockroachdb_backend.py +0 -0
  266. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/backends/test_postgres_connection.py +0 -0
  267. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/cli/__init__.py +0 -0
  268. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/cli/test_entity_migration_generator.py +0 -0
  269. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/cli/test_entity_model_generator.py +0 -0
  270. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/cli/test_generators_contract.py +0 -0
  271. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/cli/test_health_generator.py +0 -0
  272. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/cli/test_type_map.py +0 -0
  273. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/context/test_db_context.py +0 -0
  274. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/di/test_config_alignment.py +0 -0
  275. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/migrations/test_alembic_config_path_separator.py +0 -0
  276. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/migrations/test_migration_model_analyzer.py +0 -0
  277. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/migrations/test_simple_migration_manager.py +0 -0
  278. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/outbox/__init__.py +0 -0
  279. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/outbox/test_outbox_publisher.py +0 -0
  280. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/outbox/test_outbox_store.py +0 -0
  281. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/performance/test_batch_processor.py +0 -0
  282. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/performance/test_engine_pragmas.py +0 -0
  283. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/providers/test_connection_mixin.py +0 -0
  284. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/providers/test_health_monitor.py +0 -0
  285. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/providers/test_query_builder_manager.py +0 -0
  286. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/providers/test_query_mixin.py +0 -0
  287. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/query/__init__.py +0 -0
  288. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/query/test_async_builder_identifier_safety.py +0 -0
  289. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/query/test_core_mixin_dml.py +0 -0
  290. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/query/test_join_aggregate_rendering.py +0 -0
  291. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/query/test_predicate_compiler.py +0 -0
  292. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/query/test_query_operators.py +0 -0
  293. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/query/test_sort_whitelist.py +0 -0
  294. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/query/test_sql_build_mixin.py +0 -0
  295. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/query/test_sql_query_builder.py +0 -0
  296. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/repositories/__init__.py +0 -0
  297. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/repositories/test_advanced_mixin.py +0 -0
  298. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/repositories/test_filter_mixin.py +0 -0
  299. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/repositories/test_filter_objects.py +0 -0
  300. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/repositories/test_read_mixin.py +0 -0
  301. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/repositories/test_rls_mixin.py +0 -0
  302. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/repositories/test_tenant_scoping_read.py +0 -0
  303. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/repositories/test_write_mixin_core.py +0 -0
  304. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/repositories/test_write_mixin_optimistic.py +0 -0
  305. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/repositories/test_write_mixin_tenant_scoping.py +0 -0
  306. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/schema/test_descriptors.py +0 -0
  307. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/schema/test_field_types.py +0 -0
  308. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/stores/test_db_lock_secret_stores.py +0 -0
  309. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_api.py +0 -0
  310. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_append_log.py +0 -0
  311. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_backup_manager.py +0 -0
  312. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_backup_models.py +0 -0
  313. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_backup_strategy.py +0 -0
  314. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_base_provider_pool.py +0 -0
  315. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_base_provider_query.py +0 -0
  316. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_base_provider_table_exists.py +0 -0
  317. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_base_provider_transaction_rollback_logging.py +0 -0
  318. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_cached_repository.py +0 -0
  319. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_cli_contributor.py +0 -0
  320. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_config_quadkit_db.py +0 -0
  321. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_connection_lifecycle_regressions.py +0 -0
  322. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_connection_pool_base.py +0 -0
  323. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_connection_pool_validation.py +0 -0
  324. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_crud_json_binding.py +0 -0
  325. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_database_maintenance.py +0 -0
  326. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_database_monitor_connection_pool.py +0 -0
  327. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_database_monitor_facade.py +0 -0
  328. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_database_monitor_health.py +0 -0
  329. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_database_monitor_health_checker.py +0 -0
  330. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_database_monitor_more.py +0 -0
  331. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_database_monitor_pool.py +0 -0
  332. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_database_monitor_query.py +0 -0
  333. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_database_monitor_transactions.py +0 -0
  334. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_database_provider.py +0 -0
  335. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_database_provider_multi.py +0 -0
  336. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_db_constants.py +0 -0
  337. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_db_context_propagation.py +0 -0
  338. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_db_exceptions.py +0 -0
  339. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_db_full_text.py +0 -0
  340. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_db_module.py +0 -0
  341. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_db_protocols.py +0 -0
  342. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_db_query_types.py +0 -0
  343. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_db_types.py +0 -0
  344. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_domain_mapper.py +0 -0
  345. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_domain_mapper_extended.py +0 -0
  346. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_domain_mapper_more.py +0 -0
  347. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_driver_errors.py +0 -0
  348. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_driver_monitoring_integration.py +0 -0
  349. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_drivers_smoke.py +0 -0
  350. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_exception_hierarchy_scenario.py +0 -0
  351. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_exceptions_quadkit_db.py +0 -0
  352. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_execute_commit_regression.py +0 -0
  353. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_filter_objects.py +0 -0
  354. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_generic_repository_counts.py +0 -0
  355. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_generic_repository_reads.py +0 -0
  356. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_generic_repository_writes.py +0 -0
  357. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_identity_map.py +0 -0
  358. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_instrumentation_db.py +0 -0
  359. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_mappers.py +0 -0
  360. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_mappers_base.py +0 -0
  361. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_mappers_simple.py +0 -0
  362. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_metrics_collector.py +0 -0
  363. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_migration_definitions.py +0 -0
  364. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_migration_generator.py +0 -0
  365. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_migration_generator_extra.py +0 -0
  366. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_migration_manager.py +0 -0
  367. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_migration_manager_behaviour.py +0 -0
  368. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_migration_runner.py +0 -0
  369. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_migrations_api.py +0 -0
  370. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_migrations_apply_migration.py +0 -0
  371. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_migrations_manager.py +0 -0
  372. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_migrations_rollback_recording_logs.py +0 -0
  373. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_model_analyzer.py +0 -0
  374. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_mysql_backend_scenario.py +0 -0
  375. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_mysql_driver_connection.py +0 -0
  376. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_mysql_driver_health.py +0 -0
  377. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_mysql_driver_pool.py +0 -0
  378. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_mysql_driver_resilience.py +0 -0
  379. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_named_database_config.py +0 -0
  380. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_package_hooks_p2.py +0 -0
  381. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_package_structure_p0.py +0 -0
  382. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_package_structure_p1.py +0 -0
  383. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_pool.py +0 -0
  384. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_postgres_driver_connection.py +0 -0
  385. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_postgres_driver_health.py +0 -0
  386. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_postgres_driver_pool.py +0 -0
  387. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_postgres_driver_resilience.py +0 -0
  388. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_protocol_validation.py +0 -0
  389. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_provider_connection.py +0 -0
  390. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_provider_health_check_error_logs.py +0 -0
  391. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_provider_instrumentation_edgecases.py +0 -0
  392. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_provider_resilience.py +0 -0
  393. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_provider_scoped_cleanup.py +0 -0
  394. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_query.py +0 -0
  395. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_query_log_single_emission.py +0 -0
  396. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_query_logger_backends.py +0 -0
  397. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_query_logger_entry_base.py +0 -0
  398. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_query_logger_integration.py +0 -0
  399. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_query_middleware.py +0 -0
  400. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_redis_lock.py +0 -0
  401. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_redis_secrets.py +0 -0
  402. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_redis_state.py +0 -0
  403. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_replica_pool.py +0 -0
  404. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_repository_failures.py +0 -0
  405. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_repository_hooks.py +0 -0
  406. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_repository_reads.py +0 -0
  407. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_repository_uuid_params.py +0 -0
  408. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_repository_writes.py +0 -0
  409. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_request_context_query_logging.py +0 -0
  410. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_resilience.py +0 -0
  411. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_round25_hardening.py +0 -0
  412. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_round41_hardening.py +0 -0
  413. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_schema_model.py +0 -0
  414. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_scoped_unit_of_work.py +0 -0
  415. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_seed_manager.py +0 -0
  416. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_simple_connection_pool.py +0 -0
  417. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_simple_transaction_manager.py +0 -0
  418. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_smoke_sqlalchemy.py +0 -0
  419. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_sort_whitelist.py +0 -0
  420. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_specification_identifier_safety.py +0 -0
  421. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_specification_memory_scenario.py +0 -0
  422. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_sql_config.py +0 -0
  423. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_sql_constants.py +0 -0
  424. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_sql_exceptions.py +0 -0
  425. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_sql_hooks_runtime.py +0 -0
  426. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_sql_types.py +0 -0
  427. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_sqlite_driver_connection.py +0 -0
  428. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_sqlite_driver_detailed.py +0 -0
  429. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_sqlite_driver_health.py +0 -0
  430. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_sqlite_driver_pool.py +0 -0
  431. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_sqlite_driver_resilience.py +0 -0
  432. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_sqlite_provider.py +0 -0
  433. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_sqlite_provider_fixture.py +0 -0
  434. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_sqlite_stale_file.py +0 -0
  435. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_statement_cache.py +0 -0
  436. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_testing.py +0 -0
  437. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_threads_teardown.py +0 -0
  438. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_transaction_manager_task_isolation.py +0 -0
  439. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_unit_of_work_commit.py +0 -0
  440. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_unit_of_work_operations.py +0 -0
  441. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_uow_base.py +0 -0
  442. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/test_uow_lifecycle_hooks.py +0 -0
  443. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/unit_of_work/__init__.py +0 -0
  444. {quadkit_sql-0.0.44 → quadkit_sql-0.0.46}/tests/unit/unit_of_work/test_uow_outbox.py +0 -0
@@ -1,14 +1,14 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: quadkit-sql
3
- Version: 0.0.44
3
+ Version: 0.0.46
4
4
  Summary: SQL database abstractions for Quadkit Framework — Postgres, MySQL, SQLite with migrations, repositories, and query building
5
- Project-URL: Homepage, https://dbtinoy-.github.io/quadkit
5
+ Project-URL: Homepage, https://oridecon.dev
6
6
  Project-URL: Repository, https://github.com/dbtinoy-/quadkit
7
- Project-URL: Documentation, https://dbtinoy-.github.io/quadkit
7
+ Project-URL: Documentation, https://oridecon.dev/quadkit/
8
8
  Project-URL: Issues, https://github.com/dbtinoy-/quadkit/issues
9
9
  Project-URL: Changelog, https://github.com/dbtinoy-/quadkit/blob/main/CHANGELOG.md
10
- Author-email: Quadkit Framework Team <team@quadkit.dev>
11
- Maintainer-email: Quadkit Framework Team <team@quadkit.dev>
10
+ Author-email: Quadkit Framework Team <hello@oridecon.dev>
11
+ Maintainer-email: Quadkit Framework Team <hello@oridecon.dev>
12
12
  License: Apache-2.0
13
13
  License-File: LICENSE
14
14
  License-File: NOTICE
@@ -75,7 +75,7 @@ SQL database abstractions for Quadkit Framework — Postgres, MySQL, SQLite with
75
75
  ---
76
76
 
77
77
 
78
- > Full documentation: [docs.quadkit.dev](https://docs.quadkit.dev)
78
+ > Full documentation: [oridecon.dev/quadkit](https://oridecon.dev/quadkit)
79
79
  ## Install
80
80
 
81
81
  ```bash
@@ -11,7 +11,7 @@ SQL database abstractions for Quadkit Framework — Postgres, MySQL, SQLite with
11
11
  ---
12
12
 
13
13
 
14
- > Full documentation: [docs.quadkit.dev](https://docs.quadkit.dev)
14
+ > Full documentation: [oridecon.dev/quadkit](https://oridecon.dev/quadkit)
15
15
  ## Install
16
16
 
17
17
  ```bash
@@ -6,7 +6,7 @@ build-backend = "hatchling.build"
6
6
 
7
7
  [project]
8
8
  name = "quadkit-sql"
9
- version = "0.0.44"
9
+ version = "0.0.46"
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"
@@ -49,10 +49,10 @@ dependencies = [
49
49
  "anyio>=4.0.0",
50
50
  ]
51
51
  authors = [
52
- { name = "Quadkit Framework Team", email = "team@quadkit.dev" },
52
+ { name = "Quadkit Framework Team", email = "hello@oridecon.dev" },
53
53
  ]
54
54
  maintainers = [
55
- { name = "Quadkit Framework Team", email = "team@quadkit.dev" },
55
+ { name = "Quadkit Framework Team", email = "hello@oridecon.dev" },
56
56
  ]
57
57
 
58
58
  [project.license]
@@ -93,9 +93,9 @@ all = [
93
93
  ]
94
94
 
95
95
  [project.urls]
96
- Homepage = "https://dbtinoy-.github.io/quadkit"
96
+ Homepage = "https://oridecon.dev"
97
97
  Repository = "https://github.com/dbtinoy-/quadkit"
98
- Documentation = "https://dbtinoy-.github.io/quadkit"
98
+ Documentation = "https://oridecon.dev/quadkit/"
99
99
  Issues = "https://github.com/dbtinoy-/quadkit/issues"
100
100
  Changelog = "https://github.com/dbtinoy-/quadkit/blob/main/CHANGELOG.md"
101
101
 
@@ -157,6 +157,7 @@ _LAZY_IMPORTS: dict[str, tuple[str, str]] = {
157
157
  "DatabaseConfig": ("quadkit.sql.config", "DatabaseConfig"),
158
158
  "DatabaseError": ("quadkit.sql.exceptions", "DatabaseError"),
159
159
  "DatabaseModule": ("quadkit.sql.module", "DatabaseModule"),
160
+ "SessionFactory": ("quadkit.sql.orm.session", "SessionFactory"),
160
161
  "DatabaseProvider": ("quadkit.sql.di.provider", "DatabaseProvider"),
161
162
  "DatabaseMonitor": ("quadkit.sql.monitoring.database_monitor", "DatabaseMonitor"),
162
163
  "DatabaseService": ("quadkit.sql.providers", "DatabaseService"),
@@ -322,6 +323,7 @@ __all__ = [
322
323
  "SQLiteProvider",
323
324
  "Schema",
324
325
  "ScopeColumn",
326
+ "SessionFactory",
325
327
  "SimpleConnectionPool",
326
328
  "SimpleMigrationManager",
327
329
  "SimpleTransactionManager",
@@ -0,0 +1,84 @@
1
+ """Public registration of the SQL admin widget handlers.
2
+
3
+ ``SqlAdminContributor`` resolves its three widget handlers from the DI
4
+ container in ``on_admin_boot``. The contributor itself is discovered through
5
+ the ``the optional provider module`` entry-point group, so it mounts in *any*
6
+ application that installs ``quadkit-sql`` — including applications that own
7
+ their database provider instead of using
8
+ :class:`~quadkit.sql.di.provider.DatabaseProvider`. Those applications still
9
+ have to register the handlers, or the contributor boots into a
10
+ ``UnresolvableDependencyError`` and the Database widgets render nothing.
11
+
12
+ This module owns that registration so it lives in exactly one place: the
13
+ framework provider delegates to it, and applications with their own provider
14
+ call it directly.
15
+
16
+ Example:
17
+ ```python
18
+ from quadkit.sql.admin.registration import register_admin_widget_handlers
19
+
20
+ register_admin_widget_handlers(container, db=my_database_provider)
21
+ ```
22
+ """
23
+
24
+ from __future__ import annotations
25
+
26
+ from typing import TYPE_CHECKING, Any
27
+
28
+ from quadkit.logging import get_logger
29
+
30
+ if TYPE_CHECKING: # pragma: no cover — typing only
31
+ from quadkit.contracts.core.di import ContainerRegistrarProtocol
32
+
33
+ logger = get_logger(__name__)
34
+
35
+
36
+ def register_admin_widget_handlers(
37
+ container: ContainerRegistrarProtocol,
38
+ *,
39
+ db: Any = None,
40
+ migration_manager: Any = None,
41
+ migration_runner: Any = None,
42
+ ) -> None:
43
+ """Register the SQL admin widget handlers as container singletons.
44
+
45
+ Args:
46
+ container: DI registrar to bind the handlers into.
47
+ db: Database provider exposing ``get_primary_pool()``. ``None`` is
48
+ accepted — the pool widgets then report ``Unavailable`` instead of
49
+ failing, which is the honest answer when no pool is wired.
50
+ migration_manager: Migration manager behind the migration-status
51
+ widget. ``None`` renders the widget as unavailable.
52
+ migration_runner: Optional runner used to compute pending migrations.
53
+ """
54
+ from quadkit.sql.admin.handlers.migration_status import (
55
+ MigrationStatusWidgetHandler,
56
+ )
57
+ from quadkit.sql.admin.handlers.pool_utilization import (
58
+ PoolUtilizationWidgetHandler,
59
+ )
60
+ from quadkit.sql.admin.handlers.query_stats import QueryStatsWidgetHandler
61
+
62
+ container.singleton(
63
+ PoolUtilizationWidgetHandler,
64
+ lambda: PoolUtilizationWidgetHandler(db=db),
65
+ )
66
+ container.singleton(
67
+ QueryStatsWidgetHandler,
68
+ lambda: QueryStatsWidgetHandler(db=db),
69
+ )
70
+ container.singleton(
71
+ MigrationStatusWidgetHandler,
72
+ lambda: MigrationStatusWidgetHandler(
73
+ migration_manager=migration_manager,
74
+ migration_runner=migration_runner,
75
+ ),
76
+ )
77
+ logger.info(
78
+ "sql.admin_widgets_registered",
79
+ pool_widgets=db is not None,
80
+ migration_widget=migration_manager is not None,
81
+ )
82
+
83
+
84
+ __all__ = ["register_admin_widget_handlers"]
@@ -70,6 +70,18 @@ class DatabaseRepositoryGenerator(GeneratorBase):
70
70
  ),
71
71
  key_field=str(options.get("key_field") or "id"),
72
72
  needs_datetime=any(f["import_datetime"] for f in fields),
73
+ # The not-found error the repository returns. The built-in
74
+ # default is the contracts family member, so a standalone CLI
75
+ # render behaves exactly as before; an app whose exceptions live
76
+ # in its own module (the generated modular layout) passes the
77
+ # class name and import root — the class is the one named type
78
+ # for the outcome, and R6's one lineage keeps the Result
79
+ # bridge's status mapping uniform.
80
+ not_found_error=str(options.get("not_found_error") or "NotFoundError"),
81
+ exceptions_module=str(
82
+ options.get("exceptions_module") or "quadkit.contracts.exceptions"
83
+ ),
84
+ exceptions_first_party=bool(options.get("exceptions_first_party") or False),
73
85
  )
74
86
 
75
87
  self.stage(file_path, content)
@@ -64,6 +64,34 @@ class ServiceGenerator(GeneratorBase):
64
64
  for field in fields
65
65
  ],
66
66
  }
67
+ context.update(
68
+ {
69
+ # One named error type per outcome, declared once: the
70
+ # class, its import root, and the service's declared union.
71
+ # The standalone-CLI defaults keep the contracts family;
72
+ # a modular app passes its per-context exceptions module so
73
+ # the lineage runs one entity-named type end to end.
74
+ "not_found_error": str(
75
+ options.get("not_found_error") or "NotFoundError"
76
+ ),
77
+ "exceptions_module": str(
78
+ options.get("exceptions_module") or "quadkit.contracts.exceptions"
79
+ ),
80
+ "service_error_union": str(
81
+ options.get("service_error_union")
82
+ or options.get("not_found_error")
83
+ or "NotFoundError"
84
+ ),
85
+ # Isort groups change with first-party membership: the
86
+ # framework's contracts module sorts inside the third-party
87
+ # block; a generated app's own exceptions module ships
88
+ # ``[tool.ruff] src = ["src"]``, so it is first-party and
89
+ # earns the trailing group. One template, one profile each.
90
+ "exceptions_first_party": bool(
91
+ options.get("exceptions_first_party") or False
92
+ ),
93
+ }
94
+ )
67
95
  content = self.render_template("service.py.jinja2", context)
68
96
  file_path = self.output_dir / f"{snake_name}_service.py"
69
97
  self.stage(file_path, content)
@@ -1,4 +1,8 @@
1
- """{{ entity_name }} repository."""
1
+ """Convention followed: **Repository pattern** — this module owns the
2
+ row<->entity mapping only; every read/write goes through
3
+ ``GenericRepository`` plus the injected provider.
4
+
5
+ {{ entity_name }} repository."""
2
6
 
3
7
  from __future__ import annotations
4
8
 
@@ -8,16 +12,19 @@ import uuid as _uuid
8
12
  {% endif %}
9
13
  from quadkit import clock
10
14
  from quadkit.contracts import DatabaseProviderProtocol
11
-
15
+ {% if not exceptions_first_party %}from {{ exceptions_module }} import {{ not_found_error }}
16
+ {% endif %}from quadkit.result import Err, Ok, Result
17
+ from quadkit.serialization.domain import json_serialize
12
18
  from quadkit.sql.repositories.generic_repository import GenericRepository
19
+ {% if exceptions_first_party %}
20
+
21
+ from {{ exceptions_module }} import {{ not_found_error }}
22
+ {% endif %}
13
23
 
14
24
 
15
25
  class {{ entity_name }}Entity:
16
26
  """{{ entity_name }} row entity (plain attrs; swap for a model later)."""
17
-
18
- {% for field in fields %}
19
- {{ field.name }}: {{ field.py_type }}{% if not field.required %} | None = None{% endif %}
20
-
27
+ {% for field in fields %} {{ field.name }}: {{ field.py_type }}{% if not field.required %} | None = None{% endif %}
21
28
  {% endfor %}
22
29
  def __init__(self, **kwargs: Any) -> None:
23
30
  for key, value in kwargs.items():
@@ -27,8 +34,12 @@ class {{ entity_name }}Entity:
27
34
  class _{{ repo_name }}Inner(GenericRepository[{{ entity_name }}Entity, str]):
28
35
  """Row mapper bridge over the generic SQL repository."""
29
36
 
30
- def _entity_to_dict(self, entity: {{ entity_name }}Entity) -> dict[str, Any]:
31
- return dict(vars(entity))
37
+ def _serialize_entity(self, entity: {{ entity_name }}Entity) -> dict[str, Any]:
38
+ """Row dict via the framework serializer (datetime/UUID/enum-safe)."""
39
+ serialized = json_serialize(entity)
40
+ if isinstance(serialized, dict):
41
+ return serialized
42
+ return {"value": serialized}
32
43
 
33
44
  def _row_to_entity(self, row: dict[str, Any]) -> {{ entity_name }}Entity:
34
45
  return self.entity_class(**dict(row))
@@ -70,17 +81,28 @@ class {{ repo_name }}Repository:
70
81
  )
71
82
  return found
72
83
 
73
- async def get(self, key: str) -> dict[str, Any] | None:
84
+ async def get(self, key: str) -> Result[dict[str, Any], {{ not_found_error }}]:
85
+ """A row that is not there is an expected outcome: absence travels
86
+ as ``Err({{ not_found_error }})`` — a value — never as ``None`` (R6)."""
74
87
  entity = await self._inner.find_by_id(key)
75
88
  if entity is None:
76
- return None
77
- return self._inner._entity_to_dict(entity)
89
+ return Err(
90
+ {{ not_found_error }}(f"{{ entity_name }} not found with id: {key}")
91
+ )
92
+ return Ok(self._inner._serialize_entity(entity))
78
93
 
79
94
  async def list(self, limit: int = 50) -> list[dict[str, Any]]:
80
95
  entities = await self._inner.find(limit=limit)
81
- return [self._inner._entity_to_dict(e) for e in entities]
82
-
83
- async def update(self, key: str, data: dict[str, Any]) -> dict[str, Any] | None:
96
+ return [self._inner._serialize_entity(e) for e in entities]
97
+
98
+ async def update(
99
+ self, key: str, data: dict[str, Any]
100
+ ) -> Result[dict[str, Any], {{ not_found_error }}]:
101
+ existing = await self._inner.find_by_id(key)
102
+ if existing is None:
103
+ return Err(
104
+ {{ not_found_error }}(f"{{ entity_name }} not found with id: {key}")
105
+ )
84
106
  async with self._provider.transaction():
85
107
  row = {
86
108
  **data,
@@ -90,7 +112,17 @@ class {{ repo_name }}Repository:
90
112
  await self._provider.execute_update(
91
113
  "{{ table_name }}", row, '"{{ key_field }}" = ?', [key]
92
114
  )
93
- return await self.get(key)
94
-
95
- async def delete(self, key: str) -> bool:
96
- return await self._inner.delete_by_id(key)
115
+ return await self.get(key)
116
+
117
+ async def delete(self, key: str) -> Result[bool, {{ not_found_error }}]:
118
+ """Deleting a row that is not there is an expected outcome, so it
119
+ travels as ``Err({{ not_found_error }})`` — one named error type for the
120
+ outcome, defined once, instead of a truthiness every caller must
121
+ re-read (R6). Harder faults (a dead connection) stay on the throw
122
+ path."""
123
+ removed = await self._inner.delete_by_id(key)
124
+ if not removed:
125
+ return Err(
126
+ {{ not_found_error }}(f"{{ entity_name }} not found with id: {key}")
127
+ )
128
+ return Ok(True)
@@ -3,6 +3,9 @@
3
3
  Revision ID: {{ rev_id }}
4
4
  Revises: {{ prev_rev if prev_rev else "" }}
5
5
  Create Date: auto
6
+
7
+ Every table carries ``id`` + ``created_at``/``updated_at``; the entity
8
+ columns follow. Downgrade drops the table.
6
9
  """
7
10
 
8
11
  from __future__ import annotations
@@ -1,4 +1,8 @@
1
- """{{ entity_name }} entity model.
1
+ """Convention followed: **Domain model pattern** — one shape per
2
+ entity: the model carries the stored fields, the Create/Update DTOs
3
+ carry the write shapes; repository and controller share them.
4
+
5
+ {{ entity_name }} entity model.
2
6
  {% if extra_dependencies %}
3
7
 
4
8
  Requires: {{ extra_dependencies | join(', ') }} — install it alongside pydantic
@@ -1,4 +1,9 @@
1
- """Health Check for {{ name }}."""
1
+ """Health check for {{ snake_name }}.
2
+
3
+ Reports HEALTHY/UNHEALTHY through the result object — failures are
4
+ captured, never raised, so one sick component cannot take down the
5
+ readiness endpoint.
6
+ """
2
7
 
3
8
  from quadkit.contracts.core import HealthCheckResult, HealthStatus
4
9
  from quadkit.monitor.health import HealthCheck
@@ -1,4 +1,9 @@
1
- """Database seeder for {{ model_name }}."""
1
+ """Database seeder for {{ model_name }}.
2
+
3
+ Starter rows live in ``SEED_DATA``; ``run()`` inserts them once and
4
+ skips when the table is already populated. Edit ``SEED_DATA`` to
5
+ change what a fresh database contains.
6
+ """
2
7
 
3
8
  from __future__ import annotations
4
9
 
@@ -0,0 +1,159 @@
1
+ """Convention followed: **Service pattern** — domain logic behind a
2
+ small class the provider binds; controllers call the service, never
3
+ the provider. Writes commit through the unit of work, reads go
4
+ straight through. Handlers that can fail on *expected* domain
5
+ outcomes (a row that is not there) return ``Result[T, E]``
6
+ (Convention: **Result + ProblemDetail**) instead of ``None``: the
7
+ web layer's Result bridge renders ``Err(NotFoundError)`` as a
8
+ 404 RFC-9457 ``ProblemDetail``. Infra faults (a dead connection) stay
9
+ on the throw path — they are not domain outcomes.
10
+
11
+ Application service for {{ resource_name }} backed by the SQL unit of work.
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ from typing import Any
17
+
18
+ from quadkit.contracts import DatabaseProviderProtocol
19
+ {% if not exceptions_first_party %}from {{ exceptions_module }} import {{ not_found_error }}{% if service_error_union != not_found_error %}, {{ service_error_union }}{% endif %}
20
+ {% endif %}from quadkit.logging import get_logger
21
+ from quadkit.result import Err, Ok, Result
22
+ from quadkit.sql.unit_of_work import SimpleUnitOfWork
23
+ {% if exceptions_first_party %}
24
+
25
+ from {{ exceptions_module }} import {{ not_found_error }}{% if service_error_union != not_found_error %}, {{ service_error_union }}{% endif %}
26
+ {% endif %}
27
+ logger = get_logger(__name__)
28
+
29
+
30
+ class {{ entity_class_name }}:
31
+ """Row entity for the ``{{ table_name }}`` table."""
32
+
33
+ __table_name__ = "{{ table_name }}"
34
+
35
+ def __init__(self, **data: Any) -> None:
36
+ """Populate row attributes from *data*."""
37
+ for key, value in data.items():
38
+ setattr(self, key, value)
39
+
40
+
41
+ class {{ class_name }}Service:
42
+ """Service for {{ resource_name }}.
43
+
44
+ Write operations use :class:`~quadkit.sql.SimpleUnitOfWork` so entity
45
+ changes and domain events commit atomically. Single-statement reads go
46
+ straight through the injected :class:`~quadkit.contracts.DatabaseProviderProtocol`.
47
+ """
48
+
49
+ def __init__(self, provider: DatabaseProviderProtocol) -> None:
50
+ """Initialize the service.
51
+
52
+ Args:
53
+ provider: Database provider (typically resolved from DI after
54
+ registering :class:`~quadkit.sql.di.provider.DatabaseProvider`).
55
+ """
56
+ self._provider = provider
57
+
58
+ async def create(
59
+ self, data: dict[str, Any]
60
+ ) -> Result[dict[str, Any], {{ service_error_union }}]:
61
+ """Persist a new ``{{ table_name }}`` row.
62
+
63
+ Args:
64
+ data: Row values{% if fields %} (keys: {% for field in fields %}{{ field.name }}{% if not loop.last %}, {% endif %}{% endfor %}){% endif %}.
65
+
66
+ Returns:
67
+ ``Ok(row)`` — the persisted row data. Writes that cannot
68
+ legitimately fail still answer with the service's union so every
69
+ consumer chains: ``get(...).map(...)`` and
70
+ ``create(...).and_then(...)`` share one shape.
71
+ """
72
+ async with SimpleUnitOfWork(self._provider) as uow:
73
+ uow.register_new({{ entity_class_name }}(**data))
74
+ await uow.commit()
75
+ logger.info("{{ snake_name }}_created", table="{{ table_name }}")
76
+ return Ok(data)
77
+
78
+ async def get(
79
+ self, entity_id: Any
80
+ ) -> Result[dict[str, Any], {{ service_error_union }}]:
81
+ """Fetch a ``{{ table_name }}`` row by primary key.
82
+
83
+ Args:
84
+ entity_id: Primary key value.
85
+
86
+ Returns:
87
+ ``Ok(row)`` when the row exists, ``Err(...)`` when it
88
+ does not — absence is an expected outcome, so it travels as a
89
+ value, never as ``None``.
90
+ """
91
+ result = await self._provider.execute_query(
92
+ "SELECT * FROM {{ table_name }} WHERE id = ?",
93
+ params=[entity_id],
94
+ )
95
+ if not result.rows:
96
+ return Err(
97
+ {{ not_found_error }}(f"{{ table_name }} row not found with id: {entity_id}")
98
+ )
99
+ return Ok(result.rows[0])
100
+
101
+ async def update(
102
+ self, entity_id: Any, data: dict[str, Any]
103
+ ) -> Result[dict[str, Any], {{ service_error_union }}]:
104
+ """Merge *data* into one ``{{ table_name }}`` row by primary key.
105
+
106
+ The row being gone is the same expected outcome as ``get`` — the
107
+ Err arm comes straight through — so the write happens only for a
108
+ row that answered ``Ok``.
109
+ """
110
+ existing = await self.get(entity_id)
111
+ if existing.is_err():
112
+ return Err(existing.unwrap_err())
113
+ async with SimpleUnitOfWork(self._provider) as uow:
114
+ uow.register_dirty({{ entity_class_name }}(id=entity_id, **data))
115
+ await uow.commit()
116
+ logger.info("{{ snake_name }}_updated", table="{{ table_name }}")
117
+ return Ok(data)
118
+
119
+ async def list(
120
+ self,
121
+ limit: int = 100,
122
+ offset: int = 0,
123
+ ) -> Result[list[dict[str, Any]], {{ service_error_union }}]:
124
+ """List ``{{ table_name }}`` rows with pagination.
125
+
126
+ Args:
127
+ limit: Maximum number of rows.
128
+ offset: Number of rows to skip.
129
+
130
+ Returns:
131
+ ``Ok(rows)``. An empty page is a value, and its uniform arm
132
+ keeps reads chainable with the outcome-bearing methods.
133
+ """
134
+ result = await self._provider.execute_query(
135
+ "SELECT * FROM {{ table_name }} LIMIT ? OFFSET ?",
136
+ params=[limit, offset],
137
+ )
138
+ return Ok(result.rows)
139
+
140
+ async def delete(
141
+ self, entity_id: Any
142
+ ) -> Result[bool, {{ service_error_union }}]:
143
+ """Delete a ``{{ table_name }}`` row by primary key.
144
+
145
+ The existence check travels as the ``Err`` arm: deleting a missing
146
+ row answers ``Err`` (the bridge renders 404), a real
147
+ delete answers ``Ok(True)``.
148
+
149
+ Args:
150
+ entity_id: Primary key value.
151
+ """
152
+ existing = await self.get(entity_id)
153
+ if existing.is_err():
154
+ return Err(existing.unwrap_err())
155
+ async with SimpleUnitOfWork(self._provider) as uow:
156
+ uow.register_deleted({{ entity_class_name }}(id=entity_id))
157
+ await uow.commit()
158
+ logger.info("{{ snake_name }}_deleted", table="{{ table_name }}")
159
+ return Ok(True)
@@ -112,6 +112,25 @@ class _DatabaseRegistrationMixin:
112
112
  # Register admin widget services
113
113
  self._register_admin_widgets(container)
114
114
 
115
+ def _make_session_factory(self, name: str, backend: Any) -> Any:
116
+ """Build (once) the ORM session factory for one backend.
117
+
118
+ Memoised so repeated resolution shares the engine rather than
119
+ quietly opening another pool — which is the very problem this
120
+ feature exists to remove.
121
+ """
122
+ from quadkit.sql.orm.session import SessionFactory
123
+
124
+ existing = self._session_factories.get(name)
125
+ if existing is not None:
126
+ return existing
127
+ factory = SessionFactory(
128
+ backend.url.get_secret_value(),
129
+ echo=bool(getattr(backend, "echo", False)),
130
+ )
131
+ self._session_factories[name] = factory
132
+ return factory
133
+
115
134
  async def _register_single_backend(
116
135
  self,
117
136
  container: ContainerRegistrarProtocol,
@@ -125,6 +144,7 @@ class _DatabaseRegistrationMixin:
125
144
  QueryLoggerProtocol,
126
145
  UnitOfWorkProtocol,
127
146
  )
147
+ from quadkit.sql.orm.session import SessionFactory
128
148
 
129
149
  self._db_provider = self._db_provider or DatabaseService(
130
150
  config, clock=self._clock, id_generator=self._id_generator
@@ -132,6 +152,21 @@ class _DatabaseRegistrationMixin:
132
152
  container.singleton(DatabaseService, self._db_provider)
133
153
  container.singleton(DatabaseProviderProtocol, self._db_provider)
134
154
 
155
+ # ORM session factory: one engine and one pool shared with the raw
156
+ # providers, so an application mapping declarative models does not
157
+ # build a second engine against the same database
158
+ # (Improve-QuadKit #1).
159
+ #
160
+ # Registered as a FACTORY, not an instance: the engine is built
161
+ # only if something resolves it. Building eagerly would also fail
162
+ # for apps configured with a sync driver (`sqlite://` rather than
163
+ # `sqlite+aiosqlite://`), which use the raw providers happily and
164
+ # never ask for an ORM session.
165
+ container.singleton(
166
+ SessionFactory,
167
+ factory=lambda: self._make_session_factory("default", config.backend),
168
+ )
169
+
135
170
  # Protocol bindings for optional collaborators
136
171
  container.singleton(
137
172
  ConnectionPoolProtocol,
@@ -212,12 +247,15 @@ class _DatabaseRegistrationMixin:
212
247
  QueryLoggerProtocol,
213
248
  UnitOfWorkProtocol,
214
249
  )
250
+ from quadkit.sql.orm.session import SessionFactory
215
251
 
216
252
  backends = config.backends
217
253
  primary_entry = next((b for b in backends if b.primary), backends[0])
218
254
 
219
255
  self._db_services = []
256
+ self._session_factories: dict[str, Any] = {}
220
257
  primary_svc: Any = None
258
+ primary_factory: Any = None
221
259
 
222
260
  for entry in backends:
223
261
  db_cfg = DatabaseConfig.from_named(entry, base=config)
@@ -263,13 +301,31 @@ class _DatabaseRegistrationMixin:
263
301
  container, db_svc, entry.migration_dir, name=entry.name
264
302
  )
265
303
 
304
+ # ORM session factory: one engine and one pool per backend, so
305
+ # an application mapping declarative models does not build a
306
+ # second engine against the same database (Improve-QuadKit #1).
307
+ # Engine construction is lazy — no connection is opened here.
308
+ container.singleton(
309
+ SessionFactory,
310
+ name=entry.name,
311
+ factory=lambda e=entry: self._make_session_factory(e.name, e.backend),
312
+ )
313
+
266
314
  if entry.name == primary_entry.name:
267
315
  primary_svc = db_svc
316
+ primary_factory = entry
268
317
 
269
318
  # Primary backend also gets the unnamed bindings (backward compat)
270
319
  self._db_provider = primary_svc
271
320
  container.singleton(DatabaseProviderProtocol, instance=primary_svc)
272
321
  container.singleton(DatabaseService, instance=primary_svc)
322
+ if primary_factory is not None:
323
+ container.singleton(
324
+ SessionFactory,
325
+ factory=lambda e=primary_factory: self._make_session_factory(
326
+ e.name, e.backend
327
+ ),
328
+ )
273
329
 
274
330
  container.scoped(UnitOfWorkProtocol, primary_svc.get_unit_of_work) # type: ignore[type-abstract]
275
331