Updated SQLAlchemy queries and API endpoints

for single database queries to improve
application performance.
This commit is contained in:
Anastasia Gradova
2024-06-20 01:04:31 -06:00
parent e293f7e3f5
commit fd37923294
2 changed files with 125 additions and 66 deletions

View File

@@ -427,16 +427,15 @@ def dao_fetch_todays_stats_for_service(service_id):
) )
def dao_fetch_stats_for_service_from_day(service_id, day): def dao_fetch_stats_for_service_from_days(service_id, start, days):
# today = datetime.now(timezone.utc).date() start_date = get_midnight_in_utc(start)
# 2024-05-20 end_date = get_midnight_in_utc(start + timedelta(days=days))
# day_date = datetime.strptime(day, '%Y-%m-%d').date()
start_date = get_midnight_in_utc(day)
end_date = get_midnight_in_utc(day + timedelta(days=1))
return ( return (
db.session.query( db.session.query(
NotificationAllTimeView.notification_type, NotificationAllTimeView.notification_type,
NotificationAllTimeView.status, NotificationAllTimeView.status,
func.date_trunc("day", NotificationAllTimeView.created_at).label("day"),
func.count(NotificationAllTimeView.id).label("count"), func.count(NotificationAllTimeView.id).label("count"),
) )
.filter( .filter(
@@ -448,21 +447,21 @@ def dao_fetch_stats_for_service_from_day(service_id, day):
.group_by( .group_by(
NotificationAllTimeView.notification_type, NotificationAllTimeView.notification_type,
NotificationAllTimeView.status, NotificationAllTimeView.status,
func.date_trunc("day", NotificationAllTimeView.created_at),
) )
.all() .all()
) )
def dao_fetch_stats_for_service_from_day_for_user(service_id, day, user_id): def dao_fetch_stats_for_service_from_days_for_user(service_id, start, days, user_id):
# today = datetime.now(timezone.utc).date() start_date = get_midnight_in_utc(start)
# 2024-05-20 end_date = get_midnight_in_utc(start + timedelta(days=days))
# day_date = datetime.strptime(day, '%Y-%m-%d').date()
start_date = get_midnight_in_utc(day)
end_date = get_midnight_in_utc(day + timedelta(days=1))
return ( return (
db.session.query( db.session.query(
NotificationAllTimeView.notification_type, NotificationAllTimeView.notification_type,
NotificationAllTimeView.status, NotificationAllTimeView.status,
func.date_trunc("day", NotificationAllTimeView.created_at).label("day"),
func.count(NotificationAllTimeView.id).label("count"), func.count(NotificationAllTimeView.id).label("count"),
) )
.filter( .filter(
@@ -475,6 +474,7 @@ def dao_fetch_stats_for_service_from_day_for_user(service_id, day, user_id):
.group_by( .group_by(
NotificationAllTimeView.notification_type, NotificationAllTimeView.notification_type,
NotificationAllTimeView.status, NotificationAllTimeView.status,
func.date_trunc("day", NotificationAllTimeView.created_at),
) )
.all() .all()
) )

View File

@@ -1,4 +1,5 @@
import itertools import itertools
from collections import defaultdict
from datetime import datetime, timedelta from datetime import datetime, timedelta
from flask import Blueprint, current_app, jsonify, request from flask import Blueprint, current_app, jsonify, request
@@ -17,11 +18,7 @@ from app.dao.api_key_dao import (
save_model_api_key, save_model_api_key,
) )
from app.dao.dao_utils import dao_rollback, transaction from app.dao.dao_utils import dao_rollback, transaction
from app.dao.date_util import ( from app.dao.date_util import get_calendar_year, get_month_start_and_end_date_in_utc
get_calendar_year,
get_month_start_and_end_date_in_utc,
get_number_of_days_for_month,
)
from app.dao.fact_notification_status_dao import ( from app.dao.fact_notification_status_dao import (
fetch_monthly_template_usage_for_service, fetch_monthly_template_usage_for_service,
fetch_notification_status_for_service_by_month, fetch_notification_status_for_service_by_month,
@@ -67,8 +64,8 @@ from app.dao.services_dao import (
dao_fetch_all_services_by_user, dao_fetch_all_services_by_user,
dao_fetch_live_services_data, dao_fetch_live_services_data,
dao_fetch_service_by_id, dao_fetch_service_by_id,
dao_fetch_stats_for_service_from_day, dao_fetch_stats_for_service_from_days,
dao_fetch_stats_for_service_from_day_for_user, dao_fetch_stats_for_service_from_days_for_user,
dao_fetch_todays_stats_for_all_services, dao_fetch_todays_stats_for_all_services,
dao_fetch_todays_stats_for_service, dao_fetch_todays_stats_for_service,
dao_remove_user_from_service, dao_remove_user_from_service,
@@ -227,19 +224,33 @@ def get_service_notification_statistics_by_day(service_id, start, days):
def get_service_statistics_for_specific_days(service_id, start, days=1): def get_service_statistics_for_specific_days(service_id, start, days=1):
start_date = datetime.strptime(start, "%Y-%m-%d").date() start_date = datetime.strptime(start, "%Y-%m-%d").date()
if days == 1: def generate_date_range(start_date, days):
stats = {} current_date = start_date
stats[start] = statistics.format_statistics( end_date = start_date - timedelta(days=days)
dao_fetch_stats_for_service_from_day(service_id, start_date) while current_date > end_date:
) try:
else: valid_date = datetime(
stats = {} current_date.year, current_date.month, current_date.day
for d in range(days): )
new_date = start_date - timedelta(days=d) yield valid_date.date()
key = new_date.strftime("%Y-%m-%d") except ValueError:
stats[key] = statistics.format_statistics( pass
dao_fetch_stats_for_service_from_day(service_id, new_date) current_date -= timedelta(days=1)
)
results = dao_fetch_stats_for_service_from_days(service_id, start_date, days)
grouped_results = defaultdict(list)
for row in results:
notification_type, status, day, count = row
grouped_results[day.date()].append(row)
for date in generate_date_range(start_date, days):
if date not in grouped_results:
grouped_results[date] = []
stats = {}
for day, rows in grouped_results.items():
stats[day.strftime("%Y-%m-%d")] = statistics.format_statistics(rows)
return stats return stats
@@ -262,23 +273,35 @@ def get_service_statistics_for_specific_days_by_user(
): ):
start_date = datetime.strptime(start, "%Y-%m-%d").date() start_date = datetime.strptime(start, "%Y-%m-%d").date()
if days == 1: def generate_date_range(start_date, days):
stats = {} current_date = start_date
stats[start] = statistics.format_statistics( end_date = start_date - timedelta(days=days)
dao_fetch_stats_for_service_from_day_for_user( while current_date > end_date:
service_id, start_date, user_id try:
) valid_date = datetime(
) current_date.year, current_date.month, current_date.day
else:
stats = {}
for d in range(days):
new_date = start_date - timedelta(days=d)
key = new_date.strftime("%Y-%m-%d")
stats[key] = statistics.format_statistics(
dao_fetch_stats_for_service_from_day_for_user(
service_id, new_date, user_id
) )
) yield valid_date.date()
except ValueError:
pass
current_date -= timedelta(days=1)
results = dao_fetch_stats_for_service_from_days_for_user(
service_id, start_date, days, user_id
)
grouped_results = defaultdict(list)
for row in results:
notification_type, status, day, count = row
grouped_results[day.date()].append(row)
for date in generate_date_range(start_date, days):
if date not in grouped_results:
grouped_results[date] = []
stats = {}
for day, rows in grouped_results.items():
stats[day.strftime("%Y-%m-%d")] = statistics.format_statistics(rows)
return stats return stats
@@ -732,19 +755,37 @@ def get_single_month_notification_stats_by_user(service_id, user_id):
) )
month_year = datetime(year, month, 10, 00, 00, 00) month_year = datetime(year, month, 10, 00, 00, 00)
days = get_number_of_days_for_month(year, month)
start_date, end_date = get_month_start_and_end_date_in_utc(month_year) start_date, end_date = get_month_start_and_end_date_in_utc(month_year)
stats = {} def generate_date_range(start_date, end_date):
for d in range(days): current_date = start_date
new_date = start_date + timedelta(days=d) end_date = end_date
if new_date <= end_date: while current_date < end_date:
key = new_date.strftime("%Y-%m-%d") try:
stats[key] = statistics.format_statistics( valid_date = datetime(
dao_fetch_stats_for_service_from_day_for_user( current_date.year, current_date.month, current_date.day
service_id, new_date, user_id
) )
) yield valid_date.date()
except ValueError:
pass
current_date += timedelta(days=1)
results = dao_fetch_stats_for_service_from_days_for_user(
service_id, start_date, user_id
)
grouped_results = defaultdict(list)
for row in results:
notification_type, status, day, count = row
grouped_results[day.date()].append(row)
for date in generate_date_range(start_date, end_date):
if date not in grouped_results:
grouped_results[date] = []
stats = {}
for day, rows in grouped_results.items():
stats[day.strftime("%Y-%m-%d")] = statistics.format_statistics(rows)
return jsonify(stats) return jsonify(stats)
@@ -763,17 +804,35 @@ def get_single_month_notification_stats_for_service(service_id):
) )
month_year = datetime(year, month, 10, 00, 00, 00) month_year = datetime(year, month, 10, 00, 00, 00)
days = get_number_of_days_for_month(year, month)
start_date, end_date = get_month_start_and_end_date_in_utc(month_year) start_date, end_date = get_month_start_and_end_date_in_utc(month_year)
def generate_date_range(start_date, end_date):
current_date = start_date
end_date = end_date
while current_date < end_date:
try:
valid_date = datetime(
current_date.year, current_date.month, current_date.day
)
yield valid_date.date()
except ValueError:
pass
current_date += timedelta(days=1)
results = dao_fetch_stats_for_service_from_days(service_id, start_date)
grouped_results = defaultdict(list)
for row in results:
notification_type, status, day, count = row
grouped_results[day.date()].append(row)
for date in generate_date_range(start_date, end_date):
if date not in grouped_results:
grouped_results[date] = []
stats = {} stats = {}
for d in range(days): for day, rows in grouped_results.items():
new_date = start_date + timedelta(days=d) stats[day.strftime("%Y-%m-%d")] = statistics.format_statistics(rows)
if new_date <= end_date:
key = new_date.strftime("%Y-%m-%d")
stats[key] = statistics.format_statistics(
dao_fetch_stats_for_service_from_day(service_id, new_date)
)
return jsonify(stats) return jsonify(stats)