Skip to content

Commit 679caa6

Browse files
Merge v1.x into v2.x (#1530)
2 parents f736782 + 1b00b23 commit 679caa6

File tree

4 files changed

+65
-2
lines changed

4 files changed

+65
-2
lines changed

src/Operation/Distinct.php

+17-1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
use function is_array;
3232
use function is_integer;
3333
use function is_object;
34+
use function is_string;
3435
use function MongoDB\create_field_path_type_map;
3536
use function MongoDB\is_document;
3637

@@ -51,7 +52,13 @@ final class Distinct implements Explainable
5152
*
5253
* * comment (mixed): BSON value to attach as a comment to this command.
5354
*
54-
* This is not supported for servers versions < 4.4.
55+
* This is not supported for server versions < 4.4.
56+
*
57+
* * hint (string|document): The index to use. Specify either the index
58+
* name as a string or the index key pattern as a document. If specified,
59+
* then the query system will only consider plans using the hinted index.
60+
*
61+
* This is not supported for server versions < 7.1.
5562
*
5663
* * maxTimeMS (integer): The maximum amount of time to allow the query to
5764
* run.
@@ -81,6 +88,10 @@ public function __construct(private string $databaseName, private string $collec
8188
throw InvalidArgumentException::expectedDocumentType('"collation" option', $this->options['collation']);
8289
}
8390

91+
if (isset($this->options['hint']) && ! is_string($this->options['hint']) && ! is_document($this->options['hint'])) {
92+
throw InvalidArgumentException::invalidType('"hint" option', $this->options['hint'], 'string or array or object');
93+
}
94+
8495
if (isset($this->options['maxTimeMS']) && ! is_integer($this->options['maxTimeMS'])) {
8596
throw InvalidArgumentException::invalidType('"maxTimeMS" option', $this->options['maxTimeMS'], 'integer');
8697
}
@@ -170,6 +181,11 @@ private function createCommandDocument(): array
170181
$cmd['collation'] = (object) $this->options['collation'];
171182
}
172183

184+
if (isset($this->options['hint'])) {
185+
/** @psalm-var string|object */
186+
$cmd['hint'] = is_array($this->options['hint']) ? (object) $this->options['hint'] : $this->options['hint'];
187+
}
188+
173189
foreach (['comment', 'maxTimeMS'] as $option) {
174190
if (isset($this->options[$option])) {
175191
$cmd[$option] = $this->options[$option];

tests/Operation/DistinctFunctionalTest.php

+44
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,16 @@
33
namespace MongoDB\Tests\Operation;
44

55
use MongoDB\Driver\BulkWrite;
6+
use MongoDB\Operation\CreateIndexes;
67
use MongoDB\Operation\Distinct;
8+
use MongoDB\Operation\InsertMany;
79
use MongoDB\Tests\CommandObserver;
810
use PHPUnit\Framework\Attributes\DataProvider;
911
use stdClass;
1012

1113
use function is_scalar;
1214
use function json_encode;
15+
use function sort;
1316
use function usort;
1417

1518
use const JSON_THROW_ON_ERROR;
@@ -56,6 +59,47 @@ function (array $event): void {
5659
);
5760
}
5861

62+
public function testHintOption(): void
63+
{
64+
$this->skipIfServerVersion('<', '7.1.0', 'hint is not supported');
65+
66+
$insertMany = new InsertMany($this->getDatabaseName(), $this->getCollectionName(), [
67+
['x' => 1],
68+
['x' => 2, 'y' => 2],
69+
['y' => 3],
70+
]);
71+
$insertMany->execute($this->getPrimaryServer());
72+
73+
$createIndexes = new CreateIndexes($this->getDatabaseName(), $this->getCollectionName(), [
74+
['key' => ['x' => 1], 'sparse' => true, 'name' => 'sparse_x'],
75+
['key' => ['y' => 1]],
76+
]);
77+
$createIndexes->execute($this->getPrimaryServer());
78+
79+
$hintsUsingSparseIndex = [
80+
['x' => 1],
81+
'sparse_x',
82+
];
83+
84+
foreach ($hintsUsingSparseIndex as $hint) {
85+
$operation = new Distinct($this->getDatabaseName(), $this->getCollectionName(), 'y', [], ['hint' => $hint]);
86+
$this->assertSame([2], $operation->execute($this->getPrimaryServer()));
87+
}
88+
89+
$hintsNotUsingSparseIndex = [
90+
['_id' => 1],
91+
['y' => 1],
92+
'y_1',
93+
];
94+
95+
foreach ($hintsNotUsingSparseIndex as $hint) {
96+
$operation = new Distinct($this->getDatabaseName(), $this->getCollectionName(), 'x', [], ['hint' => $hint]);
97+
$values = $operation->execute($this->getPrimaryServer());
98+
sort($values);
99+
$this->assertSame([1, 2], $values);
100+
}
101+
}
102+
59103
public function testSessionOption(): void
60104
{
61105
(new CommandObserver())->observe(

tests/Operation/DistinctTest.php

+3
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ public static function provideInvalidConstructorOptions()
3030
{
3131
return self::createOptionDataProvider([
3232
'collation' => self::getInvalidDocumentValues(),
33+
'hint' => self::getInvalidHintValues(),
3334
'maxTimeMS' => self::getInvalidIntegerValues(),
3435
'readConcern' => self::getInvalidReadConcernValues(),
3536
'readPreference' => self::getInvalidReadPreferenceValues(),
@@ -42,6 +43,7 @@ public function testExplainableCommandDocument(): void
4243
{
4344
$options = [
4445
'collation' => ['locale' => 'fr'],
46+
'hint' => '_id_',
4547
'maxTimeMS' => 100,
4648
'readConcern' => new ReadConcern(ReadConcern::LOCAL),
4749
'comment' => 'explain me',
@@ -56,6 +58,7 @@ public function testExplainableCommandDocument(): void
5658
'key' => 'f',
5759
'query' => (object) ['x' => 1],
5860
'collation' => (object) ['locale' => 'fr'],
61+
'hint' => '_id_',
5962
'comment' => 'explain me',
6063
'maxTimeMS' => 100,
6164
'readConcern' => new ReadConcern(ReadConcern::LOCAL),

0 commit comments

Comments
 (0)