Skip to content

Commit 7d26bfb

Browse files
[10.x] Get indexes of a table (#49204)
* get indexes * fix tests * minor improvements * minor improvements * minor improvements
1 parent fd208de commit 7d26bfb

16 files changed

+340
-10
lines changed

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,25 @@ public function processColumns($results)
4242
];
4343
}, $results);
4444
}
45+
46+
/**
47+
* Process the results of an indexes query.
48+
*
49+
* @param array $results
50+
* @return array
51+
*/
52+
public function processIndexes($results)
53+
{
54+
return array_map(function ($result) {
55+
$result = (object) $result;
56+
57+
return [
58+
'name' => $name = strtolower($result->name),
59+
'columns' => explode(',', $result->columns),
60+
'type' => strtolower($result->type),
61+
'unique' => (bool) $result->unique,
62+
'primary' => $name === 'primary',
63+
];
64+
}, $results);
65+
}
4566
}

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,4 +70,25 @@ public function processColumns($results)
7070
];
7171
}, $results);
7272
}
73+
74+
/**
75+
* Process the results of an indexes query.
76+
*
77+
* @param array $results
78+
* @return array
79+
*/
80+
public function processIndexes($results)
81+
{
82+
return array_map(function ($result) {
83+
$result = (object) $result;
84+
85+
return [
86+
'name' => strtolower($result->name),
87+
'columns' => explode(',', $result->columns),
88+
'type' => strtolower($result->type),
89+
'unique' => (bool) $result->unique,
90+
'primary' => (bool) $result->primary,
91+
];
92+
}, $results);
93+
}
7394
}

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,17 @@ public function processColumns($results)
8888
return $results;
8989
}
9090

91+
/**
92+
* Process the results of an indexes query.
93+
*
94+
* @param array $results
95+
* @return array
96+
*/
97+
public function processIndexes($results)
98+
{
99+
return $results;
100+
}
101+
91102
/**
92103
* Process the results of a column listing query.
93104
*

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

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,37 @@ public function processColumns($results)
4646
];
4747
}, $results);
4848
}
49+
50+
/**
51+
* Process the results of an indexes query.
52+
*
53+
* @param array $results
54+
* @return array
55+
*/
56+
public function processIndexes($results)
57+
{
58+
$primaryCount = 0;
59+
60+
$indexes = array_map(function ($result) use (&$primaryCount) {
61+
$result = (object) $result;
62+
63+
if ($isPrimary = (bool) $result->primary) {
64+
$primaryCount += 1;
65+
}
66+
67+
return [
68+
'name' => strtolower($result->name),
69+
'columns' => explode(',', $result->columns),
70+
'type' => null,
71+
'unique' => (bool) $result->unique,
72+
'primary' => $isPrimary,
73+
];
74+
}, $results);
75+
76+
if ($primaryCount > 1) {
77+
$indexes = array_filter($indexes, fn ($index) => $index['name'] !== 'primary');
78+
}
79+
80+
return $indexes;
81+
}
4982
}

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,4 +100,25 @@ public function processColumns($results)
100100
];
101101
}, $results);
102102
}
103+
104+
/**
105+
* Process the results of an indexes query.
106+
*
107+
* @param array $results
108+
* @return array
109+
*/
110+
public function processIndexes($results)
111+
{
112+
return array_map(function ($result) {
113+
$result = (object) $result;
114+
115+
return [
116+
'name' => strtolower($result->name),
117+
'columns' => explode(',', $result->columns),
118+
'type' => strtolower($result->type),
119+
'unique' => (bool) $result->unique,
120+
'primary' => (bool) $result->primary,
121+
];
122+
}, $results);
123+
}
103124
}

src/Illuminate/Database/Schema/Builder.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,21 @@ public function getColumns($table)
342342
);
343343
}
344344

345+
/**
346+
* Get the indexes for a given table.
347+
*
348+
* @param string $table
349+
* @return array
350+
*/
351+
public function getIndexes($table)
352+
{
353+
$table = $this->connection->getTablePrefix().$table;
354+
355+
return $this->connection->getPostProcessor()->processIndexes(
356+
$this->connection->selectFromWriteConnection($this->grammar->compileIndexes($table))
357+
);
358+
}
359+
345360
/**
346361
* Modify a table on the schema.
347362
*

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,25 @@ public function compileColumns($database, $table)
166166
);
167167
}
168168

169+
/**
170+
* Compile the query to determine the indexes.
171+
*
172+
* @param string $database
173+
* @param string $table
174+
* @return string
175+
*/
176+
public function compileIndexes($database, $table)
177+
{
178+
return sprintf(
179+
'select index_name as `name`, group_concat(column_name order by seq_in_index) as `columns`, '
180+
.'index_type as `type`, not non_unique as `unique` '
181+
.'from information_schema.statistics where table_schema = %s and table_name = %s '
182+
.'group by index_name, index_type, non_unique',
183+
$this->quoteString($database),
184+
$this->quoteString($table)
185+
);
186+
}
187+
169188
/**
170189
* Compile a create table command.
171190
*

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

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,32 @@ public function compileColumns($database, $schema, $table)
163163
);
164164
}
165165

166+
/**
167+
* Compile the query to determine the indexes.
168+
*
169+
* @param string $schema
170+
* @param string $table
171+
* @return string
172+
*/
173+
public function compileIndexes($schema, $table)
174+
{
175+
return sprintf(
176+
"select ic.relname as name, string_agg(a.attname, ',' order by indseq.ord) as columns, "
177+
.'am.amname as "type", i.indisunique as "unique", i.indisprimary as "primary" '
178+
.'from pg_index i '
179+
.'join pg_class tc on tc.oid = i.indrelid '
180+
.'join pg_namespace tn on tn.oid = tc.relnamespace '
181+
.'join pg_class ic on ic.oid = i.indexrelid '
182+
.'join pg_am am on am.oid = ic.relam '
183+
.'join lateral unnest(i.indkey) with ordinality as indseq(num, ord) on true '
184+
.'left join pg_attribute a on a.attrelid = i.indrelid and a.attnum = indseq.num '
185+
.'where tc.relname = %s and tn.nspname = %s '
186+
.'group by ic.relname, am.amname, i.indisunique, i.indisprimary',
187+
$this->quoteString($table),
188+
$this->quoteString($schema)
189+
);
190+
}
191+
166192
/**
167193
* Compile a create table command.
168194
*

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,25 @@ public function compileColumns($table)
127127
);
128128
}
129129

130+
/**
131+
* Compile the query to determine the indexes.
132+
*
133+
* @param string $table
134+
* @return string
135+
*/
136+
public function compileIndexes($table)
137+
{
138+
return sprintf(
139+
'select "primary" as name, group_concat(col) as columns, 1 as "unique", 1 as "primary" '
140+
.'from (select name as col from pragma_table_info(%s) where pk > 0 order by pk, cid) group by name '
141+
.'union select name, group_concat(col) as columns, "unique", origin = "pk" as "primary" '
142+
.'from (select il.*, ii.name as col from pragma_index_list(%s) il, pragma_index_info(il.name) ii order by il.seq, ii.seqno) '
143+
.'group by name, "unique", "primary"',
144+
$table = $this->wrap(str_replace('.', '__', $table)),
145+
$table
146+
);
147+
}
148+
130149
/**
131150
* Compile a create table command.
132151
*

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,28 @@ public function compileColumns($table)
167167
);
168168
}
169169

170+
/**
171+
* Compile the query to determine the indexes.
172+
*
173+
* @param string $table
174+
* @return string
175+
*/
176+
public function compileIndexes($table)
177+
{
178+
return sprintf(
179+
"select idx.name as name, string_agg(col.name, ',') within group (order by idxcol.key_ordinal) as columns, "
180+
.'idx.type_desc as [type], idx.is_unique as [unique], idx.is_primary_key as [primary] '
181+
.'from sys.indexes as idx '
182+
.'join sys.tables as tbl on idx.object_id = tbl.object_id '
183+
.'join sys.schemas as scm on tbl.schema_id = scm.schema_id '
184+
.'join sys.index_columns as idxcol on idx.object_id = idxcol.object_id and idx.index_id = idxcol.index_id '
185+
.'join sys.columns as col on idxcol.object_id = col.object_id and idxcol.column_id = col.column_id '
186+
.'where tbl.name = %s and scm.name = SCHEMA_NAME() '
187+
.'group by idx.name, idx.type_desc, idx.is_unique, idx.is_primary_key',
188+
$this->quoteString($table),
189+
);
190+
}
191+
170192
/**
171193
* Compile a create table command.
172194
*

src/Illuminate/Database/Schema/MySqlBuilder.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,23 @@ public function getColumns($table)
103103
return $this->connection->getPostProcessor()->processColumns($results);
104104
}
105105

106+
/**
107+
* Get the indexes for a given table.
108+
*
109+
* @param string $table
110+
* @return array
111+
*/
112+
public function getIndexes($table)
113+
{
114+
$table = $this->connection->getTablePrefix().$table;
115+
116+
return $this->connection->getPostProcessor()->processIndexes(
117+
$this->connection->selectFromWriteConnection(
118+
$this->grammar->compileIndexes($this->connection->getDatabaseName(), $table)
119+
)
120+
);
121+
}
122+
106123
/**
107124
* Drop all tables from the database.
108125
*

src/Illuminate/Database/Schema/PostgresBuilder.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,23 @@ public function getColumns($table)
203203
return $this->connection->getPostProcessor()->processColumns($results);
204204
}
205205

206+
/**
207+
* Get the indexes for a given table.
208+
*
209+
* @param string $table
210+
* @return array
211+
*/
212+
public function getIndexes($table)
213+
{
214+
[, $schema, $table] = $this->parseSchemaAndTable($table);
215+
216+
$table = $this->connection->getTablePrefix().$table;
217+
218+
return $this->connection->getPostProcessor()->processIndexes(
219+
$this->connection->selectFromWriteConnection($this->grammar->compileIndexes($schema, $table))
220+
);
221+
}
222+
206223
/**
207224
* Get the schemas for the connection.
208225
*

src/Illuminate/Support/Facades/Schema.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
* @method static string getColumnType(string $table, string $column, bool $fullDefinition = false)
2222
* @method static array getColumnListing(string $table)
2323
* @method static array getColumns(string $table)
24+
* @method static array getIndexes(string $table)
2425
* @method static void table(string $table, \Closure $callback)
2526
* @method static void create(string $table, \Closure $callback)
2627
* @method static void drop(string $table)

tests/Database/DatabaseSQLiteSchemaGrammarTest.php

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

167-
$manager = $db->getConnection()->getDoctrineSchemaManager();
168-
$details = $manager->listTableDetails('prefix_users');
169-
$this->assertTrue($details->hasIndex('index1'));
170-
$this->assertFalse($details->hasIndex('index2'));
167+
$indexes = array_column($schema->getIndexes('users'), 'name');
168+
169+
$this->assertContains('index1', $indexes);
170+
$this->assertNotContains('index2', $indexes);
171171

172172
$schema->table('users', function (Blueprint $table) {
173173
$table->renameIndex('index1', 'index2');
174174
});
175175

176-
$details = $manager->listTableDetails('prefix_users');
177-
$this->assertFalse($details->hasIndex('index1'));
178-
$this->assertTrue($details->hasIndex('index2'));
176+
$indexes = $schema->getIndexes('users');
179177

180-
$this->assertEquals(['name', 'email'], $details->getIndex('index2')->getUnquotedColumns());
178+
$this->assertNotContains('index1', array_column($indexes, 'name'));
179+
$this->assertTrue(collect($indexes)->contains(
180+
fn ($index) => $index['name'] === 'index2' && $index['columns'] === ['name', 'email']
181+
));
181182
}
182183

183184
public function testAddingPrimaryKey()

tests/Database/DatabaseSchemaBuilderIntegrationTest.php

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

90-
$this->assertArrayHasKey('table1_name_index', $this->db->connection()->getDoctrineSchemaManager()->listTableIndexes('example_table1'));
90+
$this->assertContains(
91+
'table1_name_index',
92+
array_column($this->db->connection()->getSchemaBuilder()->getIndexes('table1'), 'name')
93+
);
9194
}
9295

9396
public function testHasColumnAndIndexWithPrefixIndexEnabled()
@@ -104,7 +107,10 @@ public function testHasColumnAndIndexWithPrefixIndexEnabled()
104107
$table->string('name')->index();
105108
});
106109

107-
$this->assertArrayHasKey('example_table1_name_index', $this->db->connection()->getDoctrineSchemaManager()->listTableIndexes('example_table1'));
110+
$this->assertContains(
111+
'example_table1_name_index',
112+
array_column($this->db->connection()->getSchemaBuilder()->getIndexes('table1'), 'name')
113+
);
108114
}
109115

110116
public function testDropColumnWithTablePrefix()

0 commit comments

Comments
 (0)