Skip to content

Commit d2a9458

Browse files
Merge v1.20 into master (#1380)
2 parents e5e6b61 + 2b06ec5 commit d2a9458

9 files changed

+217
-36
lines changed

psalm-baseline.xml

+1-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<files psalm-version="5.26.0@4787eaf414e16c661902b94dfe5d882223e5b513">
2+
<files psalm-version="5.25.0@01a8eb06b9e9cc6cfb6a320bf9fb14331919d505">
33
<file src="examples/atlas_search.php">
44
<MixedArgument>
55
<code><![CDATA[$document['name']]]></code>
@@ -216,11 +216,6 @@
216216
<code><![CDATA[$value]]></code>
217217
</MixedArgumentTypeCoercion>
218218
</file>
219-
<file src="src/Collection.php">
220-
<MixedArgumentTypeCoercion>
221-
<code><![CDATA[$options]]></code>
222-
</MixedArgumentTypeCoercion>
223-
</file>
224219
<file src="src/Command/ListCollections.php">
225220
<MixedAssignment>
226221
<code><![CDATA[$cmd[$option]]]></code>

src/Collection.php

+11-11
Original file line numberDiff line numberDiff line change
@@ -361,22 +361,22 @@ public function createIndexes(array $indexes, array $options = [])
361361
*
362362
* @see https://www.mongodb.com/docs/manual/reference/command/createSearchIndexes/
363363
* @see https://mongodb.com/docs/manual/reference/method/db.collection.createSearchIndex/
364-
* @param array|object $definition Atlas Search index mapping definition
365-
* @param array{name?: string, comment?: mixed} $options Command options
364+
* @param array|object $definition Atlas Search index mapping definition
365+
* @param array{comment?: mixed, name?: string, type?: string} $options Index and command options
366366
* @return string The name of the created search index
367367
* @throws UnsupportedException if options are not supported by the selected server
368368
* @throws InvalidArgumentException for parameter/option parsing errors
369369
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
370370
*/
371371
public function createSearchIndex(array|object $definition, array $options = []): string
372372
{
373-
$index = ['definition' => $definition];
374-
if (isset($options['name'])) {
375-
$index['name'] = $options['name'];
376-
unset($options['name']);
377-
}
373+
$indexOptionKeys = ['name' => 1, 'type' => 1];
374+
/** @psalm-var array{name?: string, type?: string} */
375+
$indexOptions = array_intersect_key($options, $indexOptionKeys);
376+
/** @psalm-var array{comment?: mixed} */
377+
$operationOptions = array_diff_key($options, $indexOptionKeys);
378378

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

381381
return current($names);
382382
}
@@ -390,16 +390,16 @@ public function createSearchIndex(array|object $definition, array $options = [])
390390
* For example:
391391
*
392392
* $indexes = [
393-
* // Create a search index with the default name, on
393+
* // Create a search index with the default name on a single field
394394
* ['definition' => ['mappings' => ['dynamic' => false, 'fields' => ['title' => ['type' => 'string']]]]],
395395
* // Create a named search index on all fields
396396
* ['name' => 'search_all', 'definition' => ['mappings' => ['dynamic' => true]]],
397397
* ];
398398
*
399399
* @see https://www.mongodb.com/docs/manual/reference/command/createSearchIndexes/
400400
* @see https://mongodb.com/docs/manual/reference/method/db.collection.createSearchIndex/
401-
* @param list<array{name?: string, definition: array|object}> $indexes List of search index specifications
402-
* @param array{comment?: string} $options Command options
401+
* @param list<array{definition: array|object, name?: string, type?: string}> $indexes List of search index specifications
402+
* @param array{comment?: mixed} $options Command options
403403
* @return string[] The names of the created search indexes
404404
* @throws UnsupportedException if options are not supported by the selected server
405405
* @throws InvalidArgumentException for parameter/option parsing errors

src/Model/SearchIndexInput.php

+5-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
class SearchIndexInput implements Serializable
3838
{
3939
/**
40-
* @param array{name?: string, definition: array|object} $index Search index specification
40+
* @param array{definition: array|object, name?: string, type?: string} $index Search index specification
4141
* @throws InvalidArgumentException
4242
*/
4343
public function __construct(private array $index)
@@ -54,6 +54,10 @@ public function __construct(private array $index)
5454
if (isset($index['name']) && ! is_string($index['name'])) {
5555
throw InvalidArgumentException::invalidType('"name" option', $index['name'], 'string');
5656
}
57+
58+
if (isset($index['type']) && ! is_string($index['type'])) {
59+
throw InvalidArgumentException::invalidType('"type" option', $index['type'], 'string');
60+
}
5761
}
5862

5963
/**

tests/Model/SearchIndexInputTest.php

+8
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,14 @@ public function testConstructorShouldRequireNameToBeString($name): void
3232
new SearchIndexInput(['definition' => ['mapping' => ['dynamic' => true]], 'name' => $name]);
3333
}
3434

35+
/** @dataProvider provideInvalidStringValues */
36+
public function testConstructorShouldRequireTypeToBeString($type): void
37+
{
38+
$this->expectException(InvalidArgumentException::class);
39+
$this->expectExceptionMessage('Expected "type" option to have type "string"');
40+
new SearchIndexInput(['definition' => ['mapping' => ['dynamic' => true]], 'type' => $type]);
41+
}
42+
3543
public function testBsonSerialization(): void
3644
{
3745
$expected = (object) [

tests/Operation/CreateSearchIndexesTest.php

+8
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,14 @@ public function testConstructorIndexNameMustBeAString($name): void
3030
new CreateSearchIndexes($this->getDatabaseName(), $this->getCollectionName(), [['name' => $name, 'definition' => ['mappings' => ['dynamic' => true]]]], []);
3131
}
3232

33+
/** @dataProvider provideInvalidStringValues */
34+
public function testConstructorIndexTypeMustBeAString($type): void
35+
{
36+
$this->expectException(InvalidArgumentException::class);
37+
$this->expectExceptionMessage('Expected "type" option to have type "string"');
38+
new CreateSearchIndexes($this->getDatabaseName(), $this->getCollectionName(), [['type' => $type, 'definition' => ['mappings' => ['dynamic' => true]]]], []);
39+
}
40+
3341
public function testConstructorIndexDefinitionMustBeDefined(): void
3442
{
3543
$this->expectException(InvalidArgumentException::class);

tests/UnifiedSpecTests/Operation.php

+13-7
Original file line numberDiff line numberDiff line change
@@ -533,19 +533,25 @@ private function executeForCollection(Collection $collection)
533533
);
534534

535535
case 'createSearchIndex':
536-
$options = [];
537-
if (isset($args['model']->name)) {
538-
assertIsString($args['model']->name);
539-
$options['name'] = $args['model']->name;
540-
}
541-
536+
assertArrayHasKey('model', $args);
537+
assertIsObject($args['model']);
538+
assertObjectHasAttribute('definition', $args['model']);
542539
assertInstanceOf(stdClass::class, $args['model']->definition);
543540

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

546548
case 'createSearchIndexes':
549+
assertArrayHasKey('models', $args);
550+
assertIsArray($args['models']);
551+
547552
$indexes = array_map(function ($index) {
548553
$index = (array) $index;
554+
assertArrayHasKey('definition', $index);
549555
assertInstanceOf(stdClass::class, $index['definition']);
550556

551557
return $index;

tests/UnifiedSpecTests/index-management/createSearchIndex.json

+79-5
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,17 @@
2828
],
2929
"runOnRequirements": [
3030
{
31-
"minServerVersion": "7.0.0",
31+
"minServerVersion": "7.0.5",
32+
"maxServerVersion": "7.0.99",
33+
"topologies": [
34+
"replicaset",
35+
"load-balanced",
36+
"sharded"
37+
],
38+
"serverless": "forbid"
39+
},
40+
{
41+
"minServerVersion": "7.2.0",
3242
"topologies": [
3343
"replicaset",
3444
"load-balanced",
@@ -50,7 +60,8 @@
5060
"mappings": {
5161
"dynamic": true
5262
}
53-
}
63+
},
64+
"type": "search"
5465
}
5566
},
5667
"expectError": {
@@ -73,7 +84,8 @@
7384
"mappings": {
7485
"dynamic": true
7586
}
76-
}
87+
},
88+
"type": "search"
7789
}
7890
],
7991
"$db": "database0"
@@ -97,7 +109,8 @@
97109
"dynamic": true
98110
}
99111
},
100-
"name": "test index"
112+
"name": "test index",
113+
"type": "search"
101114
}
102115
},
103116
"expectError": {
@@ -121,7 +134,68 @@
121134
"dynamic": true
122135
}
123136
},
124-
"name": "test index"
137+
"name": "test index",
138+
"type": "search"
139+
}
140+
],
141+
"$db": "database0"
142+
}
143+
}
144+
}
145+
]
146+
}
147+
]
148+
},
149+
{
150+
"description": "create a vector search index",
151+
"operations": [
152+
{
153+
"name": "createSearchIndex",
154+
"object": "collection0",
155+
"arguments": {
156+
"model": {
157+
"definition": {
158+
"fields": [
159+
{
160+
"type": "vector",
161+
"path": "plot_embedding",
162+
"numDimensions": 1536,
163+
"similarity": "euclidean"
164+
}
165+
]
166+
},
167+
"name": "test index",
168+
"type": "vectorSearch"
169+
}
170+
},
171+
"expectError": {
172+
"isError": true,
173+
"errorContains": "Atlas"
174+
}
175+
}
176+
],
177+
"expectEvents": [
178+
{
179+
"client": "client0",
180+
"events": [
181+
{
182+
"commandStartedEvent": {
183+
"command": {
184+
"createSearchIndexes": "collection0",
185+
"indexes": [
186+
{
187+
"definition": {
188+
"fields": [
189+
{
190+
"type": "vector",
191+
"path": "plot_embedding",
192+
"numDimensions": 1536,
193+
"similarity": "euclidean"
194+
}
195+
]
196+
},
197+
"name": "test index",
198+
"type": "vectorSearch"
125199
}
126200
],
127201
"$db": "database0"

tests/UnifiedSpecTests/index-management/createSearchIndexes.json

+81-5
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,17 @@
2828
],
2929
"runOnRequirements": [
3030
{
31-
"minServerVersion": "7.0.0",
31+
"minServerVersion": "7.0.5",
32+
"maxServerVersion": "7.0.99",
33+
"topologies": [
34+
"replicaset",
35+
"load-balanced",
36+
"sharded"
37+
],
38+
"serverless": "forbid"
39+
},
40+
{
41+
"minServerVersion": "7.2.0",
3242
"topologies": [
3343
"replicaset",
3444
"load-balanced",
@@ -83,7 +93,8 @@
8393
"mappings": {
8494
"dynamic": true
8595
}
86-
}
96+
},
97+
"type": "search"
8798
}
8899
]
89100
},
@@ -107,7 +118,8 @@
107118
"mappings": {
108119
"dynamic": true
109120
}
110-
}
121+
},
122+
"type": "search"
111123
}
112124
],
113125
"$db": "database0"
@@ -132,7 +144,8 @@
132144
"dynamic": true
133145
}
134146
},
135-
"name": "test index"
147+
"name": "test index",
148+
"type": "search"
136149
}
137150
]
138151
},
@@ -157,7 +170,70 @@
157170
"dynamic": true
158171
}
159172
},
160-
"name": "test index"
173+
"name": "test index",
174+
"type": "search"
175+
}
176+
],
177+
"$db": "database0"
178+
}
179+
}
180+
}
181+
]
182+
}
183+
]
184+
},
185+
{
186+
"description": "create a vector search index",
187+
"operations": [
188+
{
189+
"name": "createSearchIndexes",
190+
"object": "collection0",
191+
"arguments": {
192+
"models": [
193+
{
194+
"definition": {
195+
"fields": [
196+
{
197+
"type": "vector",
198+
"path": "plot_embedding",
199+
"numDimensions": 1536,
200+
"similarity": "euclidean"
201+
}
202+
]
203+
},
204+
"name": "test index",
205+
"type": "vectorSearch"
206+
}
207+
]
208+
},
209+
"expectError": {
210+
"isError": true,
211+
"errorContains": "Atlas"
212+
}
213+
}
214+
],
215+
"expectEvents": [
216+
{
217+
"client": "client0",
218+
"events": [
219+
{
220+
"commandStartedEvent": {
221+
"command": {
222+
"createSearchIndexes": "collection0",
223+
"indexes": [
224+
{
225+
"definition": {
226+
"fields": [
227+
{
228+
"type": "vector",
229+
"path": "plot_embedding",
230+
"numDimensions": 1536,
231+
"similarity": "euclidean"
232+
}
233+
]
234+
},
235+
"name": "test index",
236+
"type": "vectorSearch"
161237
}
162238
],
163239
"$db": "database0"

0 commit comments

Comments
 (0)