From 83524bdf054805c029300af3c0a069ff414882bc Mon Sep 17 00:00:00 2001 From: Jason Date: Mon, 24 Mar 2025 12:25:25 +0000 Subject: [PATCH 01/17] feat: exclude system collections, add engine collection type to getTables --- src/Schema/Builder.php | 43 ++++++++++++++++++------ tests/SchemaTest.php | 76 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 108 insertions(+), 11 deletions(-) diff --git a/src/Schema/Builder.php b/src/Schema/Builder.php index ef450745a..a2213b6c6 100644 --- a/src/Schema/Builder.php +++ b/src/Schema/Builder.php @@ -29,6 +29,7 @@ use function sort; use function sprintf; use function str_ends_with; +use function str_starts_with; use function substr; use function usort; @@ -148,11 +149,25 @@ public function getTables($schema = null) $db = $this->connection->getDatabase($schema); $collections = []; - foreach ($db->listCollectionNames() as $collectionName) { - $stats = $db->selectCollection($collectionName)->aggregate([ - ['$collStats' => ['storageStats' => ['scale' => 1]]], - ['$project' => ['storageStats.totalSize' => 1]], - ])->toArray(); + foreach ($db->listCollections() as $collectionInfo) { + $collectionName = $collectionInfo->getName(); + + // Skip system collections + if (str_starts_with($collectionName, 'system.')) { + continue; + } + + // Skip views it doesnt suport aggregate + $isView = ($collectionInfo['type'] ?? '') === 'view'; + $stats = null; + + if (! $isView) { + // Only run aggregation if it's a normal collection + $stats = $db->selectCollection($collectionName)->aggregate([ + ['$collStats' => ['storageStats' => ['scale' => 1]]], + ['$project' => ['storageStats.totalSize' => 1]], + ])->toArray(); + } $collections[] = [ 'name' => $collectionName, @@ -161,13 +176,11 @@ public function getTables($schema = null) 'size' => $stats[0]?->storageStats?->totalSize ?? null, 'comment' => null, 'collation' => null, - 'engine' => null, + 'engine' => $isView ? 'view' : 'collection', ]; } - usort($collections, function ($a, $b) { - return $a['name'] <=> $b['name']; - }); + usort($collections, fn ($a, $b) => $a['name'] <=> $b['name']); return $collections; } @@ -196,6 +209,9 @@ public function getTableListing($schema = null, $schemaQualified = false) $collections = array_merge(...array_values($collections)); + // Exclude system collections before sorting + $collections = array_filter($collections, fn ($name) => ! str_starts_with($name, 'system.')); + sort($collections); return $collections; @@ -346,7 +362,14 @@ protected function getAllCollections() { $collections = []; foreach ($this->connection->getDatabase()->listCollections() as $collection) { - $collections[] = $collection->getName(); + $name = $collection->getName(); + + // Skip system collections + if (str_starts_with($name, 'system.')) { + continue; + } + + $collections[] = $name; } return $collections; diff --git a/tests/SchemaTest.php b/tests/SchemaTest.php index 8e91a2f66..7d6561b36 100644 --- a/tests/SchemaTest.php +++ b/tests/SchemaTest.php @@ -17,15 +17,17 @@ use function collect; use function count; use function sprintf; +use function str_starts_with; class SchemaTest extends TestCase { public function tearDown(): void { - $database = $this->getConnection('mongodb')->getMongoDB(); + $database = $this->getConnection('mongodb')->getDatabase(); assert($database instanceof Database); $database->dropCollection('newcollection'); $database->dropCollection('newcollection_two'); + $database->dropCollection('test_view'); parent::tearDown(); } @@ -397,6 +399,13 @@ public function testGetTables() DB::connection('mongodb')->table('newcollection_two')->insert(['test' => 'value']); $dbName = DB::connection('mongodb')->getDatabaseName(); + // Create a view (this creates system.views) + DB::connection('mongodb')->getDatabase()->command([ + 'create' => 'test_view', + 'viewOn' => 'newcollection', + 'pipeline' => [], + ]); + $tables = Schema::getTables(); $this->assertIsArray($tables); $this->assertGreaterThanOrEqual(2, count($tables)); @@ -413,6 +422,9 @@ public function testGetTables() $this->assertEquals($dbName . '.newcollection', $table['schema_qualified_name']); $found = true; } + + // Ensure system collections are excluded + $this->assertFalse(str_starts_with($table['name'], 'system.')); } if (! $found) { @@ -425,12 +437,22 @@ public function testGetTableListing() DB::connection('mongodb')->table('newcollection')->insert(['test' => 'value']); DB::connection('mongodb')->table('newcollection_two')->insert(['test' => 'value']); + // Create a view (this creates system.views) + DB::connection('mongodb')->getDatabase()->command([ + 'create' => 'test_view', + 'viewOn' => 'newcollection', + 'pipeline' => [], + ]); + $tables = Schema::getTableListing(); $this->assertIsArray($tables); $this->assertGreaterThanOrEqual(2, count($tables)); $this->assertContains('newcollection', $tables); $this->assertContains('newcollection_two', $tables); + + // Ensure system collections are excluded + $this->assertNotContains('system.views', $tables); } public function testGetTableListingBySchema() @@ -453,6 +475,58 @@ public function testGetTableListingBySchema() $this->assertContains('newcollection', $tables); $this->assertContains('newcollection_two', $tables); } +// Protected method cannot test + // public function testGetAllCollections() + // { + // // Insert test data into normal collections + // DB::connection('mongodb')->table('newcollection')->insert(['test' => 'value']); + // DB::connection('mongodb')->table('newcollection_two')->insert(['test' => 'value']); + + // // Create a view (this creates system.views) + // DB::connection('mongodb')->getDatabase()->command([ + // 'create' => 'test_view', + // 'viewOn' => 'newcollection', + // 'pipeline' => [], + // ]); + + // $collections = Schema::getAllCollections(); + + // $this->assertIsArray($collections); + // $this->assertGreaterThanOrEqual(2, count($collections)); + + // // Ensure normal collections are present + // $this->assertContains('newcollection', $collections); + // $this->assertContains('newcollection_two', $collections); + + // // Ensure system collections are excluded + // $this->assertNotContains('system.views', $collections); + // } + + public function testSystemCollectionsArePresentButFiltered() + { + // Create a view to trigger system.views collection + DB::connection('mongodb')->getDatabase()->command([ + 'create' => 'test_view', + 'viewOn' => 'newcollection', + 'pipeline' => [], + ]); + + // Get all collections directly from MongoDB + $allCollections = DB::connection('mongodb')->getDatabase()->listCollectionNames(); + + // Ensure the system.views collection exists in MongoDB + $this->assertContains('system.views', $allCollections); + + // Ensure Schema::getTables does NOT include system collections + $tables = Schema::getTables(); + foreach ($tables as $table) { + $this->assertFalse(str_starts_with($table['name'], 'system.')); + } + + // Ensure Schema::getTableListing does NOT include system collections + $tableListing = Schema::getTableListing(); + $this->assertNotContains('system.views', $tableListing); + } public function testGetColumns() { From b543b647400e39e0ae9d43e38ba338fea922db7b Mon Sep 17 00:00:00 2001 From: Jason Date: Mon, 24 Mar 2025 12:32:15 +0000 Subject: [PATCH 02/17] chore: remove comment --- Dockerfile | 2 +- composer.json | 3 ++- docker-compose.yml | 2 +- phpunit.xml.dist | 2 +- tests/SchemaTest.php | 26 -------------------------- 5 files changed, 5 insertions(+), 30 deletions(-) diff --git a/Dockerfile b/Dockerfile index 43529d9e4..740ed5852 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -ARG PHP_VERSION=8.1 +ARG PHP_VERSION=8.3 FROM php:${PHP_VERSION}-cli diff --git a/composer.json b/composer.json index 2542b51bb..08a96405a 100644 --- a/composer.json +++ b/composer.json @@ -43,7 +43,8 @@ "doctrine/coding-standard": "12.0.x-dev", "spatie/laravel-query-builder": "^5.6|^6", "phpstan/phpstan": "^1.10", - "rector/rector": "^1.2" + "rector/rector": "^1.2", + "squizlabs/php_codesniffer": "^3.12" }, "conflict": { "illuminate/bus": "< 10.37.2" diff --git a/docker-compose.yml b/docker-compose.yml index fc0f0e49a..8722ca1c8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,7 +3,7 @@ services: tty: true build: . working_dir: /var/www/laravel-mongodb - command: "bash -c 'composer install && composer run test'" + command: "bash -c 'composer install'" environment: MONGODB_URI: 'mongodb://mongodb/' volumes: diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 7044f9069..bb25b6db9 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -17,7 +17,7 @@ - + diff --git a/tests/SchemaTest.php b/tests/SchemaTest.php index 7d6561b36..e24e7a1b3 100644 --- a/tests/SchemaTest.php +++ b/tests/SchemaTest.php @@ -475,32 +475,6 @@ public function testGetTableListingBySchema() $this->assertContains('newcollection', $tables); $this->assertContains('newcollection_two', $tables); } -// Protected method cannot test - // public function testGetAllCollections() - // { - // // Insert test data into normal collections - // DB::connection('mongodb')->table('newcollection')->insert(['test' => 'value']); - // DB::connection('mongodb')->table('newcollection_two')->insert(['test' => 'value']); - - // // Create a view (this creates system.views) - // DB::connection('mongodb')->getDatabase()->command([ - // 'create' => 'test_view', - // 'viewOn' => 'newcollection', - // 'pipeline' => [], - // ]); - - // $collections = Schema::getAllCollections(); - - // $this->assertIsArray($collections); - // $this->assertGreaterThanOrEqual(2, count($collections)); - - // // Ensure normal collections are present - // $this->assertContains('newcollection', $collections); - // $this->assertContains('newcollection_two', $collections); - - // // Ensure system collections are excluded - // $this->assertNotContains('system.views', $collections); - // } public function testSystemCollectionsArePresentButFiltered() { From 1115f8ed30e17b7eff2a33cebb91dd27f55fe275 Mon Sep 17 00:00:00 2001 From: Jason Date: Mon, 24 Mar 2025 13:07:14 +0000 Subject: [PATCH 03/17] feat: separate virtual view and table --- src/Schema/Builder.php | 50 +++++++++++++++++++++++++++++++++++------- tests/SchemaTest.php | 38 ++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 8 deletions(-) diff --git a/src/Schema/Builder.php b/src/Schema/Builder.php index a2213b6c6..2e69b5619 100644 --- a/src/Schema/Builder.php +++ b/src/Schema/Builder.php @@ -143,7 +143,7 @@ public function dropAllTables() } } - /** @param string|null $schema Database name */ + /** @param string|null $schema Database name */ public function getTables($schema = null) { $db = $this->connection->getDatabase($schema); @@ -161,12 +161,8 @@ public function getTables($schema = null) $isView = ($collectionInfo['type'] ?? '') === 'view'; $stats = null; - if (! $isView) { - // Only run aggregation if it's a normal collection - $stats = $db->selectCollection($collectionName)->aggregate([ - ['$collStats' => ['storageStats' => ['scale' => 1]]], - ['$project' => ['storageStats.totalSize' => 1]], - ])->toArray(); + if ($isView) { + continue; } $collections[] = [ @@ -176,7 +172,45 @@ public function getTables($schema = null) 'size' => $stats[0]?->storageStats?->totalSize ?? null, 'comment' => null, 'collation' => null, - 'engine' => $isView ? 'view' : 'collection', + 'engine' => null, + ]; + } + + usort($collections, fn ($a, $b) => $a['name'] <=> $b['name']); + + return $collections; + } + + /** @param string|null $schema Database name */ + public function getViews($schema = null) + { + $db = $this->connection->getDatabase($schema); + $collections = []; + + foreach ($db->listCollections() as $collectionInfo) { + $collectionName = $collectionInfo->getName(); + + // Skip system collections + if (str_starts_with($collectionName, 'system.')) { + continue; + } + + // Skip views it doesnt suport aggregate + $isView = ($collectionInfo['type'] ?? '') === 'view'; + $stats = null; + + if (! $isView) { + continue; + } + + $collections[] = [ + 'name' => $collectionName, + 'schema' => $db->getDatabaseName(), + 'schema_qualified_name' => $db->getDatabaseName() . '.' . $collectionName, + 'size' => null, + 'comment' => null, + 'collation' => null, + 'engine' => null, ]; } diff --git a/tests/SchemaTest.php b/tests/SchemaTest.php index e24e7a1b3..1911c6076 100644 --- a/tests/SchemaTest.php +++ b/tests/SchemaTest.php @@ -431,6 +431,44 @@ public function testGetTables() $this->fail('Collection "newcollection" not found'); } } + public function testGetViews() + { + DB::connection('mongodb')->table('newcollection')->insert(['test' => 'value']); + DB::connection('mongodb')->table('newcollection_two')->insert(['test' => 'value']); + $dbName = DB::connection('mongodb')->getDatabaseName(); + + + DB::connection('mongodb')->getDatabase()->command([ + 'create' => 'test_view', + 'viewOn' => 'newcollection', + 'pipeline' => [], + ]); + + $tables = Schema::getViews(); + + $this->assertIsArray($tables); + $this->assertGreaterThanOrEqual(1, count($tables)); + $found = false; + foreach ($tables as $table) { + $this->assertArrayHasKey('name', $table); + $this->assertArrayHasKey('size', $table); + $this->assertArrayHasKey('schema', $table); + $this->assertArrayHasKey('schema_qualified_name', $table); + + if ($table['name'] === 'test_view') { + $this->assertEquals($dbName, $table['schema']); + $this->assertEquals($dbName . '.test_view', $table['schema_qualified_name']); + $found = true; + } + + // Ensure system collections are excluded + $this->assertFalse(str_starts_with($table['name'], 'system.')); + } + + if (! $found) { + $this->fail('Collection "test_view" not found'); + } + } public function testGetTableListing() { From 887c67fe6fe7d6baf407c6c26be7398e465c4689 Mon Sep 17 00:00:00 2001 From: Jason Date: Mon, 24 Mar 2025 13:09:09 +0000 Subject: [PATCH 04/17] chore: cs fix --- tests/SchemaTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/SchemaTest.php b/tests/SchemaTest.php index 1911c6076..ac39e8e2e 100644 --- a/tests/SchemaTest.php +++ b/tests/SchemaTest.php @@ -431,13 +431,13 @@ public function testGetTables() $this->fail('Collection "newcollection" not found'); } } + public function testGetViews() { DB::connection('mongodb')->table('newcollection')->insert(['test' => 'value']); DB::connection('mongodb')->table('newcollection_two')->insert(['test' => 'value']); $dbName = DB::connection('mongodb')->getDatabaseName(); - DB::connection('mongodb')->getDatabase()->command([ 'create' => 'test_view', 'viewOn' => 'newcollection', @@ -445,7 +445,7 @@ public function testGetViews() ]); $tables = Schema::getViews(); - + $this->assertIsArray($tables); $this->assertGreaterThanOrEqual(1, count($tables)); $found = false; From 8b27d10b053b74248a94c435789a5e2fe9ae9d0a Mon Sep 17 00:00:00 2001 From: Jason Date: Mon, 24 Mar 2025 13:15:51 +0000 Subject: [PATCH 05/17] chore: remove modified dev environment --- Dockerfile | 2 +- composer.json | 3 +-- docker-compose.yml | 2 +- phpunit.xml.dist | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Dockerfile b/Dockerfile index 740ed5852..43529d9e4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -ARG PHP_VERSION=8.3 +ARG PHP_VERSION=8.1 FROM php:${PHP_VERSION}-cli diff --git a/composer.json b/composer.json index 08a96405a..2542b51bb 100644 --- a/composer.json +++ b/composer.json @@ -43,8 +43,7 @@ "doctrine/coding-standard": "12.0.x-dev", "spatie/laravel-query-builder": "^5.6|^6", "phpstan/phpstan": "^1.10", - "rector/rector": "^1.2", - "squizlabs/php_codesniffer": "^3.12" + "rector/rector": "^1.2" }, "conflict": { "illuminate/bus": "< 10.37.2" diff --git a/docker-compose.yml b/docker-compose.yml index 8722ca1c8..fc0f0e49a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,7 +3,7 @@ services: tty: true build: . working_dir: /var/www/laravel-mongodb - command: "bash -c 'composer install'" + command: "bash -c 'composer install && composer run test'" environment: MONGODB_URI: 'mongodb://mongodb/' volumes: diff --git a/phpunit.xml.dist b/phpunit.xml.dist index bb25b6db9..7044f9069 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -17,7 +17,7 @@ - + From c2ccde4699ab6a8b569c422bb458f27e3ee57517 Mon Sep 17 00:00:00 2001 From: Jason Date: Mon, 24 Mar 2025 13:20:55 +0000 Subject: [PATCH 06/17] fix: restore aggregate getTables --- src/Schema/Builder.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Schema/Builder.php b/src/Schema/Builder.php index 2e69b5619..39a3b261f 100644 --- a/src/Schema/Builder.php +++ b/src/Schema/Builder.php @@ -165,6 +165,11 @@ public function getTables($schema = null) continue; } + $stats = $db->selectCollection($collectionName)->aggregate([ + ['$collStats' => ['storageStats' => ['scale' => 1]]], + ['$project' => ['storageStats.totalSize' => 1]], + ])->toArray(); + $collections[] = [ 'name' => $collectionName, 'schema' => $db->getDatabaseName(), From 75fdb03a988abc4731c41cd1e01e3c6216ff2542 Mon Sep 17 00:00:00 2001 From: Jason Date: Mon, 24 Mar 2025 17:42:51 +0000 Subject: [PATCH 07/17] fix: follow suggestions --- src/Schema/Builder.php | 6 +++--- tests/SchemaTest.php | 24 ++++-------------------- 2 files changed, 7 insertions(+), 23 deletions(-) diff --git a/src/Schema/Builder.php b/src/Schema/Builder.php index 39a3b261f..3037565bc 100644 --- a/src/Schema/Builder.php +++ b/src/Schema/Builder.php @@ -158,7 +158,7 @@ public function getTables($schema = null) } // Skip views it doesnt suport aggregate - $isView = ($collectionInfo['type'] ?? '') === 'view'; + $isView = $collectionInfo->getType() === 'view'; $stats = null; if ($isView) { @@ -201,10 +201,10 @@ public function getViews($schema = null) } // Skip views it doesnt suport aggregate - $isView = ($collectionInfo['type'] ?? '') === 'view'; + $isNotView = $collectionInfo->getType() !== 'view'; $stats = null; - if (! $isView) { + if ($isNotView) { continue; } diff --git a/tests/SchemaTest.php b/tests/SchemaTest.php index ac39e8e2e..a9c598653 100644 --- a/tests/SchemaTest.php +++ b/tests/SchemaTest.php @@ -400,11 +400,7 @@ public function testGetTables() $dbName = DB::connection('mongodb')->getDatabaseName(); // Create a view (this creates system.views) - DB::connection('mongodb')->getDatabase()->command([ - 'create' => 'test_view', - 'viewOn' => 'newcollection', - 'pipeline' => [], - ]); + DB::connection('mongodb')->getDatabase()->createCollection('test_view', ['viewOn' => 'newcollection']); $tables = Schema::getTables(); $this->assertIsArray($tables); @@ -438,11 +434,7 @@ public function testGetViews() DB::connection('mongodb')->table('newcollection_two')->insert(['test' => 'value']); $dbName = DB::connection('mongodb')->getDatabaseName(); - DB::connection('mongodb')->getDatabase()->command([ - 'create' => 'test_view', - 'viewOn' => 'newcollection', - 'pipeline' => [], - ]); + DB::connection('mongodb')->getDatabase()->createCollection('test_view', ['viewOn' => 'newcollection']); $tables = Schema::getViews(); @@ -476,11 +468,7 @@ public function testGetTableListing() DB::connection('mongodb')->table('newcollection_two')->insert(['test' => 'value']); // Create a view (this creates system.views) - DB::connection('mongodb')->getDatabase()->command([ - 'create' => 'test_view', - 'viewOn' => 'newcollection', - 'pipeline' => [], - ]); + DB::connection('mongodb')->getDatabase()->createCollection('test_view', ['viewOn' => 'newcollection']); $tables = Schema::getTableListing(); @@ -517,11 +505,7 @@ public function testGetTableListingBySchema() public function testSystemCollectionsArePresentButFiltered() { // Create a view to trigger system.views collection - DB::connection('mongodb')->getDatabase()->command([ - 'create' => 'test_view', - 'viewOn' => 'newcollection', - 'pipeline' => [], - ]); + DB::connection('mongodb')->getDatabase()->createCollection('test_view', ['viewOn' => 'newcollection']); // Get all collections directly from MongoDB $allCollections = DB::connection('mongodb')->getDatabase()->listCollectionNames(); From 76555835e28248929a05a667e67d6a7d47d6ec4d Mon Sep 17 00:00:00 2001 From: Jason Date: Mon, 24 Mar 2025 18:35:15 +0000 Subject: [PATCH 08/17] fix: remove stats, comparison directly in if --- phpunit.xml.dist | 2 +- src/Schema/Builder.php | 12 +++--------- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 7044f9069..bb25b6db9 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -17,7 +17,7 @@ - + diff --git a/src/Schema/Builder.php b/src/Schema/Builder.php index 3037565bc..4e4b125a7 100644 --- a/src/Schema/Builder.php +++ b/src/Schema/Builder.php @@ -158,10 +158,7 @@ public function getTables($schema = null) } // Skip views it doesnt suport aggregate - $isView = $collectionInfo->getType() === 'view'; - $stats = null; - - if ($isView) { + if ($collectionInfo->getType() === 'view') { continue; } @@ -200,11 +197,8 @@ public function getViews($schema = null) continue; } - // Skip views it doesnt suport aggregate - $isNotView = $collectionInfo->getType() !== 'view'; - $stats = null; - - if ($isNotView) { + // Skip normal type collection + if ($collectionInfo->getType() !== 'view') { continue; } From db43bbb4abf0d00679015f58c8516d955e99e5b8 Mon Sep 17 00:00:00 2001 From: Jason Date: Tue, 25 Mar 2025 02:38:58 +0000 Subject: [PATCH 09/17] fix: follow master jmikola suggestions --- phpunit.xml.dist | 2 +- src/Schema/Builder.php | 10 ---------- tests/SchemaTest.php | 4 ++-- 3 files changed, 3 insertions(+), 13 deletions(-) diff --git a/phpunit.xml.dist b/phpunit.xml.dist index bb25b6db9..7044f9069 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -17,7 +17,7 @@ - + diff --git a/src/Schema/Builder.php b/src/Schema/Builder.php index 4e4b125a7..a3ad1018b 100644 --- a/src/Schema/Builder.php +++ b/src/Schema/Builder.php @@ -152,11 +152,6 @@ public function getTables($schema = null) foreach ($db->listCollections() as $collectionInfo) { $collectionName = $collectionInfo->getName(); - // Skip system collections - if (str_starts_with($collectionName, 'system.')) { - continue; - } - // Skip views it doesnt suport aggregate if ($collectionInfo->getType() === 'view') { continue; @@ -192,11 +187,6 @@ public function getViews($schema = null) foreach ($db->listCollections() as $collectionInfo) { $collectionName = $collectionInfo->getName(); - // Skip system collections - if (str_starts_with($collectionName, 'system.')) { - continue; - } - // Skip normal type collection if ($collectionInfo->getType() !== 'view') { continue; diff --git a/tests/SchemaTest.php b/tests/SchemaTest.php index a9c598653..5adbc926a 100644 --- a/tests/SchemaTest.php +++ b/tests/SchemaTest.php @@ -420,7 +420,7 @@ public function testGetTables() } // Ensure system collections are excluded - $this->assertFalse(str_starts_with($table['name'], 'system.')); + $this->assertStringStartsNotWith($table['name'], 'system.'); } if (! $found) { @@ -516,7 +516,7 @@ public function testSystemCollectionsArePresentButFiltered() // Ensure Schema::getTables does NOT include system collections $tables = Schema::getTables(); foreach ($tables as $table) { - $this->assertFalse(str_starts_with($table['name'], 'system.')); + $this->assertStringStartsNotWith($table['name'], 'system.'); } // Ensure Schema::getTableListing does NOT include system collections From 1a0b5dbc3a360d49135ace592daffca3cfa2e001 Mon Sep 17 00:00:00 2001 From: Jason Date: Tue, 25 Mar 2025 02:47:58 +0000 Subject: [PATCH 10/17] chore: fix grammar comment --- src/Schema/Builder.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Schema/Builder.php b/src/Schema/Builder.php index a3ad1018b..8116f91ec 100644 --- a/src/Schema/Builder.php +++ b/src/Schema/Builder.php @@ -152,7 +152,7 @@ public function getTables($schema = null) foreach ($db->listCollections() as $collectionInfo) { $collectionName = $collectionInfo->getName(); - // Skip views it doesnt suport aggregate + // Skip views, which don't support aggregate if ($collectionInfo->getType() === 'view') { continue; } From aa3155e172b6434c42863dd39ef4e17fdf50020a Mon Sep 17 00:00:00 2001 From: Jason Date: Tue, 25 Mar 2025 15:55:30 +0000 Subject: [PATCH 11/17] feat: categorize by collection type, drop database in dropAllTables - Group collections based on type for better organization - dropAllTables removes database --- src/Schema/Builder.php | 28 +++++++++++----------------- tests/SchemaTest.php | 38 -------------------------------------- 2 files changed, 11 insertions(+), 55 deletions(-) diff --git a/src/Schema/Builder.php b/src/Schema/Builder.php index 8116f91ec..998e774aa 100644 --- a/src/Schema/Builder.php +++ b/src/Schema/Builder.php @@ -29,7 +29,6 @@ use function sort; use function sprintf; use function str_ends_with; -use function str_starts_with; use function substr; use function usort; @@ -135,12 +134,18 @@ public function drop($table) $blueprint->drop(); } - /** @inheritdoc */ +/** + * @inheritdoc + * + * Drops the entire database instead of deleting each collection individually. + * + * In MongoDB, dropping the whole database is much faster than dropping collections + * one by one. The database will be automatically recreated when a new connection + * writes to it. + */ public function dropAllTables() { - foreach ($this->getAllCollections() as $collection) { - $this->drop($collection); - } + $this->connection->getDatabase()->drop(); } /** @param string|null $schema Database name */ @@ -231,10 +236,6 @@ public function getTableListing($schema = null, $schemaQualified = false) } $collections = array_merge(...array_values($collections)); - - // Exclude system collections before sorting - $collections = array_filter($collections, fn ($name) => ! str_starts_with($name, 'system.')); - sort($collections); return $collections; @@ -385,14 +386,7 @@ protected function getAllCollections() { $collections = []; foreach ($this->connection->getDatabase()->listCollections() as $collection) { - $name = $collection->getName(); - - // Skip system collections - if (str_starts_with($name, 'system.')) { - continue; - } - - $collections[] = $name; + $collections[] = $collection->getName(); } return $collections; diff --git a/tests/SchemaTest.php b/tests/SchemaTest.php index 5adbc926a..cd2ad1809 100644 --- a/tests/SchemaTest.php +++ b/tests/SchemaTest.php @@ -17,7 +17,6 @@ use function collect; use function count; use function sprintf; -use function str_starts_with; class SchemaTest extends TestCase { @@ -399,9 +398,6 @@ public function testGetTables() DB::connection('mongodb')->table('newcollection_two')->insert(['test' => 'value']); $dbName = DB::connection('mongodb')->getDatabaseName(); - // Create a view (this creates system.views) - DB::connection('mongodb')->getDatabase()->createCollection('test_view', ['viewOn' => 'newcollection']); - $tables = Schema::getTables(); $this->assertIsArray($tables); $this->assertGreaterThanOrEqual(2, count($tables)); @@ -418,9 +414,6 @@ public function testGetTables() $this->assertEquals($dbName . '.newcollection', $table['schema_qualified_name']); $found = true; } - - // Ensure system collections are excluded - $this->assertStringStartsNotWith($table['name'], 'system.'); } if (! $found) { @@ -452,9 +445,6 @@ public function testGetViews() $this->assertEquals($dbName . '.test_view', $table['schema_qualified_name']); $found = true; } - - // Ensure system collections are excluded - $this->assertFalse(str_starts_with($table['name'], 'system.')); } if (! $found) { @@ -467,18 +457,12 @@ public function testGetTableListing() DB::connection('mongodb')->table('newcollection')->insert(['test' => 'value']); DB::connection('mongodb')->table('newcollection_two')->insert(['test' => 'value']); - // Create a view (this creates system.views) - DB::connection('mongodb')->getDatabase()->createCollection('test_view', ['viewOn' => 'newcollection']); - $tables = Schema::getTableListing(); $this->assertIsArray($tables); $this->assertGreaterThanOrEqual(2, count($tables)); $this->assertContains('newcollection', $tables); $this->assertContains('newcollection_two', $tables); - - // Ensure system collections are excluded - $this->assertNotContains('system.views', $tables); } public function testGetTableListingBySchema() @@ -502,28 +486,6 @@ public function testGetTableListingBySchema() $this->assertContains('newcollection_two', $tables); } - public function testSystemCollectionsArePresentButFiltered() - { - // Create a view to trigger system.views collection - DB::connection('mongodb')->getDatabase()->createCollection('test_view', ['viewOn' => 'newcollection']); - - // Get all collections directly from MongoDB - $allCollections = DB::connection('mongodb')->getDatabase()->listCollectionNames(); - - // Ensure the system.views collection exists in MongoDB - $this->assertContains('system.views', $allCollections); - - // Ensure Schema::getTables does NOT include system collections - $tables = Schema::getTables(); - foreach ($tables as $table) { - $this->assertStringStartsNotWith($table['name'], 'system.'); - } - - // Ensure Schema::getTableListing does NOT include system collections - $tableListing = Schema::getTableListing(); - $this->assertNotContains('system.views', $tableListing); - } - public function testGetColumns() { $collection = DB::connection('mongodb')->table('newcollection'); From cd8aa29077b9e5344dd72a7fd3faf98f0253f586 Mon Sep 17 00:00:00 2001 From: Jason Date: Tue, 25 Mar 2025 16:10:55 +0000 Subject: [PATCH 12/17] chore: add test to ensure normal collections are excluded from getViews --- tests/SchemaTest.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/SchemaTest.php b/tests/SchemaTest.php index cd2ad1809..7281ecf7b 100644 --- a/tests/SchemaTest.php +++ b/tests/SchemaTest.php @@ -396,6 +396,7 @@ public function testGetTables() { DB::connection('mongodb')->table('newcollection')->insert(['test' => 'value']); DB::connection('mongodb')->table('newcollection_two')->insert(['test' => 'value']); + DB::connection('mongodb')->getDatabase()->createCollection('test_view', ['viewOn' => 'newcollection']); $dbName = DB::connection('mongodb')->getDatabaseName(); $tables = Schema::getTables(); @@ -408,6 +409,9 @@ public function testGetTables() $this->assertArrayHasKey('schema', $table); $this->assertArrayHasKey('schema_qualified_name', $table); + // Ensure "test_view" is not in the tables list + $this->assertNotEquals('test_view', $table['name'], 'Standard views should not be included in the result of getTables.'); + if ($table['name'] === 'newcollection') { $this->assertEquals(8192, $table['size']); $this->assertEquals($dbName, $table['schema']); @@ -440,6 +444,9 @@ public function testGetViews() $this->assertArrayHasKey('schema', $table); $this->assertArrayHasKey('schema_qualified_name', $table); + // Ensure "normal collections" are not in the views list + $this->assertNotEquals('newcollection', $table['name'], 'Normal collections should not be included in the result of getViews.'); + if ($table['name'] === 'test_view') { $this->assertEquals($dbName, $table['schema']); $this->assertEquals($dbName . '.test_view', $table['schema_qualified_name']); From 8a55690dbf9916e0f1f3a80bc0e013db9fc69e0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Fri, 18 Apr 2025 09:30:06 +0200 Subject: [PATCH 13/17] Fix CS --- src/Schema/Builder.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Schema/Builder.php b/src/Schema/Builder.php index 998e774aa..1ad0f7d13 100644 --- a/src/Schema/Builder.php +++ b/src/Schema/Builder.php @@ -134,15 +134,15 @@ public function drop($table) $blueprint->drop(); } -/** - * @inheritdoc - * - * Drops the entire database instead of deleting each collection individually. - * - * In MongoDB, dropping the whole database is much faster than dropping collections - * one by one. The database will be automatically recreated when a new connection - * writes to it. - */ + /** + * @inheritdoc + * + * Drops the entire database instead of deleting each collection individually. + * + * In MongoDB, dropping the whole database is much faster than dropping collections + * one by one. The database will be automatically recreated when a new connection + * writes to it. + */ public function dropAllTables() { $this->connection->getDatabase()->drop(); From 5b3f50ad20da0b525cf85ea9f05a5615456d2cf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Fri, 18 Apr 2025 09:33:52 +0200 Subject: [PATCH 14/17] Deprecate getAllCollections --- src/Schema/Builder.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Schema/Builder.php b/src/Schema/Builder.php index 1ad0f7d13..b9158d7c0 100644 --- a/src/Schema/Builder.php +++ b/src/Schema/Builder.php @@ -30,8 +30,11 @@ use function sprintf; use function str_ends_with; use function substr; +use function trigger_error; use function usort; +use const E_USER_DEPRECATED; + /** @property Connection $connection */ class Builder extends \Illuminate\Database\Schema\Builder { @@ -380,10 +383,14 @@ public function getCollection($name) /** * Get all of the collections names for the database. * + * @deprecated + * * @return array */ protected function getAllCollections() { + trigger_error(sprintf('Since mongodb/laravel-mongodb:5.4, Method "%s()" is deprecated without replacement.', __METHOD__), E_USER_DEPRECATED); + $collections = []; foreach ($this->connection->getDatabase()->listCollections() as $collection) { $collections[] = $collection->getName(); From aa69f3c52dc0764d4eb4d65efeabfecf56c20dd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Fri, 18 Apr 2025 09:41:59 +0200 Subject: [PATCH 15/17] Remove comment --- tests/SchemaTest.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/SchemaTest.php b/tests/SchemaTest.php index 7281ecf7b..929572cfb 100644 --- a/tests/SchemaTest.php +++ b/tests/SchemaTest.php @@ -408,8 +408,6 @@ public function testGetTables() $this->assertArrayHasKey('size', $table); $this->assertArrayHasKey('schema', $table); $this->assertArrayHasKey('schema_qualified_name', $table); - - // Ensure "test_view" is not in the tables list $this->assertNotEquals('test_view', $table['name'], 'Standard views should not be included in the result of getTables.'); if ($table['name'] === 'newcollection') { From 837fbb3b8e9eeaa62f1dc2fb1b93e3e8fa404121 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Fri, 18 Apr 2025 10:43:03 +0200 Subject: [PATCH 16/17] Split qualified table names provided in db:table command --- src/Schema/Builder.php | 11 +++++++++-- tests/SchemaTest.php | 5 +++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/Schema/Builder.php b/src/Schema/Builder.php index b9158d7c0..a2acc7f47 100644 --- a/src/Schema/Builder.php +++ b/src/Schema/Builder.php @@ -21,6 +21,7 @@ use function assert; use function count; use function current; +use function explode; use function implode; use function in_array; use function is_array; @@ -28,6 +29,7 @@ use function iterator_to_array; use function sort; use function sprintf; +use function str_contains; use function str_ends_with; use function substr; use function trigger_error; @@ -50,7 +52,7 @@ public function hasColumn($table, $column): bool } /** - * Check if columns exists in the collection schema. + * Check if columns exist in the collection schema. * * @param string $table * @param string[] $columns @@ -246,7 +248,12 @@ public function getTableListing($schema = null, $schemaQualified = false) public function getColumns($table) { - $stats = $this->connection->getDatabase()->selectCollection($table)->aggregate([ + $db = null; + if (str_contains($table, '.')) { + [$db, $table] = explode('.', $table, 2); + } + + $stats = $this->connection->getDatabase($db)->selectCollection($table)->aggregate([ // Sample 1,000 documents to get a representative sample of the collection ['$sample' => ['size' => 1_000]], // Convert each document to an array of fields diff --git a/tests/SchemaTest.php b/tests/SchemaTest.php index 929572cfb..159b733aa 100644 --- a/tests/SchemaTest.php +++ b/tests/SchemaTest.php @@ -526,6 +526,11 @@ public function testGetColumns() // Non-existent collection $columns = Schema::getColumns('missing'); $this->assertSame([], $columns); + + // Qualified table name + $columns = Schema::getColumns(DB::getDatabaseName().'.newcollection'); + $this->assertIsArray($columns); + $this->assertCount(5, $columns); } /** @see AtlasSearchTest::testGetIndexes() */ From b36efb18d9f28d357c30260966c2e74e7c8b35f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Fri, 18 Apr 2025 10:58:35 +0200 Subject: [PATCH 17/17] Fix CS --- src/Schema/Builder.php | 3 ++- tests/SchemaTest.php | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Schema/Builder.php b/src/Schema/Builder.php index a2acc7f47..746fda99e 100644 --- a/src/Schema/Builder.php +++ b/src/Schema/Builder.php @@ -153,7 +153,7 @@ public function dropAllTables() $this->connection->getDatabase()->drop(); } - /** @param string|null $schema Database name */ + /** @param string|null $schema Database name */ public function getTables($schema = null) { $db = $this->connection->getDatabase($schema); @@ -241,6 +241,7 @@ public function getTableListing($schema = null, $schemaQualified = false) } $collections = array_merge(...array_values($collections)); + sort($collections); return $collections; diff --git a/tests/SchemaTest.php b/tests/SchemaTest.php index 159b733aa..3257a671e 100644 --- a/tests/SchemaTest.php +++ b/tests/SchemaTest.php @@ -528,7 +528,7 @@ public function testGetColumns() $this->assertSame([], $columns); // Qualified table name - $columns = Schema::getColumns(DB::getDatabaseName().'.newcollection'); + $columns = Schema::getColumns(DB::getDatabaseName() . '.newcollection'); $this->assertIsArray($columns); $this->assertCount(5, $columns); }