def validate_params(self, params): start_date_str = params['start_date'] end_date_str = params['end_date'] enrollment_statuses = params['enrollment_statuses'] awardees = params['awardees'] stratification = params['stratification'] # Validate dates if not start_date_str or not end_date_str: raise BadRequest('Start date and end date should not be empty') try: start_date = datetime.datetime.strptime(start_date_str, DATE_FORMAT).date() except ValueError: raise BadRequest('Invalid start date: %s' % start_date_str) try: end_date = datetime.datetime.strptime(end_date_str, DATE_FORMAT).date() except ValueError: raise BadRequest('Invalid end date: %s' % end_date_str) date_diff = abs((end_date - start_date).days) if date_diff > DAYS_LIMIT: raise BadRequest('Difference between start date and end date ' \ 'should not be greater than %s days' % DAYS_LIMIT) params['start_date'] = start_date params['end_date'] = end_date # Validate awardees, get ID list awardee_ids = [] for awardee in awardees: awardee_id = get_awardee_id_from_name({'awardee': awardee}, self.hpo_dao) if awardee_id == None: raise BadRequest('Invalid awardee name: %s' % awardee) awardee_ids.append(awardee_ids) params['awardee_ids'] = awardee_ids # Validate enrollment statuses try: params["enrollment_statuses"] = [ EnrollmentStatus(val) for val in enrollment_statuses ] except TypeError: valid_enrollment_statuses = EnrollmentStatus.to_dict() for enrollment_status in enrollment_statuses: if enrollment_status not in valid_enrollment_statuses: raise BadRequest('Invalid enrollment status: %s' % enrollment_status) # Validate stratifications try: params['stratification'] = Stratifications( params['stratification']) except TypeError: raise BadRequest('Invalid stratification: %s' % stratification) return params
def get_filtered_results(self, stratification, start_date, end_date, history, awardee_ids, enrollment_statuses, sample_time_def): """Queries DB, returns results in format consumed by front-end :param start_date: Start date object :param end_date: End date object :param awardee_ids: indicate awardee ids :param enrollment_statuses: indicate the enrollment status :param sample_time_def: indicate how to filter the core participant :param history: query for history data from metrics cache table :param stratification: How to stratify (layer) results, as in a stacked bar chart :return: Filtered, stratified results by date """ # Filters for participant_summary (ps) and participant (p) table # filters_sql_ps is used in the general case when we're querying participant_summary # filters_sql_p is used when also LEFT OUTER JOINing p and ps facets = { 'enrollment_statuses': [EnrollmentStatus(val) for val in enrollment_statuses], 'awardee_ids': awardee_ids } filters_sql_ps = self.get_facets_sql(facets, stratification) filters_sql_p = self.get_facets_sql(facets, stratification, table_prefix='p') if str(history) == 'TRUE' and stratification == Stratifications.TOTAL: dao = MetricsEnrollmentStatusCacheDao() return dao.get_total_interested_count(start_date, end_date, awardee_ids) elif str( history ) == 'TRUE' and stratification == Stratifications.ENROLLMENT_STATUS: dao = MetricsEnrollmentStatusCacheDao() return dao.get_latest_version_from_cache(start_date, end_date, awardee_ids) elif str( history ) == 'TRUE' and stratification == Stratifications.GENDER_IDENTITY: dao = MetricsGenderCacheDao() return dao.get_latest_version_from_cache(start_date, end_date, awardee_ids, enrollment_statuses) elif str(history ) == 'TRUE' and stratification == Stratifications.AGE_RANGE: dao = MetricsAgeCacheDao() return dao.get_latest_version_from_cache(start_date, end_date, awardee_ids, enrollment_statuses) elif str(history) == 'TRUE' and stratification == Stratifications.RACE: dao = MetricsRaceCacheDao() return dao.get_latest_version_from_cache(start_date, end_date, awardee_ids, enrollment_statuses) elif str(history) == 'TRUE' and stratification in [ Stratifications.FULL_STATE, Stratifications.FULL_CENSUS, Stratifications.FULL_AWARDEE, Stratifications.GEO_STATE, Stratifications.GEO_CENSUS, Stratifications.GEO_AWARDEE ]: dao = MetricsRegionCacheDao() return dao.get_latest_version_from_cache(end_date, stratification, awardee_ids, enrollment_statuses) elif str(history ) == 'TRUE' and stratification == Stratifications.LANGUAGE: dao = MetricsLanguageCacheDao() return dao.get_latest_version_from_cache(start_date, end_date, awardee_ids, enrollment_statuses) elif str(history ) == 'TRUE' and stratification == Stratifications.LIFECYCLE: dao = MetricsLifecycleCacheDao() return dao.get_latest_version_from_cache(end_date, awardee_ids) elif stratification == Stratifications.TOTAL: strata = ['TOTAL'] sql = self.get_total_sql(filters_sql_ps) elif stratification == Stratifications.ENROLLMENT_STATUS: strata = [str(val) for val in EnrollmentStatus] sql = self.get_enrollment_status_sql(filters_sql_p, sample_time_def) elif stratification == Stratifications.EHR_CONSENT: strata = ['EHR_CONSENT'] sql = self.get_total_sql(filters_sql_ps, ehr_count=True) elif stratification == Stratifications.EHR_RATIO: strata = ['EHR_RATIO'] sql = self.get_ratio_sql(filters_sql_ps) else: raise BadRequest('Invalid stratification: %s' % stratification) params = {'start_date': start_date, 'end_date': end_date} results_by_date = [] with self.session() as session: cursor = session.execute(sql, params) # Iterate through each result (by date), transforming tabular SQL results # into expected list-of-dictionaries response format try: results = cursor.fetchall() for result in results: date = result[-1] metrics = {} values = result[:-1] for i, value in enumerate(values): key = strata[i] if value is None or (stratification == Stratifications.ENROLLMENT_STATUS and enrollment_statuses and key not in enrollment_statuses): value = 0 metrics[key] = float( value ) if stratification == Stratifications.EHR_RATIO else int( value) results_by_date.append({'date': str(date), 'metrics': metrics}) finally: cursor.close() return results_by_date
# Note that we depend on the participant_summary table containing only consented # participants, by definition. Therefore these metrics only cover consented # individuals. _SQL_AGGREGATIONS = [ _SqlAggregation( MetricsKey.ENROLLMENT_STATUS, """ SELECT enrollment_status, COUNT(*) FROM participant_summary WHERE {summary_filter_sql} GROUP BY 1; """.format(summary_filter_sql=_SUMMARY_FILTER_SQL), # Rewrite INTERESTED to CONSENTED, see note above. lambda v: ('CONSENTED' if v is EnrollmentStatus.INTERESTED.number else EnrollmentStatus.lookup_by_number(v).name), None), # TODO(calbach): Verify whether we need to be conditionally trimming these # prefixes or leaving them unmodified. Unclear if all codes will have prefix # "PMI_". _SqlAggregation( MetricsKey.GENDER, """ SELECT CASE WHEN code.value IS NULL THEN 'UNSET' ELSE code.value END, ps.count FROM ( SELECT gender_identity_id, COUNT(*) count FROM participant_summary
def validate_params(self, start_date_str, end_date_str, stratification_str, enrollment_statuses, awardees, history): """Validates URL parameters, and converts human-friendly values to canonical form :param start_date_str: Start date string, e.g. '2018-01-01' :param end_date_str: End date string, e.g. '2018-01-31' :param stratification_str: How to stratify (layer) results, as in a stacked bar chart :param enrollment_statuses: enrollment level filters :param awardees: awardee name filters :param history: indicate if it's for historical data :return: Validated parameters in canonical form """ params = {} # Validate stratifications try: params['stratification'] = Stratifications(stratification_str) except TypeError: raise BadRequest('Invalid stratification: %s' % stratification_str) if params['stratification'] in [ Stratifications.FULL_STATE, Stratifications.FULL_CENSUS, Stratifications.FULL_AWARDEE, Stratifications.LIFECYCLE ]: # Validate dates if not end_date_str: raise BadRequest('end date should not be empty') start_date = datetime.datetime.strptime('2017-01-01', DATE_FORMAT).date() try: end_date = datetime.datetime.strptime(end_date_str, DATE_FORMAT).date() except ValueError: raise BadRequest('Invalid end date: %s' % end_date_str) params['start_date'] = start_date params['end_date'] = end_date else: # Validate dates if not start_date_str or not end_date_str: raise BadRequest('Start date and end date should not be empty') try: start_date = datetime.datetime.strptime( start_date_str, DATE_FORMAT).date() except ValueError: raise BadRequest('Invalid start date: %s' % start_date_str) try: end_date = datetime.datetime.strptime(end_date_str, DATE_FORMAT).date() except ValueError: raise BadRequest('Invalid end date: %s' % end_date_str) date_diff = abs((end_date - start_date).days) if history != 'TRUE' and date_diff > DAYS_LIMIT_FOR_REALTIME_DATA: raise BadRequest('Difference between start date and end date ' 'should not be greater than %s days' % DAYS_LIMIT_FOR_REALTIME_DATA) if history == 'TRUE' and date_diff > DAYS_LIMIT_FOR_HISTORY_DATA: raise BadRequest('Difference between start date and end date ' 'should not be greater than %s days' % DAYS_LIMIT_FOR_HISTORY_DATA) params['start_date'] = start_date params['end_date'] = end_date # Validate awardees, get ID list awardee_ids = [] if awardees is not None: awardees = awardees.split(',') for awardee in awardees: if awardee != '': awardee_id = get_awardee_id_from_name({'awardee': awardee}, self.hpo_dao) if awardee_id == None: raise BadRequest('Invalid awardee name: %s' % awardee) awardee_ids.append(awardee_id) params['awardee_ids'] = awardee_ids # Validate enrollment statuses if enrollment_statuses is not None: enrollment_statuses = enrollment_statuses.split(',') try: params['enrollment_statuses'] = [ EnrollmentStatus(val) for val in enrollment_statuses ] except TypeError: valid_enrollment_statuses = EnrollmentStatus.to_dict() for enrollment_status in enrollment_statuses: if enrollment_status != '': if enrollment_status not in valid_enrollment_statuses: raise BadRequest('Invalid enrollment status: %s' % enrollment_status) return params
def validate_params(self, params): filters = {} # Validate stratifications try: filters['stratification'] = Stratifications(params['stratification']) except TypeError: raise BadRequest('Invalid stratification: %s' % params['stratification']) if filters['stratification'] in [Stratifications.FULL_STATE, Stratifications.FULL_CENSUS, Stratifications.FULL_AWARDEE, Stratifications.GEO_STATE, Stratifications.GEO_CENSUS, Stratifications.GEO_AWARDEE, Stratifications.LIFECYCLE]: # Validate dates if not params['end_date']: raise BadRequest('end date should not be empty') try: end_date = datetime.datetime.strptime(params['end_date'], DATE_FORMAT).date() start_date = end_date except ValueError: raise BadRequest('Invalid end date: %s' % params['end_date']) filters['start_date'] = start_date filters['end_date'] = end_date else: # Validate dates if not params['start_date'] or not params['end_date']: raise BadRequest('Start date and end date should not be empty') try: start_date = datetime.datetime.strptime(params['start_date'], DATE_FORMAT).date() except ValueError: raise BadRequest('Invalid start date: %s' % params['start_date']) try: end_date = datetime.datetime.strptime(params['end_date'], DATE_FORMAT).date() except ValueError: raise BadRequest('Invalid end date: %s' % params['end_date']) date_diff = abs((end_date - start_date).days) if params['history'] != 'TRUE' and date_diff > DAYS_LIMIT_FOR_REALTIME_DATA: raise BadRequest('Difference between start date and end date ' 'should not be greater than %s days' % DAYS_LIMIT_FOR_REALTIME_DATA) if params['history'] == 'TRUE' and date_diff > DAYS_LIMIT_FOR_HISTORY_DATA: raise BadRequest('Difference between start date and end date ' 'should not be greater than %s days' % DAYS_LIMIT_FOR_HISTORY_DATA) filters['start_date'] = start_date filters['end_date'] = end_date # Validate awardees, get ID list awardee_ids = [] if params['awardees'] is not None: awardees = params['awardees'].split(',') for awardee in awardees: if awardee != '': awardee_id = get_awardee_id_from_name({'awardee': awardee}, self.hpo_dao) if awardee_id is None: raise BadRequest('Invalid awardee name: %s' % awardee) awardee_ids.append(awardee_id) filters['awardee_ids'] = awardee_ids # Validate enrollment statuses enrollment_status_strs = [] if params['enrollment_statuses'] is not None: enrollment_statuses = params['enrollment_statuses'].split(',') try: enrollment_status_strs = [str(EnrollmentStatus(val)) for val in enrollment_statuses] except TypeError: valid_enrollment_statuses = EnrollmentStatus.to_dict() for enrollment_status in enrollment_statuses: if enrollment_status != '': if enrollment_status not in valid_enrollment_statuses: raise BadRequest('Invalid enrollment status: %s' % enrollment_status) filters['enrollment_statuses'] = enrollment_status_strs if params['sample_time_def'] and params['sample_time_def'] not in ['STORED', 'ORDERED']: raise BadRequest('Invalid value for parameter filterBy: %s' % params['sample_time_def']) else: filters['sample_time_def'] = params['sample_time_def'] if params['history'] and params['history'] not in ['TRUE', 'FALSE']: raise BadRequest('Invalid value for parameter history: %s' % params['history']) else: filters['history'] = params['history'] return filters