-
-
Save thunder-spb/56279a5d0b4038c46fdbb11f616fa8d2 to your computer and use it in GitHub Desktop.
Revisions
-
Indribell revised this gist
Oct 15, 2020 . 1 changed file with 15 additions and 16 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -24,35 +24,34 @@ type User struct { Age int `db:"age" json:"age,omitempty"` } // QueryStruct allows a Struct or Slice with Struct as result // // Example: // // contacts := []Contact{} // QueryStruct(&contacts, "SELECT * FROM contact") // // contact := Contact{} // QueryOne(&contact, "SELECT * FROM contact") // func (connection *Connection) QueryStruct(dest interface{}, query string, args ...interface{}) bool { rows, err := connection.sql.Query(query, args...) if err != nil { log.Println("DB: QueryAll failed: " + err.Error()) return false } defer rows.Close() err = structScan(rows, dest) if err != nil { log.Println("DB: QueryAll structScan failed: " + err.Error()) return false } return true } // structScan will scan the results of a database query and try to merge then with the supplied struct // // Example: []Users, User -
Indribell revised this gist
Oct 15, 2020 . 1 changed file with 17 additions and 8 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -52,6 +52,12 @@ func (connection *Connection) QueryAll(dest interface{}, query string, args ...i return err } // structScan will scan the results of a database query and try to merge then with the supplied struct // // Example: []Users, User // // Are both valid structs as the routing will automatically figure out if the results are a slice with struct or a pure struct func structScan(rows *sql.Rows, model interface{}) error { v := reflect.ValueOf(model) @@ -98,26 +104,29 @@ func structScan(rows *sql.Rows, model interface{}) error { } if isStruct == true { if len(m) > 0 { // Ensure we have data fields! changeStruct(v, t, m[0]) } } if isSlice == true { if len(m) > 0 { // Ensure we have data in the slice! var elem reflect.Value for _, d := range m { typ := v.Type().Elem() elem = reflect.New(typ).Elem() changeStruct(elem, typ, d) v.Set(reflect.Append(v, elem)) } } } return nil } func changeStruct(v reflect.Value, t reflect.Type, m map[string]interface{}) { for i := 0; i < v.NumField(); i++ { field := strings.Split(t.Field(i).Tag.Get("db"), ",")[0] -
Indribell revised this gist
Sep 28, 2020 . 1 changed file with 3 additions and 3 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -2,12 +2,12 @@ // https://gist.github.com/PumpkinSeed/b4993c6ad20ea90e3da8c991a90a91e1 // // 1. It was only able to extract database information, based upon a Struct. // The code now can deal with a struct or a slice with structs. // // 2. The code relied on the json tag in the struct. // You need to match the data with database fields, not the output fields. // This will match up more 1 to 1 as you are in controle of your Database naming and selecting of that data. // If a client expect different named exported json fields, ... // // 3. The code while designed for a single struct, kept looping over all the rows. // So if you tried to extract one result and did not use a limitor ( LIMIT ) in your SQL code, it will have looped the column information ..N times -
Indribell revised this gist
Sep 28, 2020 . 1 changed file with 1 addition and 3 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,4 +1,3 @@ // Fixing some of the errors in the: // https://gist.github.com/PumpkinSeed/b4993c6ad20ea90e3da8c991a90a91e1 // @@ -148,5 +147,4 @@ func changeStruct(v reflect.Value, t reflect.Type, m map[string]interface{}) { } } } } -
Indribell renamed this gist
Sep 28, 2020 . 1 changed file with 0 additions and 0 deletions.There are no files selected for viewing
File renamed without changes. -
Indribell revised this gist
Sep 28, 2020 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,4 +1,4 @@ ``` // Fixing some of the errors in the: // https://gist.github.com/PumpkinSeed/b4993c6ad20ea90e3da8c991a90a91e1 // -
Indribell revised this gist
Sep 28, 2020 . 1 changed file with 2 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,3 +1,4 @@ ```go // Fixing some of the errors in the: // https://gist.github.com/PumpkinSeed/b4993c6ad20ea90e3da8c991a90a91e1 // @@ -148,5 +149,4 @@ func changeStruct(v reflect.Value, t reflect.Type, m map[string]interface{}) { } } } ``` -
Indribell created this gist
Sep 28, 2020 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,152 @@ // Fixing some of the errors in the: // https://gist.github.com/PumpkinSeed/b4993c6ad20ea90e3da8c991a90a91e1 // // 1. It was only able to extract database information, based upon a Struct. // The code now can deal with a struct or a slice with structs. As those are the most common information extraction, you will do // // 2. The code relied on the json tag in the struct. // This is a very incorrect as you need to match the data with database fields, not your output fields. // This will match up more 1 to 1 as you are in controle of your Database naming and selecting of that data. // If a client expect different named exported json fields, ... // // 3. The code while designed for a single struct, kept looping over all the rows. // So if you tried to extract one result and did not use a limitor ( LIMIT ) in your SQL code, it will have looped the column information ..N times // // 4. Some data types like Int had been missing // // 5. Fix a few bugs type User struct { ID int `db:"id"` Firstname string `db:"firstname" json:"first_name"` Lastname string `db:"lastname" json:"last_name"` Age int `db:"age" json:"age,omitempty"` } // QueryAll allows a Slice of results, to be pushed into Struct // // Example: // Multi results: // // users := []User{} // QueryAll(&user, "SELECT id, firstname, age FROM user") // // Single result: // // user := User{} // QueryAll(&user, "SELECT id, firstname, age FROM user") // func (connection *Connection) QueryAll(dest interface{}, query string, args ...interface{}) error { rows, _ := connection.sql.Query(query, args...) defer rows.Close() err := structScan(rows, dest) if err != nil { log.Println("DB: QueryAll failed on error") log.Println(err) return errors.New("DB: QueryAll failed on error") } return err } func structScan(rows *sql.Rows, model interface{}) error { v := reflect.ValueOf(model) if v.Kind() != reflect.Ptr { return errors.New("must pass a pointer, not a value, to StructScan destination") // @todo add new error message } v = reflect.Indirect(v) t := v.Type() // Find out if what we are using is a Struct ( Query One ) or a Slice with Structs ( QueryAll ) isStruct, isSlice := false, false if t.Kind() == reflect.Slice { isSlice = true } else if t.Kind() == reflect.Struct { isStruct = true } // Ensure we only get the column information one time! cols, _ := rows.Columns() columns := make([]interface{}, len(cols)) columnPointers := make([]interface{}, len(cols)) for i := range columns { columnPointers[i] = &columns[i] } var m []map[string]interface{} for rows.Next() { if err := rows.Scan(columnPointers...); err != nil { return err } x := make(map[string]interface{}) for i, colName := range cols { val := columnPointers[i].(*interface{}) x[colName] = *val } m = append(m, x) // If we are dealing with a struct. There is no point in looping over all the results, if they are more then one! if isStruct == true { break } } if isStruct == true { changeStruct(v, t, m[0]) } if isSlice == true { var elem reflect.Value for _, d := range m { typ := v.Type().Elem() elem = reflect.New(typ).Elem() changeStruct(elem, typ, d) v.Set(reflect.Append(v, elem)) } } return nil } func changeStruct(v reflect.Value, t reflect.Type, m map[string]interface{}) { for i := 0; i < v.NumField(); i++ { field := strings.Split(t.Field(i).Tag.Get("db"), ",")[0] if item, ok := m[field]; ok { if v.Field(i).CanSet() { if item != nil { switch v.Field(i).Kind() { case reflect.String: v.Field(i).SetString(item.(string)) // s := bytesToString(item.([]uint8)) case reflect.Float32, reflect.Float64: v.Field(i).SetFloat(item.(float64)) case reflect.Int, reflect.Int32, reflect.Int64: v.Field(i).SetInt(item.(int64)) case reflect.Bool: v.Field(i).Set(reflect.ValueOf(!(item.(int64) == 0))) case reflect.Ptr: if reflect.ValueOf(item).Kind() == reflect.Bool { itemBool := item.(bool) v.Field(i).Set(reflect.ValueOf(&itemBool)) } case reflect.Struct: v.Field(i).Set(reflect.ValueOf(item)) default: fmt.Println(t.Field(i).Name, ": ", v.Field(i).Kind(), " - > - ", reflect.ValueOf(item).Kind()) // @todo remove after test out the Get methods } } } } } }