How to update in BD only the fields filled in my struct? - go

I have a struct to get the data from the user and update the info in the database. However, if the user lets a field in a blank, the correspondent field into DB will be blank. I don't want that, I would like to edit only the fields that the user informed.
My model:
type Business struct {
Id uint64 `json:"id,omitempty"`
Company_name string `json:"company_name,omitempty"`
Trading_name string `json:"trading_name,omitempty"`
Facebook string `json:"facebook,omitempty"`
Instagram string `json:"instagram,omitempty"`
Tel string `json:"tel,omitempty"`
User_id uint64 `json:"user_id,omitempty"`
}
My controller:
func EditBusinessInfo(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
businessIDParams, err := strconv.ParseUint(params["businessID"], 10, 64)
if err != nil {
returns.ERROR(w, http.StatusBadRequest, err)
return
}
userIDInToken, err := auth.ExtractUserID(r)
if err != nil {
returns.ERROR(w, http.StatusInternalServerError, err)
return
}
db, err := db.ConnectToDB()
if err != nil {
returns.ERROR(w, http.StatusInternalServerError, err)
return
}
defer db.Close()
repository := repositories.NewUsersRepository(db)
businessInBD, err := repository.GetBusiness(businessIDParams)
if err != nil {
returns.ERROR(w, http.StatusInternalServerError, err)
return
}
if userIDInToken != businessInBD.User_id {
returns.ERROR(w, http.StatusUnauthorized, errors.New("você não pode editar a empresa de outra pessoa"))
return
}
if businessIDParams != businessInBD.Id {
returns.ERROR(w, http.StatusForbidden, errors.New("essa empresa não peertence a você"))
return
}
bodyRequest, err := ioutil.ReadAll(r.Body)
if err != nil {
returns.ERROR(w, http.StatusBadRequest, err)
return
}
var business models.Business
if err := json.Unmarshal(bodyRequest, &business); err != nil {
returns.ERROR(w, http.StatusUnprocessableEntity, err)
return
}
if err := repository.EditBusinessInfo(userIDInToken, business); err != nil {
returns.ERROR(w, http.StatusInternalServerError, err)
return
}
returns.JSON_RESPONSE(w, http.StatusOK, nil)
}

An int and string both have default values, so if you don't assign a value to them they will be populated with their default value (0 or ""). Since they will always have a value assigned, the omitempty tag will never come into play.
A common solution to this issue is to make your struct fields be pointers, if a pointer isn't set then it is nil. the nil value will then trigger the json marshaler to recognize the omitempty tag. And when you insert to you DB those values will be null/nil as well.
You should evaluate which fields need a value and which can be allowed to be empty in case your DB has integrity constraints. You will also have to add nil checks in your code when working with data.

Related

pq: invalid input syntax for type integer: ""

i was trying to get id value from the URL with the help of chi.URLParam which I have assigned to id value, after getting id value from value i want to perform database operation with id value,so i was sending id value to
d.DB.Query("SELECT * FROM employees WHERE id=$1", id)
but id returns nil data means id:=" ".
Handler
func GetOne(w http.ResponseWriter, r *http.Request) {
id := chi.URLParam(r, "id")
fmt.Println("id is :", id)
slc := data.GetOneEmp(id)
out, err := json.MarshalIndent(slc, "", " ")
if err != nil {
fmt.Println(err)
}
w.Header().Set("Content-Type", "application/json")
w.Write(out)
}
Database function
func GetOneEmp(id int) []m.Employees {
rows, err := d.DB.Query(`SELECT * FROM employees WHERE id=$1`, id)
if err != nil {
fmt.Println(err)
//return
}
var item m.Employees
var slc []m.Employees
defer rows.Close()
for rows.Next() {
err = rows.Scan(&item.ID, &item.Name, &item.Rank, &item.Address, &item.Salary)
//show status as well
if err != nil {
fmt.Println(err)
//return everywhere when you get an error
}
slc = append(slc, item)
}
return slc
}

Using or in bind and validation?

I'm using go gin with validation package called ozzo-validation and when I bind json data and validation error like this:
err := c.ShouldBind(&user)
valErrors := user.LoginValidate()
if err != nil || valErrors != nil {
util.ErrorJSON(c, http.StatusBadRequest, err.Error())
return
}
I got errors in console:
/usr/local/go/src/net/http/server.go:2878 +0x43b
net/http.(*conn).serve(0xc0002cebe0, {0x17430c0, 0xc0004a6f30})
/usr/local/go/src/net/http/server.go:1929 +0xb08
created by net/http.(*Server).Serve
/usr/local/go/src/net/http/server.go:3033 +0x4e8
when I convert the above code to the following it works!
var user models.User
// Decode request data
if err := c.ShouldBind(&user); err != nil {
util.ErrorJSON(c, http.StatusBadRequest, err.Error())
return
}
// Validate Error
if err := user.LoginValidate(); err != nil {
util.ErrorJSON(c, http.StatusBadRequest, err.Error())
return
}
what is variable user? is it a model? why don't you declare validation on your model with validatin-ozzo like :
func (f *user) Validate() error {
if err := validation.Validate(f.name, validation.Required); err != nil {
return &response.ErrorResponse{
ErrorID: 422,
Msg: map[string]string{
"en": "name cannot be empty",
},
}
}
return nil
}
type ErrorResponse struct {
ErrorID int `json:"error_id"`
Msg map[string]string `json:"message"`
}
func (c *ErrorResponse) Error() string {
b, _ := json.Marshal(c)
return string(b)
}
// and validate it on your code like :
if err := user.Validate(); err != nil {
return nil, err
}

How to handle result

I'm working on a Go project that use a neo4j database. I don't fully understand how to handle results from my queries.
Under, this is my code that I managed to work but I would like to return user instead of return user.email as email, user.pseudo as pseudo. Here I have 2 return values, but what if I have more than 10 values to return... I'm not sure, I'm doing it properly.
data, err := session.ReadTransaction(func(tx neo4j.Transaction)(interface{}, error) {
res, err := tx.Run(
`match (user:User) where user.email = $email
return user.email as email, user.pseudo as pseudo`,
map[string]interface{}{"email": email})
if err != nil {
return nil, err
}
if res.Next() {
if pseudo, found := res.Record().Get("pseudo"); found {
userData.Pseudo = pseudo.(string)
}
if email, found := res.Record().Get("email"); found {
userData.Email = email.(string)
}
return userData, nil
}
return nil, nil
})
Thing is, when I return user := res.Record().Values()[0] instead of res.Record().Get("something"), I got an interface but I don't know how to extract the data specifying the id like user.email.
A fmt.Printf("%t", user) gives &{%!t(*types.Node=&{0 [User] map[email:testman#mail.com pseudo:testman]})}.
**UPDATE
data, err := session.ReadTransaction(func(tx neo4j.Transaction)(interface{}, error) {
res, err := tx.Run(`MATCH (user:User) WHERE user.email = $email RETURN user`, map[string]interface{}{"email": email})
if err != nil {
return nil, err
}
if res.Next() {
record, err := res.Single()
if err != nil {
fmt.Printf("%s\n", err.Error())
return nil, err
}
userRecord, found := record.Get("user")
if !found {
return nil, errors.New("User not found")
}
userAttributes := userRecord.(map[string]interface{})
userData.Email = userAttributes["email"].(string)
return userData, nil
}
return nil, nil
})
Welcome!
If you query ends with RETURN user and because it seems you want a single result, you can write:
record, err := res.Single()
// [...] check err
userRecord, err := record.Get("user")
// [...] check err
userAttributes := userRecord.(dbtype.Node).Props // 1st cast record into node and extract properties
userData.pseudo := userAttributes["pseudo"].(string) // then cast each property value to expected type
// ...

Getting data from Firestore to display a go template file

How can I get the p.template from firestore, which is a string, into template.ParseFiles function? Is it possible to use the field value in the function to select the correct template file?
type Property struct {
Name string `firestore:"name"`
ApprovedOrigins []interface{} `firestore:"approvedOrigins"`
Template string `firestore:"selected"`
}
As you can see above the firestore field name is selected
func serveHandler(w http.ResponseWriter, r *http.Request, params map[string]string) {
ctx := context.Background()
client, err := firestore.NewClient(ctx, projectId)
if err != nil {
// TODO: Handle error.
log.Println("FIREBASE ERROR:", err)
}
// collection group query in firestore
q := client.CollectionGroup("data").Where("approvedOrigins", "array-contains", r.Host).Limit(1)
// iterate through the document query
iter := q.Documents(ctx)
defer iter.Stop()
for {
doc, err := iter.Next()
if err == iterator.Done {
break
}
if err != nil {
// TODO: Handle error.
log.Println("FIREBASE ERROR:", err)
}
fmt.Println("Database connected...")
var p Property
if err := doc.DataTo(&p); err != nil {
fmt.Println(err)
}
fmt.Println(p.Template) // This is not logging any data/string
t, _ := template.ParseFiles(p.Template + ".html")
fmt.Println(t.Execute(w, p)) //504 error happens here
}
}

pass interface pointer and assignment value

I want to write a file cache in Go. I am using gob encoding, and saving to a file, but my get function has some problem:
package main
import (
"encoding/gob"
"fmt"
"os"
)
var (
file = "tmp.txt"
)
type Data struct {
Expire int64
D interface{}
}
type User struct {
Id int
Name string
}
func main() {
user := User{
Id: 1,
Name: "lei",
}
err := set(file, user, 10)
if err != nil {
fmt.Println(err)
return
}
user = User{}
err = get(file, &user)
if err != nil {
fmt.Println(err)
return
}
//user not change.
fmt.Println(user)
}
func set(file string, v interface{}, expire int64) error {
f, err := os.OpenFile(file, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0600)
if err != nil {
return err
}
defer f.Close()
//wrapper data
//save v in data.D
data := Data{
Expire: expire,
D: v,
}
gob.Register(v)
enc := gob.NewEncoder(f)
err = enc.Encode(data)
if err != nil {
return err
}
return nil
}
func get(file string, v interface{}) error {
f, err := os.OpenFile(file, os.O_RDONLY, 0600)
if err != nil {
return err
}
defer f.Close()
var data Data
dec := gob.NewDecoder(f)
err = dec.Decode(&data)
if err != nil {
return err
}
//get v
v = data.D
fmt.Println(v)
return nil
}
The get function passes interface type and I want to change the value, but not change.
http://play.golang.org/p/wV7rBH028o
In order to insert an unknown value into v of type interface{}, you need to use reflection. This is somewhat involved, but if you want to support this in full, you can see how its done by walking through the decoding process in some of the encoding packages (json, gob).
To get you started, here's a basic version of your get function using reflection. This skips a number of checks, and will only decode something that was encoded as a pointer.
func get(file string, v interface{}) error {
f, err := os.OpenFile(file, os.O_RDONLY, 0600)
if err != nil {
return err
}
defer f.Close()
rv := reflect.ValueOf(v)
if rv.Kind() != reflect.Ptr || rv.IsNil() {
panic("need a non nil pointer")
}
var data Data
dec := gob.NewDecoder(f)
err = dec.Decode(&data)
if err != nil {
return err
}
dv := reflect.ValueOf(data.D)
if dv.Kind() != reflect.Ptr {
panic("didn't decode a pointer")
}
rv.Elem().Set(dv.Elem())
return nil
}
I would actually suggest an easier way to handle this in your own code, which is to have the Get function return an interface{}. Since you will know what the possible types are at that point, you can use a type switch to assert the correct value.
An alternative approach is to return directly the value from the file:
func get(file string) (interface{}, error) {
f, err := os.OpenFile(file, os.O_RDONLY, 0600)
if err != nil {
return nil, err
}
defer f.Close()
var data Data
dec := gob.NewDecoder(f)
err = dec.Decode(&data)
if err != nil {
return nil,err
}
fmt.Println(data.D)
return data.D,nil
}
full working example: http://play.golang.org/p/178U_LVC5y

Resources