diff --git a/HISTORY.rst b/HISTORY.rst index 374f25318..097607a2e 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -13,6 +13,7 @@ End-User Summary - Extra annotations in export completed and tested (#495). - Fixed bug where Exac and thousand genomes settings were not shown in frequency tab for GRCh37 (#597). - Form template reports error if genomebuild variable is not set (#607). +- Create single result row even if multiple clinvar entries (#565). Full Change List ================ @@ -21,6 +22,7 @@ Full Change List - Fixing issue with sync-from-remote when no remote is defined (#570). - Fixed bug where Exac and thousand genomes settings were not shown in frequency tab for GRCh37 (#597). - Form template reports error if genomebuild variable is not set (#607). +- Create single result row even if multiple clinvar entries (#565). ----------------- v1.2.1 (anthenea) diff --git a/variants/file_export.py b/variants/file_export.py index 0be4fd3f9..c94ca330a 100644 --- a/variants/file_export.py +++ b/variants/file_export.py @@ -110,7 +110,7 @@ def to_str(val): ("gnomad_oe_lof", "Gnomad constrains lof observed/expected", float), ("gnomad_oe_lof_upper", "Gnomad constrains lof observed/expected upper", float), ("gnomad_oe_lof_lower", "Gnomad constrains lof observed/expected lower", float), - ("pathogenicity_summary", "ClinVar pathogenicity summary", str), + ("pathogenicity_summary_arr", "ClinVar pathogenicity summary", str), ) if settings.KIOSK_MODE: HEADER_FIXED = tuple(filter(lambda x: not x[0].startswith("inhouse_"), HEADER_FIXED)) @@ -123,8 +123,8 @@ def to_str(val): #: Names of the pathogenicity scoring header columns. HEADERS_PATHO_SCORES = ( - ("pathogenicity_score", "Pathogenicity Score", float), - ("pathogenicity_rank", "Pathogenicity Rank", int), + ("pathogenicity_score_arr", "Pathogenicity Score", float), + ("pathogenicity_rank_arr", "Pathogenicity Rank", int), ) HEADERS_TRANSCRIPTS = (("transcripts", "Transcript ids", str),) diff --git a/variants/queries.py b/variants/queries.py index 9035cb8f9..8b850be37 100644 --- a/variants/queries.py +++ b/variants/queries.py @@ -9,8 +9,9 @@ from django.conf import settings from django.core.exceptions import ImproperlyConfigured from sqlalchemy import Table, true, column, union, literal_column, delete, tuple_ +from sqlalchemy.dialects.postgresql import ARRAY from sqlalchemy.sql import select, func, and_, not_, or_, cast -from sqlalchemy.types import ARRAY, VARCHAR, Integer, Float +from sqlalchemy.types import VARCHAR, Integer, Float, String import sqlparse from clinvar.models import Clinvar @@ -360,16 +361,23 @@ def extend_selectable(self, query_parts): class ExtendQueryPartsClinvarJoin(ExtendQueryPartsBase): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) + self._col_names = ( + "variation_type", + "vcv", + "point_rating", + "pathogenicity", + "review_status", + "pathogenicity_summary", + "details", + ) + self.subquery = ( select( - ( - Clinvar.sa.variation_type, - Clinvar.sa.vcv, - Clinvar.sa.point_rating, - Clinvar.sa.pathogenicity, - Clinvar.sa.review_status, - Clinvar.sa.pathogenicity_summary, - Clinvar.sa.details, + tuple( + func.array_agg( + getattr(Clinvar.sa, name), type_=ARRAY(String(length=128)) + ).label(f"{name}_arr") + for name in self._col_names ) ) .select_from(Clinvar.sa) @@ -382,12 +390,8 @@ def extend_selectable(self, query_parts): def extend_fields(self, _query_parts): return [ - self.subquery.c.variation_type, - self.subquery.c.vcv, - self.subquery.c.point_rating, - self.subquery.c.pathogenicity, - self.subquery.c.pathogenicity_summary, - self.subquery.c.details, + func.coalesce(getattr(self.subquery.c, f"{name}_arr"), []).label(f"{name}_arr") + for name in self._col_names ] @@ -417,7 +421,10 @@ def _build_significance_term(self): return True for patho_key in self.patho_keys: if self.kwargs.get("clinvar_include_%s" % patho_key): - terms.append(self.subquery.c.pathogenicity == patho_key.replace("_", " ")) + # import pdb; pdb.set_trace() + terms.append( + self.subquery.c.pathogenicity_arr.contains([patho_key.replace("_", " ")]) + ) return or_(*terms) diff --git a/variants/tests/test_queries.py b/variants/tests/test_queries.py index adc30eb8e..8de9264f7 100644 --- a/variants/tests/test_queries.py +++ b/variants/tests/test_queries.py @@ -4476,6 +4476,33 @@ def test_render_query_require_membership_include_benign(self): ) self.assertEqual(res[0].start, self.small_vars[6].start) + def test_render_query_single_output_line_even_with_multiple_clinvar_annos(self): + # Add second ClinVar annotation + ClinvarFactory( + release=self.small_vars[1].release, + chromosome=self.small_vars[1].chromosome, + start=self.small_vars[1].start, + end=self.small_vars[1].end, + bin=self.small_vars[1].bin, + reference=self.small_vars[1].reference, + alternative=self.small_vars[1].alternative, + pathogenicity="pathogenic", + ) + res = self.run_query( + self.query_class, + { + "genomic_region": [ + ( + self.small_vars[1].chromosome, + self.small_vars[1].start - 1, + self.small_vars[1].end + 1, + ) + ] + }, + 1, + ) + self.assertEqual(res[0].start, self.small_vars[1].start) + class RenderQueryTestCaseThreeClinvarFilter(CaseThreeClinvarFilterTestMixin, SupportQueryTestBase): """Test clinvar membership using RenderFilterQuery.""" diff --git a/variants/tests/test_views.py b/variants/tests/test_views.py index 17bc0343a..1f4c1a4dc 100644 --- a/variants/tests/test_views.py +++ b/variants/tests/test_views.py @@ -1098,7 +1098,7 @@ def test_clinvar(self): ), {"filter_job_uuid": self.bgjob.sodar_uuid}, ) - self.assertEqual(response.context["result_rows"][1].pathogenicity, "pathogenic") + self.assertEqual(response.context["result_rows"][1].pathogenicity_arr, ["pathogenic"]) def test_training_mode(self): with self.login(self.superuser): @@ -2264,7 +2264,7 @@ def test_clinvar(self): {"filter_job_uuid": self.bgjob.sodar_uuid}, ) self.assertEqual(response.status_code, 200) - self.assertEqual(response.context["result_rows"][4].pathogenicity, "pathogenic") + self.assertEqual(response.context["result_rows"][4].pathogenicity_arr, ["pathogenic"]) @patch("django.conf.settings.VARFISH_ENABLE_CADD", True) @patch("django.conf.settings.VARFISH_CADD_REST_API_URL", "https://cadd.com")