Skip to content

Commit afb565e

Browse files
GromNaNbitgandtter
andauthored
Allow to paginate $search aggregation with searchBefore and searchAfter markers (#2808)
* feat: allow to paginate search aggregation with searchBefore and searchAfter markers * chore: reduce testing scenarios * chore: add new skip rules to phpstan-baseline.neon --------- Co-authored-by: bitgandtter <[email protected]>
1 parent d12f52f commit afb565e

File tree

3 files changed

+120
-0
lines changed

3 files changed

+120
-0
lines changed

lib/Doctrine/ODM/MongoDB/Aggregation/Stage/Search.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434
* maxNumPassages?: int,
3535
* },
3636
* returnStoredSource?: bool,
37+
* searchBefore?: string,
38+
* searchAfter?: string,
3739
* sort?: object,
3840
* autocomplete?: object,
3941
* compound?: object,
@@ -61,6 +63,8 @@ class Search extends Stage implements SupportsAllSearchOperators
6163
private ?object $count = null;
6264
private ?object $highlight = null;
6365
private ?bool $returnStoredSource = null;
66+
private ?string $searchBefore = null;
67+
private ?string $searchAfter = null;
6468
private ?SearchOperator $operator = null;
6569

6670
/** @var array<string, -1|1|SortMeta> */
@@ -92,6 +96,14 @@ public function getExpression(): array
9296
$params->returnStoredSource = $this->returnStoredSource;
9397
}
9498

99+
if ($this->searchBefore) {
100+
$params->searchBefore = $this->searchBefore;
101+
}
102+
103+
if ($this->searchAfter) {
104+
$params->searchAfter = $this->searchAfter;
105+
}
106+
95107
if ($this->sort) {
96108
$params->sort = (object) $this->sort;
97109
}
@@ -145,6 +157,20 @@ public function returnStoredSource(bool $returnStoredSource = true): static
145157
return $this;
146158
}
147159

160+
public function searchBefore(string $searchBefore): static
161+
{
162+
$this->searchBefore = $searchBefore;
163+
164+
return $this;
165+
}
166+
167+
public function searchAfter(string $searchAfter): static
168+
{
169+
$this->searchAfter = $searchAfter;
170+
171+
return $this;
172+
}
173+
148174
/**
149175
* @param array<string, int|string>|string $fieldName Field name or array of field/order pairs
150176
* @param int|string $order Field order (if one field is specified)

phpstan-baseline.neon

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1524,6 +1524,18 @@ parameters:
15241524
count: 1
15251525
path: tests/Doctrine/ODM/MongoDB/Tests/Aggregation/Stage/SearchTest.php
15261526

1527+
-
1528+
message: '#^Method Doctrine\\ODM\\MongoDB\\Tests\\Aggregation\\Stage\\SearchTest\:\:testSearchOperatorsWithSearchAfter\(\) has parameter \$expectedOperator with no value type specified in iterable type array\.$#'
1529+
identifier: missingType.iterableValue
1530+
count: 1
1531+
path: tests/Doctrine/ODM/MongoDB/Tests/Aggregation/Stage/SearchTest.php
1532+
1533+
-
1534+
message: '#^Method Doctrine\\ODM\\MongoDB\\Tests\\Aggregation\\Stage\\SearchTest\:\:testSearchOperatorsWithSearchBefore\(\) has parameter \$expectedOperator with no value type specified in iterable type array\.$#'
1535+
identifier: missingType.iterableValue
1536+
count: 1
1537+
path: tests/Doctrine/ODM/MongoDB/Tests/Aggregation/Stage/SearchTest.php
1538+
15271539
-
15281540
message: '#^Method Doctrine\\ODM\\MongoDB\\Tests\\Aggregation\\Stage\\SearchTest\:\:testSearchOperatorsWithSort\(\) has parameter \$expectedOperator with no value type specified in iterable type array\.$#'
15291541
identifier: missingType.iterableValue

tests/Doctrine/ODM/MongoDB/Tests/Aggregation/Stage/SearchTest.php

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1313,4 +1313,86 @@ public function testSearchEmbeddedDocumentOperators(array $expectedOperator, Clo
13131313
$searchStage->getExpression(),
13141314
);
13151315
}
1316+
1317+
#[DataProvider('provideAutocompleteBuilders')]
1318+
public function testSearchOperatorsWithSearchBefore(array $expectedOperator, Closure $createOperator): void
1319+
{
1320+
$baseExpected = [
1321+
'index' => 'my_search_index',
1322+
'highlight' => (object) [
1323+
'path' => 'content',
1324+
'maxCharsToExamine' => 2,
1325+
'maxNumPassages' => 3,
1326+
],
1327+
'count' => (object) [
1328+
'type' => 'lowerBound',
1329+
'threshold' => 1000,
1330+
],
1331+
'returnStoredSource' => true,
1332+
'searchBefore' => 'marker',
1333+
];
1334+
1335+
$searchStage = new Search($this->getTestAggregationBuilder());
1336+
$searchStage
1337+
->index('my_search_index')
1338+
->searchBefore('marker');
1339+
1340+
$result = $createOperator($searchStage);
1341+
1342+
self::logicalOr(
1343+
new IsInstanceOf(AbstractSearchOperator::class),
1344+
new IsInstanceOf(Search::class),
1345+
);
1346+
1347+
$result
1348+
->highlight('content', 2, 3)
1349+
->countDocuments('lowerBound', 1000)
1350+
->returnStoredSource();
1351+
1352+
self::assertEquals(
1353+
['$search' => (object) array_merge($baseExpected, $expectedOperator)],
1354+
$searchStage->getExpression(),
1355+
);
1356+
}
1357+
1358+
#[DataProvider('provideAutocompleteBuilders')]
1359+
public function testSearchOperatorsWithSearchAfter(array $expectedOperator, Closure $createOperator): void
1360+
{
1361+
$baseExpected = [
1362+
'index' => 'my_search_index',
1363+
'highlight' => (object) [
1364+
'path' => 'content',
1365+
'maxCharsToExamine' => 2,
1366+
'maxNumPassages' => 3,
1367+
],
1368+
'count' => (object) [
1369+
'type' => 'lowerBound',
1370+
'threshold' => 1000,
1371+
],
1372+
'returnStoredSource' => true,
1373+
'searchAfter' => 'marker',
1374+
];
1375+
1376+
$searchStage = new Search($this->getTestAggregationBuilder());
1377+
$searchStage
1378+
->index('my_search_index')
1379+
->searchAfter('marker');
1380+
1381+
$result = $createOperator($searchStage);
1382+
1383+
self::logicalOr(
1384+
new IsInstanceOf(AbstractSearchOperator::class),
1385+
new IsInstanceOf(Search::class),
1386+
);
1387+
1388+
$result
1389+
->highlight('content', 2, 3)
1390+
->countDocuments('lowerBound', 1000)
1391+
->returnStoredSource();
1392+
1393+
self::assertEquals(
1394+
['$search' => (object) array_merge($baseExpected, $expectedOperator)],
1395+
$searchStage->getExpression(),
1396+
);
1397+
}
13161398
}

0 commit comments

Comments
 (0)