refactor: get_group_by_count

Refactored raw query and partial get_all building with db.query + qb
notation equivalent. Added type hints & f-strings.

Intent: This particular API (for field "assigned_to") was taking
a while to run so decided to refactor this in hopes of perf improvemnts.

Result: 50% reduction in response times :D
This commit is contained in:
gavin 2022-05-27 17:00:57 +05:30
parent e50dfbc859
commit f355034e7c

View file

@ -1,6 +1,11 @@
# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors
# Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and Contributors
# License: MIT. See LICENSE
from typing import Dict, List
import frappe
from frappe.query_builder.functions import Count
from frappe.query_builder.terms import subqry
from frappe.query_builder.utils import DocType
@frappe.whitelist()
@ -24,37 +29,36 @@ def set_list_settings(doctype, values):
@frappe.whitelist()
def get_group_by_count(doctype, current_filters, field):
def get_group_by_count(doctype: str, current_filters: str, field: str) -> List[Dict]:
current_filters = frappe.parse_json(current_filters)
subquery_condition = ""
subquery = frappe.get_all(doctype, filters=current_filters, run=False)
if field == "assigned_to":
subquery_condition = " and `tabToDo`.reference_name in ({subquery})".format(subquery=subquery)
return frappe.db.sql(
"""select `tabToDo`.allocated_to as name, count(*) as count
from
`tabToDo`, `tabUser`
where
`tabToDo`.status!='Cancelled' and
`tabToDo`.allocated_to = `tabUser`.name and
`tabUser`.user_type = 'System User'
{subquery_condition}
group by
`tabToDo`.allocated_to
order by
count desc
limit 50""".format(
subquery_condition=subquery_condition
),
as_dict=True,
)
else:
return frappe.db.get_list(
doctype,
filters=current_filters,
group_by="`tab{0}`.{1}".format(doctype, field),
fields=["count(*) as count", "`{}` as name".format(field)],
order_by="count desc",
limit=50,
ToDo = DocType("ToDo")
User = DocType("User")
count = Count("*").as_("count")
filtered_records = frappe.db.query.build_conditions(doctype, current_filters).select("name")
return (
frappe.qb.from_(ToDo)
.from_(User)
.select(ToDo.allocated_to.as_("name"), count)
.where(
(ToDo.status != "Cancelled")
& (ToDo.allocated_to == User.name)
& (User.user_type == "System User")
& (ToDo.reference_name.isin(subqry(filtered_records)))
)
.groupby(ToDo.allocated_to)
.orderby(count)
.limit(50)
.run(as_dict=True)
)
return frappe.get_list(
doctype,
filters=current_filters,
group_by=f"`tab{doctype}`.{field}",
fields=["count(*) as count", f"`{field}` as name"],
order_by="count desc",
limit=50,
)