GeneralManager 0.37.0__tar.gz → 0.37.2__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.37.0/src/GeneralManager.egg-info → generalmanager-0.37.2}/PKG-INFO +1 -1
- {generalmanager-0.37.0 → generalmanager-0.37.2}/pyproject.toml +1 -1
- {generalmanager-0.37.0 → generalmanager-0.37.2/src/GeneralManager.egg-info}/PKG-INFO +1 -1
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/bucket/database_bucket.py +100 -6
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/cache/dependency_index.py +192 -12
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/capabilities/orm/support.py +170 -2
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/manager/general_manager.py +0 -10
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/utils/testing.py +1 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/LICENSE +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/README.md +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/setup.cfg +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/GeneralManager.egg-info/SOURCES.txt +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/GeneralManager.egg-info/dependency_links.txt +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/GeneralManager.egg-info/requires.txt +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/GeneralManager.egg-info/top_level.txt +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/__init__.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/_types/__init__.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/_types/api.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/_types/bucket.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/_types/cache.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/_types/factory.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/_types/general_manager.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/_types/interface.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/_types/manager.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/_types/measurement.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/_types/permission.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/_types/rule.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/_types/utils.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/api/__init__.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/api/graphql.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/api/graphql_errors.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/api/graphql_mutations.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/api/graphql_resolvers.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/api/graphql_search.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/api/graphql_subscription_consumer.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/api/graphql_subscriptions.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/api/graphql_view.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/api/mutation.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/api/property.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/api/registry.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/api/remote_api.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/api/remote_invalidation.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/api/remote_invalidation_client.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/apps.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/bootstrap.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/bucket/__init__.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/bucket/base_bucket.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/bucket/calculation_bucket.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/bucket/group_bucket.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/bucket/request_bucket.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/cache/__init__.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/cache/cache_decorator.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/cache/cache_tracker.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/cache/model_dependency_collector.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/cache/signals.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/conf.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/factory/__init__.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/factory/auto_factory.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/factory/factories.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/factory/factory_methods.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/__init__.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/base_interface.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/bundles/__init__.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/bundles/calculation.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/bundles/database.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/bundles/remote_manager.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/bundles/request.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/capabilities/__init__.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/capabilities/base.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/capabilities/builtin.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/capabilities/calculation/__init__.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/capabilities/calculation/_compat.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/capabilities/calculation/lifecycle.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/capabilities/configuration.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/capabilities/core/observability.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/capabilities/core/utils.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/capabilities/exceptions.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/capabilities/existing_model/__init__.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/capabilities/existing_model/_compat.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/capabilities/existing_model/resolution.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/capabilities/factory.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/capabilities/orm/__init__.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/capabilities/orm/_compat.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/capabilities/orm/history.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/capabilities/orm/lifecycle.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/capabilities/orm/mutations.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/capabilities/orm_utils/__init__.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/capabilities/orm_utils/django_manager_utils.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/capabilities/orm_utils/field_descriptors.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/capabilities/orm_utils/payload_normalizer.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/capabilities/read_only/__init__.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/capabilities/read_only/_compat.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/capabilities/read_only/lifecycle.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/capabilities/read_only/management.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/capabilities/registry.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/capabilities/remote_manager.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/capabilities/request/__init__.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/infrastructure/startup_hooks.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/infrastructure/system_checks.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/interfaces/__init__.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/interfaces/calculation.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/interfaces/database.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/interfaces/existing_model.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/interfaces/read_only.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/interfaces/remote_manager.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/interfaces/request.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/manifests/__init__.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/manifests/capability_builder.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/manifests/capability_manifest.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/manifests/capability_models.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/orm_interface.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/requests.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/utils/__init__.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/utils/database_interface_protocols.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/utils/errors.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/interface/utils/models.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/logging.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/management/commands/search_index.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/management/commands/shell.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/management/commands/workflow_drain_outbox.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/management/commands/workflow_replay_dead_letters.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/manager/__init__.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/manager/group_manager.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/manager/input.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/manager/meta.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/measurement/__init__.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/measurement/measurement.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/measurement/measurement_field.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/metrics/__init__.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/metrics/graphql.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/migrations/0001_initial.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/migrations/0002_workflow_outbox_scaling_indexes.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/migrations/0003_workflow_execution_correlation_constraint.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/migrations/__init__.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/models.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/permission/__init__.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/permission/audit.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/permission/base_permission.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/permission/manager_based_permission.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/permission/mutation_permission.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/permission/permission_checks.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/permission/permission_data_manager.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/permission/utils.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/public_api_registry.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/py.typed +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/rule/__init__.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/rule/handler.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/rule/rule.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/search/__init__.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/search/async_tasks.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/search/backend.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/search/backend_registry.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/search/backends/__init__.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/search/backends/dev.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/search/backends/meilisearch.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/search/backends/opensearch.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/search/backends/typesense.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/search/config.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/search/indexer.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/search/registry.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/search/utils.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/utils/__init__.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/utils/args_to_kwargs.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/utils/filter_parser.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/utils/format_string.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/utils/json_encoder.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/utils/make_cache_key.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/utils/none_to_zero.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/utils/path_mapping.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/utils/public_api.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/workflow/__init__.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/workflow/actions.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/workflow/backend_registry.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/workflow/backends/__init__.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/workflow/backends/celery.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/workflow/backends/local.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/workflow/backends/n8n.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/workflow/config.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/workflow/engine.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/workflow/event_registry.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/workflow/events.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/workflow/models.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/workflow/signal_bridge.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/workflow/tasks.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/workflow/telemetry.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/tests/test_settings.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/tests/test_urls.py +0 -0
- {generalmanager-0.37.0 → generalmanager-0.37.2}/tests/testing_asgi.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: GeneralManager
|
|
3
|
-
Version: 0.37.
|
|
3
|
+
Version: 0.37.2
|
|
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.37.
|
|
7
|
+
version = "0.37.2"
|
|
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.37.
|
|
3
|
+
Version: 0.37.2
|
|
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
|
{generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/bucket/database_bucket.py
RENAMED
|
@@ -8,6 +8,8 @@ from django.core.exceptions import FieldError
|
|
|
8
8
|
from django.db import models
|
|
9
9
|
|
|
10
10
|
from general_manager.bucket.base_bucket import Bucket
|
|
11
|
+
from general_manager.cache.cache_tracker import DependencyTracker
|
|
12
|
+
from general_manager.cache.dependency_index import serialize_dependency_identifier
|
|
11
13
|
from general_manager.manager.general_manager import GeneralManager
|
|
12
14
|
from general_manager.utils.filter_parser import create_filter_function
|
|
13
15
|
|
|
@@ -149,6 +151,8 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
|
|
|
149
151
|
exclude_definitions: dict[str, list[Any]] | None = None,
|
|
150
152
|
*,
|
|
151
153
|
search_date: datetime | date | None = None,
|
|
154
|
+
sort_keys: tuple[str, ...] | None = None,
|
|
155
|
+
sort_reverse: bool = False,
|
|
152
156
|
) -> None:
|
|
153
157
|
"""
|
|
154
158
|
Instantiate a database-backed bucket with optional filter state.
|
|
@@ -165,15 +169,77 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
|
|
|
165
169
|
"""
|
|
166
170
|
self._data = data
|
|
167
171
|
self._manager_class = manager_class
|
|
168
|
-
self.filters =
|
|
169
|
-
self.excludes =
|
|
172
|
+
self.filters = self._copy_filter_definitions(filter_definitions)
|
|
173
|
+
self.excludes = self._copy_filter_definitions(exclude_definitions)
|
|
170
174
|
self._search_date = search_date
|
|
175
|
+
self._sort_keys = sort_keys
|
|
176
|
+
self._sort_reverse = sort_reverse
|
|
171
177
|
|
|
172
178
|
def _build_manager(self, pk: Any) -> GeneralManagerType:
|
|
173
179
|
if self._search_date is None:
|
|
174
180
|
return self._manager_class(pk)
|
|
175
181
|
return self._manager_class(pk, search_date=self._search_date)
|
|
176
182
|
|
|
183
|
+
@staticmethod
|
|
184
|
+
def _copy_filter_definitions(
|
|
185
|
+
definitions: dict[str, Any] | None,
|
|
186
|
+
) -> dict[str, list[Any]]:
|
|
187
|
+
"""
|
|
188
|
+
Return a copy of filter/exclude definitions without sharing nested lists.
|
|
189
|
+
"""
|
|
190
|
+
copied: dict[str, list[Any]] = {}
|
|
191
|
+
for key, values in (definitions or {}).items():
|
|
192
|
+
if isinstance(values, list):
|
|
193
|
+
copied[key] = list(values)
|
|
194
|
+
elif isinstance(values, tuple):
|
|
195
|
+
copied[key] = list(values)
|
|
196
|
+
else:
|
|
197
|
+
copied[key] = [values]
|
|
198
|
+
return copied
|
|
199
|
+
|
|
200
|
+
@staticmethod
|
|
201
|
+
def _normalize_dependency_mapping(
|
|
202
|
+
definitions: dict[str, Any],
|
|
203
|
+
) -> dict[str, Any]:
|
|
204
|
+
return {
|
|
205
|
+
key: values[0]
|
|
206
|
+
if isinstance(values, (list, tuple)) and len(values) == 1
|
|
207
|
+
else values
|
|
208
|
+
for key, values in definitions.items()
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
def _track_effective_dependencies(self) -> None:
|
|
212
|
+
"""Record the bucket's effective filter/exclude state when it is evaluated."""
|
|
213
|
+
manager_name = self._manager_class.__name__
|
|
214
|
+
normalized_filters = self._normalize_dependency_mapping(self.filters)
|
|
215
|
+
normalized_excludes = self._normalize_dependency_mapping(self.excludes)
|
|
216
|
+
if self.filters:
|
|
217
|
+
DependencyTracker.track(
|
|
218
|
+
manager_name,
|
|
219
|
+
"filter",
|
|
220
|
+
serialize_dependency_identifier(normalized_filters),
|
|
221
|
+
)
|
|
222
|
+
else:
|
|
223
|
+
DependencyTracker.track(manager_name, "all", "")
|
|
224
|
+
if self.excludes:
|
|
225
|
+
DependencyTracker.track(
|
|
226
|
+
manager_name,
|
|
227
|
+
"exclude",
|
|
228
|
+
serialize_dependency_identifier(normalized_excludes),
|
|
229
|
+
)
|
|
230
|
+
if self._sort_keys:
|
|
231
|
+
for sort_key in self._sort_keys:
|
|
232
|
+
payload = {
|
|
233
|
+
"filters": normalized_filters,
|
|
234
|
+
"excludes": normalized_excludes,
|
|
235
|
+
"reverse": self._sort_reverse,
|
|
236
|
+
}
|
|
237
|
+
DependencyTracker.track(
|
|
238
|
+
manager_name,
|
|
239
|
+
"filter",
|
|
240
|
+
serialize_dependency_identifier({f"__sort__{sort_key}": payload}),
|
|
241
|
+
)
|
|
242
|
+
|
|
177
243
|
def __iter__(self) -> Generator[GeneralManagerType, None, None]:
|
|
178
244
|
"""
|
|
179
245
|
Iterate over manager instances corresponding to the queryset rows.
|
|
@@ -181,6 +247,7 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
|
|
|
181
247
|
Yields:
|
|
182
248
|
GeneralManagerType: Manager instance for each primary key in the queryset.
|
|
183
249
|
"""
|
|
250
|
+
self._track_effective_dependencies()
|
|
184
251
|
for item in self._data:
|
|
185
252
|
yield self._build_manager(item.pk)
|
|
186
253
|
|
|
@@ -223,6 +290,8 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
|
|
|
223
290
|
self._manager_class,
|
|
224
291
|
{},
|
|
225
292
|
search_date=self._search_date,
|
|
293
|
+
sort_keys=self._sort_keys,
|
|
294
|
+
sort_reverse=self._sort_reverse,
|
|
226
295
|
)
|
|
227
296
|
|
|
228
297
|
def __merge_filter_definitions(
|
|
@@ -238,9 +307,7 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
|
|
|
238
307
|
Returns:
|
|
239
308
|
dict[str, list[Any]]: Combined mapping of lookups to value lists.
|
|
240
309
|
"""
|
|
241
|
-
kwarg_filter
|
|
242
|
-
for key, value in basis.items():
|
|
243
|
-
kwarg_filter[key] = value
|
|
310
|
+
kwarg_filter = self._copy_filter_definitions(basis)
|
|
244
311
|
for key, value in kwargs.items():
|
|
245
312
|
if key not in kwarg_filter:
|
|
246
313
|
kwarg_filter[key] = []
|
|
@@ -360,6 +427,8 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
|
|
|
360
427
|
merged_filter,
|
|
361
428
|
self.excludes,
|
|
362
429
|
search_date=search_date,
|
|
430
|
+
sort_keys=self._sort_keys,
|
|
431
|
+
sort_reverse=self._sort_reverse,
|
|
363
432
|
)
|
|
364
433
|
|
|
365
434
|
def exclude(self, **kwargs: Any) -> DatabaseBucket[GeneralManagerType]:
|
|
@@ -405,6 +474,8 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
|
|
|
405
474
|
self.filters,
|
|
406
475
|
merged_exclude,
|
|
407
476
|
search_date=search_date,
|
|
477
|
+
sort_keys=self._sort_keys,
|
|
478
|
+
sort_reverse=self._sort_reverse,
|
|
408
479
|
)
|
|
409
480
|
|
|
410
481
|
def first(self) -> GeneralManagerType | None:
|
|
@@ -414,6 +485,7 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
|
|
|
414
485
|
Returns:
|
|
415
486
|
GeneralManagerType | None: First manager instance if available.
|
|
416
487
|
"""
|
|
488
|
+
self._track_effective_dependencies()
|
|
417
489
|
first_element = self._data.first()
|
|
418
490
|
if first_element is None:
|
|
419
491
|
return None
|
|
@@ -426,6 +498,7 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
|
|
|
426
498
|
Returns:
|
|
427
499
|
GeneralManagerType | None: Last manager instance if available.
|
|
428
500
|
"""
|
|
501
|
+
self._track_effective_dependencies()
|
|
429
502
|
first_element = self._data.last()
|
|
430
503
|
if first_element is None:
|
|
431
504
|
return None
|
|
@@ -438,6 +511,7 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
|
|
|
438
511
|
Returns:
|
|
439
512
|
int: Number of queryset rows.
|
|
440
513
|
"""
|
|
514
|
+
self._track_effective_dependencies()
|
|
441
515
|
return self._data.count()
|
|
442
516
|
|
|
443
517
|
def all(self) -> DatabaseBucket[GeneralManagerType]:
|
|
@@ -450,7 +524,11 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
|
|
|
450
524
|
return self.__class__(
|
|
451
525
|
self._data.all(),
|
|
452
526
|
self._manager_class,
|
|
527
|
+
self.filters,
|
|
528
|
+
self.excludes,
|
|
453
529
|
search_date=self._search_date,
|
|
530
|
+
sort_keys=self._sort_keys,
|
|
531
|
+
sort_reverse=self._sort_reverse,
|
|
454
532
|
)
|
|
455
533
|
|
|
456
534
|
def get(self, **kwargs: Any) -> GeneralManagerType:
|
|
@@ -467,6 +545,7 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
|
|
|
467
545
|
models.ObjectDoesNotExist: Propagated from the underlying queryset when no row matches.
|
|
468
546
|
models.MultipleObjectsReturned: Propagated when multiple rows satisfy the lookup.
|
|
469
547
|
"""
|
|
548
|
+
self._track_effective_dependencies()
|
|
470
549
|
element = self._data.get(**kwargs)
|
|
471
550
|
return self._build_manager(element.pk)
|
|
472
551
|
|
|
@@ -486,8 +565,13 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
|
|
|
486
565
|
return self.__class__(
|
|
487
566
|
self._data[item],
|
|
488
567
|
self._manager_class,
|
|
568
|
+
self.filters,
|
|
569
|
+
self.excludes,
|
|
489
570
|
search_date=self._search_date,
|
|
571
|
+
sort_keys=self._sort_keys,
|
|
572
|
+
sort_reverse=self._sort_reverse,
|
|
490
573
|
)
|
|
574
|
+
self._track_effective_dependencies()
|
|
491
575
|
return self._build_manager(self._data[item].pk)
|
|
492
576
|
|
|
493
577
|
def __len__(self) -> int:
|
|
@@ -497,6 +581,7 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
|
|
|
497
581
|
Returns:
|
|
498
582
|
int: Size of the queryset.
|
|
499
583
|
"""
|
|
584
|
+
self._track_effective_dependencies()
|
|
500
585
|
return self._data.count()
|
|
501
586
|
|
|
502
587
|
def __str__(self) -> str:
|
|
@@ -529,6 +614,7 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
|
|
|
529
614
|
"""
|
|
530
615
|
from general_manager.manager.general_manager import GeneralManager
|
|
531
616
|
|
|
617
|
+
self._track_effective_dependencies()
|
|
532
618
|
if isinstance(item, GeneralManager):
|
|
533
619
|
return item.identification.get("id", None) in self._data.values_list(
|
|
534
620
|
"pk", flat=True
|
|
@@ -610,7 +696,15 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
|
|
|
610
696
|
except (FieldError, TypeError, ValueError) as error:
|
|
611
697
|
raise QuerysetOrderingError(error) from error
|
|
612
698
|
|
|
613
|
-
return self.__class__(
|
|
699
|
+
return self.__class__(
|
|
700
|
+
qs,
|
|
701
|
+
self._manager_class,
|
|
702
|
+
self.filters,
|
|
703
|
+
self.excludes,
|
|
704
|
+
search_date=self._search_date,
|
|
705
|
+
sort_keys=key,
|
|
706
|
+
sort_reverse=reverse,
|
|
707
|
+
)
|
|
614
708
|
|
|
615
709
|
def none(self) -> DatabaseBucket[GeneralManagerType]:
|
|
616
710
|
"""
|
{generalmanager-0.37.0 → generalmanager-0.37.2}/src/general_manager/cache/dependency_index.py
RENAMED
|
@@ -24,7 +24,7 @@ type lookup = str # e.g. "field__gt", "field__in", "field__contains", "field"
|
|
|
24
24
|
type cache_keys = set[str] # e.g. "cache_key_1", "cache_key_2"
|
|
25
25
|
type identifier = str # e.g. "{'id': 1}"", "{'project': Project(**{'id': 1})}", ...
|
|
26
26
|
type dependency_index = dict[
|
|
27
|
-
Literal["filter", "exclude", "request_query"],
|
|
27
|
+
Literal["filter", "exclude", "request_query", "all"],
|
|
28
28
|
dict[
|
|
29
29
|
general_manager_name,
|
|
30
30
|
dict[attribute, dict[lookup, cache_keys]] | dict[identifier, cache_keys],
|
|
@@ -34,7 +34,9 @@ type lookup_dependency_map = dict[lookup, cache_keys]
|
|
|
34
34
|
type manager_dependency_section = dict[attribute, lookup_dependency_map]
|
|
35
35
|
type request_query_manager_section = dict[identifier, cache_keys]
|
|
36
36
|
|
|
37
|
-
type filter_type = Literal[
|
|
37
|
+
type filter_type = Literal[
|
|
38
|
+
"filter", "exclude", "identification", "request_query", "all"
|
|
39
|
+
]
|
|
38
40
|
type Dependency = Tuple[general_manager_name, filter_type, str]
|
|
39
41
|
|
|
40
42
|
logger = get_logger("cache.dependency_index")
|
|
@@ -64,6 +66,8 @@ LOCK_TIMEOUT = 5 # Lock TTL in seconds
|
|
|
64
66
|
UNDEFINED = object() # Sentinel for undefined values
|
|
65
67
|
ACTIONS: tuple[Literal["filter"], Literal["exclude"]] = ("filter", "exclude")
|
|
66
68
|
REQUEST_QUERY_ACTION: Literal["request_query"] = "request_query"
|
|
69
|
+
ALL_RECORDS_LOOKUP = "__all__"
|
|
70
|
+
ALL_RECORDS_VALUE = "__all__"
|
|
67
71
|
|
|
68
72
|
|
|
69
73
|
# -----------------------------------------------------------------------------
|
|
@@ -130,15 +134,31 @@ def get_full_index() -> dependency_index:
|
|
|
130
134
|
Fetch the dependency index from cache, initialising it on first access.
|
|
131
135
|
|
|
132
136
|
Returns:
|
|
133
|
-
dependency_index: Mapping of tracked `filter`, `exclude`, and
|
|
137
|
+
dependency_index: Mapping of tracked `filter`, `exclude`, `all`, and
|
|
134
138
|
`request_query` dependencies keyed by manager name.
|
|
135
139
|
"""
|
|
136
140
|
cached_index = cache.get(INDEX_KEY, None)
|
|
137
141
|
if cached_index is None:
|
|
138
|
-
idx: dependency_index = {
|
|
142
|
+
idx: dependency_index = {
|
|
143
|
+
"filter": {},
|
|
144
|
+
"exclude": {},
|
|
145
|
+
"request_query": {},
|
|
146
|
+
"all": {},
|
|
147
|
+
}
|
|
139
148
|
cache.set(INDEX_KEY, idx, None)
|
|
140
149
|
return idx
|
|
141
|
-
|
|
150
|
+
idx = cast(dependency_index, cached_index)
|
|
151
|
+
changed = False
|
|
152
|
+
for key in cast(
|
|
153
|
+
tuple[Literal["filter", "exclude", "request_query", "all"], ...],
|
|
154
|
+
("filter", "exclude", "request_query", "all"),
|
|
155
|
+
):
|
|
156
|
+
if key not in idx:
|
|
157
|
+
idx[key] = {}
|
|
158
|
+
changed = True
|
|
159
|
+
if changed:
|
|
160
|
+
cache.set(INDEX_KEY, idx, None)
|
|
161
|
+
return idx
|
|
142
162
|
|
|
143
163
|
|
|
144
164
|
def set_full_index(idx: dependency_index) -> None:
|
|
@@ -223,6 +243,10 @@ def record_dependencies(
|
|
|
223
243
|
idx[action_key],
|
|
224
244
|
)
|
|
225
245
|
section = action_section.setdefault(model_name, {})
|
|
246
|
+
if not params:
|
|
247
|
+
lookup_map = section.setdefault(ALL_RECORDS_LOOKUP, {})
|
|
248
|
+
lookup_map.setdefault(ALL_RECORDS_VALUE, set()).add(cache_key)
|
|
249
|
+
continue
|
|
226
250
|
if len(params) > 1:
|
|
227
251
|
cache_dependencies = section.setdefault(
|
|
228
252
|
"__cache_dependencies__", {}
|
|
@@ -243,6 +267,13 @@ def record_dependencies(
|
|
|
243
267
|
request_section = request_index.setdefault(model_name, {})
|
|
244
268
|
request_section.setdefault(identifier, set()).add(cache_key)
|
|
245
269
|
|
|
270
|
+
elif action == "all":
|
|
271
|
+
all_index = cast(
|
|
272
|
+
dict[str, set[str]],
|
|
273
|
+
idx.setdefault("all", {}),
|
|
274
|
+
)
|
|
275
|
+
all_index.setdefault(model_name, set()).add(cache_key)
|
|
276
|
+
|
|
246
277
|
else:
|
|
247
278
|
# Treat identification lookups as a simple filter on `id`
|
|
248
279
|
filter_section = cast(
|
|
@@ -278,6 +309,12 @@ def remove_cache_key_from_index(cache_key: str) -> None:
|
|
|
278
309
|
acquire_lock_with_retry("remove_cache_key_from_index")
|
|
279
310
|
try:
|
|
280
311
|
idx = get_full_index()
|
|
312
|
+
all_section = cast(dict[str, set[str]], idx.get("all", {}))
|
|
313
|
+
for mname, key_set in list(all_section.items()):
|
|
314
|
+
if cache_key in key_set:
|
|
315
|
+
key_set.remove(cache_key)
|
|
316
|
+
if not key_set:
|
|
317
|
+
del all_section[mname]
|
|
281
318
|
for action in ACTIONS:
|
|
282
319
|
action_section = cast(
|
|
283
320
|
dict[general_manager_name, manager_dependency_section],
|
|
@@ -286,7 +323,7 @@ def remove_cache_key_from_index(cache_key: str) -> None:
|
|
|
286
323
|
for mname, model_section in list(action_section.items()):
|
|
287
324
|
cache_dependencies = model_section.get("__cache_dependencies__", {})
|
|
288
325
|
for lookup, lookup_map in list(model_section.items()):
|
|
289
|
-
if lookup
|
|
326
|
+
if lookup == "__cache_dependencies__":
|
|
290
327
|
continue
|
|
291
328
|
lookup_map = cast(lookup_dependency_map, lookup_map)
|
|
292
329
|
for val_key, key_set in list(lookup_map.items()):
|
|
@@ -340,6 +377,12 @@ def _remove_cache_keys_from_index_locked(
|
|
|
340
377
|
cache_keys: tuple[str, ...],
|
|
341
378
|
) -> None:
|
|
342
379
|
"""Remove cache keys from all dependency-index sections while the lock is held."""
|
|
380
|
+
all_section = cast(dict[str, set[str]], idx.get("all", {}))
|
|
381
|
+
for mname, key_set in list(all_section.items()):
|
|
382
|
+
for cache_key in cache_keys:
|
|
383
|
+
key_set.discard(cache_key)
|
|
384
|
+
if not key_set:
|
|
385
|
+
del all_section[mname]
|
|
343
386
|
for action in ACTIONS:
|
|
344
387
|
action_section = cast(
|
|
345
388
|
dict[general_manager_name, manager_dependency_section],
|
|
@@ -348,7 +391,7 @@ def _remove_cache_keys_from_index_locked(
|
|
|
348
391
|
for mname, model_section in list(action_section.items()):
|
|
349
392
|
cache_dependencies = model_section.get("__cache_dependencies__", {})
|
|
350
393
|
for lookup, lookup_map in list(model_section.items()):
|
|
351
|
-
if lookup
|
|
394
|
+
if lookup == "__cache_dependencies__":
|
|
352
395
|
continue
|
|
353
396
|
lookup_map = cast(lookup_dependency_map, lookup_map)
|
|
354
397
|
for val_key, key_set in list(lookup_map.items()):
|
|
@@ -453,11 +496,15 @@ def capture_old_values(
|
|
|
453
496
|
for action in ACTIONS:
|
|
454
497
|
model_section = idx[action].get(manager_name)
|
|
455
498
|
if isinstance(model_section, dict):
|
|
456
|
-
|
|
457
|
-
lookup
|
|
458
|
-
|
|
459
|
-
if
|
|
460
|
-
|
|
499
|
+
for lookup in model_section.keys():
|
|
500
|
+
if not isinstance(lookup, str):
|
|
501
|
+
continue
|
|
502
|
+
if lookup.startswith("__sort__"):
|
|
503
|
+
lookups.add(lookup.removeprefix("__sort__"))
|
|
504
|
+
continue
|
|
505
|
+
if lookup.startswith("__"):
|
|
506
|
+
continue
|
|
507
|
+
lookups.add(lookup)
|
|
461
508
|
elif isinstance(model_section, list):
|
|
462
509
|
lookups |= set(model_section)
|
|
463
510
|
if lookups and instance.identification:
|
|
@@ -504,6 +551,20 @@ def generic_cache_invalidation(
|
|
|
504
551
|
},
|
|
505
552
|
)
|
|
506
553
|
idx = get_full_index()
|
|
554
|
+
all_cache_keys = tuple(
|
|
555
|
+
cast(dict[str, set[str]], idx.get("all", {})).get(manager_name, set())
|
|
556
|
+
)
|
|
557
|
+
for cache_key in all_cache_keys:
|
|
558
|
+
logger.info(
|
|
559
|
+
"invalidating cache key",
|
|
560
|
+
context={
|
|
561
|
+
"manager": manager_name,
|
|
562
|
+
"key": cache_key,
|
|
563
|
+
"action": "all",
|
|
564
|
+
},
|
|
565
|
+
)
|
|
566
|
+
invalidate_cache_key(cache_key)
|
|
567
|
+
remove_cache_key_from_index(cache_key)
|
|
507
568
|
|
|
508
569
|
def _json_loads_val_key(val_key: Any) -> Any:
|
|
509
570
|
if isinstance(val_key, str):
|
|
@@ -783,6 +844,74 @@ def generic_cache_invalidation(
|
|
|
783
844
|
return True
|
|
784
845
|
return False
|
|
785
846
|
|
|
847
|
+
def bucket_membership_matches(
|
|
848
|
+
params: dict[str, Any],
|
|
849
|
+
*,
|
|
850
|
+
use_old_values: bool,
|
|
851
|
+
) -> bool:
|
|
852
|
+
"""
|
|
853
|
+
Check whether the changed row belongs to a bucket described by filters/excludes.
|
|
854
|
+
"""
|
|
855
|
+
filters = params.get("filters", {})
|
|
856
|
+
excludes = params.get("excludes", {})
|
|
857
|
+
if not isinstance(filters, dict) or not isinstance(excludes, dict):
|
|
858
|
+
return False
|
|
859
|
+
|
|
860
|
+
def value_for_lookup(attr_path: list[str]) -> Any:
|
|
861
|
+
if use_old_values:
|
|
862
|
+
return old_relevant_values.get("__".join(attr_path))
|
|
863
|
+
return current_value_for_path(attr_path)
|
|
864
|
+
|
|
865
|
+
for lookup, expected in filters.items():
|
|
866
|
+
parts = lookup.split("__")
|
|
867
|
+
if parts[-1] in (
|
|
868
|
+
"gt",
|
|
869
|
+
"gte",
|
|
870
|
+
"lt",
|
|
871
|
+
"lte",
|
|
872
|
+
"in",
|
|
873
|
+
"contains",
|
|
874
|
+
"startswith",
|
|
875
|
+
"endswith",
|
|
876
|
+
"regex",
|
|
877
|
+
):
|
|
878
|
+
op = parts[-1]
|
|
879
|
+
attr_path = parts[:-1]
|
|
880
|
+
else:
|
|
881
|
+
op = "eq"
|
|
882
|
+
attr_path = parts
|
|
883
|
+
expected_key = json.dumps(
|
|
884
|
+
_normalize_dependency_identifier(expected), sort_keys=True
|
|
885
|
+
)
|
|
886
|
+
if not matches(op, value_for_lookup(attr_path), expected_key):
|
|
887
|
+
return False
|
|
888
|
+
|
|
889
|
+
for lookup, expected in excludes.items():
|
|
890
|
+
parts = lookup.split("__")
|
|
891
|
+
if parts[-1] in (
|
|
892
|
+
"gt",
|
|
893
|
+
"gte",
|
|
894
|
+
"lt",
|
|
895
|
+
"lte",
|
|
896
|
+
"in",
|
|
897
|
+
"contains",
|
|
898
|
+
"startswith",
|
|
899
|
+
"endswith",
|
|
900
|
+
"regex",
|
|
901
|
+
):
|
|
902
|
+
op = parts[-1]
|
|
903
|
+
attr_path = parts[:-1]
|
|
904
|
+
else:
|
|
905
|
+
op = "eq"
|
|
906
|
+
attr_path = parts
|
|
907
|
+
expected_key = json.dumps(
|
|
908
|
+
_normalize_dependency_identifier(expected), sort_keys=True
|
|
909
|
+
)
|
|
910
|
+
if matches(op, value_for_lookup(attr_path), expected_key):
|
|
911
|
+
return False
|
|
912
|
+
|
|
913
|
+
return True
|
|
914
|
+
|
|
786
915
|
for action in ACTIONS:
|
|
787
916
|
action_section = cast(
|
|
788
917
|
dict[general_manager_name, manager_dependency_section],
|
|
@@ -793,6 +922,57 @@ def generic_cache_invalidation(
|
|
|
793
922
|
continue
|
|
794
923
|
for lookup, lookup_map in model_section.items():
|
|
795
924
|
if lookup.startswith("__"):
|
|
925
|
+
if lookup == ALL_RECORDS_LOOKUP:
|
|
926
|
+
for cache_keys in cast(lookup_dependency_map, lookup_map).values():
|
|
927
|
+
for ck in list(cache_keys):
|
|
928
|
+
logger.info(
|
|
929
|
+
"invalidating cache key",
|
|
930
|
+
context={
|
|
931
|
+
"manager": manager_name,
|
|
932
|
+
"key": ck,
|
|
933
|
+
"lookup": lookup,
|
|
934
|
+
"action": action,
|
|
935
|
+
"value": ALL_RECORDS_VALUE,
|
|
936
|
+
},
|
|
937
|
+
)
|
|
938
|
+
invalidate_cache_key(ck)
|
|
939
|
+
remove_cache_key_from_index(ck)
|
|
940
|
+
elif lookup.startswith("__sort__"):
|
|
941
|
+
sort_lookup = lookup.removeprefix("__sort__")
|
|
942
|
+
attr_path = sort_lookup.split("__")
|
|
943
|
+
old_sort_value = old_relevant_values.get(sort_lookup)
|
|
944
|
+
new_sort_value = current_value_for_path(attr_path)
|
|
945
|
+
if old_sort_value == new_sort_value:
|
|
946
|
+
continue
|
|
947
|
+
for val_key, cache_keys in list(
|
|
948
|
+
cast(lookup_dependency_map, lookup_map).items()
|
|
949
|
+
):
|
|
950
|
+
payload = _json_loads_val_key(val_key)
|
|
951
|
+
if not isinstance(payload, dict):
|
|
952
|
+
continue
|
|
953
|
+
old_in_bucket = bucket_membership_matches(
|
|
954
|
+
payload,
|
|
955
|
+
use_old_values=True,
|
|
956
|
+
)
|
|
957
|
+
new_in_bucket = bucket_membership_matches(
|
|
958
|
+
payload,
|
|
959
|
+
use_old_values=False,
|
|
960
|
+
)
|
|
961
|
+
if not (old_in_bucket or new_in_bucket):
|
|
962
|
+
continue
|
|
963
|
+
for ck in list(cache_keys):
|
|
964
|
+
logger.info(
|
|
965
|
+
"invalidating cache key",
|
|
966
|
+
context={
|
|
967
|
+
"manager": manager_name,
|
|
968
|
+
"key": ck,
|
|
969
|
+
"lookup": lookup,
|
|
970
|
+
"action": action,
|
|
971
|
+
"value": val_key,
|
|
972
|
+
},
|
|
973
|
+
)
|
|
974
|
+
invalidate_cache_key(ck)
|
|
975
|
+
remove_cache_key_from_index(ck)
|
|
796
976
|
continue
|
|
797
977
|
lookup_map = cast(lookup_dependency_map, lookup_map)
|
|
798
978
|
# 1) get operator and attribute path
|