-
-
Notifications
You must be signed in to change notification settings - Fork 786
Add solution for gorm challenge-2-associations by aswinsreeraj #853
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
RezaSi
merged 1 commit into
RezaSi:main
from
aswinsreeraj:package-gorm-challenge-2-associations-aswinsreeraj-1765169626
Dec 8, 2025
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
117 changes: 117 additions & 0 deletions
117
packages/gorm/challenge-2-associations/submissions/aswinsreeraj/solution.go
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,117 @@ | ||
| package main | ||
|
|
||
| import ( | ||
| "time" | ||
|
|
||
| "gorm.io/gorm" | ||
| "gorm.io/driver/sqlite" | ||
| ) | ||
|
|
||
| // User represents a user in the blog system | ||
| type User struct { | ||
| ID uint `gorm:"primaryKey"` | ||
| Name string `gorm:"not null"` | ||
| Email string `gorm:"unique;not null"` | ||
| Posts []Post `gorm:"foreignKey:UserID"` | ||
| CreatedAt time.Time | ||
| UpdatedAt time.Time | ||
| } | ||
|
|
||
| // Post represents a blog post | ||
| type Post struct { | ||
| ID uint `gorm:"primaryKey"` | ||
| Title string `gorm:"not null"` | ||
| Content string `gorm:"type:text"` | ||
| UserID uint `gorm:"not null"` | ||
| User User `gorm:"foreignKey:UserID"` | ||
| Tags []Tag `gorm:"many2many:post_tags;"` | ||
| CreatedAt time.Time | ||
| UpdatedAt time.Time | ||
| } | ||
|
|
||
| // Tag represents a tag for categorizing posts | ||
| type Tag struct { | ||
| ID uint `gorm:"primaryKey"` | ||
| Name string `gorm:"unique;not null"` | ||
| Posts []Post `gorm:"many2many:post_tags;"` | ||
| } | ||
|
|
||
| // ConnectDB establishes a connection to the SQLite database and auto-migrates the models | ||
| func ConnectDB() (*gorm.DB, error) { | ||
| // TODO: Implement database connection with auto-migration | ||
| db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{}) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| err = db.AutoMigrate(&User{}, &Post{}, &Tag{}) | ||
| return db, err | ||
| } | ||
|
|
||
| // CreateUserWithPosts creates a new user with associated posts | ||
| func CreateUserWithPosts(db *gorm.DB, user *User) error { | ||
| // TODO: Implement user creation with posts | ||
| result := db.Create(user) | ||
| return result.Error | ||
| } | ||
|
|
||
| // GetUserWithPosts retrieves a user with all their posts preloaded | ||
| func GetUserWithPosts(db *gorm.DB, userID uint) (*User, error) { | ||
| // TODO: Implement user retrieval with posts | ||
| var user User | ||
| result := db.Preload("Posts").First(&user, userID) | ||
| return &user, result.Error | ||
| } | ||
|
|
||
| // CreatePostWithTags creates a new post with specified tags | ||
| func CreatePostWithTags(db *gorm.DB, post *Post, tagNames []string) error { | ||
| // TODO: Implement post creation with tags | ||
| if err := db.Create(post).Error; err != nil { | ||
| return err | ||
| } | ||
| for _, name := range tagNames { | ||
| var tag Tag | ||
| db.FirstOrCreate(&tag, Tag{Name: name}) | ||
| db.Model(post).Association("Tags").Append(&tag) | ||
| } | ||
| return nil | ||
| } | ||
|
|
||
| // GetPostsByTag retrieves all posts that have a specific tag | ||
| func GetPostsByTag(db *gorm.DB, tagName string) ([]Post, error) { | ||
| // TODO: Implement posts retrieval by tag | ||
| var posts []Post | ||
| err := db.Joins("JOIN post_tags ON posts.id = post_tags.post_id"). | ||
| Joins("JOIN tags ON post_tags.tag_id = tags.id"). | ||
| Where("tags.name = ?", tagName). | ||
| Find(&posts).Error | ||
| return posts, err | ||
| } | ||
|
|
||
| // AddTagsToPost adds tags to an existing post | ||
| func AddTagsToPost(db *gorm.DB, postID uint, tagNames []string) error { | ||
| // TODO: Implement adding tags to existing post | ||
| var post Post | ||
| result := db.First(&post, postID) | ||
| if result.Error != nil { | ||
| return result.Error | ||
| } | ||
| for _, tagName := range tagNames { | ||
| var tag Tag | ||
| db.FirstOrCreate(&tag, Tag{Name: tagName}) | ||
| if err := db.Model(&post).Association("Tags").Append(&tag); err != nil { | ||
| return err | ||
| } | ||
| } | ||
| return nil | ||
| } | ||
|
|
||
| // GetPostWithUserAndTags retrieves a post with user and tags preloaded | ||
| func GetPostWithUserAndTags(db *gorm.DB, postID uint) (*Post, error) { | ||
| // TODO: Implement post retrieval with user and tags | ||
| var post Post | ||
| err := db.Preload("User").Preload("Tags").First(&post, postID).Error | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| return &post, nil | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: RezaSi/go-interview-practice
Length of output: 200
🏁 Script executed:
fd "solution.go" packages/gorm/challenge-2-associations/submissions/aswinsreeraj/Repository: RezaSi/go-interview-practice
Length of output: 200
🏁 Script executed:
Repository: RezaSi/go-interview-practice
Length of output: 200
🏁 Script executed:
git ls-files | grep -i aswinsreerajRepository: RezaSi/go-interview-practice
Length of output: 200
🏁 Script executed:
Repository: RezaSi/go-interview-practice
Length of output: 200
🏁 Script executed:
fd -H "solution.go" --max-one-resultRepository: RezaSi/go-interview-practice
Length of output: 200
🏁 Script executed:
Repository: RezaSi/go-interview-practice
Length of output: 200
🏁 Script executed:
git ls-files | head -50Repository: RezaSi/go-interview-practice
Length of output: 200
🌐 Web query:
GORM FirstOrCreate error handling return value💡 Result:
Short answer — check result.Error for DB errors and use result.RowsAffected to tell if a create/update happened.
Details and example:
Example:
Sources: GORM docs — FirstOrCreate / Error handling and examples. [1][2][3]
References
🌐 Web query:
GORM Association Append error handling💡 Result:
Short answer — check the Association's Error field (or the returned error for the Generics API) and use transactions for multi-step/atomic work.
Examples and notes
Traditional (chainable) API — Append returns *Association; check .Error:
Generics API (v2 newer style) — methods return error directly; check the returned error:
Use db.Transaction when you need atomicity across multiple operations:
if err := tx.Model(&user).Association("Languages").Append(&lang).Error; err != nil { return err }
// other ops...
return nil
})
Common gotchas:
References
References mapping:
[1] https://gorm.io/docs/associations.html
[2] https://gorm.io/docs/error_handling.html
[3] https://gorm.io/docs/transactions.html
[4] https://learnku.com/docs/gorm/v2/associations/9740
[5] https://pkg.go.dev/github.com/let-s-go/gorm
🌐 Web query:
GORM v2 FirstOrCreate documentation error💡 Result:
Short answer — the GORM v2 docs/examples can be misleading: FirstOrCreate (and FirstOrInit) only use struct/map conditions for the lookup; string/SQL-style Where conditions may be ignored when passed as the "where" argument to FirstOrCreate. Use struct or map conditions (or call Where(...) then FirstOrCreate with a struct) or provide create attrs via the second parameter (or Attrs/Assign). Sources and examples: [1][2][3].
References
[1] Lessons Learned: Golang’s GORM FirstOrCreate — David Vassallo.
[2] GORM docs — Query / FirstOrCreate (Attrs / Assign examples).
[3] pkg.go.dev: FirstOrCreate description (notes only struct/map conditions).
🌐 Web query:
GORM v2 Association Append Error method💡 Result:
Short answer: In official go-gorm/gorm (v2) Association.Append returns an *Association (whose Error field holds any error). Do not use .Error after Append as if it returned a *gorm.DB — instead either read the returned Association.Error or call Association(...).Error before/after. Some forks or older examples differ (some implementations returned error directly), so you may see both patterns in the wild.
Examples:
References:
Sources:
[1] GORM Associations docs — gorm.io.
[2] StackOverflow — "Getting 'Missing Error method' when migrating from GORM V1 to V2".
Handle errors from
FirstOrCreateand appending tag associationsThe
CreatePostWithTagsfunction ignores DB errors fromFirstOrCreateandAssociation("Tags").Append, allowing the function to return success even if tags fail to persist. Both operations in GORM v2 require error checking via the.Errorfield:func CreatePostWithTags(db *gorm.DB, post *Post, tagNames []string) error { if err := db.Create(post).Error; err != nil { return err } for _, name := range tagNames { var tag Tag - db.FirstOrCreate(&tag, Tag{Name: name}) - db.Model(post).Association("Tags").Append(&tag) + if err := db.FirstOrCreate(&tag, Tag{Name: name}).Error; err != nil { + return err + } + if err := db.Model(post).Association("Tags").Append(&tag).Error; err != nil { + return err + } } return nil }For full atomicity (rollback on failure), wrap the operation in a transaction using
db.Transaction().📝 Committable suggestion
🤖 Prompt for AI Agents