func (db *DB) rawSelectByStruct(structType reflect.Type, qi SqlQueryInfo) (rows *sql.Rows, fields []string, err error) { // nums of struct's fields lf := structType.NumField() // type's fields fields = make([]string, 0, lf) // sql select columns, it's Snake Cased columns := make([]string, 0, lf) // get fields in structType, // and convert to sql query column name for i := 0; i < lf; i++ { structField := structType.Field(i) if structField.Type.Kind() != reflect.Func && structField.Tag.Get("db") != "exclude" { fieldName := structField.Name fields = append(fields, fieldName) columns = append(columns, "`"+utils.SnakeCasedName(fieldName)+"`") } } tableName := utils.SnakeCasedName(structType.Name()) // TODO: check the fileds has specified ? qi.Fields = strings.Join(columns, ", ") // run query from db rows, err = db.Select(tableName, qi) return }
// insert struct to database // if i is pointer to struct and has a int type field named "Id" // the field "Id" will set to the last insert id if has LastInsertId // // field mapping rule is: HelloWorld => hello_world // mean that struct's field "HelloWorld" in database table's field is "hello_world" // table name mapping use the same rule as field func (db *DB) InsertStruct(i interface{}) (sql.Result, error) { m := utils.StructToSnakeKeyMap(i) table := utils.SnakeCasedName(utils.StructName(i)) r, err := db.Insert(table, m) if err == nil { insertId, err2 := r.LastInsertId() if err2 == nil && insertId > 0 { ps := reflect.ValueOf(i) if ps.Kind() == reflect.Ptr { // struct s := ps.Elem() if s.Kind() == reflect.Struct { // exported field f := s.FieldByName("Id") if f.IsValid() { // A Value can be changed only if it is // addressable and was not obtained by // the use of unexported struct fields. if f.CanSet() { // change value of N k := f.Kind() if k == reflect.Int || k == reflect.Int32 || k == reflect.Int64 { if !f.OverflowInt(insertId) { f.SetInt(insertId) } } } } } } } } return r, err }