mirror of
https://github.com/ManyakRus/crud_generator.git
synced 2024-12-22 00:36:41 +02:00
194 lines
4.8 KiB
Go
194 lines
4.8 KiB
Go
package dbmeta
|
|
|
|
import (
|
|
"database/sql"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/jimsmart/schema"
|
|
)
|
|
|
|
// LoadSqliteMeta fetch db meta data for Sqlite3 database
|
|
func LoadSqliteMeta(db *sql.DB, sqlType, sqlDatabase, tableName string) (DbTableMeta, error) {
|
|
if tableName == "sqlite_sequence" || tableName == "sqlite_stat1" {
|
|
return nil, fmt.Errorf("unsupported table: %s", tableName)
|
|
}
|
|
|
|
m := &dbTableMeta{
|
|
sqlType: sqlType,
|
|
sqlDatabase: sqlDatabase,
|
|
tableName: tableName,
|
|
}
|
|
|
|
ddl, err := sqliteLoadDDL(db, tableName)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("unable to load ddl from sqlite_master: %v", err)
|
|
}
|
|
|
|
m.ddl = ddl
|
|
|
|
colsInfos, err := sqliteLoadPragma(db, tableName)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("unable to load PRAGMA table_info %s: %v", m.tableName, err)
|
|
}
|
|
|
|
colsDDL := sqliteParseDDL(ddl)
|
|
|
|
cols, err := schema.ColumnTypes(db, sqlDatabase, tableName)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
m.columns = make([]*columnMeta, len(cols))
|
|
|
|
for i, v := range cols {
|
|
colDDL := colsDDL[v.Name()]
|
|
|
|
colDDLLower := strings.ToLower(colDDL)
|
|
notNull := strings.Index(colDDLLower, "not null") > -1
|
|
isPrimaryKey := strings.Index(colDDLLower, "primary key") > -1
|
|
isAutoIncrement := strings.Index(colDDLLower, "autoincrement") > -1
|
|
defaultVal := ""
|
|
columnLen := int64(-1)
|
|
columnType := v.DatabaseTypeName()
|
|
|
|
details, ok := colsInfos[v.Name()]
|
|
if ok {
|
|
isPrimaryKey = details.primaryKey == 1
|
|
if details.dfltValue != nil {
|
|
defaultVal = details.dfltValue.(string)
|
|
}
|
|
|
|
notNull = details.notnull == 1
|
|
columnType, columnLen = ParseSQLType(details.dataType)
|
|
}
|
|
|
|
if isPrimaryKey {
|
|
notNull = true
|
|
}
|
|
// fmt.Printf("%s: notNull: %v isPrimaryKey: %v isAutoIncrement: %v\n",colDDL, notNull, isPrimaryKey, isAutoIncrement)
|
|
|
|
colMeta := &columnMeta{
|
|
index: i,
|
|
name: v.Name(),
|
|
databaseTypeName: columnType,
|
|
nullable: !notNull,
|
|
isPrimaryKey: isPrimaryKey,
|
|
isAutoIncrement: isAutoIncrement,
|
|
colDDL: colDDL,
|
|
defaultVal: defaultVal,
|
|
columnType: columnType,
|
|
columnLen: columnLen,
|
|
}
|
|
|
|
m.columns[i] = colMeta
|
|
}
|
|
|
|
m = updateDefaultPrimaryKey(m)
|
|
return m, nil
|
|
}
|
|
|
|
func sqliteLoadPragma(db *sql.DB, tableName string) (colsInfos map[string]*sqliteColumnInfo, err error) {
|
|
pragmaSQL := fmt.Sprintf("PRAGMA table_info('%s');", tableName)
|
|
res, err := db.Query(pragmaSQL)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("unable to load PRAGMA table_info %s: %v", tableName, err)
|
|
}
|
|
|
|
defer res.Close()
|
|
colsInfos = make(map[string]*sqliteColumnInfo)
|
|
for res.Next() {
|
|
ci := &sqliteColumnInfo{}
|
|
err = res.Scan(&ci.cid, &ci.name, &ci.dataType, &ci.notnull, &ci.dfltValue, &ci.primaryKey)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("unable to load identity info from sqlite Scan: %v", err)
|
|
}
|
|
colsInfos[ci.name] = ci
|
|
|
|
// fmt.Printf("cid: |%2d| name: |%-20s| data_type: |%-20s| notnull: |%d| dflt_value: |%-10T| dflt_value: |%-10v| primary_key: |%d|\n",
|
|
// ci.cid, ci.name, ci.data_type, ci.notnull, ci.dflt_value, ci.dflt_value, ci.primary_key)
|
|
}
|
|
return colsInfos, nil
|
|
}
|
|
|
|
func sqliteParseDDL(ddl string) map[string]string {
|
|
idx1 := strings.Index(ddl, "(")
|
|
idx2 := strings.LastIndex(ddl, ")")
|
|
|
|
if idx1 > -1 && idx2 > -1 {
|
|
ddl = ddl[idx1+1 : idx2]
|
|
}
|
|
|
|
ddl = strings.Replace(ddl, "\r", "", -1)
|
|
ddl = strings.Replace(ddl, "\n", " ", -1)
|
|
ddl = strings.TrimPrefix(ddl, "\n")
|
|
ddl = strings.TrimSuffix(ddl, "\n")
|
|
|
|
colsDDL := make(map[string]string)
|
|
|
|
lines := strings.Split(ddl, ",")
|
|
for _, line := range lines {
|
|
line = strings.Replace(line, "\n", " ", -1)
|
|
|
|
line := strings.TrimSpace(line)
|
|
|
|
line = TrimSpaceNewlineInString(line)
|
|
line = strings.TrimPrefix(line, "\n")
|
|
line = strings.TrimSuffix(line, "\n")
|
|
line = strings.TrimSuffix(line, ",")
|
|
line = strings.Trim(line, " ")
|
|
line = strings.Trim(line, ",")
|
|
|
|
if len(line) == 0 {
|
|
continue
|
|
}
|
|
|
|
if strings.HasPrefix(line, "FOREIGN KEY") || strings.HasPrefix(line, "CONSTRAINT") {
|
|
continue
|
|
}
|
|
|
|
// fmt.Printf("[%2d] %s\n", i, line)
|
|
|
|
parts := strings.Split(line, " ")
|
|
name := parts[0]
|
|
colDDL := strings.Join(parts[1:], " ")
|
|
|
|
name = strings.Trim(name, " \t[]\"")
|
|
colDDL = strings.Trim(colDDL, " \t,")
|
|
|
|
if len(colDDL) == 0 {
|
|
continue
|
|
}
|
|
|
|
colsDDL[name] = colDDL
|
|
|
|
}
|
|
return colsDDL
|
|
}
|
|
|
|
func sqliteLoadDDL(db *sql.DB, tableName string) (string, error) {
|
|
var ddl string
|
|
ddlSQL := fmt.Sprintf("SELECT sql FROM sqlite_master WHERE type='table' and name = '%s';", tableName)
|
|
//_, err := db.Query(ddlSQL)
|
|
//if err != nil {
|
|
//return "", fmt.Errorf("unable to load ddl from sqlite_master: %v", err)
|
|
//}
|
|
|
|
row := db.QueryRow(ddlSQL, 0)
|
|
err := row.Scan(&ddl)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return ddl, nil
|
|
}
|
|
|
|
type sqliteColumnInfo struct {
|
|
cid int
|
|
name string
|
|
dataType string
|
|
notnull int
|
|
dfltValue interface{}
|
|
primaryKey int
|
|
}
|