Files: Extend search to also cover tags

fixes #326

Signed-off-by: Marcel Klehr <mklehr@gmx.net>
This commit is contained in:
Marcel Klehr 2021-04-28 19:07:15 +02:00
parent 48f05158e5
commit 9995706863
5 changed files with 28 additions and 9 deletions

View File

@ -29,6 +29,7 @@ declare(strict_types=1);
namespace OCA\Files\Search; namespace OCA\Files\Search;
use OC\Files\Search\SearchBinaryOperator;
use OC\Files\Search\SearchComparison; use OC\Files\Search\SearchComparison;
use OC\Files\Search\SearchOrder; use OC\Files\Search\SearchOrder;
use OC\Files\Search\SearchQuery; use OC\Files\Search\SearchQuery;
@ -103,7 +104,11 @@ class FilesSearchProvider implements IProvider {
public function search(IUser $user, ISearchQuery $query): SearchResult { public function search(IUser $user, ISearchQuery $query): SearchResult {
$userFolder = $this->rootFolder->getUserFolder($user->getUID()); $userFolder = $this->rootFolder->getUserFolder($user->getUID());
$fileQuery = new SearchQuery( $fileQuery = new SearchQuery(
new SearchComparison(ISearchComparison::COMPARE_LIKE, 'name', '%' . $query->getTerm() . '%'), new SearchBinaryOperator(SearchBinaryOperator::OPERATOR_OR, [
new SearchComparison(ISearchComparison::COMPARE_LIKE, 'name', '%' . $query->getTerm() . '%'),
new SearchComparison(ISearchComparison::COMPARE_LIKE, 'tagname', '%' . $query->getTerm() . '%'),
new SearchComparison(ISearchComparison::COMPARE_LIKE, 'systemtag', '%' . $query->getTerm() . '%'),
]),
$query->getLimit(), $query->getLimit(),
(int)$query->getCursor(), (int)$query->getCursor(),
$query->getSortOrder() === ISearchQuery::SORT_DATE_DESC ? [ $query->getSortOrder() === ISearchQuery::SORT_DATE_DESC ? [

View File

@ -850,13 +850,21 @@ class Cache implements ICache {
throw new \InvalidArgumentException("Searching by tag requires the user to be set in the query"); throw new \InvalidArgumentException("Searching by tag requires the user to be set in the query");
} }
$query $query
->innerJoin('file', 'vcategory_to_object', 'tagmap', $builder->expr()->eq('file.fileid', 'tagmap.objid')) ->leftJoin('file', 'vcategory_to_object', 'tagmap', $builder->expr()->eq('file.fileid', 'tagmap.objid'))
->innerJoin('tagmap', 'vcategory', 'tag', $builder->expr()->andX( ->leftJoin('tagmap', 'vcategory', 'tag', $builder->expr()->andX(
$builder->expr()->eq('tagmap.type', 'tag.type'), $builder->expr()->eq('tagmap.type', 'tag.type'),
$builder->expr()->eq('tagmap.categoryid', 'tag.id') $builder->expr()->eq('tagmap.categoryid', 'tag.id'),
$builder->expr()->eq('tag.type', $builder->createNamedParameter('files')),
$builder->expr()->eq('tag.uid', $builder->createNamedParameter($user->getUID()))
)) ))
->andWhere($builder->expr()->eq('tag.type', $builder->createNamedParameter('files'))) ->leftJoin('file', 'systemtag_object_mapping', 'systemtagmap', $builder->expr()->andX(
->andWhere($builder->expr()->eq('tag.uid', $builder->createNamedParameter($user->getUID()))); $builder->expr()->eq('file.fileid', $builder->expr()->castColumn('systemtagmap.objectid', IQueryBuilder::PARAM_INT)),
$builder->expr()->eq('systemtagmap.objecttype', $builder->createNamedParameter('files'))
))
->leftJoin('systemtagmap', 'systemtag', 'systemtag', $builder->expr()->andX(
$builder->expr()->eq('systemtag.id', 'systemtagmap.systemtagid'),
$builder->expr()->eq('systemtag.visibility', $builder->createNamedParameter(true))
));
} }
$searchExpr = $this->querySearchHelper->searchOperatorToDBExpr($builder, $searchQuery->getSearchOperation()); $searchExpr = $this->querySearchHelper->searchOperatorToDBExpr($builder, $searchQuery->getSearchOperation());

View File

@ -47,7 +47,7 @@ class CacheQueryBuilder extends QueryBuilder {
public function selectFileCache(string $alias = null) { public function selectFileCache(string $alias = null) {
$name = $alias ? $alias : 'filecache'; $name = $alias ? $alias : 'filecache';
$this->select("$name.fileid", 'storage', 'path', 'path_hash', "$name.parent", 'name', 'mimetype', 'mimepart', 'size', 'mtime', $this->select("$name.fileid", 'storage', 'path', 'path_hash', "$name.parent", "$name.name", 'mimetype', 'mimepart', 'size', 'mtime',
'storage_mtime', 'encrypted', 'etag', 'permissions', 'checksum', 'metadata_etag', 'creation_time', 'upload_time') 'storage_mtime', 'encrypted', 'etag', 'permissions', 'checksum', 'metadata_etag', 'creation_time', 'upload_time')
->from('filecache', $name) ->from('filecache', $name)
->leftJoin($name, 'filecache_extended', 'fe', $this->expr()->eq("$name.fileid", 'fe.fileid')); ->leftJoin($name, 'filecache_extended', 'fe', $this->expr()->eq("$name.fileid", 'fe.fileid'));

View File

@ -81,7 +81,7 @@ class QuerySearchHelper {
return $shouldJoin || $this->shouldJoinTags($operator); return $shouldJoin || $this->shouldJoinTags($operator);
}, false); }, false);
} elseif ($operator instanceof ISearchComparison) { } elseif ($operator instanceof ISearchComparison) {
return $operator->getField() === 'tagname' || $operator->getField() === 'favorite'; return $operator->getField() === 'tagname' || $operator->getField() === 'favorite' || $operator->getField() === 'systemtag';
} }
return false; return false;
} }
@ -162,8 +162,12 @@ class QuerySearchHelper {
} elseif ($field === 'favorite') { } elseif ($field === 'favorite') {
$field = 'tag.category'; $field = 'tag.category';
$value = self::TAG_FAVORITE; $value = self::TAG_FAVORITE;
} elseif ($field === 'name') {
$field = 'file.name';
} elseif ($field === 'tagname') { } elseif ($field === 'tagname') {
$field = 'tag.category'; $field = 'tag.category';
} elseif ($field === 'systemtag') {
$field = 'systemtag.name';
} elseif ($field === 'fileid') { } elseif ($field === 'fileid') {
$field = 'file.fileid'; $field = 'file.fileid';
} elseif ($field === 'path' && $type === ISearchComparison::COMPARE_EQUAL) { } elseif ($field === 'path' && $type === ISearchComparison::COMPARE_EQUAL) {
@ -181,6 +185,7 @@ class QuerySearchHelper {
'path' => 'string', 'path' => 'string',
'size' => 'integer', 'size' => 'integer',
'tagname' => 'string', 'tagname' => 'string',
'systemtag' => 'string',
'favorite' => 'boolean', 'favorite' => 'boolean',
'fileid' => 'integer' 'fileid' => 'integer'
]; ];
@ -191,6 +196,7 @@ class QuerySearchHelper {
'path' => ['eq', 'like'], 'path' => ['eq', 'like'],
'size' => ['eq', 'gt', 'lt', 'gte', 'lte'], 'size' => ['eq', 'gt', 'lt', 'gte', 'lte'],
'tagname' => ['eq', 'like'], 'tagname' => ['eq', 'like'],
'systemtag' => ['eq', 'like'],
'favorite' => ['eq'], 'favorite' => ['eq'],
'fileid' => ['eq'] 'fileid' => ['eq']
]; ];

View File

@ -79,7 +79,7 @@ class QuerySearchHelperTest extends TestCase {
$this->numericStorageId = 10000; $this->numericStorageId = 10000;
$this->builder->select(['fileid']) $this->builder->select(['fileid'])
->from('filecache') ->from('filecache', 'file') // alias needed for QuerySearchHelper#getOperatorFieldAndValue
->where($this->builder->expr()->eq('storage', new Literal($this->numericStorageId))); ->where($this->builder->expr()->eq('storage', new Literal($this->numericStorageId)));
} }