Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
rework search api to allow searching on multiple caches at once
Signed-off-by: Robin Appelman <[email protected]>
  • Loading branch information
icewind1991 committed Jun 14, 2021
commit e198dc1b200f3ade93498e0ea7b468c87d46748a
22 changes: 11 additions & 11 deletions apps/files_sharing/lib/Cache.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
use OC\Files\Cache\FailedCache;
use OC\Files\Cache\Wrapper\CacheJail;
use OC\Files\Storage\Wrapper\Jail;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\Files\Cache\ICacheEntry;
use OCP\Files\StorageNotAvailableException;

Expand Down Expand Up @@ -181,19 +182,18 @@ public function clear() {
// Not a valid action for Shared Cache
}

public function search($pattern) {
// Do the normal search on the whole storage for non files
public function getQueryFilterForStorage(IQueryBuilder $builder) {
// Do the normal jail behavior for non files
if ($this->storage->getItemType() !== 'file') {
return parent::search($pattern);
return parent::getQueryFilterForStorage($builder);
}

$regex = '/' . str_replace('%', '.*', $pattern) . '/i';

$data = $this->get('');
if (preg_match($regex, $data->getName()) === 1) {
return [$data];
}

return [];
// for single file shares we don't need to do the LIKE
return $builder->expr()->andX(
parent::getQueryFilterForStorage($builder),
$builder->expr()->orX(
$builder->expr()->eq('path_hash', $builder->createNamedParameter(md5($this->getGetUnjailedRoot()))),
)
);
}
}
5 changes: 2 additions & 3 deletions apps/files_trashbin/lib/Trashbin.php
Original file line number Diff line number Diff line change
Expand Up @@ -988,8 +988,7 @@ private static function getVersionsFromTrash($filename, $timestamp, $user) {
$query = new CacheQueryBuilder(
\OC::$server->getDatabaseConnection(),
\OC::$server->getSystemConfig(),
\OC::$server->getLogger(),
$cache
\OC::$server->getLogger()
);
$normalizedParentPath = ltrim(Filesystem::normalizePath(dirname('files_trashbin/versions/'. $filename)), '/');
$parentId = $cache->getId($normalizedParentPath);
Expand All @@ -998,7 +997,7 @@ private static function getVersionsFromTrash($filename, $timestamp, $user) {
}

$query->selectFileCache()
->whereStorageId()
->whereStorageId($cache->getNumericStorageId())
->andWhere($query->expr()->eq('parent', $query->createNamedParameter($parentId)))
->andWhere($query->expr()->iLike('name', $query->createNamedParameter($pattern)));

Expand Down
140 changes: 37 additions & 103 deletions lib/private/Files/Cache/Cache.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -52,6 +53,7 @@
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;
Expand Down Expand Up @@ -118,15 +120,19 @@ public function __construct(IStorage $storage) {
$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()
);
}

Expand All @@ -153,7 +159,7 @@ public function get($file) {
// normalize file
$file = $this->normalize($file);

$query->whereStorageId()
$query->whereStorageId($this->getNumericStorageId())
->wherePath($file);
} else { //file id
$query->whereFileId($file);
Expand Down Expand Up @@ -482,7 +488,7 @@ public function getId($file) {
$query = $this->getQueryBuilder();
$query->select('fileid')
->from('filecache')
->whereStorageId()
->whereStorageId($this->getNumericStorageId())
->wherePath($file);

$result = $query->execute();
Expand Down Expand Up @@ -718,7 +724,7 @@ public function moveFromCache(ICache $sourceCache, $sourcePath, $targetPath) {
public function clear() {
$query = $this->getQueryBuilder();
$query->delete('filecache')
->whereStorageId();
->whereStorageId($this->getNumericStorageId());
$query->execute();

$query = $this->connection->getQueryBuilder();
Expand Down Expand Up @@ -746,7 +752,7 @@ public function getStatus($file) {
$query = $this->getQueryBuilder();
$query->select('size')
->from('filecache')
->whereStorageId()
->whereStorageId($this->getNumericStorageId())
->wherePath($file);

$result = $query->execute();
Expand Down Expand Up @@ -775,37 +781,8 @@ public function getStatus($file) {
* @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));
}

/**
Expand All @@ -816,71 +793,16 @@ private function searchResultToCacheEntries(IResult $result): array {
* @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]);
}

/**
Expand Down Expand Up @@ -949,7 +871,7 @@ public function calculateFolderSize($path, $entry = null) {
$query->selectAlias($query->func()->sum('size'), 'f1')
->selectAlias($query->func()->min('size'), 'f2')
->from('filecache')
->whereStorageId()
->whereStorageId($this->getNumericStorageId())
->whereParent($id);

$result = $query->execute();
Expand Down Expand Up @@ -982,7 +904,7 @@ public function getAll() {
$query = $this->getQueryBuilder();
$query->select('fileid')
->from('filecache')
->whereStorageId();
->whereStorageId($this->getNumericStorageId());

$result = $query->execute();
$files = $result->fetchAll(\PDO::FETCH_COLUMN);
Expand All @@ -1006,7 +928,7 @@ public function getIncomplete() {
$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);
Expand All @@ -1028,7 +950,7 @@ public function getPathById($id) {
$query = $this->getQueryBuilder();
$query->select('path')
->from('filecache')
->whereStorageId()
->whereStorageId($this->getNumericStorageId())
->whereFileId($id);

$result = $query->execute();
Expand Down Expand Up @@ -1127,4 +1049,16 @@ private function cacheEntryToArray(ICacheEntry $entry): array {
'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;
}
}
}
4 changes: 4 additions & 0 deletions lib/private/Files/Cache/CacheEntry.php
Original file line number Diff line number Diff line change
Expand Up @@ -124,4 +124,8 @@ public function getUploadTime(): ?int {
public function getData() {
return $this->data;
}

public function __clone() {
$this->data = array_merge([], $this->data);
}
}
9 changes: 3 additions & 6 deletions lib/private/Files/Cache/CacheQueryBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,10 @@
* Query builder with commonly used helpers for filecache queries
*/
class CacheQueryBuilder extends QueryBuilder {
private $cache;
private $alias = null;

public function __construct(IDBConnection $connection, SystemConfig $systemConfig, ILogger $logger, Cache $cache) {
public function __construct(IDBConnection $connection, SystemConfig $systemConfig, ILogger $logger) {
parent::__construct($connection, $systemConfig, $logger);

$this->cache = $cache;
}

public function selectFileCache(string $alias = null) {
Expand All @@ -56,8 +53,8 @@ public function selectFileCache(string $alias = null) {
return $this;
}

public function whereStorageId() {
$this->andWhere($this->expr()->eq('storage', $this->createNamedParameter($this->cache->getNumericStorageId(), IQueryBuilder::PARAM_INT)));
public function whereStorageId(int $storageId) {
$this->andWhere($this->expr()->eq('storage', $this->createNamedParameter($storageId, IQueryBuilder::PARAM_INT)));

return $this;
}
Expand Down
9 changes: 9 additions & 0 deletions lib/private/Files/Cache/FailedCache.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
namespace OC\Files\Cache;

use OCP\Constants;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\Files\Cache\ICache;
use OCP\Files\Cache\ICacheEntry;
use OCP\Files\Search\ISearchQuery;
Expand Down Expand Up @@ -138,4 +139,12 @@ public function normalize($path) {
public function copyFromCache(ICache $sourceCache, ICacheEntry $sourceEntry, string $targetPath): int {
throw new \Exception("Invalid cache");
}

public function getQueryFilterForStorage(IQueryBuilder $builder) {
return 'false';
}

public function getCacheEntryFromSearchResult(ICacheEntry $rawEntry): ?ICacheEntry {
return null;
}
}
Loading