I am trying to abstract my uses of my MySQL database and I'm stuck on a error.
There is the object I will take as example:
package models
// Product : The Product's model
type Product struct {
ID int
Name string
Price int
PictureURL string
}
I'm going to try to retrieve the Product id = 1
in my database. For that, let's say that I already have a connection to my database which is represented by the next variable:
var databaseMySQL *sql.DB
In order to query my database, I am using this function:
// QueryMySQL query our MySQL database
func QueryMySQL(sqlquery model.SQLQuery) model.Status {
// prepare the query
stmtOut, err := databaseMySQL.Prepare(sqlquery.Query)
if err != nil {
return model.Status{Code: http.StatusInternalServerError, Error: err}
}
defer stmtOut.Close()
// Run the query
err = stmtOut.QueryRow(sqlquery.Args).Scan(sqlquery.Dest)
if err != nil {
return model.Status{Code: http.StatusInternalServerError, Error: err}
} else {
return model.Status{Code: http.StatusOK, Error: nil}
}
}
The 2 models used over here are SQLQuery
& Status
.
package models
type SQLQuery struct {
Query string
Args []interface{}
Dest []*interface{}
}
Status
just basically contains an error
and an int
.
So, since Scan()
as the following prototype Scan func(dest ...interface{}) error
, I can pass a []*interface{}
as parameter.
If I'm right, then I should be able to get my Dest's elements filled by T
type element, and then cast/transform them into the types I need?
func GetProductByID(ID int) (model.Product, model.Status) {
// "SELECT ID, Name, Price, PictureURL FROM Products WHERE ID = ?"
var _product model.Product
// HERE IS THE PROBLEM
var dest []*interface{}
append(dest, &_product.Name)
append(dest, &_product.Price)
append(dest, &_product.PictureURL)
// HERE IS THE PROBLEM
status := QueryMySQL(model.SQLQuery{
Query: "SELECT Name, Price, PictureURL FROM Products WHERE ID = ?",
Args: []interface{}{ID},
Dest: dest})
return _product, model.Status{Code: http.StatusOK, Error: nil}
}
PS: this function is just a basic test to try my logic
However, I am getting an error:
cannot use &_product.Name (type *string) as type *interface {} in append: *interface {} is pointer to interface, not interface
To me, there is two errors:
cannot use &_product.Name (type *string) as type *interface {}
*interface {} is pointer to interface, not interface
First, why can't I use a interface to store my string?
Second, since I am passing a pointer on string, what's the matter with interface{}
? it should be *interface{}, doesn't it?
The correct code, thanks to David Budworth for his answer
In addition to the given code, you can pass slice as varargs like I did by adding ...
after your slice variable's name
mysqlproduct.go
// GetProductByID returns a Product based on a given ID
func GetProductByID(ID int) (model.Product, model.Status) {
_product := model.Product{
ID: ID}
status := QueryMySQL(&model.SQLQuery{
Query: "SELECT Name, Price, PictureURL FROM Products WHERE ID = ?",
Args: []interface{}{_product.ID},
Dest: []interface{}{&_product.Name, &_product.Price, &_product.PictureURL}})
if status.Code != http.StatusOK {
return _product, status
}
return _product, model.Status{Code: http.StatusOK, Error: ""}
}
mysql.go
// QueryMySQL query our MySQL database
func QueryMySQL(sqlquery *model.SQLQuery) model.Status {
stmtOut, err := databaseMySQL.Prepare(sqlquery.Query)
if err != nil {
return model.Status{Code: http.StatusInternalServerError, Error: err.Error()}
}
defer stmtOut.Close()
// Run the query
err = stmtOut.QueryRow(sqlquery.Args...).Scan(sqlquery.Dest...)
if err != nil {
return model.Status{Code: http.StatusInternalServerError, Error: err.Error()}
}
defer stmtOut.Close()
return model.Status{Code: http.StatusOK, Error: ""}
}