| 214 | } |
| 215 | |
| 216 | export async function executeIntrospect( |
| 217 | connection: mysql.Connection, |
| 218 | databaseName: string |
| 219 | ): Promise<MySQLIntrospectionResult> { |
| 220 | const [databasesRows] = await connection.execute<mysql.RowDataPacket[]>( |
| 221 | `SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA |
| 222 | WHERE SCHEMA_NAME NOT IN ('mysql', 'information_schema', 'performance_schema', 'sys') |
| 223 | ORDER BY SCHEMA_NAME` |
| 224 | ) |
| 225 | const databases = databasesRows.map((row) => row.SCHEMA_NAME) |
| 226 | |
| 227 | const [tablesRows] = await connection.execute<mysql.RowDataPacket[]>( |
| 228 | `SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES |
| 229 | WHERE TABLE_SCHEMA = ? AND TABLE_TYPE = 'BASE TABLE' |
| 230 | ORDER BY TABLE_NAME`, |
| 231 | [databaseName] |
| 232 | ) |
| 233 | |
| 234 | const tables = [] |
| 235 | |
| 236 | for (const tableRow of tablesRows) { |
| 237 | const tableName = tableRow.TABLE_NAME |
| 238 | |
| 239 | const [columnsRows] = await connection.execute<mysql.RowDataPacket[]>( |
| 240 | `SELECT COLUMN_NAME, DATA_TYPE, COLUMN_TYPE, IS_NULLABLE, COLUMN_DEFAULT, EXTRA |
| 241 | FROM INFORMATION_SCHEMA.COLUMNS |
| 242 | WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ? |
| 243 | ORDER BY ORDINAL_POSITION`, |
| 244 | [databaseName, tableName] |
| 245 | ) |
| 246 | |
| 247 | const [pkRows] = await connection.execute<mysql.RowDataPacket[]>( |
| 248 | `SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE |
| 249 | WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ? AND CONSTRAINT_NAME = 'PRIMARY' |
| 250 | ORDER BY ORDINAL_POSITION`, |
| 251 | [databaseName, tableName] |
| 252 | ) |
| 253 | const primaryKeyColumns = pkRows.map((row) => row.COLUMN_NAME) |
| 254 | |
| 255 | const [fkRows] = await connection.execute<mysql.RowDataPacket[]>( |
| 256 | `SELECT kcu.COLUMN_NAME, kcu.REFERENCED_TABLE_NAME, kcu.REFERENCED_COLUMN_NAME |
| 257 | FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu |
| 258 | WHERE kcu.TABLE_SCHEMA = ? AND kcu.TABLE_NAME = ? AND kcu.REFERENCED_TABLE_NAME IS NOT NULL`, |
| 259 | [databaseName, tableName] |
| 260 | ) |
| 261 | |
| 262 | const foreignKeys = fkRows.map((row) => ({ |
| 263 | column: row.COLUMN_NAME, |
| 264 | referencesTable: row.REFERENCED_TABLE_NAME, |
| 265 | referencesColumn: row.REFERENCED_COLUMN_NAME, |
| 266 | })) |
| 267 | |
| 268 | const fkColumnSet = new Set(foreignKeys.map((fk) => fk.column)) |
| 269 | |
| 270 | const [indexRows] = await connection.execute<mysql.RowDataPacket[]>( |
| 271 | `SELECT INDEX_NAME, COLUMN_NAME, SEQ_IN_INDEX, NON_UNIQUE |
| 272 | FROM INFORMATION_SCHEMA.STATISTICS |
| 273 | WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ? AND INDEX_NAME != 'PRIMARY' |