GeneralManager 0.81.4__tar.gz → 0.82.0__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.
- {generalmanager-0.81.4/src/GeneralManager.egg-info → generalmanager-0.82.0}/PKG-INFO +1 -1
- {generalmanager-0.81.4 → generalmanager-0.82.0}/pyproject.toml +1 -1
- {generalmanager-0.81.4 → generalmanager-0.82.0/src/GeneralManager.egg-info}/PKG-INFO +1 -1
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/GeneralManager.egg-info/SOURCES.txt +1 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/api/graphql.py +10 -25
- generalmanager-0.82.0/src/general_manager/api/graphql_identifiers.py +79 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/api/graphql_mutations.py +130 -50
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/api/graphql_search.py +82 -20
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/api/mutation.py +4 -1
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/base_interface.py +3 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/capabilities/orm_utils/field_descriptors.py +30 -3
- {generalmanager-0.81.4 → generalmanager-0.82.0}/LICENSE +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/README.md +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/setup.cfg +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/GeneralManager.egg-info/dependency_links.txt +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/GeneralManager.egg-info/requires.txt +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/GeneralManager.egg-info/top_level.txt +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/__init__.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/_types/__init__.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/_types/api.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/_types/bucket.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/_types/cache.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/_types/dataframes.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/_types/factory.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/_types/general_manager.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/_types/interface.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/_types/manager.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/_types/measurement.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/_types/permission.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/_types/rule.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/_types/search.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/_types/utils.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/api/__init__.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/api/graphql_as_of.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/api/graphql_errors.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/api/graphql_groups.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/api/graphql_ordering.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/api/graphql_output.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/api/graphql_prefetch.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/api/graphql_relations.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/api/graphql_resolvers.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/api/graphql_subscription_consumer.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/api/graphql_subscriptions.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/api/graphql_type.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/api/graphql_view.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/api/graphql_warmup.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/api/graphql_warmup_registry.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/api/graphql_warmup_tasks.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/api/notification_batching.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/api/property.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/api/registry.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/api/remote_api.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/api/remote_invalidation.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/api/remote_invalidation_client.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/apps.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/as_of.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/bootstrap.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/bucket/__init__.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/bucket/_materialized_bucket.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/bucket/_ordering.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/bucket/base_bucket.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/bucket/calculation_bucket.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/bucket/database_bucket.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/bucket/excel_bucket.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/bucket/group_bucket.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/bucket/indexing.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/bucket/projection.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/bucket/request_bucket.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/cache/__init__.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/cache/_dependency_graph.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/cache/batch_refresh.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/cache/cache_decorator.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/cache/cache_tracker.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/cache/data_change_context.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/cache/dependency_cache.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/cache/dependency_index.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/cache/dependency_matching.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/cache/dependency_publish.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/cache/dependency_shards.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/cache/model_dependency_collector.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/cache/run_context.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/cache/run_context_lru.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/cache/signals.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/__init__.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/audit.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/bootstrap.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/checks.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/consumer.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/context.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/errors.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/evals/__init__.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/evals/__main__.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/evals/baseline.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/evals/datasets/basic_queries.yaml +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/evals/datasets/demo_readiness.yaml +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/evals/datasets/edge_cases.yaml +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/evals/datasets/follow_ups.yaml +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/evals/datasets/large_schema.yaml +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/evals/datasets/multi_hop.yaml +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/evals/datasets/planned_orchestration.yaml +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/evals/diagnostics.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/evals/fingerprints.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/evals/fixtures.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/evals/judges/__init__.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/evals/judges/answer_quality.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/evals/judges/contract.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/evals/judges/result_accuracy.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/evals/judges/tool_sequence.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/evals/readiness.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/evals/runner.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/evals/traces.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/grounding.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/models.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/planned/__init__.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/planned/budget.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/planned/calculations.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/planned/catalog.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/planned/config.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/planned/events.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/planned/evidence.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/planned/models.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/planned/planner.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/planned/provider_calls.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/planned/resolver.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/planned/routing.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/planned/scheduler.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/planned/synthesis.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/planned/validation.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/providers/__init__.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/providers/_shared.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/providers/anthropic.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/providers/base.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/providers/google.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/providers/ollama.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/providers/openai.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/rate_limits.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/routing.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/schema_index.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/settings.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/signals.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/system_prompt.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/tool_metadata.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/tools.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/turns.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/chat/views.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/conf.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/dataframes/__init__.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/dataframes/measurements.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/factory/__init__.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/factory/auto_factory.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/factory/factories.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/factory/factory_methods.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/__init__.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/bundles/__init__.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/bundles/calculation.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/bundles/database.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/bundles/excel.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/bundles/remote_manager.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/bundles/request.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/capabilities/__init__.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/capabilities/base.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/capabilities/builtin.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/capabilities/calculation/__init__.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/capabilities/calculation/_compat.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/capabilities/calculation/input_resolution.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/capabilities/calculation/lifecycle.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/capabilities/configuration.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/capabilities/core/observability.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/capabilities/core/utils.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/capabilities/excel/__init__.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/capabilities/exceptions.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/capabilities/existing_model/__init__.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/capabilities/existing_model/_compat.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/capabilities/existing_model/resolution.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/capabilities/factory.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/capabilities/orm/__init__.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/capabilities/orm/_compat.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/capabilities/orm/bulk.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/capabilities/orm/create_many.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/capabilities/orm/history.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/capabilities/orm/lifecycle.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/capabilities/orm/mutations.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/capabilities/orm/support.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/capabilities/orm_utils/__init__.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/capabilities/orm_utils/django_manager_utils.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/capabilities/orm_utils/payload_normalizer.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/capabilities/orm_utils/update_state.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/capabilities/read_only/__init__.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/capabilities/read_only/_compat.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/capabilities/read_only/_types.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/capabilities/read_only/lifecycle.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/capabilities/read_only/management.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/capabilities/registry.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/capabilities/remote_manager.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/capabilities/request/__init__.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/excel.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/excel_store.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/excel_workbook.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/infrastructure/__init__.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/infrastructure/startup_hooks.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/infrastructure/system_checks.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/interfaces/__init__.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/interfaces/calculation.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/interfaces/database.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/interfaces/excel.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/interfaces/existing_model.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/interfaces/read_only.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/interfaces/remote_manager.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/interfaces/request.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/manifests/__init__.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/manifests/capability_builder.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/manifests/capability_manifest.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/manifests/capability_models.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/orm_interface.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/requests.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/utils/__init__.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/utils/database_interface_protocols.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/utils/errors.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/utils/history.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/interface/utils/models.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/logging.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/management/commands/chat_cleanup.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/management/commands/cleanup_upload_intents.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/management/commands/graphql_warmup.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/management/commands/graphql_warmup_refresh_due.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/management/commands/search_index.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/management/commands/search_reconcile.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/management/commands/seed_manager_landscape.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/management/commands/shell.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/management/commands/workflow_drain_outbox.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/management/commands/workflow_replay_dead_letters.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/manager/__init__.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/manager/bulk_create.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/manager/general_manager.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/manager/group_manager.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/manager/input.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/manager/meta.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/measurement/__init__.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/measurement/measurement.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/measurement/measurement_field.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/metrics/__init__.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/metrics/graphql.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/migrations/0001_initial.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/migrations/0002_workflow_outbox_scaling_indexes.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/migrations/0003_workflow_execution_correlation_constraint.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/migrations/0004_chat_persistence_models.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/migrations/0004_search_index_state.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/migrations/0005_merge_chat_search.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/migrations/0006_chat_pending_confirmation_scoped_ids.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/migrations/0007_upload_intent.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/migrations/0008_upload_finalization_versions.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/migrations/0009_upload_cleanup_state.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/migrations/0010_chat_pending_confirmation_portable_uniqueness.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/migrations/0011_search_index_state_dirty_generation.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/migrations/0012_chat_context_watermarks.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/migrations/__init__.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/models.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/permission/__init__.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/permission/audit.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/permission/base_permission.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/permission/graphql_capabilities.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/permission/manager_based_permission.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/permission/mutation_permission.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/permission/permission_checks.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/permission/permission_data_manager.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/permission/utils.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/public_api_registry.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/py.typed +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/rule/__init__.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/rule/handler.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/rule/rule.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/search/__init__.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/search/async_tasks.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/search/backend.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/search/backend_registry.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/search/backends/__init__.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/search/backends/dev.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/search/backends/meilisearch.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/search/backends/opensearch.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/search/backends/typesense.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/search/checks.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/search/config.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/search/indexer.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/search/invalidation.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/search/m2m_invalidation.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/search/models.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/search/reconciliation.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/search/registry.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/search/tasks.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/search/utils.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/seeding/__init__.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/seeding/manager_landscape.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/uploads/__init__.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/uploads/adapters.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/uploads/checks.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/uploads/config.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/uploads/errors.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/uploads/finalization.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/uploads/graphql.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/uploads/graphql_types.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/uploads/metrics.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/uploads/models.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/uploads/public.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/uploads/s3.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/uploads/services.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/uploads/tokens.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/uploads/types.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/uploads/urls.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/uploads/views.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/utils/__init__.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/utils/_args_to_kwargs.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/utils/_cache_key_encoder.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/utils/_make_cache_key.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/utils/_none_to_zero.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/utils/filter_parser.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/utils/format_string.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/utils/json_encoder.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/utils/path_mapping.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/utils/public_api.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/utils/testing.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/utils/type_checks.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/workflow/__init__.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/workflow/actions.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/workflow/backend_registry.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/workflow/backends/__init__.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/workflow/backends/celery.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/workflow/backends/local.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/workflow/backends/n8n.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/workflow/config.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/workflow/engine.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/workflow/event_registry.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/workflow/events.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/workflow/models.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/workflow/signal_bridge.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/workflow/tasks.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/workflow/telemetry.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/tests/test_settings.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/tests/test_urls.py +0 -0
- {generalmanager-0.81.4 → generalmanager-0.82.0}/tests/testing_asgi.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: GeneralManager
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.82.0
|
|
4
4
|
Summary: Modular Django-based data management framework with ORM, GraphQL, fine-grained permissions, rule validation, calculations and caching.
|
|
5
5
|
Author-email: Tim Kleindick <tkleindick@yahoo.de>
|
|
6
6
|
License: MIT License
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "GeneralManager"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.82.0"
|
|
8
8
|
description = "Modular Django-based data management framework with ORM, GraphQL, fine-grained permissions, rule validation, calculations and caching."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
authors = [{ name = "Tim Kleindick", email = "tkleindick@yahoo.de" }]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: GeneralManager
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.82.0
|
|
4
4
|
Summary: Modular Django-based data management framework with ORM, GraphQL, fine-grained permissions, rule validation, calculations and caching.
|
|
5
5
|
Author-email: Tim Kleindick <tkleindick@yahoo.de>
|
|
6
6
|
License: MIT License
|
|
@@ -34,6 +34,7 @@ src/general_manager/api/graphql.py
|
|
|
34
34
|
src/general_manager/api/graphql_as_of.py
|
|
35
35
|
src/general_manager/api/graphql_errors.py
|
|
36
36
|
src/general_manager/api/graphql_groups.py
|
|
37
|
+
src/general_manager/api/graphql_identifiers.py
|
|
37
38
|
src/general_manager/api/graphql_mutations.py
|
|
38
39
|
src/general_manager/api/graphql_ordering.py
|
|
39
40
|
src/general_manager/api/graphql_output.py
|
|
@@ -38,6 +38,7 @@ from django.core.exceptions import ObjectDoesNotExist
|
|
|
38
38
|
from django.db import DEFAULT_DB_ALIAS, models, transaction
|
|
39
39
|
from django.utils.module_loading import import_string
|
|
40
40
|
|
|
41
|
+
from general_manager.api.graphql_identifiers import build_identification_arguments
|
|
41
42
|
from general_manager.bucket.base_bucket import Bucket
|
|
42
43
|
from general_manager.bucket.group_bucket import GroupBucket
|
|
43
44
|
from general_manager.cache.dependency_index import (
|
|
@@ -1355,7 +1356,8 @@ class GraphQL:
|
|
|
1355
1356
|
plus generated relation filter/exclude inputs when available. Explicit
|
|
1356
1357
|
sibling ``*_groups`` fields provide grouped results. Other types map through the scalar base
|
|
1357
1358
|
mapper and may use `field_info["graphql_scalar"]` for supported scalar
|
|
1358
|
-
overrides such as `"bigint"`.
|
|
1359
|
+
overrides such as `"bigint"`. Scalar attributes marked ``is_identifier``
|
|
1360
|
+
map to ``ID`` without altering their Python metadata type.
|
|
1359
1361
|
|
|
1360
1362
|
Parameters:
|
|
1361
1363
|
field_type (type): Python type declared on the interface.
|
|
@@ -1410,6 +1412,8 @@ class GraphQL:
|
|
|
1410
1412
|
return graphene.Field(StoredFile)
|
|
1411
1413
|
if orm_field_kind == "image":
|
|
1412
1414
|
return graphene.Field(StoredImage)
|
|
1415
|
+
if field_info and field_info.get("is_identifier"):
|
|
1416
|
+
return graphene.ID()
|
|
1413
1417
|
scalar_type = cast(type, field_type)
|
|
1414
1418
|
return GraphQL._map_field_to_graphene_base_type(
|
|
1415
1419
|
scalar_type,
|
|
@@ -1646,7 +1650,10 @@ class GraphQL:
|
|
|
1646
1650
|
"""
|
|
1647
1651
|
Build the GraphQL arguments required to uniquely identify an instance of the given manager class.
|
|
1648
1652
|
|
|
1649
|
-
|
|
1653
|
+
ORM constructor identifiers and explicit scalar identity metadata use
|
|
1654
|
+
``ID``. Manager references use ``<name>_id`` with ``ID`` or structured
|
|
1655
|
+
composite input types. Named business inputs retain their native scalars;
|
|
1656
|
+
nullability mirrors ``input_field.required``.
|
|
1650
1657
|
|
|
1651
1658
|
Parameters:
|
|
1652
1659
|
generalManagerClass: GeneralManager subclass whose Interface.input_fields are used to derive identification arguments.
|
|
@@ -1654,29 +1661,7 @@ class GraphQL:
|
|
|
1654
1661
|
Returns:
|
|
1655
1662
|
dict[str, object]: Mapping of argument name to a Graphene Argument suitable for identifying a single manager instance.
|
|
1656
1663
|
"""
|
|
1657
|
-
|
|
1658
|
-
for (
|
|
1659
|
-
input_field_name,
|
|
1660
|
-
input_field,
|
|
1661
|
-
) in generalManagerClass.Interface.input_fields.items():
|
|
1662
|
-
if resolve_general_manager_type(
|
|
1663
|
-
input_field.type,
|
|
1664
|
-
cls.manager_registry,
|
|
1665
|
-
):
|
|
1666
|
-
key = f"{input_field_name}_id"
|
|
1667
|
-
identification_fields[key] = graphene.Argument(
|
|
1668
|
-
graphene.ID, required=input_field.required
|
|
1669
|
-
)
|
|
1670
|
-
elif input_field_name == "id":
|
|
1671
|
-
identification_fields[input_field_name] = graphene.Argument(
|
|
1672
|
-
graphene.ID, required=input_field.required
|
|
1673
|
-
)
|
|
1674
|
-
else:
|
|
1675
|
-
base_type = cls._map_field_to_graphene_base_type(input_field.type)
|
|
1676
|
-
identification_fields[input_field_name] = graphene.Argument(
|
|
1677
|
-
base_type, required=input_field.required
|
|
1678
|
-
)
|
|
1679
|
-
return identification_fields
|
|
1664
|
+
return build_identification_arguments(generalManagerClass)
|
|
1680
1665
|
|
|
1681
1666
|
@classmethod
|
|
1682
1667
|
def _add_queries_to_schema(
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"""Share declared constructor arguments between generated GraphQL operations."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Mapping
|
|
6
|
+
from typing import cast
|
|
7
|
+
|
|
8
|
+
import graphene
|
|
9
|
+
from django.db import models
|
|
10
|
+
|
|
11
|
+
from general_manager.api.graphql_errors import (
|
|
12
|
+
GrapheneBaseTypeClass,
|
|
13
|
+
map_field_to_graphene_base_type,
|
|
14
|
+
)
|
|
15
|
+
from general_manager.api.graphql_relations import (
|
|
16
|
+
get_graphql_manager_registry,
|
|
17
|
+
resolve_general_manager_type,
|
|
18
|
+
)
|
|
19
|
+
from general_manager.manager.general_manager import GeneralManager
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def is_orm_identifier_input(manager_class: type[GeneralManager], name: str) -> bool:
|
|
23
|
+
"""Identify the ORM constructor alias addressing the actual model PK."""
|
|
24
|
+
model = getattr(manager_class.Interface, "_model", None)
|
|
25
|
+
return name == "id" and isinstance(model, type) and issubclass(model, models.Model)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def map_identification_scalar(
|
|
29
|
+
manager_class: type[GeneralManager], name: str, input_type: type
|
|
30
|
+
) -> GrapheneBaseTypeClass:
|
|
31
|
+
"""Map actual scalar identities consistently, including nested references."""
|
|
32
|
+
metadata: Mapping[str, object] = manager_class.Interface.get_attribute_types().get(
|
|
33
|
+
name, {}
|
|
34
|
+
)
|
|
35
|
+
if is_orm_identifier_input(manager_class, name) or metadata.get("is_identifier"):
|
|
36
|
+
return cast(GrapheneBaseTypeClass, graphene.ID)
|
|
37
|
+
return map_field_to_graphene_base_type(
|
|
38
|
+
input_type, cast(str | None, metadata.get("graphql_scalar"))
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def build_identification_arguments(
|
|
43
|
+
manager_class: type[GeneralManager], *, for_mutation: bool = False
|
|
44
|
+
) -> dict[str, object]:
|
|
45
|
+
"""Keep named business inputs and use ID only for scalar identities/references."""
|
|
46
|
+
interface = manager_class.Interface
|
|
47
|
+
arguments: dict[str, object] = {}
|
|
48
|
+
for name, input_field in interface.input_fields.items():
|
|
49
|
+
# The ORM constructor's id input addresses model._meta.pk. Its public
|
|
50
|
+
# name is independent of the actual primary-key column name.
|
|
51
|
+
is_orm_id = is_orm_identifier_input(manager_class, name)
|
|
52
|
+
required = input_field.required or (for_mutation and is_orm_id)
|
|
53
|
+
manager_type = resolve_general_manager_type(
|
|
54
|
+
input_field.type, get_graphql_manager_registry()
|
|
55
|
+
)
|
|
56
|
+
if manager_type is not None:
|
|
57
|
+
# Reuse custom mutation support for structured/composite manager
|
|
58
|
+
# references. Import lazily after GraphQL startup to avoid a cycle.
|
|
59
|
+
from general_manager.api.mutation import (
|
|
60
|
+
_build_manager_argument_field,
|
|
61
|
+
_uses_single_id_input,
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
arguments[f"{name}_id"] = (
|
|
65
|
+
graphene.Argument(graphene.ID, required=required)
|
|
66
|
+
if _uses_single_id_input(manager_type)
|
|
67
|
+
else _build_manager_argument_field(manager_type, required=required)
|
|
68
|
+
)
|
|
69
|
+
else:
|
|
70
|
+
scalar = map_identification_scalar(manager_class, name, input_field.type)
|
|
71
|
+
arguments[name] = graphene.Argument(scalar, required=required)
|
|
72
|
+
return arguments
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def pop_identification(
|
|
76
|
+
arguments: dict[str, object], payload: dict[str, object]
|
|
77
|
+
) -> dict[str, object]:
|
|
78
|
+
"""Extract only declared constructor values, preserving omission for defaults."""
|
|
79
|
+
return {name: payload.pop(name) for name in arguments if name in payload}
|
{generalmanager-0.81.4 → generalmanager-0.82.0}/src/general_manager/api/graphql_mutations.py
RENAMED
|
@@ -11,7 +11,7 @@ module can be imported by ``graphql.py`` without creating a circular dependency.
|
|
|
11
11
|
|
|
12
12
|
from __future__ import annotations
|
|
13
13
|
|
|
14
|
-
from typing import TYPE_CHECKING, Protocol, cast
|
|
14
|
+
from typing import TYPE_CHECKING, Mapping, Protocol, cast
|
|
15
15
|
|
|
16
16
|
import graphene
|
|
17
17
|
from graphql import GraphQLError, Undefined
|
|
@@ -35,6 +35,11 @@ from general_manager.api.graphql_errors import (
|
|
|
35
35
|
handle_graph_ql_error,
|
|
36
36
|
map_field_to_graphene_base_type,
|
|
37
37
|
)
|
|
38
|
+
from general_manager.api.graphql_identifiers import (
|
|
39
|
+
build_identification_arguments,
|
|
40
|
+
is_orm_identifier_input,
|
|
41
|
+
pop_identification,
|
|
42
|
+
)
|
|
38
43
|
|
|
39
44
|
if TYPE_CHECKING:
|
|
40
45
|
from graphene import ResolveInfo as GraphQLResolveInfo
|
|
@@ -161,7 +166,9 @@ def _normalize_mutation_kwargs_for_manager(
|
|
|
161
166
|
|
|
162
167
|
GraphQL-facing relation inputs may arrive as ``field``/``field_list`` while
|
|
163
168
|
ORM mutation capabilities expect ``field_id``/``field_id_list`` for manager
|
|
164
|
-
relations.
|
|
169
|
+
relations. Structured references pass through their manager constructor so
|
|
170
|
+
all declared inputs are validated. Scalar reference values stay unchanged.
|
|
171
|
+
Unknown keys and already-normalized keys are preserved.
|
|
165
172
|
"""
|
|
166
173
|
interface_cls = getattr(general_manager_class, "Interface", None)
|
|
167
174
|
if interface_cls is None:
|
|
@@ -171,33 +178,59 @@ def _normalize_mutation_kwargs_for_manager(
|
|
|
171
178
|
normalized = dict(kwargs)
|
|
172
179
|
manager_registry = get_graphql_manager_registry()
|
|
173
180
|
|
|
181
|
+
def normalize_reference(
|
|
182
|
+
manager_type: type[GeneralManager], value: object, relation_name: str
|
|
183
|
+
) -> object:
|
|
184
|
+
if not isinstance(value, Mapping):
|
|
185
|
+
return value
|
|
186
|
+
reference = manager_type(**dict(value))
|
|
187
|
+
model = getattr(interface_cls, "_model", None)
|
|
188
|
+
if isinstance(model, type) and issubclass(model, models.Model):
|
|
189
|
+
try:
|
|
190
|
+
model_field = model._meta.get_field(relation_name)
|
|
191
|
+
except FieldDoesNotExist:
|
|
192
|
+
return reference
|
|
193
|
+
target_field = getattr(model_field, "target_field", None)
|
|
194
|
+
if isinstance(model_field, models.ManyToManyField):
|
|
195
|
+
related_model = model_field.remote_field.model
|
|
196
|
+
target_field = related_model._meta.get_field(
|
|
197
|
+
model_field.m2m_reverse_target_field_name()
|
|
198
|
+
)
|
|
199
|
+
if target_field is not None and not target_field.primary_key:
|
|
200
|
+
return cast(object, getattr(reference, target_field.attname))
|
|
201
|
+
return reference
|
|
202
|
+
|
|
174
203
|
for key in list(kwargs.keys()):
|
|
175
204
|
if key.endswith("_list") and not key.endswith("_id_list"):
|
|
176
205
|
base_key = key.removesuffix("_list")
|
|
177
206
|
type_info = attribute_types.get(key)
|
|
178
207
|
relation_type = type_info["type"] if type_info is not None else None
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
208
|
+
manager_type = resolve_general_manager_type(relation_type, manager_registry)
|
|
209
|
+
if manager_type is not None:
|
|
210
|
+
target_key = f"{base_key}_id_list"
|
|
211
|
+
if target_key not in normalized:
|
|
212
|
+
value = normalized[key]
|
|
213
|
+
normalized[target_key] = (
|
|
214
|
+
[
|
|
215
|
+
normalize_reference(manager_type, item, base_key)
|
|
216
|
+
for item in value
|
|
217
|
+
]
|
|
218
|
+
if isinstance(value, (list, tuple))
|
|
219
|
+
else normalize_reference(manager_type, value, base_key)
|
|
220
|
+
)
|
|
187
221
|
normalized.pop(key, None)
|
|
188
222
|
continue
|
|
189
223
|
|
|
190
224
|
if not key.endswith("_id"):
|
|
191
225
|
type_info = attribute_types.get(key)
|
|
192
226
|
relation_type = type_info["type"] if type_info is not None else None
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
normalized.setdefault(f"{key}_id", normalized[key])
|
|
227
|
+
manager_type = resolve_general_manager_type(relation_type, manager_registry)
|
|
228
|
+
if manager_type is not None:
|
|
229
|
+
target_key = f"{key}_id"
|
|
230
|
+
if target_key not in normalized:
|
|
231
|
+
normalized[target_key] = normalize_reference(
|
|
232
|
+
manager_type, normalized[key], key
|
|
233
|
+
)
|
|
201
234
|
normalized.pop(key, None)
|
|
202
235
|
|
|
203
236
|
return normalized
|
|
@@ -291,8 +324,8 @@ def create_write_fields(
|
|
|
291
324
|
is the ``*_list`` metadata entry whose type is a ``GeneralManager`` subclass.
|
|
292
325
|
|
|
293
326
|
Non-editable attributes are still returned with ``editable=False``. Create
|
|
294
|
-
and update builders filter on that flag; delete
|
|
295
|
-
|
|
327
|
+
and update builders filter on that flag; delete uses the shared constructor
|
|
328
|
+
argument builder plus explicit metadata arguments. ``_EditableGrapheneField`` is an
|
|
296
329
|
internal structural contract used by this module to annotate the dynamic flag
|
|
297
330
|
attached to otherwise untyped Graphene field instances.
|
|
298
331
|
|
|
@@ -302,7 +335,9 @@ def create_write_fields(
|
|
|
302
335
|
helper produces an ID field or a list of ID fields for names ending with
|
|
303
336
|
``"_list"``. Later mutation resolvers normalize those canonical inputs to
|
|
304
337
|
``"owner_id"`` and ``"member_id_list"`` before calling the ORM mutation
|
|
305
|
-
layer.
|
|
338
|
+
layer. Scalar identity metadata maps to ``ID`` as well. Sentinel and callable
|
|
339
|
+
defaults are omitted from the schema; runtime defaults and validation stay
|
|
340
|
+
with the interface/ORM. Always includes an optional ``history_comment``.
|
|
306
341
|
|
|
307
342
|
Parameters:
|
|
308
343
|
interface_cls: Interface providing attribute metadata used to build
|
|
@@ -337,21 +372,42 @@ def create_write_fields(
|
|
|
337
372
|
# GraphQL injects argument defaults before the resolver sees the payload.
|
|
338
373
|
# Partial updates must preserve omission, including defaults of None.
|
|
339
374
|
default = info["default"] if require_fields else Undefined
|
|
375
|
+
if default is NOT_PROVIDED or callable(default):
|
|
376
|
+
default = Undefined
|
|
377
|
+
manager_type = resolve_general_manager_type(typ, manager_registry)
|
|
340
378
|
|
|
341
379
|
fld: object
|
|
342
380
|
if info.get("orm_field_kind") in {"file", "image"}:
|
|
343
381
|
fld = UploadToken(required=req, default_value=default)
|
|
344
|
-
elif (
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
382
|
+
elif info.get("is_identifier"):
|
|
383
|
+
fld = graphene.ID(required=req, default_value=default)
|
|
384
|
+
elif manager_type is not None:
|
|
385
|
+
from general_manager.api.mutation import (
|
|
386
|
+
_build_manager_argument_field,
|
|
387
|
+
_get_or_create_manager_input_type,
|
|
388
|
+
_uses_single_id_input,
|
|
348
389
|
)
|
|
349
|
-
|
|
350
|
-
):
|
|
390
|
+
|
|
351
391
|
if name.endswith("_list"):
|
|
352
|
-
|
|
392
|
+
reference_type = (
|
|
393
|
+
graphene.ID
|
|
394
|
+
if _uses_single_id_input(manager_type)
|
|
395
|
+
else _get_or_create_manager_input_type(manager_type)
|
|
396
|
+
)
|
|
397
|
+
fld = graphene.List(reference_type, required=req, default_value=default)
|
|
353
398
|
else:
|
|
399
|
+
fld = _build_manager_argument_field(
|
|
400
|
+
manager_type, required=req, default_value=default
|
|
401
|
+
)
|
|
402
|
+
elif isinstance(typ, type) and issubclass(typ, models.Model):
|
|
403
|
+
if info.get("relation_kind") == "collection":
|
|
404
|
+
fld = graphene.List(graphene.ID, required=req, default_value=default)
|
|
405
|
+
elif info.get("relation_kind") == "direct":
|
|
354
406
|
fld = graphene.ID(required=req, default_value=default)
|
|
407
|
+
else:
|
|
408
|
+
fld = map_field_to_graphene_base_type(typ)(
|
|
409
|
+
required=req, default_value=default
|
|
410
|
+
)
|
|
355
411
|
else:
|
|
356
412
|
base_cls = map_field_to_graphene_base_type(
|
|
357
413
|
typ,
|
|
@@ -399,6 +455,11 @@ def generate_create_mutation_class(
|
|
|
399
455
|
if not interface_cls:
|
|
400
456
|
return None
|
|
401
457
|
write_fields = create_write_fields(interface_cls)
|
|
458
|
+
attribute_types: Mapping[str, Mapping[str, object]] = (
|
|
459
|
+
interface_cls.get_attribute_types()
|
|
460
|
+
)
|
|
461
|
+
model = getattr(interface_cls, "_model", None)
|
|
462
|
+
has_model = isinstance(model, type) and issubclass(model, models.Model)
|
|
402
463
|
file_field_names = tuple(
|
|
403
464
|
name
|
|
404
465
|
for name in _file_token_field_names(interface_cls, write_fields)
|
|
@@ -456,8 +517,14 @@ def generate_create_mutation_class(
|
|
|
456
517
|
{
|
|
457
518
|
field_name: field
|
|
458
519
|
for field_name, field in write_fields.items()
|
|
459
|
-
if
|
|
460
|
-
and
|
|
520
|
+
if field.editable
|
|
521
|
+
and not attribute_types.get(field_name, {}).get(
|
|
522
|
+
"is_auto_primary_key"
|
|
523
|
+
)
|
|
524
|
+
and (
|
|
525
|
+
has_model
|
|
526
|
+
or field_name not in generalManagerClass.Interface.input_fields
|
|
527
|
+
)
|
|
461
528
|
},
|
|
462
529
|
),
|
|
463
530
|
"mutate": create_mutation,
|
|
@@ -493,6 +560,16 @@ def generate_update_mutation_class(
|
|
|
493
560
|
if not interface_cls:
|
|
494
561
|
return None
|
|
495
562
|
write_fields = create_write_fields(interface_cls, require_fields=False)
|
|
563
|
+
attribute_types: Mapping[str, Mapping[str, object]] = (
|
|
564
|
+
interface_cls.get_attribute_types()
|
|
565
|
+
)
|
|
566
|
+
identification_arguments = build_identification_arguments(
|
|
567
|
+
generalManagerClass, for_mutation=True
|
|
568
|
+
)
|
|
569
|
+
requires_id = is_orm_identifier_input(generalManagerClass, "id")
|
|
570
|
+
if not identification_arguments:
|
|
571
|
+
identification_arguments = {"id": graphene.Argument(graphene.ID, required=True)}
|
|
572
|
+
requires_id = True
|
|
496
573
|
file_field_names = _file_token_field_names(interface_cls, write_fields)
|
|
497
574
|
|
|
498
575
|
def update_mutation(
|
|
@@ -500,8 +577,9 @@ def generate_update_mutation_class(
|
|
|
500
577
|
info: GraphQLResolveInfo,
|
|
501
578
|
**kwargs: object,
|
|
502
579
|
) -> MutationPayload:
|
|
503
|
-
|
|
504
|
-
|
|
580
|
+
identification = pop_identification(identification_arguments, kwargs)
|
|
581
|
+
manager_id = identification.get("id")
|
|
582
|
+
if requires_id and manager_id is None:
|
|
505
583
|
raise handle_graph_ql_error(MissingManagerIdentifierError())
|
|
506
584
|
try:
|
|
507
585
|
kwargs = {
|
|
@@ -520,7 +598,7 @@ def generate_update_mutation_class(
|
|
|
520
598
|
kwargs = _normalize_mutation_kwargs_for_manager(generalManagerClass, kwargs)
|
|
521
599
|
history_comment = _pop_history_comment(kwargs)
|
|
522
600
|
update = cast(
|
|
523
|
-
_ManagerUpdateMethod, generalManagerClass(
|
|
601
|
+
_ManagerUpdateMethod, generalManagerClass(**identification).update
|
|
524
602
|
)
|
|
525
603
|
update_kwargs = {"creator_id": info.context.user.id, **kwargs}
|
|
526
604
|
if isinstance(history_comment, _UnsetHistoryComment):
|
|
@@ -549,12 +627,15 @@ def generate_update_mutation_class(
|
|
|
549
627
|
"Arguments",
|
|
550
628
|
(),
|
|
551
629
|
{
|
|
552
|
-
"id": graphene.ID(required=True),
|
|
553
630
|
**{
|
|
554
631
|
field_name: field
|
|
555
632
|
for field_name, field in write_fields.items()
|
|
556
633
|
if field.editable
|
|
634
|
+
and not attribute_types.get(field_name, {}).get(
|
|
635
|
+
"is_primary_key"
|
|
636
|
+
)
|
|
557
637
|
},
|
|
638
|
+
**identification_arguments,
|
|
558
639
|
},
|
|
559
640
|
),
|
|
560
641
|
"mutate": update_mutation,
|
|
@@ -570,10 +651,9 @@ def generate_delete_mutation_class(
|
|
|
570
651
|
Generate a Graphene Mutation class that deletes instances of the given manager.
|
|
571
652
|
|
|
572
653
|
The generated mutation is named ``Delete<ManagerName>``. It always requires
|
|
573
|
-
an ``id
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
by the generated resolver.
|
|
654
|
+
an ``id: ID!`` argument for ORM managers and exposes optional
|
|
655
|
+
``history_comment`` metadata. Non-ORM managers retain their named constructor
|
|
656
|
+
arguments, all of which are consumed to locate the target instance.
|
|
577
657
|
|
|
578
658
|
Parameters:
|
|
579
659
|
generalManagerClass: The GeneralManager subclass to expose a delete
|
|
@@ -591,18 +671,26 @@ def generate_delete_mutation_class(
|
|
|
591
671
|
if not interface_cls:
|
|
592
672
|
return None
|
|
593
673
|
|
|
674
|
+
identification_arguments = build_identification_arguments(
|
|
675
|
+
generalManagerClass, for_mutation=True
|
|
676
|
+
)
|
|
677
|
+
requires_id = is_orm_identifier_input(generalManagerClass, "id")
|
|
678
|
+
if not identification_arguments:
|
|
679
|
+
identification_arguments = {"id": graphene.Argument(graphene.ID, required=True)}
|
|
680
|
+
requires_id = True
|
|
681
|
+
|
|
594
682
|
def delete_mutation(
|
|
595
683
|
self: object,
|
|
596
684
|
info: GraphQLResolveInfo,
|
|
597
685
|
**kwargs: object,
|
|
598
686
|
) -> MutationPayload:
|
|
599
|
-
|
|
600
|
-
if
|
|
687
|
+
identification = pop_identification(identification_arguments, kwargs)
|
|
688
|
+
if requires_id and identification.get("id") is None:
|
|
601
689
|
raise handle_graph_ql_error(MissingManagerIdentifierError())
|
|
602
690
|
history_comment = _pop_history_comment(kwargs)
|
|
603
691
|
try:
|
|
604
692
|
delete = cast(
|
|
605
|
-
_ManagerDeleteMethod, generalManagerClass(
|
|
693
|
+
_ManagerDeleteMethod, generalManagerClass(**identification).delete
|
|
606
694
|
)
|
|
607
695
|
if isinstance(history_comment, _UnsetHistoryComment):
|
|
608
696
|
delete(creator_id=info.context.user.id)
|
|
@@ -632,16 +720,8 @@ def generate_delete_mutation_class(
|
|
|
632
720
|
"Arguments",
|
|
633
721
|
(),
|
|
634
722
|
{
|
|
635
|
-
# Always include id so the resolver can locate the instance.
|
|
636
|
-
"id": graphene.ID(required=True),
|
|
637
723
|
"history_comment": graphene.String(),
|
|
638
|
-
**
|
|
639
|
-
field_name: field
|
|
640
|
-
for field_name, field in create_write_fields(
|
|
641
|
-
interface_cls
|
|
642
|
-
).items()
|
|
643
|
-
if field_name in generalManagerClass.Interface.input_fields
|
|
644
|
-
},
|
|
724
|
+
**identification_arguments,
|
|
645
725
|
},
|
|
646
726
|
),
|
|
647
727
|
"mutate": delete_mutation,
|
|
@@ -21,6 +21,8 @@ from typing import (
|
|
|
21
21
|
|
|
22
22
|
import graphene
|
|
23
23
|
from graphql import GraphQLError
|
|
24
|
+
from django.core.exceptions import FieldDoesNotExist
|
|
25
|
+
from django.db import models
|
|
24
26
|
|
|
25
27
|
from general_manager.conf import get_setting
|
|
26
28
|
from general_manager.api.graphql_ordering import (
|
|
@@ -522,8 +524,10 @@ def get_filter_options(
|
|
|
522
524
|
Emitted variants are:
|
|
523
525
|
- GeneralManager relations: the base attribute with ``None`` so relation
|
|
524
526
|
filter generation can handle it separately.
|
|
525
|
-
-
|
|
526
|
-
``
|
|
527
|
+
- Scalar identifiers marked in metadata: base, ``exact`` and ``in`` use
|
|
528
|
+
``ID``/``[ID]``; range variants retain the native scalar mapper.
|
|
529
|
+
- Other scalar fields named ``id`` retain their legacy ``exact``, ``in``
|
|
530
|
+
and range operators, using their native scalar types.
|
|
527
531
|
- ``Measurement``: base attribute plus ``gt/gte/lt/lte`` using
|
|
528
532
|
``MeasurementScalar``.
|
|
529
533
|
- numeric, date, and datetime types: base attribute plus
|
|
@@ -570,23 +574,57 @@ def get_filter_options(
|
|
|
570
574
|
|
|
571
575
|
if manager_type is not None:
|
|
572
576
|
yield attribute_name, None
|
|
573
|
-
elif
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
+
elif (attr_info and attr_info.get("is_identifier")) or (
|
|
578
|
+
attribute_name == "id" and not safe_issubclass(normalized_type, Measurement)
|
|
579
|
+
):
|
|
580
|
+
# The legacy id filter operators also belong to business fields. Only
|
|
581
|
+
# explicit identity metadata selects ID; the name preserves operators.
|
|
582
|
+
is_identifier = bool(attr_info and attr_info.get("is_identifier"))
|
|
583
|
+
native_info = {
|
|
584
|
+
k: v for k, v in (attr_info or {}).items() if k != "is_identifier"
|
|
585
|
+
}
|
|
586
|
+
for option in (attribute_name, f"{attribute_name}__exact"):
|
|
587
|
+
yield (
|
|
588
|
+
option,
|
|
589
|
+
graphene.ID()
|
|
590
|
+
if is_identifier
|
|
591
|
+
else map_field_to_graphene_read(
|
|
592
|
+
normalized_type, attribute_name, native_info
|
|
593
|
+
),
|
|
594
|
+
)
|
|
595
|
+
graphql_scalar = native_info.get("graphql_scalar")
|
|
596
|
+
membership_type = (
|
|
597
|
+
graphene.ID
|
|
598
|
+
if is_identifier
|
|
599
|
+
else map_field_to_graphene_base_type(
|
|
600
|
+
normalized_type,
|
|
601
|
+
graphql_scalar if isinstance(graphql_scalar, str) else None,
|
|
602
|
+
)
|
|
603
|
+
)
|
|
604
|
+
yield f"{attribute_name}__in", graphene.List(membership_type)
|
|
577
605
|
for option in ("gt", "gte", "lt", "lte"):
|
|
578
606
|
yield (
|
|
579
607
|
f"{attribute_name}__{option}",
|
|
580
608
|
map_field_to_graphene_read(
|
|
581
609
|
normalized_type,
|
|
582
610
|
attribute_name,
|
|
583
|
-
|
|
611
|
+
native_info,
|
|
584
612
|
),
|
|
585
613
|
)
|
|
614
|
+
if safe_issubclass(normalized_type, str):
|
|
615
|
+
for option in ("icontains", "contains", "startswith", "endswith"):
|
|
616
|
+
yield (
|
|
617
|
+
f"{attribute_name}__{option}",
|
|
618
|
+
map_field_to_graphene_read(
|
|
619
|
+
normalized_type, attribute_name, native_info
|
|
620
|
+
),
|
|
621
|
+
)
|
|
586
622
|
elif safe_issubclass(normalized_type, Measurement):
|
|
587
623
|
yield attribute_name, MeasurementScalar()
|
|
588
624
|
for option in number_options:
|
|
589
625
|
yield f"{attribute_name}__{option}", MeasurementScalar()
|
|
626
|
+
if attribute_name == "id":
|
|
627
|
+
yield f"{attribute_name}__in", graphene.List(MeasurementScalar)
|
|
590
628
|
else:
|
|
591
629
|
yield (
|
|
592
630
|
attribute_name,
|
|
@@ -833,31 +871,55 @@ def normalize_id_filter_value(
|
|
|
833
871
|
value: object,
|
|
834
872
|
) -> object:
|
|
835
873
|
"""
|
|
836
|
-
|
|
874
|
+
Convert equality filters marked as scalar identities to their native types.
|
|
837
875
|
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
876
|
+
Actual ORM primary keys use the declared constructor input, independent of
|
|
877
|
+
the model column name. Raw relation references use the target field's
|
|
878
|
+
``to_python`` conversion, including ``to_field`` references. Ordered lookups
|
|
879
|
+
and non-list/tuple ``in`` values pass through unchanged. Conversion preserves
|
|
880
|
+
existing filter semantics; constructor and write validation remain separate.
|
|
842
881
|
|
|
843
882
|
Raises:
|
|
844
|
-
Exceptions from
|
|
845
|
-
unchanged.
|
|
883
|
+
Exceptions from ``Input.cast()`` or ORM field conversion propagate.
|
|
846
884
|
"""
|
|
847
|
-
|
|
885
|
+
parts = lookup.split("__")
|
|
886
|
+
attribute_name = parts[0]
|
|
887
|
+
operator = parts[1] if len(parts) == 2 else "exact"
|
|
888
|
+
if len(parts) > 2 or operator not in {"exact", "in"}:
|
|
848
889
|
return value
|
|
849
890
|
|
|
850
891
|
interface = getattr(field_type, "Interface", None)
|
|
892
|
+
if interface is None:
|
|
893
|
+
return value
|
|
894
|
+
metadata = interface.get_attribute_types().get(attribute_name, {})
|
|
895
|
+
if not metadata.get("is_identifier"):
|
|
896
|
+
return value
|
|
851
897
|
input_fields = getattr(interface, "input_fields", {})
|
|
852
|
-
|
|
853
|
-
|
|
898
|
+
input_field = input_fields.get(attribute_name)
|
|
899
|
+
model = getattr(interface, "_model", None)
|
|
900
|
+
converter: Callable[[object], object] | None = None
|
|
901
|
+
if isinstance(model, type) and issubclass(model, models.Model):
|
|
902
|
+
try:
|
|
903
|
+
model_field = model._meta.get_field(attribute_name)
|
|
904
|
+
except FieldDoesNotExist:
|
|
905
|
+
return value
|
|
906
|
+
if model_field.primary_key:
|
|
907
|
+
# ORM constructors expose the actual PK under their public id input,
|
|
908
|
+
# even when the model column has another name.
|
|
909
|
+
input_field = input_fields.get("id")
|
|
910
|
+
if input_field is None:
|
|
911
|
+
target_field = getattr(model_field, "target_field", model_field)
|
|
912
|
+
converter = target_field.to_python
|
|
913
|
+
if input_field is not None:
|
|
914
|
+
converter = input_field.cast
|
|
915
|
+
if converter is None:
|
|
854
916
|
return value
|
|
855
917
|
|
|
856
|
-
if
|
|
918
|
+
if operator == "in":
|
|
857
919
|
if not isinstance(value, (list, tuple)):
|
|
858
920
|
return value
|
|
859
|
-
return [
|
|
860
|
-
return
|
|
921
|
+
return [converter(item) for item in value]
|
|
922
|
+
return converter(value)
|
|
861
923
|
|
|
862
924
|
|
|
863
925
|
def normalize_filter_input(
|