matrx-orm 3.1.185__tar.gz → 3.1.187__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.185 → matrx_orm-3.1.187}/BASE_CLASS_METHODS.md +1 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/CHANGELOG.md +5 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/PKG-INFO +1 -1
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/core/base.py +18 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/core/types.py +9 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/operations/create.py +46 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/query/builder.py +54 -1
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/query/executor.py +11 -2
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/secrets_battery/FEATURE.md +19 -19
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/secrets_battery/items.py +5 -6
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/pyproject.toml +1 -1
- matrx_orm-3.1.187/tests/level1/test_column_scoped_writes.py +126 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/test_secrets_battery.py +3 -3
- matrx_orm-3.1.187/tests/test_update_result_truthiness.py +6 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/.gitignore +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/AGENTS.md +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/CLAUDE.md +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/MODEL_API.md +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/README.md +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/database/orm/extended/managers/ai_model_base.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/docs/migrations.md +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/FEATURE.md +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/MODULE_README.md +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/__init__.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/adapters/MODULE_README.md +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/adapters/__init__.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/adapters/async_postgresql.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/adapters/base_adapter.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/adapters/postgrest_client_adapter.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/adapters/supabase_adapter.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/admin/FEATURE.md +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/admin/__init__.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/admin/router.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/api/__init__.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/api/auth.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/api/config.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/api/handlers.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/api/protocol.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/api/server.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/associations.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/cache_debug.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/catalog.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/catalog_sql.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/client/MODULE_README.md +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/client/__init__.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/client/postgres_connection.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/client/postgrest.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/client/supabase_auth.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/client/supabase_config.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/client/supabase_manager.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/core/EXTENDED-TASK.md +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/core/FEATURE.md +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/core/MODULE_README.md +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/core/RELATIONS-TASKS.md +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/core/TASKS.md +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/core/__init__.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/core/admin_lane.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/core/async_db_manager.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/core/config.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/core/connections.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/core/db_function.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/core/diagnostics.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/core/expressions.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/core/extended.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/core/fields.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/core/introspection.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/core/listen.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/core/loop_filters.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/core/model_dto.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/core/model_view.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/core/one_database.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/core/paginator.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/core/pool_maintenance.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/core/pool_watch.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/core/pooler_role.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/core/pydantic_bridge.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/core/registry.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/core/relations.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/core/resilience.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/core/rls_session.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/core/session_context.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/core/signals.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/core/tls.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/core/transaction.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/core/write_queue.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/core/write_retry.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/entity.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/error_handling.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/exceptions.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/extended/__init__.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/extended/app_error_handler.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/identity_rule.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/local_sqlite.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/middleware/__init__.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/middleware/base.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/migrations/MODULE_README.md +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/migrations/__init__.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/migrations/cli.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/migrations/ddl.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/migrations/diff.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/migrations/executor.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/migrations/integration.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/migrations/loader.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/migrations/operations.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/migrations/state.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/migrations/table_filter.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/no_org_assignment.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/operations/FEATURE.md +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/operations/MODULE_README.md +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/operations/__init__.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/operations/bulk_update_values.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/operations/catalog_select.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/operations/conflict.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/operations/conflict_writes.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/operations/db_functions.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/operations/delete.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/operations/dynamic_admin.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/operations/dynamic_crud.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/operations/graph_walk.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/operations/latest_rows.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/operations/queue_claim.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/operations/read.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/operations/relational_backfill.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/operations/staging_load.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/operations/update.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/platform_access.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/platform_db.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/py.typed +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/pytest_live_db_guard.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/pytest_lock_guard.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/pytest_plugin.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/python_sql/MODULE_README.md +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/python_sql/__init__.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/python_sql/db_objects.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/python_sql/table_detailed_relationships.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/python_sql/table_typescript_relationship.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/query/FEATURE.md +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/query/MODULE_README.md +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/query/__init__.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/resources/__init__.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/resources/additional-assigners-2026-09-12.json +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/resources/org_assignment_trigger_baseline.json +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/schema_builder/FEATURE.md +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/schema_builder/MODULE_README.md +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/schema_builder/__init__.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/schema_builder/code_handler.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/schema_builder/codegen_writer.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/schema_builder/columns.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/schema_builder/common.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/schema_builder/diff_preview.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/schema_builder/entity_capabilities.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/schema_builder/generator.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/schema_builder/helpers/__init__.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/schema_builder/helpers/base_generators.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/schema_builder/helpers/entity_generators.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/schema_builder/helpers/git_checker.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/schema_builder/package_wiring.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/schema_builder/relationships.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/schema_builder/runner.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/schema_builder/schema.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/schema_builder/schema_manager.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/schema_builder/tables.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/schema_builder/views.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/secrets_battery/__init__.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/secrets_battery/attachments.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/secrets_battery/backup_restore.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/secrets_battery/crypto.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/secrets_battery/host_authorization.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/secrets_battery/model.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/secrets_battery/mutation_receipts.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/secrets_battery/native_enable.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/secrets_battery/native_lifecycle.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/secrets_battery/native_passkeys.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/secrets_battery/native_source.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/secrets_battery/org_service.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/secrets_battery/service.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/secrets_battery/vault_history.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/session/README.md +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/session/__init__.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/session/coalesce.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/session/dag.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/session/errors.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/session/fallback.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/session/flush.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/session/lifecycle.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/session/managed.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/session/op.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/session/reads.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/session/session.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/session/telemetry.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/sql_executor/MODULE_README.md +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/sql_executor/__init__.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/sql_executor/executor.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/sql_executor/queries.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/sql_executor/registry.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/sql_executor/types.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/sql_executor/utils.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/state.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/utils/__init__.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/utils/sql_utils.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/utils/type_converters.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/matrx_orm/write_actor.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/scripts/git-branches.sh +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/scripts/publish.sh +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/scripts/release.sh +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/MODULE_README.md +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/__init__.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/conftest.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/MODULE_README.md +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/__init__.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_adapter_registry.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_admin_db_columns.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_admin_response_rendering.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_admin_search_negation.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_admin_search_sentinels.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_advisory_lock.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_agent_message.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_api_auth.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_api_config.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_api_handlers.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_api_protocol.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_array_agg_order_by.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_association_trigger_actor_naming.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_associations.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_associations_wiring.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_bulk_hydration_offload.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_bulk_update_by_pk.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_bulk_upsert_increment_set_fields.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_cache_debug.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_call_function.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_case_when.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_catalog.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_committed_row_guard.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_composite_pk_filter.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_composite_pk_write_paths.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_config.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_conflict_target.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_conflict_writes.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_connection_codecs.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_connection_poison_guard.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_connection_primitives.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_count_composite_distinct.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_count_limit_param_leak.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_db_function_field.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_ddl_generator.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_deadlock_retry.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_derived_table.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_dirty_tracking.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_dynamic_crud.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_exceptions.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_execute_query_integrity_mapping.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_expression_primitives.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_fields.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_filter_jsonb_agg_array_index.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_fk_cycle_resolution.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_from_alias.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_fts.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_func_expression_args.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_graph_walk.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_having_annotate_alias.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_insert_ignore_and_admin_primitives.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_introspect_rls_policies.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_join_and_aggregate.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_latest_rows.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_listen_notify.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_local_sqlite.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_lock_contention_retry.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_managed_write_guard.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_matrx_entity.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_migration_diff_types.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_migration_loader.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_model_instance.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_model_meta.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_optimistic_concurrency.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_order_by_expression.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_org_assignment_inventory.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_orm_banners_are_client_safe.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_parameter_name_hydration.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_patch_jsonb_path.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_percentile_cont.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_persisted_count.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_pool_create_never_wedges.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_pool_holder_census.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_pool_loop_recreation.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_pool_maintenance.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_postgrest_filters.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_pydantic_bridge.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_query_builder.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_query_error_detail.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_query_executor_sql.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_query_timeout.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_querybuilder_clone_semantics.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_queue_claim.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_read_connection_retry.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_registry.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_registry_multi_database.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_registry_multi_schema.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_relational_backfill.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_relations.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_resilience.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_rls_session_scope.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_schema_exists.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_session_advisory_lock.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_standalone_write_session_context.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_state_cache.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_subquery_filter_raw.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_subquery_in_filter.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_subquery_nested_expressions.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_supabase_auth.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_supabase_config.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_tls.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_transaction_database_identity.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_typed_join_projection.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_typed_predicates.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_update_case_expression.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_update_subquery.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_update_with_rebase.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_upsert_default_leak.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_upsert_with_conflict.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_values_jsonb_decode.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_watched_lifecycle.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_write_queue_deadline.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level1/test_write_retry_semantics.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level2/MODULE_README.md +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level2/__init__.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level2/conftest.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level2/test_bulk_ops.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level2/test_cache_integration.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level2/test_crud.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level2/test_foreign_keys.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level2/test_m2m.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level2/test_manager.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level2/test_migrations_live.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level2/test_query_execution.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level2/test_schema_diff.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/level2/verify_committed_row_guard_pg17.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/live_pooler_role.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/native_source_cases.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/native_source_oracle.rs +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/sample_project/.env.example +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/sample_project/README.md +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/sample_project/__init__.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/sample_project/generate.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/sample_project/generated/.gitkeep +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/sample_project/matrx_orm.yaml +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/sample_project/test_schema_generation.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/sample_project_desktop/.env.example +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/sample_project_desktop/README.md +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/sample_project_desktop/__init__.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/sample_project_desktop/client_example.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/sample_project_desktop/client_example.ts +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/sample_project_desktop/client_supabase_example.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/sample_project_desktop/server.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/schema/entity_tests.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/schema/test_base_generation.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/schema/test_composite_pk_fk_generation.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/schema/test_composite_unique_generation.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/schema/test_dto_identity_generation.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/schema/test_entity_capability_generation.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/schema/test_enum_ordering.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/schema/test_generate_schema.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/schema/test_junction_analysis.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/schema/test_multi_schema_output.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/schema/test_schema_analysis.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/schema/test_sql_expression_defaults.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/schema/test_table_relationships_query.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/schema/test_view_generation.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/schema_builder/test_array_default_parsing.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/schema_builder/test_focused_generation_plan.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/schema_builder/test_host_models_aggregator.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/session/__init__.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/session/conftest.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/session/test_a_failed_capture_still_names_the_failure.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/session/test_cache_no_downgrade.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/session/test_capture_poison_proof.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/session/test_coalesce.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/session/test_dag.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/session/test_disk_spill_fallback.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/session/test_flush_individual_fallback.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/session/test_governed_write.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/session/test_live_db_guard_plugin.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/session/test_managed.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/session/test_op_enqueue_site.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/session/test_reads.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/session/test_record_error_bounded_insert.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/session/test_record_error_storm.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/session/test_session.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/session/test_spill_guard_plugin.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/test_array_arg_element_type.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/test_attachment_mutation_serialization.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/test_backup_alias_conflict.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/test_backup_history_restore.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/test_backup_restore_live.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/test_composite_fk_is_not_a_column_fk.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/test_database_name_alias.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/test_db_functions.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/test_dsn_password_masking.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/test_dynamic_select_unregistered.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/test_immutable_insert_or_exact_verify.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/test_keyed_digest.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/test_model_cls_refactor.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/test_native_enable.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/test_native_lifecycle.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/test_native_lifecycle_fences.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/test_native_passkey_receipts.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/test_native_source.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/test_no_blocking_asyncpg_tls.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/test_one_database.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/test_order_by_desc_nulls_last.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/test_pooler_role_guard.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/test_secret_audit_names_its_organization.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/test_secrets_minting_keys.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/test_shared_lock_guard.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/test_sql_param_casts.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/test_sync_twins_guard.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/test_user_visible_lookup.py +0 -0
- {matrx_orm-3.1.185 → matrx_orm-3.1.187}/tests/test_vault_aggregate_recovery_stateful.py +0 -0
|
@@ -60,6 +60,7 @@ The following methods are available directly from all manager classes:
|
|
|
60
60
|
- `upsert_items(items_data, conflict_fields, update_fields=None)`
|
|
61
61
|
- `count(**filters)`
|
|
62
62
|
- `update_where(filters, *, expected_version=None, lock_rows_in_pk_order=False, **updates)`
|
|
63
|
+
- `insert_returning(data, *, returning)` — INSERT only the named columns (the rest take DB defaults), RETURNING only `returning`; the acting-as-user create on a table whose system-only columns the person is not granted. Update twin: `Model.filter(...).returning(*cols).update(...)`.
|
|
63
64
|
- `delete_where(*, expected_version=None, **filters)`
|
|
64
65
|
|
|
65
66
|
### A multi-row UPDATE that racing callers share — `lock_rows_in_pk_order=True`
|
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
- `Model.insert_returning` and `QueryBuilder.returning(*fields)` — a create/update
|
|
6
|
+
write can now ask Postgres to hand back only the columns the caller is
|
|
7
|
+
actually granted, instead of the row the ORM already had in hand (which may
|
|
8
|
+
carry columns the writer's RLS/column-scope never authorised it to read
|
|
9
|
+
back). Guard: `packages/matrx-orm/tests/level1/test_column_scoped_writes.py`.
|
|
5
10
|
- Pool creation always ends. A pool `init` failure now aborts the connection
|
|
6
11
|
(asyncpg's own failure path awaited an untimed graceful close), and
|
|
7
12
|
`asyncpg.create_pool` runs under one deadline (`pool_create_timeout`, default
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: matrx-orm
|
|
3
|
-
Version: 3.1.
|
|
3
|
+
Version: 3.1.187
|
|
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
|
|
@@ -673,6 +673,24 @@ class Model(RuntimeMixin, metaclass=ModelMeta):
|
|
|
673
673
|
await StateManager.cache(cls, instance)
|
|
674
674
|
return cast(Self, instance)
|
|
675
675
|
|
|
676
|
+
@classmethod
|
|
677
|
+
async def insert_returning(
|
|
678
|
+
cls,
|
|
679
|
+
data: dict[str, Any],
|
|
680
|
+
*,
|
|
681
|
+
returning: Sequence[str],
|
|
682
|
+
statement_timeout: float | None = None,
|
|
683
|
+
) -> dict[str, Any]:
|
|
684
|
+
"""INSERT only the columns in ``data`` (the rest take their DB defaults)
|
|
685
|
+
and return only ``returning`` — the write door for an acting-as-user
|
|
686
|
+
insert into a table whose system-only columns the person is not granted.
|
|
687
|
+
See ``matrx_orm.operations.create.insert_returning``."""
|
|
688
|
+
from matrx_orm.operations.create import insert_returning as _insert_returning
|
|
689
|
+
|
|
690
|
+
return await _insert_returning(
|
|
691
|
+
cls, data, returning=returning, statement_timeout=statement_timeout
|
|
692
|
+
)
|
|
693
|
+
|
|
676
694
|
@classmethod
|
|
677
695
|
async def bulk_create(cls, objects_data: list[dict[str, Any]]) -> list[Self]:
|
|
678
696
|
"""
|
|
@@ -228,6 +228,15 @@ class UpdateResult:
|
|
|
228
228
|
rows_affected: int
|
|
229
229
|
updated_rows: list[dict[str, Any]]
|
|
230
230
|
|
|
231
|
+
def __bool__(self) -> bool:
|
|
232
|
+
"""True only when the UPDATE changed a row.
|
|
233
|
+
|
|
234
|
+
A dataclass without this is ALWAYS truthy, so ``if await q.update(...):``
|
|
235
|
+
read as "it changed something" even at zero rows — the runtime reaper
|
|
236
|
+
soft-deleted a stream's frames on that false yes (found 2026-09-26).
|
|
237
|
+
"""
|
|
238
|
+
return self.rows_affected > 0
|
|
239
|
+
|
|
231
240
|
def to_dict(self) -> dict[str, Any]:
|
|
232
241
|
"""Serialise to the legacy dict shape for JSON / API boundaries."""
|
|
233
242
|
return {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
|
+
from collections.abc import Sequence
|
|
4
5
|
from typing import Any, TYPE_CHECKING, Union
|
|
5
6
|
|
|
6
7
|
from matrx_orm.state import StateManager
|
|
@@ -122,6 +123,51 @@ async def save(instance: Model, *, statement_timeout: float | None = None) -> Mo
|
|
|
122
123
|
return instance
|
|
123
124
|
|
|
124
125
|
|
|
126
|
+
async def insert_returning(
|
|
127
|
+
model_cls: type[Model],
|
|
128
|
+
data: dict[str, Any],
|
|
129
|
+
*,
|
|
130
|
+
returning: Sequence[str],
|
|
131
|
+
statement_timeout: float | None = None,
|
|
132
|
+
) -> dict[str, Any]:
|
|
133
|
+
"""INSERT exactly the columns in ``data`` and hand back ``returning`` only.
|
|
134
|
+
|
|
135
|
+
``create()`` materializes every model default and asks for ``RETURNING *``,
|
|
136
|
+
so it needs INSERT and SELECT on every column. A governed table may withhold
|
|
137
|
+
a system-only column from the acting role (``agent.term_list.metadata`` is
|
|
138
|
+
neither insertable nor readable by ``authenticated``), and then an
|
|
139
|
+
acting-as-user create fails with 42501 though the caller never set that
|
|
140
|
+
column. Here the columns the caller did not name take their DATABASE
|
|
141
|
+
defaults, and only the named, granted columns come back. The result is a
|
|
142
|
+
plain dict (python-coerced); a partial row is never cached as a model.
|
|
143
|
+
"""
|
|
144
|
+
if not returning:
|
|
145
|
+
raise ValueError("insert_returning needs at least one returning column")
|
|
146
|
+
fields = model_cls._fields
|
|
147
|
+
unknown = [
|
|
148
|
+
k
|
|
149
|
+
for k in [*data, *returning]
|
|
150
|
+
if not isinstance(fields.get(k), Field) or not getattr(fields[k], "is_native", True)
|
|
151
|
+
]
|
|
152
|
+
if unknown:
|
|
153
|
+
raise ValueError(f"insert_returning: {unknown} are not columns of {model_cls.__name__}")
|
|
154
|
+
prepared = {
|
|
155
|
+
getattr(fields[k], "field_name", k): fields[k].get_db_prep_value(v)
|
|
156
|
+
for k, v in data.items()
|
|
157
|
+
if v is not None
|
|
158
|
+
}
|
|
159
|
+
query = QueryBuilder(model_cls)._build_query()
|
|
160
|
+
query["data"] = prepared
|
|
161
|
+
query["returning"] = [getattr(fields[k], "field_name", k) for k in returning]
|
|
162
|
+
if statement_timeout is not None:
|
|
163
|
+
query["statement_timeout"] = statement_timeout
|
|
164
|
+
row = await QueryExecutor(query).insert(query)
|
|
165
|
+
return {
|
|
166
|
+
key: (fields[key].to_python(value) if isinstance(fields.get(key), Field) else value)
|
|
167
|
+
for key, value in dict(row).items()
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
|
|
125
171
|
async def bulk_create(model_cls: type[Model], objects_data: list[dict[str, Any]]) -> list[Model]:
|
|
126
172
|
"""Bulk insert with field coercion. Returns hydrated model instances."""
|
|
127
173
|
if not objects_data:
|
|
@@ -35,6 +35,19 @@ _SQL_IDENTIFIER_RE = re.compile(r"^[A-Za-z_][A-Za-z0-9_]*$")
|
|
|
35
35
|
_JOIN_TYPES = {"INNER", "LEFT", "RIGHT", "FULL"}
|
|
36
36
|
|
|
37
37
|
|
|
38
|
+
async def _evict_updated_rows(model_cls: type, rows: list[Any]) -> None:
|
|
39
|
+
"""Evict the cache entries for rows an UPDATE ... RETURNING <named columns>
|
|
40
|
+
touched. Keyed by pk when the caller returned it; otherwise the model's
|
|
41
|
+
cache is flushed (losing warmth is free, serving a stale row is not)."""
|
|
42
|
+
if not rows or not StateManager.is_registered(model_cls):
|
|
43
|
+
return
|
|
44
|
+
pks = model_cls._meta.primary_keys or ["id"]
|
|
45
|
+
if all(isinstance(r, dict) and all(pk in r for pk in pks) for r in rows):
|
|
46
|
+
await StateManager.refresh_from_rows(model_cls, rows, max_rows=-1) # evict-only
|
|
47
|
+
else:
|
|
48
|
+
await StateManager.clear_cache(model_cls)
|
|
49
|
+
|
|
50
|
+
|
|
38
51
|
def _merge_pending_into_models(model_cls: type, db_models: list, filters: dict[str, Any]) -> list:
|
|
39
52
|
"""Apply pending Session state to a list of Model instances from DB.
|
|
40
53
|
|
|
@@ -216,6 +229,8 @@ class QueryBuilder(Generic[ModelT]):
|
|
|
216
229
|
verify_empty_val: bool
|
|
217
230
|
#: lock_rows_in_pk_order() — take an UPDATE's row locks ascending by pk.
|
|
218
231
|
lock_rows_in_pk_order_val: bool
|
|
232
|
+
#: returning() — the columns an UPDATE hands back (None = every column).
|
|
233
|
+
returning_fields: tuple[str, ...] | None
|
|
219
234
|
|
|
220
235
|
def __init__(self, model_cls: type[ModelT], database: str | None = None) -> None:
|
|
221
236
|
self.model = model_cls
|
|
@@ -244,6 +259,7 @@ class QueryBuilder(Generic[ModelT]):
|
|
|
244
259
|
self.timeout_val: float | None = None
|
|
245
260
|
self.verify_empty_val = True
|
|
246
261
|
self.lock_rows_in_pk_order_val = False
|
|
262
|
+
self.returning_fields = None
|
|
247
263
|
|
|
248
264
|
def _set_database(self, model_cls: type[ModelT]) -> str:
|
|
249
265
|
if hasattr(model_cls, "_database") and model_cls._database:
|
|
@@ -566,6 +582,37 @@ class QueryBuilder(Generic[ModelT]):
|
|
|
566
582
|
new.lock_rows_in_pk_order_val = True
|
|
567
583
|
return new
|
|
568
584
|
|
|
585
|
+
def returning(self, *fields: str) -> QueryBuilder[ModelT]:
|
|
586
|
+
"""Name the columns an ``update()`` hands back (``RETURNING a, b``).
|
|
587
|
+
|
|
588
|
+
The default is ``RETURNING *``, which needs SELECT on EVERY column. A
|
|
589
|
+
governed table can withhold a column from the acting role (a system-only
|
|
590
|
+
``metadata`` the person may neither read nor write), and then every
|
|
591
|
+
acting-as-user update fails with 42501 even though it touched only
|
|
592
|
+
granted columns. Name the granted columns instead::
|
|
593
|
+
|
|
594
|
+
await TermList.filter(id=x).returning("id", "name", "version").update(name=n)
|
|
595
|
+
|
|
596
|
+
Rows come back as dicts carrying just these columns; the identity cache
|
|
597
|
+
entries for them are EVICTED (a partial row is never cached as a model).
|
|
598
|
+
"""
|
|
599
|
+
if not fields:
|
|
600
|
+
raise ValueError("returning() needs at least one column")
|
|
601
|
+
unknown = [
|
|
602
|
+
f
|
|
603
|
+
for f in fields
|
|
604
|
+
if f not in self.model._fields or not getattr(self.model._fields[f], "is_native", True)
|
|
605
|
+
]
|
|
606
|
+
if unknown:
|
|
607
|
+
raise ValueError(
|
|
608
|
+
f"returning(): {unknown} are not columns of {self.model.__name__}"
|
|
609
|
+
)
|
|
610
|
+
new = self._clone()
|
|
611
|
+
new.returning_fields = tuple(
|
|
612
|
+
getattr(self.model._fields[f], "field_name", f) for f in fields
|
|
613
|
+
)
|
|
614
|
+
return new
|
|
615
|
+
|
|
569
616
|
def using(self, database: str) -> QueryBuilder[ModelT]:
|
|
570
617
|
"""Override the database for this query.
|
|
571
618
|
|
|
@@ -782,6 +829,7 @@ class QueryBuilder(Generic[ModelT]):
|
|
|
782
829
|
"timeout": self.timeout_val,
|
|
783
830
|
"verify_empty": self.verify_empty_val,
|
|
784
831
|
"lock_rows_in_pk_order": self.lock_rows_in_pk_order_val,
|
|
832
|
+
"returning": self.returning_fields,
|
|
785
833
|
}
|
|
786
834
|
return query
|
|
787
835
|
|
|
@@ -980,7 +1028,12 @@ class QueryBuilder(Generic[ModelT]):
|
|
|
980
1028
|
raise ValidationError(model=self.model, reason="No update data provided")
|
|
981
1029
|
executor = await self._get_executor_async()
|
|
982
1030
|
result = await executor.update(**kwargs)
|
|
983
|
-
|
|
1031
|
+
if self.returning_fields is None:
|
|
1032
|
+
await StateManager.refresh_from_rows(self.model, result.updated_rows)
|
|
1033
|
+
else:
|
|
1034
|
+
# Partial rows (named columns only) must never be cached as a
|
|
1035
|
+
# model — drop whatever copy the cache held instead.
|
|
1036
|
+
await _evict_updated_rows(self.model, result.updated_rows)
|
|
984
1037
|
return result
|
|
985
1038
|
except ValidationError:
|
|
986
1039
|
raise
|
|
@@ -1216,10 +1216,14 @@ class QueryExecutor:
|
|
|
1216
1216
|
columns = list(data.keys())
|
|
1217
1217
|
values = list(data.values())
|
|
1218
1218
|
placeholders = [f"${i + 1}" for i in range(len(values))]
|
|
1219
|
+
# ``returning`` (Model.insert_returning) names the columns handed back;
|
|
1220
|
+
# the default ``*`` needs SELECT on every column (see update()).
|
|
1221
|
+
named = query.get("returning")
|
|
1222
|
+
returning_clause = ", ".join(named) if named else "*"
|
|
1219
1223
|
sql = (
|
|
1220
1224
|
f"INSERT INTO {table} ({', '.join(columns)}) "
|
|
1221
1225
|
f"VALUES ({', '.join(placeholders)}) "
|
|
1222
|
-
f"RETURNING
|
|
1226
|
+
f"RETURNING {returning_clause}"
|
|
1223
1227
|
)
|
|
1224
1228
|
|
|
1225
1229
|
try:
|
|
@@ -1650,7 +1654,12 @@ class QueryExecutor:
|
|
|
1650
1654
|
rows = dict_result # type: ignore[assignment]
|
|
1651
1655
|
return UpdateResult(rows_affected=len(rows or []), updated_rows=rows or [])
|
|
1652
1656
|
|
|
1653
|
-
|
|
1657
|
+
# returning() on the builder names the columns handed back; the
|
|
1658
|
+
# default ``*`` needs SELECT on every column, which an acting-as-user
|
|
1659
|
+
# write on a column-governed table does not hold (42501).
|
|
1660
|
+
named = self._full_query_dict.get("returning")
|
|
1661
|
+
returning_clause = ", ".join(named) if named else "*"
|
|
1662
|
+
result = await self.db.execute_write(sql + f" RETURNING {returning_clause}", *params)
|
|
1654
1663
|
return UpdateResult(rows_affected=len(result), updated_rows=result)
|
|
1655
1664
|
|
|
1656
1665
|
except (ValidationError, IntegrityError, DatabaseError, ParameterError):
|
|
@@ -33,22 +33,20 @@ charset-validated here — `provider_key`, `display_name`, `tags`, `status`,
|
|
|
33
33
|
alias (nullable). A DB trigger (`trg_user_secrets_owner_match`) rejects any field
|
|
34
34
|
row whose owner columns don't match its item's owner.
|
|
35
35
|
|
|
36
|
-
**
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
grant/offboarding parent-lock contract.
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
until every producer and reader gate is accepted; 1047 is never applied outside
|
|
51
|
-
the named runner's reviewed rehearsal.
|
|
36
|
+
**Personal-password history.** The installed history counter is mapped and the
|
|
37
|
+
ordinary personal-password capture gate is on. Battery mutations record the
|
|
38
|
+
closed v1 chain under the private writer: revision 1 is an A=A bootstrap and
|
|
39
|
+
later revisions are prior-after-matched deltas. Migrations 1035 and 1036 keep the private
|
|
40
|
+
`vault_history_writer` personal-only and establish the closed v1 envelope.
|
|
41
|
+
Installed migration 1047 requires exact keys, typed identifiers and timestamp,
|
|
42
|
+
locked original ownership, and exactly one manifest and one changed component
|
|
43
|
+
bound to the locked active personal password field. Organization-owned history refuses until the host supplies the
|
|
44
|
+
grant/offboarding parent-lock contract. Capture, list/reveal, and restore are
|
|
45
|
+
backend capabilities for this bounded personal-password chain. Migration 1166
|
|
46
|
+
is reviewed and enabled in source; installed behavior requires the migration
|
|
47
|
+
ledger and exact live validator bodies. The physical history timestamp remains
|
|
48
|
+
the destination audit time, while authenticated backup source dates are retained
|
|
49
|
+
separately when the installed contract supports them.
|
|
52
50
|
|
|
53
51
|
Items may also own N encrypted **file attachments**
|
|
54
52
|
(`users.credential_attachments`). An attachment has its own stable id,
|
|
@@ -391,9 +389,11 @@ delete).
|
|
|
391
389
|
replacement, matching the host bulk reader's revocation order. A focused
|
|
392
390
|
ordering test fails if deletion moves ahead of the parent lock.
|
|
393
391
|
|
|
394
|
-
- **2026-09-
|
|
395
|
-
|
|
396
|
-
|
|
392
|
+
- **2026-09-26** — The personal-password capture gate is on. The battery maps
|
|
393
|
+
the installed history counter and maintains the bounded A=A then A→B chain;
|
|
394
|
+
organization history remains refused pending the canonical grant/offboarding
|
|
395
|
+
parent lock. Guarded migration 1166 does not yet provide backup source-date
|
|
396
|
+
fidelity.
|
|
397
397
|
|
|
398
398
|
- **2026-09-19** — Restored native lifecycle metadata with the parsed, timezone-aware manifest instant at the typed mutation boundary, preserving the manifest string for aggregate integrity checks.
|
|
399
399
|
|
|
@@ -90,9 +90,9 @@ ITEM_SOURCES: tuple[str, ...] = (
|
|
|
90
90
|
"system_import",
|
|
91
91
|
)
|
|
92
92
|
|
|
93
|
-
#
|
|
94
|
-
#
|
|
95
|
-
_PASSWORD_HISTORY_CAPTURE_ENABLED =
|
|
93
|
+
# Eligible personal password writes capture their prior value and the new
|
|
94
|
+
# value atomically. Organization history remains outside this boundary.
|
|
95
|
+
_PASSWORD_HISTORY_CAPTURE_ENABLED = True
|
|
96
96
|
|
|
97
97
|
|
|
98
98
|
class CredentialItemNotFoundError(LookupError):
|
|
@@ -1296,9 +1296,8 @@ def _captures_personal_password_history(
|
|
|
1296
1296
|
) -> bool:
|
|
1297
1297
|
"""Return whether this locked row belongs in the private password history.
|
|
1298
1298
|
|
|
1299
|
-
The module-local gate
|
|
1300
|
-
|
|
1301
|
-
future activation boundary without adding a caller-controlled switch.
|
|
1299
|
+
The module-local gate keeps every existing-field ciphertext writer behind
|
|
1300
|
+
the same eligibility boundary without adding a caller-controlled switch.
|
|
1302
1301
|
"""
|
|
1303
1302
|
return (
|
|
1304
1303
|
_PASSWORD_HISTORY_CAPTURE_ENABLED
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "matrx-orm"
|
|
3
|
-
version = "3.1.
|
|
3
|
+
version = "3.1.187"
|
|
4
4
|
description = "Async-first PostgreSQL ORM with bidirectional migrations, schema introspection, many-to-many relationships, and built-in state caching"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = { text = "MIT" }
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"""Level 1: a write on a column-governed table names only the columns it may touch.
|
|
2
|
+
|
|
3
|
+
REGRESSION — 2026-09-26, aidream term lists. ``agent.term_list.metadata`` (vendor
|
|
4
|
+
caches) is withheld from ``authenticated``: no INSERT, no SELECT. ``create()``
|
|
5
|
+
materializes every model default (so it INSERTs ``metadata``) and asks for
|
|
6
|
+
``RETURNING *`` (so it SELECTs ``metadata``); ``update()`` also asked for
|
|
7
|
+
``RETURNING *``. Every acting-as-user create and edit failed with 42501 though the
|
|
8
|
+
person never set that column. ``Model.insert_returning`` and
|
|
9
|
+
``QueryBuilder.returning()`` are the doors that name the columns instead.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
from typing import Any
|
|
15
|
+
|
|
16
|
+
import pytest
|
|
17
|
+
from matrx_orm.core.fields import JSONBField, TextField
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class _Meta:
|
|
22
|
+
def __init__(self, qualified: str) -> None:
|
|
23
|
+
self.qualified_table_name = qualified
|
|
24
|
+
self.primary_keys = ["id"]
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@pytest.fixture
|
|
28
|
+
def captured_sql(monkeypatch: pytest.MonkeyPatch) -> list[tuple[str, tuple[Any, ...]]]:
|
|
29
|
+
"""Intercept at the executor's DB boundary so the real insert path runs."""
|
|
30
|
+
calls: list[tuple[str, tuple[Any, ...]]] = []
|
|
31
|
+
|
|
32
|
+
from matrx_orm.query import builder as builder_mod
|
|
33
|
+
from matrx_orm.query import executor as executor_mod
|
|
34
|
+
|
|
35
|
+
class _DBStub:
|
|
36
|
+
async def execute_write(self, sql: str, *params: Any, **_kw: Any) -> list[dict[str, Any]]:
|
|
37
|
+
calls.append((sql, params))
|
|
38
|
+
return [{"id": "row-1"}]
|
|
39
|
+
|
|
40
|
+
def _fake_init(self: Any, query: dict[str, Any]) -> None:
|
|
41
|
+
self.query = query
|
|
42
|
+
self.model = query.get("model")
|
|
43
|
+
self.db = _DBStub()
|
|
44
|
+
|
|
45
|
+
async def _no_dict(self: Any, _query: dict[str, Any]) -> Any:
|
|
46
|
+
return NotImplemented
|
|
47
|
+
|
|
48
|
+
monkeypatch.setattr(executor_mod.QueryExecutor, "__init__", _fake_init)
|
|
49
|
+
monkeypatch.setattr(executor_mod.QueryExecutor, "_try_write_dict", _no_dict)
|
|
50
|
+
monkeypatch.setattr(executor_mod.QueryExecutor, "_guard_writable", lambda self, _op: None)
|
|
51
|
+
monkeypatch.setattr(
|
|
52
|
+
builder_mod.QueryBuilder,
|
|
53
|
+
"_build_query",
|
|
54
|
+
lambda self: {"table": self.model._meta.qualified_table_name, "model": self.model},
|
|
55
|
+
)
|
|
56
|
+
return calls
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _term_list_model() -> type:
|
|
60
|
+
fields: dict[str, Any] = {
|
|
61
|
+
"id": TextField(),
|
|
62
|
+
"organization_id": TextField(),
|
|
63
|
+
"name": TextField(),
|
|
64
|
+
"entries": JSONBField(default=[]),
|
|
65
|
+
# The system-only column: a Python default the person cannot write.
|
|
66
|
+
"metadata": JSONBField(default={}),
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
class _TermList:
|
|
70
|
+
_meta = _Meta("agent.term_list")
|
|
71
|
+
_fields = fields
|
|
72
|
+
_read_only = False
|
|
73
|
+
_database = "test_db"
|
|
74
|
+
|
|
75
|
+
def __init__(self, **kw: Any) -> None:
|
|
76
|
+
for name in fields:
|
|
77
|
+
setattr(self, name, None)
|
|
78
|
+
for k, v in kw.items():
|
|
79
|
+
setattr(self, k, v)
|
|
80
|
+
|
|
81
|
+
@classmethod
|
|
82
|
+
def get_database_name(cls) -> str:
|
|
83
|
+
return "test_db"
|
|
84
|
+
|
|
85
|
+
return _TermList
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
@pytest.mark.asyncio
|
|
89
|
+
async def test_insert_returning_writes_only_named_columns_and_returns_only_granted_ones(
|
|
90
|
+
captured_sql,
|
|
91
|
+
) -> None:
|
|
92
|
+
from matrx_orm.operations.create import insert_returning
|
|
93
|
+
|
|
94
|
+
model = _term_list_model()
|
|
95
|
+
row = await insert_returning(
|
|
96
|
+
model,
|
|
97
|
+
{"organization_id": "org-1", "name": "All Green brand terms", "entries": []},
|
|
98
|
+
returning=["id", "name"],
|
|
99
|
+
)
|
|
100
|
+
sql, params = captured_sql[0]
|
|
101
|
+
assert "metadata" not in sql, sql # the DB default applies; the person never names it
|
|
102
|
+
assert sql.endswith("RETURNING id, name"), sql
|
|
103
|
+
assert "RETURNING *" not in sql
|
|
104
|
+
assert params[1] == "All Green brand terms"
|
|
105
|
+
assert row == {"id": "row-1"}
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
@pytest.mark.asyncio
|
|
109
|
+
async def test_insert_returning_refuses_unknown_columns(captured_sql) -> None:
|
|
110
|
+
from matrx_orm.operations.create import insert_returning
|
|
111
|
+
|
|
112
|
+
with pytest.raises(ValueError, match="not columns"):
|
|
113
|
+
await insert_returning(_term_list_model(), {"name": "x"}, returning=["id", "nope"])
|
|
114
|
+
assert captured_sql == []
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def test_builder_returning_names_columns_for_update() -> None:
|
|
118
|
+
from matrx_orm.query.builder import QueryBuilder
|
|
119
|
+
|
|
120
|
+
model = _term_list_model()
|
|
121
|
+
qb = QueryBuilder(model)
|
|
122
|
+
scoped = qb.returning("id", "name")
|
|
123
|
+
assert scoped.returning_fields == ("id", "name")
|
|
124
|
+
assert qb.returning_fields is None # chainable clone, never mutates the source
|
|
125
|
+
with pytest.raises(ValueError, match="not columns"):
|
|
126
|
+
qb.returning("metadatax")
|
|
@@ -1324,17 +1324,17 @@ async def test_second_history_write_failure_propagates_from_atomic_transaction(m
|
|
|
1324
1324
|
assert updates # The real transaction owns this statement and rolls it back on the propagated failure.
|
|
1325
1325
|
|
|
1326
1326
|
|
|
1327
|
-
def
|
|
1327
|
+
def test_password_history_capture_is_on_and_not_a_public_writer_option():
|
|
1328
1328
|
from matrx_orm.secrets_battery import items
|
|
1329
1329
|
|
|
1330
|
-
assert items._PASSWORD_HISTORY_CAPTURE_ENABLED is
|
|
1330
|
+
assert items._PASSWORD_HISTORY_CAPTURE_ENABLED is True
|
|
1331
1331
|
for writer in (items.update_credential_field_value, items.rotate_credential_fields):
|
|
1332
1332
|
assert "capture" not in inspect.signature(writer).parameters
|
|
1333
1333
|
|
|
1334
1334
|
|
|
1335
1335
|
@pytest.mark.asyncio
|
|
1336
1336
|
async def test_enabled_history_capture_chains_two_writers_and_rolls_back(monkeypatch):
|
|
1337
|
-
"""
|
|
1337
|
+
"""An active capture writer propagates append failure so the transaction rolls back."""
|
|
1338
1338
|
from matrx_orm.secrets_battery import items
|
|
1339
1339
|
|
|
1340
1340
|
monkeypatch.setenv("CREDENTIALS_ENCRYPTION_KEY", _fernet_key())
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|