matrx-orm 3.1.254__tar.gz → 3.1.255__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.
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/PKG-INFO +2 -2
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/core/FEATURE.md +22 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/core/async_db_manager.py +26 -9
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/core/transaction.py +140 -26
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/pyproject.toml +2 -2
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_connection_poison_guard.py +77 -2
- matrx_orm-3.1.255/tests/level1/test_transaction_isolation.py +213 -0
- matrx_orm-3.1.255/tests/level1/test_transaction_top_level_cleanup.py +471 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/.gitignore +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/AGENTS.md +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/BASE_CLASS_METHODS.md +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/CHANGELOG.md +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/CLAUDE.md +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/MODEL_API.md +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/README.md +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/database/orm/extended/managers/ai_model_base.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/docs/migrations.md +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/FEATURE.md +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/MODULE_README.md +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/__init__.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/adapters/MODULE_README.md +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/adapters/__init__.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/adapters/async_postgresql.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/adapters/base_adapter.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/adapters/postgrest_client_adapter.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/adapters/supabase_adapter.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/admin/FEATURE.md +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/admin/__init__.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/admin/router.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/api/__init__.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/api/auth.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/api/config.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/api/handlers.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/api/protocol.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/api/server.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/associations.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/cache_debug.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/catalog.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/catalog_sql.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/client/MODULE_README.md +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/client/__init__.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/client/postgres_connection.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/client/postgrest.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/client/supabase_auth.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/client/supabase_config.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/client/supabase_manager.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/core/EXTENDED-TASK.md +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/core/MODULE_README.md +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/core/RELATIONS-TASKS.md +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/core/TASKS.md +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/core/__init__.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/core/admin_lane.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/core/base.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/core/config.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/core/connections.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/core/db_function.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/core/diagnostics.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/core/expressions.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/core/extended.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/core/fields.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/core/foreign_session_state.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/core/introspection.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/core/listen.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/core/loop_filters.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/core/model_dto.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/core/model_view.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/core/one_database.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/core/paginator.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/core/pool_maintenance.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/core/pool_watch.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/core/pooler_role.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/core/pydantic_bridge.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/core/read_write.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/core/registry.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/core/relations.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/core/resilience.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/core/rls_session.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/core/session_context.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/core/signals.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/core/statement_ceiling.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/core/tls.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/core/types.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/core/write_queue.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/core/write_retry.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/entity.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/error_handling.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/exceptions.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/extended/__init__.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/extended/app_error_handler.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/identity_rule.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/local_sqlite.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/middleware/__init__.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/middleware/base.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/migrations/MODULE_README.md +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/migrations/__init__.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/migrations/cli.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/migrations/ddl.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/migrations/diff.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/migrations/executor.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/migrations/integration.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/migrations/loader.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/migrations/operations.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/migrations/state.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/migrations/table_filter.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/no_org_assignment.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/operations/FEATURE.md +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/operations/MODULE_README.md +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/operations/__init__.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/operations/bulk_update_values.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/operations/catalog_select.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/operations/conflict.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/operations/conflict_writes.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/operations/create.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/operations/db_functions.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/operations/delete.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/operations/dynamic_admin.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/operations/dynamic_crud.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/operations/graph_walk.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/operations/latest_rows.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/operations/queue_claim.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/operations/read.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/operations/relational_backfill.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/operations/staging_load.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/operations/update.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/platform_access.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/platform_db.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/py.typed +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/pytest_lock_guard.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/pytest_plugin.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/python_sql/MODULE_README.md +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/python_sql/__init__.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/python_sql/db_objects.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/python_sql/table_detailed_relationships.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/python_sql/table_typescript_relationship.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/query/FEATURE.md +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/query/MODULE_README.md +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/query/__init__.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/query/builder.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/query/executor.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/resources/__init__.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/resources/additional-assigners-2026-09-12.json +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/resources/org_assignment_trigger_baseline.json +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/schema_builder/FEATURE.md +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/schema_builder/MODULE_README.md +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/schema_builder/__init__.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/schema_builder/code_handler.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/schema_builder/codegen_writer.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/schema_builder/columns.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/schema_builder/common.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/schema_builder/diff_preview.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/schema_builder/entity_capabilities.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/schema_builder/excluded_targets.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/schema_builder/generator.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/schema_builder/helpers/__init__.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/schema_builder/helpers/base_generators.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/schema_builder/helpers/entity_generators.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/schema_builder/helpers/git_checker.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/schema_builder/package_wiring.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/schema_builder/relationships.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/schema_builder/runner.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/schema_builder/schema.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/schema_builder/schema_manager.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/schema_builder/tables.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/schema_builder/views.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/secrets_battery/FEATURE.md +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/secrets_battery/__init__.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/secrets_battery/attachments.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/secrets_battery/backup_restore.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/secrets_battery/crypto.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/secrets_battery/host_authorization.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/secrets_battery/items.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/secrets_battery/model.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/secrets_battery/mutation_receipts.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/secrets_battery/native_enable.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/secrets_battery/native_lifecycle.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/secrets_battery/native_passkeys.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/secrets_battery/native_source.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/secrets_battery/org_service.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/secrets_battery/org_vault_gate.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/secrets_battery/service.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/secrets_battery/use_stamp.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/secrets_battery/vault_history.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/session/README.md +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/session/__init__.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/session/coalesce.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/session/dag.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/session/errors.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/session/fallback.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/session/flush.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/session/lifecycle.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/session/managed.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/session/op.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/session/reads.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/session/session.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/session/telemetry.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/sql_executor/MODULE_README.md +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/sql_executor/__init__.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/sql_executor/executor.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/sql_executor/queries.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/sql_executor/registry.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/sql_executor/types.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/sql_executor/utils.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/state.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/utils/__init__.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/utils/sql_utils.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/utils/type_converters.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/matrx_orm/write_actor.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/scripts/git-branches.sh +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/scripts/publish.sh +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/scripts/release.sh +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/scripts/verify_wheel.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/MODULE_README.md +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/__init__.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/conftest.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/MODULE_README.md +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/__init__.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_adapter_registry.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_admin_db_columns.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_admin_response_rendering.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_admin_search_negation.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_admin_search_sentinels.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_advisory_lock.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_agent_message.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_api_auth.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_api_config.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_api_handlers.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_api_protocol.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_array_agg_order_by.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_association_trigger_actor_naming.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_associations.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_associations_wiring.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_borrowed_role_never_reaches_server_calls.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_bulk_hydration_offload.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_bulk_update_by_pk.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_bulk_upsert_increment_set_fields.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_cache_debug.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_call_function.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_case_when.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_catalog.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_column_scoped_writes.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_committed_row_guard.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_composite_pk_filter.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_composite_pk_write_paths.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_config.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_conflict_target.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_conflict_writes.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_connection_codecs.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_connection_primitives.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_count_composite_distinct.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_count_limit_param_leak.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_db_function_field.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_ddl_generator.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_deadlock_retry.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_derived_table.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_dirty_tracking.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_dynamic_crud.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_exceptions.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_execute_query_integrity_mapping.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_expression_primitives.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_fetch_on_init_holds_whole_table.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_fields.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_filter_jsonb_agg_array_index.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_fk_cycle_resolution.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_from_alias.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_fts.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_func_expression_args.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_graph_walk.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_guarded_read_never_reruns_empty.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_having_annotate_alias.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_insert_ignore_and_admin_primitives.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_introspect_rls_policies.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_join_and_aggregate.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_latest_rows.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_listen_notify.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_local_sqlite.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_lock_contention_retry.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_managed_write_guard.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_matrx_entity.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_migration_diff_types.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_migration_loader.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_model_instance.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_model_meta.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_optimistic_concurrency.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_order_by_expression.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_org_assignment_inventory.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_orm_banners_are_client_safe.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_parameter_name_hydration.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_patch_jsonb_path.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_percentile_cont.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_persisted_count.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_person_scoped_session_bypasses_shared_cache.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_pool_create_never_wedges.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_pool_holder_census.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_pool_loop_recreation.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_pool_maintenance.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_postgrest_filters.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_pydantic_bridge.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_query_builder.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_query_error_detail.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_query_executor_sql.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_query_timeout.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_querybuilder_clone_semantics.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_queue_claim.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_read_connection_retry.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_read_write_declared.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_registry.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_registry_multi_database.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_registry_multi_schema.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_registry_reads_outside_the_person_session.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_relational_backfill.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_relations.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_resilience.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_rls_session_scope.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_schema_exists.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_session_advisory_lock.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_standalone_write_session_context.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_state_cache.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_subquery_filter_raw.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_subquery_in_filter.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_subquery_nested_expressions.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_supabase_auth.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_supabase_config.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_sync_pool_declares_read_write.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_tls.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_transaction_database_identity.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_transaction_gucs_one_round_trip.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_transaction_pool_release_sends_nothing.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_typed_join_projection.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_typed_predicates.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_update_case_expression.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_update_subquery.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_update_with_rebase.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_upsert_default_leak.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_upsert_with_conflict.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_values_jsonb_decode.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_watched_lifecycle.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_wheel_contents.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_write_queue_deadline.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level1/test_write_retry_semantics.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level2/MODULE_README.md +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level2/__init__.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level2/conftest.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level2/test_bulk_ops.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level2/test_cache_integration.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level2/test_crud.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level2/test_foreign_keys.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level2/test_m2m.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level2/test_manager.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level2/test_migrations_live.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level2/test_query_execution.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level2/test_schema_diff.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/level2/verify_committed_row_guard_pg17.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/live_pooler_role.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/native_source_cases.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/native_source_oracle.rs +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/sample_project/.env.example +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/sample_project/README.md +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/sample_project/__init__.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/sample_project/generate.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/sample_project/generated/.gitkeep +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/sample_project/matrx_orm.yaml +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/sample_project/test_schema_generation.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/sample_project_desktop/.env.example +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/sample_project_desktop/README.md +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/sample_project_desktop/__init__.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/sample_project_desktop/client_example.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/sample_project_desktop/client_example.ts +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/sample_project_desktop/client_supabase_example.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/sample_project_desktop/server.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/schema/entity_tests.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/schema/test_base_generation.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/schema/test_composite_pk_fk_generation.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/schema/test_composite_unique_generation.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/schema/test_dto_identity_generation.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/schema/test_entity_capability_generation.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/schema/test_enum_ordering.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/schema/test_excluded_fk_targets.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/schema/test_generate_schema.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/schema/test_junction_analysis.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/schema/test_multi_schema_output.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/schema/test_schema_analysis.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/schema/test_sql_expression_defaults.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/schema/test_table_relationships_query.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/schema/test_view_generation.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/schema_builder/test_array_default_parsing.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/schema_builder/test_enum_array_column.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/schema_builder/test_focused_generation_plan.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/schema_builder/test_host_models_aggregator.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/schema_builder/test_never_filter_columns.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/session/__init__.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/session/conftest.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/session/test_a_failed_capture_still_names_the_failure.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/session/test_a_grouped_update_writes_only_each_rows_own_fields.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/session/test_cache_no_downgrade.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/session/test_capture_poison_proof.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/session/test_coalesce.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/session/test_dag.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/session/test_disk_spill_fallback.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/session/test_flush_individual_fallback.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/session/test_governed_write.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/session/test_managed.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/session/test_op_enqueue_site.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/session/test_pending_insert_honors_operator_filters.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/session/test_reads.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/session/test_record_error_bounded_insert.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/session/test_record_error_group_open.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/session/test_record_error_storm.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/session/test_session.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/session/test_spill_guard_plugin.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/session/test_tests_never_write_live_system_error.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/test_a_backend_handed_over_mid_transaction_never_takes_our_writes.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/test_a_bulk_cache_never_stalls_the_loop.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/test_a_failed_use_stamp_never_fails_the_read.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/test_a_keyword_column_refuses_generation.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/test_a_list_of_uuids_binds_as_uuid_array.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/test_a_read_only_backend_never_refuses_our_writes.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/test_a_sealed_field_shows_no_character_of_its_value.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/test_array_arg_element_type.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/test_attachment_mutation_serialization.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/test_backup_alias_conflict.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/test_backup_history_restore.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/test_backup_restore_live.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/test_call_function_as.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/test_call_function_none_mode.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/test_composite_fk_is_not_a_column_fk.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/test_database_name_alias.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/test_db_functions.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/test_dsn_password_masking.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/test_dynamic_select_unregistered.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/test_first_asks_the_database_for_one_row.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/test_foreign_session_state.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/test_immutable_insert_or_exact_verify.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/test_instance_update_runs_expressions.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/test_jsonb_postgres_illegal_text.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/test_keyed_digest.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/test_model_cls_refactor.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/test_native_enable.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/test_native_lifecycle.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/test_native_lifecycle_fences.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/test_native_passkey_receipts.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/test_native_source.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/test_no_blocking_asyncpg_tls.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/test_one_database.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/test_order_by_desc_nulls_last.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/test_org_vault_gate.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/test_package_wiring_views.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/test_pooler_role_guard.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/test_secret_audit_names_its_organization.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/test_secrets_battery.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/test_secrets_minting_keys.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/test_shared_lock_guard.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/test_sql_param_casts.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/test_state_cache_sweeps_stale.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/test_statement_ceiling_warning.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/test_sync_twins_guard.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/test_update_result_truthiness.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/test_user_visible_lookup.py +0 -0
- {matrx_orm-3.1.254 → matrx_orm-3.1.255}/tests/test_vault_aggregate_recovery_stateful.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: matrx-orm
|
|
3
|
-
Version: 3.1.
|
|
3
|
+
Version: 3.1.255
|
|
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
|
|
@@ -26,7 +26,7 @@ Requires-Dist: asyncpg>=0.31.0
|
|
|
26
26
|
Requires-Dist: cbor2<7,>=6.1.3
|
|
27
27
|
Requires-Dist: cryptography>=43.0
|
|
28
28
|
Requires-Dist: gitpython>=3.1.40
|
|
29
|
-
Requires-Dist: matrx-utils>=2.0.
|
|
29
|
+
Requires-Dist: matrx-utils>=2.0.89
|
|
30
30
|
Requires-Dist: psycopg-pool>=3.2.5
|
|
31
31
|
Requires-Dist: psycopg[binary]>=3.2.5
|
|
32
32
|
Requires-Dist: python-dotenv>=1.0
|
|
@@ -289,6 +289,28 @@ trip from a laptop): 435 → ~200 round trips. Pinned by
|
|
|
289
289
|
`tests/level1/test_transaction_pool_release_sends_nothing.py` and
|
|
290
290
|
`tests/level1/test_rls_session_scope.py`.
|
|
291
291
|
|
|
292
|
+
**Snapshot isolation is selected only at the canonical transaction boundary.**
|
|
293
|
+
`transaction(isolation=…)` accepts `read_committed`, `repeatable_read`, or
|
|
294
|
+
`serializable` and emits the corresponding fixed `BEGIN ISOLATION LEVEL` clause;
|
|
295
|
+
omitting it preserves plain `BEGIN`. Unknown values fail before connection
|
|
296
|
+
acquisition. An explicit mode inside an existing transaction refuses before any
|
|
297
|
+
savepoint or depth mutation because a savepoint cannot change the outer isolation;
|
|
298
|
+
an ordinary nested transaction remains a savepoint. Opening GUCs still follow the
|
|
299
|
+
BEGIN in their one ordered round trip. Pinned by
|
|
300
|
+
`tests/level1/test_transaction_isolation.py`.
|
|
301
|
+
|
|
302
|
+
**A top-level transaction does not outlive its physical cleanup.** COMMIT or
|
|
303
|
+
ROLLBACK and adapter release run in one retained task; caller cancellation is
|
|
304
|
+
remembered while repeated cancellation is consumed and the task is shielded and
|
|
305
|
+
joined. Precedence is caller cancellation, then the original body error, then a
|
|
306
|
+
cleanup error. Command and release faults are observed separately using only a
|
|
307
|
+
fixed code, phase, exception type, and database alias; an unknown release fault
|
|
308
|
+
terminates only an asyncpg proxy that still owns its backend. A successful COMMIT
|
|
309
|
+
whose bounded pool reset times out remains successful because asyncpg has already
|
|
310
|
+
discarded that backend; its diagnostic is metadata-only. Pinned by
|
|
311
|
+
`tests/level1/test_transaction_top_level_cleanup.py` and
|
|
312
|
+
`tests/level1/test_connection_poison_guard.py`.
|
|
313
|
+
|
|
292
314
|
**A backend another client left read-only never refuses our writes.** A transaction
|
|
293
315
|
pooler shares server connections with every client of the same login and never resets
|
|
294
316
|
one between clients, so a session-level `SET default_transaction_read_only = on` (or
|
|
@@ -64,6 +64,24 @@ from matrx_orm.core.write_retry import (
|
|
|
64
64
|
logger = logging.getLogger("matrx_orm.async_db_manager")
|
|
65
65
|
|
|
66
66
|
|
|
67
|
+
def _log_connection_release_failure(
|
|
68
|
+
*, config_name: str, code: str, error: BaseException
|
|
69
|
+
) -> None:
|
|
70
|
+
error_type = type(error).__name__
|
|
71
|
+
logger.error(
|
|
72
|
+
"matrx_orm_connection_release_failed code=%s phase=release error_type=%s database=%s",
|
|
73
|
+
code,
|
|
74
|
+
error_type,
|
|
75
|
+
config_name,
|
|
76
|
+
extra={
|
|
77
|
+
"code": code,
|
|
78
|
+
"phase": "release",
|
|
79
|
+
"error_type": error_type,
|
|
80
|
+
"database": config_name,
|
|
81
|
+
},
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
|
|
67
85
|
def _terminate_pool_after_loop_change(pool: Any, config_name: str) -> None:
|
|
68
86
|
try:
|
|
69
87
|
pool.terminate()
|
|
@@ -1271,10 +1289,10 @@ class AsyncDatabaseManager:
|
|
|
1271
1289
|
return
|
|
1272
1290
|
release_exc = task.exception()
|
|
1273
1291
|
if release_exc is not None:
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
release_exc,
|
|
1292
|
+
_log_connection_release_failure(
|
|
1293
|
+
config_name=config_name,
|
|
1294
|
+
code="connection_release_failed",
|
|
1295
|
+
error=release_exc,
|
|
1278
1296
|
)
|
|
1279
1297
|
return
|
|
1280
1298
|
try:
|
|
@@ -1295,11 +1313,10 @@ class AsyncDatabaseManager:
|
|
|
1295
1313
|
# release timeout. The query already completed successfully, so
|
|
1296
1314
|
# this cleanup failure must not replace its result with a false
|
|
1297
1315
|
# request crash. Keep the pool-health signal loud.
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
"
|
|
1301
|
-
|
|
1302
|
-
release_exc,
|
|
1316
|
+
_log_connection_release_failure(
|
|
1317
|
+
config_name=config_name,
|
|
1318
|
+
code="connection_release_timeout_discarded",
|
|
1319
|
+
error=release_exc,
|
|
1303
1320
|
)
|
|
1304
1321
|
else:
|
|
1305
1322
|
try:
|
|
@@ -21,11 +21,12 @@ automatically uses the same connection without any manual passing.
|
|
|
21
21
|
|
|
22
22
|
Adapter decoupling
|
|
23
23
|
------------------
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
24
|
+
``TransactionContext`` obtains its connection through
|
|
25
|
+
``AdapterRegistry.get(database).get_connection()``, which returns an asyncpg
|
|
26
|
+
pool proxy for the default adapter but can return any connection object for
|
|
27
|
+
custom adapters, as long as that object supports ``.execute(sql)`` and
|
|
28
|
+
``.fetch(sql, *args)``. The one driver-specific check is the failed-release
|
|
29
|
+
discard boundary: only an attached ``PoolConnectionProxy`` may be terminated.
|
|
29
30
|
|
|
30
31
|
The ``_active_connection`` ContextVar is typed as ``Any`` so the rest of the
|
|
31
32
|
ORM can hold a reference to the active connection without depending on asyncpg.
|
|
@@ -37,17 +38,71 @@ from __future__ import annotations
|
|
|
37
38
|
|
|
38
39
|
import asyncio
|
|
39
40
|
import contextvars
|
|
41
|
+
import logging
|
|
40
42
|
import os
|
|
41
43
|
import re
|
|
42
44
|
import uuid
|
|
43
45
|
from collections.abc import AsyncIterator, Awaitable, Callable
|
|
44
46
|
from contextlib import asynccontextmanager
|
|
45
47
|
from contextvars import ContextVar, Token
|
|
46
|
-
from typing import Any,
|
|
48
|
+
from typing import Any, Literal
|
|
49
|
+
|
|
50
|
+
from asyncpg.pool import PoolConnectionProxy
|
|
47
51
|
|
|
48
52
|
from matrx_orm.exceptions import DatabaseError
|
|
49
53
|
|
|
50
|
-
|
|
54
|
+
logger = logging.getLogger("matrx_orm.transaction")
|
|
55
|
+
|
|
56
|
+
type TransactionIsolation = Literal[
|
|
57
|
+
"read_committed", "repeatable_read", "serializable"
|
|
58
|
+
]
|
|
59
|
+
|
|
60
|
+
_ISOLATION_BEGIN_STATEMENTS: dict[TransactionIsolation, str] = {
|
|
61
|
+
"read_committed": "BEGIN ISOLATION LEVEL READ COMMITTED",
|
|
62
|
+
"repeatable_read": "BEGIN ISOLATION LEVEL REPEATABLE READ",
|
|
63
|
+
"serializable": "BEGIN ISOLATION LEVEL SERIALIZABLE",
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _begin_statement(isolation: TransactionIsolation | None) -> str:
|
|
68
|
+
if isolation is None:
|
|
69
|
+
return "BEGIN"
|
|
70
|
+
try:
|
|
71
|
+
return _ISOLATION_BEGIN_STATEMENTS[isolation]
|
|
72
|
+
except (KeyError, TypeError):
|
|
73
|
+
accepted = ", ".join(_ISOLATION_BEGIN_STATEMENTS)
|
|
74
|
+
raise ValueError(
|
|
75
|
+
f"Unsupported transaction isolation {isolation!r}; expected one of: {accepted}"
|
|
76
|
+
) from None
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _log_cleanup_failure(*, database: str, phase: str, error: BaseException) -> None:
|
|
80
|
+
error_type = type(error).__name__
|
|
81
|
+
logger.error(
|
|
82
|
+
"matrx_orm_transaction_cleanup_failed code=%s phase=%s error_type=%s database=%s",
|
|
83
|
+
"transaction_cleanup_failed",
|
|
84
|
+
phase,
|
|
85
|
+
error_type,
|
|
86
|
+
database,
|
|
87
|
+
extra={
|
|
88
|
+
"code": "transaction_cleanup_failed",
|
|
89
|
+
"phase": phase,
|
|
90
|
+
"error_type": error_type,
|
|
91
|
+
"database": database,
|
|
92
|
+
},
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def _discard_still_owned_asyncpg_proxy(connection: Any) -> None:
|
|
97
|
+
# asyncpg detaches a PoolConnectionProxy by clearing ``_con`` before that
|
|
98
|
+
# pool slot can be borrowed again. Only terminate while this exact proxy
|
|
99
|
+
# still owns its backend; never chase a holder or a later borrower.
|
|
100
|
+
if not isinstance(connection, PoolConnectionProxy) or connection._con is None:
|
|
101
|
+
return
|
|
102
|
+
try:
|
|
103
|
+
connection.terminate()
|
|
104
|
+
except Exception:
|
|
105
|
+
pass
|
|
51
106
|
|
|
52
107
|
# ContextVar holding the active connection (if any) for the current task tree.
|
|
53
108
|
_active_connection: ContextVar[Any | None] = ContextVar("_active_connection", default=None)
|
|
@@ -72,7 +127,7 @@ def in_person_scoped_session() -> bool:
|
|
|
72
127
|
_savepoint_depth: ContextVar[int] = ContextVar("_savepoint_depth", default=0)
|
|
73
128
|
|
|
74
129
|
|
|
75
|
-
async def outside_transaction(fn: Callable[[], Awaitable[
|
|
130
|
+
async def outside_transaction[T](fn: Callable[[], Awaitable[T]]) -> T:
|
|
76
131
|
"""Await ``fn()`` on the process's own connection, outside the caller's transaction.
|
|
77
132
|
|
|
78
133
|
For process-wide VOCABULARY reads (the entity-type registry) whose answer must not
|
|
@@ -278,8 +333,16 @@ class TransactionContext:
|
|
|
278
333
|
On nested entry (active connection exists): creates a SAVEPOINT instead.
|
|
279
334
|
"""
|
|
280
335
|
|
|
281
|
-
def __init__(
|
|
336
|
+
def __init__(
|
|
337
|
+
self,
|
|
338
|
+
database: str,
|
|
339
|
+
opening_gucs: dict[str, str] | None = None,
|
|
340
|
+
*,
|
|
341
|
+
isolation: TransactionIsolation | None = None,
|
|
342
|
+
) -> None:
|
|
282
343
|
self.database = database
|
|
344
|
+
self._isolation = isolation
|
|
345
|
+
self._begin_sql = _begin_statement(isolation)
|
|
283
346
|
# Transaction-local GUCs the OPENER needs set at BEGIN (``rls_session``'s
|
|
284
347
|
# claims + role), emitted in the same statement as the ceilings and the
|
|
285
348
|
# declared session context — one round trip for all of them. Top-level only.
|
|
@@ -295,6 +358,14 @@ class TransactionContext:
|
|
|
295
358
|
async def __aenter__(self) -> TransactionContext:
|
|
296
359
|
existing = _active_connection.get()
|
|
297
360
|
if existing is not None:
|
|
361
|
+
if self._isolation is not None:
|
|
362
|
+
raise DatabaseError(
|
|
363
|
+
message=(
|
|
364
|
+
"transaction(isolation=...) must open a TOP-LEVEL transaction: "
|
|
365
|
+
"a nested savepoint cannot change the outer transaction's isolation."
|
|
366
|
+
),
|
|
367
|
+
details={"database": self.database, "isolation": self._isolation},
|
|
368
|
+
)
|
|
298
369
|
if self._opening_gucs:
|
|
299
370
|
raise DatabaseError(
|
|
300
371
|
message=(
|
|
@@ -329,7 +400,7 @@ class TransactionContext:
|
|
|
329
400
|
conn = await self._adapter_cm.__aenter__()
|
|
330
401
|
self._raw_conn = conn
|
|
331
402
|
try:
|
|
332
|
-
await conn.execute(
|
|
403
|
+
await conn.execute(self._begin_sql)
|
|
333
404
|
except BaseException as e:
|
|
334
405
|
await self._adapter_cm.__aexit__(type(e), e, e.__traceback__)
|
|
335
406
|
self._raw_conn = None
|
|
@@ -414,35 +485,72 @@ class TransactionContext:
|
|
|
414
485
|
# pool poisoned (an in-transaction connection causes the next
|
|
415
486
|
# consumer's first statement to fail with "transaction is
|
|
416
487
|
# aborted" and lose that request's data).
|
|
488
|
+
command_error: BaseException | None = None
|
|
489
|
+
release_error: BaseException | None = None
|
|
417
490
|
try:
|
|
418
491
|
if exc_type is None:
|
|
419
492
|
await conn_to_use.execute("COMMIT")
|
|
420
493
|
else:
|
|
421
494
|
await conn_to_use.execute("ROLLBACK")
|
|
422
|
-
except BaseException:
|
|
495
|
+
except BaseException as error:
|
|
496
|
+
command_error = error
|
|
497
|
+
_log_cleanup_failure(database=self.database, phase="command", error=error)
|
|
423
498
|
try:
|
|
424
499
|
conn_to_use.terminate()
|
|
425
500
|
except Exception:
|
|
426
501
|
pass
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
if adapter_cm is not None:
|
|
502
|
+
if adapter_cm is not None:
|
|
503
|
+
try:
|
|
430
504
|
await adapter_cm.__aexit__(exc_type, exc_val, exc_tb)
|
|
505
|
+
except BaseException as error:
|
|
506
|
+
release_error = error
|
|
507
|
+
_log_cleanup_failure(database=self.database, phase="release", error=error)
|
|
508
|
+
_discard_still_owned_asyncpg_proxy(conn_to_use)
|
|
509
|
+
|
|
510
|
+
if command_error is not None:
|
|
511
|
+
raise command_error
|
|
512
|
+
if release_error is not None:
|
|
513
|
+
raise release_error
|
|
514
|
+
|
|
515
|
+
# One retained task owns command + release. Caller cancellation is
|
|
516
|
+
# remembered and temporarily consumed while this task is shielded and
|
|
517
|
+
# joined; repeated cancellation cannot let the async-with frame escape
|
|
518
|
+
# with locks or a checkout still held. A child that cancels itself is
|
|
519
|
+
# distinguished by its completed/cancelled state, so it cannot spin.
|
|
520
|
+
teardown_task = asyncio.create_task(
|
|
521
|
+
_teardown(), name=f"matrx-orm-transaction-cleanup:{self.database}"
|
|
522
|
+
)
|
|
523
|
+
caller_cancelled = False
|
|
524
|
+
current_task = asyncio.current_task()
|
|
525
|
+
while not teardown_task.done():
|
|
526
|
+
try:
|
|
527
|
+
await asyncio.shield(teardown_task)
|
|
528
|
+
except asyncio.CancelledError:
|
|
529
|
+
if current_task is not None and current_task.cancelling():
|
|
530
|
+
caller_cancelled = True
|
|
531
|
+
current_task.uncancel()
|
|
532
|
+
continue
|
|
533
|
+
if teardown_task.done() and teardown_task.cancelled():
|
|
534
|
+
break
|
|
535
|
+
raise
|
|
536
|
+
except BaseException:
|
|
537
|
+
if teardown_task.done():
|
|
538
|
+
break
|
|
539
|
+
raise
|
|
431
540
|
|
|
432
|
-
|
|
433
|
-
# client disconnect, shutdown) can never SKIP the ROLLBACK and leak a
|
|
434
|
-
# poisoned (in-transaction) connection back to the pool. The shielded
|
|
435
|
-
# teardown runs to completion even when the outer await is canceled.
|
|
541
|
+
cleanup_error: BaseException | None = None
|
|
436
542
|
try:
|
|
437
|
-
|
|
438
|
-
except
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
543
|
+
teardown_task.result()
|
|
544
|
+
except BaseException as error:
|
|
545
|
+
cleanup_error = error
|
|
546
|
+
|
|
547
|
+
if caller_cancelled:
|
|
548
|
+
raise asyncio.CancelledError
|
|
443
549
|
|
|
444
550
|
if exc_type is not None:
|
|
445
551
|
return False # re-raise the original exception
|
|
552
|
+
if cleanup_error is not None:
|
|
553
|
+
raise cleanup_error
|
|
446
554
|
|
|
447
555
|
return False # never suppress exceptions
|
|
448
556
|
|
|
@@ -497,17 +605,23 @@ def _opening_statement_gucs(opening_gucs: dict[str, str]) -> dict[str, str]:
|
|
|
497
605
|
|
|
498
606
|
|
|
499
607
|
def transaction(
|
|
500
|
-
database: str | None = None,
|
|
608
|
+
database: str | None = None,
|
|
609
|
+
*,
|
|
610
|
+
opening_gucs: dict[str, str] | None = None,
|
|
611
|
+
isolation: TransactionIsolation | None = None,
|
|
501
612
|
) -> TransactionContext:
|
|
502
613
|
"""Return a ``TransactionContext`` async context manager.
|
|
503
614
|
|
|
504
615
|
``database`` defaults to the first configured database when omitted.
|
|
505
616
|
``opening_gucs`` are transaction-local settings the opener needs at BEGIN;
|
|
506
617
|
they ride the one opening statement (top-level transactions only).
|
|
618
|
+
``isolation`` selects one of the fixed PostgreSQL isolation clauses; an
|
|
619
|
+
explicit mode is top-level only.
|
|
507
620
|
"""
|
|
621
|
+
_begin_statement(isolation)
|
|
508
622
|
if database is None:
|
|
509
623
|
database = _get_default_database()
|
|
510
|
-
return TransactionContext(database, opening_gucs)
|
|
624
|
+
return TransactionContext(database, opening_gucs, isolation=isolation)
|
|
511
625
|
|
|
512
626
|
|
|
513
627
|
def _get_default_database() -> str:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "matrx-orm"
|
|
3
|
-
version = "3.1.
|
|
3
|
+
version = "3.1.255"
|
|
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" }
|
|
@@ -41,7 +41,7 @@ dependencies = [
|
|
|
41
41
|
"gitpython>=3.1.40",
|
|
42
42
|
"psycopg[binary]>=3.2.5",
|
|
43
43
|
"psycopg-pool>=3.2.5",
|
|
44
|
-
"matrx-utils>=2.0.
|
|
44
|
+
"matrx-utils>=2.0.89",
|
|
45
45
|
"pyyaml>=6.0.3",
|
|
46
46
|
"python-dotenv>=1.0",
|
|
47
47
|
"cryptography>=43.0",
|
|
@@ -14,6 +14,8 @@ connection is terminated (never reused).
|
|
|
14
14
|
|
|
15
15
|
from __future__ import annotations
|
|
16
16
|
|
|
17
|
+
import asyncio
|
|
18
|
+
|
|
17
19
|
import pytest
|
|
18
20
|
from matrx_orm.core.async_db_manager import AsyncDatabaseManager
|
|
19
21
|
from matrx_orm.exceptions import StateError
|
|
@@ -84,13 +86,35 @@ class _FakePool:
|
|
|
84
86
|
|
|
85
87
|
|
|
86
88
|
class _ReleaseTimeoutPool(_FakePool):
|
|
89
|
+
async def release(
|
|
90
|
+
self,
|
|
91
|
+
conn: _FakeConn,
|
|
92
|
+
timeout: float | None = None, # noqa: ASYNC109 - mirrors asyncpg
|
|
93
|
+
) -> None:
|
|
94
|
+
del timeout
|
|
95
|
+
# Installed asyncpg discards the physical backend before surfacing a
|
|
96
|
+
# reset timeout from Pool.release(). This fake owns that network edge.
|
|
97
|
+
conn.terminate()
|
|
98
|
+
raise TimeoutError("private reset payload exceeded release budget")
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class _GatedReleaseFailurePool(_FakePool):
|
|
102
|
+
def __init__(self, conn: _FakeConn) -> None:
|
|
103
|
+
super().__init__(conn)
|
|
104
|
+
self.release_started = asyncio.Event()
|
|
105
|
+
self.release_gate = asyncio.Event()
|
|
106
|
+
self.release_finished = asyncio.Event()
|
|
107
|
+
|
|
87
108
|
async def release(
|
|
88
109
|
self,
|
|
89
110
|
conn: _FakeConn,
|
|
90
111
|
timeout: float | None = None, # noqa: ASYNC109 - mirrors asyncpg
|
|
91
112
|
) -> None:
|
|
92
113
|
del conn, timeout
|
|
93
|
-
|
|
114
|
+
self.release_started.set()
|
|
115
|
+
await self.release_gate.wait()
|
|
116
|
+
self.release_finished.set()
|
|
117
|
+
raise RuntimeError("private delayed release payload")
|
|
94
118
|
|
|
95
119
|
|
|
96
120
|
def _patch_pool(monkeypatch, pool: _FakePool) -> None:
|
|
@@ -146,4 +170,55 @@ async def test_release_timeout_does_not_replace_successful_query_result(monkeypa
|
|
|
146
170
|
result = await AsyncDatabaseManager.execute_query("x", "SELECT 1 AS value")
|
|
147
171
|
|
|
148
172
|
assert result == [{"value": 1}]
|
|
149
|
-
assert "
|
|
173
|
+
assert "TERMINATE" in conn.calls
|
|
174
|
+
records = [
|
|
175
|
+
record
|
|
176
|
+
for record in caplog.records
|
|
177
|
+
if record.name == "matrx_orm.async_db_manager"
|
|
178
|
+
and getattr(record, "code", None) == "connection_release_timeout_discarded"
|
|
179
|
+
]
|
|
180
|
+
assert len(records) == 1
|
|
181
|
+
record = records[0]
|
|
182
|
+
assert record.phase == "release"
|
|
183
|
+
assert record.error_type == "TimeoutError"
|
|
184
|
+
assert record.database == "x"
|
|
185
|
+
assert record.exc_info is None and record.stack_info is None
|
|
186
|
+
assert not any(isinstance(arg, BaseException) for arg in record.args)
|
|
187
|
+
assert "private reset payload" not in record.getMessage()
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
async def test_cancelled_holder_observes_late_release_failure_without_private_text(
|
|
191
|
+
monkeypatch, caplog
|
|
192
|
+
):
|
|
193
|
+
conn = _FakeConn(in_tx=False)
|
|
194
|
+
pool = _GatedReleaseFailurePool(conn)
|
|
195
|
+
_patch_pool(monkeypatch, pool)
|
|
196
|
+
|
|
197
|
+
async def use_connection() -> None:
|
|
198
|
+
async with AsyncDatabaseManager.get_connection("x"):
|
|
199
|
+
pass
|
|
200
|
+
|
|
201
|
+
with caplog.at_level("ERROR", logger="matrx_orm.async_db_manager"):
|
|
202
|
+
caller = asyncio.create_task(use_connection())
|
|
203
|
+
await pool.release_started.wait()
|
|
204
|
+
caller.cancel()
|
|
205
|
+
with pytest.raises(asyncio.CancelledError):
|
|
206
|
+
await caller
|
|
207
|
+
pool.release_gate.set()
|
|
208
|
+
await pool.release_finished.wait()
|
|
209
|
+
await asyncio.sleep(0)
|
|
210
|
+
|
|
211
|
+
records = [
|
|
212
|
+
record
|
|
213
|
+
for record in caplog.records
|
|
214
|
+
if record.name == "matrx_orm.async_db_manager"
|
|
215
|
+
and getattr(record, "code", None) == "connection_release_failed"
|
|
216
|
+
]
|
|
217
|
+
assert len(records) == 1
|
|
218
|
+
record = records[0]
|
|
219
|
+
assert record.phase == "release"
|
|
220
|
+
assert record.error_type == "RuntimeError"
|
|
221
|
+
assert record.database == "x"
|
|
222
|
+
assert record.exc_info is None and record.stack_info is None
|
|
223
|
+
assert not any(isinstance(arg, BaseException) for arg in record.args)
|
|
224
|
+
assert "private delayed release payload" not in record.getMessage()
|