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