diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/private/Files/Cache/Cache.php | 43 | ||||
-rw-r--r-- | lib/private/Files/Cache/FailedCache.php | 5 | ||||
-rw-r--r-- | lib/private/Files/Cache/QuerySearchHelper.php | 37 | ||||
-rw-r--r-- | lib/private/Files/Cache/Wrapper/CacheJail.php | 6 | ||||
-rw-r--r-- | lib/private/Files/Cache/Wrapper/CacheWrapper.php | 6 | ||||
-rw-r--r-- | lib/private/Files/Node/Folder.php | 9 | ||||
-rw-r--r-- | lib/private/Files/Search/SearchBinaryOperator.php | 37 | ||||
-rw-r--r-- | lib/private/Files/Search/SearchQuery.php | 57 | ||||
-rw-r--r-- | lib/private/Lockdown/Filesystem/NullCache.php | 5 | ||||
-rw-r--r-- | lib/public/Files/Cache/ICache.php | 12 | ||||
-rw-r--r-- | lib/public/Files/Folder.php | 3 | ||||
-rw-r--r-- | lib/public/Files/Search/ISearchBinaryOperator.php | 5 | ||||
-rw-r--r-- | lib/public/Files/Search/ISearchComparison.php | 3 | ||||
-rw-r--r-- | lib/public/Files/Search/ISearchOperator.php | 5 | ||||
-rw-r--r-- | lib/public/Files/Search/ISearchQuery.php | 24 |
15 files changed, 230 insertions, 27 deletions
diff --git a/lib/private/Files/Cache/Cache.php b/lib/private/Files/Cache/Cache.php index 7e7ebd795a0..b0527d801d6 100644 --- a/lib/private/Files/Cache/Cache.php +++ b/lib/private/Files/Cache/Cache.php @@ -36,9 +36,11 @@ namespace OC\Files\Cache; +use Doctrine\DBAL\Driver\Statement; use OCP\Files\Cache\ICache; use OCP\Files\Cache\ICacheEntry; use \OCP\Files\IMimeTypeLoader; +use OCP\Files\Search\ISearchQuery; use OCP\IDBConnection; /** @@ -79,6 +81,9 @@ class Cache implements ICache { */ protected $connection; + /** @var QuerySearchHelper */ + protected $querySearchHelper; + /** * @param \OC\Files\Storage\Storage|string $storage */ @@ -95,6 +100,7 @@ class Cache implements ICache { $this->storageCache = new Storage($storage); $this->mimetypeLoader = \OC::$server->getMimeTypeLoader(); $this->connection = \OC::$server->getDatabaseConnection(); + $this->querySearchHelper = new QuerySearchHelper($this->mimetypeLoader); } /** @@ -350,7 +356,7 @@ class Cache implements ICache { $queryParts[] = '`mtime`'; } } elseif ($name === 'encrypted') { - if(isset($data['encryptedVersion'])) { + if (isset($data['encryptedVersion'])) { $value = $data['encryptedVersion']; } else { // Boolean to integer conversion @@ -599,9 +605,17 @@ class Cache implements ICache { [$this->getNumericStorageId(), $pattern] ); + return $this->searchResultToCacheEntries($result); + } + + /** + * @param Statement $result + * @return CacheEntry[] + */ + private function searchResultToCacheEntries(Statement $result) { $files = $result->fetchAll(); - return array_map(function(array $data) { + return array_map(function (array $data) { return self::cacheEntryFromData($data, $this->mimetypeLoader); }, $files); } @@ -624,14 +638,29 @@ class Cache implements ICache { $mimetype = $this->mimetypeLoader->getId($mimetype); $result = $this->connection->executeQuery($sql, array($mimetype, $this->getNumericStorageId())); - $files = $result->fetchAll(); + return $this->searchResultToCacheEntries($result); + } - return array_map(function (array $data) { - return self::cacheEntryFromData($data, $this->mimetypeLoader); - }, $files); + public function searchQuery(ISearchQuery $searchQuery) { + $builder = \OC::$server->getDatabaseConnection()->getQueryBuilder(); + + $query = $builder->select(['fileid', 'storage', 'path', 'parent', 'name', 'mimetype', 'mimepart', 'size', 'mtime', 'storage_mtime', 'encrypted', 'etag', 'permissions', 'checksum']) + ->from('filecache') + ->where($builder->expr()->eq('storage', $builder->createNamedParameter($this->getNumericStorageId()))) + ->andWhere($this->querySearchHelper->searchOperatorToDBExpr($builder, $searchQuery->getSearchOperation())); + + if ($searchQuery->getLimit()) { + $query->setMaxResults($searchQuery->getLimit()); + } + if ($searchQuery->getOffset()) { + $query->setFirstResult($searchQuery->getOffset()); + } + + $result = $query->execute(); + return $this->searchResultToCacheEntries($result); } - /** + /** * Search for files by tag of a given users. * * Note that every user can tag files differently. diff --git a/lib/private/Files/Cache/FailedCache.php b/lib/private/Files/Cache/FailedCache.php index 3a0424b5e26..932a5e5181a 100644 --- a/lib/private/Files/Cache/FailedCache.php +++ b/lib/private/Files/Cache/FailedCache.php @@ -24,6 +24,7 @@ namespace OC\Files\Cache; use OCP\Constants; use OCP\Files\Cache\ICache; +use OCP\Files\Search\ISearchQuery; /** * Storage placeholder to represent a missing precondition, storage unavailable @@ -125,6 +126,10 @@ class FailedCache implements ICache { return []; } + public function searchQuery(ISearchQuery $query) { + return []; + } + public function getAll() { return []; } diff --git a/lib/private/Files/Cache/QuerySearchHelper.php b/lib/private/Files/Cache/QuerySearchHelper.php index 60f4e484da5..931f258ec5b 100644 --- a/lib/private/Files/Cache/QuerySearchHelper.php +++ b/lib/private/Files/Cache/QuerySearchHelper.php @@ -30,7 +30,7 @@ use OCP\Files\Search\ISearchOperator; /** * Tools for transforming search queries into database queries */ -class QuerySearchUtil { +class QuerySearchHelper { static protected $searchOperatorMap = [ ISearchComparison::COMPARE_LIKE => 'iLike', ISearchComparison::COMPARE_EQUAL => 'eq', @@ -73,9 +73,9 @@ class QuerySearchUtil { throw new \InvalidArgumentException('Binary operators inside "not" is not supported'); } case ISearchBinaryOperator::OPERATOR_AND: - return $expr->andX($this->searchOperatorToDBExpr($operator->getArguments()[0], $operator->getArguments()[1])); + return $expr->andX($this->searchOperatorToDBExpr($builder, $operator->getArguments()[0]), $this->searchOperatorToDBExpr($builder, $operator->getArguments()[1])); case ISearchBinaryOperator::OPERATOR_OR: - return $expr->orX($this->searchOperatorToDBExpr($operator->getArguments()[0], $operator->getArguments()[1])); + return $expr->orX($this->searchOperatorToDBExpr($builder, $operator->getArguments()[0]), $this->searchOperatorToDBExpr($builder, $operator->getArguments()[1])); default: throw new \InvalidArgumentException('Invalid operator type: ' . $operator->getType()); } @@ -87,13 +87,11 @@ class QuerySearchUtil { } private function searchComparisonToDBExpr(IQueryBuilder $builder, ISearchComparison $comparison, array $operatorMap) { - if (!$this->isValidComparison($comparison)) { - throw new \InvalidArgumentException('Invalid comparison ' . $operator->getType() . ' on field ' . $operator->getField()); - } + $this->validateComparison($comparison); - list($field, $value) = $this->getOperatorFieldAndValue($comparison); - if (isset($operatorMap[$comparison->getType()])) { - $queryOperator = $operatorMap[$comparison->getType()]; + list($field, $value, $type) = $this->getOperatorFieldAndValue($comparison); + if (isset($operatorMap[$type])) { + $queryOperator = $operatorMap[$type]; return $builder->expr()->$queryOperator($field, $this->getParameterForValue($builder, $value)); } else { throw new \InvalidArgumentException('Invalid operator type: ' . $comparison->getType()); @@ -103,6 +101,7 @@ class QuerySearchUtil { private function getOperatorFieldAndValue(ISearchComparison $operator) { $field = $operator->getField(); $value = $operator->getValue(); + $type = $operator->getType(); if ($field === 'mimetype') { if ($operator->getType() === ISearchComparison::COMPARE_EQUAL) { $value = $this->mimetypeLoader->getId($value); @@ -111,16 +110,20 @@ class QuerySearchUtil { if (preg_match('|(.+)/%|', $value, $matches)) { $field = 'mimepart'; $value = $this->mimetypeLoader->getId($matches[1]); + $type = ISearchComparison::COMPARE_EQUAL; + } + if (strpos($value, '%') !== false) { + throw new \InvalidArgumentException('Unsupported query value for mimetype: ' . $value . ', only values in the format "mime/type" or "mime/%" are supported'); } } } - return [$field, $value]; + return [$field, $value, $type]; } - private function isValidComparison(ISearchComparison $operator) { + private function validateComparison(ISearchComparison $operator) { $types = [ 'mimetype' => 'string', - 'mtime' => \DateTime::class, + 'mtime' => 'integer', 'name' => 'string', 'size' => 'integer' ]; @@ -132,13 +135,15 @@ class QuerySearchUtil { ]; if (!isset($types[$operator->getField()])) { - return false; + throw new \InvalidArgumentException('Unsupported comparison field ' . $operator->getField()); } $type = $types[$operator->getField()]; - if (gettype($operator->getValue()) !== $type && !(is_a($operator->getValue(), $type))) { - return false; + if (gettype($operator->getValue()) !== $type) { + throw new \InvalidArgumentException('Invalid type for field ' . $operator->getField()); + } + if (!in_array($operator->getType(), $comparisons[$operator->getField()])) { + throw new \InvalidArgumentException('Unsupported comparison for field ' . $operator->getField() . ': ' . $operator->getType()); } - return in_array($operator->getType(), $comparisons[$operator->getField()]); } private function getParameterForValue(IQueryBuilder $builder, $value) { diff --git a/lib/private/Files/Cache/Wrapper/CacheJail.php b/lib/private/Files/Cache/Wrapper/CacheJail.php index 894fbcc803d..ebab20fbaed 100644 --- a/lib/private/Files/Cache/Wrapper/CacheJail.php +++ b/lib/private/Files/Cache/Wrapper/CacheJail.php @@ -28,6 +28,7 @@ namespace OC\Files\Cache\Wrapper; use OC\Files\Cache\Cache; use OCP\Files\Cache\ICacheEntry; +use OCP\Files\Search\ISearchQuery; /** * Jail to a subdirectory of the wrapped cache @@ -218,6 +219,11 @@ class CacheJail extends CacheWrapper { return $this->formatSearchResults($results); } + public function searchQuery(ISearchQuery $query) { + $results = $this->getCache()->searchQuery($query); + return $this->formatSearchResults($results); + } + /** * search for files by mimetype * diff --git a/lib/private/Files/Cache/Wrapper/CacheWrapper.php b/lib/private/Files/Cache/Wrapper/CacheWrapper.php index 83fe7e5f43e..1463d1467b8 100644 --- a/lib/private/Files/Cache/Wrapper/CacheWrapper.php +++ b/lib/private/Files/Cache/Wrapper/CacheWrapper.php @@ -31,6 +31,7 @@ namespace OC\Files\Cache\Wrapper; use OC\Files\Cache\Cache; use OCP\Files\Cache\ICacheEntry; use OCP\Files\Cache\ICache; +use OCP\Files\Search\ISearchQuery; class CacheWrapper extends Cache { /** @@ -229,6 +230,11 @@ class CacheWrapper extends Cache { return array_map(array($this, 'formatCacheEntry'), $results); } + public function searchQuery(ISearchQuery $query) { + $results = $this->getCache()->searchQuery($query); + return array_map(array($this, 'formatCacheEntry'), $results); + } + /** * search for files by tag * diff --git a/lib/private/Files/Node/Folder.php b/lib/private/Files/Node/Folder.php index fd907f708f3..45372d0fedf 100644 --- a/lib/private/Files/Node/Folder.php +++ b/lib/private/Files/Node/Folder.php @@ -33,6 +33,7 @@ use OCP\Files\FileInfo; use OCP\Files\Mount\IMountPoint; use OCP\Files\NotFoundException; use OCP\Files\NotPermittedException; +use OCP\Files\Search\ISearchOperator; class Folder extends Node implements \OCP\Files\Folder { /** @@ -190,11 +191,15 @@ class Folder extends Node implements \OCP\Files\Folder { /** * search for files with the name matching $query * - * @param string $query + * @param string|ISearchOperator $query * @return \OC\Files\Node\Node[] */ public function search($query) { - return $this->searchCommon('search', array('%' . $query . '%')); + if (is_string($query)) { + return $this->searchCommon('search', array('%' . $query . '%')); + } else { + return $this->searchCommon('searchQuery', array($query)); + } } /** diff --git a/lib/private/Files/Search/SearchBinaryOperator.php b/lib/private/Files/Search/SearchBinaryOperator.php index 15944e27768..c9466d8b9ea 100644 --- a/lib/private/Files/Search/SearchBinaryOperator.php +++ b/lib/private/Files/Search/SearchBinaryOperator.php @@ -18,3 +18,40 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ + +namespace OC\Files\Search; + +use OCP\Files\Search\ISearchBinaryOperator; +use OCP\Files\Search\ISearchOperator; + +class SearchBinaryOperator implements ISearchBinaryOperator { + /** @var string */ + private $type; + /** @var ISearchOperator[] */ + private $arguments; + + /** + * SearchBinaryOperator constructor. + * + * @param string $type + * @param ISearchOperator[] $arguments + */ + public function __construct($type, array $arguments) { + $this->type = $type; + $this->arguments = $arguments; + } + + /** + * @return string + */ + public function getType() { + return $this->type; + } + + /** + * @return ISearchOperator[] + */ + public function getArguments() { + return $this->arguments; + } +} diff --git a/lib/private/Files/Search/SearchQuery.php b/lib/private/Files/Search/SearchQuery.php index a017d3e245b..8a0478ae98e 100644 --- a/lib/private/Files/Search/SearchQuery.php +++ b/lib/private/Files/Search/SearchQuery.php @@ -21,3 +21,60 @@ namespace OC\Files\Search; +use OCP\Files\Search\ISearchOperator; +use OCP\Files\Search\ISearchOrder; +use OCP\Files\Search\ISearchQuery; + +class SearchQuery implements ISearchQuery { + /** @var ISearchOperator */ + private $searchOperation; + /** @var integer */ + private $limit; + /** @var integer */ + private $offset; + /** @var ISearchOrder[] */ + private $order; + + /** + * SearchQuery constructor. + * + * @param ISearchOperator $searchOperation + * @param int $limit + * @param int $offset + * @param array $order + */ + public function __construct(ISearchOperator $searchOperation, $limit, $offset, array $order) { + $this->searchOperation = $searchOperation; + $this->limit = $limit; + $this->offset = $offset; + $this->order = $order; + } + + /** + * @return ISearchOperator + */ + public function getSearchOperation() { + return $this->searchOperation; + } + + /** + * @return int + */ + public function getLimit() { + return $this->limit; + } + + /** + * @return int + */ + public function getOffset() { + return $this->offset; + } + + /** + * @return ISearchOrder[] + */ + public function getOrder() { + return $this->order; + } +} diff --git a/lib/private/Lockdown/Filesystem/NullCache.php b/lib/private/Lockdown/Filesystem/NullCache.php index 8c6b5258aa8..9cb8016194b 100644 --- a/lib/private/Lockdown/Filesystem/NullCache.php +++ b/lib/private/Lockdown/Filesystem/NullCache.php @@ -24,6 +24,7 @@ use OCP\Constants; use OCP\Files\Cache\ICache; use OCP\Files\Cache\ICacheEntry; use OCP\Files\FileInfo; +use OCP\Files\Search\ISearchQuery; class NullCache implements ICache { public function getNumericStorageId() { @@ -103,6 +104,10 @@ class NullCache implements ICache { return []; } + public function searchQuery(ISearchQuery $query) { + return []; + } + public function searchByTag($tag, $userId) { return []; } diff --git a/lib/public/Files/Cache/ICache.php b/lib/public/Files/Cache/ICache.php index 7d01b1a2908..63993d0a8cb 100644 --- a/lib/public/Files/Cache/ICache.php +++ b/lib/public/Files/Cache/ICache.php @@ -21,6 +21,8 @@ */ namespace OCP\Files\Cache; +use OCP\Files\Search\ISearchOperator; +use OCP\Files\Search\ISearchQuery; /** * Metadata cache for a storage @@ -213,6 +215,16 @@ interface ICache { public function searchByMime($mimetype); /** + * Search for files with a flexible query + * + * @param ISearchQuery $query + * @return ICacheEntry[] + * @throw \InvalidArgumentException if the cache is unable to perform the query + * @since 12.0.0 + */ + public function searchQuery(ISearchQuery $query); + + /** * Search for files by tag of a given users. * * Note that every user can tag files differently. diff --git a/lib/public/Files/Folder.php b/lib/public/Files/Folder.php index 8f8576d8503..52a4b303196 100644 --- a/lib/public/Files/Folder.php +++ b/lib/public/Files/Folder.php @@ -30,6 +30,7 @@ // use OCP namespace for all classes that are considered public. // This means that they should be used by apps instead of the internal ownCloud classes namespace OCP\Files; +use OCP\Files\Search\ISearchQuery; /** * @since 6.0.0 @@ -115,7 +116,7 @@ interface Folder extends Node { /** * search for files with the name matching $query * - * @param string $query + * @param string|ISearchQuery $query * @return \OCP\Files\Node[] * @since 6.0.0 */ diff --git a/lib/public/Files/Search/ISearchBinaryOperator.php b/lib/public/Files/Search/ISearchBinaryOperator.php index 248e3de56b8..d5a2d5dc02d 100644 --- a/lib/public/Files/Search/ISearchBinaryOperator.php +++ b/lib/public/Files/Search/ISearchBinaryOperator.php @@ -21,6 +21,9 @@ namespace OCP\Files\Search; +/** + * @since 12.0.0 + */ interface ISearchBinaryOperator extends ISearchOperator { const OPERATOR_AND = 'and'; const OPERATOR_OR = 'or'; @@ -32,6 +35,7 @@ interface ISearchBinaryOperator extends ISearchOperator { * One of the ISearchBinaryOperator::OPERATOR_* constants * * @return string + * @since 12.0.0 */ public function getType(); @@ -41,6 +45,7 @@ interface ISearchBinaryOperator extends ISearchOperator { * One argument for the 'not' operator and two for 'and' and 'or' * * @return ISearchOperator[] + * @since 12.0.0 */ public function getArguments(); } diff --git a/lib/public/Files/Search/ISearchComparison.php b/lib/public/Files/Search/ISearchComparison.php index 05342218616..e5175ee3117 100644 --- a/lib/public/Files/Search/ISearchComparison.php +++ b/lib/public/Files/Search/ISearchComparison.php @@ -33,6 +33,7 @@ interface ISearchComparison extends ISearchOperator { * Get the type of comparison, one of the ISearchComparison::COMPARE_* constants * * @return string + * @since 12.0.0 */ public function getType(); @@ -42,6 +43,7 @@ interface ISearchComparison extends ISearchOperator { * i.e. 'size', 'name' or 'mimetype' * * @return string + * @since 12.0.0 */ public function getField(); @@ -49,6 +51,7 @@ interface ISearchComparison extends ISearchOperator { * Get the value to compare the field with * * @return string|integer|\DateTime + * @since 12.0.0 */ public function getValue(); } diff --git a/lib/public/Files/Search/ISearchOperator.php b/lib/public/Files/Search/ISearchOperator.php index fc1db57f4ca..047792bc782 100644 --- a/lib/public/Files/Search/ISearchOperator.php +++ b/lib/public/Files/Search/ISearchOperator.php @@ -21,6 +21,9 @@ namespace OCP\Files\Search; -interface ISearchCondition { +/** + * @since 12.0.0 + */ +interface ISearchOperator { } diff --git a/lib/public/Files/Search/ISearchQuery.php b/lib/public/Files/Search/ISearchQuery.php index f9c07533a1e..5a701b321b1 100644 --- a/lib/public/Files/Search/ISearchQuery.php +++ b/lib/public/Files/Search/ISearchQuery.php @@ -30,4 +30,28 @@ interface ISearchQuery { * @since 12.0.0 */ public function getSearchOperation(); + + /** + * Get the maximum number of results to return + * + * @return integer + * @since 12.0.0 + */ + public function getLimit(); + + /** + * Get the offset for returned results + * + * @return integer + * @since 12.0.0 + */ + public function getOffset(); + + /** + * The fields and directions to order by + * + * @return ISearchOrder[] + * @since 12.0.0 + */ + public function getOrder(); } |