Skip to content

Commit 0c31932

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

28 files changed

+1660
-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>
@@ -317,6 +322,14 @@
317322
<code>isInTransaction</code>
318323
</MixedMethodCall>
319324
</file>
325+
<file src="src/Operation/CreateSearchIndexes.php">
326+
<MixedArgumentTypeCoercion>
327+
<code>(array) $index</code>
328+
</MixedArgumentTypeCoercion>
329+
<MixedAssignment>
330+
<code>$cmd[$option]</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>$cmd[$option]</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>$cmd[$option]</code>
600+
</MixedAssignment>
601+
</file>
579602
<file src="src/Operation/Watch.php">
580603
<MixedArgument>
581604
<code><![CDATA[$reply->cursor->firstBatch]]></code>

src/Collection.php

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,12 @@
1717

1818
namespace MongoDB;
1919

20+
use Countable;
2021
use Iterator;
2122
use MongoDB\BSON\JavascriptInterface;
2223
use MongoDB\Codec\DocumentCodec;
2324
use MongoDB\Driver\CursorInterface;
25+
use MongoDB\Driver\Exception\CommandException;
2426
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
2527
use MongoDB\Driver\Manager;
2628
use MongoDB\Driver\ReadConcern;
@@ -38,12 +40,14 @@
3840
use MongoDB\Operation\Count;
3941
use MongoDB\Operation\CountDocuments;
4042
use MongoDB\Operation\CreateIndexes;
43+
use MongoDB\Operation\CreateSearchIndexes;
4144
use MongoDB\Operation\DeleteMany;
4245
use MongoDB\Operation\DeleteOne;
4346
use MongoDB\Operation\Distinct;
4447
use MongoDB\Operation\DropCollection;
4548
use MongoDB\Operation\DropEncryptedCollection;
4649
use MongoDB\Operation\DropIndexes;
50+
use MongoDB\Operation\DropSearchIndex;
4751
use MongoDB\Operation\EstimatedDocumentCount;
4852
use MongoDB\Operation\Explain;
4953
use MongoDB\Operation\Explainable;
@@ -55,11 +59,13 @@
5559
use MongoDB\Operation\InsertMany;
5660
use MongoDB\Operation\InsertOne;
5761
use MongoDB\Operation\ListIndexes;
62+
use MongoDB\Operation\ListSearchIndexes;
5863
use MongoDB\Operation\MapReduce;
5964
use MongoDB\Operation\RenameCollection;
6065
use MongoDB\Operation\ReplaceOne;
6166
use MongoDB\Operation\UpdateMany;
6267
use MongoDB\Operation\UpdateOne;
68+
use MongoDB\Operation\UpdateSearchIndex;
6369
use MongoDB\Operation\Watch;
6470

6571
use function array_diff_key;
@@ -360,6 +366,64 @@ public function createIndexes(array $indexes, array $options = [])
360366
return $operation->execute(select_server($this->manager, $options));
361367
}
362368

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

568+
/**
569+
* Drop a single Atlas Search index in the collection.
570+
* Only available when used against a 7.0+ Atlas cluster.
571+
*
572+
* @param string $name Search index name
573+
* @param array{comment?: mixed} $options Additional options
574+
* @throws UnsupportedException if options are not supported by the selected server
575+
* @throws InvalidArgumentException for parameter/option parsing errors
576+
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
577+
*/
578+
public function dropSearchIndex(string $name, array $options = []): void
579+
{
580+
$operation = new DropSearchIndex($this->databaseName, $this->collectionName, $name);
581+
$server = select_server($this->manager, $options);
582+
583+
try {
584+
$operation->execute($server);
585+
} catch (CommandException $e) {
586+
// Suppress namespace not found errors for idempotency
587+
if ($e->getCode() !== 26) {
588+
throw $e;
589+
}
590+
}
591+
}
592+
504593
/**
505594
* Gets an estimated number of documents in the collection using the collection metadata.
506595
*
@@ -812,6 +901,24 @@ public function listIndexes(array $options = [])
812901
return $operation->execute(select_server($this->manager, $options));
813902
}
814903

904+
/**
905+
* Returns information for all Atlas Search indexes for the collection.
906+
* Only available when used against a 7.0+ Atlas cluster.
907+
*
908+
* @param array{name?: string} $options Command options
909+
* @return Countable&Iterator<array{id: string, name: string, status: string, queryable: bool, latestDefinition: array}>
910+
* @throws InvalidArgumentException for parameter/option parsing errors
911+
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
912+
* @see ListSearchIndexes::__construct() for supported options
913+
*/
914+
public function listSearchIndexes(array $options = []): Iterator
915+
{
916+
$operation = new ListSearchIndexes($this->databaseName, $this->collectionName, $options);
917+
$server = select_server($this->manager, $options);
918+
919+
return $operation->execute($server);
920+
}
921+
815922
/**
816923
* Executes a map-reduce aggregation on the collection.
817924
*
@@ -946,6 +1053,25 @@ public function updateOne($filter, $update, array $options = [])
9461053
return $operation->execute(select_server($this->manager, $options));
9471054
}
9481055

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

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)