model structs for many to many relationship using std - mysql

I'm trying to learn go and I want to create a many to many relationship between a post and a tag. A tag can belong to many posts and a post can have many tags. I am using the standard library using the mysql drive (github.com/go-sql-driver/mysql)
Here's my code:
post.go
package main
type post struct {
ID int `json:"id"`
Title string `json:"title"`
Content string `json:"content"`
Tags: Tag `json:"tags"`
}
tag.go
package main
type tag struct {
ID int `json:"id"`
Name string `json:"name"`
Posts: Post `json:"posts"`
}
Is this the correct way to structure this many to many relationship?
Cheers

Here are a couple of modifications to consider:
Keep your type names consistent (post vs. Post for example)
I think you were going for a slice of Tags and a slice of Posts, so I updated the syntax for that.
One significant question you'll need to answer; do you need/want your structures to be stored in memory with single structs for each item? If so you'll probably want to consider using slices of pointers to Tag and Post instead ([]*Post and []*Tag for example), but popular ORM libraries don't strictly need that (for example gorm: http://jinzhu.me/gorm/associations.html#many-to-many).
Example code:
type Post struct {
ID int `json:"id"`
Title string `json:"title"`
Content string `json:"content"`
Tags []Tag `json:"tags"`
}
type Tag struct {
ID int `json:"id"`
Name string `json:"name"`
Posts []Post `json:"posts"`
}

Related

Use Validator/Dive to enter an array and validate nested structs in go

type myType struct {
value int `json:"value"`
Name string `json:"name" validate:"required"`
URL string `json:"URL" validate:"required"`
args []otherType `json:"args" validate:"dive", "required"`
}
type otherType struct {
name string `validate:"required"`
origin string `validate:"required"`
}
err := paramsValidator.Validate(someInstantiationOfThisStruct)
Hello there! I'm a tad bit stumped on using validator's dive feature. This specific combination of validation scheme isn't present in the documentation for the validator, and I was unable to get it working with a little bit of tweaking.
I would like to simply enter the args array in the primary struct, and validate each of two sets of otherType. However I don't quite understand how this is supposed to transpire.
I understand dive incorrectly and it's not working of course, as the validator is unable to determine incorrect validations using Validate().
Is there any particular thing I'm doing wrong? In general how should I approach evaluating and validating args that are in an array?
I was able to figure it out. I am so sorry for even posting! I was stumped for thirty minutes, but the solution was not that particularly bad.
type myType struct {
value int `json:"value"`
Name string `json:"name" validate:"required"`
URL string `json:"URL" validate:"required"`
args []otherType `json:"args" validate:"dive", "required"`
}
type otherType struct {
name string `validate:"required"`
origin string `validate:"required"`
}
is the updated code. There was a missing , between "dive" and "required", and I had posted code that read
`validate: "dive, required"
dyslexia sorry! :(
I came searching for the answer here but the solution didn't work for me.
In order to validate nested struct using go-playground/validator add dive.
So add below code to the nested struct at top level
`validate:"required,dive,required"`
Note: add without spaces, also make sure the fields are exposed (use PascalCase) to package incase u importing the struct
type myType struct {
value int `json:"value"`
Name string `json:"name" validate:"required"`
URL string `json:"URL" validate:"required"`
Args []OtherType `json:"args" validate:"required,dive,required"`
}
type OtherType struct {
Name string `validate:"required"`
Origin string `validate:"required"`
}
Note: This validation is as per my use case where i want Args to be required and also want it to be exposed to other packages. Just trying to help other who come searching for the same issue as "Dive" is not documented properly in go/playground documentation

How to Unmarshall data to JSON with unknown field types

I have these 'structures'
type Results struct {
Gender string `json:"gender"`
Name struct {
First string `json:"first"`
Last string `json:"last"`
} `json:"name"`
Location struct {
Postcode int `json:"postcode"`
}
Registered struct {
Date string `json:"date"`
} `json:"registered"`
}
type Info struct {
Seed string `json:"seed"`
Results int64 `json:"results"`
Page int64 `json:"page"`
Version string `json:"version"`
}
type Response struct {
Results []Results `json:"results"`
Info Info `json:"info"`
}
I' making a request to an external API and converting data to a JSON view.
I know in advance the types of all fields, but the problem occurs with the 'postcode' field. I'm getting different types of values, which is why I get a JSON decoding error.
In this case, 'postcode' can be one of three variants:
string ~ "13353"
int ~ 13353
string ~ "13353postcode"
Changing the postcode type from string to json.Number solved the problem.
But this solution does not satisfy the third "option".
I know I can try to create a custom type and implement an interface on it. Seems to me the best solution using json.RawMessage. It’s the first I've faced this problem, So I'm still looking for an implementation of a solution to this and reading the documentation.
What's the best way solution in this case?
Thanks in advance.
Declare a custom string type and have it implement the json.Unmarshaler interface.
For example, you could do this:
type PostCodeString string
// UnmarshalJSON implements the json.Unmarshaler interface.
func (s *PostCodeString) UnmarshalJSON(data []byte) error {
if data[0] != '"' { // not string, so probably int, make it a string by wrapping it in double quotes
data = []byte(`"`+string(data)+`"`)
}
// unmarshal as plain string
return json.Unmarshal(data, (*string)(s))
}
https://play.golang.org/p/pp-zNNWY38M

One to One relation mapping using GORM for Golang

I am trying to understand how GORM works for one to one relational mapping with MySQL. I have 2 structs like so:
type User struct {
Id uint `gorm:"AUTO_INCREMENT"`
FirstName string `gorm:"column:first_name"`
LastName string `gorm:"column:last_name"`
EncryptedUserId string `gorm:"size:255"`
Email string `gorm:"not null;unique"`
Password string `gorm:"not null;unique"`
CreatedAt int64 `gorm:"type(timestamp)"`
}
type UserSession struct {
Id uint `gorm:"AUTO_INCREMENT"`
UserId User
SessionToken string `gorm:"column:session_token"`
CreatedAt int64 `gorm:"type(timestamp)"`
}
User and UserSession share one to one relation. But when code above is run, the column UserId for UserSession table is not created. Even after specifying the foreign key constraint gorm:"ForeignKey:Id"
the result is same. Why isn't the above code working? Is anything missing in the struct definition?
I can't comment your questions so I would ask it here:
Do you migrate your schema in any way like:
db.AutoMigrate(&User{}, &UserSession{})
?
If you do, you should get some detailed errors in log, which might be useful for you.
The way I have managed to get something similar to work is this.
type UserSession struct {
Id uint `gorm:"AUTO_INCREMENT"`
UserId uint
User User
SessionToken string `gorm:"column:session_token"`
CreatedAt int64 `gorm:"type(timestamp)"`
}

Unmarshalling Complex Json

I just recently started working with apis and http requests and I'm trying to build an application that uses the Reddit API to pull posts on a specific subreddit.
This is the the page with json and search parameters that I'm practicing on:
https://www.reddit.com/r/hiphopheads.json?limit=1
Looking at the standard library of the JSON module for Golang, I still don't understand how to use json.Unmarshal for this complex JSON. From what I gather, I have to define a struct that resembles the JSON structure to actually hold the data
I posted the link into this website to get a feel for what the JSON is actually strucutred like: https://jsonformatter.curiousconcept.com/
Right now the main thing I'm after is the title which is under Data->Children->Data->Title. If I want to unmarshal the JSON into an object, do I define a nested struct object? Or is there a simpler way to do this so that I don't have to figure out all the attributes of the JSON and define them myself??
Any help that can get me on the right track is greatly appreciated. Thanks!
You don't have to define fields you don't need in your struct. Unmarshal will only decode the values that are present in your struct. But with nested JSONs you unfortunately have to define all the parent fields also (unlike in xml package in which you can define paths in tags). So your struct could look like this:
type Foo struct {
Data struct {
Children []struct {
Data struct {
Title string
}
}
}
}
See here for a working example: https://play.golang.org/p/UeUYfWBONL
It seems like the JSON you are trying to unmarshal is over complex, so your struct has to be complex, but that's the way it goes.
There are a few tools that generate struct definitions from a JSON, and that saves a ton of work. Using the JSON you posted and such an online tool, I generated the following struct:
package main
type MyJsonName struct {
Data struct {
After string `json:"after"`
Before interface{} `json:"before"`
Children []struct {
Data struct {
ApprovedBy interface{} `json:"approved_by"`
Archived bool `json:"archived"`
Author string `json:"author"`
AuthorFlairCSSClass string `json:"author_flair_css_class"`
AuthorFlairText interface{} `json:"author_flair_text"`
BannedBy interface{} `json:"banned_by"`
Clicked bool `json:"clicked"`
ContestMode bool `json:"contest_mode"`
Created int `json:"created"`
CreatedUtc int `json:"created_utc"`
Distinguished string `json:"distinguished"`
Domain string `json:"domain"`
Downs int `json:"downs"`
Edited bool `json:"edited"`
Gilded int `json:"gilded"`
Hidden bool `json:"hidden"`
HideScore bool `json:"hide_score"`
ID string `json:"id"`
IsSelf bool `json:"is_self"`
Likes interface{} `json:"likes"`
LinkFlairCSSClass string `json:"link_flair_css_class"`
LinkFlairText string `json:"link_flair_text"`
Locked bool `json:"locked"`
Media interface{} `json:"media"`
MediaEmbed struct{} `json:"media_embed"`
ModReports []interface{} `json:"mod_reports"`
Name string `json:"name"`
NumComments int `json:"num_comments"`
NumReports interface{} `json:"num_reports"`
Over18 bool `json:"over_18"`
Permalink string `json:"permalink"`
Quarantine bool `json:"quarantine"`
RemovalReason interface{} `json:"removal_reason"`
ReportReasons interface{} `json:"report_reasons"`
Saved bool `json:"saved"`
Score int `json:"score"`
SecureMedia interface{} `json:"secure_media"`
SecureMediaEmbed struct{} `json:"secure_media_embed"`
Selftext string `json:"selftext"`
SelftextHTML string `json:"selftext_html"`
Stickied bool `json:"stickied"`
Subreddit string `json:"subreddit"`
SubredditID string `json:"subreddit_id"`
SuggestedSort interface{} `json:"suggested_sort"`
Thumbnail string `json:"thumbnail"`
Title string `json:"title"`
Ups int `json:"ups"`
URL string `json:"url"`
UserReports []interface{} `json:"user_reports"`
Visited bool `json:"visited"`
} `json:"data"`
Kind string `json:"kind"`
} `json:"children"`
Modhash string `json:"modhash"`
} `json:"data"`
Kind string `json:"kind"`
}
Usually, the output of these tools still needs to manual tweaking to work properly. for example:
MediaEmbed struct{} `json:"media_embed"`
I'm pretty sure that's not what's needed here. But it does go a long way in showing the basic idea and figuring out most of the stuff correctly. There are other similar tools you can try.

Override struct tags in go

I have an entity in my project that is viewable by public and by admin. Not all fields should be accessible by public.
For example
type Foo struct {
Id bson.ObjectId `json:"id" bson:"_id"`
DateAdded time.Time `json:"date_added" bson:"date_added"`
Bar string `json:"bar" bson:"bar"`
AdminOnly string `json:"admin_only" bson:"admin_only"`
}
AdminOnly field should be only visible to admins.
For now, when requests comes from public, I call separate method that copies every needed field to new struct
type FooPublic struct {
Id bson.ObjectId `json:"id" bson:"_id"`
DateAdded time.Time `json:"date_added" bson:"date_added"`
Bar string `json:"bar" bson:"bar"`
}
func (f *Foo) Public() (res FooPublic) {
res = FooPublic{
Id: f.Id,
DateAdded: f.DateAdded,
Bar:f.Bar,
}
return
}
But if I need to add new field to my entity, I need to add it in 3 places. In struct itself, in PublicFoo and in Public method.
This seems to be agains DRY principle. What is correct, idiomatic solution here? Can I define FooPublic so it overrides tags of needed fields? Or probably there is at least good way to copy corresponding fields from one struct to another, so I don't need to do this manually in Public method?
In general this repetition can be avoided by using embedding. Your Foo type should embed FooPublic:
type FooPublic struct {
Id bson.ObjectId `json:"id" bson:"_id"`
DateAdded time.Time `json:"date_added" bson:"date_added"`
Bar string `json:"bar" bson:"bar"`
}
type Foo struct {
FooPublic
AdminOnly string `json:"admin_only" bson:"admin_only"`
}
func (f *Foo) Public() FooPublic {
return f.FooPublic
}
But if someone is able to call the Foo.Public(), that someone already has the Foo or *Foo value (and so can access the exported AdminOnly field), so what's the point?
A better solution would be to use an interface, and not expose the Foo struct.