Skip to content

Commit 72be9c2

Browse files
committedJul 15, 2024
PHPORM-215 Implement Schema::getColumns and getIndexes
1 parent 256a830 commit 72be9c2

File tree

3 files changed

+139
-1
lines changed

3 files changed

+139
-1
lines changed
 

‎CHANGELOG.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ All notable changes to this project will be documented in this file.
44
## [4.9.0] - coming soon
55

66
* Add `Connection::getServerVersion()` by @GromNaN in [#3043](https://github.com/mongodb/laravel-mongodb/pull/3043)
7-
* Add `Schema\Builder::getTables()` and `getTableListing` by @GromNaN in [#3044](https://github.com/mongodb/laravel-mongodb/pull/3044)
7+
* Add `Schema\Builder::getTables()` and `getTableListing()` by @GromNaN in [#3044](https://github.com/mongodb/laravel-mongodb/pull/3044)
8+
* Add `Schema\Builder::getColumns()` and `getIndexes()` by @GromNaN in [#3045](https://github.com/mongodb/laravel-mongodb/pull/3045)
89

910
## [4.6.0] - 2024-07-09
1011

‎src/Schema/Builder.php

+70
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,17 @@
66

77
use Closure;
88
use MongoDB\Model\CollectionInfo;
9+
use MongoDB\Model\IndexInfo;
10+
use stdClass;
911

12+
use function array_keys;
13+
use function assert;
1014
use function count;
1115
use function current;
16+
use function implode;
1217
use function iterator_to_array;
1318
use function sort;
19+
use function sprintf;
1420
use function usort;
1521

1622
class Builder extends \Illuminate\Database\Schema\Builder
@@ -146,6 +152,70 @@ public function getTableListing()
146152
return $collections;
147153
}
148154

155+
public function getColumns($table)
156+
{
157+
$stats = $this->connection->getMongoDB()->selectCollection($table)->aggregate([
158+
['$project' => ['fields' => ['$objectToArray' => '$$ROOT']]],
159+
['$unwind' => '$fields'],
160+
[
161+
'$group' => [
162+
'_id' => '$fields.k',
163+
'total' => ['$count' => new stdClass()],
164+
'types' => ['$addToSet' => ['$type' => '$fields.v']],
165+
],
166+
],
167+
['$sort' => ['_id' => 1]],
168+
], ['typeMap' => ['array' => 'array']])->toArray();
169+
170+
$columns = [];
171+
foreach ($stats as $stat) {
172+
sort($stat->types);
173+
$type = implode(', ', $stat->types);
174+
$columns[] = [
175+
'name' => $stat->_id,
176+
'type_name' => $type,
177+
'type' => $type,
178+
'collation' => null,
179+
'nullable' => $stat->_id !== '_id',
180+
'default' => null,
181+
'auto_increment' => false,
182+
'comment' => sprintf('%d occurrences', $stat->total),
183+
'generation' => $stat->_id === '_id' ? ['type' => 'objectId', 'expression' => null] : null,
184+
];
185+
}
186+
187+
return $columns;
188+
}
189+
190+
public function getIndexes($table)
191+
{
192+
$indexes = $this->connection->getMongoDB()->selectCollection($table)->listIndexes();
193+
194+
$indexList = [];
195+
foreach ($indexes as $index) {
196+
assert($index instanceof IndexInfo);
197+
$indexList[] = [
198+
'name' => $index->getName(),
199+
'columns' => array_keys($index->getKey()),
200+
'primary' => $index->getKey() === ['_id' => 1],
201+
'type' => match (true) {
202+
$index->isText() => 'text',
203+
$index->is2dSphere() => '2dsphere',
204+
$index->isTtl() => 'ttl',
205+
default => 'default',
206+
},
207+
'unique' => $index->isUnique(),
208+
];
209+
}
210+
211+
return $indexList;
212+
}
213+
214+
public function getForeignKeys($table)
215+
{
216+
return [];
217+
}
218+
149219
/** @inheritdoc */
150220
protected function createBlueprint($table, ?Closure $callback = null)
151221
{

‎tests/SchemaTest.php

+67
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,11 @@
66

77
use Illuminate\Support\Facades\DB;
88
use Illuminate\Support\Facades\Schema;
9+
use MongoDB\BSON\Binary;
10+
use MongoDB\BSON\UTCDateTime;
911
use MongoDB\Laravel\Schema\Blueprint;
1012

13+
use function collect;
1114
use function count;
1215

1316
class SchemaTest extends TestCase
@@ -416,6 +419,70 @@ public function testGetTableListing()
416419
$this->assertContains('newcollection_two', $tables);
417420
}
418421

422+
public function testGetColumns()
423+
{
424+
$collection = DB::connection('mongodb')->collection('newcollection');
425+
$collection->insert(['text' => 'value', 'mixed' => ['key' => 'value']]);
426+
$collection->insert(['date' => new UTCDateTime(), 'binary' => new Binary('binary'), 'mixed' => true]);
427+
428+
$columns = Schema::getColumns('newcollection');
429+
$this->assertIsArray($columns);
430+
$this->assertCount(5, $columns);
431+
432+
$columns = collect($columns)->keyBy('name');
433+
434+
$columns->each(function ($column) {
435+
$this->assertIsString($column['name']);
436+
$this->assertEquals($column['type'], $column['type_name']);
437+
$this->assertNull($column['collation']);
438+
$this->assertIsBool($column['nullable']);
439+
$this->assertNull($column['default']);
440+
$this->assertFalse($column['auto_increment']);
441+
$this->assertIsString($column['comment']);
442+
});
443+
444+
$this->assertEquals('objectId', $columns->get('_id')['type']);
445+
$this->assertEquals('objectId', $columns->get('_id')['generation']['type']);
446+
$this->assertNull($columns->get('text')['generation']);
447+
$this->assertEquals('string', $columns->get('text')['type']);
448+
$this->assertEquals('date', $columns->get('date')['type']);
449+
$this->assertEquals('binData', $columns->get('binary')['type']);
450+
$this->assertEquals('bool, object', $columns->get('mixed')['type']);
451+
$this->assertEquals('2 occurrences', $columns->get('mixed')['comment']);
452+
453+
// Non-existent collection
454+
$columns = Schema::getColumns('missing');
455+
$this->assertSame([], $columns);
456+
}
457+
458+
public function testGetIndexes()
459+
{
460+
Schema::create('newcollection', function (Blueprint $collection) {
461+
$collection->index('mykey1');
462+
$collection->string('mykey2')->unique('unique_index');
463+
$collection->string('mykey3')->index();
464+
});
465+
$indexes = Schema::getIndexes('newcollection');
466+
$this->assertIsArray($indexes);
467+
$this->assertCount(4, $indexes);
468+
469+
$indexes = collect($indexes)->keyBy('name');
470+
471+
$indexes->each(function ($index) {
472+
$this->assertIsString($index['name']);
473+
$this->assertIsString($index['type']);
474+
$this->assertIsArray($index['columns']);
475+
$this->assertIsBool($index['unique']);
476+
$this->assertIsBool($index['primary']);
477+
});
478+
$this->assertTrue($indexes->get('_id_')['primary']);
479+
$this->assertTrue($indexes->get('unique_index_1')['unique']);
480+
481+
// Non-existent collection
482+
$indexes = Schema::getIndexes('missing');
483+
$this->assertSame([], $indexes);
484+
}
485+
419486
protected function getIndex(string $collection, string $name)
420487
{
421488
$collection = DB::getCollection($collection);

0 commit comments

Comments
 (0)