Fix pagination of contacts search
Signed-off-by: Joas Schilling <coding@schilljs.com>
This commit is contained in:
parent
d6923b4bb5
commit
a8ef2418f2
|
@ -944,39 +944,49 @@ class CardDavBackend implements BackendInterface, SyncSupport {
|
||||||
* @param array $searchProperties defines the properties within the query pattern should match
|
* @param array $searchProperties defines the properties within the query pattern should match
|
||||||
* @param array $options = array() to define the search behavior
|
* @param array $options = array() to define the search behavior
|
||||||
* - 'escape_like_param' - If set to false wildcards _ and % are not escaped, otherwise they are
|
* - 'escape_like_param' - If set to false wildcards _ and % are not escaped, otherwise they are
|
||||||
|
* - 'limit' - Set a numeric limit for the search results
|
||||||
|
* - 'offset' - Set the offset for the limited search results
|
||||||
* @return array an array of contacts which are arrays of key-value-pairs
|
* @return array an array of contacts which are arrays of key-value-pairs
|
||||||
*/
|
*/
|
||||||
public function search($addressBookId, $pattern, $searchProperties, $options = []) {
|
public function search($addressBookId, $pattern, $searchProperties, $options = []) {
|
||||||
$query = $this->db->getQueryBuilder();
|
|
||||||
$query2 = $this->db->getQueryBuilder();
|
$query2 = $this->db->getQueryBuilder();
|
||||||
|
|
||||||
$query2->selectDistinct('cp.cardid')->from($this->dbCardsPropertiesTable, 'cp');
|
$query2->selectDistinct('cp.cardid')
|
||||||
$query2->andWhere($query2->expr()->eq('cp.addressbookid', $query->createNamedParameter($addressBookId)));
|
->from($this->dbCardsPropertiesTable, 'cp')
|
||||||
|
->andWhere($query2->expr()->eq('cp.addressbookid', $query2->createNamedParameter($addressBookId)));
|
||||||
$or = $query2->expr()->orX();
|
$or = $query2->expr()->orX();
|
||||||
foreach ($searchProperties as $property) {
|
foreach ($searchProperties as $property) {
|
||||||
$or->add($query2->expr()->eq('cp.name', $query->createNamedParameter($property)));
|
$or->add($query2->expr()->eq('cp.name', $query2->createNamedParameter($property)));
|
||||||
}
|
}
|
||||||
$query2->andWhere($or);
|
$query2->andWhere($or);
|
||||||
|
|
||||||
// No need for like when the pattern is empty
|
// No need for like when the pattern is empty
|
||||||
if ('' !== $pattern) {
|
if ('' !== $pattern) {
|
||||||
if (\array_key_exists('escape_like_param', $options) && $options['escape_like_param'] === false) {
|
if (\array_key_exists('escape_like_param', $options) && $options['escape_like_param'] === false) {
|
||||||
$query2->andWhere($query2->expr()->ilike('cp.value', $query->createNamedParameter($pattern)));
|
$query2->andWhere($query2->expr()->ilike('cp.value', $query2->createNamedParameter($pattern)));
|
||||||
} else {
|
} else {
|
||||||
$query2->andWhere($query2->expr()->ilike('cp.value', $query->createNamedParameter('%' . $this->db->escapeLikeParameter($pattern) . '%')));
|
$query2->andWhere($query2->expr()->ilike('cp.value', $query2->createNamedParameter('%' . $this->db->escapeLikeParameter($pattern) . '%')));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// // FIXME Broken on MySQL: SQLSTATE[42000]: Syntax error or access violation: 1235 This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery'
|
|
||||||
// // FIXME Should use 2 queries instead
|
|
||||||
// if (isset($options['limit'])) {
|
|
||||||
// $query2->setMaxResults($options['limit']);
|
|
||||||
// }
|
|
||||||
// if (isset($options['offset'])) {
|
|
||||||
// $query2->setFirstResult($options['offset']);
|
|
||||||
// }
|
|
||||||
|
|
||||||
$query->select('c.carddata', 'c.uri')->from($this->dbCardsTable, 'c')
|
if (isset($options['limit'])) {
|
||||||
->where($query->expr()->in('c.id', $query->createFunction($query2->getSQL())));
|
$query2->setMaxResults($options['limit']);
|
||||||
|
}
|
||||||
|
if (isset($options['offset'])) {
|
||||||
|
$query2->setFirstResult($options['offset']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = $query2->execute();
|
||||||
|
$matches = $result->fetchAll();
|
||||||
|
$result->closeCursor();
|
||||||
|
$matches = array_map(function ($match) {
|
||||||
|
return (int) $match['cardid'];
|
||||||
|
}, $matches);
|
||||||
|
|
||||||
|
$query = $this->db->getQueryBuilder();
|
||||||
|
$query->select('c.carddata', 'c.uri')
|
||||||
|
->from($this->dbCardsTable, 'c')
|
||||||
|
->where($query->expr()->in('c.id', $query->createNamedParameter($matches, IQueryBuilder::PARAM_INT_ARRAY)));
|
||||||
|
|
||||||
$result = $query->execute();
|
$result = $query->execute();
|
||||||
$cards = $result->fetchAll();
|
$cards = $result->fetchAll();
|
||||||
|
|
|
@ -759,6 +759,8 @@ class CardDavBackendTest extends TestCase {
|
||||||
['Do', ['FN'], [], [['uri0', 'John Doe'], ['uri1', 'John M. Doe']]],
|
['Do', ['FN'], [], [['uri0', 'John Doe'], ['uri1', 'John M. Doe']]],
|
||||||
'check if duplicates are handled correctly' => ['John', ['FN', 'CLOUD'], [], [['uri0', 'John Doe'], ['uri1', 'John M. Doe']]],
|
'check if duplicates are handled correctly' => ['John', ['FN', 'CLOUD'], [], [['uri0', 'John Doe'], ['uri1', 'John M. Doe']]],
|
||||||
'case insensitive' => ['john', ['FN'], [], [['uri0', 'John Doe'], ['uri1', 'John M. Doe']]],
|
'case insensitive' => ['john', ['FN'], [], [['uri0', 'John Doe'], ['uri1', 'John M. Doe']]],
|
||||||
|
'limit' => ['john', ['FN'], ['limit' => 1], [['uri0', 'John Doe']]],
|
||||||
|
'limit and offset' => ['john', ['FN'], ['limit' => 1, 'offset' => 1], [['uri1', 'John M. Doe']]],
|
||||||
'find "_" escaped' => ['_', ['CLOUD'], [], [['uri2', 'find without options']]],
|
'find "_" escaped' => ['_', ['CLOUD'], [], [['uri2', 'find without options']]],
|
||||||
'find not empty ClOUD' => ['%_%', ['CLOUD'], ['escape_like_param'=>false], [['uri0', 'John Doe'], ['uri2', 'find without options']]],
|
'find not empty ClOUD' => ['%_%', ['CLOUD'], ['escape_like_param'=>false], [['uri0', 'John Doe'], ['uri2', 'find without options']]],
|
||||||
];
|
];
|
||||||
|
|
Loading…
Reference in New Issue