From 30fe09185faa3acc44b5e0fc6206c1a46f197711 Mon Sep 17 00:00:00 2001 From: Son NK <> Date: Fri, 21 Aug 2020 19:51:48 +0200 Subject: [PATCH] create get_alias_infos_with_pagination_v3 - reduce nb queries used in get_alias_infos_with_pagination_v2 --- app/api/serializer.py | 102 ++++++++++++++++++- app/api/views/alias.py | 4 +- app/dashboard/templates/dashboard/index.html | 2 +- app/dashboard/views/index.py | 5 +- 4 files changed, 107 insertions(+), 6 deletions(-) diff --git a/app/api/serializer.py b/app/api/serializer.py index 31b85784..167f5480 100644 --- a/app/api/serializer.py +++ b/app/api/serializer.py @@ -1,7 +1,7 @@ from dataclasses import dataclass from arrow import Arrow -from sqlalchemy import or_, func, case +from sqlalchemy import or_, func, case, and_ from sqlalchemy.orm import joinedload from app.config import PAGE_LIMIT @@ -186,6 +186,106 @@ def get_alias_infos_with_pagination_v2( return ret +def get_alias_infos_with_pagination_v3( + user, page_id=0, query=None, sort=None, alias_filter=None +) -> [AliasInfo]: + ret = [] + latest_activity = func.max( + case( + [ + (Alias.created_at > EmailLog.created_at, Alias.created_at), + (Alias.created_at < EmailLog.created_at, EmailLog.created_at), + ], + else_=Alias.created_at, + ) + ).label("latest") + + sub = ( + db.session.query( + Alias.id, + latest_activity, + func.sum(case([(EmailLog.is_reply, 1)], else_=0)).label("nb_reply"), + func.sum( + case( + [(and_(EmailLog.is_reply == False, EmailLog.blocked), 1)], else_=0, + ) + ).label("nb_blocked"), + func.sum( + case( + [ + ( + and_( + EmailLog.is_reply == False, EmailLog.blocked == False, + ), + 1, + ) + ], + else_=0, + ) + ).label("nb_forward"), + func.max(EmailLog.created_at).label("max_created_at"), + ) + .join(Contact, Alias.id == Contact.alias_id, isouter=True) + .join(EmailLog, Contact.id == EmailLog.contact_id, isouter=True) + .filter(Alias.user_id == user.id) + .group_by(Alias.id) + .subquery() + ) + + q = db.session.query( + Alias, Contact, EmailLog, sub.c.nb_reply, sub.c.nb_blocked, sub.c.nb_forward + ).filter( + Alias.id == sub.c.id, + Alias.id == Contact.alias_id, + Contact.id == EmailLog.contact_id, + EmailLog.created_at == sub.c.latest, + ) + + if query: + q = q.filter( + or_( + Alias.email.ilike(f"%{query}%"), + Alias.note.ilike(f"%{query}%"), + Alias.name.ilike(f"%{query}%"), + ) + ) + + if alias_filter == "enabled": + q = q.filter(Alias.enabled) + elif alias_filter == "disabled": + q = q.filter(Alias.enabled == False) + + if sort == "old2new": + q = q.order_by(Alias.created_at) + elif sort == "new2old": + q = q.order_by(Alias.created_at.desc()) + elif sort == "a2z": + q = q.order_by(Alias.email) + elif sort == "z2a": + q = q.order_by(Alias.email.desc()) + else: + # default sorting + q = q.order_by(sub.c.latest.desc()) + + q = list(q.limit(PAGE_LIMIT).offset(page_id * PAGE_LIMIT)) + + for alias, contact, email_log, nb_reply, nb_blocked, nb_forward in q: + ret.append( + AliasInfo( + alias=alias, + mailbox=alias.mailbox, + mailboxes=alias.mailboxes, + nb_forward=nb_forward, + nb_blocked=nb_blocked, + nb_reply=nb_reply, + latest_email_log=email_log, + latest_contact=contact, + ) + ) + + return ret + + def get_alias_info(alias: Alias) -> AliasInfo: q = ( db.session.query(Contact, EmailLog) diff --git a/app/api/views/alias.py b/app/api/views/alias.py index 7d619651..21d8561b 100644 --- a/app/api/views/alias.py +++ b/app/api/views/alias.py @@ -10,9 +10,9 @@ from app.api.serializer import ( serialize_contact, get_alias_infos_with_pagination, get_alias_contacts, - get_alias_infos_with_pagination_v2, serialize_alias_info_v2, get_alias_info_v2, + get_alias_infos_with_pagination_v3, ) from app.config import EMAIL_DOMAIN from app.dashboard.views.alias_log import get_alias_log @@ -107,7 +107,7 @@ def get_aliases_v2(): if data: query = data.get("query") - alias_infos: [AliasInfo] = get_alias_infos_with_pagination_v2( + alias_infos: [AliasInfo] = get_alias_infos_with_pagination_v3( user, page_id=page_id, query=query ) diff --git a/app/dashboard/templates/dashboard/index.html b/app/dashboard/templates/dashboard/index.html index a986bd13..263c206c 100644 --- a/app/dashboard/templates/dashboard/index.html +++ b/app/dashboard/templates/dashboard/index.html @@ -171,7 +171,7 @@ {% set alias = alias_info.alias %}
-
+
diff --git a/app/dashboard/views/index.py b/app/dashboard/views/index.py index baf850de..ccc1ea61 100644 --- a/app/dashboard/views/index.py +++ b/app/dashboard/views/index.py @@ -1,10 +1,11 @@ from dataclasses import dataclass + from flask import render_template, request, redirect, url_for, flash from flask_login import login_required, current_user from sqlalchemy.orm import joinedload from app import alias_utils -from app.api.serializer import get_alias_infos_with_pagination_v2 +from app.api.serializer import get_alias_infos_with_pagination_v3 from app.config import PAGE_LIMIT from app.dashboard.base import dashboard_bp from app.extensions import db @@ -136,7 +137,7 @@ def index(): stats = get_stats(current_user) - alias_infos = get_alias_infos_with_pagination_v2( + alias_infos = get_alias_infos_with_pagination_v3( current_user, page, query, sort, alias_filter ) last_page = len(alias_infos) < PAGE_LIMIT