Skip to content

Commit bcf97d2

Browse files
authored
PHPORM-325 Add getViews and categorize table types (#3327)
1 parent c49a73f commit bcf97d2

File tree

2 files changed

+108
-11
lines changed

2 files changed

+108
-11
lines changed

Diff for: src/Schema/Builder.php

+65-10
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,22 @@
2121
use function assert;
2222
use function count;
2323
use function current;
24+
use function explode;
2425
use function implode;
2526
use function in_array;
2627
use function is_array;
2728
use function is_string;
2829
use function iterator_to_array;
2930
use function sort;
3031
use function sprintf;
32+
use function str_contains;
3133
use function str_ends_with;
3234
use function substr;
35+
use function trigger_error;
3336
use function usort;
3437

38+
use const E_USER_DEPRECATED;
39+
3540
/** @property Connection $connection */
3641
class Builder extends \Illuminate\Database\Schema\Builder
3742
{
@@ -47,7 +52,7 @@ public function hasColumn($table, $column): bool
4752
}
4853

4954
/**
50-
* Check if columns exists in the collection schema.
55+
* Check if columns exist in the collection schema.
5156
*
5257
* @param string $table
5358
* @param string[] $columns
@@ -134,12 +139,18 @@ public function drop($table)
134139
$blueprint->drop();
135140
}
136141

137-
/** @inheritdoc */
142+
/**
143+
* @inheritdoc
144+
*
145+
* Drops the entire database instead of deleting each collection individually.
146+
*
147+
* In MongoDB, dropping the whole database is much faster than dropping collections
148+
* one by one. The database will be automatically recreated when a new connection
149+
* writes to it.
150+
*/
138151
public function dropAllTables()
139152
{
140-
foreach ($this->getAllCollections() as $collection) {
141-
$this->drop($collection);
142-
}
153+
$this->connection->getDatabase()->drop();
143154
}
144155

145156
/** @param string|null $schema Database name */
@@ -148,7 +159,14 @@ public function getTables($schema = null)
148159
$db = $this->connection->getDatabase($schema);
149160
$collections = [];
150161

151-
foreach ($db->listCollectionNames() as $collectionName) {
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+
152170
$stats = $db->selectCollection($collectionName)->aggregate([
153171
['$collStats' => ['storageStats' => ['scale' => 1]]],
154172
['$project' => ['storageStats.totalSize' => 1]],
@@ -165,9 +183,37 @@ public function getTables($schema = null)
165183
];
166184
}
167185

168-
usort($collections, function ($a, $b) {
169-
return $a['name'] <=> $b['name'];
170-
});
186+
usort($collections, fn ($a, $b) => $a['name'] <=> $b['name']);
187+
188+
return $collections;
189+
}
190+
191+
/** @param string|null $schema Database name */
192+
public function getViews($schema = null)
193+
{
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']);
171217

172218
return $collections;
173219
}
@@ -203,7 +249,12 @@ public function getTableListing($schema = null, $schemaQualified = false)
203249

204250
public function getColumns($table)
205251
{
206-
$stats = $this->connection->getDatabase()->selectCollection($table)->aggregate([
252+
$db = null;
253+
if (str_contains($table, '.')) {
254+
[$db, $table] = explode('.', $table, 2);
255+
}
256+
257+
$stats = $this->connection->getDatabase($db)->selectCollection($table)->aggregate([
207258
// Sample 1,000 documents to get a representative sample of the collection
208259
['$sample' => ['size' => 1_000]],
209260
// Convert each document to an array of fields
@@ -340,10 +391,14 @@ public function getCollection($name)
340391
/**
341392
* Get all of the collections names for the database.
342393
*
394+
* @deprecated
395+
*
343396
* @return array
344397
*/
345398
protected function getAllCollections()
346399
{
400+
trigger_error(sprintf('Since mongodb/laravel-mongodb:5.4, Method "%s()" is deprecated without replacement.', __METHOD__), E_USER_DEPRECATED);
401+
347402
$collections = [];
348403
foreach ($this->connection->getDatabase()->listCollections() as $collection) {
349404
$collections[] = $collection->getName();

Diff for: tests/SchemaTest.php

+43-1
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,11 @@ class SchemaTest extends TestCase
2222
{
2323
public function tearDown(): void
2424
{
25-
$database = $this->getConnection('mongodb')->getMongoDB();
25+
$database = $this->getConnection('mongodb')->getDatabase();
2626
assert($database instanceof Database);
2727
$database->dropCollection('newcollection');
2828
$database->dropCollection('newcollection_two');
29+
$database->dropCollection('test_view');
2930

3031
parent::tearDown();
3132
}
@@ -395,6 +396,7 @@ public function testGetTables()
395396
{
396397
DB::connection('mongodb')->table('newcollection')->insert(['test' => 'value']);
397398
DB::connection('mongodb')->table('newcollection_two')->insert(['test' => 'value']);
399+
DB::connection('mongodb')->getDatabase()->createCollection('test_view', ['viewOn' => 'newcollection']);
398400
$dbName = DB::connection('mongodb')->getDatabaseName();
399401

400402
$tables = Schema::getTables();
@@ -406,6 +408,7 @@ public function testGetTables()
406408
$this->assertArrayHasKey('size', $table);
407409
$this->assertArrayHasKey('schema', $table);
408410
$this->assertArrayHasKey('schema_qualified_name', $table);
411+
$this->assertNotEquals('test_view', $table['name'], 'Standard views should not be included in the result of getTables.');
409412

410413
if ($table['name'] === 'newcollection') {
411414
$this->assertEquals(8192, $table['size']);
@@ -420,6 +423,40 @@ public function testGetTables()
420423
}
421424
}
422425

426+
public function testGetViews()
427+
{
428+
DB::connection('mongodb')->table('newcollection')->insert(['test' => 'value']);
429+
DB::connection('mongodb')->table('newcollection_two')->insert(['test' => 'value']);
430+
$dbName = DB::connection('mongodb')->getDatabaseName();
431+
432+
DB::connection('mongodb')->getDatabase()->createCollection('test_view', ['viewOn' => 'newcollection']);
433+
434+
$tables = Schema::getViews();
435+
436+
$this->assertIsArray($tables);
437+
$this->assertGreaterThanOrEqual(1, count($tables));
438+
$found = false;
439+
foreach ($tables as $table) {
440+
$this->assertArrayHasKey('name', $table);
441+
$this->assertArrayHasKey('size', $table);
442+
$this->assertArrayHasKey('schema', $table);
443+
$this->assertArrayHasKey('schema_qualified_name', $table);
444+
445+
// Ensure "normal collections" are not in the views list
446+
$this->assertNotEquals('newcollection', $table['name'], 'Normal collections should not be included in the result of getViews.');
447+
448+
if ($table['name'] === 'test_view') {
449+
$this->assertEquals($dbName, $table['schema']);
450+
$this->assertEquals($dbName . '.test_view', $table['schema_qualified_name']);
451+
$found = true;
452+
}
453+
}
454+
455+
if (! $found) {
456+
$this->fail('Collection "test_view" not found');
457+
}
458+
}
459+
423460
public function testGetTableListing()
424461
{
425462
DB::connection('mongodb')->table('newcollection')->insert(['test' => 'value']);
@@ -489,6 +526,11 @@ public function testGetColumns()
489526
// Non-existent collection
490527
$columns = Schema::getColumns('missing');
491528
$this->assertSame([], $columns);
529+
530+
// Qualified table name
531+
$columns = Schema::getColumns(DB::getDatabaseName() . '.newcollection');
532+
$this->assertIsArray($columns);
533+
$this->assertCount(5, $columns);
492534
}
493535

494536
/** @see AtlasSearchTest::testGetIndexes() */

0 commit comments

Comments
 (0)