Merging 2 structures with different types - go

I have two structures.
EventForm is the structure that is used to parse the POST body of a request.
EventTable is used for creating the MYSQL table structure and finding/creating rows.
I want to merge EventForm with EventTable so that fields like ID cannot be overridden via the POST body. I am not able to convert the type of EventForm to EventTable since you cannot convert a struct to a different type if the fields do not 100% match. So my question is what is the best way to merge these two structs? If it is not plausible to merge these two structs how could I best solve this problem?
package models
import "time"
// EventTable table structure of "events"
type EventTable struct {
EventForm `xorm:"extends"`
ID int `xorm:"autoincr pk 'id'" json:"id"`
Created time.Time `xorm:"not null created" json:"created"`
Updated time.Time `xorm:"not null updated" json:"updated"`
}
// TableName table name of EventTable
func (u *EventTable) TableName() string {
return "events"
}
// EventForm the structure that is received via an API call
type EventForm struct {
Title string `xorm:"not null" json:"title" required:"true"`
Description string `xorm:"not null" json:"description" required:"true"`
Owner string `xorm:"not null" json:"owner" required:"true"`
Lat string `xorm:"not null" json:"lat" required:"true"`
Lng string `xorm:"not null" json:"lng" required:"true"`
}

I am with #mkopriva and don't fully understand what the problem is. Assuming you are receiving EventForm from some API call
evtForm := GetSomeEventForm()
evtTable := &models.EventTable{ EventForm: evtForm, Created: time.Now() }
someORMProbably.Insert(evtTable)

Related

GORM: unsupported Scan, storing driver.Value type int64 into type *models.Team

I have issue with my first GORM usage. I want to load Point with preloaded Team structure. Go throw error that int64 cannot be stored in models.Team. I suppose that I have to use GORM the wrong way, but I am not able to find out why. Database contain data, relation many2many on other structs works fine for me (users in Team struct).
type Point struct {
Id int `gorm:"primaryKey"`
TeamX Team `gorm:"column:team_id;foreignKey:id"` // <<< this struct I want to get
CreatedAt time.Time
Note string
}
func (Point) TableName() string {
return "points"
}
type Team struct {
Id int `gorm:"primaryKey"`
Name string
Users []User `gorm:"many2many:teams_users;"`
}
func (Team) TableName() string {
return "teams"
}
var obj models.Point
log.Println(getDatabase().Preload("Teams").First(&obj, 1).Error.Error())
fmt.Println(obj.Id) // <<< this one loads ok
fmt.Println(obj.TeamX.Id) // <<< this throw error
points table
id int(11), auto_increment
team_id int(11), foreign key teams(id)
createdAt datetime
note text
teams table
id int(11), auto_increment
name text
sql: Scan error on column index 1, name "team_id": unsupported Scan, storing driver.Value type int64 into type *models.Team

Mapping one type to another

Let's say I have the following types.
type Contract struct {
Id string `json:"id" gorm:"column:uuid"`
Name string `json:"name" gorm:"column:name"`
Description string `json:"descr" gorm:"column:descr"`
ContractTypeId int `json:"contract_type_id" gorm:"column:contract_type_id"`
}
type ContractModel struct {
Id string `json:"id" gorm:"column:uuid"`
Name string `json:"name" gorm:"column:name"`
Description string `json:"descr" gorm:"column:descr"`
}
I have a SQL query using gorm to scan results into a contract object.
How can I map the values from the contract object into contractModel object?
I tried using the package go-automapper as such:
automapper.Map(contract, ContractModel{})
I want to drop the ContractTypeId.
Can I do this for multiple types in a list?
var contractModels []ContractModel
automapper.Map(contracts, &contractModels)
You can do either:
models := []ContractModel{}
automapper.Map(contracts, &models)
Or call automapper.Map in a loop:
models := make([]ContractModel, len(contracts))
for i := range contracts {
automapper.Map(contracts[i], &models[i])
}
You should be aware that automapper uses reflection behind the scenes and thus is much slower than straight forward non-polymorphic copying like #ThinkGoodly suggests. It's a totally fine solution if performance isn't top priority though.

Specify key for many-to-many relationship in go-pg ORM

I have these 2 models with many-to-many relationship:
type Person struct {
tableName struct{} `sql:"person"`
UUID string `sql:"person_uuid,pk"`
ContactDatas []ContactData `pg:",many2many:person_contact_data,joinFK:"`
}
type ContactData struct {
tableName struct{} `sql:"contact_data"`
UUID string `sql:"contact_data_uuid,pk"`
}
And model for person_contact_data table is:
type PersonContactData struct {
tableName struct{} `sql:"person_contact_data"`
PersonUUID string `sql:"person_uuid"`
ContactDataUUID string `sql:"contact_data_uuid"`
}
If joinFK in ContactDatas struct tag is empty go-pg adds underscore under the hood, so generated SQL part looks like this: WHERE ("contact_data"."contact_data_uuid" = person_contact_data."_contact_data_uuid").
Is there a way to specify joining keys completely manual?
I was using version 5. In latest version this was fixed, now you can specify full joining keys:
type Person struct {
tableName struct{} `sql:"person"`
UUID string `sql:"person_uuid,pk"`
ContactDatas []ContactData `pg:",many2many:person_contact_data,fk:person_uuid,joinFK:contact_data_uuid"`
}

Golang Decode a BSON with special character Keys to a struct

I have a Golang struct called Person where all the properties have to be exported:
type Person struct {
Id string
Name string
}
Now I need to encode my MongoDB BSON response to this Person struct. The BSON looks like:
{
"_id": "ajshJSH78N",
"Name": "Athavan Kanapuli"
}
The Golang code to encode the BSON is:
mongoRecord := Person{}
c := response.session.DB("mydb").C("users")
err := c.Find(bson.M{"username": Credentials.Username, "password": Credentials.Password}).One(&mongoRecord)
The Problem:
_id is not getting encoded into Id
If I change the Person property into _Id, then it won't be exported.
How can I solve this problem?
Define your struct with json tag-
type Person struct {
Id string `json:"_id"`
Name string // this field match with json, so mapping not need
}
I tried to put a json tag like ,
type Person struct {
Id string `json:"_id"`
Name string // this field match with json, so mapping not need
}
But still it didn't work. Because the Mongodb returns '_id' which is of type bson.ObjectId . Hence changing the Struct tag to bson:"_id" and the type of the Person struct has been changed from string to bson.ObjectId. The changes done are as follows ,
type Person struct {
Id bson.ObjectId `bson:"_id"`
Name string
UserName string
IsAdmin bool
IsApprover bool
}
And It works!

golang not supporting struct slice depth with template

I stuck with an unique problem. To learn golang, I created a twitter kind of website. It has tweets and each tweets can have comments and each comment can have sub-comments.
Showing struct pd in homepage.html
Env.Tpl.ExecuteTemplate(w, "homePage.html", pd)
where pd is pagedata (I removed extra information for simplicity)
type PageData struct {
TweetView []tweets.TweetView
}
Where tweet.TweetView is
type TweetView struct {
Tweet
CV []comments.Comment
}
where comments.Comment is
type Comment struct {
TweetID int64
ParentCommentID int64
CommentID int64
CreatedAt time.Time
Name string
UserID int64
CommentMsg string
}
This works. but if I change the CV in tweetView with comment.CommentView .. template stop showing TweetView.
comment.CommentView is
type CommentView struct {
Comment
CC []Comment
}
the new TweetView would be defined as
type TweetView struct {
Tweet
CV []comments.CommentView
}
Getting this error, when trying to make a datastore query to extract tweet object into Tweetview
err := datastore.Get(ctx, tweetKey, &tweetView[v])
datastore: flattening nested structs leads to a slice of slices: field
"CV",
I think it is a limitation of golang. What should I do?
I was able to solve the problem. The problem was with datastore.Get query.
It was giving below error when I was running
err := datastore.Get(ctx, tweetKey, &tweetView[v])
datastore: flattening nested structs leads to a slice of slices: field
"CV",
So what I changed the query like this
var tweetTemp Tweet
datastore.Get(ctx, tweetKey, &tweetTemp)
tweetSlice[v].Tweet = tweetTemp
Please let me know if you see problem with this approach

Resources