Skip to content

Commit 9368b63

Browse files
committed
add RVDSS endpoint and python client support
1 parent cf49a54 commit 9368b63

File tree

3 files changed

+160
-4
lines changed

3 files changed

+160
-4
lines changed

src/client/delphi_epidata.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -675,6 +675,48 @@ def covid_hosp_facility_lookup(state=None, ccn=None, city=None, zip=None, fips_c
675675
# Make the API call
676676
return Epidata._request("covid_hosp_facility_lookup", params)
677677

678+
# Fetch Canadian respiratory RVDSS data
679+
@staticmethod
680+
def rvdss(
681+
geo_type,
682+
time_values,
683+
geo_value,
684+
as_of=None,
685+
issues=None,
686+
):
687+
"""Fetch RVDSS data."""
688+
# Check parameters
689+
if None in (geo_type, time_values, geo_value):
690+
raise EpidataBadRequestException(
691+
"`geo_type`, `time_values`, and `geo_value` are all required"
692+
)
693+
694+
# Set up request
695+
params = {
696+
"data_source": data_source,
697+
"signals": Epidata._list(signals),
698+
"time_type": time_type,
699+
"geo_type": geo_type,
700+
"time_values": Epidata._list(time_values),
701+
# Fake a time type param so that we can use some helper functions later.
702+
"time_type": "week",
703+
}
704+
705+
if isinstance(geo_value, (list, tuple)):
706+
params["geo_values"] = ",".join(geo_value)
707+
else:
708+
params["geo_value"] = geo_value
709+
if as_of is not None:
710+
params["as_of"] = as_of
711+
if issues is not None:
712+
params["issues"] = Epidata._list(issues)
713+
# if lag is not None:
714+
# params["lag"] = lag
715+
716+
# Make the API call
717+
return Epidata._request("rvdss", params)
718+
719+
678720
@staticmethod
679721
def async_epidata(param_list, batch_size=50):
680722
"""[DEPRECATED] Make asynchronous Epidata calls for a list of parameters."""

src/server/_query.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -483,15 +483,21 @@ def apply_issues_filter(self, history_table: str, issues: Optional[TimeValues])
483483
self.where_integers("issue", issues)
484484
return self
485485

486-
def apply_as_of_filter(self, history_table: str, as_of: Optional[int]) -> "QueryBuilder":
486+
def apply_as_of_filter(self, history_table: str, as_of: Optional[int], use_source_signal: Optional[bool] = TRUE) -> "QueryBuilder":
487487
if as_of is not None:
488488
self.retable(history_table)
489489
sub_condition_asof = "(issue <= :as_of)"
490490
self.params["as_of"] = as_of
491-
sub_fields = "max(issue) max_issue, time_type, time_value, `source`, `signal`, geo_type, geo_value"
492-
sub_group = "time_type, time_value, `source`, `signal`, geo_type, geo_value"
491+
493492
alias = self.alias
494-
sub_condition = f"x.max_issue = {alias}.issue AND x.time_type = {alias}.time_type AND x.time_value = {alias}.time_value AND x.source = {alias}.source AND x.signal = {alias}.signal AND x.geo_type = {alias}.geo_type AND x.geo_value = {alias}.geo_value"
493+
source_signal_plain = source_signal_alias = ""
494+
if use_source_signal:
495+
source_signal_plain = ", `source`, `signal`"
496+
source_signal_alias = f"AND x.source = {alias}.source AND x.signal = {alias}.signal"
497+
498+
sub_fields = f"max(issue) max_issue, time_type, time_value{source_signal_plain}, geo_type, geo_value"
499+
sub_group = f"time_type, time_value{source_signal_plain}, geo_type, geo_value"
500+
sub_condition = f"x.max_issue = {alias}.issue AND x.time_type = {alias}.time_type AND x.time_value = {alias}.time_value{source_signal_alias} AND x.geo_type = {alias}.geo_type AND x.geo_value = {alias}.geo_value"
495501
self.subquery = f"JOIN (SELECT {sub_fields} FROM {self.table} WHERE {self.conditions_clause} AND {sub_condition_asof} GROUP BY {sub_group}) x ON {sub_condition}"
496502
return self
497503

src/server/endpoints/rvdss.py

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
from flask import Blueprint, request
2+
3+
from .._params import extract_integers, extract_strings, extract_date, extract_dates
4+
from .._query import execute_query, QueryBuilder
5+
from .._validate import require_all
6+
7+
bp = Blueprint("rvdss", __name__)
8+
9+
db_table_name = "rvdss"
10+
11+
def parse_time_set_epiweeks() -> TimeSet:
12+
require_all(request, "epiweeks")
13+
time_values = extract_dates("epiweeks")
14+
if time_values == ["*"]:
15+
return TimeSet("week", True)
16+
return TimeSet("week", time_values)
17+
18+
return parse_time_arg()
19+
20+
21+
@bp.route("/", methods=("GET", "POST"))
22+
def handle():
23+
require_all(request, "epiweeks", "geo_type", "geo_values")
24+
25+
# epiweeks = extract_integers("epiweeks")
26+
time_set = parse_time_set_epiweeks()
27+
geo_sets = parse_geo_sets()
28+
# issues = extract_integers("issues") # TODO
29+
issues = extract_dates("issues")
30+
# as_of = extract_date("as_of")
31+
32+
# basic query info
33+
q = QueryBuilder(db_table_name, "rv")
34+
35+
fields_string = [
36+
"geo_type",
37+
"geo_value",
38+
"region",
39+
]
40+
fields_int = [
41+
"epiweek",
42+
"week",
43+
"weekorder",
44+
"year",
45+
"time_value",
46+
"issue",
47+
]
48+
fields_float = [
49+
"sarscov2_tests",
50+
"sarscov2_positive_tests",
51+
"sarscov2_pct_positive",
52+
"flu_tests",
53+
"flua_tests",
54+
"flub_tests",
55+
"flu_positive_tests",
56+
"flu_pct_positive",
57+
"fluah1n1pdm09_positive_tests",
58+
"fluah3_positive_tests",
59+
"fluauns_positive_tests",
60+
"flua_positive_tests",
61+
"flua_pct_positive",
62+
"flub_positive_tests",
63+
"flub_pct_positive",
64+
"rsv_tests",
65+
"rsv_positive_tests",
66+
"rsv_pct_positive",
67+
"hpiv_tests",
68+
"hpiv1_positive_tests",
69+
"hpiv2_positive_tests",
70+
"hpiv3_positive_tests",
71+
"hpiv4_positive_tests",
72+
"hpivother_positive_tests",
73+
"hpiv_positive_tests",
74+
"hpiv_pct_positive",
75+
"adv_tests",
76+
"adv_positive_tests",
77+
"adv_pct_positive",
78+
"hmpv_tests",
79+
"hmpv_positive_tests",
80+
"hmpv_pct_positive",
81+
"evrv_tests",
82+
"evrv_positive_tests",
83+
"evrv_pct_positive",
84+
"hcov_tests",
85+
"hcov_positive_tests",
86+
"hcov_pct_positive",
87+
]
88+
89+
q.set_sort_order("epiweek", "time_value" "geo_type", "geo_value", "issue")
90+
q.set_fields(fields_string, fields_int, fields_float)
91+
92+
# q.where_strings("geo_type", geo_type)
93+
q.apply_geo_filters("geo_type", "geo_value", geo_sets)
94+
# TODO: can only use this if have a time_type field in data
95+
# q.apply_time_filter("time_type", "time_value", time_set)
96+
q.where_integers("epiweek", epiweeks)
97+
98+
q.apply_issues_filter(db_table_name, issues)
99+
# TODO: can only use this if have a time_type field in data
100+
# q.apply_as_of_filter(db_table_name, as_of, use_source_signal = FALSE)
101+
102+
# if issues is not None:
103+
# q.where_integers("issue", issues)
104+
# else:
105+
# q.with_max_issue("epiweek", "geo_value")
106+
107+
# send query
108+
return execute_query(str(q), q.params, fields_string, fields_int, fields_float)

0 commit comments

Comments
 (0)