Skip to content

Commit ea742b8

Browse files
authored
PHPORM-326 Add collation to db:table command (#3394)
2 parents 72d6e57 + f6e3c18 commit ea742b8

File tree

3 files changed

+215
-182
lines changed

3 files changed

+215
-182
lines changed

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
},
1717
"authors": [
1818
{ "name": "Andreas Braun", "email": "[email protected]", "role": "Leader" },
19+
{ "name": "Pauline Vos", "email": "[email protected]", "role": "Maintainer" },
1920
{ "name": "Jérôme Tamarelle", "email": "[email protected]", "role": "Maintainer" },
2021
{ "name": "Jeremy Mikola", "email": "[email protected]", "role": "Maintainer" },
2122
{ "name": "Jens Segers", "homepage": "https://jenssegers.com", "role": "Creator" }

src/Schema/Builder.php

Lines changed: 71 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use Closure;
88
use MongoDB\Collection;
9+
use MongoDB\Database;
910
use MongoDB\Driver\Exception\ServerException;
1011
use MongoDB\Laravel\Connection;
1112
use MongoDB\Model\CollectionInfo;
@@ -14,6 +15,7 @@
1415
use function array_column;
1516
use function array_fill_keys;
1617
use function array_filter;
18+
use function array_key_exists;
1719
use function array_keys;
1820
use function array_map;
1921
use function array_merge;
@@ -25,6 +27,7 @@
2527
use function implode;
2628
use function in_array;
2729
use function is_array;
30+
use function is_bool;
2831
use function is_string;
2932
use function iterator_to_array;
3033
use function sort;
@@ -156,66 +159,13 @@ public function dropAllTables()
156159
/** @param string|null $schema Database name */
157160
public function getTables($schema = null)
158161
{
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);
189163
}
190164

191165
/** @param string|null $schema Database name */
192166
public function getViews($schema = null)
193167
{
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);
219169
}
220170

221171
/**
@@ -254,7 +204,7 @@ public function getColumns($table)
254204
[$db, $table] = explode('.', $table, 2);
255205
}
256206

257-
$stats = $this->connection->getDatabase($db)->selectCollection($table)->aggregate([
207+
$stats = $this->connection->getDatabase($db)->getCollection($table)->aggregate([
258208
// Sample 1,000 documents to get a representative sample of the collection
259209
['$sample' => ['size' => 1_000]],
260210
// Convert each document to an array of fields
@@ -389,7 +339,7 @@ public function getCollection($name)
389339
}
390340

391341
/**
392-
* Get all of the collections names for the database.
342+
* Get all the collections names for the database.
393343
*
394344
* @deprecated
395345
*
@@ -418,4 +368,68 @@ public static function isAtlasSearchNotSupportedException(ServerException $e): b
418368
31082, // MongoDB 8: Using Atlas Search Database Commands and the $listSearchIndexes aggregation stage requires additional configuration.
419369
], true);
420370
}
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+
}
421435
}

0 commit comments

Comments
 (0)