Data binding in go using sqlBoiler - go

I am fetching some data from MYSQL database.. Using query data is getting correclty (eg 10 rows)
I want to bind into a list of model for displaying.
But panic error displaying
type UserDetails []UserDetail
type UserDetail struct {
id string `json:"id" boil:",bind"`
ScreenName string `json:"screenName" boil:",bind" `
}
func (m *mysqlStore) GetUsersDetails(ctx context.Context) () {
var userDetails []*models.UserDetail
err := queries.Raw(`
SELECT
user.id,
user.screen_name
FROM user
group by user.id
`).Bind(ctx, m.db, &userDetails)
if err != nil {
fmt.Println(err)
}
fmt.Println(userDetails)
}
here using the MYSQLQuery i am getting the correct data. I want to display that in a list of arrary eg:
[
{"id":"1",
"screenName":"test"},
{"id":"2",
"screenName":"test"}
]
what is the issue in my go code?

I got the Answer
In this case struct must be
type UserDetail struct {
id string `json:"id"`
ScreenName string `json:"screenName"`
}
and
var userDetails []models.UserDetail

Related

How to do a many-to-many query

I'm trying to understand how to use GORM to make query on items with many2many relations but I'm really lost.
I've got the following database model:
type Asset struct {
gorm.Model
Id uint `gorm:"primaryKey"`
MachineUID string `gorm:"type:varchar(128)" json:"machine_uid"`
AssetToken string `gorm:"uniqueIndex;type:varchar(128)"`
CommandQueries []*CommandQuery `gorm:"many2many:command_asset;"`
}
type CommandQuery struct {
gorm.Model
Id uint `gorm:"primaryKey"`
UUID string `gorm:"type:varchar(128)" json:"uuid"`
CmdType int `json:"cmdtype"`
CmdArgs string `gorm:"type:varchar(128)" json:"cmdargs"`
Assets *[]Asset `gorm:"many2many:command_asset;"`
Active bool
}
First, i'm successfully trying to retrieve an asset from a token with something like this:
token := "test-token"
var result Asset
db.Where("asset_token = ?", token).First(&result)
if result.Id == 0 {
return fmt.Errorf("Asset cannot be found in database")
}
But fom this returned struct, i would like to retrive all CommandQuery objects where:
this asset is in CommandQuery.assets
Where CommandQuery.active = true
I tried many things but nothing works, any help would be appreciated.
If I understood correctly, you want to load a slice of CommandQuery objects, and these objects should contain only assets where asset_token should be equal to the token you passed. Also, return only CommanQuery objects that have active=true.
If this is the case, it can be done like this:
token := "test-token"
var list []CommandQuery{}
tx := db.Preload("Assets", func (gdb *gorm.DB) *gorm.DB{
return gdb.Where("asset_token = ?", token)
}).
Where("active = ?", true).Find(&list)
if tx.Error == nil {
return nil, tx.Error
}
return *list, nil
In short, custom preloading is used to load assets into command query objects.

golang: convert row sql to object

Hello I am using pgx to use my postgres, and I have doubts as to how I can transform a row in the database into an aggregate
I am using entities and value objects
without value object it seems easy using marshal, but using value object I think it is not a good idea to have fields exported and then my question comes in, how can I convert my line into a struct of my aggregate
my aggregrate :
type Email struct {
address string
}
type Password struct {
value string
}
type Name struct {
firstName string
lastName string
}
type Person struct {
Id string
Name valueObject.Name
Email valueObject.Email
Password valueObject.Password
Created time.Time
Updated time.Time
}
func NewPerson(name valueObject.Name, email valueObject.Email, password valueObject.Password) *Person {
id := uuid.New()
return &Person{
Id: id.String(),
Name: name,
Email: email,
Password: password,
Created: time.Now(),
Updated: time.Now(),
}
}
all my value objects have a method to get the private value through a function simulating a get, I didn’t put the rest of the code of my value objects so it wouldn’t get big
func to get all rows from table:
func (r *personRepository) GetAll() (persons []*entities.Person, err error) {
qry := `select id, first_name, last_name, email, password created_at, updated_at from persons`
rows, err := r.conn.Query(context.Background(), qry)
return nil, fmt.Errorf("err")
}
If someone can give me a glimpse of how I can pass this line from the bank to a struct of my aggregate using this value object
You can use something like this (not yet tested and need optimization):
func (r *personRepository) GetAll() (persons []*entities.Person, err error) {
qry := `select id, first_name, last_name, email, password, created_at, updated_at from persons`
rows, err := r.conn.Query(context.Background(), qry)
var items []*entities.Person
if err != nil {
// No result found with the query.
if err == pgx.ErrNoRows {
return items, nil
}
// Error happened
log.Printf("can't get list person: %v\n", err)
return items, err
}
defer rows.Close()
for rows.Next() {
// Build item Person for earch row.
// must be the same with the query column position.
var id, firstName, lastName, email, password string
var createdAt, updatedAt time.Time
err = rows.Scan(&id, &firstName, &lastName, &email,
&createdAt, updatedAt)
if err != nil {
log.Printf("Failed to build item: %v\n", err)
return items, err
}
item := &entities.Person{
Id: id,
FirstName: firstName,
// fill other value
}
// Add item to the list.
items = append(items, item)
}
return items, nil
}
Don't forget to add the comma after text password in your query.
I am using entities and value objects without value object it seems easy using marshal,
Sorry, I don't know about the value object in your question.

How can I skip a specific field from struct while inserting with gorm

I was trying to make a rest API for user registration and on that api there is a field named "gender", so I'm receiving that field as Struct but on user table there is no field for "gender". Is it possible to skip that "gender" field from struct while inserting with gorm?
This is my DataModel
package DataModels
type User struct {
Id uint `json:"id"`
Otp int `json:"otp"`
UserId string `json:"user_id"`
UserType string `json:"user_type"`
FullName string `json:"full_name"`
MobileNo string `json:"mobile"`
Email string `json:"email"`
Gender string `json:"gender"` // I want to skip this filed while inserting to users table
Password string `json:"password"`
}
func (b *User) TableName() string {
return "users"
}
This my Controller Function
func CreateUser(c *gin.Context) {
var user Models.User
_ = c.BindJSON(&user)
err := Models.CreateUser(&user) // want to skip that gender filed while inserting
if err != nil {
fmt.Println(err.Error())
c.AbortWithStatus(http.StatusNotFound)
} else {
c.JSON(http.StatusOK, user)
}
}
This is my model function for inserting
func CreateUser(user *User) (err error) {
if err = Config.DB.Create(user).Error; err != nil {
return err
}
return nil
}
GORM allows you to ignore the field with tag, use gorm:"-" to ignore the field
type User struct {
...
Gender string `json:"gender" gorm:"-"` // ignore this field when write and read
}
Offical doc details about Field-Level Permission
Eklavyas Answer is omitting gender always, not just on Create.
If I am correct you want to Skip the Gender field within the Registration. You can use Omit for that.
db.Omit("Gender").Create(&user)

How to read custom types from datastore

I have a datastore table, which is like that
Name/ID | UserEmail | UserRole | UserPermissions
------------------------------------------------------
The UserRole attribute in json is a string. However, in Go code, it's a type
type UserDetails struct {
NameID string
UserEmail string
UserRole UserType
UserPermissions string //json??
}
type UserType string
const (
UnknownUserRole UserType = "UNKNOWN"
SiteAdmin UserType = "SITE_ADMIN"
SiteHR UserType = "SITE_HR"
)
func (ut *UserType) String() string {
return string(*ut)
}
func UserTypeFromString(userType string) UserType {
switch userType {
case "SITE_ADMIN":
return SiteAdmin
case "SITE_HR":
return SiteHR
default:
return UnknownRole
}
}
Now, I have to read all users for given org. I am using this code to do so
func (c DataStoreClient) GetUserDetailsByOrg(ctx context.Context, orgName string) ([]*UserDetails, error) {
var userDetails []*UserDetails
q := datastore.NewQuery(userDetailsKind).
Namespace(orgName)
keys, err := c.client.GetAll(ctx, q, &userDetails)
for i, key := range keys {
userDetails[i].NameID = key.Name
}
return userDetails, err
}
How can i read UserType from datastore using above code into UserDetails.UserType enum?
The code in the question works as is. There's no need to implement PropertyLoadSaver or loop over returned entities as suggested in other answers.
The custom data type is a string. The datastore package marshals all string types to and from datastore strings. It just works.
What you're essentially doing with UserType is that you have two valid values, and you're mapping all other values to a common unknown value. The following should work:
for i, key := range keys {
userDetails[i].NameID = key.Name
userDetails[i].UserRole = UserTypeFromString( string(userDetails[i].UserRole))
}
If you make your struct implement PropertyLoadSaver interface
https://godoc.org/cloud.google.com/go/datastore#hdr-The_PropertyLoadSaver_Interface
then you can handle these special requirements. You wouldn't have to remember to post process with every get/query.

Reuse or cast structs for validation, API results, and DB saves in Go

I'm trying to write an API that will do different things with the data depending on its purpose.
API results - The API should expose certain fields to the user
Validation - Validation should handle different schemas e.g. login form doesn't require Name, but register does
Database - The database should save everything, including password etc. - if I try using the same struct for the API and DB with json:"-" or un-exporting the field the database save also ignores the field
Some sample code is below with a couple of comments in capitals to show where I ideally need to type cast to change the data. As they are different structs, they cannot be type cast, so I get an error. How can I fix this?
Alternatively, what is a better way of doing different things with the data without having lots of similar structs?
// IDValidation for uuids
type IDValidation struct {
ID string `json:"id" validate:"required,uuid"`
}
// RegisterValidation for register form
type RegisterValidation struct {
Name string `json:"name" validate:"required"`
Email string `json:"email" validate:"required,email"`
Password string `json:"password" validate:"required,min=8"`
}
// UserModel to save in DB
type UserModel struct {
ID string `json:"id,omitempty"`
Name string `json:"name"`
Email string `json:"email"`
Password string `json:"password,omitempty"`
Active bool `json:"active,omitempty"`
CreatedAt int64 `json:"created_at,omitempty"`
UpdatedAt int64 `json:"updated_at,omitempty"`
jwt.StandardClaims
}
// UserAPI data to display to user
type UserAPI struct {
ID string `json:"id,omitempty"`
Name string `json:"name"`
Email string `json:"email"`
Active bool `json:"active,omitempty"`
}
// register a user
func register(c echo.Context) error {
u := new(UserModel)
if err := c.Bind(u); err != nil {
return err
}
// NEED TO CAST TO RegisterValidation HERE?
if err := c.Validate(u); err != nil {
return err
}
token, err := u.Register()
if err != nil {
return err
}
return c.JSON(http.StatusOK, lib.JSON{"token": token})
}
// retrieve a user
func retrieve(c echo.Context) error {
u := IDValidation{
ID: c.Param("id"),
}
if err := c.Validate(u); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, err.Error())
}
// NEED TO CAST USER TO UserAPI?
user, err := userModel.GetByID(u.ID)
if err != nil {
return err
}
return c.JSON(200, lib.JSON{"message": "User found", "user": user})
}

Resources