I am receiving this error in my new_user.go
when creating a user using Golang packages viper
and cobra
. The error is as follows:
cannot use result (variable of type sql.Result) as error value in return statement: sql.Result does not implement error (missing method Error)
My code is broken into 2 files which talk to each other, here is the tree hierarchy:
.
├── Makefile
├── README.md
├── cli
│ ├── config.go
│ ├── db-creds.yaml
│ ├── go.mod
│ ├── go.sum
│ ├── new_user.go
│ └── root.go
├── docker-compose.yaml
├── go.work
└── main.go
To connect to the database, I created a YAML file db-creds.yaml
to pull the creds for config.go
. No errors are popping up here:
config.go
file
package cli
import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
_ "github.com/lib/pq"
"github.com/spf13/viper"
)
// var dialects = map[string]gorp.Dialect{
// "postgres": gorp.PostgresDialect{},
// "mysql": gorp.MySQLDialect{Engine: "InnoDB", Encoding: "UTF8"},
// }
// initConfig reads in config file and ENV variables if set
func initConfig() {
if cfgFile != "" {
viper.SetConfigFile(cfgFile)
} else {
viper.AddConfigPath("./")
viper.SetConfigName("db-creds")
viper.SetConfigType("yaml")
}
// If a config file is found, read it in:
err := viper.ReadInConfig()
if err == nil {
fmt.Println("Fatal error config file: ", viper.ConfigFileUsed())
}
return
}
func getConnection() *sql.DB {
// Make sure we only accept dialects that were compiled in.
// dialect := viper.GetString("database.dialect")
// _, exists := dialects[dialect]
// if !exists {
// return nil, "", fmt.Errorf("Unsupported dialect: %s", dialect)
// }
// Will want to create another command that will use a mapping
// to connect to a preset db in the yaml file.
dsn := fmt.Sprintf("%s:%s@%s(%s)?parseTime=true",
viper.GetString("mysql-5.7-dev.user"),
viper.GetString("mysql-5.7-dev.password"),
viper.GetString("mysql-5.7-dev.protocol"),
viper.GetString("mysql-5.7-dev.address"),
)
viper.Set("database.datasource", dsn)
db, err := sql.Open("msyql", viper.GetString("database.datasource"))
if err != nil {
fmt.Errorf("Cannot connect to database: %s", err)
}
return db
}
The error that I put at the top is where the error appears when I return my result
. I am implementing the flag
option for cobra
to use -n
follow by the name
to represent the new user being added`.
new_user.go
file
package cli
import (
"log"
"github.com/sethvargo/go-password/password"
"github.com/spf13/cobra"
)
var name string
// newCmd represents the new command
var newCmd = &cobra.Command{
Use: "new",
Short: "Create a new a user which will accommodate the individuals user name",
Long: `Create a new a user that will randomize a password to the specified user`,
RunE: func(cmd *cobra.Command, args []string) error {
db := getConnection()
superSecretPassword, err := password.Generate(64, 10, 10, false, false)
result, err := db.Exec("CREATE USER" name "'@'%'" "IDENTIFIED BY" superSecretPassword)
if err != nil {
log.Fatal(err)
}
// Will output the secret password combined with the user.
log.Printf(superSecretPassword)
return result <---- Error is here
},
}
func init() {
rootCmd.AddCommand(newCmd)
newCmd.Flags().StringVarP(&name, "name", "n", "", "The name of user to be added")
_ = newCmd.MarkFlagRequired("name")
}
The main purpose of this project are three things: 1.) Create a new user, 2.) Give any user specific permissions 3.) Delete them. That is my end goal. Going one step at a time and just ran into this error. Hope anyone can help me. Golang is new to me and started about 2 weeks ago.
CodePudding user response:
Go gives you a pretty clear indication about what's going on. The RunE
member of cobra expects its callback to return an error (or nil, in case of success).
Here, you are returning result, which is not an error, but a specific type returned by your sql query. This is what your function should look like.
RunE: func(cmd *cobra.Command, args []string) error {
db := getConnection()
superSecretPassword, err := password.Generate(64, 10, 10, false, false)
_, err := db.Exec("CREATE USER" name "'@'%'" "IDENTIFIED BY" superSecretPassword)
if err != nil {
// Don't Fatal uselessly, let cobra handle your error the way it
// was designed to do it.
return err
}
// Will output the secret password combined with the user.
log.Printf(superSecretPassword)
// Here is how you should indicate your callback terminated successfully.
// Error is an interface, so it accepts nil values.
return nil
}
If you need the result of the db.Exec
command (which does not seem to be the case), you'll need to do all the required processing within your cobra callback, as it is not designed to return values to the main thread.
Error handling
A few bad practices about handling error I noticed in your code:
If a go function has an error return, don't panic or kill the program if something unexpected occurs (like you did with
log.Fatal
). Instead, use that error return to propagate the error to the main thread, and let it decide what to do.On the other hand, don't return results if something went wrong. Your
getConnection
function should be able to return an error if it fails:func getConnection() (*sql.DB, error)
. You should then handle this error in yourRunE
function, instead of just logging it and processing normally.