perf: HTTP cache list view counts when count is >1000 (#29871)

This allows for caching the count which are frequently requested but
rarely change and even if they changed, UI doesn't show accurate value
to begin with.

After this change any filters that result in "1,000+" response will be
just cached by client and won't be requested again and again (for at
least 30 minutes, it's SWR after that so UI should still be snappy)
This commit is contained in:
Ankush Menat 2025-01-21 14:55:58 +05:30 committed by GitHub
parent e4a2b8db38
commit 930d006f4c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 28 additions and 15 deletions

View file

@ -67,6 +67,9 @@ def get_count() -> int:
args.fields = [fieldname]
partial_query = execute(**args, run=0)
count = frappe.db.sql(f"""select count(*) from ( {partial_query} ) p""")[0][0]
if count == args.limit:
frappe.response.can_cache = True
else:
args.fields = [f"count({fieldname}) as total_count"]
count = execute(**args)[0].get("total_count")

View file

@ -102,7 +102,7 @@ frappe.db = {
frappe.call("frappe.client.delete", { doctype, name }, (r) => resolve(r.message));
});
},
count: function (doctype, args = {}) {
count: function (doctype, args = {}, cache = false) {
let filters = args.filters || {};
let limit = args.limit;
@ -115,13 +115,18 @@ frappe.db = {
const fields = [];
return frappe.xcall("frappe.desk.reportview.get_count", {
doctype,
filters,
fields,
distinct,
limit,
});
return frappe.xcall(
"frappe.desk.reportview.get_count",
{
doctype,
filters,
fields,
distinct,
limit,
},
cache ? "GET" : "POST",
{ cache }
);
},
get_link_options(doctype, txt = "", filters = {}) {
return new Promise((resolve) => {

View file

@ -1008,10 +1008,14 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
let count_without_children = this.data.uniqBy((d) => d.name).length;
return frappe.db
.count(this.doctype, {
filters: this.get_filters_for_args(),
limit: this.count_upper_bound,
})
.count(
this.doctype,
{
filters: this.get_filters_for_args(),
limit: this.count_upper_bound,
},
Boolean(this.count_upper_bound)
)
.then((total_count) => {
this.total_count = total_count || current_count;
this.count_without_children =

View file

@ -10,7 +10,7 @@ frappe.request.ajax_count = 0;
frappe.request.waiting_for_ajax = [];
frappe.request.logs = {};
frappe.xcall = function (method, params, type) {
frappe.xcall = function (method, params, type, opts = {}) {
return new Promise((resolve, reject) => {
frappe.call({
method: method,
@ -22,6 +22,7 @@ frappe.xcall = function (method, params, type) {
error: (r) => {
reject(r?.message);
},
...opts,
});
});
};
@ -118,11 +119,11 @@ frappe.call = function (opts) {
freeze_message: opts.freeze_message,
headers: opts.headers || {},
error_handlers: opts.error_handlers || {},
// show_spinner: !opts.no_spinner,
async: opts.async,
silent: opts.silent,
api_version: opts.api_version,
url,
cache: opts.cache,
});
};
@ -268,7 +269,7 @@ frappe.request.call = function (opts) {
},
opts.headers
),
cache: window.dev_server ? false : true,
cache: window.dev_server ? false : opts.cache || false,
};
if (opts.args && opts.args.doctype) {