Skip to content

Commit 5700592

Browse files
committed
PHPORM-274 List search indexes in Schema::getIndexes introspection method
1 parent a257a9f commit 5700592

File tree

2 files changed

+155
-2
lines changed

2 files changed

+155
-2
lines changed

src/Schema/Builder.php

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@
55
namespace MongoDB\Laravel\Schema;
66

77
use Closure;
8+
use MongoDB\Collection;
9+
use MongoDB\Driver\Exception\ServerException;
810
use MongoDB\Model\CollectionInfo;
911
use MongoDB\Model\IndexInfo;
1012

13+
use function array_column;
1114
use function array_fill_keys;
1215
use function array_filter;
1316
use function array_keys;
@@ -225,9 +228,11 @@ public function getColumns($table)
225228

226229
public function getIndexes($table)
227230
{
228-
$indexes = $this->connection->getMongoDB()->selectCollection($table)->listIndexes();
229-
231+
$collection = $this->connection->getMongoDB()->selectCollection($table);
232+
assert($collection instanceof Collection);
230233
$indexList = [];
234+
235+
$indexes = $collection->listIndexes();
231236
foreach ($indexes as $index) {
232237
assert($index instanceof IndexInfo);
233238
$indexList[] = [
@@ -244,6 +249,26 @@ public function getIndexes($table)
244249
];
245250
}
246251

252+
try {
253+
$indexes = $collection->listSearchIndexes(['typeMap' => ['root' => 'array', 'array' => 'array', 'document' => 'array']]);
254+
foreach ($indexes as $index) {
255+
$indexList[] = [
256+
'name' => $index['name'],
257+
'columns' => match ($index['type']) {
258+
'search' => array_keys($index['latestDefinition']['mappings']['fields'] ?? []),
259+
'vectorSearch' => array_column($index['latestDefinition']['fields'], 'path'),
260+
},
261+
'type' => $index['type'],
262+
'primary' => false,
263+
'unique' => false,
264+
];
265+
}
266+
} catch (ServerException $exception) {
267+
if (! self::isAtlasSearchNotSupportedException($exception)) {
268+
throw $exception;
269+
}
270+
}
271+
247272
return $indexList;
248273
}
249274

@@ -290,4 +315,10 @@ protected function getAllCollections()
290315

291316
return $collections;
292317
}
318+
319+
/** @internal */
320+
public static function isAtlasSearchNotSupportedException(ServerException $e): bool
321+
{
322+
return in_array($e->getCode(), [59, 40324, 115, 6047401, 31082], true);
323+
}
293324
}

tests/AtlasSearchTest.php

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
<?php
2+
3+
namespace MongoDB\Laravel\Tests;
4+
5+
use Illuminate\Support\Facades\Schema;
6+
use MongoDB\Collection as MongoDBCollection;
7+
use MongoDB\Driver\Exception\ServerException;
8+
use MongoDB\Laravel\Schema\Builder;
9+
use MongoDB\Laravel\Tests\Models\Book;
10+
11+
use function assert;
12+
use function usleep;
13+
14+
class AtlasSearchTest extends TestCase
15+
{
16+
public function setUp(): void
17+
{
18+
parent::setUp();
19+
20+
Book::insert([
21+
['title' => 'Introduction to Algorithms'],
22+
['title' => 'Clean Code: A Handbook of Agile Software Craftsmanship'],
23+
['title' => 'Design Patterns: Elements of Reusable Object-Oriented Software'],
24+
['title' => 'The Pragmatic Programmer: Your Journey to Mastery'],
25+
['title' => 'Artificial Intelligence: A Modern Approach'],
26+
['title' => 'Structure and Interpretation of Computer Programs'],
27+
['title' => 'Code Complete: A Practical Handbook of Software Construction'],
28+
['title' => 'The Art of Computer Programming'],
29+
['title' => 'Computer Networks'],
30+
['title' => 'Operating System Concepts'],
31+
['title' => 'Database System Concepts'],
32+
['title' => 'Compilers: Principles, Techniques, and Tools'],
33+
['title' => 'Introduction to the Theory of Computation'],
34+
['title' => 'Modern Operating Systems'],
35+
['title' => 'Computer Organization and Design'],
36+
['title' => 'The Mythical Man-Month: Essays on Software Engineering'],
37+
['title' => 'Algorithms'],
38+
['title' => 'Understanding Machine Learning: From Theory to Algorithms'],
39+
['title' => 'Deep Learning'],
40+
['title' => 'Pattern Recognition and Machine Learning'],
41+
]);
42+
43+
$collection = $this->getConnection('mongodb')->getCollection('books');
44+
assert($collection instanceof MongoDBCollection);
45+
try {
46+
$collection->createSearchIndex([
47+
'mappings' => [
48+
'fields' => [
49+
'title' => [
50+
['type' => 'string', 'analyzer' => 'lucene.english'],
51+
['type' => 'autocomplete', 'analyzer' => 'lucene.english'],
52+
],
53+
],
54+
],
55+
]);
56+
57+
$collection->createSearchIndex([
58+
'fields' => [
59+
['type' => 'vector', 'numDimensions' => 16, 'path' => 'vector16', 'similarity' => 'cosine'],
60+
['type' => 'vector', 'numDimensions' => 32, 'path' => 'vector32', 'similarity' => 'euclidean'],
61+
],
62+
], ['name' => 'vector', 'type' => 'vectorSearch']);
63+
} catch (ServerException $e) {
64+
if (Builder::isAtlasSearchNotSupportedException($e)) {
65+
self::markTestSkipped('Atlas Search not supported. ' . $e->getMessage());
66+
}
67+
68+
throw $e;
69+
}
70+
71+
// Wait for the index to be ready
72+
do {
73+
$ready = true;
74+
usleep(10_000);
75+
foreach ($collection->listSearchIndexes() as $index) {
76+
if ($index['status'] !== 'READY') {
77+
$ready = false;
78+
}
79+
}
80+
} while (! $ready);
81+
}
82+
83+
public function tearDown(): void
84+
{
85+
$this->getConnection('mongodb')->getCollection('books')->drop();
86+
87+
parent::tearDown();
88+
}
89+
90+
public function testGetIndexes()
91+
{
92+
$indexes = Schema::getIndexes('books');
93+
94+
self::assertCount(3, $indexes);
95+
96+
$expected = [
97+
[
98+
'name' => '_id_',
99+
'columns' => ['_id'],
100+
'primary' => true,
101+
'type' => 'default',
102+
'unique' => false,
103+
],
104+
[
105+
'name' => 'default',
106+
'columns' => ['title'],
107+
'type' => 'search',
108+
'primary' => false,
109+
'unique' => false,
110+
],
111+
[
112+
'name' => 'vector',
113+
'columns' => ['vector16', 'vector32'],
114+
'type' => 'vectorSearch',
115+
'primary' => false,
116+
'unique' => false,
117+
],
118+
];
119+
120+
self::assertSame($expected, $indexes);
121+
}
122+
}

0 commit comments

Comments
 (0)