One to One relation mapping using GORM for Golang - mysql

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)"`
}

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

Golang unset Struct Field

In Golang, I have below Struct with three fields
type Person struct {
name string
age int
rank int
}
For Processing, I need a rank field, but for output, I want to exclude the rank field from struct as I am directly passing above struct to JSON encoder to throw a response.
Is there any way by which I can unset rank field from Struct?
To unset a field, assign its zero value to it, like:
var p Person
p.rank = 0
Also know that if you want to use Person to work with JSON, you have to export the fields, unexported fields are not processed by the encoding/json package, so change Person to:
type Person struct {
Name string
Age int
rank int
}
This alone will make rank left out from JSON processing, as it is unexported.
If you need to export the rank field too, then use the json:"-" tag value to exclude an exported field from JSON processing:
type Person struct {
Name string
Age int
Rank int `json:"-"`
}

Return a whole struct in solidity?

Let's say I have a struct & a mapping like this:
struct myStruct {
address addr;
uint256 price;
bool approved;
}
mapping(string => myStruct) mappy;
How can I retrieve all the keys?
I know solidity will generate getters so if I have the key I can retrieve the info from inside the struct. But the keys are unknown to me and I need to retrieve the complete struct.
Maybe a better solution would be to have a public variable which would be the size of the struct and an index has key and store the key in the struct?
That way I will know the size and I suppose I can iterate it
First thing is that you shouldn't use string as key, better declare bytes32 as string is just an alias for it.
you can make a call to the mapping giving the string key as reference.
However it will retrieve only an iterative array without the internal keynames.
let's say for example you have :
mappy['a'] that contains the following information
{
'0x000...000',
1,
true
}
the call will retrieve an simple array like this : ['0x000...000',1,true]
If you want to make it an object you'll have to rebuild it on your own.

golang - elegant way to omit a json property from being serialized

I've got a user struct, which has sensitive fields like password:
type User struct {
UID string `json:"uid" binding:"required"`
Password string `json:"password" binding:"required"`
EmailAddress string `json:"email" binding:"required"`
}
Now I want to be able to use this struct to register a user and update, delete but also to view. What I don't want is for the password to be serialized for viewing. I can, of course, make a custom marshaller but is that the only way? I tried using the json:"-" option but that causes it to be ignored while unmarshalling as well, which I don't want. Is there a better way?
EDIT:
To put some of you guys at ease, I'm NOT going to be storing the password in plaintext, of course. It's the bcrypt hash of the password, but still. I don't want it to be returned when I search for users.
I'd say implementing json.Marshaler is the elegant solution if you want custom marshaling. It's quite simple in this case:
func (u User) MarshalJSON() ([]byte, error) {
type user User // prevent recursion
x := user(u)
x.Password = ""
return json.Marshal(x)
}
Add "omitempty" in your User type if you don't want the password field at all when marshaling.
I would go with another struct and composition.
Password should never be stored in plain-text, they should be securely hashed (bcrypt, pbkdf2, etc.). That hash is the one that has to be stored and should never be serialized. By using composition, you can do something like this:
type User struct {
UID string `json:"uid" binding:"required"`
HashedPassword string `json:"-"`
EmailAddress string `json:"email" binding:"required"`
}
type UserFormData struct {
User
Password string `json:"password" binding:"required"`
}
This also gives you more flexibility. For instance, if you ask the user to confirm the password, you can simply change the UserFormData struct like this:
type UserFormData struct {
User
Password string `json:"password" binding:"required"`
ConfirmPassword string `json:"confirm_password" binding:"required"`
}
Which also has the advantage to keep that serialization details outside your User object.
A simple solution would be to sanitize the user struct before marshaling it:
type User struct {
UID string `json:"uid" binding:"required"`
Password string `json:"password,omitempty" binding:"required"`
EmailAddress string `json:"email" binding:"required"`
}
func sanitizeUser(u User) User {
return User{u.UID, "", u.EmailAddress}
}
Demo: https://play.golang.org/p/RjKVoFc9o8
Now I want to be able to use this struct to register a user and update, delete but also to view.
Another solution is not to store the password at all in the struct. You don't need it to view, or delete, or update (normally).
You need it to create the user record, at which point you'll store a hash in your data store.
You need it to verify their identity (on login), at which point you verify against the hash in your data store, then usually issue a token they can use to keep accessing the service.
So there are only a few points you need it, and at those points you can simply keep it in memory separately and verify identity, it doesn't need to be exposed or stored in the struct for most operations. This is IMO more elegant than having it in the struct where it can very easily be exposed by mistake in export or logging.
You can query the database with a select statement to get only fields you like.
db.Model(&User{}).Select([]string{"uid","email"}).Find(&users)
Also add omitempty in your User type since empty response is sent for fields not included in select.

Golang Gorm error migrating struct

I have a small mistake in my small application and I really do not see where it can come from. So I have 4 structs, one of the 4 struct has several one-to-one relationships.
I connect to my database and use automigrate to migrate my 4 structs and create the necessary tables.
The problem is at this point, it does not create anything in the database and in the terminal I have this message:
(Error 1060: Name of the 'id' field already in use)
My code
main.go
package main
import (
"fmt"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
var db *gorm.DB
var err error
const (
mysupersecretpassword = "cr9ih_pvr9f9kc75n#bz&y%(#+^&1_#hr0^)-$kv%n3dh84$^w"
)
func main() {
db, err = gorm.Open("mysql", "root:root#/test?charset=utf8&parseTime=True")
if err != nil {
fmt.Println(err)
}
defer db.Close()
db.AutoMigrate(&User{}, &Ads{}, &Type{}, &Category{}, &Location{})
}
models.go
package main
import (
"github.com/jinzhu/gorm"
)
type User struct {
gorm.Model
Username string `json:"username"`
Email string `json:"email" form:"email"`
Password string `json:"password" form:"password"`
active bool `json:"active" gorm:"default:0"`
level bool `json:"level" gorm:"default:0"`
}
type Type struct {
gorm.Model
Name string `json:"name" form:"name"`
}
type Category struct {
gorm.Model
CatID uint `json:"category-parent" form:"category-parent" gorm:"default:0"`
Name string `json:"name" form:"name"`
}
type Location struct {
gorm.Model
Location string `json:"location" form:"location"`
}
type Ads struct {
gorm.Model
User User `json:"user"`
Type Type `json:"type" form:"type"`
Category Category `json:"category" form:"category"`
Title string `json:"title" form:"title"`
Content string `json:"content" form:"content"`
Location Location `json:"location" form:"location"`
}
Waiting for an answer that could put me on the right path :)
AutoMigrate will ONLY create tables, missing columns and missing indexes, and WON'T change existing column's type or delete unused columns to protect your data.
I would guess that one of your tables already exists, and the id column in that table is a different type than what gorm.Model wants to create. I would figure out which table it is by doing:
db.AutoMigrate(&User{})
db.AutoMigrate(&Ads{})
db.AutoMigrate(&Type{})
db.AutoMigrate(&Category{})
db.AutoMigrate(&Location{})
and seeing where it fails. Then, I would backup that table (just in case), and then either just drop the table completely, or rename the id column to tmp_id, see if automigrate fixes it, and if so, drop the tmp_id column.
FYI I've found Gorm will not log proper error or any error if it has permission issues on the user. For example the table existed when logged in as root, but the user I was logging in as didn't see it at all, Gorm just ran through Migration without creating the table or altering it (even though it was different schema) just didn't report any permission issue at all.