1
0
Fork 0
bocadillo/reader/schema/manager.go

81 lines
1.7 KiB
Go
Raw Normal View History

2018-11-05 17:16:12 +00:00
package schema
import (
"database/sql"
2018-11-12 12:33:47 +00:00
"regexp"
2018-11-05 17:16:12 +00:00
"strings"
)
2018-11-12 12:33:47 +00:00
// Manager maintains table schemas.
type Manager struct {
2018-11-05 17:16:12 +00:00
Schema *Schema
db *sql.DB
}
// NewManager creates a new schema manager.
2018-11-12 12:33:47 +00:00
func NewManager(db *sql.DB) *Manager {
return &Manager{
2018-11-05 17:16:12 +00:00
Schema: NewSchema(),
db: db,
}
}
// Manage adds given tables to a list of managed tables and updates its details.
2018-11-12 12:33:47 +00:00
func (m *Manager) Manage(database, table string) error {
2018-11-05 17:16:12 +00:00
cols, err := m.tableColumns(database, table)
if err != nil {
return err
}
m.Schema.Update(database, table, cols)
return nil
}
// ProcessQuery accepts an SQL query and updates schema if required.
2018-11-12 12:33:47 +00:00
func (m *Manager) ProcessQuery(database, query string) error {
if tableName, ok := changedTable(query); !ok {
if tbl := m.Schema.Table(database, tableName); tbl != nil {
return m.Manage(database, tableName)
2018-11-05 17:16:12 +00:00
}
}
return nil
}
2018-11-12 12:33:47 +00:00
func (m *Manager) tableColumns(database, table string) ([]Column, error) {
2018-11-05 17:16:12 +00:00
rows, err := m.db.Query(`
SELECT COLUMN_NAME, COLUMN_TYPE
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?
ORDER BY ORDINAL_POSITION ASC
`, database, table)
if err != nil {
return nil, err
}
defer rows.Close()
cols := make([]Column, 0)
for rows.Next() {
var col Column
var typ string
err := rows.Scan(&col.Name, &typ)
if err != nil {
return nil, err
}
if strings.Contains(strings.ToLower(typ), "unsigned") {
col.Unsigned = true
}
cols = append(cols, col)
}
return cols, nil
}
2018-11-12 12:33:47 +00:00
var alterRegexp = regexp.MustCompile(`(?im)^alter[\s\t\n]+table[\s\t\n]+` + "`" + `?([a-z0-9_]+)`)
func changedTable(query string) (string, bool) {
m := alterRegexp.FindAllStringSubmatch(query, -1)
if len(m) > 0 {
return m[0][1], true
}
return "", false
}