Skip to content

Commit 0d3d54a

Browse files
committed
PHPLIB-1143: Add search index operations to Collection class
Sync with mongodb/specifications@78554de
1 parent e3b6462 commit 0d3d54a

27 files changed

+1636
-19
lines changed

psalm-baseline.xml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@
2828
<code>($value is NativeType ? BSONType : $value)</code>
2929
</MixedInferredReturnType>
3030
</file>
31+
<file src="src/Collection.php">
32+
<MixedArgumentTypeCoercion>
33+
<code>$options</code>
34+
</MixedArgumentTypeCoercion>
35+
</file>
3136
<file src="src/Command/ListCollections.php">
3237
<MixedAssignment>
3338
<code>$cmd[$option]</code>
@@ -309,6 +314,14 @@
309314
<code>isInTransaction</code>
310315
</MixedMethodCall>
311316
</file>
317+
<file src="src/Operation/CreateSearchIndexes.php">
318+
<MixedArgumentTypeCoercion>
319+
<code>(array) $index</code>
320+
</MixedArgumentTypeCoercion>
321+
<MixedAssignment>
322+
<code>$cmd[$option]</code>
323+
</MixedAssignment>
324+
</file>
312325
<file src="src/Operation/DatabaseCommand.php">
313326
<MixedArgument>
314327
<code><![CDATA[$this->options['typeMap']]]></code>
@@ -389,6 +402,11 @@
389402
<code>isInTransaction</code>
390403
</MixedMethodCall>
391404
</file>
405+
<file src="src/Operation/DropSearchIndex.php">
406+
<MixedAssignment>
407+
<code>$cmd[$option]</code>
408+
</MixedAssignment>
409+
</file>
392410
<file src="src/Operation/Explain.php">
393411
<MixedArgument>
394412
<code><![CDATA[$this->options['typeMap']]]></code>
@@ -537,6 +555,11 @@
537555
<code>isInTransaction</code>
538556
</MixedMethodCall>
539557
</file>
558+
<file src="src/Operation/UpdateSearchIndex.php">
559+
<MixedAssignment>
560+
<code>$cmd[$option]</code>
561+
</MixedAssignment>
562+
</file>
540563
<file src="src/Operation/Watch.php">
541564
<MixedArgument>
542565
<code><![CDATA[$reply->cursor->firstBatch]]></code>

src/Collection.php

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,11 @@
1717

1818
namespace MongoDB;
1919

20+
use Countable;
21+
use Iterator;
2022
use MongoDB\BSON\JavascriptInterface;
2123
use MongoDB\Driver\Cursor;
24+
use MongoDB\Driver\Exception\CommandException;
2225
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
2326
use MongoDB\Driver\Manager;
2427
use MongoDB\Driver\ReadConcern;
@@ -36,12 +39,14 @@
3639
use MongoDB\Operation\Count;
3740
use MongoDB\Operation\CountDocuments;
3841
use MongoDB\Operation\CreateIndexes;
42+
use MongoDB\Operation\CreateSearchIndexes;
3943
use MongoDB\Operation\DeleteMany;
4044
use MongoDB\Operation\DeleteOne;
4145
use MongoDB\Operation\Distinct;
4246
use MongoDB\Operation\DropCollection;
4347
use MongoDB\Operation\DropEncryptedCollection;
4448
use MongoDB\Operation\DropIndexes;
49+
use MongoDB\Operation\DropSearchIndex;
4550
use MongoDB\Operation\EstimatedDocumentCount;
4651
use MongoDB\Operation\Explain;
4752
use MongoDB\Operation\Explainable;
@@ -53,11 +58,13 @@
5358
use MongoDB\Operation\InsertMany;
5459
use MongoDB\Operation\InsertOne;
5560
use MongoDB\Operation\ListIndexes;
61+
use MongoDB\Operation\ListSearchIndexes;
5662
use MongoDB\Operation\MapReduce;
5763
use MongoDB\Operation\RenameCollection;
5864
use MongoDB\Operation\ReplaceOne;
5965
use MongoDB\Operation\UpdateMany;
6066
use MongoDB\Operation\UpdateOne;
67+
use MongoDB\Operation\UpdateSearchIndex;
6168
use MongoDB\Operation\Watch;
6269

6370
use function array_diff_key;
@@ -377,6 +384,64 @@ public function createIndexes(array $indexes, array $options = [])
377384
return $operation->execute($server);
378385
}
379386

387+
/**
388+
* Create an Atlas Search index for the collection.
389+
* Only available when used against a 7.0+ Atlas cluster.
390+
*
391+
* @see https://www.mongodb.com/docs/manual/reference/command/createSearchIndexes/
392+
* @see https://mongodb.com/docs/manual/reference/method/db.collection.createSearchIndex/
393+
* @param array|object $definition Atlas Search index mapping definition
394+
* @param array{name?: string, comment?: mixed} $options Command options
395+
* @return string The name of the created search index
396+
* @throws UnsupportedException if options are not supported by the selected server
397+
* @throws InvalidArgumentException for parameter/option parsing errors
398+
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
399+
*/
400+
public function createSearchIndex($definition, array $options = []): string
401+
{
402+
$index = ['definition' => $definition];
403+
if (isset($options['name'])) {
404+
$index['name'] = $options['name'];
405+
unset($options['name']);
406+
}
407+
408+
$names = $this->createSearchIndexes([$index], $options);
409+
410+
return current($names);
411+
}
412+
413+
/**
414+
* Create one or more Atlas Search indexes for the collection.
415+
* Only available when used against a 7.0+ Atlas cluster.
416+
*
417+
* Each element in the $indexes array must have "definition" document and they may have a "name" string.
418+
* The name can be omitted for a single index, in which case a name will be the default.
419+
* For example:
420+
*
421+
* $indexes = [
422+
* // Create a search index with the default name, on
423+
* ['definition' => ['mappings' => ['dynamic' => false, 'fields' => ['title' => ['type' => 'string']]]]],
424+
* // Create a named search index on all fields
425+
* ['name' => 'search_all', 'definition' => ['mappings' => ['dynamic' => true]]],
426+
* ];
427+
*
428+
* @see https://www.mongodb.com/docs/manual/reference/command/createSearchIndexes/
429+
* @see https://mongodb.com/docs/manual/reference/method/db.collection.createSearchIndex/
430+
* @param list<array{name?: string, definition: array|object}> $indexes List of search index specifications
431+
* @param array{comment?: string} $options Command options
432+
* @return string[] The names of the created search indexes
433+
* @throws UnsupportedException if options are not supported by the selected server
434+
* @throws InvalidArgumentException for parameter/option parsing errors
435+
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
436+
*/
437+
public function createSearchIndexes(array $indexes, array $options = []): array
438+
{
439+
$operation = new CreateSearchIndexes($this->databaseName, $this->collectionName, $indexes, $options);
440+
$server = select_server($this->manager, $options);
441+
442+
return $operation->execute($server);
443+
}
444+
380445
/**
381446
* Deletes all documents matching the filter.
382447
*
@@ -554,6 +619,31 @@ public function dropIndexes(array $options = [])
554619
return $operation->execute($server);
555620
}
556621

622+
/**
623+
* Drop a single Atlas Search index in the collection.
624+
* Only available when used against a 7.0+ Atlas cluster.
625+
*
626+
* @param string $name Search index name
627+
* @param array{comment?: mixed} $options Additional options
628+
* @throws UnsupportedException if options are not supported by the selected server
629+
* @throws InvalidArgumentException for parameter/option parsing errors
630+
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
631+
*/
632+
public function dropSearchIndex(string $name, array $options = []): void
633+
{
634+
$operation = new DropSearchIndex($this->databaseName, $this->collectionName, $name);
635+
$server = select_server($this->manager, $options);
636+
637+
try {
638+
$operation->execute($server);
639+
} catch (CommandException $e) {
640+
// Suppress namespace not found errors for idempotency
641+
if ($e->getCode() !== 26) {
642+
throw $e;
643+
}
644+
}
645+
}
646+
557647
/**
558648
* Gets an estimated number of documents in the collection using the collection metadata.
559649
*
@@ -928,6 +1018,24 @@ public function listIndexes(array $options = [])
9281018
return $operation->execute($server);
9291019
}
9301020

1021+
/**
1022+
* Returns information for all Atlas Search indexes for the collection.
1023+
* Only available when used against a 7.0+ Atlas cluster.
1024+
*
1025+
* @param array{name?: string} $options Command options
1026+
* @return Countable&Iterator<array{id: string, name: string, status: string, queryable: bool, latestDefinition: array}>
1027+
* @throws InvalidArgumentException for parameter/option parsing errors
1028+
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
1029+
* @see ListSearchIndexes::__construct() for supported options
1030+
*/
1031+
public function listSearchIndexes(array $options = []): Iterator
1032+
{
1033+
$operation = new ListSearchIndexes($this->databaseName, $this->collectionName, $options);
1034+
$server = select_server($this->manager, $options);
1035+
1036+
return $operation->execute($server);
1037+
}
1038+
9311039
/**
9321040
* Executes a map-reduce aggregation on the collection.
9331041
*
@@ -1088,6 +1196,25 @@ public function updateOne($filter, $update, array $options = [])
10881196
return $operation->execute($server);
10891197
}
10901198

1199+
/**
1200+
* Update a single Atlas Search index in the collection.
1201+
* Only available when used against a 7.0+ Atlas cluster.
1202+
*
1203+
* @param string $name Search index name
1204+
* @param array|object $definition Atlas Search index definition
1205+
* @param array{comment?: mixed} $options Command options
1206+
* @throws UnsupportedException if options are not supported by the selected server
1207+
* @throws InvalidArgumentException for parameter parsing errors
1208+
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
1209+
*/
1210+
public function updateSearchIndex(string $name, $definition, array $options = []): void
1211+
{
1212+
$operation = new UpdateSearchIndex($this->databaseName, $this->collectionName, $name, $definition, $options);
1213+
$server = select_server($this->manager, $options);
1214+
1215+
$operation->execute($server);
1216+
}
1217+
10911218
/**
10921219
* Create a change stream for watching changes to the collection.
10931220
*

src/Model/IndexInput.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,9 @@ public function __toString(): string
8686
* @see \MongoDB\Collection::createIndexes()
8787
* @see https://php.net/mongodb-bson-serializable.bsonserialize
8888
*/
89-
public function bsonSerialize(): array
89+
public function bsonSerialize(): object
9090
{
91-
return $this->index;
91+
return (object) $this->index;
9292
}
9393

9494
/**

src/Model/SearchIndexInput.php

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<?php
2+
/*
3+
* Copyright 2015-present MongoDB, Inc.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* https://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
namespace MongoDB\Model;
19+
20+
use MongoDB\BSON\Serializable;
21+
use MongoDB\Exception\InvalidArgumentException;
22+
23+
use function is_string;
24+
use function MongoDB\is_document;
25+
26+
/**
27+
* Search index input model class.
28+
*
29+
* This class is used to validate user input for search index creation.
30+
*
31+
* @internal
32+
* @see \MongoDB\Collection::createSearchIndexes()
33+
* @see https://github.com/mongodb/specifications/blob/master/source/index-management/index-management.rst#search-indexes
34+
* @see https://mongodb.com/docs/manual/reference/method/db.collection.createSearchIndex/
35+
*/
36+
class SearchIndexInput implements Serializable
37+
{
38+
/** @var array */
39+
private array $index;
40+
41+
/**
42+
* @param array{name?: string, definition: array|object} $index Search index specification
43+
* @throws InvalidArgumentException
44+
*/
45+
public function __construct(array $index)
46+
{
47+
if (! isset($index['definition'])) {
48+
throw new InvalidArgumentException('Required "definition" document is missing from search index specification');
49+
}
50+
51+
if (! is_document($index['definition'])) {
52+
throw InvalidArgumentException::expectedDocumentType('"definition" option', $index['definition']);
53+
}
54+
55+
// Name is optional, but must be a non-empty string if provided
56+
if (isset($index['name']) && ! is_string($index['name'])) {
57+
throw InvalidArgumentException::invalidType('"name" option', $index['name'], 'string');
58+
}
59+
60+
$this->index = $index;
61+
}
62+
63+
/**
64+
* Serialize the search index information to BSON for search index creation.
65+
*
66+
* @see \MongoDB\Collection::createSearchIndexes()
67+
* @see https://php.net/mongodb-bson-serializable.bsonserialize
68+
*/
69+
public function bsonSerialize(): object
70+
{
71+
return (object) $this->index;
72+
}
73+
}

0 commit comments

Comments
 (0)