2020-10-22 18:33:09 +08:00
package model
2021-03-01 17:29:07 +08:00
import (
"fmt"
"sort"
2022-01-25 23:15:07 +08:00
"github.com/zeromicro/go-zero/core/stores/sqlx"
"github.com/zeromicro/go-zero/tools/goctl/model/sql/util"
2021-03-01 17:29:07 +08:00
)
const indexPri = "PRIMARY"
2020-10-22 18:33:09 +08:00
type (
2021-02-26 16:11:47 +08:00
// InformationSchemaModel defines information schema model
2020-10-22 18:33:09 +08:00
InformationSchemaModel struct {
conn sqlx . SqlConn
}
2021-01-14 13:24:24 +08:00
2021-02-26 16:11:47 +08:00
// Column defines column in table
2020-11-18 15:32:53 +08:00
Column struct {
2021-03-01 17:29:07 +08:00
* DbColumn
Index * DbIndex
}
// DbColumn defines column info of columns
DbColumn struct {
Name string ` db:"COLUMN_NAME" `
DataType string ` db:"DATA_TYPE" `
Extra string ` db:"EXTRA" `
Comment string ` db:"COLUMN_COMMENT" `
ColumnDefault interface { } ` db:"COLUMN_DEFAULT" `
IsNullAble string ` db:"IS_NULLABLE" `
OrdinalPosition int ` db:"ORDINAL_POSITION" `
}
// DbIndex defines index of columns in information_schema.statistic
DbIndex struct {
IndexName string ` db:"INDEX_NAME" `
NonUnique int ` db:"NON_UNIQUE" `
SeqInIndex int ` db:"SEQ_IN_INDEX" `
}
// ColumnData describes the columns of table
ColumnData struct {
Db string
Table string
Columns [ ] * Column
}
// Table describes mysql table which contains database name, table name, columns, keys
Table struct {
Db string
Table string
Columns [ ] * Column
// Primary key not included
UniqueIndex map [ string ] [ ] * Column
PrimaryKey * Column
NormalIndex map [ string ] [ ] * Column
}
// IndexType describes an alias of string
IndexType string
// Index describes a column index
Index struct {
IndexType IndexType
Columns [ ] * Column
2020-11-18 15:32:53 +08:00
}
2020-10-22 18:33:09 +08:00
)
2021-02-26 16:11:47 +08:00
// NewInformationSchemaModel creates an instance for InformationSchemaModel
2020-10-22 18:33:09 +08:00
func NewInformationSchemaModel ( conn sqlx . SqlConn ) * InformationSchemaModel {
return & InformationSchemaModel { conn : conn }
}
2021-02-26 16:11:47 +08:00
// GetAllTables selects all tables from TABLE_SCHEMA
2020-10-22 18:33:09 +08:00
func ( m * InformationSchemaModel ) GetAllTables ( database string ) ( [ ] string , error ) {
query := ` select TABLE_NAME from TABLES where TABLE_SCHEMA = ? `
var tables [ ] string
err := m . conn . QueryRows ( & tables , query , database )
if err != nil {
return nil , err
}
2020-11-18 15:32:53 +08:00
2020-10-22 18:33:09 +08:00
return tables , nil
}
2020-11-18 15:32:53 +08:00
2021-03-01 17:29:07 +08:00
// FindColumns return columns in specified database and table
func ( m * InformationSchemaModel ) FindColumns ( db , table string ) ( * ColumnData , error ) {
querySql := ` SELECT c.COLUMN_NAME,c.DATA_TYPE,EXTRA,c.COLUMN_COMMENT,c.COLUMN_DEFAULT,c.IS_NULLABLE,c.ORDINAL_POSITION from COLUMNS c WHERE c.TABLE_SCHEMA = ? and c.TABLE_NAME = ? `
var reply [ ] * DbColumn
err := m . conn . QueryRowsPartial ( & reply , querySql , db , table )
if err != nil {
return nil , err
}
var list [ ] * Column
for _ , item := range reply {
index , err := m . FindIndex ( db , table , item . Name )
if err != nil {
if err != sqlx . ErrNotFound {
return nil , err
}
continue
}
if len ( index ) > 0 {
for _ , i := range index {
list = append ( list , & Column {
DbColumn : item ,
Index : i ,
} )
}
} else {
list = append ( list , & Column {
DbColumn : item ,
} )
}
}
sort . Slice ( list , func ( i , j int ) bool {
return list [ i ] . OrdinalPosition < list [ j ] . OrdinalPosition
} )
var columnData ColumnData
columnData . Db = db
columnData . Table = table
columnData . Columns = list
return & columnData , nil
}
2021-03-02 00:11:18 +08:00
// FindIndex finds index with given db, table and column.
2021-03-01 17:29:07 +08:00
func ( m * InformationSchemaModel ) FindIndex ( db , table , column string ) ( [ ] * DbIndex , error ) {
querySql := ` SELECT s.INDEX_NAME,s.NON_UNIQUE,s.SEQ_IN_INDEX from STATISTICS s WHERE s.TABLE_SCHEMA = ? and s.TABLE_NAME = ? and s.COLUMN_NAME = ? `
var reply [ ] * DbIndex
err := m . conn . QueryRowsPartial ( & reply , querySql , db , table , column )
if err != nil {
return nil , err
}
return reply , nil
}
// Convert converts column data into Table
func ( c * ColumnData ) Convert ( ) ( * Table , error ) {
var table Table
2022-04-07 10:40:21 +08:00
table . Table = c . Table
table . Db = c . Db
2021-03-01 17:29:07 +08:00
table . Columns = c . Columns
table . UniqueIndex = map [ string ] [ ] * Column { }
table . NormalIndex = map [ string ] [ ] * Column { }
m := make ( map [ string ] [ ] * Column )
for _ , each := range c . Columns {
2021-05-12 12:28:23 +08:00
each . Comment = util . TrimNewLine ( each . Comment )
2021-03-01 17:29:07 +08:00
if each . Index != nil {
m [ each . Index . IndexName ] = append ( m [ each . Index . IndexName ] , each )
}
}
primaryColumns := m [ indexPri ]
if len ( primaryColumns ) == 0 {
return nil , fmt . Errorf ( "db:%s, table:%s, missing primary key" , c . Db , c . Table )
}
if len ( primaryColumns ) > 1 {
return nil , fmt . Errorf ( "db:%s, table:%s, joint primary key is not supported" , c . Db , c . Table )
}
table . PrimaryKey = primaryColumns [ 0 ]
for indexName , columns := range m {
if indexName == indexPri {
continue
}
for _ , one := range columns {
if one . Index != nil {
if one . Index . NonUnique == 0 {
table . UniqueIndex [ indexName ] = columns
} else {
table . NormalIndex [ indexName ] = columns
}
}
}
}
return & table , nil
2020-11-18 15:32:53 +08:00
}