|
|
@@ -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, |