2022-09-11 02:05:04 +00:00
|
|
|
<?php
|
2022-10-19 17:10:36 +00:00
|
|
|
|
2022-09-11 02:05:04 +00:00
|
|
|
declare(strict_types=1);
|
|
|
|
|
|
|
|
namespace OCA\Memories\Db;
|
|
|
|
|
|
|
|
use OCP\DB\QueryBuilder\IQueryBuilder;
|
2022-09-24 01:54:14 +00:00
|
|
|
use OCP\Files\Folder;
|
2022-10-19 17:10:36 +00:00
|
|
|
use OCP\IDBConnection;
|
2022-09-11 02:05:04 +00:00
|
|
|
|
2022-10-19 17:10:36 +00:00
|
|
|
trait TimelineQueryDays
|
|
|
|
{
|
2022-09-11 02:05:04 +00:00
|
|
|
protected IDBConnection $connection;
|
|
|
|
|
|
|
|
/**
|
2022-10-19 17:10:36 +00:00
|
|
|
* Get the days response from the database for the timeline.
|
|
|
|
*
|
|
|
|
* @param Folder $folder The folder to get the days from
|
|
|
|
* @param bool $recursive Whether to get the days recursively
|
|
|
|
* @param bool $archive Whether to get the days only from the archive folder
|
|
|
|
* @param array $queryTransforms An array of query transforms to apply to the query
|
2022-10-06 19:24:45 +00:00
|
|
|
*
|
|
|
|
* @return array The days response
|
2022-09-11 02:05:04 +00:00
|
|
|
*/
|
|
|
|
public function getDays(
|
2022-09-24 01:54:14 +00:00
|
|
|
Folder &$folder,
|
|
|
|
string $uid,
|
|
|
|
bool $recursive,
|
2022-09-25 23:02:26 +00:00
|
|
|
bool $archive,
|
2022-09-12 01:33:38 +00:00
|
|
|
array $queryTransforms = []
|
2022-09-12 01:06:16 +00:00
|
|
|
): array {
|
2022-09-11 02:05:04 +00:00
|
|
|
$query = $this->connection->getQueryBuilder();
|
2022-09-12 01:03:40 +00:00
|
|
|
|
2022-09-24 01:54:14 +00:00
|
|
|
// Get all entries also present in filecache
|
|
|
|
$count = $query->func()->count($query->createFunction('DISTINCT m.fileid'), 'count');
|
|
|
|
$query->select('m.dayid', $count)
|
|
|
|
->from('memories', 'm')
|
2022-10-19 17:10:36 +00:00
|
|
|
->innerJoin('m', 'filecache', 'f', $this->getFilecacheJoinQuery($query, $folder, $recursive, $archive))
|
|
|
|
;
|
2022-09-24 01:54:14 +00:00
|
|
|
|
|
|
|
// Group and sort by dayid
|
|
|
|
$query->groupBy('m.dayid')
|
2022-10-19 17:10:36 +00:00
|
|
|
->orderBy('m.dayid', 'DESC')
|
|
|
|
;
|
2022-09-11 02:05:04 +00:00
|
|
|
|
2022-09-12 01:33:38 +00:00
|
|
|
// Apply all transformations
|
2022-10-06 21:19:47 +00:00
|
|
|
$this->applyAllTransforms($queryTransforms, $query, $uid);
|
2022-09-12 01:33:38 +00:00
|
|
|
|
2022-09-25 11:30:28 +00:00
|
|
|
$cursor = $query->executeQuery();
|
|
|
|
$rows = $cursor->fetchAll();
|
|
|
|
$cursor->closeCursor();
|
2022-10-19 17:10:36 +00:00
|
|
|
|
2022-09-11 02:05:04 +00:00
|
|
|
return $this->processDays($rows);
|
|
|
|
}
|
|
|
|
|
2022-10-06 19:24:45 +00:00
|
|
|
/**
|
2022-10-19 17:10:36 +00:00
|
|
|
* Get the day response from the database for the timeline.
|
|
|
|
*
|
|
|
|
* @param Folder $folder The folder to get the day from
|
|
|
|
* @param string $uid The user id
|
|
|
|
* @param int[] $dayid The day id
|
|
|
|
* @param bool $recursive If the query should be recursive
|
|
|
|
* @param bool $archive If the query should include only the archive folder
|
|
|
|
* @param array $queryTransforms The query transformations to apply
|
|
|
|
* @param mixed $day_ids
|
|
|
|
*
|
2022-10-06 19:24:45 +00:00
|
|
|
* @return array An array of day responses
|
2022-09-11 02:05:04 +00:00
|
|
|
*/
|
2022-09-24 01:54:14 +00:00
|
|
|
public function getDay(
|
|
|
|
Folder &$folder,
|
|
|
|
string $uid,
|
2022-10-06 22:01:28 +00:00
|
|
|
$day_ids,
|
2022-09-24 01:54:14 +00:00
|
|
|
bool $recursive,
|
2022-09-25 23:02:26 +00:00
|
|
|
bool $archive,
|
2022-09-24 01:54:14 +00:00
|
|
|
array $queryTransforms = []
|
|
|
|
): array {
|
2022-09-11 02:05:04 +00:00
|
|
|
$query = $this->connection->getQueryBuilder();
|
2022-09-24 01:54:14 +00:00
|
|
|
|
|
|
|
// Get all entries also present in filecache
|
|
|
|
$fileid = $query->createFunction('DISTINCT m.fileid');
|
|
|
|
|
|
|
|
// We don't actually use m.datetaken here, but postgres
|
|
|
|
// needs that all fields in ORDER BY are also in SELECT
|
|
|
|
// when using DISTINCT on selected fields
|
2022-10-15 19:23:31 +00:00
|
|
|
$query->select($fileid, 'f.etag', 'm.isvideo', 'vco.categoryid', 'm.datetaken', 'm.dayid', 'm.w', 'm.h')
|
2022-09-24 01:54:14 +00:00
|
|
|
->from('memories', 'm')
|
2022-10-19 17:10:36 +00:00
|
|
|
->innerJoin('m', 'filecache', 'f', $this->getFilecacheJoinQuery($query, $folder, $recursive, $archive))
|
|
|
|
;
|
2022-10-06 22:01:28 +00:00
|
|
|
|
|
|
|
// Filter by dayid unless wildcard
|
2022-10-19 17:10:36 +00:00
|
|
|
if (null !== $day_ids) {
|
2022-10-06 22:01:28 +00:00
|
|
|
$query->andWhere($query->expr()->in('m.dayid', $query->createNamedParameter($day_ids, IQueryBuilder::PARAM_INT_ARRAY)));
|
|
|
|
} else {
|
|
|
|
// Limit wildcard to 100 results
|
|
|
|
$query->setMaxResults(100);
|
|
|
|
}
|
2022-09-24 01:54:14 +00:00
|
|
|
|
|
|
|
// Add favorite field
|
|
|
|
$this->addFavoriteTag($query, $uid);
|
|
|
|
|
|
|
|
// Group and sort by date taken
|
|
|
|
$query->orderBy('m.datetaken', 'DESC');
|
2022-10-16 19:18:31 +00:00
|
|
|
$query->addOrderBy('m.fileid', 'DESC'); // tie-breaker
|
2022-09-24 01:54:14 +00:00
|
|
|
|
|
|
|
// Apply all transformations
|
2022-10-06 21:19:47 +00:00
|
|
|
$this->applyAllTransforms($queryTransforms, $query, $uid);
|
2022-09-11 02:05:04 +00:00
|
|
|
|
2022-09-25 11:30:28 +00:00
|
|
|
$cursor = $query->executeQuery();
|
|
|
|
$rows = $cursor->fetchAll();
|
|
|
|
$cursor->closeCursor();
|
2022-10-19 17:10:36 +00:00
|
|
|
|
2022-09-24 01:54:14 +00:00
|
|
|
return $this->processDay($rows);
|
2022-09-11 02:05:04 +00:00
|
|
|
}
|
2022-10-19 17:10:36 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Process the days response.
|
|
|
|
*
|
|
|
|
* @param array $days
|
|
|
|
*/
|
|
|
|
private function processDays(&$days)
|
|
|
|
{
|
|
|
|
foreach ($days as &$row) {
|
2022-10-19 17:15:14 +00:00
|
|
|
$row['dayid'] = (int) $row['dayid'];
|
|
|
|
$row['count'] = (int) $row['count'];
|
2022-10-19 17:10:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return $days;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Process the single day response.
|
|
|
|
*
|
|
|
|
* @param array $day
|
|
|
|
*/
|
|
|
|
private function processDay(&$day)
|
|
|
|
{
|
|
|
|
foreach ($day as &$row) {
|
|
|
|
// We don't need date taken (see query builder)
|
|
|
|
unset($row['datetaken']);
|
|
|
|
|
|
|
|
// Convert field types
|
2022-10-19 17:15:14 +00:00
|
|
|
$row['fileid'] = (int) $row['fileid'];
|
|
|
|
$row['isvideo'] = (int) $row['isvideo'];
|
|
|
|
$row['dayid'] = (int) $row['dayid'];
|
|
|
|
$row['w'] = (int) $row['w'];
|
|
|
|
$row['h'] = (int) $row['h'];
|
2022-10-19 17:10:36 +00:00
|
|
|
if (!$row['isvideo']) {
|
|
|
|
unset($row['isvideo']);
|
|
|
|
}
|
|
|
|
if ($row['categoryid']) {
|
|
|
|
$row['isfavorite'] = 1;
|
|
|
|
}
|
|
|
|
unset($row['categoryid']);
|
|
|
|
|
|
|
|
// All transform processing
|
|
|
|
$this->processFace($row);
|
|
|
|
}
|
|
|
|
|
|
|
|
return $day;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Get the query for oc_filecache join */
|
|
|
|
private function getFilecacheJoinQuery(
|
|
|
|
IQueryBuilder &$query,
|
|
|
|
Folder &$folder,
|
|
|
|
bool $recursive,
|
|
|
|
bool $archive
|
|
|
|
) {
|
|
|
|
// Subquery to get storage and path
|
|
|
|
$subQuery = $query->getConnection()->getQueryBuilder();
|
|
|
|
$cursor = $subQuery->select('path', 'storage')->from('filecache')->where(
|
|
|
|
$subQuery->expr()->eq('fileid', $subQuery->createNamedParameter($folder->getId())),
|
|
|
|
)->executeQuery();
|
|
|
|
$finfo = $cursor->fetch();
|
|
|
|
$cursor->closeCursor();
|
|
|
|
if (empty($finfo)) {
|
|
|
|
throw new \Exception('Folder not found');
|
|
|
|
}
|
|
|
|
|
|
|
|
$pathQuery = null;
|
|
|
|
if ($recursive) {
|
|
|
|
// Filter by path for recursive query
|
|
|
|
$likePath = $finfo['path'];
|
|
|
|
if (!empty($likePath)) {
|
|
|
|
$likePath .= '/';
|
|
|
|
}
|
|
|
|
$pathQuery = $query->expr()->like('f.path', $query->createNamedParameter($likePath.'%'));
|
|
|
|
|
|
|
|
// Exclude/show archive folder
|
|
|
|
$archiveLikePath = $likePath.\OCA\Memories\Util::$ARCHIVE_FOLDER.'/%';
|
|
|
|
if (!$archive) {
|
|
|
|
// Exclude archive folder
|
|
|
|
$pathQuery = $query->expr()->andX(
|
|
|
|
$pathQuery,
|
|
|
|
$query->expr()->notLike('f.path', $query->createNamedParameter($archiveLikePath))
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
// Show only archive folder
|
|
|
|
$pathQuery = $query->expr()->like('f.path', $query->createNamedParameter($archiveLikePath));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// If getting non-recursively folder only check for parent
|
|
|
|
$pathQuery = $query->expr()->eq('f.parent', $query->createNamedParameter($folder->getId(), IQueryBuilder::PARAM_INT));
|
|
|
|
}
|
|
|
|
|
|
|
|
return $query->expr()->andX(
|
|
|
|
$query->expr()->eq('f.fileid', 'm.fileid'),
|
|
|
|
$query->expr()->in('f.storage', $query->createNamedParameter($finfo['storage'])),
|
|
|
|
$pathQuery,
|
|
|
|
);
|
|
|
|
}
|
2022-09-11 02:05:04 +00:00
|
|
|
}
|