memories/lib/Db/TimelineQueryMap.php

122 lines
4.0 KiB
PHP
Raw Normal View History

2023-02-08 21:53:38 +00:00
<?php
declare(strict_types=1);
namespace OCA\Memories\Db;
use OCP\DB\QueryBuilder\IQueryBuilder;
2023-02-09 01:45:55 +00:00
use OCP\IDBConnection;
2023-02-08 21:53:38 +00:00
trait TimelineQueryMap
{
2023-02-09 01:45:55 +00:00
protected IDBConnection $connection;
2023-02-09 05:55:12 +00:00
public function transformMapBoundsFilter(IQueryBuilder &$query, string $userId, string $bounds, $table = 'm')
2023-02-08 21:53:38 +00:00
{
$bounds = explode(',', $bounds);
$bounds = array_map('floatval', $bounds);
if (4 !== \count($bounds)) {
return;
}
2023-02-09 05:55:12 +00:00
$latCol = $table.'.lat';
$lonCol = $table.'.lon';
2023-02-08 21:53:38 +00:00
$query->andWhere(
$query->expr()->andX(
2023-02-09 05:55:12 +00:00
$query->expr()->gte($latCol, $query->createNamedParameter($bounds[0], IQueryBuilder::PARAM_STR)),
$query->expr()->lte($latCol, $query->createNamedParameter($bounds[1], IQueryBuilder::PARAM_STR)),
$query->expr()->gte($lonCol, $query->createNamedParameter($bounds[2], IQueryBuilder::PARAM_STR)),
$query->expr()->lte($lonCol, $query->createNamedParameter($bounds[3], IQueryBuilder::PARAM_STR))
2023-02-08 21:53:38 +00:00
)
);
}
public function getMapClusters(
float $gridLen,
string $bounds,
TimelineRoot &$root
): array {
$query = $this->connection->getQueryBuilder();
// Get the average location of each cluster
2023-02-09 05:55:12 +00:00
$lat = $query->createFunction('AVG(c.lat) AS lat');
$lon = $query->createFunction('AVG(c.lon) AS lon');
2023-02-08 21:53:38 +00:00
$count = $query->createFunction('COUNT(m.fileid) AS count');
2023-02-09 16:25:37 +00:00
$update = $query->createFunction('MAX(c.last_update) as u');
2023-02-09 05:55:12 +00:00
2023-02-09 16:25:37 +00:00
$query->select($lat, $lon, $update, $count)
2023-02-09 08:35:35 +00:00
->from('memories_mapclusters', 'c')
2023-02-08 21:53:38 +00:00
;
2023-02-09 07:36:31 +00:00
if ($gridLen > 0.02) {
2023-02-09 05:55:12 +00:00
// Coarse grouping
2023-02-09 07:36:31 +00:00
$query->addSelect($query->createFunction('MAX(c.id) as id'));
2023-02-09 05:55:12 +00:00
$query->addGroupBy($query->createFunction("CAST(c.lat / {$gridLen} AS INT)"));
$query->addGroupBy($query->createFunction("CAST(c.lon / {$gridLen} AS INT)"));
} else {
// Fine grouping
$query->addSelect('c.id')->groupBy('c.id');
}
// JOIN with memories for files from the current user
2023-02-09 08:35:35 +00:00
$query->innerJoin('c', 'memories', 'm', $query->expr()->eq('c.id', 'm.mapcluster'));
2023-02-09 05:55:12 +00:00
2023-02-08 21:53:38 +00:00
// JOIN with filecache for existing files
$query = $this->joinFilecache($query, $root, true, false);
2023-02-09 05:55:12 +00:00
// Bound the query to the map bounds
$this->transformMapBoundsFilter($query, '', $bounds, 'c');
2023-02-08 21:53:38 +00:00
// Execute query
$cursor = $this->executeQueryWithCTEs($query);
$res = $cursor->fetchAll();
$cursor->closeCursor();
// Post-process results
$clusters = [];
2023-02-09 05:55:12 +00:00
foreach ($res as &$cluster) {
$c = [
2023-02-08 21:53:38 +00:00
'center' => [
2023-02-09 05:55:12 +00:00
(float) $cluster['lat'],
(float) $cluster['lon'],
2023-02-08 21:53:38 +00:00
],
'count' => (float) $cluster['count'],
2023-02-09 16:25:37 +00:00
'u' => (int) $cluster['u'],
2023-02-08 21:53:38 +00:00
];
2023-02-09 05:55:12 +00:00
if (\array_key_exists('id', $cluster)) {
$c['id'] = (int) $cluster['id'];
}
$clusters[] = $c;
2023-02-08 21:53:38 +00:00
}
return $clusters;
}
2023-02-09 05:55:12 +00:00
public function getMapClusterPreviews(int $clusterId, TimelineRoot &$root)
{
$query = $this->connection->getQueryBuilder();
// SELECT all photos with this tag
$query->select('f.fileid', 'f.etag')->from('memories', 'm')->where(
2023-02-09 08:35:35 +00:00
$query->expr()->eq('m.mapcluster', $query->createNamedParameter($clusterId, IQueryBuilder::PARAM_INT))
2023-02-09 05:55:12 +00:00
);
// WHERE these photos are in the user's requested folder recursively
$query = $this->joinFilecache($query, $root, true, false);
// MAX 8
$query->setMaxResults(8);
// FETCH tag previews
$cursor = $this->executeQueryWithCTEs($query);
$ans = $cursor->fetchAll();
// Post-process
foreach ($ans as &$row) {
$row['fileid'] = (int) $row['fileid'];
}
return $ans;
}
2023-02-08 21:53:38 +00:00
}