Skip to content

Merge v1.20 into master #1380

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Sep 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 1 addition & 6 deletions psalm-baseline.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<files psalm-version="5.26.0@4787eaf414e16c661902b94dfe5d882223e5b513">
<files psalm-version="5.25.0@01a8eb06b9e9cc6cfb6a320bf9fb14331919d505">
<file src="examples/atlas_search.php">
<MixedArgument>
<code><![CDATA[$document['name']]]></code>
Expand Down Expand Up @@ -216,11 +216,6 @@
<code><![CDATA[$value]]></code>
</MixedArgumentTypeCoercion>
</file>
<file src="src/Collection.php">
<MixedArgumentTypeCoercion>
<code><![CDATA[$options]]></code>
</MixedArgumentTypeCoercion>
</file>
<file src="src/Command/ListCollections.php">
<MixedAssignment>
<code><![CDATA[$cmd[$option]]]></code>
Expand Down
22 changes: 11 additions & 11 deletions src/Collection.php
Original file line number Diff line number Diff line change
Expand Up @@ -361,22 +361,22 @@ public function createIndexes(array $indexes, array $options = [])
*
* @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
* @param array|object $definition Atlas Search index mapping definition
* @param array{comment?: mixed, name?: string, type?: string} $options Index and 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(array|object $definition, array $options = []): string
{
$index = ['definition' => $definition];
if (isset($options['name'])) {
$index['name'] = $options['name'];
unset($options['name']);
}
$indexOptionKeys = ['name' => 1, 'type' => 1];
/** @psalm-var array{name?: string, type?: string} */
$indexOptions = array_intersect_key($options, $indexOptionKeys);
/** @psalm-var array{comment?: mixed} */
$operationOptions = array_diff_key($options, $indexOptionKeys);

$names = $this->createSearchIndexes([$index], $options);
$names = $this->createSearchIndexes([['definition' => $definition] + $indexOptions], $operationOptions);

return current($names);
}
Expand All @@ -390,16 +390,16 @@ public function createSearchIndex(array|object $definition, array $options = [])
* For example:
*
* $indexes = [
* // Create a search index with the default name, on
* // Create a search index with the default name on a single field
* ['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
* @param list<array{definition: array|object, name?: string, type?: string}> $indexes List of search index specifications
* @param array{comment?: mixed} $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
Expand Down
6 changes: 5 additions & 1 deletion src/Model/SearchIndexInput.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
class SearchIndexInput implements Serializable
{
/**
* @param array{name?: string, definition: array|object} $index Search index specification
* @param array{definition: array|object, name?: string, type?: string} $index Search index specification
* @throws InvalidArgumentException
*/
public function __construct(private array $index)
Expand All @@ -54,6 +54,10 @@ public function __construct(private array $index)
if (isset($index['name']) && ! is_string($index['name'])) {
throw InvalidArgumentException::invalidType('"name" option', $index['name'], 'string');
}

if (isset($index['type']) && ! is_string($index['type'])) {
throw InvalidArgumentException::invalidType('"type" option', $index['type'], 'string');
}
}

/**
Expand Down
8 changes: 8 additions & 0 deletions tests/Model/SearchIndexInputTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@ public function testConstructorShouldRequireNameToBeString($name): void
new SearchIndexInput(['definition' => ['mapping' => ['dynamic' => true]], 'name' => $name]);
}

/** @dataProvider provideInvalidStringValues */
public function testConstructorShouldRequireTypeToBeString($type): void
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Expected "type" option to have type "string"');
new SearchIndexInput(['definition' => ['mapping' => ['dynamic' => true]], 'type' => $type]);
}

public function testBsonSerialization(): void
{
$expected = (object) [
Expand Down
8 changes: 8 additions & 0 deletions tests/Operation/CreateSearchIndexesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,14 @@ public function testConstructorIndexNameMustBeAString($name): void
new CreateSearchIndexes($this->getDatabaseName(), $this->getCollectionName(), [['name' => $name, 'definition' => ['mappings' => ['dynamic' => true]]]], []);
}

/** @dataProvider provideInvalidStringValues */
public function testConstructorIndexTypeMustBeAString($type): void
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Expected "type" option to have type "string"');
new CreateSearchIndexes($this->getDatabaseName(), $this->getCollectionName(), [['type' => $type, 'definition' => ['mappings' => ['dynamic' => true]]]], []);
}

public function testConstructorIndexDefinitionMustBeDefined(): void
{
$this->expectException(InvalidArgumentException::class);
Expand Down
20 changes: 13 additions & 7 deletions tests/UnifiedSpecTests/Operation.php
Original file line number Diff line number Diff line change
Expand Up @@ -533,19 +533,25 @@ private function executeForCollection(Collection $collection)
);

case 'createSearchIndex':
$options = [];
if (isset($args['model']->name)) {
assertIsString($args['model']->name);
$options['name'] = $args['model']->name;
}

assertArrayHasKey('model', $args);
assertIsObject($args['model']);
assertObjectHasAttribute('definition', $args['model']);
assertInstanceOf(stdClass::class, $args['model']->definition);

return $collection->createSearchIndex($args['model']->definition, $options);
/* Note: tests specify options within "model". A top-level
* "options" key (CreateSearchIndexOptions) is not used. */
$definition = $args['model']->definition;
$options = array_diff_key((array) $args['model'], ['definition' => 1]);

return $collection->createSearchIndex($definition, $options);

case 'createSearchIndexes':
assertArrayHasKey('models', $args);
assertIsArray($args['models']);

$indexes = array_map(function ($index) {
$index = (array) $index;
assertArrayHasKey('definition', $index);
assertInstanceOf(stdClass::class, $index['definition']);

return $index;
Expand Down
84 changes: 79 additions & 5 deletions tests/UnifiedSpecTests/index-management/createSearchIndex.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,17 @@
],
"runOnRequirements": [
{
"minServerVersion": "7.0.0",
"minServerVersion": "7.0.5",
"maxServerVersion": "7.0.99",
"topologies": [
"replicaset",
"load-balanced",
"sharded"
],
"serverless": "forbid"
},
{
"minServerVersion": "7.2.0",
"topologies": [
"replicaset",
"load-balanced",
Expand All @@ -50,7 +60,8 @@
"mappings": {
"dynamic": true
}
}
},
"type": "search"
}
},
"expectError": {
Expand All @@ -73,7 +84,8 @@
"mappings": {
"dynamic": true
}
}
},
"type": "search"
}
],
"$db": "database0"
Expand All @@ -97,7 +109,8 @@
"dynamic": true
}
},
"name": "test index"
"name": "test index",
"type": "search"
}
},
"expectError": {
Expand All @@ -121,7 +134,68 @@
"dynamic": true
}
},
"name": "test index"
"name": "test index",
"type": "search"
}
],
"$db": "database0"
}
}
}
]
}
]
},
{
"description": "create a vector search index",
"operations": [
{
"name": "createSearchIndex",
"object": "collection0",
"arguments": {
"model": {
"definition": {
"fields": [
{
"type": "vector",
"path": "plot_embedding",
"numDimensions": 1536,
"similarity": "euclidean"
}
]
},
"name": "test index",
"type": "vectorSearch"
}
},
"expectError": {
"isError": true,
"errorContains": "Atlas"
}
}
],
"expectEvents": [
{
"client": "client0",
"events": [
{
"commandStartedEvent": {
"command": {
"createSearchIndexes": "collection0",
"indexes": [
{
"definition": {
"fields": [
{
"type": "vector",
"path": "plot_embedding",
"numDimensions": 1536,
"similarity": "euclidean"
}
]
},
"name": "test index",
"type": "vectorSearch"
}
],
"$db": "database0"
Expand Down
86 changes: 81 additions & 5 deletions tests/UnifiedSpecTests/index-management/createSearchIndexes.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,17 @@
],
"runOnRequirements": [
{
"minServerVersion": "7.0.0",
"minServerVersion": "7.0.5",
"maxServerVersion": "7.0.99",
"topologies": [
"replicaset",
"load-balanced",
"sharded"
],
"serverless": "forbid"
},
{
"minServerVersion": "7.2.0",
"topologies": [
"replicaset",
"load-balanced",
Expand Down Expand Up @@ -83,7 +93,8 @@
"mappings": {
"dynamic": true
}
}
},
"type": "search"
}
]
},
Expand All @@ -107,7 +118,8 @@
"mappings": {
"dynamic": true
}
}
},
"type": "search"
}
],
"$db": "database0"
Expand All @@ -132,7 +144,8 @@
"dynamic": true
}
},
"name": "test index"
"name": "test index",
"type": "search"
}
]
},
Expand All @@ -157,7 +170,70 @@
"dynamic": true
}
},
"name": "test index"
"name": "test index",
"type": "search"
}
],
"$db": "database0"
}
}
}
]
}
]
},
{
"description": "create a vector search index",
"operations": [
{
"name": "createSearchIndexes",
"object": "collection0",
"arguments": {
"models": [
{
"definition": {
"fields": [
{
"type": "vector",
"path": "plot_embedding",
"numDimensions": 1536,
"similarity": "euclidean"
}
]
},
"name": "test index",
"type": "vectorSearch"
}
]
},
"expectError": {
"isError": true,
"errorContains": "Atlas"
}
}
],
"expectEvents": [
{
"client": "client0",
"events": [
{
"commandStartedEvent": {
"command": {
"createSearchIndexes": "collection0",
"indexes": [
{
"definition": {
"fields": [
{
"type": "vector",
"path": "plot_embedding",
"numDimensions": 1536,
"similarity": "euclidean"
}
]
},
"name": "test index",
"type": "vectorSearch"
}
],
"$db": "database0"
Expand Down
Loading