From 4cb62ca0d6aeb8a61d6f8a33654d9033a5ffd5d6 Mon Sep 17 00:00:00 2001 From: epriestley Date: Thu, 22 Feb 2018 10:51:27 -0800 Subject: [PATCH] Support "phriction.document.search" queries by "parentPaths" or "ancestorPaths" Summary: Ref T13090. Ref T13077. This adds `parentPaths` and `ancestorPaths` constraints to `phriction.document.query`. These should be a little more usable than the internal `slugPrefix` / `depth` stuff -- that's technically more powerful, but requires callers to know more slug normalization rules. We could perhaps expose `minDepth` / `maxDepth` in the future. Test Plan: Ran valid and invalid `parentPaths` and `ancestorPaths` queries for `/`, `aaa/`, `AAA/`, etc. Got sensible-seeming results. Maniphest Tasks: T13090, T13077 Differential Revision: https://secure.phabricator.com/D19125 --- .../query/PhrictionDocumentQuery.php | 103 +++++++++++++++++- .../query/PhrictionDocumentSearchEngine.php | 16 +++ 2 files changed, 118 insertions(+), 1 deletion(-) diff --git a/src/applications/phriction/query/PhrictionDocumentQuery.php b/src/applications/phriction/query/PhrictionDocumentQuery.php index de3064fd42..0c6a2c23bc 100644 --- a/src/applications/phriction/query/PhrictionDocumentQuery.php +++ b/src/applications/phriction/query/PhrictionDocumentQuery.php @@ -10,6 +10,9 @@ final class PhrictionDocumentQuery private $slugPrefix; private $statuses; + private $parentPaths; + private $ancestorPaths; + private $needContent; const ORDER_HIERARCHY = 'hierarchy'; @@ -34,7 +37,7 @@ final class PhrictionDocumentQuery return $this; } - public function withSlugPrefix($slug_prefix) { + public function withSlugPrefix($slug_prefix) { $this->slugPrefix = $slug_prefix; return $this; } @@ -44,6 +47,16 @@ final class PhrictionDocumentQuery return $this; } + public function withParentPaths(array $paths) { + $this->parentPaths = $paths; + return $this; + } + + public function withAncestorPaths(array $paths) { + $this->ancestorPaths = $paths; + return $this; + } + public function needContent($need_content) { $this->needContent = $need_content; return $this; @@ -214,6 +227,94 @@ final class PhrictionDocumentQuery $this->depths); } + if ($this->parentPaths !== null || $this->ancestorPaths !== null) { + $sets = array( + array( + 'paths' => $this->parentPaths, + 'parents' => true, + ), + array( + 'paths' => $this->ancestorPaths, + 'parents' => false, + ), + ); + + $paths = array(); + foreach ($sets as $set) { + $set_paths = $set['paths']; + if ($set_paths === null) { + continue; + } + + if (!$set_paths) { + throw new PhabricatorEmptyQueryException( + pht('No parent/ancestor paths specified.')); + } + + $is_parents = $set['parents']; + foreach ($set_paths as $path) { + $path_normal = PhabricatorSlug::normalize($path); + if ($path !== $path_normal) { + throw new Exception( + pht( + 'Document path "%s" is not a valid path. The normalized '. + 'form of this path is "%s".', + $path, + $path_normal)); + } + + $depth = PhabricatorSlug::getDepth($path_normal); + if ($is_parents) { + $min_depth = $depth + 1; + $max_depth = $depth + 1; + } else { + $min_depth = $depth + 1; + $max_depth = null; + } + + $paths[] = array( + $path_normal, + $min_depth, + $max_depth, + ); + } + } + + $path_clauses = array(); + foreach ($paths as $path) { + $parts = array(); + list($prefix, $min, $max) = $path; + + // If we're getting children or ancestors of the root document, they + // aren't actually stored with the leading "/" in the database, so + // just skip this part of the clause. + if ($prefix !== '/') { + $parts[] = qsprintf( + $conn, + 'd.slug LIKE %>', + $prefix); + } + + if ($min !== null) { + $parts[] = qsprintf( + $conn, + 'd.depth >= %d', + $min); + } + + if ($max !== null) { + $parts[] = qsprintf( + $conn, + 'd.depth <= %d', + $max); + } + + $path_clauses[] = '('.implode(') AND (', $parts).')'; + } + + $where[] = '('.implode(') OR (', $path_clauses).')'; + } + return $where; } diff --git a/src/applications/phriction/query/PhrictionDocumentSearchEngine.php b/src/applications/phriction/query/PhrictionDocumentSearchEngine.php index e0781ec81f..e3d962146a 100644 --- a/src/applications/phriction/query/PhrictionDocumentSearchEngine.php +++ b/src/applications/phriction/query/PhrictionDocumentSearchEngine.php @@ -27,6 +27,14 @@ final class PhrictionDocumentSearchEngine $query->withSlugs($map['paths']); } + if ($map['parentPaths']) { + $query->withParentPaths($map['parentPaths']); + } + + if ($map['ancestorPaths']) { + $query->withAncestorPaths($map['ancestorPaths']); + } + return $query; } @@ -40,6 +48,14 @@ final class PhrictionDocumentSearchEngine ->setKey('paths') ->setIsHidden(true) ->setLabel(pht('Paths')), + id(new PhabricatorSearchStringListField()) + ->setKey('parentPaths') + ->setIsHidden(true) + ->setLabel(pht('Parent Paths')), + id(new PhabricatorSearchStringListField()) + ->setKey('ancestorPaths') + ->setIsHidden(true) + ->setLabel(pht('Ancestor Paths')), ); }