matrx-orm 3.1.227__tar.gz → 3.1.229__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.227 → matrx_orm-3.1.229}/CLAUDE.md +8 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/PKG-INFO +1 -1
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/core/base.py +12 -3
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/operations/create.py +26 -3
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/query/executor.py +14 -3
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/schema_builder/common.py +3 -60
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/schema_builder/package_wiring.py +74 -3
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/state.py +34 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/pyproject.toml +1 -1
- matrx_orm-3.1.229/tests/test_state_cache_sweeps_stale.py +52 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/.gitignore +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/AGENTS.md +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/BASE_CLASS_METHODS.md +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/CHANGELOG.md +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/MODEL_API.md +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/README.md +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/database/orm/extended/managers/ai_model_base.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/docs/migrations.md +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/FEATURE.md +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/MODULE_README.md +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/__init__.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/adapters/MODULE_README.md +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/adapters/__init__.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/adapters/async_postgresql.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/adapters/base_adapter.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/adapters/postgrest_client_adapter.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/adapters/supabase_adapter.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/admin/FEATURE.md +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/admin/__init__.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/admin/router.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/api/__init__.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/api/auth.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/api/config.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/api/handlers.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/api/protocol.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/api/server.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/associations.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/cache_debug.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/catalog.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/catalog_sql.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/client/MODULE_README.md +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/client/__init__.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/client/postgres_connection.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/client/postgrest.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/client/supabase_auth.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/client/supabase_config.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/client/supabase_manager.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/core/EXTENDED-TASK.md +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/core/FEATURE.md +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/core/MODULE_README.md +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/core/RELATIONS-TASKS.md +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/core/TASKS.md +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/core/__init__.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/core/admin_lane.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/core/async_db_manager.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/core/config.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/core/connections.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/core/db_function.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/core/diagnostics.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/core/expressions.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/core/extended.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/core/fields.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/core/foreign_session_state.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/core/introspection.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/core/listen.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/core/loop_filters.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/core/model_dto.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/core/model_view.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/core/one_database.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/core/paginator.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/core/pool_maintenance.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/core/pool_watch.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/core/pooler_role.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/core/pydantic_bridge.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/core/read_write.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/core/registry.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/core/relations.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/core/resilience.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/core/rls_session.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/core/session_context.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/core/signals.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/core/statement_ceiling.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/core/tls.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/core/transaction.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/core/types.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/core/write_queue.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/core/write_retry.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/entity.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/error_handling.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/exceptions.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/extended/__init__.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/extended/app_error_handler.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/identity_rule.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/local_sqlite.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/middleware/__init__.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/middleware/base.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/migrations/MODULE_README.md +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/migrations/__init__.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/migrations/cli.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/migrations/ddl.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/migrations/diff.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/migrations/executor.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/migrations/integration.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/migrations/loader.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/migrations/operations.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/migrations/state.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/migrations/table_filter.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/no_org_assignment.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/operations/FEATURE.md +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/operations/MODULE_README.md +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/operations/__init__.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/operations/bulk_update_values.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/operations/catalog_select.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/operations/conflict.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/operations/conflict_writes.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/operations/db_functions.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/operations/delete.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/operations/dynamic_admin.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/operations/dynamic_crud.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/operations/graph_walk.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/operations/latest_rows.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/operations/queue_claim.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/operations/read.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/operations/relational_backfill.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/operations/staging_load.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/operations/update.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/platform_access.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/platform_db.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/py.typed +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/pytest_lock_guard.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/pytest_plugin.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/python_sql/MODULE_README.md +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/python_sql/__init__.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/python_sql/db_objects.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/python_sql/table_detailed_relationships.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/python_sql/table_typescript_relationship.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/query/FEATURE.md +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/query/MODULE_README.md +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/query/__init__.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/query/builder.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/resources/__init__.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/resources/additional-assigners-2026-09-12.json +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/resources/org_assignment_trigger_baseline.json +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/schema_builder/FEATURE.md +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/schema_builder/MODULE_README.md +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/schema_builder/__init__.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/schema_builder/code_handler.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/schema_builder/codegen_writer.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/schema_builder/columns.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/schema_builder/diff_preview.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/schema_builder/entity_capabilities.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/schema_builder/excluded_targets.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/schema_builder/generator.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/schema_builder/helpers/__init__.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/schema_builder/helpers/base_generators.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/schema_builder/helpers/entity_generators.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/schema_builder/helpers/git_checker.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/schema_builder/relationships.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/schema_builder/runner.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/schema_builder/schema.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/schema_builder/schema_manager.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/schema_builder/tables.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/schema_builder/views.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/secrets_battery/FEATURE.md +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/secrets_battery/__init__.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/secrets_battery/attachments.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/secrets_battery/backup_restore.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/secrets_battery/crypto.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/secrets_battery/host_authorization.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/secrets_battery/items.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/secrets_battery/model.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/secrets_battery/mutation_receipts.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/secrets_battery/native_enable.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/secrets_battery/native_lifecycle.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/secrets_battery/native_passkeys.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/secrets_battery/native_source.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/secrets_battery/org_service.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/secrets_battery/org_vault_gate.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/secrets_battery/service.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/secrets_battery/vault_history.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/session/README.md +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/session/__init__.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/session/coalesce.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/session/dag.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/session/errors.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/session/fallback.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/session/flush.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/session/lifecycle.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/session/managed.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/session/op.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/session/reads.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/session/session.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/session/telemetry.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/sql_executor/MODULE_README.md +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/sql_executor/__init__.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/sql_executor/executor.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/sql_executor/queries.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/sql_executor/registry.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/sql_executor/types.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/sql_executor/utils.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/utils/__init__.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/utils/sql_utils.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/utils/type_converters.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/matrx_orm/write_actor.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/scripts/git-branches.sh +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/scripts/publish.sh +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/scripts/release.sh +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/MODULE_README.md +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/__init__.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/conftest.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/MODULE_README.md +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/__init__.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_adapter_registry.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_admin_db_columns.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_admin_response_rendering.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_admin_search_negation.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_admin_search_sentinels.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_advisory_lock.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_agent_message.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_api_auth.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_api_config.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_api_handlers.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_api_protocol.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_array_agg_order_by.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_association_trigger_actor_naming.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_associations.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_associations_wiring.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_bulk_hydration_offload.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_bulk_update_by_pk.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_bulk_upsert_increment_set_fields.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_cache_debug.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_call_function.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_case_when.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_catalog.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_column_scoped_writes.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_committed_row_guard.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_composite_pk_filter.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_composite_pk_write_paths.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_config.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_conflict_target.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_conflict_writes.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_connection_codecs.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_connection_poison_guard.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_connection_primitives.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_count_composite_distinct.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_count_limit_param_leak.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_db_function_field.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_ddl_generator.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_deadlock_retry.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_derived_table.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_dirty_tracking.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_dynamic_crud.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_exceptions.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_execute_query_integrity_mapping.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_expression_primitives.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_fields.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_filter_jsonb_agg_array_index.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_fk_cycle_resolution.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_from_alias.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_fts.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_func_expression_args.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_graph_walk.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_having_annotate_alias.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_insert_ignore_and_admin_primitives.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_introspect_rls_policies.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_join_and_aggregate.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_latest_rows.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_listen_notify.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_local_sqlite.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_lock_contention_retry.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_managed_write_guard.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_matrx_entity.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_migration_diff_types.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_migration_loader.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_model_instance.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_model_meta.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_optimistic_concurrency.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_order_by_expression.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_org_assignment_inventory.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_orm_banners_are_client_safe.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_parameter_name_hydration.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_patch_jsonb_path.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_percentile_cont.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_persisted_count.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_person_scoped_session_bypasses_shared_cache.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_pool_create_never_wedges.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_pool_holder_census.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_pool_loop_recreation.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_pool_maintenance.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_postgrest_filters.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_pydantic_bridge.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_query_builder.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_query_error_detail.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_query_executor_sql.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_query_timeout.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_querybuilder_clone_semantics.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_queue_claim.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_read_connection_retry.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_read_write_declared.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_registry.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_registry_multi_database.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_registry_multi_schema.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_relational_backfill.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_relations.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_resilience.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_rls_session_scope.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_schema_exists.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_session_advisory_lock.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_standalone_write_session_context.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_state_cache.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_subquery_filter_raw.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_subquery_in_filter.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_subquery_nested_expressions.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_supabase_auth.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_supabase_config.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_tls.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_transaction_database_identity.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_transaction_gucs_one_round_trip.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_transaction_pool_release_sends_nothing.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_typed_join_projection.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_typed_predicates.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_update_case_expression.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_update_subquery.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_update_with_rebase.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_upsert_default_leak.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_upsert_with_conflict.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_values_jsonb_decode.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_watched_lifecycle.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_write_queue_deadline.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level1/test_write_retry_semantics.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level2/MODULE_README.md +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level2/__init__.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level2/conftest.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level2/test_bulk_ops.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level2/test_cache_integration.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level2/test_crud.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level2/test_foreign_keys.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level2/test_m2m.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level2/test_manager.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level2/test_migrations_live.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level2/test_query_execution.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level2/test_schema_diff.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/level2/verify_committed_row_guard_pg17.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/live_pooler_role.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/native_source_cases.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/native_source_oracle.rs +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/sample_project/.env.example +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/sample_project/README.md +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/sample_project/__init__.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/sample_project/generate.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/sample_project/generated/.gitkeep +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/sample_project/matrx_orm.yaml +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/sample_project/test_schema_generation.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/sample_project_desktop/.env.example +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/sample_project_desktop/README.md +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/sample_project_desktop/__init__.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/sample_project_desktop/client_example.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/sample_project_desktop/client_example.ts +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/sample_project_desktop/client_supabase_example.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/sample_project_desktop/server.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/schema/entity_tests.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/schema/test_base_generation.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/schema/test_composite_pk_fk_generation.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/schema/test_composite_unique_generation.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/schema/test_dto_identity_generation.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/schema/test_entity_capability_generation.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/schema/test_enum_ordering.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/schema/test_excluded_fk_targets.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/schema/test_generate_schema.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/schema/test_junction_analysis.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/schema/test_multi_schema_output.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/schema/test_schema_analysis.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/schema/test_sql_expression_defaults.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/schema/test_table_relationships_query.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/schema/test_view_generation.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/schema_builder/test_array_default_parsing.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/schema_builder/test_focused_generation_plan.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/schema_builder/test_host_models_aggregator.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/schema_builder/test_never_filter_columns.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/session/__init__.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/session/conftest.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/session/test_a_failed_capture_still_names_the_failure.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/session/test_cache_no_downgrade.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/session/test_capture_poison_proof.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/session/test_coalesce.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/session/test_dag.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/session/test_disk_spill_fallback.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/session/test_flush_individual_fallback.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/session/test_governed_write.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/session/test_managed.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/session/test_op_enqueue_site.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/session/test_reads.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/session/test_record_error_bounded_insert.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/session/test_record_error_storm.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/session/test_session.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/session/test_spill_guard_plugin.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/test_a_backend_handed_over_mid_transaction_never_takes_our_writes.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/test_a_list_of_uuids_binds_as_uuid_array.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/test_a_read_only_backend_never_refuses_our_writes.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/test_a_sealed_field_shows_no_character_of_its_value.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/test_array_arg_element_type.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/test_attachment_mutation_serialization.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/test_backup_alias_conflict.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/test_backup_history_restore.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/test_backup_restore_live.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/test_call_function_as.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/test_call_function_none_mode.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/test_composite_fk_is_not_a_column_fk.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/test_database_name_alias.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/test_db_functions.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/test_dsn_password_masking.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/test_dynamic_select_unregistered.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/test_foreign_session_state.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/test_immutable_insert_or_exact_verify.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/test_keyed_digest.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/test_model_cls_refactor.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/test_native_enable.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/test_native_lifecycle.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/test_native_lifecycle_fences.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/test_native_passkey_receipts.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/test_native_source.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/test_no_blocking_asyncpg_tls.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/test_one_database.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/test_order_by_desc_nulls_last.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/test_org_vault_gate.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/test_package_wiring_views.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/test_pooler_role_guard.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/test_secret_audit_names_its_organization.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/test_secrets_battery.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/test_secrets_minting_keys.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/test_shared_lock_guard.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/test_sql_param_casts.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/test_statement_ceiling_warning.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/test_sync_twins_guard.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/test_update_result_truthiness.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/test_user_visible_lookup.py +0 -0
- {matrx_orm-3.1.227 → matrx_orm-3.1.229}/tests/test_vault_aggregate_recovery_stateful.py +0 -0
|
@@ -158,6 +158,14 @@ enforced in code:
|
|
|
158
158
|
attribution, or whether a request may run at all passes `use_cache=False`
|
|
159
159
|
(`load_by_id(id, use_cache=False)`). Fast is not a reason to guess.
|
|
160
160
|
|
|
161
|
+
4. **Entries die with their age.** Writes sweep entries the policy already treats
|
|
162
|
+
as stale (`ModelState.sweep_stale`, every `STALE_SWEEP_EVERY_WRITES`); an
|
|
163
|
+
append-only writer of big JSON passes `returning=[...]` to `upsert` /
|
|
164
|
+
`bulk_create` (or uses `insert_returning`) so its rows are neither read back
|
|
165
|
+
nor cached. Before this an unread entry lived for the whole process, and a
|
|
166
|
+
workflow worker's checkpoints/outcomes/events grew it until ECS killed the
|
|
167
|
+
task for memory (MKT-111, 2026-10-15). Guard: `tests/test_state_cache_sweeps_stale.py`.
|
|
168
|
+
|
|
161
169
|
This is not theoretical hygiene. On 2026-07-25 rule 1 was missing: `session/flush.py`
|
|
162
170
|
builds a `{pk + payload}` stub per queued UPDATE and `bulk_update` cached it, so a
|
|
163
171
|
chat conversation read back with `organization_id = None` right after its own
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: matrx-orm
|
|
3
|
-
Version: 3.1.
|
|
3
|
+
Version: 3.1.229
|
|
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
|
|
@@ -693,14 +693,19 @@ class Model(RuntimeMixin, metaclass=ModelMeta):
|
|
|
693
693
|
)
|
|
694
694
|
|
|
695
695
|
@classmethod
|
|
696
|
-
async def bulk_create(
|
|
696
|
+
async def bulk_create(
|
|
697
|
+
cls, objects_data: list[dict[str, Any]], *, returning: Sequence[str] | None = None
|
|
698
|
+
) -> list[Self]:
|
|
697
699
|
"""
|
|
698
700
|
Bulk create multiple instances using enhanced bulk operations.
|
|
699
701
|
Follows the same data processing pipeline as individual create().
|
|
702
|
+
|
|
703
|
+
``returning``: hand back only these columns, as plain dicts, uncached —
|
|
704
|
+
for append-only writers that must not read large rows back.
|
|
700
705
|
"""
|
|
701
706
|
from matrx_orm.operations.create import bulk_create
|
|
702
707
|
|
|
703
|
-
return cast(list[Self], await bulk_create(cls, objects_data))
|
|
708
|
+
return cast(list[Self], await bulk_create(cls, objects_data, returning=returning))
|
|
704
709
|
|
|
705
710
|
@classmethod
|
|
706
711
|
async def bulk_update(cls, objects: Sequence[Model], fields: list[str]) -> int:
|
|
@@ -728,6 +733,7 @@ class Model(RuntimeMixin, metaclass=ModelMeta):
|
|
|
728
733
|
update_fields: list[str] | None = None,
|
|
729
734
|
*,
|
|
730
735
|
on_conflict: list[str] | ConflictTarget | None = None, # noqa: F821
|
|
736
|
+
returning: Sequence[str] | None = None,
|
|
731
737
|
) -> Self:
|
|
732
738
|
"""INSERT ... ON CONFLICT (...) DO UPDATE SET ... RETURNING *
|
|
733
739
|
|
|
@@ -744,11 +750,14 @@ class Model(RuntimeMixin, metaclass=ModelMeta):
|
|
|
744
750
|
partial unique index. Preferred over
|
|
745
751
|
``conflict_fields``; exactly one of the two must be
|
|
746
752
|
provided.
|
|
753
|
+
returning: Only these columns are read back; the instance is then
|
|
754
|
+
not cached (it is not a row snapshot). For append-only
|
|
755
|
+
writers of large JSON.
|
|
747
756
|
"""
|
|
748
757
|
from matrx_orm.operations.create import upsert
|
|
749
758
|
|
|
750
759
|
target = _resolve_on_conflict(conflict_fields, on_conflict)
|
|
751
|
-
return cast(Self, await upsert(cls, data, target, update_fields))
|
|
760
|
+
return cast(Self, await upsert(cls, data, target, update_fields, returning=returning))
|
|
752
761
|
|
|
753
762
|
@classmethod
|
|
754
763
|
async def bulk_upsert(
|
|
@@ -168,8 +168,19 @@ async def insert_returning(
|
|
|
168
168
|
}
|
|
169
169
|
|
|
170
170
|
|
|
171
|
-
async def bulk_create(
|
|
172
|
-
|
|
171
|
+
async def bulk_create(
|
|
172
|
+
model_cls: type[Model],
|
|
173
|
+
objects_data: list[dict[str, Any]],
|
|
174
|
+
*,
|
|
175
|
+
returning: Sequence[str] | None = None,
|
|
176
|
+
) -> list[Any]:
|
|
177
|
+
"""Bulk insert with field coercion. Returns hydrated model instances.
|
|
178
|
+
|
|
179
|
+
``returning`` names the only columns handed back: the result is then a list
|
|
180
|
+
of plain dicts and nothing is cached. An append-only writer of large JSON
|
|
181
|
+
(workflow events) uses it so its rows are not read back over the wire,
|
|
182
|
+
decoded, and kept in the process cache.
|
|
183
|
+
"""
|
|
173
184
|
if not objects_data:
|
|
174
185
|
return []
|
|
175
186
|
|
|
@@ -192,6 +203,9 @@ async def bulk_create(model_cls: type[Model], objects_data: list[dict[str, Any]]
|
|
|
192
203
|
|
|
193
204
|
query = QueryBuilder(model_cls)._build_query()
|
|
194
205
|
query["data"] = data_list
|
|
206
|
+
if returning:
|
|
207
|
+
query["returning"] = [getattr(model_cls._fields[k], "field_name", k) for k in returning]
|
|
208
|
+
return await QueryExecutor(query).bulk_insert(query)
|
|
195
209
|
|
|
196
210
|
executor = QueryExecutor(query)
|
|
197
211
|
created_instances = await executor.bulk_insert(query)
|
|
@@ -236,12 +250,17 @@ async def upsert(
|
|
|
236
250
|
data: dict[str, Any],
|
|
237
251
|
on_conflict: OnConflictArg,
|
|
238
252
|
update_fields: list[str] | None = None,
|
|
253
|
+
returning: Sequence[str] | None = None,
|
|
239
254
|
) -> Model:
|
|
240
255
|
"""INSERT ... ON CONFLICT (...) DO UPDATE SET ... RETURNING *
|
|
241
256
|
|
|
242
257
|
``on_conflict`` accepts either a ``list[str]`` of column names (the
|
|
243
258
|
original behaviour) OR a :class:`ConflictTarget` describing an
|
|
244
259
|
expression / partial unique index.
|
|
260
|
+
|
|
261
|
+
``returning`` names the only columns read back: the instance then carries
|
|
262
|
+
the caller's values plus those columns, and is NOT cached (it is not a row
|
|
263
|
+
snapshot). For append-only writers of large JSON.
|
|
245
264
|
"""
|
|
246
265
|
conflict_fields, target = _normalise_on_conflict(on_conflict)
|
|
247
266
|
instance = model_cls(**data)
|
|
@@ -271,6 +290,9 @@ async def upsert(
|
|
|
271
290
|
conflict_fields,
|
|
272
291
|
)
|
|
273
292
|
|
|
293
|
+
if returning:
|
|
294
|
+
query["returning"] = [getattr(model_cls._fields[k], "field_name", k) for k in returning]
|
|
295
|
+
|
|
274
296
|
executor = QueryExecutor(query)
|
|
275
297
|
result = await executor.upsert(query)
|
|
276
298
|
|
|
@@ -280,7 +302,8 @@ async def upsert(
|
|
|
280
302
|
value = field.to_python(value)
|
|
281
303
|
setattr(instance, key, value)
|
|
282
304
|
|
|
283
|
-
|
|
305
|
+
if not returning:
|
|
306
|
+
await StateManager.cache(model_cls, instance)
|
|
284
307
|
return instance
|
|
285
308
|
|
|
286
309
|
|
|
@@ -1296,13 +1296,19 @@ class QueryExecutor:
|
|
|
1296
1296
|
chunk_values.append(row_data.get(col))
|
|
1297
1297
|
param_index += 1
|
|
1298
1298
|
placeholders_list.append(f"({', '.join(row_phs)})")
|
|
1299
|
+
named = query.get("returning")
|
|
1299
1300
|
sql = (
|
|
1300
1301
|
f"INSERT INTO {table} ({', '.join(columns)}) "
|
|
1301
1302
|
f"VALUES {', '.join(placeholders_list)} "
|
|
1302
|
-
f"RETURNING *"
|
|
1303
|
+
f"RETURNING {', '.join(named) if named else '*'}"
|
|
1303
1304
|
)
|
|
1304
1305
|
chunk_rows = await self.db.execute_write(sql, *chunk_values)
|
|
1305
|
-
|
|
1306
|
+
if named:
|
|
1307
|
+
# Plain dicts of the named columns: a partial row is never
|
|
1308
|
+
# hydrated into a Model (and so never cached as one).
|
|
1309
|
+
results.extend(dict(row) for row in chunk_rows) # type: ignore[misc]
|
|
1310
|
+
else:
|
|
1311
|
+
results.extend(self._make(row) for row in chunk_rows)
|
|
1306
1312
|
return results
|
|
1307
1313
|
except DatabaseError:
|
|
1308
1314
|
# Already classified upstream — see note on single-insert.
|
|
@@ -1371,11 +1377,16 @@ class QueryExecutor:
|
|
|
1371
1377
|
)
|
|
1372
1378
|
|
|
1373
1379
|
set_clause = ", ".join(f"{f} = EXCLUDED.{f}" for f in fields_to_update)
|
|
1380
|
+
# ``returning`` (Model.upsert(returning=...)) names the columns handed
|
|
1381
|
+
# back. An append-only writer of big JSON (a workflow node outcome)
|
|
1382
|
+
# must not read its own megabytes back over the wire and decode them.
|
|
1383
|
+
named = query.get("returning")
|
|
1384
|
+
returning_clause = ", ".join(named) if named else "*"
|
|
1374
1385
|
sql = (
|
|
1375
1386
|
f"INSERT INTO {table} ({', '.join(columns)}) "
|
|
1376
1387
|
f"VALUES ({', '.join(placeholders)}) "
|
|
1377
1388
|
f"ON CONFLICT {target_clause} DO UPDATE SET {set_clause} "
|
|
1378
|
-
f"RETURNING
|
|
1389
|
+
f"RETURNING {returning_clause}"
|
|
1379
1390
|
)
|
|
1380
1391
|
|
|
1381
1392
|
try:
|
|
@@ -141,66 +141,9 @@ DEBUG_CONFIG = {
|
|
|
141
141
|
"verbose": False,
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
-
#
|
|
145
|
-
#
|
|
146
|
-
|
|
147
|
-
# the abstract base and never gets its table wired) or silently rebinds a field
|
|
148
|
-
# type. A table whose PascalCase lands on one of these is renamed deterministically
|
|
149
|
-
# by safe_model_class_name() to <Schema><Pascal> (e.g. ai.model -> AiModel). This
|
|
150
|
-
# is the ONLY place a name still carries a schema, and only for a true collision.
|
|
151
|
-
RESERVED_MODEL_NAMES: frozenset[str] = frozenset(
|
|
152
|
-
{
|
|
153
|
-
"Model",
|
|
154
|
-
"BaseManager",
|
|
155
|
-
"BaseDTO",
|
|
156
|
-
"ModelView",
|
|
157
|
-
"model_registry",
|
|
158
|
-
"Enum",
|
|
159
|
-
"dataclass",
|
|
160
|
-
"ClassVar",
|
|
161
|
-
"Field",
|
|
162
|
-
"CharField",
|
|
163
|
-
"TextField",
|
|
164
|
-
"IntegerField",
|
|
165
|
-
"BigIntegerField",
|
|
166
|
-
"SmallIntegerField",
|
|
167
|
-
"BooleanField",
|
|
168
|
-
"FloatField",
|
|
169
|
-
"DecimalField",
|
|
170
|
-
"DateTimeField",
|
|
171
|
-
"DateField",
|
|
172
|
-
"TimeField",
|
|
173
|
-
"UUIDField",
|
|
174
|
-
"JSONField",
|
|
175
|
-
"JSONBField",
|
|
176
|
-
"EnumField",
|
|
177
|
-
"ForeignKey",
|
|
178
|
-
"ObjectField",
|
|
179
|
-
"BinaryField",
|
|
180
|
-
"IPAddressField",
|
|
181
|
-
"RangeField",
|
|
182
|
-
"VectorField",
|
|
183
|
-
"TextArrayField",
|
|
184
|
-
"IntegerArrayField",
|
|
185
|
-
"UUIDArrayField",
|
|
186
|
-
"FloatArrayField",
|
|
187
|
-
}
|
|
188
|
-
)
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
def safe_model_class_name(table_name: str, schema: str | None, to_pascal_case) -> str:
|
|
192
|
-
"""PascalCase class name for *table_name*, schema-prefixed ONLY if the bare
|
|
193
|
-
PascalCase collides with a framework-reserved symbol (see RESERVED_MODEL_NAMES).
|
|
194
|
-
|
|
195
|
-
e.g. ``ai.model`` -> ``AiModel`` (a class literally named ``Model`` is
|
|
196
|
-
unusable), while every non-reserved table keeps its clean, prefix-free name.
|
|
197
|
-
The same (table, schema) always yields the same name, so a FK target and the
|
|
198
|
-
target's own class agree.
|
|
199
|
-
"""
|
|
200
|
-
base = to_pascal_case(table_name)
|
|
201
|
-
if base in RESERVED_MODEL_NAMES:
|
|
202
|
-
return f"{to_pascal_case(schema or 'public')}{base}"
|
|
203
|
-
return base
|
|
144
|
+
# RESERVED_MODEL_NAMES / safe_model_class_name live in package_wiring.py (stdlib-only, so the
|
|
145
|
+
# package-wiring drift gate can name view classes without importing matrx_orm); re-exported here.
|
|
146
|
+
from matrx_orm.schema_builder.package_wiring import RESERVED_MODEL_NAMES, safe_model_class_name # noqa: E402,F401
|
|
204
147
|
|
|
205
148
|
|
|
206
149
|
def resolve_fk_related_model_name(
|
|
@@ -179,6 +179,79 @@ def _lookup(inventory: dict[tuple[str, str], TableInfo], table: str) -> TableInf
|
|
|
179
179
|
return info
|
|
180
180
|
|
|
181
181
|
|
|
182
|
+
# Names a generated model class can NEVER take, because the models file imports
|
|
183
|
+
# or defines them at module scope — a model class shadowing one of these either
|
|
184
|
+
# breaks the module (e.g. a class named `Model` is special-cased by ModelMeta as
|
|
185
|
+
# the abstract base and never gets its table wired) or silently rebinds a field
|
|
186
|
+
# type. A table whose PascalCase lands on one of these is renamed deterministically
|
|
187
|
+
# by safe_model_class_name() to <Schema><Pascal> (e.g. ai.model -> AiModel). This
|
|
188
|
+
# is the ONLY place a name still carries a schema, and only for a true collision.
|
|
189
|
+
RESERVED_MODEL_NAMES: frozenset[str] = frozenset(
|
|
190
|
+
{
|
|
191
|
+
"Model",
|
|
192
|
+
"BaseManager",
|
|
193
|
+
"BaseDTO",
|
|
194
|
+
"ModelView",
|
|
195
|
+
"model_registry",
|
|
196
|
+
"Enum",
|
|
197
|
+
"dataclass",
|
|
198
|
+
"ClassVar",
|
|
199
|
+
"Field",
|
|
200
|
+
"CharField",
|
|
201
|
+
"TextField",
|
|
202
|
+
"IntegerField",
|
|
203
|
+
"BigIntegerField",
|
|
204
|
+
"SmallIntegerField",
|
|
205
|
+
"BooleanField",
|
|
206
|
+
"FloatField",
|
|
207
|
+
"DecimalField",
|
|
208
|
+
"DateTimeField",
|
|
209
|
+
"DateField",
|
|
210
|
+
"TimeField",
|
|
211
|
+
"UUIDField",
|
|
212
|
+
"JSONField",
|
|
213
|
+
"JSONBField",
|
|
214
|
+
"EnumField",
|
|
215
|
+
"ForeignKey",
|
|
216
|
+
"ObjectField",
|
|
217
|
+
"BinaryField",
|
|
218
|
+
"IPAddressField",
|
|
219
|
+
"RangeField",
|
|
220
|
+
"VectorField",
|
|
221
|
+
"TextArrayField",
|
|
222
|
+
"IntegerArrayField",
|
|
223
|
+
"UUIDArrayField",
|
|
224
|
+
"FloatArrayField",
|
|
225
|
+
}
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def safe_model_class_name(table_name: str, schema: str | None, to_pascal_case) -> str:
|
|
230
|
+
"""PascalCase class name for *table_name*, schema-prefixed ONLY if the bare
|
|
231
|
+
PascalCase collides with a framework-reserved symbol (see RESERVED_MODEL_NAMES).
|
|
232
|
+
|
|
233
|
+
e.g. ``ai.model`` -> ``AiModel`` (a class literally named ``Model`` is
|
|
234
|
+
unusable), while every non-reserved table keeps its clean, prefix-free name.
|
|
235
|
+
The same (table, schema) always yields the same name, so a FK target and the
|
|
236
|
+
target's own class agree.
|
|
237
|
+
"""
|
|
238
|
+
base = to_pascal_case(table_name)
|
|
239
|
+
if base in RESERVED_MODEL_NAMES:
|
|
240
|
+
return f"{to_pascal_case(schema or 'public')}{base}"
|
|
241
|
+
return base
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
def _pascal_case(s: str) -> str:
|
|
245
|
+
"""Stdlib twin of ``DataTransformer.to_pascal_case`` (matrx_utils): snake-normalize, then title each part.
|
|
246
|
+
|
|
247
|
+
Kept stdlib-only so the wiring gate needs neither matrx_orm nor matrx_utils's runtime deps; a drift
|
|
248
|
+
from the generator's naming fails the gate loudly (the class is checked against the models file).
|
|
249
|
+
"""
|
|
250
|
+
s = re.sub(r"(?<!^)(?=[A-Z])", "_", s)
|
|
251
|
+
s = re.sub(r"[^a-zA-Z0-9]+", "_", s).lower()
|
|
252
|
+
return "".join(x.title() for x in s.split("_"))
|
|
253
|
+
|
|
254
|
+
|
|
182
255
|
def _lookup_view(
|
|
183
256
|
inventory: dict[tuple[str, str], TableInfo], view: str, python_root: str | Path | None
|
|
184
257
|
) -> TableInfo:
|
|
@@ -190,9 +263,7 @@ def _lookup_view(
|
|
|
190
263
|
raise PackageWiringError(
|
|
191
264
|
f"package_wiring: view '{view}' — schema '{schema}' has no generated models module"
|
|
192
265
|
)
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
pascal = safe_model_class_name(snake, schema, dt_utils.to_pascal_case)
|
|
266
|
+
pascal = safe_model_class_name(snake, schema, _pascal_case)
|
|
196
267
|
if python_root is not None:
|
|
197
268
|
models_file = Path(python_root) / (sibling.models_module.replace(".", "/") + ".py")
|
|
198
269
|
tree = ast.parse(models_file.read_text(), filename=str(models_file))
|
|
@@ -57,6 +57,12 @@ def _scream_downgrade(model_class, blanked: list[str]) -> None:
|
|
|
57
57
|
)
|
|
58
58
|
|
|
59
59
|
|
|
60
|
+
#: Every this-many cache writes on one model, entries the policy already treats
|
|
61
|
+
#: as stale are dropped (``ModelState.sweep_stale``). Bounds the identity cache
|
|
62
|
+
#: by time instead of letting it grow for the life of the process.
|
|
63
|
+
STALE_SWEEP_EVERY_WRITES = 200
|
|
64
|
+
|
|
65
|
+
|
|
60
66
|
class CachePolicy(Enum):
|
|
61
67
|
PERMANENT = "permanent"
|
|
62
68
|
LONG_TERM = "long_term"
|
|
@@ -75,6 +81,7 @@ class ModelState:
|
|
|
75
81
|
self._cache_times = {}
|
|
76
82
|
self._subscriptions = set()
|
|
77
83
|
self._locks = {}
|
|
84
|
+
self._writes_since_sweep = 0
|
|
78
85
|
except Exception as e:
|
|
79
86
|
raise ConfigurationError(
|
|
80
87
|
model=model_class,
|
|
@@ -330,6 +337,9 @@ class ModelState:
|
|
|
330
337
|
|
|
331
338
|
self._cache[cache_key] = record
|
|
332
339
|
self._cache_times[cache_key] = datetime.now()
|
|
340
|
+
self._writes_since_sweep = getattr(self, "_writes_since_sweep", 0) + 1
|
|
341
|
+
if self._writes_since_sweep >= STALE_SWEEP_EVERY_WRITES:
|
|
342
|
+
self.sweep_stale()
|
|
333
343
|
|
|
334
344
|
if self.realtime and self.policy in (
|
|
335
345
|
CachePolicy.PERMANENT,
|
|
@@ -346,6 +356,30 @@ class ModelState:
|
|
|
346
356
|
original_error=e,
|
|
347
357
|
) from e
|
|
348
358
|
|
|
359
|
+
def sweep_stale(self) -> int:
|
|
360
|
+
"""Drop every entry its policy already treats as stale. Returns how many.
|
|
361
|
+
|
|
362
|
+
THE LEAK THIS CLOSES (MKT-111, 2026-10-15): staleness was only ever
|
|
363
|
+
checked on READ, so an entry nobody read again stayed forever. Every
|
|
364
|
+
append-only row a process creates (each workflow checkpoint, node
|
|
365
|
+
outcome and event — fresh primary keys, never re-read through the
|
|
366
|
+
cache) accumulated for the life of the process, multi-megabyte JSON
|
|
367
|
+
included, until ECS killed the task for memory. A stale entry is
|
|
368
|
+
already a miss, so dropping it changes no read.
|
|
369
|
+
"""
|
|
370
|
+
self._writes_since_sweep = 0
|
|
371
|
+
dropped = 0
|
|
372
|
+
for key in list(self._cache_times):
|
|
373
|
+
record = self._cache.get(key)
|
|
374
|
+
if record is None or self._is_stale(record):
|
|
375
|
+
self._cache.pop(key, None)
|
|
376
|
+
self._cache_times.pop(key, None)
|
|
377
|
+
lock = self._locks.get(key)
|
|
378
|
+
if lock is not None and not lock.locked():
|
|
379
|
+
self._locks.pop(key, None)
|
|
380
|
+
dropped += 1
|
|
381
|
+
return dropped
|
|
382
|
+
|
|
349
383
|
def _downgraded_fields(self, existing, incoming) -> list[str]:
|
|
350
384
|
"""Column names the incoming record would blank on the cached one."""
|
|
351
385
|
blanked: list[str] = []
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "matrx-orm"
|
|
3
|
-
version = "3.1.
|
|
3
|
+
version = "3.1.229"
|
|
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,52 @@
|
|
|
1
|
+
"""The identity cache never keeps a row past its policy's age (MKT-111).
|
|
2
|
+
|
|
3
|
+
Staleness used to be checked only on READ, so an entry nobody read again stayed for
|
|
4
|
+
the life of the process: every append-only row a worker created (workflow
|
|
5
|
+
checkpoints, node outcomes, events — fresh keys, multi-megabyte JSON) piled up
|
|
6
|
+
until ECS killed the task for memory. Writes now sweep stale entries.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import types
|
|
12
|
+
from datetime import datetime, timedelta
|
|
13
|
+
|
|
14
|
+
import pytest
|
|
15
|
+
|
|
16
|
+
from matrx_orm import state as state_module
|
|
17
|
+
from matrx_orm.state import CachePolicy, ModelState
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class _Model:
|
|
21
|
+
_cache_policy = CachePolicy.SHORT_TERM
|
|
22
|
+
_fields: dict = {}
|
|
23
|
+
_meta = types.SimpleNamespace(primary_keys=["id"])
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _record(i: int) -> object:
|
|
27
|
+
rec = types.SimpleNamespace(id=f"row-{i}", payload="x" * 10)
|
|
28
|
+
rec._meta = _Model._meta
|
|
29
|
+
return rec
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@pytest.mark.asyncio
|
|
33
|
+
async def test_rows_past_their_age_are_dropped_by_later_writes(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
34
|
+
monkeypatch.setattr(state_module, "STALE_SWEEP_EVERY_WRITES", 10)
|
|
35
|
+
state = ModelState(_Model)
|
|
36
|
+
for i in range(5):
|
|
37
|
+
await state.cache(_record(i))
|
|
38
|
+
old = datetime.now() - timedelta(minutes=11) # SHORT_TERM is 10 minutes
|
|
39
|
+
for key in list(state._cache_times):
|
|
40
|
+
state._cache_times[key] = old
|
|
41
|
+
for i in range(5, 15):
|
|
42
|
+
await state.cache(_record(i))
|
|
43
|
+
assert not any(f"row-{i}" in state._cache for i in range(5)), sorted(state._cache)
|
|
44
|
+
assert all(f"row-{i}" in state._cache for i in range(5, 15))
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@pytest.mark.asyncio
|
|
48
|
+
async def test_a_fresh_row_is_never_swept() -> None:
|
|
49
|
+
state = ModelState(_Model)
|
|
50
|
+
await state.cache(_record(1))
|
|
51
|
+
assert state.sweep_stale() == 0
|
|
52
|
+
assert "row-1" in state._cache
|
|
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
|
|
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
|