Browse Source

Merge pull request #44858 from nextcloud/artonge/feat/support_multiple_scope_in_dav_search

Support multiple scopes in DAV search
pull/44931/merge
Louis 1 week ago
parent
commit
097f04c8b7
No account linked to committer's email address
1 changed files with 74 additions and 17 deletions
  1. 74
    17
      apps/dav/lib/Files/FileSearchBackend.php

+ 74
- 17
apps/dav/lib/Files/FileSearchBackend.php View File

@@ -30,6 +30,7 @@ use OC\Files\Search\SearchBinaryOperator;
use OC\Files\Search\SearchComparison;
use OC\Files\Search\SearchOrder;
use OC\Files\Search\SearchQuery;
use OC\Files\Storage\Wrapper\Jail;
use OC\Files\View;
use OCA\DAV\Connector\Sabre\CachingTree;
use OCA\DAV\Connector\Sabre\Directory;
@@ -39,6 +40,8 @@ use OCP\Files\Cache\ICacheEntry;
use OCP\Files\Folder;
use OCP\Files\IRootFolder;
use OCP\Files\Node;
use OCP\Files\Search\ISearchBinaryOperator;
use OCP\Files\Search\ISearchComparison;
use OCP\Files\Search\ISearchOperator;
use OCP\Files\Search\ISearchOrder;
use OCP\Files\Search\ISearchQuery;
@@ -152,28 +155,74 @@ class FileSearchBackend implements ISearchBackend {
public function preloadPropertyFor(array $nodes, array $requestProperties): void {
}

/**
* @param Query $search
* @return SearchResult[]
*/
public function search(Query $search): array {
if (count($search->from) !== 1) {
throw new \InvalidArgumentException('Searching more than one folder is not supported');
}
$query = $this->transformQuery($search);
$scope = $search->from[0];
if ($scope->path === null) {
private function getFolderForPath(?string $path = null): Folder {
if ($path === null) {
throw new \InvalidArgumentException('Using uri\'s as scope is not supported, please use a path relative to the search arbiter instead');
}
$node = $this->tree->getNodeForPath($scope->path);

$node = $this->tree->getNodeForPath($path);

if (!$node instanceof Directory) {
throw new \InvalidArgumentException('Search is only supported on directories');
}

$fileInfo = $node->getFileInfo();
$folder = $this->rootFolder->get($fileInfo->getPath());
/** @var Folder $folder $results */
$results = $folder->search($query);

/** @var Folder */
return $this->rootFolder->get($fileInfo->getPath());
}

/**
* @param Query $search
* @return SearchResult[]
*/
public function search(Query $search): array {
switch (count($search->from)) {
case 0:
throw new \InvalidArgumentException('You need to specify a scope for the search.');
break;
case 1:
$scope = $search->from[0];
$folder = $this->getFolderForPath($scope->path);
$query = $this->transformQuery($search);
$results = $folder->search($query);
break;
default:
$scopes = [];
foreach ($search->from as $scope) {
$folder = $this->getFolderForPath($scope->path);
$folderStorage = $folder->getStorage();
if ($folderStorage->instanceOfStorage(Jail::class)) {
/** @var Jail $folderStorage */
$internalPath = $folderStorage->getUnjailedPath($folder->getInternalPath());
} else {
$internalPath = $folder->getInternalPath();
}

$scopes[] = new SearchBinaryOperator(
ISearchBinaryOperator::OPERATOR_AND,
[
new SearchComparison(
ISearchComparison::COMPARE_EQUAL,
'storage',
$folderStorage->getCache()->getNumericStorageId(),
''
),
new SearchComparison(
ISearchComparison::COMPARE_LIKE,
'path',
$internalPath . '/%',
''
),
]
);
}

$scopeOperators = new SearchBinaryOperator(ISearchBinaryOperator::OPERATOR_OR, $scopes);
$query = $this->transformQuery($search, $scopeOperators);
$userFolder = $this->rootFolder->getUserFolder($this->user->getUID());
$results = $userFolder->search($query);
}

/** @var SearchResult[] $nodes */
$nodes = array_map(function (Node $node) {
@@ -288,7 +337,7 @@ class FileSearchBackend implements ISearchBackend {
*
* @return ISearchQuery
*/
private function transformQuery(Query $query): ISearchQuery {
private function transformQuery(Query $query, ?SearchBinaryOperator $scopeOperators = null): ISearchQuery {
$orders = array_map(function (Order $order): ISearchOrder {
$direction = $order->order === Order::ASC ? ISearchOrder::DIRECTION_ASCENDING : ISearchOrder::DIRECTION_DESCENDING;
if (str_starts_with($order->property->name, FilesPlugin::FILE_METADATA_PREFIX)) {
@@ -316,8 +365,16 @@ class FileSearchBackend implements ISearchBackend {
throw new \InvalidArgumentException('Invalid search query, maximum operator limit of ' . self::OPERATOR_LIMIT . ' exceeded, got ' . $operatorCount . ' operators');
}

/** @var SearchBinaryOperator|SearchComparison */
$queryOperators = $this->transformSearchOperation($query->where);
if ($scopeOperators === null) {
$operators = $queryOperators;
} else {
$operators = new SearchBinaryOperator(ISearchBinaryOperator::OPERATOR_AND, [$queryOperators, $scopeOperators]);
}

return new SearchQuery(
$this->transformSearchOperation($query->where),
$operators,
(int)$limit->maxResults,
$offset,
$orders,

Loading…
Cancel
Save