diff --git a/rdrf/rdrf/models/definition/models.py b/rdrf/rdrf/models/definition/models.py index 7cd1b5125..43aee369a 100644 --- a/rdrf/rdrf/models/definition/models.py +++ b/rdrf/rdrf/models/definition/models.py @@ -1087,6 +1087,20 @@ def registry_form_definition_changed(sender, instance, **kwargs): clear_prefetched_form_data_cache(all_forms) +@receiver([post_save, post_delete], sender="rdrf.Registry") +@receiver([post_save, post_delete], sender="rdrf.RegistryForm") +@receiver([post_save, post_delete], sender="rdrf.Section") +@receiver([post_save, post_delete], sender="rdrf.CommonDataElement") +@receiver([post_save, post_delete], sender="rdrf.ContextFormGroup") +@receiver([post_save, post_delete], sender="rdrf.ContextFormGroupItem") +@receiver([post_save, post_delete], sender="rdrf.ConsentSection") +@receiver([post_save, post_delete], sender="rdrf.ConsentQuestion") +def schema_definition_changed(sender, instance, **kwargs): + from report.schema_cache import invalidate_schema_cache + + invalidate_schema_cache() + + class RegistryFormTranslation(models.Model): language = models.OneToOneField(Language, on_delete=models.CASCADE) translated_forms = models.ManyToManyField( diff --git a/rdrf/rdrf/patients/query_data.py b/rdrf/rdrf/patients/query_data.py index d8f41e025..f726ba165 100644 --- a/rdrf/rdrf/patients/query_data.py +++ b/rdrf/rdrf/patients/query_data.py @@ -2,7 +2,7 @@ from gql_query_builder import GqlQuery from graphql import GraphQLError -from report.schema import create_dynamic_schema +from report.schema_cache import get_cached_schema logger = logging.getLogger(__name__) @@ -96,7 +96,7 @@ def build_all_patients_query( def execute_query(request, query, variable_values=None): - schema = create_dynamic_schema() + schema = get_cached_schema() result = schema.execute( query, context_value=request, variable_values=variable_values ) diff --git a/rdrf/rdrf/urls.py b/rdrf/rdrf/urls.py index 68cb25b21..cfbf843ad 100644 --- a/rdrf/rdrf/urls.py +++ b/rdrf/rdrf/urls.py @@ -6,7 +6,7 @@ from django.urls import include, path, re_path from django.views.generic.base import TemplateView from django.views.i18n import JavaScriptCatalog -from report.schema import create_dynamic_schema +from report.schema_cache import get_cached_schema from report.TrrfGraphQLView import TrrfGraphQLView from two_factor import views as twv @@ -110,7 +110,7 @@ path( "graphql", lambda request: TrrfGraphQLView.as_view( - schema=create_dynamic_schema(), graphiql=True + schema=get_cached_schema(), graphiql=True )(request), ), ] diff --git a/rdrf/rdrf/views/patients_listing.py b/rdrf/rdrf/views/patients_listing.py index 7b97bc19b..a68685a1c 100644 --- a/rdrf/rdrf/views/patients_listing.py +++ b/rdrf/rdrf/views/patients_listing.py @@ -9,7 +9,8 @@ from django.utils.translation import gettext as _ from django.views.generic.base import View from registry.patients.models import Patient -from report.schema import create_dynamic_schema, to_camel_case +from report.schema import to_camel_case +from report.schema_cache import get_cached_schema from rdrf.db.contexts_api import RDRFContextManager from rdrf.forms.progress.form_progress import FormProgress @@ -246,7 +247,7 @@ def _query_all_patients( registry, ["total", patient_query], query_input, operation_input ) - schema = create_dynamic_schema() + schema = get_cached_schema() result_all = schema.execute( build_all_patients_query(registry, ["total"]), context_value=request diff --git a/rdrf/registry/groups/models.py b/rdrf/registry/groups/models.py index 6368de036..d814efdf9 100644 --- a/rdrf/registry/groups/models.py +++ b/rdrf/registry/groups/models.py @@ -14,6 +14,7 @@ from django.core import validators from django.db import models from django.db.models import Q +from django.db.models.signals import post_delete, post_save from django.dispatch import receiver from django.utils import timezone from django.utils.module_loading import import_string @@ -587,3 +588,11 @@ class EmailChangeRequest(models.Model): ) history = HistoricalRecords() + + +@receiver([post_save, post_delete], sender="groups.WorkingGroupType") +@receiver([post_save, post_delete], sender="groups.WorkingGroup") +def working_group_changed(sender, instance, **kwargs): + from report.schema_cache import invalidate_schema_cache + + invalidate_schema_cache() diff --git a/rdrf/report/report_builder.py b/rdrf/report/report_builder.py index a0ac9ad6e..0ed4d98d3 100644 --- a/rdrf/report/report_builder.py +++ b/rdrf/report/report_builder.py @@ -20,10 +20,8 @@ from report.clinical_data_csv_util import ClinicalDataCsvUtil from report.models import ReportCdeHeadingFormat -from report.schema import ( - create_dynamic_schema, - get_schema_field_name, -) +from report.schema import get_schema_field_name +from report.schema_cache import get_cached_schema from report.utils import ( get_flattened_json_path, get_graphql_result_value, @@ -39,7 +37,7 @@ def __init__(self, report_design): self.report_config = load_report_configuration()["demographic_model"] self.report_fields_lookup = self.__init_report_fields_lookup() self.patient_filters = self.__init_patient_filters() - self.schema = create_dynamic_schema() + self.schema = get_cached_schema() def __init_report_fields_lookup(self): return { diff --git a/rdrf/report/schema_cache.py b/rdrf/report/schema_cache.py new file mode 100644 index 000000000..4119cd36d --- /dev/null +++ b/rdrf/report/schema_cache.py @@ -0,0 +1,25 @@ +import logging + +logger = logging.getLogger(__name__) + +_schema_cache = None + + +def get_cached_schema(): + global _schema_cache + + if _schema_cache is None: + from report.schema import create_dynamic_schema + + logger.info("Creating dynamic GraphQL schema (cache miss)") + _schema_cache = create_dynamic_schema() + + return _schema_cache + + +def invalidate_schema_cache(): + global _schema_cache + + if _schema_cache is not None: + logger.info("Invalidating GraphQL schema cache") + _schema_cache = None