mirror of
https://github.com/nextcloud/server.git
synced 2026-06-12 18:21:40 -04:00
perf(dav): push carddav report filtering to the db
Signed-off-by: Christoph Wurst <christoph@winzerhof-wurst.at>
This commit is contained in:
parent
b469840b3d
commit
ac97f10b44
2 changed files with 91 additions and 1 deletions
|
|
@ -13,6 +13,8 @@ use OCP\IL10N;
|
|||
use OCP\Server;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Sabre\CardDAV\Backend\BackendInterface;
|
||||
use Sabre\CardDAV\IAddressBookObjectContainer;
|
||||
use Sabre\CardDAV\Xml\Request\AddressBookQueryReport;
|
||||
use Sabre\DAV\Exception\Forbidden;
|
||||
use Sabre\DAV\Exception\NotFound;
|
||||
use Sabre\DAV\IMoveTarget;
|
||||
|
|
@ -25,7 +27,7 @@ use Sabre\DAV\PropPatch;
|
|||
* @package OCA\DAV\CardDAV
|
||||
* @property CardDavBackend $carddavBackend
|
||||
*/
|
||||
class AddressBook extends \Sabre\CardDAV\AddressBook implements IShareable, IMoveTarget {
|
||||
class AddressBook extends \Sabre\CardDAV\AddressBook implements IShareable, IMoveTarget, IAddressBookObjectContainer {
|
||||
/**
|
||||
* AddressBook constructor.
|
||||
*
|
||||
|
|
@ -258,4 +260,11 @@ class AddressBook extends \Sabre\CardDAV\AddressBook implements IShareable, IMov
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function addressBookQuery(AddressBookQueryReport $report): array {
|
||||
return $this->carddavBackend->addressBookReport(
|
||||
$this->addressBookInfo['id'],
|
||||
$report,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,9 +30,12 @@ use PDO;
|
|||
use Sabre\CardDAV\Backend\BackendInterface;
|
||||
use Sabre\CardDAV\Backend\SyncSupport;
|
||||
use Sabre\CardDAV\Plugin;
|
||||
use Sabre\CardDAV\Xml\Request\AddressBookQueryReport;
|
||||
use Sabre\DAV\Exception\BadRequest;
|
||||
use Sabre\VObject\Component\VCard;
|
||||
use Sabre\VObject\Reader;
|
||||
use function in_array;
|
||||
use function strtoupper;
|
||||
|
||||
class CardDavBackend implements BackendInterface, SyncSupport {
|
||||
use TTransactional;
|
||||
|
|
@ -1533,4 +1536,82 @@ class CardDavBackend implements BackendInterface, SyncSupport {
|
|||
// should already be handled, but just in case
|
||||
throw new BadRequest('vCard can not be empty');
|
||||
}
|
||||
|
||||
public function addressBookReport(int $addressBookId, AddressBookQueryReport $report): array {
|
||||
$selectQuery = $this->db->getQueryBuilder();
|
||||
$selectQuery->select('c.uri')
|
||||
->from($this->dbCardsPropertiesTable, 'cp')
|
||||
->join('cp', $this->dbCardsTable, 'c', $selectQuery->expr()->eq('c.id', 'cp.cardid', IQueryBuilder::PARAM_INT))
|
||||
->where($selectQuery->expr()->eq('c.addressbookid', $selectQuery->createNamedParameter($addressBookId, IQueryBuilder::PARAM_INT), IQueryBuilder::PARAM_INT));
|
||||
|
||||
$needsPostFilter = false;
|
||||
$dbFilters = [];
|
||||
foreach ($report->filters as $filter) {
|
||||
if (!in_array(strtoupper($filter['name']), self::$indexProperties, true)) {
|
||||
// We can't push the filter down to the DB
|
||||
$needsPostFilter = true;
|
||||
}
|
||||
if (!empty($filter['param-filter'])) {
|
||||
// Parameters are not indexed
|
||||
$needsPostFilter = true;
|
||||
}
|
||||
if ($filter['is-not-defined'] === true) {
|
||||
// Can't easily look for this with a query
|
||||
$needsPostFilter = true;
|
||||
}
|
||||
|
||||
foreach ($filter['text-matches'] as $matchFilter) {
|
||||
// TODO: handle negate-condition
|
||||
$dbFilters[] = $selectQuery->expr()->andX(
|
||||
$selectQuery->expr()->eq(
|
||||
'cp.name',
|
||||
$selectQuery->createNamedParameter($filter['name']),
|
||||
),
|
||||
match ($matchFilter['match-type']) {
|
||||
'equals' => $selectQuery->expr()->eq(
|
||||
'cp.value',
|
||||
$selectQuery->createNamedParameter($matchFilter['value'], IQueryBuilder::PARAM_STR)
|
||||
),
|
||||
'contains' => $selectQuery->expr()->like(
|
||||
'cp.value',
|
||||
$selectQuery->createNamedParameter('%' . $matchFilter['value'] . '%', IQueryBuilder::PARAM_STR) // TODO: escaping
|
||||
),
|
||||
'starts-with' => $selectQuery->expr()->eq(
|
||||
'cp.value',
|
||||
$selectQuery->createNamedParameter($matchFilter['value'] . '%', IQueryBuilder::PARAM_STR) // TODO: escaping
|
||||
),
|
||||
'ends-with' => $selectQuery->expr()->eq(
|
||||
'cp.value',
|
||||
$selectQuery->createNamedParameter('%' . $matchFilter['value'], IQueryBuilder::PARAM_STR) // TODO: escaping
|
||||
),
|
||||
default => throw new \InvalidArgumentException('Invalid filter match'),
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ($dbFilters !== []) {
|
||||
$selectQuery->andWhere(
|
||||
match ($report->test) {
|
||||
'allof' => $selectQuery->expr()->andX(...$dbFilters),
|
||||
'anyof' => $selectQuery->expr()->orX(...$dbFilters),
|
||||
default => throw new \InvalidArgumentException('Invalid filter test'),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
$selectQuery->groupBy('c.uri'); // deduplicate
|
||||
$result = $selectQuery->executeQuery();
|
||||
$uris = [];
|
||||
while (($uri = $result->fetchOne()) !== false) {
|
||||
$uris[] = $uri;
|
||||
}
|
||||
$result->closeCursor();
|
||||
|
||||
if ($needsPostFilter) {
|
||||
// TODO implement
|
||||
}
|
||||
|
||||
return $uris;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue