How to skip Hook in one-to-many-association model? - go

I have two models and their BeforeSave() Hooks
type Store struct {
ID int `json:"id"`
Name string `json:"name"`
Products []*Product `json:"products"`
}
type Product struct {
ID int `json:"id"`
Name string `json:"name"`
}
func (s *Store) BeforeSave(db *gorm.DB) error {
.....
return nil
}
func (p *Product) BeforeSave(db *gorm.DB) error{
......
return nil
}
When I insert a new Store into database using Gorm db.Create(&product), both Hooks are invoked. Is there any way to skip hook of Product (which means only invoke Store's BeforeSave())?

Related

How to add value before create using gorm?

I have this post.go model
package models
type Post struct {
Id uint `json:"ID"`
Name string `json:"Name"`
Message string `gorm:"type:text; index" json:"Message"`
Status string `gorm:"type:varchar(255); index" json:"Status"`
Desc string `gorm:"type:text; index" json:"Desc"`
}
func (p *Post) BeforeCreate() (err error) {
p.Status = "todo"
return nil
}
I need when I create any record by default put the status into the todo value
in my controller:
config.DB.Model(&models.Post{}).Create(&posts)
The result is I got a null value in status in the database
BeforeCreate interface signature is incorrect it should be BeforeCreate(*gorm.DB) error
func (p *Post) BeforeCreate(tx *gorm.DB) (err error) {
p.Status = "todo"
return nil
}
Another way would be to add default-values to the post struct
type Post struct {
Id uint `json:"ID"`
Name string `json:"Name"`
Message string `gorm:"type:text; index" json:"Message"`
Status string `gorm:"type:varchar(255); index; default: todo" json:"Status"`
Desc string `gorm:"type:text; index" json:"Desc"`
}
Output:
db.Create(&Post{}) // INSERT INTO `posts` (`name`,`message`,`status`,`desc`) VALUES ("","","todo","") RETURNING `id`

How to update struct data for array

I am trying to update "age" of data struct using SetAge() function after the array creation in the user struct. Here is the code snippet:
//data struct to set the user details
type data struct {
Name string `json:"name"`
College string `json:"college"`
Age int64 `json:"age"`
}
// user struct to store the user details in JSON Array
type user struct {
DataValue []*data `json:"data"`
}
func (u *user) Details(name, college string) *user {
d:=&data{Name:name, College:college}
u.DataValue=append(u.DataValue, d)
return u
}
func (u *user) SetAge(age int64) *user { //age is optional
// what code should be here such that age is added to resp detail
}
Output:
"data":[{
"name":"test",
"college":"test",
"age":10
},{
"name":"test",
"college":"test"
// in this object "Age" hasn't been set
}]
If you want to update the Age field of all the data objects, You're almost done.
You just need to iterate over the u.DataValue slice, and update the age field as follows:
func (u *user) SetAge(age int64) *user {
for index := range u.DataValue {
u.DataValue[index].Age = age
}
return u
}
As per the requirement in my application, it would be like this:
func (u *user) SetAge(age int64) *user {
u.DataValue[len(u.DataValue) - 1].Age = age
return u
}

How to get a struct in graphql resolvers with xorm?

Here is the struct in models_gen.go
type Students struct {
StudentID string `json:"student_id"`
Class string `json:"class"`
TestsHistory []*TestsHistory `json:"test_history"
}
type TestsHistory struct {
English string `json:"eng"`
Math string `json:"math"`
Music string `json:"music"`
PE string `json:"pe"`
}
The query function in resolvers.go:
func (r *queryResolver) GetStudents(ctx context.Context, id *int) (*model.Students, error) {
var students []*model.students
engine.Sync2(new(model.students))
fmt.Printf("%v\n", engine.Find(students))
return nil, nil
}
When I check MySQL, the students table only contains "StudentID" and "Class" Field, no "TestsHistory". How do I get "TestsHistory" in resolvers?

Marshal JSON field in database to struct using Pop

I'm using Go Buffalo's ORM Pop and want to store JSON in a field and be able to marshal it into a struct.
e.g.
schema.sql
CREATE TABLE tree (
id uuid PRIMARY KEY,
name text NOT NULL,
fruit json,
);
main.go
type Tree struct {
ID uuid.UUID `json:"id" db:"id"`
Name string `json:"name" db:"name"`
Fruit []Fruit `json:"fruit" db:"fruit"`
}
type Fruit struct {
ID int `json:"id"`
Name string `json:"name"`
}
I get the following error:
sql: converting argument $25 type: unsupported type []Fruit, a slice of struct
UPDATE
Based on feedback added the following methods:
type Fruits []Fruit
// Value implements the driver.Valuer interface
func (f Fruits) Value() (driver.Value, error) {
return json.Marshal(of)
}
// Scan implements the sql.Scanner interface
func (f * Fruits) Scan(value interface{}) error {
var data []byte
if b, ok := value.([]byte); !ok {
data = b
return errors.New("type assertion to []byte for Fruit failed")
}
return json.Unmarshal(data, &of)
}
Now receive the error:
Cannot fetch from database: unable to fetch records: sql: Scan error on column index 26, name "fruit": unexpected end of JSON input
Update 2
Updated Scan method to the following and fixed error:
// Scan implements the sql.Scanner interface
func (f * Fruits) Scan(value interface{}) error {
var data = []byte(value.([]uint8))
return json.Unmarshal(data, &of)
}
Based on the help provided by #mkopriva
You need to provide Value and Scan methods for your struct
// Tree tall tree with many fruit
type Tree struct {
ID uuid.UUID `json:"id" db:"id"`
Name string `json:"name" db:"name"`
Fruit []Fruit `json:"fruit" db:"fruit"`
}
// Fruit fruit found on a tree
type Fruit struct {
ID int `json:"id"`
Name string `json:"name"`
}
// Creates a splice of Fruit
type Fruits []Fruit
// Value implements the driver.Valuer interface
func (f Fruits) Value() (driver.Value, error) {
return json.Marshal(of)
}
// Scan implements the sql.Scanner interface
func (f * Fruits) Scan(value interface{}) error {
var data = []byte(value.([]uint8))
return json.Unmarshal(data, &f)
}

Golang jsonapi requires string or int but mongo needs bson.ObjectId

Playing with go and the following packages:
github.com/julienschmidt/httprouter
github.com/shwoodard/jsonapi
gopkg.in/mgo.v2/bson
I have the following structs:
type Blog struct{
Posts []interface{}
}
type BlogPost struct {
Id bson.ObjectId `jsonapi:"primary,posts" bson:"_id,omitempty"`
Author string `jsonapi:"attr,author"`
CreatedDate time.Time `jsonapi:"attr,created_date"`
Body string `jsonapi:"attr,body"`
Title string `jsonapi:"attr,title"`
}
and this router handler:
func (blog *Blog) GetAll(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
if err := jsonapi.MarshalManyPayload(w, blog.Posts); err != nil {
http.Error(w, err.Error(), 500)
}
}
When the handler function is called it spits out the error:
id should be either string or int
How should this struct look so I can use it with mgo and jsonapi?
Create one more struct of Blog like below
type BlogPostVO struct {
Id string `jsonapi:"primary,posts" bson:"_id,omitempty"`
Author string `jsonapi:"attr,author"`
CreatedDate time.Time `jsonapi:"attr,created_date"`
Body string `jsonapi:"attr,body"`
Title string `jsonapi:"attr,title"`
}
and use the below function in your controller to parse
func parseToVO(blog *models.Blog) *models.BlogVO {
bolgVO := models.BlogVO{}
bolgVO.Id = blog.Id.Hex()
bolgVO.Author = blog.Author
bolgVO.CreatedDate = blog.CreatedDate
bolgVO.Body = blog.Body
bolgVO.Title = blog.Title
return &models.Blog
}
this worked for me

Resources