matrx-orm 3.0.30__tar.gz → 3.0.32__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 (187) hide show
  1. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/PKG-INFO +3 -1
  2. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/README.md +2 -0
  3. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/pyproject.toml +1 -1
  4. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/schema_builder/columns.py +4 -2
  5. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/schema_builder/diff_preview.py +42 -1
  6. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/schema_builder/schema.py +110 -7
  7. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/schema_builder/tables.py +8 -2
  8. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/sample_project/matrx_orm.yaml +19 -0
  9. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/.arman/pending/versioning/INITIAL.md +0 -0
  10. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/.env.example +0 -0
  11. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/.github/workflows/publish.yml +0 -0
  12. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/.gitignore +0 -0
  13. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/.python-version +0 -0
  14. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/.vscode/settings.json +0 -0
  15. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/CLAUDE.md +0 -0
  16. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/DESKTOP-API-INTEGRATION.md +0 -0
  17. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/MIGRATIONS.md +0 -0
  18. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/MODULE_README.md +0 -0
  19. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/RESERVED_NAMES.md +0 -0
  20. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/TASKS-TEMPLATE.md +0 -0
  21. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/TASKS.md +0 -0
  22. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/TRANSACTION_POOLER_PLAN.MD +0 -0
  23. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/WRITE-QUEUE-UPGRADE.md +0 -0
  24. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/database/orm/extended/managers/ai_model_base.py +0 -0
  25. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/docs/migrations.md +0 -0
  26. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/extended_jan5_backup.py +0 -0
  27. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/main.py +0 -0
  28. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/release.sh +0 -0
  29. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/scripts/git-branches.sh +0 -0
  30. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/scripts/publish.sh +0 -0
  31. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/scripts/release.sh +0 -0
  32. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/MODULE_README.md +0 -0
  33. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/MODULE_README.md +0 -0
  34. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/__init__.py +0 -0
  35. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/adapters/MODULE_README.md +0 -0
  36. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/adapters/__init__.py +0 -0
  37. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/adapters/async_postgresql.py +0 -0
  38. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/adapters/base_adapter.py +0 -0
  39. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/adapters/postgresql.py +0 -0
  40. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/adapters/postgrest_client_adapter.py +0 -0
  41. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/adapters/supabase_adapter.py +0 -0
  42. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/api/__init__.py +0 -0
  43. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/api/auth.py +0 -0
  44. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/api/config.py +0 -0
  45. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/api/handlers.py +0 -0
  46. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/api/protocol.py +0 -0
  47. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/api/server.py +0 -0
  48. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/client/MODULE_README.md +0 -0
  49. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/client/__init__.py +0 -0
  50. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/client/postgres_connection.py +0 -0
  51. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/client/postgrest.py +0 -0
  52. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/client/supabase_auth.py +0 -0
  53. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/client/supabase_config.py +0 -0
  54. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/client/supabase_manager.py +0 -0
  55. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/core/EXTENDED-TASK.md +0 -0
  56. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/core/MODULE_README.md +0 -0
  57. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/core/RELATIONS-TASKS.md +0 -0
  58. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/core/TASKS.md +0 -0
  59. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/core/__init__.py +0 -0
  60. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/core/async_db_manager.py +0 -0
  61. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/core/base.py +0 -0
  62. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/core/config.py +0 -0
  63. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/core/expressions.py +0 -0
  64. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/core/extended.py +0 -0
  65. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/core/fields.py +0 -0
  66. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/core/model_dto.py +0 -0
  67. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/core/model_view.py +0 -0
  68. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/core/paginator.py +0 -0
  69. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/core/pydantic_bridge.py +0 -0
  70. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/core/registry.py +0 -0
  71. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/core/relations.py +0 -0
  72. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/core/signals.py +0 -0
  73. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/core/transaction.py +0 -0
  74. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/core/types.py +0 -0
  75. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/core/write_queue.py +0 -0
  76. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/error_handling.py +0 -0
  77. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/exceptions.py +0 -0
  78. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/extended/__init__.py +0 -0
  79. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/extended/app_error_handler.py +0 -0
  80. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/middleware/__init__.py +0 -0
  81. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/middleware/base.py +0 -0
  82. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/migrations/MODULE_README.md +0 -0
  83. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/migrations/__init__.py +0 -0
  84. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/migrations/cli.py +0 -0
  85. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/migrations/ddl.py +0 -0
  86. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/migrations/diff.py +0 -0
  87. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/migrations/executor.py +0 -0
  88. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/migrations/integration.py +0 -0
  89. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/migrations/loader.py +0 -0
  90. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/migrations/operations.py +0 -0
  91. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/migrations/state.py +0 -0
  92. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/migrations/table_filter.py +0 -0
  93. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/operations/MODULE_README.md +0 -0
  94. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/operations/__init__.py +0 -0
  95. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/operations/create.py +0 -0
  96. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/operations/delete.py +0 -0
  97. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/operations/read.py +0 -0
  98. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/operations/update.py +0 -0
  99. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/py.typed +0 -0
  100. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/python_sql/MODULE_README.md +0 -0
  101. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/python_sql/__init__.py +0 -0
  102. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/python_sql/db_objects.py +0 -0
  103. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/python_sql/table_detailed_relationships.py +0 -0
  104. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/python_sql/table_typescript_relationship.py +0 -0
  105. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/query/MODULE_README.md +0 -0
  106. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/query/__init__.py +0 -0
  107. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/query/builder.py +0 -0
  108. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/query/executor.py +0 -0
  109. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/schema_builder/MODULE_README.md +0 -0
  110. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/schema_builder/__init__.py +0 -0
  111. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/schema_builder/code_handler.py +0 -0
  112. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/schema_builder/common.py +0 -0
  113. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/schema_builder/generator.py +0 -0
  114. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/schema_builder/helpers/__init__.py +0 -0
  115. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/schema_builder/helpers/base_generators.py +0 -0
  116. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/schema_builder/helpers/entity_generators.py +0 -0
  117. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/schema_builder/helpers/git_checker.py +0 -0
  118. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/schema_builder/relationships.py +0 -0
  119. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/schema_builder/runner.py +0 -0
  120. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/schema_builder/schema_manager.py +0 -0
  121. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/schema_builder/views.py +0 -0
  122. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/sql_executor/MODULE_README.md +0 -0
  123. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/sql_executor/__init__.py +0 -0
  124. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/sql_executor/executor.py +0 -0
  125. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/sql_executor/queries.py +0 -0
  126. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/sql_executor/registry.py +0 -0
  127. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/sql_executor/types.py +0 -0
  128. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/sql_executor/utils.py +0 -0
  129. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/state.py +0 -0
  130. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/utils/__init__.py +0 -0
  131. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/utils/sql_utils.py +0 -0
  132. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/src/matrx_orm/utils/type_converters.py +0 -0
  133. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/MODULE_README.md +0 -0
  134. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/__init__.py +0 -0
  135. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/conftest.py +0 -0
  136. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/level1/MODULE_README.md +0 -0
  137. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/level1/__init__.py +0 -0
  138. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/level1/test_api_auth.py +0 -0
  139. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/level1/test_api_config.py +0 -0
  140. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/level1/test_api_handlers.py +0 -0
  141. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/level1/test_api_protocol.py +0 -0
  142. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/level1/test_config.py +0 -0
  143. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/level1/test_ddl_generator.py +0 -0
  144. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/level1/test_exceptions.py +0 -0
  145. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/level1/test_fields.py +0 -0
  146. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/level1/test_migration_diff_types.py +0 -0
  147. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/level1/test_migration_loader.py +0 -0
  148. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/level1/test_model_instance.py +0 -0
  149. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/level1/test_model_meta.py +0 -0
  150. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/level1/test_postgrest_filters.py +0 -0
  151. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/level1/test_query_builder.py +0 -0
  152. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/level1/test_query_executor_sql.py +0 -0
  153. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/level1/test_registry.py +0 -0
  154. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/level1/test_relations.py +0 -0
  155. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/level1/test_state_cache.py +0 -0
  156. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/level1/test_supabase_auth.py +0 -0
  157. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/level1/test_supabase_config.py +0 -0
  158. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/level2/MODULE_README.md +0 -0
  159. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/level2/__init__.py +0 -0
  160. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/level2/conftest.py +0 -0
  161. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/level2/test_bulk_ops.py +0 -0
  162. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/level2/test_cache_integration.py +0 -0
  163. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/level2/test_crud.py +0 -0
  164. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/level2/test_foreign_keys.py +0 -0
  165. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/level2/test_m2m.py +0 -0
  166. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/level2/test_manager.py +0 -0
  167. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/level2/test_migrations_live.py +0 -0
  168. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/level2/test_query_execution.py +0 -0
  169. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/level2/test_schema_diff.py +0 -0
  170. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/sample_project/.env.example +0 -0
  171. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/sample_project/README.md +0 -0
  172. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/sample_project/__init__.py +0 -0
  173. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/sample_project/generate.py +0 -0
  174. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/sample_project/generated/.gitkeep +0 -0
  175. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/sample_project/test_schema_generation.py +0 -0
  176. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/sample_project_desktop/.env.example +0 -0
  177. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/sample_project_desktop/README.md +0 -0
  178. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/sample_project_desktop/__init__.py +0 -0
  179. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/sample_project_desktop/client_example.py +0 -0
  180. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/sample_project_desktop/client_example.ts +0 -0
  181. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/sample_project_desktop/client_supabase_example.py +0 -0
  182. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/sample_project_desktop/server.py +0 -0
  183. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/schema/entity_tests.py +0 -0
  184. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/schema/test_base_generation.py +0 -0
  185. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/schema/test_generate_schema.py +0 -0
  186. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/tests/test_model_cls_refactor.py +0 -0
  187. {matrx_orm-3.0.30 → matrx_orm-3.0.32}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: matrx-orm
3
- Version: 3.0.30
3
+ Version: 3.0.32
4
4
  Summary: Async-first PostgreSQL ORM with bidirectional migrations, schema introspection, many-to-many relationships, and built-in state caching. Works with any PostgreSQL database.
5
5
  Project-URL: Homepage, https://github.com/armanisadeghi/matrx-orm
6
6
  Project-URL: Repository, https://github.com/armanisadeghi/matrx-orm
@@ -1838,6 +1838,8 @@ When you run the schema builder against a database that has `vector(n)` columns,
1838
1838
 
1839
1839
  | Version | Highlights |
1840
1840
  |---|---|
1841
+ | **v3.0.32** | Patch release |
1842
+ | **v3.0.31** | Patch release |
1841
1843
  | **v3.0.30** | Patch release |
1842
1844
  | **v3.0.29** | Patch release |
1843
1845
  | **v3.0.28** | Patch release |
@@ -1795,6 +1795,8 @@ When you run the schema builder against a database that has `vector(n)` columns,
1795
1795
 
1796
1796
  | Version | Highlights |
1797
1797
  |---|---|
1798
+ | **v3.0.32** | Patch release |
1799
+ | **v3.0.31** | Patch release |
1798
1800
  | **v3.0.30** | Patch release |
1799
1801
  | **v3.0.29** | Patch release |
1800
1802
  | **v3.0.28** | Patch release |
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "matrx-orm"
3
- version = "3.0.30"
3
+ version = "3.0.32"
4
4
  description = "Async-first PostgreSQL ORM with bidirectional migrations, schema introspection, many-to-many relationships, and built-in state caching. Works with any PostgreSQL database."
5
5
  readme = "README.md"
6
6
  license = { text = "MIT" }
@@ -1266,7 +1266,7 @@ class Column:
1266
1266
  )
1267
1267
  return self.calc_max_length
1268
1268
 
1269
- def to_python_model_field(self):
1269
+ def to_python_model_field(self, forward_ref_tables: set[str] | None = None):
1270
1270
  field_options = []
1271
1271
  if self.is_primary_key:
1272
1272
  field_options.append("primary_key=True")
@@ -1315,7 +1315,9 @@ class Column:
1315
1315
  to_schema_arg = ""
1316
1316
  if fk_schema and fk_schema != "public":
1317
1317
  to_schema_arg = f", to_schema='{fk_schema}'"
1318
- if related_model == self.utils.to_pascal_case(self.table_name):
1318
+ is_self_ref = related_model == self.utils.to_pascal_case(self.table_name)
1319
+ is_forward_ref = forward_ref_tables is not None and related_model in forward_ref_tables
1320
+ if is_self_ref or is_forward_ref:
1319
1321
  field_def = f"{self.name} = ForeignKey(to_model='{related_model}', to_column='{self.foreign_key_reference['column']}'{to_schema_arg}, {options_str})"
1320
1322
  else:
1321
1323
  field_def = f"{self.name} = ForeignKey(to_model={related_model}, to_column='{self.foreign_key_reference['column']}'{to_schema_arg}, {options_str})"
@@ -361,6 +361,7 @@ def parse_models_file(path: str | Path) -> tuple[dict[str, TableSnapshot], dict[
361
361
  m2m_config: dict[str, dict[str, str]] = {}
362
362
  database: str | None = None
363
363
  table_name_override: str | None = None
364
+ db_schema: str | None = None
364
365
 
365
366
  for item in node.body:
366
367
  if isinstance(item, (ast.Assign, ast.AnnAssign)):
@@ -395,6 +396,13 @@ def parse_models_file(path: str | Path) -> tuple[dict[str, TableSnapshot], dict[
395
396
  pass
396
397
  continue
397
398
 
399
+ if attr_name == "_db_schema":
400
+ try:
401
+ db_schema = ast.literal_eval(value)
402
+ except (ValueError, TypeError):
403
+ pass
404
+ continue
405
+
398
406
  if attr_name == "_inverse_foreign_keys":
399
407
  try:
400
408
  ifk_config = ast.literal_eval(value)
@@ -416,6 +424,12 @@ def parse_models_file(path: str | Path) -> tuple[dict[str, TableSnapshot], dict[
416
424
  field_type, kwargs = _parse_field_call(value)
417
425
  fields[attr_name] = _kwargs_to_field_snapshot(attr_name, field_type, kwargs)
418
426
 
427
+ # Skip cross-schema stub models (e.g. Users with _db_schema="auth").
428
+ # They are hardcoded in generate_models() and don't correspond to any
429
+ # introspected table in the target schema.
430
+ if db_schema is not None:
431
+ continue
432
+
419
433
  snake_name = table_name_override or _pascal_to_snake(class_name)
420
434
 
421
435
  snapshot = TableSnapshot(
@@ -451,6 +465,33 @@ def _pascal_to_snake(name: str) -> str:
451
465
  # Table-to-snapshot converter — extract TableSnapshot from a schema_builder Table
452
466
  # ---------------------------------------------------------------------------
453
467
 
468
+ def _normalize_python_default(value: Any) -> Any:
469
+ """Apply the same default-value normalization as Column.to_python_model_field().
470
+
471
+ The generator converts raw ``clean_default["python"]`` values before writing
472
+ them into model source code (e.g. the string ``"false"`` becomes the Python
473
+ boolean ``False``). This function mirrors that logic so the snapshot
474
+ produced from a Table object is directly comparable to what the AST parser
475
+ extracts from generated code.
476
+ """
477
+ if isinstance(value, (bool, int, float, dict, list)):
478
+ return value
479
+ if isinstance(value, str):
480
+ if value == "false":
481
+ return False
482
+ if value == "true":
483
+ return True
484
+ try:
485
+ import ast as _ast
486
+ parsed = _ast.literal_eval(value)
487
+ if isinstance(parsed, (bool, int, float, dict, list)):
488
+ return parsed
489
+ return value
490
+ except (ValueError, SyntaxError):
491
+ return value
492
+ return value
493
+
494
+
454
495
  def table_to_snapshot(table: Any) -> TableSnapshot:
455
496
  """Convert a schema_builder.tables.Table into a TableSnapshot."""
456
497
  from matrx_orm.schema_builder.common import dt_utils
@@ -496,7 +537,7 @@ def table_to_snapshot(table: Any) -> TableSnapshot:
496
537
  if column.clean_default is not None:
497
538
  py_default = column.clean_default.get("python")
498
539
  if py_default is not None and py_default != "":
499
- default_val = repr(py_default)
540
+ default_val = repr(_normalize_python_default(py_default))
500
541
 
501
542
  fields[column.name] = FieldSnapshot(
502
543
  name=column.name,
@@ -778,12 +778,62 @@ class Schema:
778
778
  _database = \"{self.database_project}\"\n"""
779
779
  return users_model
780
780
 
781
- def get_string_model_registry(self, sorted_tables: list[str]) -> str:
782
- # Only register the models that are actually defined in this file.
783
- # When include_tables / exclude_tables is active, sorted_tables is the
784
- # filtered subset registering the full schema would produce NameErrors
785
- # for every class that wasn't generated.
781
+ def _utils_for_stubs(self):
782
+ return self.utils
783
+
784
+ def _generate_stub_model(self, table_name: str) -> str:
785
+ """Return a minimal Model stub for *table_name*.
786
+
787
+ If the table was introspected (i.e. exists in ``self.tables``), the
788
+ stub includes the real PK column(s) and their types. Otherwise a
789
+ generic ``id = UUIDField(primary_key=True, null=False)`` is emitted.
790
+
791
+ The stub carries ``_unfetchable = True`` so the ORM never tries to
792
+ query through it (the real table may not be in scope).
793
+ """
794
+ utils = self._utils_for_stubs()
795
+ pascal_name = utils.to_pascal_case(table_name)
796
+
797
+ if table_name in self.tables:
798
+ table = self.tables[table_name]
799
+ pk_lines = []
800
+ for col in table.columns:
801
+ if col.is_primary_key:
802
+ pk_lines.append(
803
+ f" {col.name} = {col.python_field_type}"
804
+ f"(primary_key=True, null=False)"
805
+ )
806
+ if not pk_lines:
807
+ pk_lines = [" id = UUIDField(primary_key=True, null=False)"]
808
+ else:
809
+ pk_lines = [" id = UUIDField(primary_key=True, null=False)"]
810
+
811
+ pk_block = "\n".join(pk_lines)
812
+ return (
813
+ f"class {pascal_name}(Model):\n"
814
+ f"{pk_block}\n"
815
+ f" _table_name = \"{table_name}\"\n"
816
+ f" _database = \"{self.database_project}\"\n"
817
+ f" _unfetchable = True\n"
818
+ )
819
+
820
+ def get_string_model_registry(
821
+ self,
822
+ sorted_tables: list[str],
823
+ stub_model_names: set[str] | None = None,
824
+ ) -> str:
825
+ # Register every model class defined in the file: included tables,
826
+ # stub models for FK dependencies, and the Users stub.
786
827
  all_models = [self.tables[t].name_pascal for t in sorted_tables]
828
+ if stub_model_names:
829
+ utils = self._utils_for_stubs()
830
+ for sn in sorted(stub_model_names):
831
+ pascal = (
832
+ self.tables[sn].name_pascal
833
+ if sn in self.tables
834
+ else utils.to_pascal_case(sn)
835
+ )
836
+ all_models.append(pascal)
787
837
  all_models.append("Users") # Users stub is always generated
788
838
 
789
839
  model_registry_string = (
@@ -842,9 +892,60 @@ class Schema:
842
892
  py_structure = [self.get_string_user_model()]
843
893
  all_field_types = {"UUIDField", "CharField", "Model"}
844
894
 
895
+ # --- Stub generation for FK targets outside the filtered set ----------
896
+ # When include_tables / exclude_tables is active, included tables may
897
+ # reference models that aren't being generated. We emit minimal stub
898
+ # classes for those targets so FK declarations resolve without NameError
899
+ # and resolve_model() can find them in the registry at runtime.
900
+ sorted_set = set(sorted_tables)
901
+ _stub_model_names: set[str] = set()
902
+
903
+ if self._include_tables is not None or self._exclude_tables is not None:
904
+ for table_name in sorted_tables:
905
+ table = self.tables[table_name]
906
+ for col in table.columns:
907
+ if col.foreign_key_reference:
908
+ target_snake = col.foreign_key_reference["table"]
909
+ fk_schema = col.foreign_key_reference.get("schema")
910
+ if fk_schema and fk_schema != "public":
911
+ continue # cross-schema (e.g. auth.users) — stub already exists
912
+ if target_snake not in sorted_set:
913
+ _stub_model_names.add(target_snake)
914
+
915
+ for stub_table_name in sorted(_stub_model_names):
916
+ py_structure.append(
917
+ self._generate_stub_model(stub_table_name)
918
+ )
919
+
920
+ # --- Build position map for forward-reference detection ---------------
921
+ # Stubs are defined before any included table (position -1 conceptually),
922
+ # so they never need forward references.
923
+ _table_positions = {name: i for i, name in enumerate(sorted_tables)}
924
+ _defined_stubs = {
925
+ self.tables[s].name_pascal if s in self.tables
926
+ else self._utils_for_stubs().to_pascal_case(s)
927
+ for s in _stub_model_names
928
+ }
929
+
845
930
  for table_name in sorted_tables:
846
931
  table = self.tables[table_name]
847
- py_table_entry = table.to_python_model()
932
+ my_pos = _table_positions[table_name]
933
+ forward_ref_tables: set[str] = set()
934
+ for col in table.columns:
935
+ if col.foreign_key_reference:
936
+ target_snake = col.foreign_key_reference["table"]
937
+ target_pos = _table_positions.get(target_snake)
938
+ if target_pos is not None and target_pos > my_pos:
939
+ forward_ref_tables.add(
940
+ table.utils.to_pascal_case(target_snake)
941
+ )
942
+ elif target_pos is None:
943
+ target_pascal = table.utils.to_pascal_case(target_snake)
944
+ if target_pascal != "Users" and target_pascal not in _defined_stubs:
945
+ forward_ref_tables.add(target_pascal)
946
+ py_table_entry = table.to_python_model(
947
+ forward_ref_tables=forward_ref_tables or None
948
+ )
848
949
  py_structure.append(py_table_entry)
849
950
  all_field_types.update(table.unique_field_types)
850
951
 
@@ -900,7 +1001,9 @@ class Schema:
900
1001
  color="cyan",
901
1002
  )
902
1003
 
903
- py_structure.append(self.get_string_model_registry(sorted_tables))
1004
+ py_structure.append(
1005
+ self.get_string_model_registry(sorted_tables, _stub_model_names)
1006
+ )
904
1007
 
905
1008
  main_code = "\n".join(py_structure)
906
1009
  additional_code = "\n".join(py_manager_structure)
@@ -1079,9 +1079,15 @@ class Table:
1079
1079
  }
1080
1080
  return m2m_config
1081
1081
 
1082
- def to_python_model(self):
1082
+ def to_python_model(self, forward_ref_tables: set[str] | None = None):
1083
1083
  """
1084
1084
  Builds the Python class model string with dynamic foreign keys.
1085
+
1086
+ *forward_ref_tables* is an optional set of PascalCase model names that
1087
+ will be defined later in the file. FKs targeting these models are
1088
+ emitted as string forward references (``to_model='Foo'``) instead of
1089
+ bare class references (``to_model=Foo``), avoiding ``NameError`` from
1090
+ circular FK dependencies.
1085
1091
  """
1086
1092
  py_fields = []
1087
1093
  self.unique_field_types = set()
@@ -1090,7 +1096,7 @@ class Table:
1090
1096
 
1091
1097
  # Process regular fields for the model
1092
1098
  for column in self.columns:
1093
- py_field = column.to_python_model_field()
1099
+ py_field = column.to_python_model_field(forward_ref_tables=forward_ref_tables)
1094
1100
  py_fields.append(py_field)
1095
1101
 
1096
1102
  if column.foreign_key_reference:
@@ -90,6 +90,25 @@ generate:
90
90
  # This dramatically reduces git noise on large schemas. Default: false.
91
91
  # skip_unchanged_managers: true
92
92
  manager_flags:
93
+ # models_module_path — the Python import path used in each generated
94
+ # manager file to import the model class from models.py.
95
+ #
96
+ # Default: "db.models" → from db.models import MyModel
97
+ #
98
+ # Override this when the generated db/ package is not at the root of your
99
+ # Python path. For example, if your project is structured as a package:
100
+ #
101
+ # mypackage/
102
+ # db/
103
+ # models.py
104
+ # managers/
105
+ #
106
+ # and you import things as `from mypackage.db.models import ...`, set:
107
+ #
108
+ # models_module_path: "mypackage.db.models"
109
+ #
110
+ # models_module_path: "db.models"
111
+ #
93
112
  include_core_relations: true # FK/IFK fetch methods (load_by_*, fetch_fk, fetch_ifk)
94
113
  include_filter_fields: true # filter_by_* methods for indexed/common lookup fields
95
114
  include_active_relations: false # active-record style relation traversal
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes