Skip to content

Commit f6ce211

Browse files
authored
PHPLIB-1143: Add search index operations to Collection class (#1097)
Unified spec tests sync with mongodb/specifications@267a54d Create CreateSearchIndexes, DropSearchIndex and UpdateSearchIndex operation classes Create methods createSearchIndex, createSearchIndexes, dropSearchIndex, updateSearchIndex, listSearchIndexes in Collection class. Currently only Atlas M10+ clusters are supported.
1 parent a7a7682 commit f6ce211

29 files changed

+1687
-27
lines changed

psalm-baseline.xml

+23
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>
@@ -317,6 +322,14 @@
317322
<code>isInTransaction</code>
318323
</MixedMethodCall>
319324
</file>
325+
<file src="src/Operation/CreateSearchIndexes.php">
326+
<MixedArgumentTypeCoercion>
327+
<code>$index</code>
328+
</MixedArgumentTypeCoercion>
329+
<MixedAssignment>
330+
<code><![CDATA[$cmd['comment']]]></code>
331+
</MixedAssignment>
332+
</file>
320333
<file src="src/Operation/DatabaseCommand.php">
321334
<MixedArgument>
322335
<code><![CDATA[$this->options['typeMap']]]></code>
@@ -397,6 +410,11 @@
397410
<code>isInTransaction</code>
398411
</MixedMethodCall>
399412
</file>
413+
<file src="src/Operation/DropSearchIndex.php">
414+
<MixedAssignment>
415+
<code><![CDATA[$cmd['comment']]]></code>
416+
</MixedAssignment>
417+
</file>
400418
<file src="src/Operation/Explain.php">
401419
<MixedArgument>
402420
<code><![CDATA[$this->options['typeMap']]]></code>
@@ -576,6 +594,11 @@
576594
<code>isInTransaction</code>
577595
</MixedMethodCall>
578596
</file>
597+
<file src="src/Operation/UpdateSearchIndex.php">
598+
<MixedAssignment>
599+
<code><![CDATA[$cmd['comment']]]></code>
600+
</MixedAssignment>
601+
</file>
579602
<file src="src/Operation/Watch.php">
580603
<MixedArgument>
581604
<code><![CDATA[$reply->cursor->firstBatch]]></code>

src/Collection.php

+118
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
namespace MongoDB;
1919

20+
use Countable;
2021
use Iterator;
2122
use MongoDB\BSON\JavascriptInterface;
2223
use MongoDB\Codec\DocumentCodec;
@@ -38,12 +39,14 @@
3839
use MongoDB\Operation\Count;
3940
use MongoDB\Operation\CountDocuments;
4041
use MongoDB\Operation\CreateIndexes;
42+
use MongoDB\Operation\CreateSearchIndexes;
4143
use MongoDB\Operation\DeleteMany;
4244
use MongoDB\Operation\DeleteOne;
4345
use MongoDB\Operation\Distinct;
4446
use MongoDB\Operation\DropCollection;
4547
use MongoDB\Operation\DropEncryptedCollection;
4648
use MongoDB\Operation\DropIndexes;
49+
use MongoDB\Operation\DropSearchIndex;
4750
use MongoDB\Operation\EstimatedDocumentCount;
4851
use MongoDB\Operation\Explain;
4952
use MongoDB\Operation\Explainable;
@@ -55,11 +58,13 @@
5558
use MongoDB\Operation\InsertMany;
5659
use MongoDB\Operation\InsertOne;
5760
use MongoDB\Operation\ListIndexes;
61+
use MongoDB\Operation\ListSearchIndexes;
5862
use MongoDB\Operation\MapReduce;
5963
use MongoDB\Operation\RenameCollection;
6064
use MongoDB\Operation\ReplaceOne;
6165
use MongoDB\Operation\UpdateMany;
6266
use MongoDB\Operation\UpdateOne;
67+
use MongoDB\Operation\UpdateSearchIndex;
6368
use MongoDB\Operation\Watch;
6469

6570
use function array_diff_key;
@@ -360,6 +365,64 @@ public function createIndexes(array $indexes, array $options = [])
360365
return $operation->execute(select_server($this->manager, $options));
361366
}
362367

368+
/**
369+
* Create an Atlas Search index for the collection.
370+
* Only available when used against a 7.0+ Atlas cluster.
371+
*
372+
* @see https://www.mongodb.com/docs/manual/reference/command/createSearchIndexes/
373+
* @see https://mongodb.com/docs/manual/reference/method/db.collection.createSearchIndex/
374+
* @param array|object $definition Atlas Search index mapping definition
375+
* @param array{name?: string, comment?: mixed} $options Command options
376+
* @return string The name of the created search index
377+
* @throws UnsupportedException if options are not supported by the selected server
378+
* @throws InvalidArgumentException for parameter/option parsing errors
379+
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
380+
*/
381+
public function createSearchIndex($definition, array $options = []): string
382+
{
383+
$index = ['definition' => $definition];
384+
if (isset($options['name'])) {
385+
$index['name'] = $options['name'];
386+
unset($options['name']);
387+
}
388+
389+
$names = $this->createSearchIndexes([$index], $options);
390+
391+
return current($names);
392+
}
393+
394+
/**
395+
* Create one or more Atlas Search indexes for the collection.
396+
* Only available when used against a 7.0+ Atlas cluster.
397+
*
398+
* Each element in the $indexes array must have "definition" document and they may have a "name" string.
399+
* The name can be omitted for a single index, in which case a name will be the default.
400+
* For example:
401+
*
402+
* $indexes = [
403+
* // Create a search index with the default name, on
404+
* ['definition' => ['mappings' => ['dynamic' => false, 'fields' => ['title' => ['type' => 'string']]]]],
405+
* // Create a named search index on all fields
406+
* ['name' => 'search_all', 'definition' => ['mappings' => ['dynamic' => true]]],
407+
* ];
408+
*
409+
* @see https://www.mongodb.com/docs/manual/reference/command/createSearchIndexes/
410+
* @see https://mongodb.com/docs/manual/reference/method/db.collection.createSearchIndex/
411+
* @param list<array{name?: string, definition: array|object}> $indexes List of search index specifications
412+
* @param array{comment?: string} $options Command options
413+
* @return string[] The names of the created search indexes
414+
* @throws UnsupportedException if options are not supported by the selected server
415+
* @throws InvalidArgumentException for parameter/option parsing errors
416+
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
417+
*/
418+
public function createSearchIndexes(array $indexes, array $options = []): array
419+
{
420+
$operation = new CreateSearchIndexes($this->databaseName, $this->collectionName, $indexes, $options);
421+
$server = select_server($this->manager, $options);
422+
423+
return $operation->execute($server);
424+
}
425+
363426
/**
364427
* Deletes all documents matching the filter.
365428
*
@@ -501,6 +564,24 @@ public function dropIndexes(array $options = [])
501564
return $operation->execute(select_server($this->manager, $options));
502565
}
503566

567+
/**
568+
* Drop a single Atlas Search index in the collection.
569+
* Only available when used against a 7.0+ Atlas cluster.
570+
*
571+
* @param string $name Search index name
572+
* @param array{comment?: mixed} $options Additional options
573+
* @throws UnsupportedException if options are not supported by the selected server
574+
* @throws InvalidArgumentException for parameter/option parsing errors
575+
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
576+
*/
577+
public function dropSearchIndex(string $name, array $options = []): void
578+
{
579+
$operation = new DropSearchIndex($this->databaseName, $this->collectionName, $name);
580+
$server = select_server($this->manager, $options);
581+
582+
$operation->execute($server);
583+
}
584+
504585
/**
505586
* Gets an estimated number of documents in the collection using the collection metadata.
506587
*
@@ -812,6 +893,24 @@ public function listIndexes(array $options = [])
812893
return $operation->execute(select_server($this->manager, $options));
813894
}
814895

896+
/**
897+
* Returns information for all Atlas Search indexes for the collection.
898+
* Only available when used against a 7.0+ Atlas cluster.
899+
*
900+
* @param array{name?: string} $options Command options
901+
* @return Countable&Iterator
902+
* @throws InvalidArgumentException for parameter/option parsing errors
903+
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
904+
* @see ListSearchIndexes::__construct() for supported options
905+
*/
906+
public function listSearchIndexes(array $options = []): Iterator
907+
{
908+
$operation = new ListSearchIndexes($this->databaseName, $this->collectionName, $options);
909+
$server = select_server($this->manager, $options);
910+
911+
return $operation->execute($server);
912+
}
913+
815914
/**
816915
* Executes a map-reduce aggregation on the collection.
817916
*
@@ -946,6 +1045,25 @@ public function updateOne($filter, $update, array $options = [])
9461045
return $operation->execute(select_server($this->manager, $options));
9471046
}
9481047

1048+
/**
1049+
* Update a single Atlas Search index in the collection.
1050+
* Only available when used against a 7.0+ Atlas cluster.
1051+
*
1052+
* @param string $name Search index name
1053+
* @param array|object $definition Atlas Search index definition
1054+
* @param array{comment?: mixed} $options Command options
1055+
* @throws UnsupportedException if options are not supported by the selected server
1056+
* @throws InvalidArgumentException for parameter parsing errors
1057+
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
1058+
*/
1059+
public function updateSearchIndex(string $name, $definition, array $options = []): void
1060+
{
1061+
$operation = new UpdateSearchIndex($this->databaseName, $this->collectionName, $name, $definition, $options);
1062+
$server = select_server($this->manager, $options);
1063+
1064+
$operation->execute($server);
1065+
}
1066+
9491067
/**
9501068
* Create a change stream for watching changes to the collection.
9511069
*

src/Model/IndexInput.php

+2-2
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

+73
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)