Skip to content

Commit 7faa03a

Browse files
SamuelNicaisebioinfo
authored andcommitted
Merge issue_423_selected; fix #406 #423 #580 #587
- Add 'selected_samples' state to prevent Genotype based queries from failing due to too many SQLite clause terms - Pass it to querybuilder - Log message instead of letting the unrecoverable error occur - Fix group by widget related issues - Fix report related issues - Update tests
1 parent e19d32a commit 7faa03a

File tree

11 files changed

+116
-160
lines changed

11 files changed

+116
-160
lines changed

cutevariant/core/command.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ def select_cmd(
4343
having={}, # {"op":">", "value": 3 }
4444
limit=50,
4545
offset=0,
46+
selected_samples=[],
4647
**kwargs,
4748
):
4849
"""Select query Command
@@ -76,9 +77,11 @@ def select_cmd(
7677
offset=offset,
7778
group_by=group_by,
7879
having=having,
80+
selected_samples=selected_samples,
7981
**kwargs,
8082
)
8183
LOGGER.debug("command:select_cmd:: %s", query)
84+
print("cmd:select_cmd:: %s", query)
8285
for i in conn.execute(query):
8386
# THIS IS INSANE... SQLITE DOESNT RETURN ALIAS NAME WITH SQUARE BRACKET....
8487
# I HAVE TO replace [] by () and go back after...
@@ -95,6 +98,7 @@ def count_cmd(
9598
filters={},
9699
group_by=[],
97100
having={},
101+
selected_samples=[],
98102
**kwargs,
99103
):
100104
"""Count command
@@ -140,6 +144,7 @@ def count_cmd(
140144
order_by=None,
141145
group_by=group_by,
142146
having=having,
147+
selected_samples=selected_samples,
143148
**kwargs,
144149
)
145150

cutevariant/core/querybuilder.py

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
from functools import lru_cache
2727

2828
# Custom imports
29+
from cutevariant.config import Config
2930
from cutevariant.core import sql
3031

3132
import cutevariant.constants as cst
@@ -129,7 +130,6 @@ def is_annotation_join_required(fields, filters, order_by=None) -> bool:
129130
return True
130131

131132
for condition in filters_to_flat(filters):
132-
133133
condition = list(condition.keys())[0]
134134
if condition.startswith("ann."):
135135
return True
@@ -217,7 +217,6 @@ def samples_join_required(fields, filters, order_by=None) -> list:
217217

218218

219219
def fields_to_vql(fields) -> list:
220-
221220
vql_fields = []
222221
for field in fields:
223222
if field.startswith("samples."):
@@ -272,7 +271,6 @@ def fields_to_sql(fields, use_as=False) -> list:
272271
sql_fields = []
273272

274273
for field in fields:
275-
276274
if field.startswith("ann."):
277275
sql_field = f"`annotations`.`{field[4:]}`"
278276
if use_as:
@@ -388,15 +386,13 @@ def condition_to_sql(item: dict, samples=None) -> str:
388386
condition = ""
389387

390388
if table == "samples":
391-
392389
if name == "$any":
393390
operator = "OR"
394391

395392
if name == "$all":
396393
operator = "AND"
397394

398395
if operator and samples:
399-
400396
condition = (
401397
"("
402398
+ f" {operator} ".join(
@@ -519,9 +515,9 @@ def remove_field_in_filter(filters: dict, field: str = None) -> dict:
519515
Returns:
520516
dict: New filters dict with field removed
521517
"""
518+
522519
# ---------------------------------
523520
def recursive(obj):
524-
525521
output = {}
526522
for k, v in obj.items():
527523
if k in ["$and", "$or"]:
@@ -568,9 +564,9 @@ def filters_to_sql(filters: dict, samples=None) -> str:
568564
Returns:
569565
str: A sql where expression
570566
"""
567+
571568
# ---------------------------------
572569
def recursive(obj):
573-
574570
conditions = ""
575571
for k, v in obj.items():
576572
if k in ["$and", "$or"]:
@@ -617,9 +613,9 @@ def filters_to_vql(filters: dict) -> str:
617613
Returns:
618614
str: A sql where expression
619615
"""
616+
620617
# ---------------------------------
621618
def recursive(obj):
622-
623619
conditions = ""
624620
for k, v in obj.items():
625621
if k in ["$and", "$or"]:
@@ -691,10 +687,17 @@ def build_sql_query(
691687
offset (int): record count per page
692688
group_by (list/None): list of field you want to group
693689
"""
694-
695690
# get samples ids
696691

697-
samples_ids = {i["name"]: i["id"] for i in sql.get_samples(conn)}
692+
if selected_samples: # value can be None or list
693+
if len(selected_samples) > 0:
694+
samples_ids = {
695+
i["name"]: i["id"] for i in sql.get_samples(conn) if i["name"] in selected_samples
696+
}
697+
else:
698+
samples_ids = {i["name"]: i["id"] for i in sql.get_samples(conn)}
699+
else:
700+
samples_ids = {i["name"]: i["id"] for i in sql.get_samples(conn)}
698701

699702
# Create fields
700703
sql_fields = ["`variants`.`id`"] + fields_to_sql(fields, use_as=True)
@@ -756,6 +759,17 @@ def build_sql_query(
756759
if limit:
757760
sql_query += f" LIMIT {limit} OFFSET {offset}"
758761

762+
# prevent the "too many FROM clause term, max 200" error
763+
MAX_SAMPLES_DEFAULT = 100
764+
config = Config("app")
765+
max_samples = config.get("max_samples_in_query", MAX_SAMPLES_DEFAULT)
766+
if len(samples_ids) > max_samples:
767+
LOGGER.debug(f"failed query: {sql_query}")
768+
LOGGER.error(
769+
f"QUERY FAILED because too many samples in query. Expected {max_samples} max, got instead: {len(samples_ids)}"
770+
)
771+
return "SELECT * FROM variants WHERE 0 = 1 LIMIT 1" # bogus query to return 0 rows
772+
759773
return sql_query
760774

761775

@@ -766,7 +780,6 @@ def build_vql_query(
766780
order_by=[],
767781
**kwargs,
768782
):
769-
770783
select_clause = ",".join(fields_to_vql(fields))
771784

772785
where_clause = filters_to_vql(filters)

cutevariant/core/report.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ def __init__(self, conn: sqlite3.Connection, sample_id: int):
6060
super().__init__(conn)
6161
self._sample_id = sample_id
6262
self._variant_classif_threshold = 1
63+
self._sample = sql.get_sample(self._conn, self._sample_id)
6364

6465
def set_variant_classif_threshold(self, threshold: int):
6566
self._variant_classif_threshold = threshold
@@ -107,11 +108,12 @@ def get_stats(self) -> dict:
107108
"$and": [
108109
{
109110
"samples."
110-
+ sql.get_sample(self._conn, self._sample_id)["name"]
111+
+ self._sample["name"]
111112
+ ".gt": {"$gt": 0}
112113
}
113114
]
114115
},
116+
[self._sample["name"]]
115117
):
116118
# if classif is not defined in config, keep the number by default
117119
row = [variant_classifs.get(row["classification"], row["classification"]), row["count"]]
@@ -159,11 +161,12 @@ def get_variants(self) -> typing.List[dict]:
159161
"$and": [
160162
{
161163
"samples."
162-
+ sql.get_sample(self._conn, self._sample_id)["name"]
164+
+ self._sample["name"]
163165
+ ".classification": {"$gte": self._variant_classif_threshold}
164166
}
165167
]
166168
},
169+
selected_samples= [self._sample["name"]]
167170
)
168171
variants = []
169172
for var_id in variants_ids:

0 commit comments

Comments
 (0)