perf(webdav): single UNION ALL query for path resolution

Replace the double-query pattern (get_folder_by_path + get_file_by_path)
across PROPFIND, HEAD, DELETE, MOVE, and COPY handlers with a single
UNION ALL query via PathResolverService.

PG Append node short-circuits on LIMIT 1: if the folder branch matches,
the file branch is never executed. Cuts WebDAV path resolution from
2 round-trips to 1 per request.

Also adds an exists() method using EXISTS subqueries for the Overwrite
header checks in MOVE/COPY (avoids constructing full DTOs).

Legacy double-query fallback retained when PathResolver is unavailable.
This commit is contained in:
Dionisio
2026-03-02 23:40:48 +01:00
parent b199968a6e
commit b9bf7ba288
4 changed files with 648 additions and 212 deletions
+10
View File
@@ -542,6 +542,7 @@ impl AppServiceFactory {
wopi_discovery_service: None,
device_auth_service: None,
app_password_service: None,
path_resolver: None,
};
// 9b. Wire admin settings service when auth is available
@@ -651,6 +652,13 @@ impl AppServiceFactory {
}
}
// 9e. Wire PathResolver for single-query WebDAV path resolution
{
use crate::infrastructure::services::path_resolver_service::PathResolverService;
app_state.path_resolver = Some(Arc::new(PathResolverService::new(pool.clone())));
tracing::info!("PathResolver service initialized");
}
// 10. Wire CalDAV/CardDAV services
{
// CalDAV
@@ -846,6 +854,8 @@ pub struct AppState {
Option<Arc<crate::application::services::device_auth_service::DeviceAuthService>>,
pub app_password_service:
Option<Arc<crate::application::services::app_password_service::AppPasswordService>>,
pub path_resolver:
Option<Arc<crate::infrastructure::services::path_resolver_service::PathResolverService>>,
}
// All AppState construction is done via struct literal in build_app_state().