perf: drop intermediate allocs in WebDAV href encoding; fold group-list COUNT into one query

webdav encode_uri_path runs on every PROPFIND href and did
.map(...).collect::<Vec<_>>().join("/"), allocating a String per segment plus
a joined Vec. Write each utf8_percent_encode Display adapter straight into a
single preallocated String. Behavior is identical (split on '/', encode each
segment, join with '/'), including leading/trailing-slash edge cases.

subject_group list / list_with_counts each issued a second SELECT COUNT(*)
round-trip for the total. Fold it into the page query via COUNT(*) OVER() —
the pattern folder_db_repository already uses — halving the round-trips.
total_count is read from the first row and is 0 on an empty page, matching
folder_db_repository's documented convention.

https://claude.ai/code/session_01UtfkS3nZF1vrF5jNAps6wV
This commit is contained in:
Claude
2026-06-09 13:29:05 +00:00
parent f82c5ccf47
commit ec8ddebc30
2 changed files with 58 additions and 72 deletions
+17 -4
View File
@@ -63,10 +63,23 @@ fn encode_path_segment(segment: &str) -> String {
/// Percent-encode a full slash-separated path, encoding each segment individually.
pub(crate) fn encode_uri_path(path: &str) -> String {
path.split('/')
.map(encode_path_segment)
.collect::<Vec<_>>()
.join("/")
use std::fmt::Write as _;
// `utf8_percent_encode` returns a `Display` adapter, so write each encoded
// segment straight into `out` — avoids a String per segment and the joined
// Vec the previous `.map(...).collect::<Vec<_>>().join("/")` allocated on
// every PROPFIND href.
let mut out = String::with_capacity(path.len() + 8);
for (i, segment) in path.split('/').enumerate() {
if i > 0 {
out.push('/');
}
let _ = write!(
out,
"{}",
utf8_percent_encode(segment, PATH_SEGMENT_ENCODE_SET)
);
}
out
}
/// Build the `<D:href>` value for a non-collection (file) resource.