tag: get rid of windowing
parent
352f8d3d54
commit
6d8f06c885
|
@ -248,28 +248,7 @@ class ApiController extends Controller
|
||||||
);
|
);
|
||||||
|
|
||||||
// Preload all tag previews
|
// Preload all tag previews
|
||||||
$previews = $this->timelineQuery->getTagPreviews($folder);
|
$this->timelineQuery->getTagPreviews($list, $folder);
|
||||||
|
|
||||||
// Convert to map with key as systemtagid
|
|
||||||
$previews_map = [];
|
|
||||||
foreach ($previews as &$preview) {
|
|
||||||
$key = $preview['systemtagid'];
|
|
||||||
if (!\array_key_exists($key, $previews_map)) {
|
|
||||||
$previews_map[$key] = [];
|
|
||||||
}
|
|
||||||
unset($preview['systemtagid']);
|
|
||||||
$previews_map[$key][] = $preview;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add previews to list
|
|
||||||
foreach ($list as &$tag) {
|
|
||||||
$key = $tag['id'];
|
|
||||||
if (\array_key_exists($key, $previews_map)) {
|
|
||||||
$tag['previews'] = $previews_map[$key];
|
|
||||||
} else {
|
|
||||||
$tag['previews'] = [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new JSONResponse($list, Http::STATUS_OK);
|
return new JSONResponse($list, Http::STATUS_OK);
|
||||||
}
|
}
|
||||||
|
|
|
@ -159,34 +159,33 @@ trait TimelineQueryDays
|
||||||
return $day;
|
return $day;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get the query for oc_filecache join */
|
/**
|
||||||
private function getFilecacheJoinQuery(
|
* Get all folders inside a top folder
|
||||||
IQueryBuilder &$query,
|
*/
|
||||||
|
private function getSubfolderIdsRecursive(
|
||||||
|
IDBConnection &$conn,
|
||||||
Folder &$folder,
|
Folder &$folder,
|
||||||
bool $recursive,
|
|
||||||
bool $archive
|
bool $archive
|
||||||
) {
|
) {
|
||||||
$pathQuery = null;
|
// CTE to get all folders recursively in the given top folder
|
||||||
if ($recursive) {
|
$cte =
|
||||||
// CTE to get all folders recursively in the given top folder
|
'WITH RECURSIVE cte_folders(fileid) AS (
|
||||||
$cte =
|
SELECT
|
||||||
'WITH RECURSIVE cte_folders(fileid) AS (
|
f.fileid
|
||||||
SELECT
|
FROM
|
||||||
f.fileid
|
*PREFIX*filecache f
|
||||||
FROM
|
WHERE
|
||||||
*PREFIX*filecache f
|
f.fileid = :topFolderId
|
||||||
WHERE
|
UNION ALL
|
||||||
f.fileid = :topFolderId
|
SELECT
|
||||||
UNION ALL
|
f.fileid
|
||||||
SELECT
|
FROM
|
||||||
f.fileid
|
*PREFIX*filecache f
|
||||||
FROM
|
INNER JOIN cte_folders c
|
||||||
*PREFIX*filecache f
|
ON (f.parent = c.fileid
|
||||||
INNER JOIN cte_folders c
|
AND f.mimetype = 2
|
||||||
ON (f.parent = c.fileid
|
AND f.fileid NOT IN (:excludedFolderIds)
|
||||||
AND f.mimetype = 2
|
)
|
||||||
AND f.fileid NOT IN (:excludedFolderIds)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
SELECT
|
SELECT
|
||||||
fileid
|
fileid
|
||||||
|
@ -194,34 +193,60 @@ trait TimelineQueryDays
|
||||||
cte_folders
|
cte_folders
|
||||||
';
|
';
|
||||||
|
|
||||||
// Query parameters, set at the end
|
// Query parameters, set at the end
|
||||||
$topFolderId = $folder->getId();
|
$topFolderId = $folder->getId();
|
||||||
$excludedFolderIds = [-1]; // cannot be empty
|
$excludedFolderIds = [-1]; // cannot be empty
|
||||||
|
|
||||||
/** @var Folder Archive folder if it exists */
|
/** @var Folder Archive folder if it exists */
|
||||||
$archiveFolder = null;
|
$archiveFolder = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$archiveFolder = $folder->get('.archive/');
|
$archiveFolder = $folder->get('.archive/');
|
||||||
} catch (\OCP\Files\NotFoundException $e) {
|
} catch (\OCP\Files\NotFoundException $e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$archive) {
|
||||||
|
// Exclude archive folder
|
||||||
|
if ($archiveFolder) {
|
||||||
|
$excludedFolderIds[] = $archiveFolder->getId();
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// Only include archive folder
|
||||||
|
$topFolderId = $archiveFolder ? $archiveFolder->getId() : -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (!$archive) {
|
return array_column($conn->executeQuery($cte, [
|
||||||
// Exclude archive folder
|
'topFolderId' => $topFolderId,
|
||||||
if ($archiveFolder) {
|
'excludedFolderIds' => $excludedFolderIds,
|
||||||
$excludedFolderIds[] = $archiveFolder->getId();
|
])->fetchAll(), 'fileid');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the query for oc_filecache join
|
||||||
|
*
|
||||||
|
* @param IQueryBuilder $query Query builder
|
||||||
|
* @param Folder|array $folder Either the top folder or array of folder Ids
|
||||||
|
* @param bool $recursive Whether to get the days recursively
|
||||||
|
* @param bool $archive Whether to get the days only from the archive folder
|
||||||
|
*/
|
||||||
|
private function getFilecacheJoinQuery(
|
||||||
|
IQueryBuilder &$query,
|
||||||
|
&$folder,
|
||||||
|
bool $recursive,
|
||||||
|
bool $archive
|
||||||
|
) {
|
||||||
|
$pathQuery = null;
|
||||||
|
if ($recursive) {
|
||||||
|
// Get all subfolder Ids recursively
|
||||||
|
$folderIds = [];
|
||||||
|
if ($folder instanceof Folder) {
|
||||||
|
$folderIds = $this->getSubfolderIdsRecursive($query->getConnection(), $folder, $archive);
|
||||||
} else {
|
} else {
|
||||||
// Only include archive folder
|
$folderIds = $folder;
|
||||||
$topFolderId = $archiveFolder ? $archiveFolder->getId() : -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Join with CTE
|
// Join with folder IDs
|
||||||
$pathQuery = $query->expr()->in('f.parent', $query->createFunction($cte));
|
$pathQuery = $query->expr()->in('f.parent', $query->createNamedParameter($folderIds, IQueryBuilder::PARAM_INT_ARRAY));
|
||||||
|
|
||||||
// Set query parameters
|
|
||||||
$query->setParameter('topFolderId', $topFolderId, IQueryBuilder::PARAM_INT);
|
|
||||||
$query->setParameter('excludedFolderIds', $excludedFolderIds, IQueryBuilder::PARAM_INT_ARRAY);
|
|
||||||
} else {
|
} else {
|
||||||
// If getting non-recursively folder only check for parent
|
// If getting non-recursively folder only check for parent
|
||||||
$pathQuery = $query->expr()->eq('f.parent', $query->createNamedParameter($folder->getId(), IQueryBuilder::PARAM_INT));
|
$pathQuery = $query->expr()->eq('f.parent', $query->createNamedParameter($folder->getId(), IQueryBuilder::PARAM_INT));
|
||||||
|
|
|
@ -77,47 +77,39 @@ trait TimelineQueryTags
|
||||||
return $tags;
|
return $tags;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTagPreviews(Folder $folder)
|
public function getTagPreviews(array &$tags, Folder &$folder)
|
||||||
{
|
{
|
||||||
$query = $this->connection->getQueryBuilder();
|
// Cache subfolder ids to prevent duplicate requests
|
||||||
|
$folderIds = $this->getSubfolderIdsRecursive($this->connection, $folder, false);
|
||||||
|
|
||||||
// Windowing
|
foreach ($tags as &$tag) {
|
||||||
$rowNumber = $query->createFunction('ROW_NUMBER() OVER (PARTITION BY stom.systemtagid) as n');
|
$query = $this->connection->getQueryBuilder();
|
||||||
|
|
||||||
// SELECT all photos with this tag
|
// SELECT all photos with this tag
|
||||||
$query->select('f.fileid', 'f.etag', 'stom.systemtagid', $rowNumber)->from(
|
$query->select('f.fileid', 'f.etag')->from(
|
||||||
'systemtag_object_mapping',
|
'systemtag_object_mapping',
|
||||||
'stom'
|
'stom'
|
||||||
)->where(
|
)->where(
|
||||||
$query->expr()->eq('stom.objecttype', $query->createNamedParameter('files')),
|
$query->expr()->eq('stom.objecttype', $query->createNamedParameter('files')),
|
||||||
);
|
$query->expr()->eq('stom.systemtagid', $query->createNamedParameter($tag['id'])),
|
||||||
|
);
|
||||||
|
|
||||||
// WHERE these items are memories indexed photos
|
// WHERE these items are memories indexed photos
|
||||||
$query->innerJoin('stom', 'memories', 'm', $query->expr()->eq('m.fileid', 'stom.objectid'));
|
$query->innerJoin('stom', 'memories', 'm', $query->expr()->eq('m.fileid', 'stom.objectid'));
|
||||||
|
|
||||||
// WHERE these photos are in the user's requested folder recursively
|
// WHERE these photos are in the user's requested folder recursively
|
||||||
$query->innerJoin('m', 'filecache', 'f', $this->getFilecacheJoinQuery($query, $folder, true, false));
|
$query->innerJoin('m', 'filecache', 'f', $this->getFilecacheJoinQuery($query, $folderIds, true, false));
|
||||||
|
|
||||||
// Make this a sub query
|
// MAX 4
|
||||||
$fun = $query->createFunction('('.$query->getSQL().')');
|
$query->setMaxResults(4);
|
||||||
|
|
||||||
// Create outer query
|
// FETCH tag previews
|
||||||
$outerQuery = $this->connection->getQueryBuilder();
|
$tag['previews'] = $query->executeQuery()->fetchAll();
|
||||||
$outerQuery->setParameters($query->getParameters());
|
|
||||||
$outerQuery->select('*')->from($fun, 't');
|
|
||||||
$outerQuery->where($query->expr()->lte('t.n', $outerQuery->createParameter('nc')));
|
|
||||||
$outerQuery->setParameter('nc', 4, IQueryBuilder::PARAM_INT);
|
|
||||||
|
|
||||||
// FETCH all tag previews
|
// Post-process
|
||||||
$previews = $outerQuery->executeQuery()->fetchAll();
|
foreach ($tag['previews'] as &$row) {
|
||||||
|
$row['fileid'] = (int) $row['fileid'];
|
||||||
// Post-process
|
}
|
||||||
foreach ($previews as &$row) {
|
|
||||||
$row['fileid'] = (int) $row['fileid'];
|
|
||||||
$row['systemtagid'] = (int) $row['systemtagid'];
|
|
||||||
unset($row['n']);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $previews;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue