matrx-orm 3.1.28__tar.gz → 3.1.30__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 (320) hide show
  1. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/BASE_CLASS_METHODS.md +110 -148
  2. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/CLAUDE.md +5 -1
  3. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/MODEL_API.md +4 -17
  4. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/PKG-INFO +1 -1
  5. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/__init__.py +37 -4
  6. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/adapters/MODULE_README.md +0 -7
  7. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/adapters/__init__.py +7 -6
  8. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/adapters/async_postgresql.py +6 -0
  9. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/adapters/base_adapter.py +1 -0
  10. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/adapters/postgresql.py +5 -11
  11. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/adapters/postgrest_client_adapter.py +22 -19
  12. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/adapters/supabase_adapter.py +7 -0
  13. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/admin/router.py +22 -53
  14. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/api/auth.py +1 -3
  15. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/api/handlers.py +3 -8
  16. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/api/server.py +28 -44
  17. matrx_orm-3.1.30/matrx_orm/catalog.py +617 -0
  18. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/client/__init__.py +1 -1
  19. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/client/postgres_connection.py +19 -10
  20. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/client/postgrest.py +27 -29
  21. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/client/supabase_auth.py +10 -30
  22. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/client/supabase_config.py +1 -2
  23. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/client/supabase_manager.py +10 -30
  24. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/core/MODULE_README.md +0 -2
  25. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/core/async_db_manager.py +4 -31
  26. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/core/base.py +17 -54
  27. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/core/config.py +0 -11
  28. matrx_orm-3.1.30/matrx_orm/core/connections.py +72 -0
  29. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/core/expressions.py +774 -167
  30. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/core/introspection.py +1 -3
  31. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/core/model_dto.py +5 -12
  32. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/core/model_view.py +4 -7
  33. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/core/paginator.py +3 -0
  34. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/core/registry.py +4 -1
  35. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/core/relations.py +13 -5
  36. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/core/rls_session.py +1 -0
  37. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/core/signals.py +1 -0
  38. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/core/transaction.py +6 -57
  39. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/core/types.py +1 -2
  40. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/core/write_queue.py +2 -0
  41. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/entity.py +3 -9
  42. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/extended/app_error_handler.py +9 -2
  43. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/identity_rule.py +1 -5
  44. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/middleware/base.py +3 -1
  45. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/migrations/cli.py +21 -13
  46. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/migrations/ddl.py +11 -14
  47. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/migrations/diff.py +106 -49
  48. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/operations/bulk_update_values.py +17 -11
  49. matrx_orm-3.1.30/matrx_orm/operations/conflict.py +128 -0
  50. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/operations/conflict_writes.py +22 -34
  51. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/operations/dynamic_admin.py +14 -28
  52. matrx_orm-3.1.30/matrx_orm/operations/dynamic_crud.py +179 -0
  53. matrx_orm-3.1.30/matrx_orm/operations/graph_walk.py +141 -0
  54. matrx_orm-3.1.30/matrx_orm/operations/latest_rows.py +177 -0
  55. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/operations/queue_claim.py +94 -40
  56. matrx_orm-3.1.30/matrx_orm/operations/relational_backfill.py +195 -0
  57. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/operations/staging_load.py +145 -84
  58. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/python_sql/table_typescript_relationship.py +5 -2
  59. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/query/MODULE_README.md +1 -2
  60. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/query/builder.py +70 -137
  61. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/query/executor.py +107 -41
  62. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/schema_builder/codegen_writer.py +7 -1
  63. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/schema_builder/diff_preview.py +51 -19
  64. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/schema_builder/generator.py +1 -3
  65. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/schema_builder/helpers/__init__.py +0 -1
  66. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/schema_builder/helpers/entity_generators.py +2 -5
  67. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/schema_builder/helpers/git_checker.py +18 -6
  68. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/schema_builder/package_wiring.py +7 -12
  69. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/schema_builder/relationships.py +2 -6
  70. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/schema_builder/runner.py +4 -10
  71. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/schema_builder/schema_manager.py +40 -74
  72. matrx_orm-3.1.30/matrx_orm/secrets_battery/FEATURE.md +197 -0
  73. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/secrets_battery/__init__.py +73 -1
  74. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/secrets_battery/crypto.py +27 -0
  75. matrx_orm-3.1.30/matrx_orm/secrets_battery/items.py +1172 -0
  76. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/secrets_battery/model.py +60 -7
  77. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/secrets_battery/org_service.py +20 -1
  78. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/secrets_battery/service.py +93 -15
  79. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/session/coalesce.py +50 -24
  80. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/session/fallback.py +1 -3
  81. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/session/flush.py +4 -4
  82. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/session/lifecycle.py +44 -54
  83. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/session/managed.py +7 -12
  84. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/session/session.py +1 -0
  85. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/session/telemetry.py +15 -4
  86. matrx_orm-3.1.30/matrx_orm/sql_executor/__init__.py +25 -0
  87. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/sql_executor/executor.py +34 -35
  88. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/sql_executor/queries.py +2 -0
  89. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/sql_executor/registry.py +13 -9
  90. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/sql_executor/types.py +5 -1
  91. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/sql_executor/utils.py +18 -9
  92. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/utils/type_converters.py +9 -3
  93. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/pyproject.toml +1 -1
  94. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_admin_db_columns.py +45 -34
  95. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_advisory_lock.py +0 -1
  96. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_api_auth.py +0 -1
  97. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_api_config.py +0 -2
  98. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_api_handlers.py +1 -2
  99. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_api_protocol.py +2 -3
  100. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_array_agg_order_by.py +18 -7
  101. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_associations.py +0 -1
  102. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_bulk_update_by_pk.py +26 -3
  103. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_bulk_upsert_increment_set_fields.py +17 -17
  104. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_call_function.py +0 -1
  105. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_case_when.py +81 -59
  106. matrx_orm-3.1.30/tests/level1/test_catalog.py +247 -0
  107. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_composite_pk_filter.py +1 -2
  108. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_composite_pk_write_paths.py +4 -5
  109. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_config.py +0 -1
  110. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_conflict_target.py +24 -17
  111. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_conflict_writes.py +25 -9
  112. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_connection_codecs.py +0 -1
  113. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_connection_poison_guard.py +0 -1
  114. matrx_orm-3.1.30/tests/level1/test_connection_primitives.py +80 -0
  115. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_ddl_generator.py +0 -1
  116. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_dirty_tracking.py +0 -1
  117. matrx_orm-3.1.30/tests/level1/test_dynamic_crud.py +146 -0
  118. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_expression_primitives.py +39 -3
  119. matrx_orm-3.1.30/tests/level1/test_filter_jsonb_agg_array_index.py +101 -0
  120. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_from_alias.py +11 -21
  121. matrx_orm-3.1.30/tests/level1/test_graph_walk.py +106 -0
  122. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_having_annotate_alias.py +12 -43
  123. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_insert_ignore_and_admin_primitives.py +45 -80
  124. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_join_and_aggregate.py +15 -19
  125. matrx_orm-3.1.30/tests/level1/test_latest_rows.py +119 -0
  126. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_listen_notify.py +0 -1
  127. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_managed_write_guard.py +1 -2
  128. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_matrx_entity.py +0 -1
  129. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_migration_diff_types.py +6 -8
  130. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_migration_loader.py +1 -2
  131. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_model_instance.py +1 -2
  132. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_model_meta.py +2 -3
  133. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_order_by_expression.py +0 -2
  134. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_patch_jsonb_path.py +0 -1
  135. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_pool_maintenance.py +0 -1
  136. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_postgrest_filters.py +0 -1
  137. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_query_builder.py +1 -2
  138. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_query_executor_sql.py +1 -2
  139. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_querybuilder_clone_semantics.py +9 -6
  140. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_queue_claim.py +84 -19
  141. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_registry.py +1 -2
  142. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_registry_multi_database.py +0 -3
  143. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_registry_multi_schema.py +1 -2
  144. matrx_orm-3.1.30/tests/level1/test_relational_backfill.py +152 -0
  145. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_relations.py +0 -2
  146. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_resilience.py +0 -2
  147. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_session_advisory_lock.py +0 -1
  148. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_subquery_filter_raw.py +16 -34
  149. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_subquery_in_filter.py +13 -1
  150. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_supabase_auth.py +0 -2
  151. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_supabase_config.py +0 -1
  152. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_tls.py +0 -1
  153. matrx_orm-3.1.30/tests/level1/test_typed_join_projection.py +203 -0
  154. matrx_orm-3.1.30/tests/level1/test_typed_predicates.py +299 -0
  155. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_update_case_expression.py +9 -4
  156. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_upsert_with_conflict.py +16 -9
  157. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_watched_lifecycle.py +66 -46
  158. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_write_retry_semantics.py +0 -1
  159. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level2/conftest.py +2 -7
  160. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level2/test_cache_integration.py +0 -1
  161. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level2/test_crud.py +0 -2
  162. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level2/test_m2m.py +0 -4
  163. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level2/test_migrations_live.py +0 -1
  164. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level2/test_schema_diff.py +1 -2
  165. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/sample_project/generate.py +0 -1
  166. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/sample_project/test_schema_generation.py +2 -1
  167. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/sample_project_desktop/client_supabase_example.py +1 -2
  168. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/sample_project_desktop/server.py +6 -10
  169. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/schema/entity_tests.py +2 -3
  170. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/schema/test_composite_pk_fk_generation.py +0 -1
  171. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/schema/test_generate_schema.py +1 -1
  172. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/schema/test_sql_expression_defaults.py +0 -1
  173. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/schema_builder/test_focused_generation_plan.py +0 -1
  174. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/session/test_dag.py +1 -2
  175. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/session/test_disk_spill_fallback.py +0 -1
  176. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/session/test_flush_individual_fallback.py +0 -1
  177. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/session/test_governed_write.py +1 -2
  178. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/session/test_managed.py +17 -10
  179. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/session/test_reads.py +0 -2
  180. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/test_db_functions.py +0 -1
  181. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/test_model_cls_refactor.py +1 -1
  182. matrx_orm-3.1.30/tests/test_secrets_battery.py +582 -0
  183. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/test_sync_twins_guard.py +0 -1
  184. matrx_orm-3.1.28/matrx_orm/operations/conflict.py +0 -141
  185. matrx_orm-3.1.28/matrx_orm/secrets_battery/FEATURE.md +0 -112
  186. matrx_orm-3.1.28/matrx_orm/sql_executor/__init__.py +0 -20
  187. matrx_orm-3.1.28/tests/level1/test_execute_admin_sql.py +0 -142
  188. matrx_orm-3.1.28/tests/level1/test_filter_jsonb_agg_array_index.py +0 -71
  189. matrx_orm-3.1.28/tests/level1/test_filter_raw.py +0 -201
  190. matrx_orm-3.1.28/tests/test_secrets_battery.py +0 -134
  191. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/.gitignore +0 -0
  192. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/AGENTS.md +0 -0
  193. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/README.md +0 -0
  194. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/database/orm/extended/managers/ai_model_base.py +0 -0
  195. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/docs/migrations.md +0 -0
  196. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/MODULE_README.md +0 -0
  197. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/admin/__init__.py +0 -0
  198. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/api/__init__.py +0 -0
  199. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/api/config.py +0 -0
  200. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/api/protocol.py +0 -0
  201. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/associations.py +0 -0
  202. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/cache_debug.py +0 -0
  203. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/client/MODULE_README.md +0 -0
  204. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/core/EXTENDED-TASK.md +0 -0
  205. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/core/RELATIONS-TASKS.md +0 -0
  206. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/core/TASKS.md +0 -0
  207. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/core/__init__.py +0 -0
  208. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/core/db_function.py +0 -0
  209. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/core/diagnostics.py +0 -0
  210. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/core/extended.py +0 -0
  211. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/core/fields.py +0 -0
  212. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/core/listen.py +0 -0
  213. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/core/loop_filters.py +0 -0
  214. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/core/pool_maintenance.py +0 -0
  215. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/core/pydantic_bridge.py +0 -0
  216. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/core/resilience.py +0 -0
  217. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/core/tls.py +0 -0
  218. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/error_handling.py +0 -0
  219. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/exceptions.py +0 -0
  220. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/extended/__init__.py +0 -0
  221. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/middleware/__init__.py +0 -0
  222. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/migrations/MODULE_README.md +0 -0
  223. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/migrations/__init__.py +0 -0
  224. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/migrations/executor.py +0 -0
  225. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/migrations/integration.py +0 -0
  226. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/migrations/loader.py +0 -0
  227. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/migrations/operations.py +0 -0
  228. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/migrations/state.py +0 -0
  229. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/migrations/table_filter.py +0 -0
  230. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/operations/MODULE_README.md +0 -0
  231. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/operations/__init__.py +0 -0
  232. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/operations/create.py +0 -0
  233. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/operations/db_functions.py +0 -0
  234. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/operations/delete.py +0 -0
  235. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/operations/read.py +0 -0
  236. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/operations/update.py +0 -0
  237. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/py.typed +0 -0
  238. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/python_sql/MODULE_README.md +0 -0
  239. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/python_sql/__init__.py +0 -0
  240. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/python_sql/db_objects.py +0 -0
  241. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/python_sql/table_detailed_relationships.py +0 -0
  242. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/query/__init__.py +0 -0
  243. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/schema_builder/MODULE_README.md +0 -0
  244. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/schema_builder/__init__.py +0 -0
  245. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/schema_builder/code_handler.py +0 -0
  246. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/schema_builder/columns.py +0 -0
  247. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/schema_builder/common.py +0 -0
  248. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/schema_builder/entity_capabilities.py +0 -0
  249. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/schema_builder/helpers/base_generators.py +0 -0
  250. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/schema_builder/schema.py +0 -0
  251. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/schema_builder/tables.py +0 -0
  252. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/schema_builder/views.py +0 -0
  253. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/session/README.md +0 -0
  254. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/session/__init__.py +0 -0
  255. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/session/dag.py +0 -0
  256. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/session/errors.py +0 -0
  257. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/session/op.py +0 -0
  258. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/session/reads.py +0 -0
  259. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/sql_executor/MODULE_README.md +0 -0
  260. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/state.py +0 -0
  261. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/utils/__init__.py +0 -0
  262. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/matrx_orm/utils/sql_utils.py +0 -0
  263. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/scripts/git-branches.sh +0 -0
  264. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/scripts/publish.sh +0 -0
  265. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/scripts/release.sh +0 -0
  266. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/MODULE_README.md +0 -0
  267. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/__init__.py +0 -0
  268. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/conftest.py +0 -0
  269. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/MODULE_README.md +0 -0
  270. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/__init__.py +0 -0
  271. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_admin_search_negation.py +1 -1
  272. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_admin_search_sentinels.py +0 -0
  273. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_agent_message.py +0 -0
  274. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_cache_debug.py +0 -0
  275. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_count_composite_distinct.py +0 -0
  276. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_db_function_field.py +0 -0
  277. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_derived_table.py +0 -0
  278. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_exceptions.py +0 -0
  279. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_fields.py +0 -0
  280. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_fts.py +0 -0
  281. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_func_expression_args.py +0 -0
  282. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_introspect_rls_policies.py +0 -0
  283. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_pydantic_bridge.py +0 -0
  284. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_query_error_detail.py +0 -0
  285. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_query_timeout.py +0 -0
  286. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_schema_exists.py +0 -0
  287. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_state_cache.py +0 -0
  288. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_update_subquery.py +1 -1
  289. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level1/test_values_jsonb_decode.py +0 -0
  290. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level2/MODULE_README.md +0 -0
  291. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level2/__init__.py +0 -0
  292. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level2/test_bulk_ops.py +0 -0
  293. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level2/test_foreign_keys.py +0 -0
  294. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level2/test_manager.py +0 -0
  295. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/level2/test_query_execution.py +0 -0
  296. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/sample_project/.env.example +0 -0
  297. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/sample_project/README.md +0 -0
  298. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/sample_project/__init__.py +0 -0
  299. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/sample_project/generated/.gitkeep +0 -0
  300. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/sample_project/matrx_orm.yaml +0 -0
  301. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/sample_project_desktop/.env.example +0 -0
  302. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/sample_project_desktop/README.md +0 -0
  303. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/sample_project_desktop/__init__.py +0 -0
  304. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/sample_project_desktop/client_example.py +0 -0
  305. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/sample_project_desktop/client_example.ts +0 -0
  306. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/schema/test_base_generation.py +0 -0
  307. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/schema/test_composite_unique_generation.py +0 -0
  308. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/schema/test_dto_identity_generation.py +0 -0
  309. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/schema/test_entity_capability_generation.py +0 -0
  310. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/schema/test_multi_schema_output.py +0 -0
  311. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/schema/test_view_generation.py +0 -0
  312. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/session/__init__.py +0 -0
  313. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/session/conftest.py +0 -0
  314. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/session/test_capture_poison_proof.py +0 -0
  315. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/session/test_coalesce.py +0 -0
  316. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/session/test_op_enqueue_site.py +0 -0
  317. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/session/test_session.py +0 -0
  318. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/test_database_name_alias.py +0 -0
  319. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/test_no_blocking_asyncpg_tls.py +0 -0
  320. {matrx_orm-3.1.28 → matrx_orm-3.1.30}/tests/test_sql_param_casts.py +0 -0
@@ -2,7 +2,7 @@
2
2
 
3
3
  > **`QueryBuilder` chaining is clone-on-chain (copy-on-write), like Django's
4
4
  > `QuerySet`.** Every chain method (`.filter()`, `.exclude()`, `.order_by()`,
5
- > `.join()`, `.annotate()`, `.filter_raw()`, ...) returns a NEW `QueryBuilder`
5
+ > `.join()`, `.annotate()`, ...) returns a NEW `QueryBuilder`
6
6
  > and never mutates the one it was called on. It is safe to save a base
7
7
  > queryset and branch off it multiple times — each branch is independent:
8
8
  >
@@ -62,6 +62,38 @@ The following methods are available directly from all manager classes:
62
62
  - `update_where(filters, **updates)`
63
63
  - `delete_where(**filters)`
64
64
 
65
+ ### Atomic queue claims
66
+
67
+ `Model.claim_batch(set_fields=..., filters=..., order_by=..., limit=...,
68
+ returning=...)` atomically selects and updates a bounded queue batch with
69
+ `FOR UPDATE SKIP LOCKED`, so concurrent workers neither block nor double-claim.
70
+ `filters` accepts either an equality dict or a compound `Q` tree with
71
+ `eq`/`ne`/`gt`/`gte`/`lt`/`lte`/`in`/`isnull` lookups. Database expressions
72
+ such as `Now()` are valid in both filters and `set_fields`.
73
+
74
+ ```python
75
+ from datetime import timedelta
76
+ from matrx_orm import Now, Q
77
+
78
+ rows = await ToolCall.claim_batch(
79
+ set_fields={
80
+ "claimed_by_instance_id": instance_id,
81
+ "claimed_at": Now(),
82
+ "claim_expires_at": Now() + timedelta(hours=6),
83
+ },
84
+ filters=(
85
+ Q(status="delegated", tool_name__in=desktop_tool_names)
86
+ & (
87
+ Q(claimed_by_instance_id__isnull=True)
88
+ | Q(claim_expires_at__lt=Now())
89
+ )
90
+ ),
91
+ order_by="created_at",
92
+ limit=100,
93
+ returning=["id", "call_id", "tool_name"],
94
+ )
95
+ ```
96
+
65
97
  ### Load / Query
66
98
  - `load_item(use_cache=True, **kwargs)`
67
99
  - `load_item_or_none(use_cache=True, **kwargs)`
@@ -258,41 +290,13 @@ rows = await (
258
290
  )
259
291
  ```
260
292
 
261
- ### `Filter` / `JsonbObjectAgg` / `ArrayIndex` — FILTER clause, jsonb rollups, array subscript
262
-
263
- Three composable primitives (all in `matrx_orm.core.expressions`, exported from `matrx_orm`) for
264
- per-group rollup dashboards — grown converting a per-source-kind admin summary off raw SQL:
293
+ ### Typed aggregate expressions
265
294
 
266
- - `Filter(agg, condition, *params)` → `<agg SQL> FILTER (WHERE <condition>)`. `agg` is any
267
- expression with `.as_sql()` (`Count`, `Sum`, `JsonbObjectAgg`, `ArrayIndex(ArrayAgg(...), n)`,
268
- ...). `condition` is a raw SQL boolean fragment — same convention as `filter_raw`: write
269
- `$1, $2, ...` and pass the matching values as `*params`; no params needed for a static
270
- condition like `"parent_chunk_id IS NULL"`.
271
- - `JsonbObjectAgg(key, value)` → `jsonb_object_agg(key, value)`. `key`/`value` are usually raw
272
- SQL expression strings (`"COALESCE(metadata->>'k', 'unknown')"`, `"count(*)"`) — a bare string
273
- is embedded verbatim, same convention as every other raw column/expression string in this ORM
274
- (`order_by`, `select`, `group_by`).
275
- - `ArrayIndex(expr, index)` → `(expr)[index]` — the "pick one arbitrary value from the group"
276
- pattern paired with `ArrayAgg`.
277
-
278
- ```python
279
- from matrx_orm import ArrayAgg, ArrayIndex, Coalesce, Count, Filter, JsonbObjectAgg, Sum, Cast
280
-
281
- rows = await (
282
- KgChunks.filter(valid_to__isnull=True)
283
- .annotate(
284
- owner_id=ArrayIndex(ArrayAgg("owner_id::text"), 1),
285
- parent_count=Filter(Count("*"), "parent_chunk_id IS NULL"),
286
- total_tokens=Cast(Coalesce(Sum("token_count"), 0), "bigint"),
287
- section_histogram=Filter(
288
- JsonbObjectAgg("COALESCE(metadata->>'section_kind', 'unknown')", "count(*)"),
289
- "parent_chunk_id IS NULL",
290
- ),
291
- )
292
- .group_by("source_kind", "source_id")
293
- .values("owner_id", "parent_count", "total_tokens", "section_histogram")
294
- )
295
- ```
295
+ `ArrayAgg`, `ArrayIndex`, `Count`, `Sum`, `Coalesce`, and `Cast` compose
296
+ typed per-group rollups. Application callers pass field references (`F`) and
297
+ typed expression objects. Legacy string-condition aggregate constructors are
298
+ internal compatibility surfaces, not application APIs; add a typed expression
299
+ primitive when a rollup shape is missing.
296
300
 
297
301
  ### `.having()` resolves an `.annotate()` alias to its aggregate expression
298
302
 
@@ -316,18 +320,14 @@ rows = await (
316
320
  )
317
321
  ```
318
322
 
319
- A `.having()` key that does **not** match any `.annotate()` alias is left untouched — rendered
320
- verbatim as a raw column/expression, exactly as before this fix. That's still a valid escape
321
- hatch (e.g. `.having(**{"COUNT(*)__gte": 5})`), but referencing the alias directly is preferred:
322
- one definition of the aggregate (in `.annotate()`), not two that must be kept in sync by hand.
323
+ A `.having()` key should reference an `.annotate()` alias. Missing HAVING
324
+ shapes belong in the typed expression layer.
323
325
 
324
- ### `Subquery` / `Exists` now honor an inner `.filter_raw()`
326
+ ### Typed `Subquery` / `Exists`
325
327
 
326
- A correlated `Subquery(Model.filter(...).filter_raw(...))` used to silently DROP the
327
- `filter_raw` fragment (only structured `filters` were translated). Fixed — the fragment's own
328
- `$N` placeholders are shifted/bound exactly like the top-level case. The fragment can reference
329
- the outer table directly by its qualified name (no `OuterRef` needed for a raw fragment — write
330
- the qualified reference yourself, e.g. `f"{outer_table}.id::text = ..."`).
328
+ Correlated subqueries compose `Compare`, `Is`, `OuterRef`, and nested
329
+ `Exists` predicates. Parameter numbering is shifted safely at every nesting
330
+ level; application callers never write a fragment or placeholder.
331
331
 
332
332
  ### `JsonbMerge` — atomic shallow merge under a runtime key
333
333
 
@@ -351,6 +351,31 @@ await Files.update_where(
351
351
  )
352
352
  ```
353
353
 
354
+ ### `JsonbConcat` — jsonb concat of two EXPRESSIONS (columns, `F()`, `Excluded()`)
355
+
356
+ `JsonbConcat(left, right)` (in `matrx_orm.core.expressions`, exported from `matrx_orm`) renders
357
+ `(<left> || <right>)`. Unlike `JsonbMerge`, **neither operand is a Python literal** — both sides
358
+ are themselves renderable expressions. This is the primitive an `ON CONFLICT DO UPDATE SET`
359
+ "union the old and new jsonb, new keys winning" merge needs, where the RHS is the proposed
360
+ insert row's own column:
361
+
362
+ ```python
363
+ from matrx_orm import Excluded, F, JsonbConcat
364
+ from matrx_orm.operations.conflict_writes import bulk_upsert_increment
365
+
366
+ table = ProviderCall._meta.qualified_table_name
367
+ await bulk_upsert_increment(
368
+ ProviderCall, rows, on_conflict=["run_id", "provider_call_key"],
369
+ set_fields={"metadata": JsonbConcat(F(f"{table}.metadata"), Excluded("metadata"))},
370
+ )
371
+ # -> metadata = (seo.provider_call.metadata || EXCLUDED.metadata)
372
+ ```
373
+
374
+ Grown 2026-07-23 converting `matrx-seo`'s retried-provider-call evidence merge off a raw SQL
375
+ string (`f"{table}.metadata || EXCLUDED.metadata"`) — `bulk_upsert_increment`'s `set_fields`
376
+ values must be `Excluded(...)` or an object exposing `.as_sql(params)`; a bare f-string is
377
+ rejected loudly by `_render_set_field_value`.
378
+
354
379
  ### Atomic correlated-subquery UPDATE — `update(col=Subquery(...))`
355
380
 
356
381
  `QueryBuilder.update(**kwargs)` (and `Model.update_where(filters, **updates)`, which
@@ -384,7 +409,7 @@ Tests: `packages/matrx-orm/tests/level1/test_update_subquery.py`.
384
409
 
385
410
  ### Bulk UPDATE with heterogeneous per-row values — `bulk_update_by_pk`
386
411
 
387
- `Model.bulk_update_by_pk(objects_data, *, pk_field="id", casts=None, extra_set=None,
412
+ `Model.bulk_update_by_pk(objects_data, *, pk_field="id", casts=None, set_expressions=None,
388
413
  connection=None)` (also `matrx_orm.bulk_update_by_pk(model_cls, ...)`) — a set-based
389
414
  `UPDATE t SET col = v.col, ... FROM (VALUES (...), ...) AS v(pk, col, ...) WHERE t.pk =
390
415
  v.pk`, ONE round trip regardless of row count. Unlike `Model.bulk_update` (a loop of N
@@ -424,34 +449,29 @@ await KgChunks.bulk_update_by_pk(
424
449
  "page_numbers": "int[]",
425
450
  "page_spans": "jsonb",
426
451
  },
427
- extra_set={"updated_at": "now()"},
452
+ set_expressions={"updated_at": Now()},
428
453
  connection=conn, # the advisory-lock-holding connection
429
454
  )
430
455
  ```
431
456
 
432
457
  `casts` — `{column: pg_type}` for a column asyncpg can't infer unambiguously (an
433
- all-NULL column across the batch, jsonb, uuid, a typed array — the same reason the raw
434
- SQL this replaces cast every placeholder explicitly). `extra_set` — `{column:
435
- trusted_sql_fragment}` for a column every row gets the SAME value for (code-supplied,
436
- never user input — same trust model as `ConflictTarget`). Returns the count of rows
458
+ all-NULL column across the batch, jsonb, uuid, or a typed array).
459
+ `set_expressions` — `{column: typed_expression}` for a column every row gets the
460
+ same value (`Now()`, `Value(None)`, and other expression objects). Returns the count of rows
437
461
  actually matched-and-updated. Implementation:
438
462
  `packages/matrx-orm/matrx_orm/operations/bulk_update_values.py`.
439
463
 
440
464
  ### `Case` / `When` — conditional `CASE WHEN ... THEN ... ELSE ... END`
441
465
 
442
- `Case(When(condition, *condition_params, then=...), ..., default=...)` (both in
466
+ `Case(When(predicate, then=...), ..., default=...)` (both in
443
467
  `matrx_orm.core.expressions`, exported from `matrx_orm`) — the Django-standard
444
468
  conditional expression. Grown to unblock two matrx-rag sites that were kept raw solely
445
469
  for want of this (`packages/matrx-rag/matrx_rag/search.py::_entity_recall` /
446
470
  `_build_entity_map`).
447
471
 
448
- - `When.condition` — a raw SQL boolean fragment, same convention as `filter_raw` /
449
- `Filter`'s `condition`: write `$1, $2, ...` densely from `$1` (reuse OK) and pass the
450
- matching values as `*condition_params`; `Case` shifts/binds them into the query's
451
- running param sequence.
452
- - `then=` / `default=` — a literal (bound as a param), a bare column-name **string**
453
- (embedded verbatim — same convention as every other `Func` argument / `order_by` /
454
- `select`, NOT bound), or any expression object with `.as_sql(params)` (`F`, another
472
+ - `When.condition` — a composable typed `Predicate` (`Compare`, `Is`,
473
+ `ArrayAny`, `Exists`, or an `&` / `|` / `~` composition).
474
+ - `then=` / `default=` — a bound literal or typed expression (`F`, another
455
475
  `Func`, a nested `Case`, ...). `default=None` omits the `ELSE` clause entirely
456
476
  (Postgres already evaluates an unmatched `CASE` to `NULL` — behaviourally identical to
457
477
  an explicit `ELSE NULL`, so there's no ambiguity with "no default supplied").
@@ -459,43 +479,20 @@ for want of this (`packages/matrx-rag/matrx_rag/search.py::_entity_recall` /
459
479
  Composable anywhere an expression with `.as_sql(params)` is accepted:
460
480
 
461
481
  ```python
462
- from matrx_orm import Case, OrderBy, When
482
+ from matrx_orm import Case, Compare, F, Lower, OrderBy, When
463
483
 
464
484
  # ORDER BY exact-match-first tiebreak, then confidence DESC NULLS LAST
465
485
  qb.order_by(
466
- OrderBy(Case(When("lower(e.name) = $1", phrase, then=0), default=1)),
486
+ OrderBy(Case(When(Compare(Lower(F("name")), "=", phrase), then=0), default=1)),
467
487
  OrderBy("confidence_avg", descending=True, nulls="last"),
468
488
  )
469
489
 
470
490
  # .annotate(x=Case(...)) works the same way — any aggregation-block expression.
471
491
  ```
472
492
 
473
- **Inside a `join(on=..., on_params=...)` ON-clause** — `join()`'s `on` is a plain string
474
- built by the caller (not threaded through a shared params list), so use `Case.render()`
475
- to get a **fresh, `$1`-numbered** fragment (same convention as `filter_raw`) to splice in:
476
-
477
- ```python
478
- from matrx_orm import Case, When
479
-
480
- # Direction-agnostic partner: whichever endpoint is NOT in top_entity_ids.
481
- partner = Case(When("ed.src_id = ANY($1::uuid[])", top_entity_ids, then="ed.dst_id"), default="ed.src_id")
482
- on_sql, on_params = partner.render()
483
-
484
- rows = await (
485
- KgEdges.filter(kind="co_occurs_with")
486
- .from_alias("ed")
487
- .join(KgEntities, on=f"e2.id = {on_sql}", on_params=on_params, alias="e2")
488
- .filter_raw("(ed.src_id = ANY($1::uuid[]) OR ed.dst_id = ANY($1::uuid[]))", top_entity_ids)
489
- .annotate(total_weight=Sum("ed.weight"))
490
- .group_by("ed.src_id", "ed.dst_id", "e2.id", "e2.name", "e2.kind")
491
- .fetch_via(conn, "ed.src_id", "ed.dst_id", "e2.id AS partner_id", "e2.name AS partner_name", "e2.kind AS partner_kind", "total_weight")
492
- )
493
- ```
494
-
495
- `join()` grew an `on_params: list[Any] | None = None` kwarg for this — `on`'s own
496
- `$1, $2, ...` placeholders (dense from `$1`) are shifted into the query's running param
497
- sequence at the point the JOIN clause is rendered (before WHERE), exactly like
498
- `filter_raw`. Omit `on_params` for the existing plain-string-`on` usage — unchanged.
493
+ Join conditions and CASE branches must be built from typed field references
494
+ and predicates. If a join shape cannot yet accept the expression directly,
495
+ grow the join API instead of assembling SQL in application code.
499
496
 
500
497
  Tests: `packages/matrx-orm/tests/level1/test_case_when.py`.
501
498
 
@@ -510,12 +507,15 @@ bind the `Case` OBJECT as a query parameter. The executor now has a generic
510
507
  expression class gets `.update()` support for free, no new `isinstance` branch needed.
511
508
 
512
509
  ```python
513
- from matrx_orm import Case, F, When
510
+ from matrx_orm import Case, Compare, F, Interval, Now, When
514
511
 
515
512
  await OrganizationPreferences.update_where(
516
513
  {"organization_id": org_id},
517
514
  cost_used_usd=Case(
518
- When(f"{table}.window_start < now() - interval '24 hours'", then=cost_usd),
515
+ When(
516
+ Compare(F(f"{table}.window_start"), "<", Now() - Interval(hours=24)),
517
+ then=cost_usd,
518
+ ),
519
519
  default=F(f"{table}.cost_used_usd") + cost_usd,
520
520
  ),
521
521
  )
@@ -630,7 +630,6 @@ alone drives the whole conflict-time SET (at least one of the two is required).
630
630
  `set_fields` — `{column: value}` where `value` is one of:
631
631
 
632
632
  * `Excluded(column)` → `col = EXCLUDED.col`;
633
- * a trusted raw SQL fragment string with NO placeholders (e.g. `"now()"`);
634
633
  * **any expression object exposing `.as_sql(params)`** — `Case`, `Coalesce`, `F`
635
634
  arithmetic, or a nested combination — for a conflict-time SET that needs to branch on
636
635
  or reference the row's OLD (pre-conflict) value. Reference the old value via
@@ -645,18 +644,21 @@ This is the primitive behind the atomic 24h window-roll cost counter (an
645
644
  whether the stored window has gone stale — previously only expressible as hand-written SQL):
646
645
 
647
646
  ```python
648
- from matrx_orm import Case, F, Now, When
647
+ from matrx_orm import Case, Compare, F, Interval, Is, Now, When
649
648
 
650
649
  table = OrganizationPreferences._meta.qualified_table_name
651
- stale = f"{table}.window_start IS NULL OR {table}.window_start < now() - interval '24 hours'"
650
+ stale = (
651
+ Is(F(f"{table}.window_start"), None)
652
+ | Compare(F(f"{table}.window_start"), "<", Now() - Interval(hours=24))
653
+ )
652
654
 
653
655
  await OrganizationPreferences.bulk_upsert_increment(
654
656
  [{"organization_id": org_id, "cost_used_usd": cost, "window_start": now, "updated_at": now}],
655
657
  on_conflict=["organization_id"],
656
658
  set_fields={
657
- "window_start": Case(When(stale, then=Now()), default=f"{table}.window_start"),
659
+ "window_start": Case(When(stale, then=Now()), default=F(f"{table}.window_start")),
658
660
  "cost_used_usd": Case(When(stale, then=cost), default=F(f"{table}.cost_used_usd") + cost),
659
- "updated_at": "now()",
661
+ "updated_at": Now(),
660
662
  },
661
663
  )
662
664
  ```
@@ -678,14 +680,13 @@ preserve an omitted field instead of clobbering it with NULL on every write).
678
680
 
679
681
  `on_conflict` — a plain `list[str]` of columns, or a `ConflictTarget` (see
680
682
  above) for an expression/partial-index target. `set_fields` — `{column:
681
- Excluded(column) | trusted_sql_fragment | <expression with .as_sql(params)>}`
682
- (same three-way contract as `bulk_upsert_increment`'s `set_fields` above); any
683
+ Excluded(column) | <typed expression with .as_sql(params)>}`
684
+ (same contract as `bulk_upsert_increment`'s `set_fields` above); any
683
685
  column in `data` not given an explicit entry defaults to `Excluded(col)` (plain
684
- replace). Same trust model as `ConflictTarget` — fragments are code-supplied,
685
- never user input.
686
+ replace).
686
687
 
687
688
  ```python
688
- from matrx_orm import ConflictTarget, Excluded
689
+ from matrx_orm import Excluded, Now
689
690
  from matrx_orm.operations.conflict_writes import upsert_with_conflict
690
691
 
691
692
  row = await upsert_with_conflict(
@@ -696,64 +697,25 @@ row = await upsert_with_conflict(
696
697
  "description": description, "category": category,
697
698
  "is_active": True, "inject_into_sandbox": True,
698
699
  },
699
- on_conflict=ConflictTarget(expressions=["user_id", "key"], where="deleted_at IS NULL"),
700
+ on_conflict=["user_id", "key"],
700
701
  set_fields={
701
702
  "value_encrypted": Excluded("value_encrypted"),
702
703
  "value_hint": Excluded("value_hint"),
703
- "description": "COALESCE(EXCLUDED.description, users.user_secrets.description)",
704
- "category": "COALESCE(EXCLUDED.category, users.user_secrets.category)",
704
+ "description": Excluded("description"),
705
+ "category": Excluded("category"),
705
706
  "is_active": Excluded("is_active"),
706
707
  "inject_into_sandbox": Excluded("inject_into_sandbox"),
707
- "updated_at": "now()",
708
+ "updated_at": Now(),
708
709
  },
709
710
  ) # row: dict — the resulting row (RETURNING *)
710
711
  ```
711
712
 
712
713
  Tests: `packages/matrx-orm/tests/level1/test_upsert_with_conflict.py`.
713
714
 
714
- ### `execute_insert_select` — set-based `INSERT ... SELECT` between two real tables
715
-
716
- `execute_insert_select(config_name, insert_select_sql, *params, connection=None,
717
- pool=None)` (in `matrx_orm.operations.staging_load`) — runs a caller-built, code-
718
- supplied `INSERT INTO <target> SELECT ... FROM <source> [WHERE ...] [ON CONFLICT
719
- ... DO UPDATE]` statement in ONE atomic round-trip and returns the affected-row
720
- count (parsed from the `INSERT 0 N` tag). The set-based sibling of
721
- `execute_values_upsert` (that one's row source is a caller-supplied `VALUES`
722
- list; this one's is a caller-supplied `SELECT`) — for "derive N new/updated rows
723
- from an existing table without the rows ever leaving Postgres" (a
724
- `DISTINCT ON` + size-filtered fan-in into a denormalised slot table, an
725
- upsert-from-aggregate refresh, ...). Same trust model as `execute_values_upsert`
726
- / `StagingLoad.insert_select` / `ConflictTarget.expressions` / `filter_raw`:
727
- `insert_select_sql` is TRUSTED, code-supplied SQL text (never built from user
728
- input), `$1, $2, ...` bound to `*params`.
729
-
730
- ```python
731
- from matrx_orm.operations.staging_load import execute_insert_select
732
-
733
- n = await execute_insert_select(
734
- Model._database,
735
- """
736
- INSERT INTO workflow.node_data_slot (
737
- definition_id, node_id, slot, value, emissions,
738
- output_kind, source, captured_at, captured_by, user_id
739
- )
740
- SELECT $2, o.node_id, 'last_live_output', o.output, o.emissions,
741
- o.output_kind, 'live_run', now(), $3, $3
742
- FROM (
743
- SELECT DISTINCT ON (node_id) *
744
- FROM workflow.node_outcome
745
- WHERE run_id = $1 AND error IS NULL AND source = 'executor'
746
- ORDER BY node_id, step DESC, attempt DESC
747
- ) o
748
- WHERE pg_column_size(o.output) <= $4
749
- ON CONFLICT (definition_id, node_id, slot) DO UPDATE SET
750
- value = EXCLUDED.value, emissions = EXCLUDED.emissions,
751
- output_kind = EXCLUDED.output_kind, source = EXCLUDED.source,
752
- captured_at = EXCLUDED.captured_at, captured_by = EXCLUDED.captured_by,
753
- user_id = EXCLUDED.user_id
754
- """,
755
- run_id, definition_id, user_id, MAX_SLOT_VALUE_BYTES,
756
- )
757
- ```
715
+ ### Typed set-based operations
758
716
 
759
- Tests: `packages/matrx-orm/tests/level1/test_insert_ignore_and_admin_primitives.py::test_execute_insert_select_parses_tag_and_rejects_non_insert`.
717
+ Application callers use named plans such as `LatestPerGroupUpsertPlan`,
718
+ `StageUpsertPlan`, and `ValuesUpsertPlan`. These plans accept model classes,
719
+ validated field names, typed predicates, and bound values. A missing set-based
720
+ shape is added as another named operation in `matrx_orm.operations`; callers do
721
+ not supply statement text.
@@ -25,7 +25,11 @@ Every table that becomes a Model needs row identity: a single-column primary key
25
25
  - **Change tracking** — every instance records which columns were **loaded** (a SELECTed row, or the caller's kwargs) and which were **changed**. `save()` writes only those, so `.only("id","email")` + `save()` can never NULL the columns it never fetched (it used to — silent data loss). Mutable containers (jsonb/arrays) are always rewritten when loaded, because `obj.metadata["k"]=1` cannot be seen by `__setattr__`; **reassigning** (`obj.metadata = {...}`) is tracked precisely and is the sanctioned way. `Model._hydrate()` is the ONE row→model entry point.
26
26
  - **Read-only models** (`_read_only = True`): a model that can be queried but NEVER written through the ORM — every write path raises `ReadOnlyModelError` (enforced at `QueryExecutor.insert/bulk_insert/upsert/update/delete`, so it covers all of `create`/`save`/`update`/`delete`/`update_where`/`delete_where`/`upsert`/`bulk_*`). Used for DB-managed tables the app must not mutate. The canonical **`auth.users`** model is baked into the schema generator (`get_string_user_model`) as the full, curated Supabase auth schema (safe columns only — no password/token fields), `_read_only`, bound per-database. Read a user's profile/metadata there; mutate users only through Supabase Auth (GoTrue).
27
27
  - **Connection-level type codecs** (`async_db_manager._init_connection_default`): every pooled connection decodes **uuid → `str`**, **vector → `list[float]`**, and **json/jsonb → `dict`/`list`** at the driver boundary — the TYPE decides the decode, never the call path. So `call_function` scalar/rows, raw fetches, and field hydration all agree; a caller must **never `json.loads` a fetched json/jsonb value** (it's already decoded; the 2026-07-13 `build_agent_context` crash was a jsonb RPC fetched pre-codec as a raw string). Encoding: a pre-serialised JSON `str` passes through untouched; a native dict/list is dumped (`_encode_json`). Pinned by `tests/level1/test_connection_codecs.py`.
28
- - **Query layer**: `QueryBuilder`, expressions (`F`, `Q`), window functions, CTEs, subqueries.
28
+ - **Query layer**: `QueryBuilder`, typed predicates/projections (`F`, `Q`,
29
+ `Predicate`, `Projection`), window functions, QueryBuilder-backed CTEs, and
30
+ subqueries. SQL-shaped strings fail closed: plain strings name validated
31
+ columns only; compose casts, JSON paths, functions, ordering, joins, partial
32
+ conflict targets, and filtered aggregates with the exported typed objects.
29
33
  - **Migrations**: `MigrationDB`, `MigrationLoader`, `MigrationExecutor`, `makemigrations`, `migrate` — migrations declare explicit `dependencies` and apply in topological order (no multi-head/merge support yet).
30
34
  - **Admin router** (FastAPI): `admin_router` exposes read/write endpoints for any registered model.
31
35
  - **API layer** (optional `[api]` extra): `APIServer`, `APIConfig`, `TokenAuth`.
@@ -87,15 +87,6 @@ Reference for `matrx_orm.core.base.Model` (`QueryBuilder` included where `Model.
87
87
 
88
88
  ---
89
89
 
90
- ## Class methods — raw SQL (direct DB adapter)
91
-
92
- | Method | Arguments | Returns | Notes |
93
- |--------|-----------|---------|-------|
94
- | `raw` | `sql: str`, `*params` | `list[Self]` | Hydrates rows; not in PostgREST client mode |
95
- | `raw_sql` | `sql: str`, `*params` | `list[dict[str, Any]]` | Plain dict rows |
96
-
97
- ---
98
-
99
90
  ## Class methods — schema helper
100
91
 
101
92
  | Method | Arguments | Returns |
@@ -192,7 +183,7 @@ Reference for `matrx_orm.core.base.Model` (`QueryBuilder` included where `Model.
192
183
  | `select` | `(*fields: str)` |
193
184
  | `prefetch_related` | `(*fields: str)` |
194
185
  | `select_related` | `(*fields: str)` — FK names; JOIN + hydrate via `set_related` |
195
- | `join` | `(model_cls, on: str, join_type: str = "INNER")` |
186
+ | `join` | `(model_cls, on: Predicate, join_type: str = "INNER")` |
196
187
  | `group_by` | `(*fields: str)` |
197
188
  | `having` | `(**kwargs)` — merged to one dict for SQL HAVING |
198
189
  | `annotate` | `(**kwargs)` — each value: aggregate/func with `as_sql` or string |
@@ -296,12 +287,6 @@ FK filter names resolve to the **database column** name via `_meta.foreign_keys`
296
287
 
297
288
  ---
298
289
 
299
- ## Raw SQL parameters
300
-
301
- Positional `*params` bind as `$1`, `$2`, … (PostgreSQL-style) in generated SQL.
302
-
303
- ---
304
-
305
290
  ## Related types (returns)
306
291
 
307
292
  - `UpdateResult`: `rows_affected: int`, `updated_rows: list[dict[str, Any]]`, `to_dict()`.
@@ -309,4 +294,6 @@ Positional `*params` bind as `$1`, `$2`, … (PostgreSQL-style) in generated SQL
309
294
 
310
295
  ---
311
296
 
312
- *Generated from package sources; behavior may differ per database adapter (e.g. PostgREST: `raw` / DDL / some write paths not supported).*
297
+ *Generated from package sources; behavior may differ per database adapter
298
+ (e.g. DDL and some write paths are unavailable in PostgREST mode). Application
299
+ callers use typed models, predicates, expressions, and operations only.*
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: matrx-orm
3
- Version: 3.1.28
3
+ Version: 3.1.30
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
@@ -29,6 +29,11 @@ from .core.config import (
29
29
  resolve_pool_mode,
30
30
  )
31
31
  from .core.db_function import ArrayArg, call_function, call_function_sync
32
+ from .core.connections import (
33
+ create_external_pool,
34
+ get_registered_pool,
35
+ open_listener_connection,
36
+ )
32
37
  from .entity import EntityCapabilityError, MatrxEntity
33
38
  from .core.diagnostics import collect_pool_diagnostics, log_pool_diagnostics
34
39
  from .core.introspection import introspect_columns, introspect_rls_policies, schema_exists
@@ -44,6 +49,8 @@ from .core.expressions import (
44
49
  Abs,
45
50
  Aggregate,
46
51
  ArrayAgg,
52
+ ArrayAny,
53
+ ArrayContains,
47
54
  ArrayIndex,
48
55
  ArrayLength,
49
56
  Avg,
@@ -51,11 +58,13 @@ from .core.expressions import (
51
58
  Case,
52
59
  Cast,
53
60
  ColumnComparison,
61
+ Compare,
54
62
  Coalesce,
55
63
  Concat,
56
64
  Count,
57
65
  CumeDist,
58
66
  DateTrunc,
67
+ DbFunction,
59
68
  DenseRank,
60
69
  Excluded,
61
70
  Exists,
@@ -67,6 +76,12 @@ from .core.expressions import (
67
76
  Func,
68
77
  Greatest,
69
78
  JsonText,
79
+ JsonPath,
80
+ JsonArrayPathExists,
81
+ Projection,
82
+ Like,
83
+ Regex,
84
+ JsonbConcat,
70
85
  JsonbMerge,
71
86
  JsonbObjectAgg,
72
87
  Lag,
@@ -82,7 +97,13 @@ from .core.expressions import (
82
97
  Ntile,
83
98
  OrderBy,
84
99
  OuterRef,
100
+ Predicate,
85
101
  PercentRank,
102
+ ConstantPredicate,
103
+ Interval,
104
+ Is,
105
+ TupleInArrays,
106
+ Value,
86
107
  Q,
87
108
  Rank,
88
109
  Round,
@@ -192,8 +213,6 @@ from .core.transaction import (
192
213
  advisory_lock,
193
214
  advisory_unlock,
194
215
  advisory_xact_lock,
195
- execute_admin_command,
196
- execute_admin_sql,
197
216
  set_local_guc,
198
217
  transaction,
199
218
  try_advisory_lock,
@@ -449,6 +468,21 @@ __all__ = [
449
468
  "OuterRef",
450
469
  "Subquery",
451
470
  "Exists",
471
+ "Predicate",
472
+ "Compare",
473
+ "Is",
474
+ "Value",
475
+ "JsonPath",
476
+ "JsonArrayPathExists",
477
+ "Projection",
478
+ "Like",
479
+ "Regex",
480
+ "DbFunction",
481
+ "ArrayAny",
482
+ "ArrayContains",
483
+ "TupleInArrays",
484
+ "ConstantPredicate",
485
+ "Interval",
452
486
  "Func",
453
487
  "Aggregate",
454
488
  "Coalesce",
@@ -469,6 +503,7 @@ __all__ = [
469
503
  "ArrayLength",
470
504
  "ArrayIndex",
471
505
  "JsonText",
506
+ "JsonbConcat",
472
507
  "JsonbMerge",
473
508
  "JsonbObjectAgg",
474
509
  "Filter",
@@ -525,8 +560,6 @@ __all__ = [
525
560
  "try_advisory_lock",
526
561
  "advisory_unlock",
527
562
  "rls_session",
528
- "execute_admin_sql",
529
- "execute_admin_command",
530
563
  # ── Resilience (opt-in transient-failure retry) ──────────────────────────
531
564
  "retry_on_transient",
532
565
  "is_read_only_sql",
@@ -85,7 +85,6 @@ Filepath: src/matrx_orm/adapters/postgresql.py [python]
85
85
  async def update(self, query: Dict[str, Any], data: Dict[str, Any]) -> int
86
86
  async def bulk_update(self, query: Dict[str, Any]) -> int
87
87
  async def delete(self, query: Dict[str, Any]) -> int
88
- async def raw_sql(self, sql: str, params: List[Any] = None) -> Union[List[Dict[str, Any]], int]
89
88
  async def close(self)
90
89
  async def transaction(self)
91
90
  async def savepoint(self, name: str)
@@ -115,7 +114,6 @@ Filepath: src/matrx_orm/adapters/base_adapter.py [python]
115
114
  async def update(self, query: Dict[str, Any], data: Dict[str, Any]) -> int
116
115
  async def bulk_update(self, query: Dict[str, Any]) -> int
117
116
  async def delete(self, query: Dict[str, Any]) -> int
118
- async def raw_sql(self, sql: str, params: List[Any] = None) -> Union[List[Dict[str, Any]], int]
119
117
  async def transaction(self)
120
118
  async def close(self)
121
119
  async def __aenter__(self)
@@ -146,11 +144,6 @@ src.matrx_orm.adapters.postgresql.__init__ → src.matrx_orm.adapters.postgresql
146
144
  async src.matrx_orm.adapters.postgresql.update → connection.execute(sql, *params) (line 59)
147
145
  async src.matrx_orm.adapters.postgresql.bulk_update → connection.executemany(sql, params) (line 65)
148
146
  async src.matrx_orm.adapters.postgresql.delete → connection.execute(sql, *params) (line 71)
149
- async src.matrx_orm.adapters.postgresql.raw_sql → startswith('SELECT') (line 76)
150
- async src.matrx_orm.adapters.postgresql.raw_sql → upper() (line 76)
151
- async src.matrx_orm.adapters.postgresql.raw_sql → sql.strip() (line 76)
152
- async src.matrx_orm.adapters.postgresql.raw_sql → connection.fetch(sql, *params) (line 77)
153
- async src.matrx_orm.adapters.postgresql.raw_sql → connection.execute(sql, *params) (line 80)
154
147
  async src.matrx_orm.adapters.postgresql.close → ...is_closed() (line 83)
155
148
  async src.matrx_orm.adapters.postgresql.close → ...close() (line 84)
156
149
  async src.matrx_orm.adapters.postgresql.transaction → connection.transaction() (line 88)
@@ -26,6 +26,7 @@ Register any ``BaseAdapter`` subclass before the first query::
26
26
  from matrx_orm.adapters import AdapterRegistry
27
27
  AdapterRegistry.register("my_project", MyCustomAdapter("my_project"))
28
28
  """
29
+
29
30
  from __future__ import annotations
30
31
 
31
32
  import logging
@@ -69,9 +70,7 @@ class AdapterRegistry:
69
70
  Replaces any previously registered adapter for the same config_name.
70
71
  """
71
72
  if not isinstance(adapter, BaseAdapter):
72
- raise TypeError(
73
- f"adapter must be a BaseAdapter subclass, got {type(adapter)!r}"
74
- )
73
+ raise TypeError(f"adapter must be a BaseAdapter subclass, got {type(adapter)!r}")
75
74
  cls._adapters[config_name] = adapter
76
75
  logger.debug("Registered adapter %r for config %r", type(adapter).__name__, config_name)
77
76
 
@@ -92,6 +91,7 @@ class AdapterRegistry:
92
91
  an aliased config name shares the target's adapter instance.
93
92
  """
94
93
  from matrx_orm.core.config import resolve_database_name
94
+
95
95
  config_name = resolve_database_name(config_name)
96
96
  if config_name not in cls._adapters:
97
97
  cls._adapters[config_name] = cls._create_default(config_name)
@@ -107,6 +107,7 @@ class AdapterRegistry:
107
107
 
108
108
  if adapter_type == "supabase":
109
109
  from matrx_orm.adapters.supabase_adapter import SupabaseAdapter
110
+
110
111
  return SupabaseAdapter(config_name)
111
112
 
112
113
  # Allow dotted class path: "mypackage.adapters.MyAdapter"
@@ -125,6 +126,7 @@ class AdapterRegistry:
125
126
  """Read adapter_type from the registered DatabaseProjectConfig."""
126
127
  try:
127
128
  from matrx_orm.core.config import registry as _db_registry
129
+
128
130
  config = _db_registry._configs.get(config_name)
129
131
  if config is not None:
130
132
  return getattr(config, "adapter_type", "postgresql")
@@ -139,13 +141,12 @@ class AdapterRegistry:
139
141
  if not module_path:
140
142
  raise ValueError(f"Invalid dotted adapter path: {dotted_path!r}")
141
143
  import importlib
144
+
142
145
  module = importlib.import_module(module_path)
143
146
  klass = getattr(module, class_name)
144
147
  instance = klass(config_name)
145
148
  if not isinstance(instance, BaseAdapter):
146
- raise TypeError(
147
- f"{dotted_path} does not produce a BaseAdapter subclass"
148
- )
149
+ raise TypeError(f"{dotted_path} does not produce a BaseAdapter subclass")
149
150
  return instance
150
151
 
151
152
  # ------------------------------------------------------------------