matrx-orm 3.1.52__tar.gz → 3.1.53__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 (327) hide show
  1. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/CLAUDE.md +10 -0
  2. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/PKG-INFO +2 -2
  3. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/schema_builder/runner.py +127 -8
  4. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/pyproject.toml +1 -1
  5. matrx_orm-3.1.53/tests/schema_builder/test_host_models_aggregator.py +171 -0
  6. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/.gitignore +0 -0
  7. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/AGENTS.md +0 -0
  8. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/BASE_CLASS_METHODS.md +0 -0
  9. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/MODEL_API.md +0 -0
  10. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/README.md +0 -0
  11. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/database/orm/extended/managers/ai_model_base.py +0 -0
  12. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/docs/migrations.md +0 -0
  13. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/MODULE_README.md +0 -0
  14. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/__init__.py +0 -0
  15. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/adapters/MODULE_README.md +0 -0
  16. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/adapters/__init__.py +0 -0
  17. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/adapters/async_postgresql.py +0 -0
  18. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/adapters/base_adapter.py +0 -0
  19. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/adapters/postgresql.py +0 -0
  20. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/adapters/postgrest_client_adapter.py +0 -0
  21. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/adapters/supabase_adapter.py +0 -0
  22. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/admin/__init__.py +0 -0
  23. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/admin/router.py +0 -0
  24. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/api/__init__.py +0 -0
  25. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/api/auth.py +0 -0
  26. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/api/config.py +0 -0
  27. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/api/handlers.py +0 -0
  28. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/api/protocol.py +0 -0
  29. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/api/server.py +0 -0
  30. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/associations.py +0 -0
  31. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/cache_debug.py +0 -0
  32. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/catalog.py +0 -0
  33. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/client/MODULE_README.md +0 -0
  34. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/client/__init__.py +0 -0
  35. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/client/postgres_connection.py +0 -0
  36. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/client/postgrest.py +0 -0
  37. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/client/supabase_auth.py +0 -0
  38. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/client/supabase_config.py +0 -0
  39. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/client/supabase_manager.py +0 -0
  40. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/core/EXTENDED-TASK.md +0 -0
  41. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/core/FEATURE.md +0 -0
  42. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/core/MODULE_README.md +0 -0
  43. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/core/RELATIONS-TASKS.md +0 -0
  44. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/core/TASKS.md +0 -0
  45. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/core/__init__.py +0 -0
  46. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/core/async_db_manager.py +0 -0
  47. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/core/base.py +0 -0
  48. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/core/config.py +0 -0
  49. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/core/connections.py +0 -0
  50. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/core/db_function.py +0 -0
  51. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/core/diagnostics.py +0 -0
  52. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/core/expressions.py +0 -0
  53. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/core/extended.py +0 -0
  54. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/core/fields.py +0 -0
  55. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/core/introspection.py +0 -0
  56. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/core/listen.py +0 -0
  57. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/core/loop_filters.py +0 -0
  58. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/core/model_dto.py +0 -0
  59. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/core/model_view.py +0 -0
  60. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/core/one_database.py +0 -0
  61. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/core/paginator.py +0 -0
  62. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/core/pool_maintenance.py +0 -0
  63. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/core/pydantic_bridge.py +0 -0
  64. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/core/registry.py +0 -0
  65. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/core/relations.py +0 -0
  66. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/core/resilience.py +0 -0
  67. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/core/rls_session.py +0 -0
  68. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/core/signals.py +0 -0
  69. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/core/tls.py +0 -0
  70. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/core/transaction.py +0 -0
  71. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/core/types.py +0 -0
  72. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/core/write_queue.py +0 -0
  73. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/entity.py +0 -0
  74. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/error_handling.py +0 -0
  75. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/exceptions.py +0 -0
  76. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/extended/__init__.py +0 -0
  77. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/extended/app_error_handler.py +0 -0
  78. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/identity_rule.py +0 -0
  79. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/middleware/__init__.py +0 -0
  80. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/middleware/base.py +0 -0
  81. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/migrations/MODULE_README.md +0 -0
  82. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/migrations/__init__.py +0 -0
  83. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/migrations/cli.py +0 -0
  84. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/migrations/ddl.py +0 -0
  85. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/migrations/diff.py +0 -0
  86. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/migrations/executor.py +0 -0
  87. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/migrations/integration.py +0 -0
  88. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/migrations/loader.py +0 -0
  89. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/migrations/operations.py +0 -0
  90. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/migrations/state.py +0 -0
  91. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/migrations/table_filter.py +0 -0
  92. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/operations/MODULE_README.md +0 -0
  93. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/operations/__init__.py +0 -0
  94. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/operations/bulk_update_values.py +0 -0
  95. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/operations/conflict.py +0 -0
  96. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/operations/conflict_writes.py +0 -0
  97. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/operations/create.py +0 -0
  98. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/operations/db_functions.py +0 -0
  99. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/operations/delete.py +0 -0
  100. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/operations/dynamic_admin.py +0 -0
  101. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/operations/dynamic_crud.py +0 -0
  102. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/operations/graph_walk.py +0 -0
  103. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/operations/latest_rows.py +0 -0
  104. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/operations/queue_claim.py +0 -0
  105. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/operations/read.py +0 -0
  106. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/operations/relational_backfill.py +0 -0
  107. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/operations/staging_load.py +0 -0
  108. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/operations/update.py +0 -0
  109. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/platform_db.py +0 -0
  110. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/py.typed +0 -0
  111. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/python_sql/MODULE_README.md +0 -0
  112. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/python_sql/__init__.py +0 -0
  113. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/python_sql/db_objects.py +0 -0
  114. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/python_sql/table_detailed_relationships.py +0 -0
  115. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/python_sql/table_typescript_relationship.py +0 -0
  116. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/query/FEATURE.md +0 -0
  117. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/query/MODULE_README.md +0 -0
  118. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/query/__init__.py +0 -0
  119. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/query/builder.py +0 -0
  120. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/query/executor.py +0 -0
  121. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/schema_builder/MODULE_README.md +0 -0
  122. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/schema_builder/__init__.py +0 -0
  123. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/schema_builder/code_handler.py +0 -0
  124. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/schema_builder/codegen_writer.py +0 -0
  125. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/schema_builder/columns.py +0 -0
  126. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/schema_builder/common.py +0 -0
  127. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/schema_builder/diff_preview.py +0 -0
  128. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/schema_builder/entity_capabilities.py +0 -0
  129. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/schema_builder/generator.py +0 -0
  130. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/schema_builder/helpers/__init__.py +0 -0
  131. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/schema_builder/helpers/base_generators.py +0 -0
  132. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/schema_builder/helpers/entity_generators.py +0 -0
  133. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/schema_builder/helpers/git_checker.py +0 -0
  134. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/schema_builder/package_wiring.py +0 -0
  135. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/schema_builder/relationships.py +0 -0
  136. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/schema_builder/schema.py +0 -0
  137. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/schema_builder/schema_manager.py +0 -0
  138. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/schema_builder/tables.py +0 -0
  139. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/schema_builder/views.py +0 -0
  140. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/secrets_battery/FEATURE.md +0 -0
  141. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/secrets_battery/__init__.py +0 -0
  142. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/secrets_battery/crypto.py +0 -0
  143. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/secrets_battery/items.py +0 -0
  144. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/secrets_battery/model.py +0 -0
  145. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/secrets_battery/org_service.py +0 -0
  146. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/secrets_battery/service.py +0 -0
  147. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/session/README.md +0 -0
  148. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/session/__init__.py +0 -0
  149. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/session/coalesce.py +0 -0
  150. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/session/dag.py +0 -0
  151. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/session/errors.py +0 -0
  152. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/session/fallback.py +0 -0
  153. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/session/flush.py +0 -0
  154. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/session/lifecycle.py +0 -0
  155. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/session/managed.py +0 -0
  156. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/session/op.py +0 -0
  157. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/session/reads.py +0 -0
  158. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/session/session.py +0 -0
  159. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/session/telemetry.py +0 -0
  160. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/sql_executor/MODULE_README.md +0 -0
  161. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/sql_executor/__init__.py +0 -0
  162. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/sql_executor/executor.py +0 -0
  163. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/sql_executor/queries.py +0 -0
  164. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/sql_executor/registry.py +0 -0
  165. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/sql_executor/types.py +0 -0
  166. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/sql_executor/utils.py +0 -0
  167. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/state.py +0 -0
  168. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/utils/__init__.py +0 -0
  169. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/utils/sql_utils.py +0 -0
  170. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/matrx_orm/utils/type_converters.py +0 -0
  171. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/scripts/git-branches.sh +0 -0
  172. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/scripts/publish.sh +0 -0
  173. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/scripts/release.sh +0 -0
  174. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/MODULE_README.md +0 -0
  175. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/__init__.py +0 -0
  176. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/conftest.py +0 -0
  177. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/MODULE_README.md +0 -0
  178. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/__init__.py +0 -0
  179. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_admin_db_columns.py +0 -0
  180. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_admin_search_negation.py +0 -0
  181. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_admin_search_sentinels.py +0 -0
  182. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_advisory_lock.py +0 -0
  183. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_agent_message.py +0 -0
  184. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_api_auth.py +0 -0
  185. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_api_config.py +0 -0
  186. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_api_handlers.py +0 -0
  187. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_api_protocol.py +0 -0
  188. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_array_agg_order_by.py +0 -0
  189. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_associations.py +0 -0
  190. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_bulk_update_by_pk.py +0 -0
  191. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_bulk_upsert_increment_set_fields.py +0 -0
  192. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_cache_debug.py +0 -0
  193. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_call_function.py +0 -0
  194. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_case_when.py +0 -0
  195. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_catalog.py +0 -0
  196. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_composite_pk_filter.py +0 -0
  197. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_composite_pk_write_paths.py +0 -0
  198. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_config.py +0 -0
  199. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_conflict_target.py +0 -0
  200. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_conflict_writes.py +0 -0
  201. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_connection_codecs.py +0 -0
  202. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_connection_poison_guard.py +0 -0
  203. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_connection_primitives.py +0 -0
  204. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_count_composite_distinct.py +0 -0
  205. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_db_function_field.py +0 -0
  206. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_ddl_generator.py +0 -0
  207. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_derived_table.py +0 -0
  208. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_dirty_tracking.py +0 -0
  209. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_dynamic_crud.py +0 -0
  210. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_exceptions.py +0 -0
  211. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_execute_query_integrity_mapping.py +0 -0
  212. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_expression_primitives.py +0 -0
  213. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_fields.py +0 -0
  214. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_filter_jsonb_agg_array_index.py +0 -0
  215. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_from_alias.py +0 -0
  216. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_fts.py +0 -0
  217. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_func_expression_args.py +0 -0
  218. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_graph_walk.py +0 -0
  219. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_having_annotate_alias.py +0 -0
  220. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_insert_ignore_and_admin_primitives.py +0 -0
  221. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_introspect_rls_policies.py +0 -0
  222. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_join_and_aggregate.py +0 -0
  223. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_latest_rows.py +0 -0
  224. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_listen_notify.py +0 -0
  225. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_managed_write_guard.py +0 -0
  226. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_matrx_entity.py +0 -0
  227. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_migration_diff_types.py +0 -0
  228. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_migration_loader.py +0 -0
  229. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_model_instance.py +0 -0
  230. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_model_meta.py +0 -0
  231. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_optimistic_concurrency.py +0 -0
  232. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_order_by_expression.py +0 -0
  233. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_parameter_name_hydration.py +0 -0
  234. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_patch_jsonb_path.py +0 -0
  235. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_pool_loop_recreation.py +0 -0
  236. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_pool_maintenance.py +0 -0
  237. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_postgrest_filters.py +0 -0
  238. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_pydantic_bridge.py +0 -0
  239. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_query_builder.py +0 -0
  240. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_query_error_detail.py +0 -0
  241. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_query_executor_sql.py +0 -0
  242. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_query_timeout.py +0 -0
  243. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_querybuilder_clone_semantics.py +0 -0
  244. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_queue_claim.py +0 -0
  245. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_registry.py +0 -0
  246. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_registry_multi_database.py +0 -0
  247. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_registry_multi_schema.py +0 -0
  248. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_relational_backfill.py +0 -0
  249. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_relations.py +0 -0
  250. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_resilience.py +0 -0
  251. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_schema_exists.py +0 -0
  252. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_session_advisory_lock.py +0 -0
  253. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_state_cache.py +0 -0
  254. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_subquery_filter_raw.py +0 -0
  255. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_subquery_in_filter.py +0 -0
  256. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_supabase_auth.py +0 -0
  257. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_supabase_config.py +0 -0
  258. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_tls.py +0 -0
  259. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_typed_join_projection.py +0 -0
  260. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_typed_predicates.py +0 -0
  261. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_update_case_expression.py +0 -0
  262. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_update_subquery.py +0 -0
  263. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_update_with_rebase.py +0 -0
  264. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_upsert_default_leak.py +0 -0
  265. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_upsert_with_conflict.py +0 -0
  266. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_values_jsonb_decode.py +0 -0
  267. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_watched_lifecycle.py +0 -0
  268. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level1/test_write_retry_semantics.py +0 -0
  269. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level2/MODULE_README.md +0 -0
  270. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level2/__init__.py +0 -0
  271. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level2/conftest.py +0 -0
  272. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level2/test_bulk_ops.py +0 -0
  273. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level2/test_cache_integration.py +0 -0
  274. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level2/test_crud.py +0 -0
  275. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level2/test_foreign_keys.py +0 -0
  276. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level2/test_m2m.py +0 -0
  277. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level2/test_manager.py +0 -0
  278. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level2/test_migrations_live.py +0 -0
  279. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level2/test_query_execution.py +0 -0
  280. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/level2/test_schema_diff.py +0 -0
  281. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/sample_project/.env.example +0 -0
  282. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/sample_project/README.md +0 -0
  283. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/sample_project/__init__.py +0 -0
  284. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/sample_project/generate.py +0 -0
  285. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/sample_project/generated/.gitkeep +0 -0
  286. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/sample_project/matrx_orm.yaml +0 -0
  287. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/sample_project/test_schema_generation.py +0 -0
  288. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/sample_project_desktop/.env.example +0 -0
  289. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/sample_project_desktop/README.md +0 -0
  290. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/sample_project_desktop/__init__.py +0 -0
  291. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/sample_project_desktop/client_example.py +0 -0
  292. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/sample_project_desktop/client_example.ts +0 -0
  293. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/sample_project_desktop/client_supabase_example.py +0 -0
  294. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/sample_project_desktop/server.py +0 -0
  295. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/schema/entity_tests.py +0 -0
  296. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/schema/test_base_generation.py +0 -0
  297. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/schema/test_composite_pk_fk_generation.py +0 -0
  298. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/schema/test_composite_unique_generation.py +0 -0
  299. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/schema/test_dto_identity_generation.py +0 -0
  300. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/schema/test_entity_capability_generation.py +0 -0
  301. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/schema/test_generate_schema.py +0 -0
  302. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/schema/test_junction_analysis.py +0 -0
  303. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/schema/test_multi_schema_output.py +0 -0
  304. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/schema/test_sql_expression_defaults.py +0 -0
  305. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/schema/test_view_generation.py +0 -0
  306. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/schema_builder/test_focused_generation_plan.py +0 -0
  307. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/session/__init__.py +0 -0
  308. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/session/conftest.py +0 -0
  309. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/session/test_cache_no_downgrade.py +0 -0
  310. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/session/test_capture_poison_proof.py +0 -0
  311. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/session/test_coalesce.py +0 -0
  312. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/session/test_dag.py +0 -0
  313. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/session/test_disk_spill_fallback.py +0 -0
  314. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/session/test_flush_individual_fallback.py +0 -0
  315. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/session/test_governed_write.py +0 -0
  316. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/session/test_managed.py +0 -0
  317. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/session/test_op_enqueue_site.py +0 -0
  318. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/session/test_reads.py +0 -0
  319. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/session/test_session.py +0 -0
  320. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/test_database_name_alias.py +0 -0
  321. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/test_db_functions.py +0 -0
  322. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/test_model_cls_refactor.py +0 -0
  323. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/test_no_blocking_asyncpg_tls.py +0 -0
  324. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/test_one_database.py +0 -0
  325. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/test_secrets_battery.py +0 -0
  326. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/test_sql_param_casts.py +0 -0
  327. {matrx_orm-3.1.52 → matrx_orm-3.1.53}/tests/test_sync_twins_guard.py +0 -0
@@ -113,6 +113,16 @@ Tests must run against a Postgres instance the developer provides (or a testcont
113
113
  Host generators may expose a focused schema pass by forwarding
114
114
  `only_schemas={...}` to `run_schema_generation`; aidream's focused package-model
115
115
  command is `uv run python db/generate.py --schema <schema> --models-only`.
116
+ 🚨 **A scoped run must NEVER shrink the host models aggregator.** `db/models/__init__.py`
117
+ is the entire `from db.models import X` surface; it is always written from the FULL,
118
+ unfiltered `generate[]` list, never from the `only_schemas` subset — and model names for
119
+ schemas the run did not regenerate are read back from their modules on disk (AST, no
120
+ import) so cross-schema collision de-flattening stays complete. Writing it from a subset
121
+ once truncated it to one schema and broke imports repo-wide, silently at generation time
122
+ (hand-repaired in 79505fee8). `_write_host_models_aggregator` now RAISES
123
+ `AggregatorShrinkError` naming every schema that would be lost, and writes nothing.
124
+ Guard: `tests/schema_builder/test_host_models_aggregator.py`.
125
+
116
126
  `models_only=True` skips unrelated schema/type/helper outputs but still performs
117
127
  live introspection and writes the canonical generated Model file. The unfiltered
118
128
  command remains the release-wide regeneration path. A package target may declare
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: matrx-orm
3
- Version: 3.1.52
3
+ Version: 3.1.53
4
4
  Summary: Async-first PostgreSQL ORM with bidirectional migrations, schema introspection, many-to-many relationships, and built-in state caching
5
5
  Project-URL: Homepage, https://github.com/AI-Matrix-Engine/aidream-current
6
6
  Project-URL: Repository, https://github.com/AI-Matrix-Engine/aidream-current
@@ -8,7 +8,9 @@ Usage:
8
8
 
9
9
  from __future__ import annotations
10
10
 
11
+ import ast
11
12
  import os
13
+ import re
12
14
  import sys
13
15
  from pathlib import Path
14
16
  from typing import Any
@@ -408,8 +410,17 @@ def run_schema_generation(
408
410
  raise
409
411
 
410
412
  if not models_only:
413
+ # ALWAYS pass the FULL, unfiltered generate[] list. A scoped run
414
+ # (only_schemas={"hindsight"}) regenerates one schema module, but the
415
+ # aggregator must keep re-exporting EVERY host schema — it is the whole
416
+ # `from db.models import X` surface. Handing it the filtered list once
417
+ # truncated db/models/__init__.py to a single schema and broke imports
418
+ # repo-wide, silently at generation time (repaired by hand in 79505fee8).
411
419
  _write_host_models_aggregator(
412
- generate_list, python_root, output_config, host_schema_model_names
420
+ cfg.get("generate", []) or [],
421
+ python_root,
422
+ output_config,
423
+ host_schema_model_names,
413
424
  )
414
425
 
415
426
  # Declarative host→package DB wiring: resolve each incorporated package's
@@ -438,8 +449,73 @@ def run_schema_generation(
438
449
  _close_pools()
439
450
 
440
451
 
452
+ _AGGREGATOR_IMPORT_RE = re.compile(r"^from \.(\w+) import \*", re.MULTILINE)
453
+
454
+
455
+ class AggregatorShrinkError(RuntimeError):
456
+ """The host models aggregator was about to lose schemas or exported names."""
457
+
458
+
459
+ def _existing_aggregator_schemas(init_path: str) -> list[str]:
460
+ """Schemas currently re-exported by db/models/__init__.py (empty if absent)."""
461
+ try:
462
+ with open(init_path) as f:
463
+ return _AGGREGATOR_IMPORT_RE.findall(f.read())
464
+ except FileNotFoundError:
465
+ return []
466
+
467
+
468
+ _MODEL_BASES = {"Model", "MatrxEntity"}
469
+
470
+
471
+ def _module_model_names(models_dir: str, schema: str) -> list[str]:
472
+ """Read a generated schema module's MODEL class names WITHOUT importing it.
473
+
474
+ A scoped generation run only holds fresh names for the schema it regenerated;
475
+ every other schema's names come from its module on disk, so cross-schema
476
+ collision detection stays complete instead of scoped-down.
477
+
478
+ Mirrors ``Schema.model_export_names`` exactly: real Model/MatrxEntity classes
479
+ (tables, read-only views, the public ``Users`` stub) — NOT enums, NOT DTOs,
480
+ NOT managers, and NOT ``_unfetchable`` cross-schema FK stubs (a stub of a
481
+ sibling schema's table would otherwise fake a collision).
482
+ """
483
+ path = os.path.join(models_dir, f"{schema}.py")
484
+ try:
485
+ with open(path) as f:
486
+ tree = ast.parse(f.read(), filename=path)
487
+ except FileNotFoundError:
488
+ return []
489
+ except SyntaxError as e:
490
+ # Unreadable module ⇒ its names go undetected ⇒ a colliding name would
491
+ # silently stay in the flat namespace and bind whichever schema imported
492
+ # last. Never let that pass quietly.
493
+ vcprint(
494
+ f"[MATRX ORM] Could NOT parse {path} ({e}) — its model names are invisible "
495
+ "to cross-schema collision detection. Fix or regenerate that module.",
496
+ color="red",
497
+ )
498
+ return []
499
+ names: list[str] = []
500
+ for node in tree.body:
501
+ if not isinstance(node, ast.ClassDef):
502
+ continue
503
+ if not any(isinstance(b, ast.Name) and b.id in _MODEL_BASES for b in node.bases):
504
+ continue
505
+ is_stub = any(
506
+ isinstance(stmt, ast.Assign)
507
+ and any(isinstance(t, ast.Name) and t.id == "_unfetchable" for t in stmt.targets)
508
+ and isinstance(stmt.value, ast.Constant)
509
+ and stmt.value.value is True
510
+ for stmt in node.body
511
+ )
512
+ if not is_stub:
513
+ names.append(node.name)
514
+ return names
515
+
516
+
441
517
  def _write_host_models_aggregator(
442
- generate_list: list[dict[str, Any]],
518
+ all_generate_entries: list[dict[str, Any]],
443
519
  python_root: str,
444
520
  output_config: OutputConfig,
445
521
  host_schema_model_names: dict[str, list[str]] | None = None,
@@ -464,6 +540,13 @@ def _write_host_models_aggregator(
464
540
  single-file layout, so it is skipped here. ``public`` is imported first so
465
541
  its canonical models win over any cross-schema FK stub registered with
466
542
  skip_existing in a sibling schema.
543
+
544
+ ``all_generate_entries`` MUST be the full, unfiltered ``generate[]`` list —
545
+ NEVER the subset selected by ``only_schemas``. This file is the entire
546
+ ``from db.models import X`` surface; writing it from a scoped run's subset
547
+ truncates it to that one schema and breaks imports across the whole host
548
+ repo, with no error at generation time. The shrink guard below makes that
549
+ outcome impossible rather than merely discouraged.
467
550
  """
468
551
  if not (output_config.python and output_config.save_direct):
469
552
  return
@@ -471,7 +554,7 @@ def _write_host_models_aggregator(
471
554
  host_schema_model_names = host_schema_model_names or {}
472
555
 
473
556
  schemas: list[str] = []
474
- for entry in generate_list:
557
+ for entry in all_generate_entries:
475
558
  output_block = entry.get("output") or {}
476
559
  if output_block.get("python_root"):
477
560
  continue # package tree — not part of the host db/models package
@@ -485,13 +568,52 @@ def _write_host_models_aggregator(
485
568
  # public first (canonical models register before sibling stubs)
486
569
  schemas.sort(key=lambda s: (s != "public", s))
487
570
 
488
- # Detect model class names that exist in >1 host schema.
571
+ models_dir = os.path.join(python_root, "db", "models")
572
+ os.makedirs(models_dir, exist_ok=True)
573
+ init_path = os.path.join(models_dir, "__init__.py")
574
+
575
+ # Detect model class names that exist in >1 host schema. Names for schemas
576
+ # this run did NOT regenerate (a scoped `--schema X` pass) are read from
577
+ # their modules on disk, so collision detection is never scoped-down either.
489
578
  name_to_schemas: dict[str, set[str]] = {}
490
579
  for schema_name in schemas:
491
- for model_name in host_schema_model_names.get(schema_name, []):
580
+ model_names = host_schema_model_names.get(schema_name) or _module_model_names(
581
+ models_dir, schema_name
582
+ )
583
+ for model_name in model_names:
492
584
  name_to_schemas.setdefault(model_name, set()).add(schema_name)
493
585
  colliding = sorted(n for n, owners in name_to_schemas.items() if len(owners) > 1)
494
586
 
587
+ # -------------------------------------------------------------------------
588
+ # SHRINK GUARD — silent shrinkage of this file is repo-wide breakage.
589
+ # `from db.models import X` resolves through here; a lost schema import
590
+ # explodes far from generation time, at some unrelated module's import.
591
+ # -------------------------------------------------------------------------
592
+ previous_schemas = _existing_aggregator_schemas(init_path)
593
+ lost_schemas = [s for s in previous_schemas if s not in set(schemas)]
594
+ if lost_schemas:
595
+ vcprint(
596
+ "\n" + "=" * 80 + "\n"
597
+ "[MATRX ORM] REFUSING to shrink the host models aggregator.\n"
598
+ f" File: {init_path}\n"
599
+ f" Currently re-exports {len(previous_schemas)} schema(s); this run would "
600
+ f"write {len(schemas)}.\n"
601
+ f" Would LOSE: {', '.join(sorted(lost_schemas))}\n"
602
+ " Every `from db.models import X` for those schemas would break at import\n"
603
+ " time, far from here. The aggregator must always be written from the FULL\n"
604
+ " generate[] list in db/matrx_orm.yaml — never a scoped subset.\n"
605
+ " If a schema was intentionally removed from matrx_orm.yaml, delete its\n"
606
+ " db/models/<schema>.py and the stale import line by hand, then rerun.\n"
607
+ + "=" * 80
608
+ + "\n",
609
+ color="red",
610
+ )
611
+ raise AggregatorShrinkError(
612
+ f"host models aggregator would lose {len(lost_schemas)} schema(s): "
613
+ f"{', '.join(sorted(lost_schemas))} (had {len(previous_schemas)}, "
614
+ f"writing {len(schemas)})"
615
+ )
616
+
495
617
  lines = [
496
618
  "# File: db/models/__init__.py",
497
619
  "# AUTO-GENERATED by matrx-orm schema generation — do not edit by hand.",
@@ -522,9 +644,6 @@ def _write_host_models_aggregator(
522
644
  ]
523
645
  )
524
646
 
525
- models_dir = os.path.join(python_root, "db", "models")
526
- os.makedirs(models_dir, exist_ok=True)
527
- init_path = os.path.join(models_dir, "__init__.py")
528
647
  with open(init_path, "w") as f:
529
648
  f.write("\n".join(lines))
530
649
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "matrx-orm"
3
- version = "3.1.52"
3
+ version = "3.1.53"
4
4
  description = "Async-first PostgreSQL ORM with bidirectional migrations, schema introspection, many-to-many relationships, and built-in state caching"
5
5
  readme = "README.md"
6
6
  license = { text = "MIT" }
@@ -0,0 +1,171 @@
1
+ """The host db/models/__init__.py aggregator must never shrink.
2
+
3
+ A scoped generation run (`--schema hindsight`) once rewrote the aggregator down
4
+ to that one schema, breaking `from db.models import X` across the entire host
5
+ repo — silently, with the explosion arriving later at some unrelated import.
6
+ These tests exercise the real writer, not a stand-in.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import pytest
12
+ from matrx_orm.schema_builder.common import OutputConfig
13
+ from matrx_orm.schema_builder.runner import (
14
+ AggregatorShrinkError,
15
+ _select_generation_targets,
16
+ _write_host_models_aggregator,
17
+ )
18
+
19
+ FULL_GENERATE = [
20
+ {"database": "main", "schema": "public"},
21
+ {"database": "main", "schema": "agent"},
22
+ {"database": "main", "schema": "chat"},
23
+ {"database": "main", "schema": "hindsight"},
24
+ {"database": "main", "schema": "workflow"},
25
+ # A package-tree target: keeps its own layout, never joins the aggregator.
26
+ {"database": "main", "schema": "seo", "output": {"python_root": "packages/matrx-seo"}},
27
+ ]
28
+
29
+ HOST_SCHEMAS = {"public", "agent", "chat", "hindsight", "workflow"}
30
+
31
+
32
+ def _output_config() -> OutputConfig:
33
+ return OutputConfig(python=True, save_direct=True, typescript=False)
34
+
35
+
36
+ def _seed_models_tree(python_root, schema_models: dict[str, list[str]]) -> None:
37
+ """Write generated-shaped schema modules: real model classes, an enum, a DTO,
38
+ a manager, and an _unfetchable cross-schema FK stub — only the model classes
39
+ may ever count toward collision detection."""
40
+ models_dir = python_root / "db" / "models"
41
+ models_dir.mkdir(parents=True)
42
+ for schema, names in schema_models.items():
43
+ parts = [f'class {n}(Model):\n _table_name = "{n.lower()}"\n' for n in names]
44
+ parts.append('class Visibility(str, Enum):\n PUBLIC = "public"\n')
45
+ parts.append("class SomethingDTO(BaseDTO):\n id: str\n")
46
+ parts.append("class SomethingManager(BaseManager):\n pass\n")
47
+ parts.append(
48
+ 'class ForeignStub(Model):\n _table_name = "foreign"\n _unfetchable = True\n'
49
+ )
50
+ exports = "\n".join(f' "{n}",' for n in [*names, "Visibility"])
51
+ (models_dir / f"{schema}.py").write_text(
52
+ "\n".join(parts) + f"\n__all__ = [\n{exports}\n]\n"
53
+ )
54
+
55
+
56
+ def _write_aggregator(python_root, host_schema_model_names) -> str:
57
+ _write_host_models_aggregator(
58
+ FULL_GENERATE,
59
+ str(python_root),
60
+ _output_config(),
61
+ host_schema_model_names,
62
+ )
63
+ return (python_root / "db" / "models" / "__init__.py").read_text()
64
+
65
+
66
+ def test_scoped_generation_keeps_every_schema(tmp_path) -> None:
67
+ """The failure that actually happened: `--schema hindsight` must not truncate."""
68
+ _seed_models_tree(
69
+ tmp_path,
70
+ {
71
+ "public": ["Conversation", "AgentRun"],
72
+ "agent": ["Definition"],
73
+ "chat": ["AgentRun"],
74
+ "hindsight": ["Enrollment", "Review"],
75
+ "workflow": ["Definition"],
76
+ },
77
+ )
78
+
79
+ # Full run first — establishes the complete aggregator.
80
+ full_text = _write_aggregator(
81
+ tmp_path,
82
+ {
83
+ "public": ["Conversation", "AgentRun"],
84
+ "agent": ["Definition"],
85
+ "chat": ["AgentRun"],
86
+ "hindsight": ["Enrollment", "Review"],
87
+ "workflow": ["Definition"],
88
+ },
89
+ )
90
+ for schema in HOST_SCHEMAS:
91
+ assert f"from .{schema} import *" in full_text
92
+
93
+ # Now the scoped pass, exactly as db/generate.py --schema hindsight runs it:
94
+ # only the hindsight entry is selected, and only its fresh model names exist.
95
+ selected, _ = _select_generation_targets(FULL_GENERATE, {"hindsight"})
96
+ assert [e["schema"] for e in selected] == ["hindsight"]
97
+
98
+ scoped_text = _write_aggregator(tmp_path, {"hindsight": ["Enrollment", "Review", "Replay"]})
99
+
100
+ for schema in HOST_SCHEMAS:
101
+ assert f"from .{schema} import *" in scoped_text, (
102
+ f"scoped run dropped schema {schema!r} from the aggregator"
103
+ )
104
+ assert scoped_text.count("import *") == len(HOST_SCHEMAS)
105
+ # A package-tree entry never joins the host aggregator.
106
+ assert "from .seo import *" not in scoped_text
107
+
108
+
109
+ def test_scoped_generation_preserves_cross_schema_collisions(tmp_path) -> None:
110
+ """Names for un-regenerated schemas come from disk, so de-flattening survives."""
111
+ _seed_models_tree(
112
+ tmp_path,
113
+ {
114
+ "public": ["Conversation", "AgentRun"],
115
+ "agent": ["Definition"],
116
+ "chat": ["AgentRun"],
117
+ "hindsight": ["Enrollment"],
118
+ "workflow": ["Definition"],
119
+ },
120
+ )
121
+ text = _write_aggregator(tmp_path, {"hindsight": ["Enrollment"]})
122
+
123
+ assert '"AgentRun",' in text # public/chat
124
+ assert '"Definition",' in text # agent/workflow
125
+ assert '"Enrollment",' not in text # unique — stays in the flat namespace
126
+ # Enums, DTOs, managers and _unfetchable FK stubs exist in EVERY seeded
127
+ # module; counting them would fabricate collisions across all 5 schemas.
128
+ for non_model in ('"Visibility",', '"SomethingDTO",', '"SomethingManager",', '"ForeignStub",'):
129
+ assert non_model not in text
130
+
131
+
132
+ def test_shrinking_the_aggregator_raises_and_names_the_losses(tmp_path) -> None:
133
+ """A subset generate[] list is refused outright, not written."""
134
+ _seed_models_tree(tmp_path, {s: [f"Model{s.title()}"] for s in HOST_SCHEMAS})
135
+ _write_aggregator(tmp_path, {s: [f"Model{s.title()}"] for s in HOST_SCHEMAS})
136
+
137
+ init_path = tmp_path / "db" / "models" / "__init__.py"
138
+ before = init_path.read_text()
139
+
140
+ subset = [{"database": "main", "schema": "hindsight"}]
141
+ with pytest.raises(AggregatorShrinkError) as excinfo:
142
+ _write_host_models_aggregator(
143
+ subset,
144
+ str(tmp_path),
145
+ _output_config(),
146
+ {"hindsight": ["Enrollment"]},
147
+ )
148
+
149
+ message = str(excinfo.value)
150
+ for lost in HOST_SCHEMAS - {"hindsight"}:
151
+ assert lost in message
152
+ # Refused means REFUSED — the file on disk is untouched.
153
+ assert init_path.read_text() == before
154
+
155
+
156
+ def test_adding_a_new_schema_still_registers(tmp_path) -> None:
157
+ """The guard blocks loss, never growth."""
158
+ _seed_models_tree(tmp_path, {s: [f"Model{s.title()}"] for s in HOST_SCHEMAS})
159
+ _write_aggregator(tmp_path, {s: [f"Model{s.title()}"] for s in HOST_SCHEMAS})
160
+
161
+ grown = FULL_GENERATE + [{"database": "main", "schema": "brandnew"}]
162
+ _write_host_models_aggregator(
163
+ grown,
164
+ str(tmp_path),
165
+ _output_config(),
166
+ {"brandnew": ["Shiny"]},
167
+ )
168
+ text = (tmp_path / "db" / "models" / "__init__.py").read_text()
169
+ assert "from .brandnew import *" in text
170
+ for schema in HOST_SCHEMAS:
171
+ assert f"from .{schema} import *" in text
File without changes
File without changes
File without changes
File without changes