Restructured the query to be adhering to SQLAlchemy 2.0.

Signed-off-by: Cliff Hill <Clifford.hill@gsa.gov>
This commit is contained in:
Cliff Hill
2024-08-22 14:04:22 -04:00
parent 5d5ff72ca2
commit 05e27c7f3b
+70 -56
View File
@@ -1,9 +1,10 @@
from datetime import date, timedelta from datetime import date, timedelta
from sqlalchemy import Date, case, func from sqlalchemy import Date, case, func, select, union_all, cast
from sqlalchemy.dialects.postgresql import insert from sqlalchemy.dialects.postgresql import insert
from sqlalchemy.orm import aliased
from sqlalchemy.sql.expression import extract, literal from sqlalchemy.sql.expression import extract, literal
from sqlalchemy.types import DateTime, Integer from sqlalchemy.types import DateTime, Integer, Text
from app import db from app import db
from app.dao.dao_utils import autocommit from app.dao.dao_utils import autocommit
@@ -126,83 +127,96 @@ def fetch_notification_status_for_service_for_day(fetch_day, service_id):
def fetch_notification_status_for_service_for_today_and_7_previous_days( def fetch_notification_status_for_service_for_today_and_7_previous_days(
service_id, by_template=False, limit_days=7 service_id: str,
): by_template: bool = False,
limit_days: int = 7
) -> list[dict | None]:
start_date = midnight_n_days_ago(limit_days) start_date = midnight_n_days_ago(limit_days)
now = utc_now() now = utc_now()
stats_for_7_days = db.session.query(
FactNotificationStatus.notification_type.cast(db.Text).label( # Query for the last 7 days
"notification_type" stats_for_7_days = select(
), cast(FactNotificationStatus.notification_type, Text).label("notification_type"),
FactNotificationStatus.notification_status.cast(db.Text).label("status"), cast(FactNotificationStatus.notification_status, Text).label("status"),
*( *(
[ [
FactNotificationStatus.template_id.label("template_id"), FactNotificationStatus.template_id.label("template_id"),
FactNotificationStatus.local_date.label("last_used"), FactNotificationStatus.local_date.label("date_used"),
] ] if by_template else []
if by_template
else []
), ),
FactNotificationStatus.notification_count.label("count"), FactNotificationStatus.notification_count.label("count"),
).filter( ).where(
FactNotificationStatus.service_id == service_id, FactNotificationStatus.service_id == service_id,
FactNotificationStatus.local_date >= start_date, FactNotificationStatus.local_date >= start_date,
FactNotificationStatus.key_type != KeyType.TEST, FactNotificationStatus.key_type != KeyType.TEST,
) )
stats_for_today = ( # Query for today's stats
db.session.query( stats_for_today = select(
Notification.notification_type.cast(db.Text), cast(Notification.notification_type, Text),
Notification.status.cast(db.Text), cast(Notification.status, Text),
*( *(
[ [
Notification.template_id, Notification.template_id,
literal(date.today()).label("last_used"), literal(date.today()).label("date_used"),
] ] if by_template else []
if by_template ),
else [] func.count().label("count"),
), ).where(
func.count().label("count"), Notification.created_at >= get_midnight_in_utc(now),
) Notification.service_id == service_id,
.filter( Notification.key_type != KeyType.TEST,
Notification.created_at >= get_midnight_in_utc(now), ).group_by(
Notification.service_id == service_id, Notification.notification_type,
Notification.key_type != KeyType.TEST, *([Notification.template_id] if by_template else []),
) Notification.status,
.group_by(
Notification.notification_type,
*([Notification.template_id] if by_template else []),
Notification.status,
)
) )
all_stats_table = stats_for_7_days.union_all(stats_for_today).subquery() # Combine the queries using union_all
all_stats_union = union_all(stats_for_7_days, stats_for_today).subquery()
all_stats_alias = aliased(all_stats_union)
query = db.session.query( # Final query with optional template joins
query = select(
*( *(
[ [
Template.name.label("template_name"), Template.name.label("template_name"),
False, # TODO: this is related to is_precompiled_letter False, # TODO: Handle `is_precompiled_letter`
all_stats_table.c.template_id, all_stats_alias.c.template_id,
Template.folder.name.label("folder"), Template.folder.label("folder"),
Template.created_by.name.label("created_by"), Template.created_by.label("created_by"),
] func.max(all_stats_alias.c.date_used).label("last_used"), # Get the most recent date
if by_template ] if by_template else []
else []
), ),
all_stats_table.c.notification_type, all_stats_alias.c.notification_type,
all_stats_table.c.status, all_stats_alias.c.status,
func.cast(func.sum(all_stats_table.c.count), Integer).label("count"), cast(func.sum(all_stats_alias.c.count), Integer).label("count"),
) )
if by_template: if by_template:
query = query.filter(all_stats_table.c.template_id == Template.id) query = query.join(Template, all_stats_alias.c.template_id == Template.id)
return query.group_by( # Group by all necessary fields except date_used
*([Template.name, all_stats_table.c.template_id] if by_template else []), query = query.group_by(
all_stats_table.c.notification_type, *(
all_stats_table.c.status, [
).all() Template.name,
all_stats_alias.c.template_id,
Template.folder,
Template.created_by,
] if by_template else []
),
all_stats_alias.c.notification_type,
all_stats_alias.c.status,
)
print("*"*79)
print(query)
print("*"*79)
# Execute the query using Flask-SQLAlchemy's session
result = db.session.execute(query)
return result.mappings().all()
def fetch_notification_status_totals_for_all_services(start_date, end_date): def fetch_notification_status_totals_for_all_services(start_date, end_date):