|
6 | 6 |
|
7 | 7 | use Closure; |
8 | 8 | use MongoDB\Collection; |
| 9 | +use MongoDB\Database; |
9 | 10 | use MongoDB\Driver\Exception\ServerException; |
10 | 11 | use MongoDB\Laravel\Connection; |
11 | 12 | use MongoDB\Model\CollectionInfo; |
|
14 | 15 | use function array_column; |
15 | 16 | use function array_fill_keys; |
16 | 17 | use function array_filter; |
| 18 | +use function array_key_exists; |
17 | 19 | use function array_keys; |
18 | 20 | use function array_map; |
19 | 21 | use function array_merge; |
|
25 | 27 | use function implode; |
26 | 28 | use function in_array; |
27 | 29 | use function is_array; |
| 30 | +use function is_bool; |
28 | 31 | use function is_string; |
29 | 32 | use function iterator_to_array; |
30 | 33 | use function sort; |
@@ -156,66 +159,13 @@ public function dropAllTables() |
156 | 159 | /** @param string|null $schema Database name */ |
157 | 160 | public function getTables($schema = null) |
158 | 161 | { |
159 | | - $db = $this->connection->getDatabase($schema); |
160 | | - $collections = []; |
161 | | - |
162 | | - foreach ($db->listCollections() as $collectionInfo) { |
163 | | - $collectionName = $collectionInfo->getName(); |
164 | | - |
165 | | - // Skip views, which don't support aggregate |
166 | | - if ($collectionInfo->getType() === 'view') { |
167 | | - continue; |
168 | | - } |
169 | | - |
170 | | - $stats = $db->selectCollection($collectionName)->aggregate([ |
171 | | - ['$collStats' => ['storageStats' => ['scale' => 1]]], |
172 | | - ['$project' => ['storageStats.totalSize' => 1]], |
173 | | - ])->toArray(); |
174 | | - |
175 | | - $collections[] = [ |
176 | | - 'name' => $collectionName, |
177 | | - 'schema' => $db->getDatabaseName(), |
178 | | - 'schema_qualified_name' => $db->getDatabaseName() . '.' . $collectionName, |
179 | | - 'size' => $stats[0]?->storageStats?->totalSize ?? null, |
180 | | - 'comment' => null, |
181 | | - 'collation' => null, |
182 | | - 'engine' => null, |
183 | | - ]; |
184 | | - } |
185 | | - |
186 | | - usort($collections, fn ($a, $b) => $a['name'] <=> $b['name']); |
187 | | - |
188 | | - return $collections; |
| 162 | + return $this->getCollectionRows('collection', $schema); |
189 | 163 | } |
190 | 164 |
|
191 | 165 | /** @param string|null $schema Database name */ |
192 | 166 | public function getViews($schema = null) |
193 | 167 | { |
194 | | - $db = $this->connection->getDatabase($schema); |
195 | | - $collections = []; |
196 | | - |
197 | | - foreach ($db->listCollections() as $collectionInfo) { |
198 | | - $collectionName = $collectionInfo->getName(); |
199 | | - |
200 | | - // Skip normal type collection |
201 | | - if ($collectionInfo->getType() !== 'view') { |
202 | | - continue; |
203 | | - } |
204 | | - |
205 | | - $collections[] = [ |
206 | | - 'name' => $collectionName, |
207 | | - 'schema' => $db->getDatabaseName(), |
208 | | - 'schema_qualified_name' => $db->getDatabaseName() . '.' . $collectionName, |
209 | | - 'size' => null, |
210 | | - 'comment' => null, |
211 | | - 'collation' => null, |
212 | | - 'engine' => null, |
213 | | - ]; |
214 | | - } |
215 | | - |
216 | | - usort($collections, fn ($a, $b) => $a['name'] <=> $b['name']); |
217 | | - |
218 | | - return $collections; |
| 168 | + return $this->getCollectionRows('view', $schema); |
219 | 169 | } |
220 | 170 |
|
221 | 171 | /** |
@@ -254,7 +204,7 @@ public function getColumns($table) |
254 | 204 | [$db, $table] = explode('.', $table, 2); |
255 | 205 | } |
256 | 206 |
|
257 | | - $stats = $this->connection->getDatabase($db)->selectCollection($table)->aggregate([ |
| 207 | + $stats = $this->connection->getDatabase($db)->getCollection($table)->aggregate([ |
258 | 208 | // Sample 1,000 documents to get a representative sample of the collection |
259 | 209 | ['$sample' => ['size' => 1_000]], |
260 | 210 | // Convert each document to an array of fields |
@@ -389,7 +339,7 @@ public function getCollection($name) |
389 | 339 | } |
390 | 340 |
|
391 | 341 | /** |
392 | | - * Get all of the collections names for the database. |
| 342 | + * Get all the collections names for the database. |
393 | 343 | * |
394 | 344 | * @deprecated |
395 | 345 | * |
@@ -418,4 +368,68 @@ public static function isAtlasSearchNotSupportedException(ServerException $e): b |
418 | 368 | 31082, // MongoDB 8: Using Atlas Search Database Commands and the $listSearchIndexes aggregation stage requires additional configuration. |
419 | 369 | ], true); |
420 | 370 | } |
| 371 | + |
| 372 | + /** @param string|null $schema Database name */ |
| 373 | + private function getCollectionRows(string $collectionType, $schema = null) |
| 374 | + { |
| 375 | + $db = $this->connection->getDatabase($schema); |
| 376 | + $collections = []; |
| 377 | + |
| 378 | + foreach ($db->listCollections() as $collectionInfo) { |
| 379 | + $collectionName = $collectionInfo->getName(); |
| 380 | + |
| 381 | + if ($collectionInfo->getType() !== $collectionType) { |
| 382 | + continue; |
| 383 | + } |
| 384 | + |
| 385 | + $options = $collectionInfo->getOptions(); |
| 386 | + $collation = $options['collation'] ?? []; |
| 387 | + |
| 388 | + // Aggregation is not supported on views |
| 389 | + $stats = $collectionType !== 'view' ? $db->selectCollection($collectionName)->aggregate([ |
| 390 | + ['$collStats' => ['storageStats' => ['scale' => 1]]], |
| 391 | + ['$project' => ['storageStats.totalSize' => 1]], |
| 392 | + ])->toArray() : null; |
| 393 | + |
| 394 | + $collections[] = [ |
| 395 | + 'name' => $collectionName, |
| 396 | + 'schema' => $db->getDatabaseName(), |
| 397 | + 'schema_qualified_name' => $db->getDatabaseName() . '.' . $collectionName, |
| 398 | + 'size' => $stats[0]?->storageStats?->totalSize ?? null, |
| 399 | + 'comment' => null, |
| 400 | + 'collation' => $this->collationToString($collation), |
| 401 | + 'engine' => null, |
| 402 | + ]; |
| 403 | + } |
| 404 | + |
| 405 | + usort($collections, fn ($a, $b) => $a['name'] <=> $b['name']); |
| 406 | + |
| 407 | + return $collections; |
| 408 | + } |
| 409 | + |
| 410 | + private function collationToString(array $collation): string |
| 411 | + { |
| 412 | + $map = [ |
| 413 | + 'locale' => 'l', |
| 414 | + 'strength' => 's', |
| 415 | + 'caseLevel' => 'cl', |
| 416 | + 'caseFirst' => 'cf', |
| 417 | + 'numericOrdering' => 'no', |
| 418 | + 'alternate' => 'a', |
| 419 | + 'maxVariable' => 'mv', |
| 420 | + 'normalization' => 'n', |
| 421 | + 'backwards' => 'b', |
| 422 | + ]; |
| 423 | + |
| 424 | + $parts = []; |
| 425 | + foreach ($collation as $key => $value) { |
| 426 | + if (array_key_exists($key, $map)) { |
| 427 | + $shortKey = $map[$key]; |
| 428 | + $shortValue = is_bool($value) ? ($value ? '1' : '0') : $value; |
| 429 | + $parts[] = $shortKey . '=' . $shortValue; |
| 430 | + } |
| 431 | + } |
| 432 | + |
| 433 | + return implode(';', $parts); |
| 434 | + } |
421 | 435 | } |
0 commit comments