func (tbl *Table) FieldName(field string) string { _, ok := tbl._structfieldmap[field] if ok { return field } field = sqlx.NameMapper(field) _, ok = tbl._structfieldmap[field] if ok { return field } return field + "_unk" }
func (db *Db) FindRefs(name string) []string { var ret []string = []string{sqlx.NameMapper(name)} for _, tbl := range db.Tables { if tbl.Name != name { continue } for _, fld := range tbl.Fields { if len(fld.Ref) <= 0 { continue } res := db.FindRefs(fld.Ref) for _, n := range res { if !util.StringInSlice(n, ret) { ret = append(ret, n) } } } } return ret }
func (db *Db) ApplyRebuilds() error { rNames := make([]string, 0) for _, tbl := range db.Tables { if tbl._rebuildorg != tbl._rebuildnew { rNames = append(rNames, db.FindRefs(tbl.Name)...) //log.Println(">>>>>>>>>>>>>>>>>>>>>>>>>", tbl.Name, tbl._rebuildorg, tbl._rebuildnew) } } if len(rNames) <= 0 { return nil } for { bChange := false for _, tbl := range db.Tables { if util.StringInSlice(sqlx.NameMapper(tbl.Name), rNames) { continue } refs := db.FindRefs(tbl.Name)[1:] //log.Println(">>>>>>>>>>>>>>>>>>>>>>>>>2", tbl.Name, refs) for _, n := range refs { if !util.StringInSlice(sqlx.NameMapper(tbl.Name), rNames) && util.StringInSlice(n, rNames) { rNames = append(rNames, sqlx.NameMapper(tbl.Name)) //log.Println(">>>>>>>>>>>>>>>>>>>>>>>>>3", n) bChange = true } } } if !bChange { break } } log.Println("!!!DB Rebuild Begin!!!", rNames) tx, err := db.Begin() if err != nil { return err } for _, tbl := range db.Tables { if !util.StringInSlice(sqlx.NameMapper(tbl.Name), rNames) { continue } err := db.RebuildTable(tbl.Name, tbl._rebuildorg, tbl._rebuildnew, tx, 0) if err != nil { tx.Rollback() return err } } for _, tbl := range db.Tables { if !util.StringInSlice(sqlx.NameMapper(tbl.Name), rNames) { continue } err := db.RebuildTable(tbl.Name, tbl._rebuildorg, tbl._rebuildnew, tx, 1) if err != nil { tx.Rollback() return err } } for _, tbl := range db.Tables { if !util.StringInSlice(sqlx.NameMapper(tbl.Name), rNames) { continue } err := db.RebuildTable(tbl.Name, tbl._rebuildorg, tbl._rebuildnew, tx, 2) if err != nil { tx.Rollback() return err } for _, fld := range tbl.Fields { if len(fld.Index) > 0 { _, err := db.DB.Exec(fld.Index) if err != nil { tx.Rollback() return err } } } } tx.Commit() db.DB.Exec("VACUUM;") log.Println("!!!DB Rebuild Successful!!!") return nil }
func (db *Db) InitTableName(t interface{}, name string) (*Table, error) { val := reflect.ValueOf(t) //.Elem() reftype := reflect.TypeOf(t) //.Elem() fm, err := sqlx.StructFieldMap(t) if err != nil { fmt.Println("Error: ", err) return nil, err } cmdCreate := "CREATE TABLE IF NOT EXISTS " + name + " ( " cmdIdx := make([]string, 0, 32) fields := make([]Field, 0, 32) primKey := "" primType := COLTYPE_STRING primAuto := false hasuqnoprim := false for i := 0; i < val.NumField(); i++ { valueField := val.Field(i) typeField := val.Type().Field(i) // skip unexported field if len(typeField.PkgPath) != 0 { continue } tag := typeField.Tag fn := sqlx.NameMapper(typeField.Name) tn := valueField.Kind().String() if tag := tag.Get("db"); tag != "" { fn = tag } //skip nameless field if len(fn) <= 0 || fn == "dbcache" { continue } tagIdx := tag.Get("sqlidx") tagUIdx := tag.Get("sqluidx") tagSql := tag.Get("sql") bPrim := strings.Contains(strings.ToLower(tagSql), "primary") bAutoInc := strings.Contains(strings.ToLower(tagSql), "autoincrement") bUnique := bPrim || strings.Contains(strings.ToLower(tagSql), "unique") bRef := strings.Contains(strings.ToLower(tagSql), "references") if tn == "int8" || tn == "int16" || tn == "int32" || tn == "int64" || tn == "uint8" || tn == "uint16" || tn == "uint32" || tn == "uint64" { tn = "integer" if bPrim { primType = COLTYPE_INT } } else if tn == "string" { tn = "text" } else if tn == "float32" || tn == "float64" { tn = "real" if bPrim { primType = COLTYPE_FLOAT } } else if tn == "slice" { //sliceType:=typeField.Type.Elem(); //bPtr:=sliceType.String()[0]=="*" continue } else if tn == "struct" { tn = typeField.Type.Name() if tn == "NullString" { tn = "text" } else { fmt.Println("!tn2: ", tn) continue } } else { fmt.Println("!tn: ", tn) continue } if bUnique && !bPrim { hasuqnoprim = true } if bPrim { primKey = fn } if bAutoInc { primAuto = true } if i > 0 { cmdCreate += " , " } cmdCreate += "" + fn + " " + tn + " " + tagSql varIdx, ok := fm[fn] if !ok { varIdx = -1 } sRef := "" if bRef { sRef = strings.Split(tagSql, " ")[1] } bIndexUnique := false if len(tagUIdx) > 0 { bIndexUnique = true tagIdx = tagUIdx } ci := "" if len(tagIdx) > 0 { sUnique := " " if bIndexUnique { sUnique = " UNIQUE " } if !strings.Contains(tagIdx, ",") { tagIdx = "'" + fn + "' " + tagIdx } ci := "CREATE" + sUnique + "INDEX IF NOT EXISTS 'dbidx_" + name + "_" + fn + "' ON '" + name + "' (" + tagIdx + ");" cmdIdx = append(cmdIdx, ci) } //fmt.Printf("Field Name: %s,\t Field Value: %v,\t Tag Value: %s\n", typeField.Name, valueField.Interface(), tag.Get("tag_name")) fields = append(fields, Field{ Name: fn, Type: tn, Primary: bPrim, AutoInc: bAutoInc, Unique: bUnique, VarIndex: varIdx, Ref: sRef, Index: ci, }) } cmdCreate += " ) " //fmt.Println("cmdCreate: ", cmdCreate) if primKey == "" { err := errors.New("No primary key found in Table: " + name) fmt.Println("Error: ", err) return nil, err } _, err = db.DB.Exec(cmdCreate) if err != nil { fmt.Println("Error: ", err, " cmd:", cmdCreate) return nil, err } for i := 0; i < len(cmdIdx); i++ { ci := cmdIdx[i] _, err := db.DB.Exec(ci) if err != nil { fmt.Println("Error: ", err, " cmd:", cmdCreate) } } qRes := db.DB.QueryRowx("select sql from sqlite_master where type='table' and tbl_name='" + name + "'") cmdCreateOrg := "" qRes.Scan(&cmdCreateOrg) iOrg := strings.Index(cmdCreateOrg, "(") cOrg := "" if iOrg >= 0 { cOrg = strings.TrimSpace(cmdCreateOrg[iOrg:]) } cNew := strings.TrimSpace(cmdCreate[strings.Index(cmdCreate, "("):]) if strings.Trim(cOrg, " ()") != strings.Trim(cNew, " ()") { log.Println("Table Layout Changed", name) log.Println("f--->", strings.Trim(cOrg, " ()")) log.Println("t--->", strings.Trim(cNew, " ()")) log.Println("rebuild pending ...") /*err := db.RebuildTable(name, cOrg, cNew) if err != nil { log.Println("!!!!!!!!!!!!!!!!!!!!!", err) panic(err) //return nil, err }*/ } else { cOrg = cNew } tbl := &Table{ Name: name, Schema: cmdCreate, Db: db, Fields: fields, PrimKey: primKey, RefType: reftype, PrimType: primType, PrimAuto: primAuto, _hasuqnoprim: hasuqnoprim, _structfieldmap: fm, _rebuildorg: cOrg, _rebuildnew: cNew, } for i := 0; i < len(tbl.Fields); i++ { if tbl.Fields[i].Primary { continue } if len(tbl._allsetnames) > 0 { tbl._allsetnames += "," } field := sqlx.NameMapper(tbl.Fields[i].Name) tbl._allsetnames += field + "=:" + field + " " } for i := 0; i < len(tbl.Fields); i++ { if tbl.Fields[i].Primary { continue } if len(tbl._allsetvnames) > 0 { tbl._allsetvnames += "," } field := sqlx.NameMapper(tbl.Fields[i].Name) if field == "version" { tbl._allsetvnames += field + "=:" + field + " + 1 " } else { tbl._allsetvnames += field + "=:" + field + " " } } { var fn, vn string vn = ":" iC := len(tbl.Fields) for i := 0; i < iC; i++ { f := tbl.Fields[i] if f.AutoInc { //don't insert autoincrement field continue } if len(fn) > 0 { fn += "," vn += ", :" } fn += f.Name vn += f.Name } tbl._fieldnames, tbl._valuenames = fn, vn } db.Tables = append(db.Tables, tbl) return tbl, nil }
func (db *Db) InitTable(t interface{}) (*Table, error) { val := reflect.ValueOf(t) //.Elem() name := sqlx.NameMapper(val.Type().Name()) return db.InitTableName(t, name) }