diff options
author | Robin Appelman <robin@icewind.nl> | 2017-03-08 13:09:19 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-03-08 13:09:19 +0100 |
commit | 2a8e922d67a1246e101f926f1b0ab287db71929e (patch) | |
tree | c3f67150e3e03386eedc6a23b1c2dcf657e4459b /lib | |
parent | 74ac5dffbd07f9a7ac9a248eeafaa0f2852b5f79 (diff) | |
parent | a3e638709b4702156a3ddc0791de1d6ce9fb902e (diff) | |
download | nextcloud-server-2a8e922d67a1246e101f926f1b0ab287db71929e.tar.gz nextcloud-server-2a8e922d67a1246e101f926f1b0ab287db71929e.zip |
Merge pull request #3360 from nextcloud/dav-search
Implement webdav SEARCH
Diffstat (limited to 'lib')
20 files changed, 763 insertions, 10 deletions
diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index a4850fb4b38..c87bcce194f 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -141,6 +141,11 @@ return array( 'OCP\\Files\\Notify\\IRenameChange' => $baseDir . '/lib/public/Files/Notify/IRenameChange.php', 'OCP\\Files\\ObjectStore\\IObjectStore' => $baseDir . '/lib/public/Files/ObjectStore/IObjectStore.php', 'OCP\\Files\\ReservedWordException' => $baseDir . '/lib/public/Files/ReservedWordException.php', + 'OCP\\Files\\Search\\ISearchBinaryOperator' => $baseDir . '/lib/public/Files/Search/ISearchBinaryOperator.php', + 'OCP\\Files\\Search\\ISearchComparison' => $baseDir . '/lib/public/Files/Search/ISearchComparison.php', + 'OCP\\Files\\Search\\ISearchOperator' => $baseDir . '/lib/public/Files/Search/ISearchOperator.php', + 'OCP\\Files\\Search\\ISearchOrder' => $baseDir . '/lib/public/Files/Search/ISearchOrder.php', + 'OCP\\Files\\Search\\ISearchQuery' => $baseDir . '/lib/public/Files/Search/ISearchQuery.php', 'OCP\\Files\\SimpleFS\\ISimpleFile' => $baseDir . '/lib/public/Files/SimpleFS/ISimpleFile.php', 'OCP\\Files\\SimpleFS\\ISimpleFolder' => $baseDir . '/lib/public/Files/SimpleFS/ISimpleFolder.php', 'OCP\\Files\\SimpleFS\\ISimpleRoot' => $baseDir . '/lib/public/Files/SimpleFS/ISimpleRoot.php', @@ -509,6 +514,7 @@ return array( 'OC\\Files\\Cache\\HomePropagator' => $baseDir . '/lib/private/Files/Cache/HomePropagator.php', 'OC\\Files\\Cache\\MoveFromCacheTrait' => $baseDir . '/lib/private/Files/Cache/MoveFromCacheTrait.php', 'OC\\Files\\Cache\\Propagator' => $baseDir . '/lib/private/Files/Cache/Propagator.php', + 'OC\\Files\\Cache\\QuerySearchHelper' => $baseDir . '/lib/private/Files/Cache/QuerySearchHelper.php', 'OC\\Files\\Cache\\Scanner' => $baseDir . '/lib/private/Files/Cache/Scanner.php', 'OC\\Files\\Cache\\Storage' => $baseDir . '/lib/private/Files/Cache/Storage.php', 'OC\\Files\\Cache\\StorageGlobal' => $baseDir . '/lib/private/Files/Cache/StorageGlobal.php', @@ -548,6 +554,10 @@ return array( 'OC\\Files\\ObjectStore\\S3ConnectionTrait' => $baseDir . '/lib/private/Files/ObjectStore/S3ConnectionTrait.php', 'OC\\Files\\ObjectStore\\StorageObjectStore' => $baseDir . '/lib/private/Files/ObjectStore/StorageObjectStore.php', 'OC\\Files\\ObjectStore\\Swift' => $baseDir . '/lib/private/Files/ObjectStore/Swift.php', + 'OC\\Files\\Search\\SearchBinaryOperator' => $baseDir . '/lib/private/Files/Search/SearchBinaryOperator.php', + 'OC\\Files\\Search\\SearchComparison' => $baseDir . '/lib/private/Files/Search/SearchComparison.php', + 'OC\\Files\\Search\\SearchOrder' => $baseDir . '/lib/private/Files/Search/SearchOrder.php', + 'OC\\Files\\Search\\SearchQuery' => $baseDir . '/lib/private/Files/Search/SearchQuery.php', 'OC\\Files\\SimpleFS\\SimpleFile' => $baseDir . '/lib/private/Files/SimpleFS/SimpleFile.php', 'OC\\Files\\SimpleFS\\SimpleFolder' => $baseDir . '/lib/private/Files/SimpleFS/SimpleFolder.php', 'OC\\Files\\Storage\\Common' => $baseDir . '/lib/private/Files/Storage/Common.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index 654161214b2..eb7188b69b3 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -171,6 +171,11 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OCP\\Files\\Notify\\IRenameChange' => __DIR__ . '/../../..' . '/lib/public/Files/Notify/IRenameChange.php', 'OCP\\Files\\ObjectStore\\IObjectStore' => __DIR__ . '/../../..' . '/lib/public/Files/ObjectStore/IObjectStore.php', 'OCP\\Files\\ReservedWordException' => __DIR__ . '/../../..' . '/lib/public/Files/ReservedWordException.php', + 'OCP\\Files\\Search\\ISearchBinaryOperator' => __DIR__ . '/../../..' . '/lib/public/Files/Search/ISearchBinaryOperator.php', + 'OCP\\Files\\Search\\ISearchComparison' => __DIR__ . '/../../..' . '/lib/public/Files/Search/ISearchComparison.php', + 'OCP\\Files\\Search\\ISearchOperator' => __DIR__ . '/../../..' . '/lib/public/Files/Search/ISearchOperator.php', + 'OCP\\Files\\Search\\ISearchOrder' => __DIR__ . '/../../..' . '/lib/public/Files/Search/ISearchOrder.php', + 'OCP\\Files\\Search\\ISearchQuery' => __DIR__ . '/../../..' . '/lib/public/Files/Search/ISearchQuery.php', 'OCP\\Files\\SimpleFS\\ISimpleFile' => __DIR__ . '/../../..' . '/lib/public/Files/SimpleFS/ISimpleFile.php', 'OCP\\Files\\SimpleFS\\ISimpleFolder' => __DIR__ . '/../../..' . '/lib/public/Files/SimpleFS/ISimpleFolder.php', 'OCP\\Files\\SimpleFS\\ISimpleRoot' => __DIR__ . '/../../..' . '/lib/public/Files/SimpleFS/ISimpleRoot.php', @@ -539,6 +544,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OC\\Files\\Cache\\HomePropagator' => __DIR__ . '/../../..' . '/lib/private/Files/Cache/HomePropagator.php', 'OC\\Files\\Cache\\MoveFromCacheTrait' => __DIR__ . '/../../..' . '/lib/private/Files/Cache/MoveFromCacheTrait.php', 'OC\\Files\\Cache\\Propagator' => __DIR__ . '/../../..' . '/lib/private/Files/Cache/Propagator.php', + 'OC\\Files\\Cache\\QuerySearchHelper' => __DIR__ . '/../../..' . '/lib/private/Files/Cache/QuerySearchHelper.php', 'OC\\Files\\Cache\\Scanner' => __DIR__ . '/../../..' . '/lib/private/Files/Cache/Scanner.php', 'OC\\Files\\Cache\\Storage' => __DIR__ . '/../../..' . '/lib/private/Files/Cache/Storage.php', 'OC\\Files\\Cache\\StorageGlobal' => __DIR__ . '/../../..' . '/lib/private/Files/Cache/StorageGlobal.php', @@ -578,6 +584,10 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OC\\Files\\ObjectStore\\S3ConnectionTrait' => __DIR__ . '/../../..' . '/lib/private/Files/ObjectStore/S3ConnectionTrait.php', 'OC\\Files\\ObjectStore\\StorageObjectStore' => __DIR__ . '/../../..' . '/lib/private/Files/ObjectStore/StorageObjectStore.php', 'OC\\Files\\ObjectStore\\Swift' => __DIR__ . '/../../..' . '/lib/private/Files/ObjectStore/Swift.php', + 'OC\\Files\\Search\\SearchBinaryOperator' => __DIR__ . '/../../..' . '/lib/private/Files/Search/SearchBinaryOperator.php', + 'OC\\Files\\Search\\SearchComparison' => __DIR__ . '/../../..' . '/lib/private/Files/Search/SearchComparison.php', + 'OC\\Files\\Search\\SearchOrder' => __DIR__ . '/../../..' . '/lib/private/Files/Search/SearchOrder.php', + 'OC\\Files\\Search\\SearchQuery' => __DIR__ . '/../../..' . '/lib/private/Files/Search/SearchQuery.php', 'OC\\Files\\SimpleFS\\SimpleFile' => __DIR__ . '/../../..' . '/lib/private/Files/SimpleFS/SimpleFile.php', 'OC\\Files\\SimpleFS\\SimpleFolder' => __DIR__ . '/../../..' . '/lib/private/Files/SimpleFS/SimpleFolder.php', 'OC\\Files\\Storage\\Common' => __DIR__ . '/../../..' . '/lib/private/Files/Storage/Common.php', 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 new file mode 100644 index 00000000000..931f258ec5b --- /dev/null +++ b/lib/private/Files/Cache/QuerySearchHelper.php @@ -0,0 +1,160 @@ +<?php +/** + * @copyright Copyright (c) 2017 Robin Appelman <robin@icewind.nl> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OC\Files\Cache; + +use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\Files\IMimeTypeLoader; +use OCP\Files\Search\ISearchBinaryOperator; +use OCP\Files\Search\ISearchComparison; +use OCP\Files\Search\ISearchOperator; + +/** + * Tools for transforming search queries into database queries + */ +class QuerySearchHelper { + static protected $searchOperatorMap = [ + ISearchComparison::COMPARE_LIKE => 'iLike', + ISearchComparison::COMPARE_EQUAL => 'eq', + ISearchComparison::COMPARE_GREATER_THAN => 'gt', + ISearchComparison::COMPARE_GREATER_THAN_EQUAL => 'gte', + ISearchComparison::COMPARE_LESS_THAN => 'lt', + ISearchComparison::COMPARE_LESS_THAN_EQUAL => 'lte' + ]; + + static protected $searchOperatorNegativeMap = [ + ISearchComparison::COMPARE_LIKE => 'notLike', + ISearchComparison::COMPARE_EQUAL => 'neq', + ISearchComparison::COMPARE_GREATER_THAN => 'lte', + ISearchComparison::COMPARE_GREATER_THAN_EQUAL => 'lt', + ISearchComparison::COMPARE_LESS_THAN => 'gte', + ISearchComparison::COMPARE_LESS_THAN_EQUAL => 'lt' + ]; + + /** @var IMimeTypeLoader */ + private $mimetypeLoader; + + /** + * QuerySearchUtil constructor. + * + * @param IMimeTypeLoader $mimetypeLoader + */ + public function __construct(IMimeTypeLoader $mimetypeLoader) { + $this->mimetypeLoader = $mimetypeLoader; + } + + public function searchOperatorToDBExpr(IQueryBuilder $builder, ISearchOperator $operator) { + $expr = $builder->expr(); + if ($operator instanceof ISearchBinaryOperator) { + switch ($operator->getType()) { + case ISearchBinaryOperator::OPERATOR_NOT: + $negativeOperator = $operator->getArguments()[0]; + if ($negativeOperator instanceof ISearchComparison) { + return $this->searchComparisonToDBExpr($builder, $negativeOperator, self::$searchOperatorNegativeMap); + } else { + throw new \InvalidArgumentException('Binary operators inside "not" is not supported'); + } + case ISearchBinaryOperator::OPERATOR_AND: + return $expr->andX($this->searchOperatorToDBExpr($builder, $operator->getArguments()[0]), $this->searchOperatorToDBExpr($builder, $operator->getArguments()[1])); + case ISearchBinaryOperator::OPERATOR_OR: + return $expr->orX($this->searchOperatorToDBExpr($builder, $operator->getArguments()[0]), $this->searchOperatorToDBExpr($builder, $operator->getArguments()[1])); + default: + throw new \InvalidArgumentException('Invalid operator type: ' . $operator->getType()); + } + } else if ($operator instanceof ISearchComparison) { + return $this->searchComparisonToDBExpr($builder, $operator, self::$searchOperatorMap); + } else { + throw new \InvalidArgumentException('Invalid operator type: ' . get_class($operator)); + } + } + + private function searchComparisonToDBExpr(IQueryBuilder $builder, ISearchComparison $comparison, array $operatorMap) { + $this->validateComparison($comparison); + + 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()); + } + } + + 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); + } else if ($operator->getType() === ISearchComparison::COMPARE_LIKE) { + // transform "mimetype='foo/%'" to "mimepart='foo'" + 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, $type]; + } + + private function validateComparison(ISearchComparison $operator) { + $types = [ + 'mimetype' => 'string', + 'mtime' => 'integer', + 'name' => 'string', + 'size' => 'integer' + ]; + $comparisons = [ + 'mimetype' => ['eq', 'like'], + 'mtime' => ['eq', 'gt', 'lt', 'gte', 'lte'], + 'name' => ['eq', 'like'], + 'size' => ['eq', 'gt', 'lt', 'gte', 'lte'] + ]; + + if (!isset($types[$operator->getField()])) { + throw new \InvalidArgumentException('Unsupported comparison field ' . $operator->getField()); + } + $type = $types[$operator->getField()]; + 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()); + } + } + + private function getParameterForValue(IQueryBuilder $builder, $value) { + if ($value instanceof \DateTime) { + $value = $value->getTimestamp(); + } + if (is_numeric($value)) { + $type = IQueryBuilder::PARAM_INT; + } else { + $type = IQueryBuilder::PARAM_STR; + } + return $builder->createNamedParameter($value, $type); + } +} 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 new file mode 100644 index 00000000000..c9466d8b9ea --- /dev/null +++ b/lib/private/Files/Search/SearchBinaryOperator.php @@ -0,0 +1,57 @@ +<?php +/** + * @copyright Copyright (c) 2017 Robin Appelman <robin@icewind.nl> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * 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/SearchComparison.php b/lib/private/Files/Search/SearchComparison.php new file mode 100644 index 00000000000..32c4ad0e5aa --- /dev/null +++ b/lib/private/Files/Search/SearchComparison.php @@ -0,0 +1,67 @@ +<?php +/** + * @copyright Copyright (c) 2017 Robin Appelman <robin@icewind.nl> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OC\Files\Search; + +use OCP\Files\Search\ISearchComparison; + +class SearchComparison implements ISearchComparison { + /** @var string */ + private $type; + /** @var string */ + private $field; + /** @var string|integer|\DateTime */ + private $value; + + /** + * SearchComparison constructor. + * + * @param string $type + * @param string $field + * @param \DateTime|int|string $value + */ + public function __construct($type, $field, $value) { + $this->type = $type; + $this->field = $field; + $this->value = $value; + } + + /** + * @return string + */ + public function getType() { + return $this->type; + } + + /** + * @return string + */ + public function getField() { + return $this->field; + } + + /** + * @return \DateTime|int|string + */ + public function getValue() { + return $this->value; + } +} diff --git a/lib/private/Files/Search/SearchOrder.php b/lib/private/Files/Search/SearchOrder.php new file mode 100644 index 00000000000..c76d6f2e25e --- /dev/null +++ b/lib/private/Files/Search/SearchOrder.php @@ -0,0 +1,57 @@ +<?php +/** + * @copyright Copyright (c) 2017 Robin Appelman <robin@icewind.nl> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OC\Files\Search; + + +use OCP\Files\Search\ISearchOrder; + +class SearchOrder implements ISearchOrder { + /** @var string */ + private $direction; + /** @var string */ + private $field; + + /** + * SearchOrder constructor. + * + * @param string $direction + * @param string $field + */ + public function __construct($direction, $field) { + $this->direction = $direction; + $this->field = $field; + } + + /** + * @return string + */ + public function getDirection() { + return $this->direction; + } + + /** + * @return string + */ + public function getField() { + return $this->field; + } +} diff --git a/lib/private/Files/Search/SearchQuery.php b/lib/private/Files/Search/SearchQuery.php new file mode 100644 index 00000000000..8a0478ae98e --- /dev/null +++ b/lib/private/Files/Search/SearchQuery.php @@ -0,0 +1,80 @@ +<?php +/** + * @copyright Copyright (c) 2017 Robin Appelman <robin@icewind.nl> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +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 new file mode 100644 index 00000000000..d5a2d5dc02d --- /dev/null +++ b/lib/public/Files/Search/ISearchBinaryOperator.php @@ -0,0 +1,51 @@ +<?php +/** + * @copyright Copyright (c) 2017 Robin Appelman <robin@icewind.nl> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCP\Files\Search; + +/** + * @since 12.0.0 + */ +interface ISearchBinaryOperator extends ISearchOperator { + const OPERATOR_AND = 'and'; + const OPERATOR_OR = 'or'; + const OPERATOR_NOT = 'not'; + + /** + * The type of binary operator + * + * One of the ISearchBinaryOperator::OPERATOR_* constants + * + * @return string + * @since 12.0.0 + */ + public function getType(); + + /** + * The arguments for the binary operator + * + * 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 new file mode 100644 index 00000000000..5468260f001 --- /dev/null +++ b/lib/public/Files/Search/ISearchComparison.php @@ -0,0 +1,60 @@ +<?php +/** + * @copyright Copyright (c) 2017 Robin Appelman <robin@icewind.nl> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCP\Files\Search; + +/** + * @since 12.0.0 + */ +interface ISearchComparison extends ISearchOperator { + const COMPARE_EQUAL = 'eq'; + const COMPARE_GREATER_THAN = 'gt'; + const COMPARE_GREATER_THAN_EQUAL = 'gte'; + const COMPARE_LESS_THAN = 'lt'; + const COMPARE_LESS_THAN_EQUAL = 'lte'; + const COMPARE_LIKE = 'like'; + + /** + * Get the type of comparison, one of the ISearchComparison::COMPARE_* constants + * + * @return string + * @since 12.0.0 + */ + public function getType(); + + /** + * Get the name of the field to compare with + * + * i.e. 'size', 'name' or 'mimetype' + * + * @return string + * @since 12.0.0 + */ + public function getField(); + + /** + * 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 new file mode 100644 index 00000000000..047792bc782 --- /dev/null +++ b/lib/public/Files/Search/ISearchOperator.php @@ -0,0 +1,29 @@ +<?php +/** + * @copyright Copyright (c) 2017 Robin Appelman <robin@icewind.nl> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCP\Files\Search; + +/** + * @since 12.0.0 + */ +interface ISearchOperator { + +} diff --git a/lib/public/Files/Search/ISearchOrder.php b/lib/public/Files/Search/ISearchOrder.php new file mode 100644 index 00000000000..1abfd7506d5 --- /dev/null +++ b/lib/public/Files/Search/ISearchOrder.php @@ -0,0 +1,46 @@ +<?php +/** + * @copyright Copyright (c) 2017 Robin Appelman <robin@icewind.nl> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCP\Files\Search; + +/** + * @since 12.0.0 + */ +interface ISearchOrder { + const DIRECTION_ASCENDING = 'asc'; + const DIRECTION_DESCENDING = 'desc'; + + /** + * The direction to sort in, either ISearchOrder::DIRECTION_ASCENDING or ISearchOrder::DIRECTION_DESCENDING + * + * @return string + * @since 12.0.0 + */ + public function getDirection(); + + /** + * The field to sort on + * + * @return string + * @since 12.0.0 + */ + public function getField(); +} diff --git a/lib/public/Files/Search/ISearchQuery.php b/lib/public/Files/Search/ISearchQuery.php new file mode 100644 index 00000000000..5a701b321b1 --- /dev/null +++ b/lib/public/Files/Search/ISearchQuery.php @@ -0,0 +1,57 @@ +<?php +/** + * @copyright Copyright (c) 2017 Robin Appelman <robin@icewind.nl> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCP\Files\Search; + +/** + * @since 12.0.0 + */ +interface ISearchQuery { + /** + * @return ISearchOperator + * @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(); +} |