matrx-orm 3.1.30__tar.gz → 3.1.32__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/PKG-INFO +1 -1
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/core/expressions.py +8 -8
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/operations/conflict.py +6 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/python_sql/table_detailed_relationships.py +110 -133
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/pyproject.toml +1 -1
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_case_when.py +9 -8
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_conflict_target.py +10 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_typed_predicates.py +2 -0
- matrx_orm-3.1.32/tests/schema/test_junction_analysis.py +55 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/.gitignore +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/AGENTS.md +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/BASE_CLASS_METHODS.md +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/CLAUDE.md +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/MODEL_API.md +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/README.md +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/database/orm/extended/managers/ai_model_base.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/docs/migrations.md +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/MODULE_README.md +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/__init__.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/adapters/MODULE_README.md +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/adapters/__init__.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/adapters/async_postgresql.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/adapters/base_adapter.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/adapters/postgresql.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/adapters/postgrest_client_adapter.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/adapters/supabase_adapter.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/admin/__init__.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/admin/router.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/api/__init__.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/api/auth.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/api/config.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/api/handlers.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/api/protocol.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/api/server.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/associations.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/cache_debug.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/catalog.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/client/MODULE_README.md +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/client/__init__.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/client/postgres_connection.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/client/postgrest.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/client/supabase_auth.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/client/supabase_config.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/client/supabase_manager.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/core/EXTENDED-TASK.md +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/core/MODULE_README.md +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/core/RELATIONS-TASKS.md +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/core/TASKS.md +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/core/__init__.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/core/async_db_manager.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/core/base.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/core/config.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/core/connections.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/core/db_function.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/core/diagnostics.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/core/extended.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/core/fields.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/core/introspection.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/core/listen.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/core/loop_filters.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/core/model_dto.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/core/model_view.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/core/paginator.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/core/pool_maintenance.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/core/pydantic_bridge.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/core/registry.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/core/relations.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/core/resilience.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/core/rls_session.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/core/signals.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/core/tls.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/core/transaction.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/core/types.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/core/write_queue.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/entity.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/error_handling.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/exceptions.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/extended/__init__.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/extended/app_error_handler.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/identity_rule.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/middleware/__init__.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/middleware/base.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/migrations/MODULE_README.md +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/migrations/__init__.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/migrations/cli.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/migrations/ddl.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/migrations/diff.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/migrations/executor.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/migrations/integration.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/migrations/loader.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/migrations/operations.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/migrations/state.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/migrations/table_filter.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/operations/MODULE_README.md +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/operations/__init__.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/operations/bulk_update_values.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/operations/conflict_writes.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/operations/create.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/operations/db_functions.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/operations/delete.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/operations/dynamic_admin.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/operations/dynamic_crud.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/operations/graph_walk.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/operations/latest_rows.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/operations/queue_claim.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/operations/read.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/operations/relational_backfill.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/operations/staging_load.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/operations/update.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/py.typed +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/python_sql/MODULE_README.md +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/python_sql/__init__.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/python_sql/db_objects.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/python_sql/table_typescript_relationship.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/query/MODULE_README.md +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/query/__init__.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/query/builder.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/query/executor.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/schema_builder/MODULE_README.md +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/schema_builder/__init__.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/schema_builder/code_handler.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/schema_builder/codegen_writer.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/schema_builder/columns.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/schema_builder/common.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/schema_builder/diff_preview.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/schema_builder/entity_capabilities.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/schema_builder/generator.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/schema_builder/helpers/__init__.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/schema_builder/helpers/base_generators.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/schema_builder/helpers/entity_generators.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/schema_builder/helpers/git_checker.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/schema_builder/package_wiring.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/schema_builder/relationships.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/schema_builder/runner.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/schema_builder/schema.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/schema_builder/schema_manager.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/schema_builder/tables.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/schema_builder/views.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/secrets_battery/FEATURE.md +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/secrets_battery/__init__.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/secrets_battery/crypto.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/secrets_battery/items.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/secrets_battery/model.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/secrets_battery/org_service.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/secrets_battery/service.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/session/README.md +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/session/__init__.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/session/coalesce.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/session/dag.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/session/errors.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/session/fallback.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/session/flush.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/session/lifecycle.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/session/managed.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/session/op.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/session/reads.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/session/session.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/session/telemetry.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/sql_executor/MODULE_README.md +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/sql_executor/__init__.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/sql_executor/executor.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/sql_executor/queries.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/sql_executor/registry.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/sql_executor/types.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/sql_executor/utils.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/state.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/utils/__init__.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/utils/sql_utils.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/matrx_orm/utils/type_converters.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/scripts/git-branches.sh +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/scripts/publish.sh +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/scripts/release.sh +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/MODULE_README.md +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/__init__.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/conftest.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/MODULE_README.md +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/__init__.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_admin_db_columns.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_admin_search_negation.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_admin_search_sentinels.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_advisory_lock.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_agent_message.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_api_auth.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_api_config.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_api_handlers.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_api_protocol.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_array_agg_order_by.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_associations.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_bulk_update_by_pk.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_bulk_upsert_increment_set_fields.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_cache_debug.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_call_function.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_catalog.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_composite_pk_filter.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_composite_pk_write_paths.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_config.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_conflict_writes.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_connection_codecs.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_connection_poison_guard.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_connection_primitives.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_count_composite_distinct.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_db_function_field.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_ddl_generator.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_derived_table.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_dirty_tracking.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_dynamic_crud.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_exceptions.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_expression_primitives.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_fields.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_filter_jsonb_agg_array_index.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_from_alias.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_fts.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_func_expression_args.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_graph_walk.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_having_annotate_alias.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_insert_ignore_and_admin_primitives.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_introspect_rls_policies.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_join_and_aggregate.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_latest_rows.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_listen_notify.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_managed_write_guard.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_matrx_entity.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_migration_diff_types.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_migration_loader.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_model_instance.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_model_meta.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_order_by_expression.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_patch_jsonb_path.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_pool_maintenance.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_postgrest_filters.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_pydantic_bridge.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_query_builder.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_query_error_detail.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_query_executor_sql.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_query_timeout.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_querybuilder_clone_semantics.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_queue_claim.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_registry.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_registry_multi_database.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_registry_multi_schema.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_relational_backfill.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_relations.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_resilience.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_schema_exists.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_session_advisory_lock.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_state_cache.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_subquery_filter_raw.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_subquery_in_filter.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_supabase_auth.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_supabase_config.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_tls.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_typed_join_projection.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_update_case_expression.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_update_subquery.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_upsert_with_conflict.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_values_jsonb_decode.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_watched_lifecycle.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level1/test_write_retry_semantics.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level2/MODULE_README.md +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level2/__init__.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level2/conftest.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level2/test_bulk_ops.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level2/test_cache_integration.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level2/test_crud.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level2/test_foreign_keys.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level2/test_m2m.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level2/test_manager.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level2/test_migrations_live.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level2/test_query_execution.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/level2/test_schema_diff.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/sample_project/.env.example +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/sample_project/README.md +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/sample_project/__init__.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/sample_project/generate.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/sample_project/generated/.gitkeep +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/sample_project/matrx_orm.yaml +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/sample_project/test_schema_generation.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/sample_project_desktop/.env.example +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/sample_project_desktop/README.md +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/sample_project_desktop/__init__.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/sample_project_desktop/client_example.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/sample_project_desktop/client_example.ts +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/sample_project_desktop/client_supabase_example.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/sample_project_desktop/server.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/schema/entity_tests.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/schema/test_base_generation.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/schema/test_composite_pk_fk_generation.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/schema/test_composite_unique_generation.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/schema/test_dto_identity_generation.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/schema/test_entity_capability_generation.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/schema/test_generate_schema.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/schema/test_multi_schema_output.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/schema/test_sql_expression_defaults.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/schema/test_view_generation.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/schema_builder/test_focused_generation_plan.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/session/__init__.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/session/conftest.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/session/test_capture_poison_proof.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/session/test_coalesce.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/session/test_dag.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/session/test_disk_spill_fallback.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/session/test_flush_individual_fallback.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/session/test_governed_write.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/session/test_managed.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/session/test_op_enqueue_site.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/session/test_reads.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/session/test_session.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/test_database_name_alias.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/test_db_functions.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/test_model_cls_refactor.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/test_no_blocking_asyncpg_tls.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/test_secrets_battery.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/test_sql_param_casts.py +0 -0
- {matrx_orm-3.1.30 → matrx_orm-3.1.32}/tests/test_sync_twins_guard.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: matrx-orm
|
|
3
|
-
Version: 3.1.
|
|
3
|
+
Version: 3.1.32
|
|
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
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from datetime import date, datetime
|
|
3
|
+
from datetime import date, datetime, timedelta
|
|
4
4
|
from decimal import Decimal
|
|
5
5
|
from typing import TYPE_CHECKING, Any
|
|
6
6
|
from uuid import UUID
|
|
@@ -174,7 +174,7 @@ class OrderBy:
|
|
|
174
174
|
|
|
175
175
|
def __init__(
|
|
176
176
|
self,
|
|
177
|
-
expression:
|
|
177
|
+
expression: str | F | Func,
|
|
178
178
|
*,
|
|
179
179
|
descending: bool = False,
|
|
180
180
|
nulls: str | None = None,
|
|
@@ -228,7 +228,7 @@ class Q:
|
|
|
228
228
|
OR = "OR"
|
|
229
229
|
NOT = "NOT"
|
|
230
230
|
|
|
231
|
-
def __init__(self, *args:
|
|
231
|
+
def __init__(self, *args: Q, **kwargs: Any) -> None:
|
|
232
232
|
self.connector: str = self.AND
|
|
233
233
|
self.negated: bool = False
|
|
234
234
|
# Children is a list of (Q | None) for compound nodes, or kwargs for leaf nodes.
|
|
@@ -237,19 +237,19 @@ class Q:
|
|
|
237
237
|
|
|
238
238
|
# -- Boolean operators --------------------------------------------------
|
|
239
239
|
|
|
240
|
-
def __and__(self, other:
|
|
240
|
+
def __and__(self, other: Q) -> Q:
|
|
241
241
|
node = Q()
|
|
242
242
|
node.connector = self.AND
|
|
243
243
|
node.children = [self, other]
|
|
244
244
|
return node
|
|
245
245
|
|
|
246
|
-
def __or__(self, other:
|
|
246
|
+
def __or__(self, other: Q) -> Q:
|
|
247
247
|
node = Q()
|
|
248
248
|
node.connector = self.OR
|
|
249
249
|
node.children = [self, other]
|
|
250
250
|
return node
|
|
251
251
|
|
|
252
|
-
def __invert__(self) ->
|
|
252
|
+
def __invert__(self) -> Q:
|
|
253
253
|
node = Q(**self.kwargs)
|
|
254
254
|
node.connector = self.connector
|
|
255
255
|
node.children = list(self.children)
|
|
@@ -697,7 +697,7 @@ class Interval:
|
|
|
697
697
|
def __init__(self, **parts: int | float) -> None:
|
|
698
698
|
if not parts or not set(parts).issubset(self._UNITS):
|
|
699
699
|
raise ValueError("Interval received an unsupported or empty unit set")
|
|
700
|
-
self.value =
|
|
700
|
+
self.value = timedelta(**parts)
|
|
701
701
|
|
|
702
702
|
def as_sql(self, params: list[Any]) -> str:
|
|
703
703
|
params.append(self.value)
|
|
@@ -1776,7 +1776,7 @@ class Window:
|
|
|
1776
1776
|
|
|
1777
1777
|
def __init__(
|
|
1778
1778
|
self,
|
|
1779
|
-
expression:
|
|
1779
|
+
expression: Func | Aggregate,
|
|
1780
1780
|
*,
|
|
1781
1781
|
partition_by: str | list[str] | None = None,
|
|
1782
1782
|
order_by: str | list[str] | None = None,
|
|
@@ -79,6 +79,7 @@ class ConflictTarget:
|
|
|
79
79
|
*,
|
|
80
80
|
coalesce: dict[str, Any] | None = None,
|
|
81
81
|
lower: tuple[str, ...] = (),
|
|
82
|
+
md5: tuple[str, ...] = (),
|
|
82
83
|
where_is_null: tuple[str, ...] = (),
|
|
83
84
|
where_is_not_null: tuple[str, ...] = (),
|
|
84
85
|
where_equals: dict[str, Any] | None = None,
|
|
@@ -93,6 +94,9 @@ class ConflictTarget:
|
|
|
93
94
|
unknown_lower = set(lower) - set(columns)
|
|
94
95
|
if unknown_lower:
|
|
95
96
|
raise ValueError(f"lower columns are not in conflict target: {sorted(unknown_lower)}")
|
|
97
|
+
unknown_md5 = set(md5) - set(columns)
|
|
98
|
+
if unknown_md5:
|
|
99
|
+
raise ValueError(f"md5 columns are not in conflict target: {sorted(unknown_md5)}")
|
|
96
100
|
expressions: list[str] = []
|
|
97
101
|
for column in columns:
|
|
98
102
|
rendered = _identifier(column)
|
|
@@ -100,6 +104,8 @@ class ConflictTarget:
|
|
|
100
104
|
rendered = f"COALESCE({rendered}, {_literal(coalesce[column])})"
|
|
101
105
|
if column in lower:
|
|
102
106
|
rendered = f"lower({rendered})"
|
|
107
|
+
if column in md5:
|
|
108
|
+
rendered = f"md5({rendered})"
|
|
103
109
|
expressions.append(rendered)
|
|
104
110
|
predicates = [f"{_identifier(column)} IS NULL" for column in where_is_null]
|
|
105
111
|
predicates.extend(f"{_identifier(column)} IS NOT NULL" for column in where_is_not_null)
|
|
@@ -147,150 +147,127 @@ def analyze_junction_tables(schema, database_project, additional_schemas=None):
|
|
|
147
147
|
return cached
|
|
148
148
|
|
|
149
149
|
query = """
|
|
150
|
-
WITH junction_candidates AS (
|
|
151
|
-
SELECT
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
150
|
+
WITH junction_candidates AS MATERIALIZED (
|
|
151
|
+
SELECT
|
|
152
|
+
constraint_row.conrelid AS table_oid
|
|
153
|
+
FROM pg_catalog.pg_constraint constraint_row
|
|
154
|
+
JOIN pg_catalog.pg_class table_row
|
|
155
|
+
ON table_row.oid = constraint_row.conrelid
|
|
156
|
+
JOIN pg_catalog.pg_namespace table_schema
|
|
157
|
+
ON table_schema.oid = table_row.relnamespace
|
|
158
|
+
WHERE
|
|
159
|
+
constraint_row.contype = 'f'
|
|
160
|
+
AND table_schema.nspname = ANY(%s::text[])
|
|
161
|
+
AND table_row.relkind IN ('r', 'p')
|
|
162
|
+
GROUP BY constraint_row.conrelid
|
|
163
|
+
HAVING COUNT(*) >= 2
|
|
164
164
|
),
|
|
165
|
-
foreign_key_details AS (
|
|
166
|
-
SELECT
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
ON ccu.constraint_name = tc.constraint_name
|
|
200
|
-
WHERE
|
|
201
|
-
tc.table_schema = ANY(%s::text[])
|
|
202
|
-
AND tc.constraint_type = 'FOREIGN KEY'
|
|
165
|
+
foreign_key_details AS MATERIALIZED (
|
|
166
|
+
SELECT
|
|
167
|
+
candidate.table_oid,
|
|
168
|
+
table_schema.nspname AS table_schema,
|
|
169
|
+
table_row.relname AS table_name,
|
|
170
|
+
constraint_row.oid AS constraint_oid,
|
|
171
|
+
key_pair.position,
|
|
172
|
+
local_column.attname AS fk_column,
|
|
173
|
+
referenced_table.oid AS referenced_table_oid,
|
|
174
|
+
referenced_schema.nspname AS referenced_schema,
|
|
175
|
+
referenced_table.relname AS referenced_table,
|
|
176
|
+
referenced_column.attname AS referenced_column
|
|
177
|
+
FROM junction_candidates candidate
|
|
178
|
+
JOIN pg_catalog.pg_constraint constraint_row
|
|
179
|
+
ON constraint_row.conrelid = candidate.table_oid
|
|
180
|
+
AND constraint_row.contype = 'f'
|
|
181
|
+
JOIN pg_catalog.pg_class table_row
|
|
182
|
+
ON table_row.oid = candidate.table_oid
|
|
183
|
+
JOIN pg_catalog.pg_namespace table_schema
|
|
184
|
+
ON table_schema.oid = table_row.relnamespace
|
|
185
|
+
JOIN pg_catalog.pg_class referenced_table
|
|
186
|
+
ON referenced_table.oid = constraint_row.confrelid
|
|
187
|
+
JOIN pg_catalog.pg_namespace referenced_schema
|
|
188
|
+
ON referenced_schema.oid = referenced_table.relnamespace
|
|
189
|
+
CROSS JOIN LATERAL unnest(
|
|
190
|
+
constraint_row.conkey,
|
|
191
|
+
constraint_row.confkey
|
|
192
|
+
) WITH ORDINALITY AS key_pair(local_attnum, referenced_attnum, position)
|
|
193
|
+
JOIN pg_catalog.pg_attribute local_column
|
|
194
|
+
ON local_column.attrelid = candidate.table_oid
|
|
195
|
+
AND local_column.attnum = key_pair.local_attnum
|
|
196
|
+
JOIN pg_catalog.pg_attribute referenced_column
|
|
197
|
+
ON referenced_column.attrelid = referenced_table.oid
|
|
198
|
+
AND referenced_column.attnum = key_pair.referenced_attnum
|
|
203
199
|
),
|
|
204
|
-
primary_key_columns AS (
|
|
205
|
-
SELECT
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
WHERE
|
|
215
|
-
|
|
216
|
-
AND tc.constraint_type = 'PRIMARY KEY'
|
|
200
|
+
primary_key_columns AS MATERIALIZED (
|
|
201
|
+
SELECT
|
|
202
|
+
constraint_row.conrelid AS table_oid,
|
|
203
|
+
array_agg(column_row.attname ORDER BY key_column.position) AS primary_keys
|
|
204
|
+
FROM pg_catalog.pg_constraint constraint_row
|
|
205
|
+
CROSS JOIN LATERAL unnest(constraint_row.conkey)
|
|
206
|
+
WITH ORDINALITY AS key_column(attnum, position)
|
|
207
|
+
JOIN pg_catalog.pg_attribute column_row
|
|
208
|
+
ON column_row.attrelid = constraint_row.conrelid
|
|
209
|
+
AND column_row.attnum = key_column.attnum
|
|
210
|
+
WHERE constraint_row.contype = 'p'
|
|
211
|
+
GROUP BY constraint_row.conrelid
|
|
217
212
|
),
|
|
218
|
-
additional_columns AS (
|
|
219
|
-
SELECT
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
WHERE
|
|
237
|
-
c.table_schema = ANY(%s::text[])
|
|
238
|
-
AND fkd.fk_column IS NULL
|
|
239
|
-
AND pkc.pk_column IS NULL
|
|
240
|
-
GROUP BY
|
|
241
|
-
c.table_schema, c.table_name
|
|
213
|
+
additional_columns AS MATERIALIZED (
|
|
214
|
+
SELECT
|
|
215
|
+
candidate.table_oid,
|
|
216
|
+
array_agg(column_row.attname ORDER BY column_row.attnum) AS additional_fields
|
|
217
|
+
FROM junction_candidates candidate
|
|
218
|
+
JOIN pg_catalog.pg_attribute column_row
|
|
219
|
+
ON column_row.attrelid = candidate.table_oid
|
|
220
|
+
AND column_row.attnum > 0
|
|
221
|
+
AND NOT column_row.attisdropped
|
|
222
|
+
WHERE NOT EXISTS (
|
|
223
|
+
SELECT 1
|
|
224
|
+
FROM pg_catalog.pg_constraint key_constraint
|
|
225
|
+
WHERE
|
|
226
|
+
key_constraint.conrelid = candidate.table_oid
|
|
227
|
+
AND key_constraint.contype IN ('f', 'p')
|
|
228
|
+
AND column_row.attnum = ANY(key_constraint.conkey)
|
|
229
|
+
)
|
|
230
|
+
GROUP BY candidate.table_oid
|
|
242
231
|
)
|
|
243
|
-
SELECT
|
|
244
|
-
|
|
245
|
-
|
|
232
|
+
SELECT
|
|
233
|
+
foreign_key.table_schema,
|
|
234
|
+
foreign_key.table_name,
|
|
246
235
|
json_agg(
|
|
247
236
|
json_build_object(
|
|
248
|
-
'table',
|
|
249
|
-
'table_pks',
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
'related_table', fkd.referenced_table,
|
|
256
|
-
'related_pks', (
|
|
257
|
-
SELECT array_agg(DISTINCT pkc_related.pk_column)
|
|
258
|
-
FROM primary_key_columns pkc_related
|
|
259
|
-
WHERE pkc_related.table_schema = fkd.referenced_schema
|
|
260
|
-
AND pkc_related.table_name = fkd.referenced_table
|
|
261
|
-
),
|
|
262
|
-
'related_schema', fkd.referenced_schema,
|
|
263
|
-
'connecting_column', fkd.fk_column,
|
|
264
|
-
'referenced_column', fkd.referenced_column,
|
|
237
|
+
'table', foreign_key.table_name,
|
|
238
|
+
'table_pks', local_primary_key.primary_keys,
|
|
239
|
+
'related_table', foreign_key.referenced_table,
|
|
240
|
+
'related_pks', referenced_primary_key.primary_keys,
|
|
241
|
+
'related_schema', foreign_key.referenced_schema,
|
|
242
|
+
'connecting_column', foreign_key.fk_column,
|
|
243
|
+
'referenced_column', foreign_key.referenced_column,
|
|
265
244
|
'relationship_type',
|
|
266
|
-
CASE
|
|
267
|
-
WHEN
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
WHEN NOT fkd.has_unique_constraint THEN 'many-to-one'
|
|
271
|
-
WHEN fkd.has_unique_constraint THEN 'one-to-many'
|
|
272
|
-
ELSE 'undefined'
|
|
245
|
+
CASE
|
|
246
|
+
WHEN foreign_key.referenced_table_oid = foreign_key.table_oid
|
|
247
|
+
THEN 'self-referential'
|
|
248
|
+
ELSE 'many-to-many'
|
|
273
249
|
END
|
|
274
250
|
)
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
251
|
+
ORDER BY foreign_key.constraint_oid, foreign_key.position
|
|
252
|
+
) AS connected_tables,
|
|
253
|
+
COALESCE(additional.additional_fields, ARRAY[]::text[]) AS additional_fields,
|
|
254
|
+
local_primary_key.primary_keys
|
|
255
|
+
FROM foreign_key_details foreign_key
|
|
256
|
+
LEFT JOIN primary_key_columns local_primary_key
|
|
257
|
+
ON local_primary_key.table_oid = foreign_key.table_oid
|
|
258
|
+
LEFT JOIN primary_key_columns referenced_primary_key
|
|
259
|
+
ON referenced_primary_key.table_oid = foreign_key.referenced_table_oid
|
|
260
|
+
LEFT JOIN additional_columns additional
|
|
261
|
+
ON additional.table_oid = foreign_key.table_oid
|
|
262
|
+
GROUP BY
|
|
263
|
+
foreign_key.table_oid,
|
|
264
|
+
foreign_key.table_schema,
|
|
265
|
+
foreign_key.table_name,
|
|
266
|
+
local_primary_key.primary_keys,
|
|
267
|
+
additional.additional_fields;
|
|
291
268
|
"""
|
|
292
269
|
|
|
293
|
-
results = execute_sql_query(query, (schemas,
|
|
270
|
+
results = execute_sql_query(query, (schemas,), database_project)
|
|
294
271
|
|
|
295
272
|
# Transform the results into a more readable format
|
|
296
273
|
analyzed_junctions = {}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "matrx-orm"
|
|
3
|
-
version = "3.1.
|
|
3
|
+
version = "3.1.32"
|
|
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" }
|
|
@@ -13,8 +13,9 @@ style of test_expression_primitives.py / test_join_and_aggregate.py.
|
|
|
13
13
|
"""
|
|
14
14
|
from __future__ import annotations
|
|
15
15
|
|
|
16
|
+
from datetime import timedelta
|
|
17
|
+
|
|
16
18
|
import pytest
|
|
17
|
-
from matrx_orm import ColumnComparison, F
|
|
18
19
|
from matrx_orm.core.base import Model, ModelMeta
|
|
19
20
|
from matrx_orm.core.expressions import (
|
|
20
21
|
ArrayAny,
|
|
@@ -162,8 +163,8 @@ def _make_order_model():
|
|
|
162
163
|
|
|
163
164
|
|
|
164
165
|
def test_case_in_annotate():
|
|
165
|
-
|
|
166
|
-
qb =
|
|
166
|
+
Order = _make_order_model()
|
|
167
|
+
qb = Order.filter().annotate(
|
|
167
168
|
tier=Case(When(Compare(F("amount"), ">=", 1000), then=Value("gold")), default=Value("standard"))
|
|
168
169
|
)
|
|
169
170
|
sql, params = QueryExecutor(qb._build_query())._build_query()
|
|
@@ -174,8 +175,8 @@ def test_case_in_annotate():
|
|
|
174
175
|
|
|
175
176
|
|
|
176
177
|
def test_case_in_order_by():
|
|
177
|
-
|
|
178
|
-
qb =
|
|
178
|
+
Order = _make_order_model()
|
|
179
|
+
qb = Order.filter().order_by(
|
|
179
180
|
OrderBy(Case(When(Compare(F("status"), "=", "paid"), then=0), default=1)),
|
|
180
181
|
"-amount",
|
|
181
182
|
)
|
|
@@ -187,8 +188,8 @@ def test_case_in_order_by():
|
|
|
187
188
|
def test_case_in_order_by_with_nulls_last():
|
|
188
189
|
"""Mirrors the real _entity_recall Step-1 ORDER BY: exact-match-first
|
|
189
190
|
tiebreak, then confidence_avg DESC NULLS LAST."""
|
|
190
|
-
|
|
191
|
-
qb =
|
|
191
|
+
Order = _make_order_model()
|
|
192
|
+
qb = Order.filter().order_by(
|
|
192
193
|
OrderBy(Case(When(Compare(Lower(F("status")), "=", "paid"), then=0), default=1)),
|
|
193
194
|
OrderBy("amount", descending=True, nulls="last"),
|
|
194
195
|
)
|
|
@@ -405,7 +406,7 @@ def test_expression_branch_anchors_the_case_so_literals_are_not_cast():
|
|
|
405
406
|
"CASE WHEN (w IS NULL OR w < (NOW() - $1::interval)) "
|
|
406
407
|
"THEN $2 ELSE (daily_auto_rag_cost_used_usd + $3) END"
|
|
407
408
|
)
|
|
408
|
-
assert params == [
|
|
409
|
+
assert params == [timedelta(hours=24), 0.42, 0.42]
|
|
409
410
|
|
|
410
411
|
|
|
411
412
|
def test_column_branch_anchors_the_case_so_literals_are_not_cast():
|
|
@@ -102,6 +102,16 @@ def test_typed_partial_target_rejects_non_identifier_columns() -> None:
|
|
|
102
102
|
ConflictTarget.partial(["project_id; DROP TABLE x"])
|
|
103
103
|
|
|
104
104
|
|
|
105
|
+
def test_typed_partial_target_renders_md5_expression() -> None:
|
|
106
|
+
target = ConflictTarget.partial(["source_id", "url"], md5=("url",))
|
|
107
|
+
assert target.expressions == ("source_id", "md5(url)")
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def test_typed_partial_target_rejects_unknown_md5_column() -> None:
|
|
111
|
+
with pytest.raises(ValueError, match="md5 columns are not in conflict target"):
|
|
112
|
+
ConflictTarget.partial(["source_id", "url"], md5=("missing",))
|
|
113
|
+
|
|
114
|
+
|
|
105
115
|
# ── Executor SQL shape ───────────────────────────────────────────────────────
|
|
106
116
|
|
|
107
117
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from datetime import timedelta
|
|
3
4
|
from typing import Any
|
|
4
5
|
|
|
5
6
|
import pytest
|
|
@@ -193,6 +194,7 @@ def test_arrays_tuple_membership_constant_and_interval() -> None:
|
|
|
193
194
|
["a"],
|
|
194
195
|
["00000000-0000-0000-0000-000000000001"],
|
|
195
196
|
]
|
|
197
|
+
assert params[4] == timedelta(hours=24)
|
|
196
198
|
|
|
197
199
|
|
|
198
200
|
def test_function_name_and_tuple_type_are_validated() -> None:
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
from importlib import import_module
|
|
2
|
+
|
|
3
|
+
import_module("matrx_orm.schema_builder")
|
|
4
|
+
table_detailed_relationships = import_module("matrx_orm.python_sql.table_detailed_relationships")
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def test_junction_analysis_uses_oid_catalog_query(monkeypatch):
|
|
8
|
+
captured: dict[str, object] = {}
|
|
9
|
+
rows = [
|
|
10
|
+
{
|
|
11
|
+
"table_schema": "app",
|
|
12
|
+
"table_name": "membership",
|
|
13
|
+
"connected_tables": [
|
|
14
|
+
{
|
|
15
|
+
"table": "membership",
|
|
16
|
+
"table_pks": ["user_id", "team_id"],
|
|
17
|
+
"related_table": "users",
|
|
18
|
+
"related_pks": ["id"],
|
|
19
|
+
"related_schema": "auth",
|
|
20
|
+
"connecting_column": "user_id",
|
|
21
|
+
"referenced_column": "id",
|
|
22
|
+
"relationship_type": "many-to-many",
|
|
23
|
+
}
|
|
24
|
+
],
|
|
25
|
+
"additional_fields": ["created_at"],
|
|
26
|
+
"primary_keys": ["user_id", "team_id"],
|
|
27
|
+
}
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
def fake_execute_sql_query(query, params, database_project):
|
|
31
|
+
captured.update(query=query, params=params, database_project=database_project)
|
|
32
|
+
return rows
|
|
33
|
+
|
|
34
|
+
monkeypatch.setattr(
|
|
35
|
+
table_detailed_relationships,
|
|
36
|
+
"execute_sql_query",
|
|
37
|
+
fake_execute_sql_query,
|
|
38
|
+
)
|
|
39
|
+
table_detailed_relationships.clear_junction_analysis_cache()
|
|
40
|
+
|
|
41
|
+
junctions, relationships = table_detailed_relationships.analyze_junction_tables(
|
|
42
|
+
"app",
|
|
43
|
+
"main",
|
|
44
|
+
additional_schemas=["auth"],
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
query = captured["query"]
|
|
48
|
+
assert isinstance(query, str)
|
|
49
|
+
assert "pg_catalog.pg_constraint" in query
|
|
50
|
+
assert "WITH ORDINALITY" in query
|
|
51
|
+
assert "information_schema" not in query
|
|
52
|
+
assert captured["params"] == (["app", "auth"],)
|
|
53
|
+
assert captured["database_project"] == "main"
|
|
54
|
+
assert junctions["membership"]["primary_keys"] == ["user_id", "team_id"]
|
|
55
|
+
assert relationships[0]["table_additional_fields"] == ["created_at"]
|
|
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
|