How to solve gorm many2many error1062 - go

I have a many2many relation between news and tag. Whenever I tried to assign news to a tag it gives me an error Error 1062: Duplicate entry '5' for key 'news_id'
My model look like this:
type Tag struct {
ID uint64 `json:"id" gorm:"primary_key;unique;AUTO_INCREMENT"`
Title string `json:"title" gorm:"varchar(20)" binding:"required"`
News []*News `json:"news" gorm:"many2many:news_tags;association_foreignkey:ID;foreignkey:ID"`
CreatedAt time.Time `json:"created_at" gorm:"column:created_at"`
UpdatedAt time.Time `json:"updated_at" gorm:"column:updated_at"`
}
// News model
type News struct {
ID uint64 `json:"id" gorm:"primary_key;unique;AUTO_INCREMENT"`
Title string `json:"title" gorm:"varchar(20)" binding:"required"`
Body string `json:"body" gorm:"varchar(500)" binding:"required"`
Status string `json:"status" gorm:"varchar(5)"` // 1 = publish; 2 = draft; 3 = deleted;
Tags []*Tag `json:"tags" gorm:"many2many:news_tags;association_foreignkey:ID;foreignkey:ID"`
Topics []*Topic `json:"topics" gorm:"many2many:news_topics"`
CreatedAt time.Time `json:"created_at" gorm:"column:created_at"`
UpdatedAt time.Time `json:"updated_at" gorm:"column:updated_at"`
}
// My code when trying to assign new tag
func (n *News) AssignTags(tag Tag) {
db.DB().Model(n).Association("Tags").Append(tag)
}

Related

(Gorm Golang) How to select field without ignore json in struct?

So, I want to create an API, but when I try to query with a select field, I always fail, I want the data for my API only for the ID and Name fields, I want to remove movies field without ignoring the json because these fields are also needed in other urls, how to solve it?
This is model
type Movie struct {
ID int `json:"id" validate:"number"`
Title string `json:"title"`
Description string `json:"description"`
Year int `json:"year"`
ReleaseDate time.Time `json:"release_date"`
Runtime int `json:"runtime"`
Rating int `json:"rating"`
MPAARating string `json:"mpaa_rating"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
Genres []Genre `json:"genres" gorm:"many2many:movie_genres"`
}
type Genre struct {
ID int `json:"id"`
GenreName string `json:"name"`
Movies []Movie `json:"movies" gorm:"many2many:movie_genres"`
CreatedAt time.Time `json:"-"`
UpdatedAt time.Time `json:"-"`
}
type MovieGenre struct {
ID int `json:"id"`
MovieID int `json:"movie_id"`
GenreID int `json:"genre_id"`
Genre Genre `gorm:"foreignKey:GenreID"`
CreatedAt time.Time `json:"-"`
UpdatedAt time.Time `json:"-"`
}
This the code for query
func (MovieRepositoryImpl *MovieRepositoryImpl) GetGenres() (*[]Genre, error) {
var genres []Genre
err := MovieRepositoryImpl.DB.Find(&genres).Error
if err != nil {
return nil, err
}
return &genres, nil
}
This the result
I want to remove field movies without ignore the json
if you do not want send param: movies to backend and response without moives, it would work, json tag add omitempty.
type Genre struct {
ID int `json:"id"`
GenreName string `json:"name"`
Movies []Movie `json:"movies,omitempty" gorm:"many2many:movie_genres"`
CreatedAt time.Time `json:"-"`
UpdatedAt time.Time `json:"-"`
}

How to fix unsupported relations for schema error with gorm.Preload

I keep getting error Technician: unsupported relations for schema Ticket for this struct schema and query? What can I do to get make this Preload query works?
Or at least how can debug this issue? The error is pretty bare minimal and I have read the gorm preload page https://gorm.io/docs/preload.html, and don't get what I did wrong?
type Ticket struct {
ID uuid.UUID `json:"id"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
ShopID uuid.UUID `json:"shopID"`
Archived bool `json:"archived"`
Services []string `json:"services"`
Price int `json:"price"`
Location int `json:"location"`
Checkedout bool `json:"checkedout"`
TechnicianID uuid.UUID `json:"technicianId"`
Technician Technician `json:"technician"`
TechnicianPartnerID *uuid.UUID `json:"technicianPartnerId"`
LastUpdatedBy uuid.UUID `json:"lastupdatedBy"`
}
type Technician struct {
ID uuid.UUID `json:"id"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
ShopID uuid.UUID `json:"shopID"`
Name string `json:"name"`
Active bool `json:"active"`
}
dbQuery := t.Db.Orm.WithContext(ctx).Table("tickets").Preload("Technician")
You are not using the standard gorm.Model for the keys (from the docs):
type Model struct {
ID uint `gorm:"primaryKey"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt gorm.DeletedAt `gorm:"index"`
}
Gorm uses this to identify joins.
Changing your keys with the gorm:"primaryKey" indicator should fix the issue.
Or alternative: use gorm.Model:
type Ticker struct {
gorm.Model
ShopID uuid.UUID `json:"shopID"`
Archived bool `json:"archived"`
Services []string `json:"services"`
Price int `json:"price"`
Location int `json:"location"`
Checkedout bool `json:"checkedout"`
TechnicianID uuid.UUID `json:"technicianId"`
Technician Technician `json:"technician"`
TechnicianPartnerID *uuid.UUID `json:"technicianPartnerId"`
LastUpdatedBy uuid.UUID `json:"lastupdatedBy"`
}
type Technician struct {
gorm.Model
ShopID uuid.UUID `json:"shopID"`
Name string `json:"name"`
Active bool `json:"active"`
}

How to append custom attribute to Golang struct like $append on a Laravel model?

I am trying to add a custom attribute to my Golang struct just like how I usually add custom attribute on a Laravel model using the $appends variable.
This is the code:
package models
import (
"time"
)
type Dummy struct {
ID string `json:"id" gorm:"primary_key"`
Description string `json:"description"`
Image string `json:"image"`
ImageUrl ImageUrlDummy
Number int `json:"number"`
UserId string `json:"user_id"`
User User `json:"user"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
func ImageUrlDummy() string {
return "test"
}
However, the ImageUrlDummy inside the struct does not work, it return error such as:
ImageUrlDummy (value of type func() string) is not a type
How do I achieve this same code from Laravel to Golang?
class Dummy extends Model
{
protected $appends = ['image_url'];
public function getImageUrlAttribute(){
return "this is the image url";
}
}
Please pardon me I am still learning Golang, thank you
You are not far off..
Change your struct to (remove ImageUrlDummy, fix json tag for Image):
type Dummy struct {
ID string `json:"id" gorm:"primary_key"`
Description string `json:"description"`
Image string `json:"image"`
Number int `json:"number"`
UserId string `json:"user_id"`
User User `json:"user"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
Then define a method with a receiver of type Dummy pointer
func (d *Dummy) ImageUrl() string {
return "test"
}
Example with a few more things: https://play.golang.com/p/olGSFhBgqkG

Struct field level permissions

I am playing with gin-gonic+sqlx. Now I wonder what is the best way to dynamically bind database records to the struct?
Saying I have a struct and a query like this.
type Project struct {
ID string `db:"id"`
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
DeletedAt NullTime `db:"deleted_at"`
Name string
Status string
OpenDate NullTime `db:"open_date"`
Number uint
}
func (p Project) List() ([]Project, error) {
var pp []Project
err := db.Select(&pp, "SELECT * FROM Project")
return pp, err
}
Now I want to add field-level permissions to this struct. For example, an admin can view and edit all fields; User A can view CreatedAt and Name; User B can view and edit Name Status and view Number.
I was writing multiply structs for each use case, but obviously, I did choose the silliest way.
The other method I can think of is to implement Struct Tag. Am I on the right track or is there a better way to do this?
We can create multiple structs and embed among each other.
Example:
type ProjectSummary struct {
ID string `db:"id"`
Name string
}
type ProjectUser struct {
ProjectSummary
CreatedAt time.Time `db:"created_at"`
}
type ProjectSupport struct {
ProjectSummary
Status string
Number uint
}
type ProjectAdmin struct {
ProjectSupport
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
DeletedAt NullTime `db:"deleted_at"`
OpenDate NullTime `db:"open_date"`
}

Gorm simple find with foreign key not working

I have a problem with foreign key selection with gorm on MySQL database.
I got a file dto.go:
package dto
import (
"time"
)
type TaskResponse struct {
ID uint `json:"id"`
Title string `json:"title"`
Description string `json:"description"`
Status model.Status
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
A simple response object, but a task have a Status param.
I got a file task.go and status.go:
package model
// Status struct
type Status struct {
ID uint
Name string
}
// Task struct
type Task struct {
gorm.Model
ID uint
Title string
Description string
Status Status `gorm:"ForeignKey:ID"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt time.Time
}
The request:
database.DB.Model(&model.Task{}).First(dest, conds...)
The problem is that I would like to add in TaskResponse the result of request, but all the task fields are retrieved but the Status object is always empty ... (I try many things like the actual gorm:"ForeignKey:ID")
Someone know what is my problem?

Resources