Skip to content

Commit

Permalink
PHPLIB-1143: Add search index operations to Collection class
Browse files Browse the repository at this point in the history
  • Loading branch information
GromNaN committed Jul 24, 2023
1 parent e3b6462 commit 0d3d54a
Show file tree
Hide file tree
Showing 27 changed files with 1,636 additions and 19 deletions.
23 changes: 23 additions & 0 deletions psalm-baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@
<code>($value is NativeType ? BSONType : $value)</code>
</MixedInferredReturnType>
</file>
<file src="src/Collection.php">
<MixedArgumentTypeCoercion>
<code>$options</code>
</MixedArgumentTypeCoercion>
</file>
<file src="src/Command/ListCollections.php">
<MixedAssignment>
<code>$cmd[$option]</code>
Expand Down Expand Up @@ -309,6 +314,14 @@
<code>isInTransaction</code>
</MixedMethodCall>
</file>
<file src="src/Operation/CreateSearchIndexes.php">
<MixedArgumentTypeCoercion>
<code>(array) $index</code>
</MixedArgumentTypeCoercion>
<MixedAssignment>
<code>$cmd[$option]</code>
</MixedAssignment>
</file>
<file src="src/Operation/DatabaseCommand.php">
<MixedArgument>
<code><![CDATA[$this->options['typeMap']]]></code>
Expand Down Expand Up @@ -389,6 +402,11 @@
<code>isInTransaction</code>
</MixedMethodCall>
</file>
<file src="src/Operation/DropSearchIndex.php">
<MixedAssignment>
<code>$cmd[$option]</code>
</MixedAssignment>
</file>
<file src="src/Operation/Explain.php">
<MixedArgument>
<code><![CDATA[$this->options['typeMap']]]></code>
Expand Down Expand Up @@ -537,6 +555,11 @@
<code>isInTransaction</code>
</MixedMethodCall>
</file>
<file src="src/Operation/UpdateSearchIndex.php">
<MixedAssignment>
<code>$cmd[$option]</code>
</MixedAssignment>
</file>
<file src="src/Operation/Watch.php">
<MixedArgument>
<code><![CDATA[$reply->cursor->firstBatch]]></code>
Expand Down
127 changes: 127 additions & 0 deletions src/Collection.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@

namespace MongoDB;

use Countable;
use Iterator;
use MongoDB\BSON\JavascriptInterface;
use MongoDB\Driver\Cursor;
use MongoDB\Driver\Exception\CommandException;
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
use MongoDB\Driver\Manager;
use MongoDB\Driver\ReadConcern;
Expand All @@ -36,12 +39,14 @@
use MongoDB\Operation\Count;
use MongoDB\Operation\CountDocuments;
use MongoDB\Operation\CreateIndexes;
use MongoDB\Operation\CreateSearchIndexes;
use MongoDB\Operation\DeleteMany;
use MongoDB\Operation\DeleteOne;
use MongoDB\Operation\Distinct;
use MongoDB\Operation\DropCollection;
use MongoDB\Operation\DropEncryptedCollection;
use MongoDB\Operation\DropIndexes;
use MongoDB\Operation\DropSearchIndex;
use MongoDB\Operation\EstimatedDocumentCount;
use MongoDB\Operation\Explain;
use MongoDB\Operation\Explainable;
Expand All @@ -53,11 +58,13 @@
use MongoDB\Operation\InsertMany;
use MongoDB\Operation\InsertOne;
use MongoDB\Operation\ListIndexes;
use MongoDB\Operation\ListSearchIndexes;
use MongoDB\Operation\MapReduce;
use MongoDB\Operation\RenameCollection;
use MongoDB\Operation\ReplaceOne;
use MongoDB\Operation\UpdateMany;
use MongoDB\Operation\UpdateOne;
use MongoDB\Operation\UpdateSearchIndex;
use MongoDB\Operation\Watch;

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

/**
* Create an Atlas Search index for the collection.
* Only available when used against a 7.0+ Atlas cluster.
*
* @see https://www.mongodb.com/docs/manual/reference/command/createSearchIndexes/
* @see https://mongodb.com/docs/manual/reference/method/db.collection.createSearchIndex/
* @param array|object $definition Atlas Search index mapping definition
* @param array{name?: string, comment?: mixed} $options Command options
* @return string The name of the created search index
* @throws UnsupportedException if options are not supported by the selected server
* @throws InvalidArgumentException for parameter/option parsing errors
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
*/
public function createSearchIndex($definition, array $options = []): string
{
$index = ['definition' => $definition];
if (isset($options['name'])) {
$index['name'] = $options['name'];
unset($options['name']);
}

$names = $this->createSearchIndexes([$index], $options);

return current($names);
}

/**
* Create one or more Atlas Search indexes for the collection.
* Only available when used against a 7.0+ Atlas cluster.
*
* Each element in the $indexes array must have "definition" document and they may have a "name" string.
* The name can be omitted for a single index, in which case a name will be the default.
* For example:
*
* $indexes = [
* // Create a search index with the default name, on
* ['definition' => ['mappings' => ['dynamic' => false, 'fields' => ['title' => ['type' => 'string']]]]],
* // Create a named search index on all fields
* ['name' => 'search_all', 'definition' => ['mappings' => ['dynamic' => true]]],
* ];
*
* @see https://www.mongodb.com/docs/manual/reference/command/createSearchIndexes/
* @see https://mongodb.com/docs/manual/reference/method/db.collection.createSearchIndex/
* @param list<array{name?: string, definition: array|object}> $indexes List of search index specifications
* @param array{comment?: string} $options Command options
* @return string[] The names of the created search indexes
* @throws UnsupportedException if options are not supported by the selected server
* @throws InvalidArgumentException for parameter/option parsing errors
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
*/
public function createSearchIndexes(array $indexes, array $options = []): array
{
$operation = new CreateSearchIndexes($this->databaseName, $this->collectionName, $indexes, $options);
$server = select_server($this->manager, $options);

return $operation->execute($server);
}

/**
* Deletes all documents matching the filter.
*
Expand Down Expand Up @@ -554,6 +619,31 @@ public function dropIndexes(array $options = [])
return $operation->execute($server);
}

/**
* Drop a single Atlas Search index in the collection.
* Only available when used against a 7.0+ Atlas cluster.
*
* @param string $name Search index name
* @param array{comment?: mixed} $options Additional options
* @throws UnsupportedException if options are not supported by the selected server
* @throws InvalidArgumentException for parameter/option parsing errors
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
*/
public function dropSearchIndex(string $name, array $options = []): void
{
$operation = new DropSearchIndex($this->databaseName, $this->collectionName, $name);
$server = select_server($this->manager, $options);

try {
$operation->execute($server);
} catch (CommandException $e) {
// Suppress namespace not found errors for idempotency
if ($e->getCode() !== 26) {
throw $e;
}
}
}

/**
* Gets an estimated number of documents in the collection using the collection metadata.
*
Expand Down Expand Up @@ -928,6 +1018,24 @@ public function listIndexes(array $options = [])
return $operation->execute($server);
}

/**
* Returns information for all Atlas Search indexes for the collection.
* Only available when used against a 7.0+ Atlas cluster.
*
* @param array{name?: string} $options Command options
* @return Countable&Iterator<array{id: string, name: string, status: string, queryable: bool, latestDefinition: array}>
* @throws InvalidArgumentException for parameter/option parsing errors
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
* @see ListSearchIndexes::__construct() for supported options
*/
public function listSearchIndexes(array $options = []): Iterator
{
$operation = new ListSearchIndexes($this->databaseName, $this->collectionName, $options);
$server = select_server($this->manager, $options);

return $operation->execute($server);
}

/**
* Executes a map-reduce aggregation on the collection.
*
Expand Down Expand Up @@ -1088,6 +1196,25 @@ public function updateOne($filter, $update, array $options = [])
return $operation->execute($server);
}

/**
* Update a single Atlas Search index in the collection.
* Only available when used against a 7.0+ Atlas cluster.
*
* @param string $name Search index name
* @param array|object $definition Atlas Search index definition
* @param array{comment?: mixed} $options Command options
* @throws UnsupportedException if options are not supported by the selected server
* @throws InvalidArgumentException for parameter parsing errors
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
*/
public function updateSearchIndex(string $name, $definition, array $options = []): void
{
$operation = new UpdateSearchIndex($this->databaseName, $this->collectionName, $name, $definition, $options);
$server = select_server($this->manager, $options);

$operation->execute($server);
}

/**
* Create a change stream for watching changes to the collection.
*
Expand Down
4 changes: 2 additions & 2 deletions src/Model/IndexInput.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,9 @@ public function __toString(): string
* @see \MongoDB\Collection::createIndexes()
* @see https://php.net/mongodb-bson-serializable.bsonserialize
*/
public function bsonSerialize(): array
public function bsonSerialize(): object
{
return $this->index;
return (object) $this->index;
}

/**
Expand Down
73 changes: 73 additions & 0 deletions src/Model/SearchIndexInput.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<?php
/*
* Copyright 2015-present MongoDB, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

namespace MongoDB\Model;

use MongoDB\BSON\Serializable;
use MongoDB\Exception\InvalidArgumentException;

use function is_string;
use function MongoDB\is_document;

/**
* Search index input model class.
*
* This class is used to validate user input for search index creation.
*
* @internal
* @see \MongoDB\Collection::createSearchIndexes()
* @see https://github.com/mongodb/specifications/blob/master/source/index-management/index-management.rst#search-indexes
* @see https://mongodb.com/docs/manual/reference/method/db.collection.createSearchIndex/
*/
class SearchIndexInput implements Serializable
{
/** @var array */
private array $index;

/**
* @param array{name?: string, definition: array|object} $index Search index specification
* @throws InvalidArgumentException
*/
public function __construct(array $index)
{
if (! isset($index['definition'])) {
throw new InvalidArgumentException('Required "definition" document is missing from search index specification');
}

if (! is_document($index['definition'])) {
throw InvalidArgumentException::expectedDocumentType('"definition" option', $index['definition']);
}

// Name is optional, but must be a non-empty string if provided
if (isset($index['name']) && ! is_string($index['name'])) {
throw InvalidArgumentException::invalidType('"name" option', $index['name'], 'string');
}

$this->index = $index;
}

/**
* Serialize the search index information to BSON for search index creation.
*
* @see \MongoDB\Collection::createSearchIndexes()
* @see https://php.net/mongodb-bson-serializable.bsonserialize
*/
public function bsonSerialize(): object
{
return (object) $this->index;
}
}
Loading

0 comments on commit 0d3d54a

Please sign in to comment.