|
|
|
@ -40,7 +40,8 @@ |
|
|
|
namespace OC\Files\Cache; |
|
|
|
|
|
|
|
use Doctrine\DBAL\Exception\UniqueConstraintViolationException; |
|
|
|
use OCP\DB\IResult; |
|
|
|
use OC\Files\Search\SearchComparison; |
|
|
|
use OC\Files\Search\SearchQuery; |
|
|
|
use OCP\DB\QueryBuilder\IQueryBuilder; |
|
|
|
use OCP\EventDispatcher\IEventDispatcher; |
|
|
|
use OCP\Files\Cache\CacheEntryInsertedEvent; |
|
|
|
@ -52,6 +53,7 @@ use OCP\Files\Cache\ICache; |
|
|
|
use OCP\Files\Cache\ICacheEntry; |
|
|
|
use OCP\Files\FileInfo; |
|
|
|
use OCP\Files\IMimeTypeLoader; |
|
|
|
use OCP\Files\Search\ISearchComparison; |
|
|
|
use OCP\Files\Search\ISearchQuery; |
|
|
|
use OCP\Files\Storage\IStorage; |
|
|
|
use OCP\IDBConnection; |
|
|
|
@ -118,15 +120,19 @@ class Cache implements ICache { |
|
|
|
$this->mimetypeLoader = \OC::$server->getMimeTypeLoader(); |
|
|
|
$this->connection = \OC::$server->getDatabaseConnection(); |
|
|
|
$this->eventDispatcher = \OC::$server->get(IEventDispatcher::class); |
|
|
|
$this->querySearchHelper = new QuerySearchHelper($this->mimetypeLoader); |
|
|
|
$this->querySearchHelper = new QuerySearchHelper( |
|
|
|
$this->mimetypeLoader, |
|
|
|
$this->connection, |
|
|
|
\OC::$server->getSystemConfig(), |
|
|
|
\OC::$server->getLogger() |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
protected function getQueryBuilder() { |
|
|
|
return new CacheQueryBuilder( |
|
|
|
$this->connection, |
|
|
|
\OC::$server->getSystemConfig(), |
|
|
|
\OC::$server->getLogger(), |
|
|
|
$this |
|
|
|
\OC::$server->getLogger() |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
@ -153,7 +159,7 @@ class Cache implements ICache { |
|
|
|
// normalize file
|
|
|
|
$file = $this->normalize($file); |
|
|
|
|
|
|
|
$query->whereStorageId() |
|
|
|
$query->whereStorageId($this->getNumericStorageId()) |
|
|
|
->wherePath($file); |
|
|
|
} else { //file id
|
|
|
|
$query->whereFileId($file); |
|
|
|
@ -482,7 +488,7 @@ class Cache implements ICache { |
|
|
|
$query = $this->getQueryBuilder(); |
|
|
|
$query->select('fileid') |
|
|
|
->from('filecache') |
|
|
|
->whereStorageId() |
|
|
|
->whereStorageId($this->getNumericStorageId()) |
|
|
|
->wherePath($file); |
|
|
|
|
|
|
|
$result = $query->execute(); |
|
|
|
@ -718,7 +724,7 @@ class Cache implements ICache { |
|
|
|
public function clear() { |
|
|
|
$query = $this->getQueryBuilder(); |
|
|
|
$query->delete('filecache') |
|
|
|
->whereStorageId(); |
|
|
|
->whereStorageId($this->getNumericStorageId()); |
|
|
|
$query->execute(); |
|
|
|
|
|
|
|
$query = $this->connection->getQueryBuilder(); |
|
|
|
@ -746,7 +752,7 @@ class Cache implements ICache { |
|
|
|
$query = $this->getQueryBuilder(); |
|
|
|
$query->select('size') |
|
|
|
->from('filecache') |
|
|
|
->whereStorageId() |
|
|
|
->whereStorageId($this->getNumericStorageId()) |
|
|
|
->wherePath($file); |
|
|
|
|
|
|
|
$result = $query->execute(); |
|
|
|
@ -775,37 +781,8 @@ class Cache implements ICache { |
|
|
|
* @return ICacheEntry[] an array of cache entries where the name matches the search pattern |
|
|
|
*/ |
|
|
|
public function search($pattern) { |
|
|
|
// normalize pattern
|
|
|
|
$pattern = $this->normalize($pattern); |
|
|
|
|
|
|
|
if ($pattern === '%%') { |
|
|
|
return []; |
|
|
|
} |
|
|
|
|
|
|
|
$query = $this->getQueryBuilder(); |
|
|
|
$query->selectFileCache() |
|
|
|
->whereStorageId() |
|
|
|
->andWhere($query->expr()->iLike('name', $query->createNamedParameter($pattern))); |
|
|
|
|
|
|
|
$result = $query->execute(); |
|
|
|
$files = $result->fetchAll(); |
|
|
|
$result->closeCursor(); |
|
|
|
|
|
|
|
return array_map(function (array $data) { |
|
|
|
return self::cacheEntryFromData($data, $this->mimetypeLoader); |
|
|
|
}, $files); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* @param IResult $result |
|
|
|
* @return CacheEntry[] |
|
|
|
*/ |
|
|
|
private function searchResultToCacheEntries(IResult $result): array { |
|
|
|
$files = $result->fetchAll(); |
|
|
|
|
|
|
|
return array_map(function (array $data) { |
|
|
|
return self::cacheEntryFromData($data, $this->mimetypeLoader); |
|
|
|
}, $files); |
|
|
|
$operator = new SearchComparison(ISearchComparison::COMPARE_LIKE, 'name', $pattern); |
|
|
|
return $this->searchQuery(new SearchQuery($operator, 0, 0, [], null)); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
@ -816,71 +793,16 @@ class Cache implements ICache { |
|
|
|
* @return ICacheEntry[] an array of cache entries where the mimetype matches the search |
|
|
|
*/ |
|
|
|
public function searchByMime($mimetype) { |
|
|
|
$mimeId = $this->mimetypeLoader->getId($mimetype); |
|
|
|
|
|
|
|
$query = $this->getQueryBuilder(); |
|
|
|
$query->selectFileCache() |
|
|
|
->whereStorageId(); |
|
|
|
|
|
|
|
if (strpos($mimetype, '/')) { |
|
|
|
$query->andWhere($query->expr()->eq('mimetype', $query->createNamedParameter($mimeId, IQueryBuilder::PARAM_INT))); |
|
|
|
if (strpos($mimetype, '/') === false) { |
|
|
|
$operator = new SearchComparison(ISearchComparison::COMPARE_LIKE, 'mimetype', $mimetype . '/%'); |
|
|
|
} else { |
|
|
|
$query->andWhere($query->expr()->eq('mimepart', $query->createNamedParameter($mimeId, IQueryBuilder::PARAM_INT))); |
|
|
|
$operator = new SearchComparison(ISearchComparison::COMPARE_EQUAL, 'mimetype', $mimetype); |
|
|
|
} |
|
|
|
|
|
|
|
$result = $query->execute(); |
|
|
|
$files = $result->fetchAll(); |
|
|
|
$result->closeCursor(); |
|
|
|
|
|
|
|
return array_map(function (array $data) { |
|
|
|
return self::cacheEntryFromData($data, $this->mimetypeLoader); |
|
|
|
}, $files); |
|
|
|
return $this->searchQuery(new SearchQuery($operator, 0, 0, [], null)); |
|
|
|
} |
|
|
|
|
|
|
|
public function searchQuery(ISearchQuery $searchQuery) { |
|
|
|
$builder = $this->getQueryBuilder(); |
|
|
|
|
|
|
|
$query = $builder->selectFileCache('file'); |
|
|
|
|
|
|
|
$query->whereStorageId(); |
|
|
|
|
|
|
|
if ($this->querySearchHelper->shouldJoinTags($searchQuery->getSearchOperation())) { |
|
|
|
$user = $searchQuery->getUser(); |
|
|
|
if ($user === null) { |
|
|
|
throw new \InvalidArgumentException("Searching by tag requires the user to be set in the query"); |
|
|
|
} |
|
|
|
$query |
|
|
|
->innerJoin('file', 'vcategory_to_object', 'tagmap', $builder->expr()->eq('file.fileid', 'tagmap.objid')) |
|
|
|
->innerJoin('tagmap', 'vcategory', 'tag', $builder->expr()->andX( |
|
|
|
$builder->expr()->eq('tagmap.type', 'tag.type'), |
|
|
|
$builder->expr()->eq('tagmap.categoryid', 'tag.id') |
|
|
|
)) |
|
|
|
->andWhere($builder->expr()->eq('tag.type', $builder->createNamedParameter('files'))) |
|
|
|
->andWhere($builder->expr()->eq('tag.uid', $builder->createNamedParameter($user->getUID()))); |
|
|
|
} |
|
|
|
|
|
|
|
$searchExpr = $this->querySearchHelper->searchOperatorToDBExpr($builder, $searchQuery->getSearchOperation()); |
|
|
|
if ($searchExpr) { |
|
|
|
$query->andWhere($searchExpr); |
|
|
|
} |
|
|
|
|
|
|
|
if ($searchQuery->limitToHome() && ($this instanceof HomeCache)) { |
|
|
|
$query->andWhere($builder->expr()->like('path', $query->expr()->literal('files/%'))); |
|
|
|
} |
|
|
|
|
|
|
|
$this->querySearchHelper->addSearchOrdersToQuery($query, $searchQuery->getOrder()); |
|
|
|
|
|
|
|
if ($searchQuery->getLimit()) { |
|
|
|
$query->setMaxResults($searchQuery->getLimit()); |
|
|
|
} |
|
|
|
if ($searchQuery->getOffset()) { |
|
|
|
$query->setFirstResult($searchQuery->getOffset()); |
|
|
|
} |
|
|
|
|
|
|
|
$result = $query->execute(); |
|
|
|
$cacheEntries = $this->searchResultToCacheEntries($result); |
|
|
|
$result->closeCursor(); |
|
|
|
return $cacheEntries; |
|
|
|
return $this->querySearchHelper->searchInCaches($searchQuery, [$this]); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
@ -949,7 +871,7 @@ class Cache implements ICache { |
|
|
|
$query->selectAlias($query->func()->sum('size'), 'f1') |
|
|
|
->selectAlias($query->func()->min('size'), 'f2') |
|
|
|
->from('filecache') |
|
|
|
->whereStorageId() |
|
|
|
->whereStorageId($this->getNumericStorageId()) |
|
|
|
->whereParent($id); |
|
|
|
|
|
|
|
$result = $query->execute(); |
|
|
|
@ -982,7 +904,7 @@ class Cache implements ICache { |
|
|
|
$query = $this->getQueryBuilder(); |
|
|
|
$query->select('fileid') |
|
|
|
->from('filecache') |
|
|
|
->whereStorageId(); |
|
|
|
->whereStorageId($this->getNumericStorageId()); |
|
|
|
|
|
|
|
$result = $query->execute(); |
|
|
|
$files = $result->fetchAll(\PDO::FETCH_COLUMN); |
|
|
|
@ -1006,7 +928,7 @@ class Cache implements ICache { |
|
|
|
$query = $this->getQueryBuilder(); |
|
|
|
$query->select('path') |
|
|
|
->from('filecache') |
|
|
|
->whereStorageId() |
|
|
|
->whereStorageId($this->getNumericStorageId()) |
|
|
|
->andWhere($query->expr()->lt('size', $query->createNamedParameter(0, IQueryBuilder::PARAM_INT))) |
|
|
|
->orderBy('fileid', 'DESC') |
|
|
|
->setMaxResults(1); |
|
|
|
@ -1028,7 +950,7 @@ class Cache implements ICache { |
|
|
|
$query = $this->getQueryBuilder(); |
|
|
|
$query->select('path') |
|
|
|
->from('filecache') |
|
|
|
->whereStorageId() |
|
|
|
->whereStorageId($this->getNumericStorageId()) |
|
|
|
->whereFileId($id); |
|
|
|
|
|
|
|
$result = $query->execute(); |
|
|
|
@ -1127,4 +1049,16 @@ class Cache implements ICache { |
|
|
|
'metadata_etag' => $entry->getMetadataEtag(), |
|
|
|
]; |
|
|
|
} |
|
|
|
|
|
|
|
public function getQueryFilterForStorage(IQueryBuilder $builder) { |
|
|
|
return $builder->expr()->eq('storage', $builder->createNamedParameter($this->getNumericStorageId(), IQueryBuilder::PARAM_INT)); |
|
|
|
} |
|
|
|
|
|
|
|
public function getCacheEntryFromSearchResult(ICacheEntry $rawEntry): ?ICacheEntry { |
|
|
|
if ($rawEntry->getStorageId() === $this->getNumericStorageId()) { |
|
|
|
return $rawEntry; |
|
|
|
} else { |
|
|
|
return null; |
|
|
|
} |
|
|
|
} |
|
|
|
} |