Skip to content

Commit 8fd5c35

Browse files
[10.x] Add hasIndex() and minor Schema enhancements (#49796)
* add hasIndex, getIndexListing and getTableListing * minor schema enhancements * fix tests * Update Builder.php --------- Co-authored-by: Taylor Otwell <[email protected]>
1 parent caee0bd commit 8fd5c35

File tree

8 files changed

+85
-17
lines changed

8 files changed

+85
-17
lines changed

src/Illuminate/Database/Query/Processors/MySqlProcessor.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public function processColumns($results)
3838
'nullable' => $result->nullable === 'YES',
3939
'default' => $result->default,
4040
'auto_increment' => $result->extra === 'auto_increment',
41-
'comment' => $result->comment,
41+
'comment' => $result->comment ?: null,
4242
];
4343
}, $results);
4444
}

src/Illuminate/Database/Schema/Builder.php

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,16 @@ public function getTables()
202202
);
203203
}
204204

205+
/**
206+
* Get the names of the tables that belong to the database.
207+
*
208+
* @return array
209+
*/
210+
public function getTableListing()
211+
{
212+
return array_column($this->getTables(), 'name');
213+
}
214+
205215
/**
206216
* Get the views that belong to the database.
207217
*
@@ -370,6 +380,55 @@ public function getIndexes($table)
370380
);
371381
}
372382

383+
/**
384+
* Get the names of the indexes for a given table.
385+
*
386+
* @param string $table
387+
* @return array
388+
*/
389+
public function getIndexListing($table)
390+
{
391+
return array_column($this->getIndexes($table), 'name');
392+
}
393+
394+
/**
395+
* Determine if the given table has a given index.
396+
*
397+
* @param string $table
398+
* @param string|array $index
399+
* @param string|null $type
400+
* @return bool
401+
*/
402+
public function hasIndex($table, $index, $type = null)
403+
{
404+
$type = is_null($type) ? $type : strtolower($type);
405+
406+
if (is_array($index)) {
407+
sort($index);
408+
}
409+
410+
foreach ($this->getIndexes($table) as $value) {
411+
$typeMatches = is_null($type)
412+
|| ($type === 'primary' && $value['primary'])
413+
|| ($type === 'unique' && $value['unique'])
414+
|| $type === $value['type'];
415+
416+
if ($value['name'] === $index && $typeMatches) {
417+
return true;
418+
}
419+
420+
if (is_array($index)) {
421+
sort($value['columns']);
422+
423+
if ($value['columns'] === $index && $typeMatches) {
424+
return true;
425+
}
426+
}
427+
}
428+
429+
return false;
430+
}
431+
373432
/**
374433
* Get the foreign keys for a given table.
375434
*

src/Illuminate/Database/Schema/ColumnDefinition.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
* @method $this default(mixed $value) Specify a "default" value for the column
1616
* @method $this first() Place the column "first" in the table (MySQL)
1717
* @method $this from(int $startingValue) Set the starting value of an auto-incrementing field (MySQL / PostgreSQL)
18-
* @method $this generatedAs(string|Expression $expression = null) Create a SQL compliant identity column (PostgreSQL)
18+
* @method $this generatedAs(string|\Illuminate\Database\Query\Expression $expression = null) Create a SQL compliant identity column (PostgreSQL)
1919
* @method $this index(string $indexName = null) Add an index
2020
* @method $this invisible() Specify that the column should be invisible to "SELECT *" (MySQL)
2121
* @method $this nullable(bool $value = true) Allow NULL values to be inserted into the column

src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ public function compileTables()
8787
{
8888
return 'select c.relname as name, n.nspname as schema, pg_total_relation_size(c.oid) as size, '
8989
."obj_description(c.oid, 'pg_class') as comment from pg_class c, pg_namespace n "
90-
."where c.relkind in ('r', 'p') and n.oid = c.relnamespace and n.nspname not in ('pg_catalog', 'information_schema')"
90+
."where c.relkind in ('r', 'p') and n.oid = c.relnamespace and n.nspname not in ('pg_catalog', 'information_schema') "
9191
.'order by c.relname';
9292
}
9393

src/Illuminate/Support/Facades/Schema.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
* @method static bool dropDatabaseIfExists(string $name)
1313
* @method static bool hasTable(string $table)
1414
* @method static bool hasView(string $view)
15+
* @method static bool hasIndex(string $table, string|array $index, string|null $type = null)
1516
* @method static array getTables()
1617
* @method static array getViews()
1718
* @method static array getTypes()
@@ -20,7 +21,9 @@
2021
* @method static void whenTableHasColumn(string $table, string $column, \Closure $callback)
2122
* @method static void whenTableDoesntHaveColumn(string $table, string $column, \Closure $callback)
2223
* @method static string getColumnType(string $table, string $column, bool $fullDefinition = false)
24+
* @method static array getTableListing()
2325
* @method static array getColumnListing(string $table)
26+
* @method static array getIndexListing(string $table)
2427
* @method static array getColumns(string $table)
2528
* @method static array getIndexes(string $table)
2629
* @method static array getForeignKeys(string $table)

tests/Database/DatabaseSQLiteSchemaGrammarTest.php

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ public function testRenameIndex()
164164
$table->index(['name', 'email'], 'index1');
165165
});
166166

167-
$indexes = array_column($schema->getIndexes('users'), 'name');
167+
$indexes = $schema->getIndexListing('users');
168168

169169
$this->assertContains('index1', $indexes);
170170
$this->assertNotContains('index2', $indexes);
@@ -173,10 +173,8 @@ public function testRenameIndex()
173173
$table->renameIndex('index1', 'index2');
174174
});
175175

176-
$indexes = $schema->getIndexes('users');
177-
178-
$this->assertNotContains('index1', array_column($indexes, 'name'));
179-
$this->assertTrue(collect($indexes)->contains(
176+
$this->assertFalse($schema->hasIndex('users', 'index1'));
177+
$this->assertTrue(collect($schema->getIndexes('users'))->contains(
180178
fn ($index) => $index['name'] === 'index2' && $index['columns'] === ['name', 'email']
181179
));
182180
}

tests/Database/DatabaseSchemaBuilderIntegrationTest.php

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -87,10 +87,7 @@ public function testHasColumnAndIndexWithPrefixIndexDisabled()
8787
$table->string('name')->index();
8888
});
8989

90-
$this->assertContains(
91-
'table1_name_index',
92-
array_column($this->db->connection()->getSchemaBuilder()->getIndexes('table1'), 'name')
93-
);
90+
$this->assertTrue($this->db->connection()->getSchemaBuilder()->hasIndex('table1', 'table1_name_index'));
9491
}
9592

9693
public function testHasColumnAndIndexWithPrefixIndexEnabled()
@@ -107,10 +104,7 @@ public function testHasColumnAndIndexWithPrefixIndexEnabled()
107104
$table->string('name')->index();
108105
});
109106

110-
$this->assertContains(
111-
'example_table1_name_index',
112-
array_column($this->db->connection()->getSchemaBuilder()->getIndexes('table1'), 'name')
113-
);
107+
$this->assertTrue($this->db->connection()->getSchemaBuilder()->hasIndex('table1', 'example_table1_name_index'));
114108
}
115109

116110
public function testDropColumnWithTablePrefix()

tests/Integration/Database/SchemaBuilderTest.php

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,15 +193,20 @@ public function testGetAndDropTypes()
193193
DB::statement("create type enum_foo as enum ('new', 'open', 'closed')");
194194
DB::statement('create type range_foo as range (subtype = float8)');
195195
DB::statement('create domain domain_foo as text');
196+
DB::statement('create type base_foo');
197+
DB::statement("create function foo_in(cstring) returns base_foo language internal immutable strict parallel safe as 'int2in'");
198+
DB::statement("create function foo_out(base_foo) returns cstring language internal immutable strict parallel safe as 'int2out'");
199+
DB::statement('create type base_foo (input = foo_in, output = foo_out)');
196200

197201
$types = Schema::getTypes();
198202

199-
$this->assertCount(11, $types);
203+
$this->assertCount(13, $types);
200204
$this->assertTrue(collect($types)->contains(fn ($type) => $type['name'] === 'pseudo_foo' && $type['type'] === 'pseudo' && ! $type['implicit']));
201205
$this->assertTrue(collect($types)->contains(fn ($type) => $type['name'] === 'comp_foo' && $type['type'] === 'composite' && ! $type['implicit']));
202206
$this->assertTrue(collect($types)->contains(fn ($type) => $type['name'] === 'enum_foo' && $type['type'] === 'enum' && ! $type['implicit']));
203207
$this->assertTrue(collect($types)->contains(fn ($type) => $type['name'] === 'range_foo' && $type['type'] === 'range' && ! $type['implicit']));
204208
$this->assertTrue(collect($types)->contains(fn ($type) => $type['name'] === 'domain_foo' && $type['type'] === 'domain' && ! $type['implicit']));
209+
$this->assertTrue(collect($types)->contains(fn ($type) => $type['name'] === 'base_foo' && $type['type'] === 'base' && ! $type['implicit']));
205210

206211
Schema::dropAllTypes();
207212
$types = Schema::getTypes();
@@ -256,6 +261,10 @@ public function testGetIndexes()
256261
&& ! $indexes[0]['unique']
257262
&& ! $indexes[0]['primary']
258263
);
264+
$this->assertTrue(Schema::hasIndex('foo', 'my_index'));
265+
$this->assertTrue(Schema::hasIndex('foo', ['bar']));
266+
$this->assertFalse(Schema::hasIndex('foo', 'my_index', 'primary'));
267+
$this->assertFalse(Schema::hasIndex('foo', ['bar'], 'unique'));
259268
}
260269

261270
public function testGetUniqueIndexes()
@@ -277,6 +286,11 @@ public function testGetUniqueIndexes()
277286
$this->assertTrue(collect($indexes)->contains(
278287
fn ($index) => $index['name'] === 'foo_baz_bar_unique' && $index['columns'] === ['baz', 'bar'] && $index['unique']
279288
));
289+
$this->assertTrue(Schema::hasIndex('foo', 'foo_baz_bar_unique'));
290+
$this->assertTrue(Schema::hasIndex('foo', 'foo_baz_bar_unique', 'unique'));
291+
$this->assertTrue(Schema::hasIndex('foo', ['bar', 'baz']));
292+
$this->assertTrue(Schema::hasIndex('foo', ['bar', 'baz'], 'unique'));
293+
$this->assertFalse(Schema::hasIndex('foo', ['bar', 'baz'], 'primary'));
280294
}
281295

282296
public function testGetIndexesWithCompositeKeys()

0 commit comments

Comments
 (0)