Skip to content

Commit e8ce099

Browse files
committed
repository: working article repository
1 parent 5c81a01 commit e8ce099

File tree

9 files changed

+408
-24
lines changed

9 files changed

+408
-24
lines changed

database/models/article.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@ type Article struct {
1313
Body string `gorm:"size:2048"`
1414
Author User
1515
AuthorID uint
16-
Tags []Tag `gorm:"many2many:article_tags;"`
16+
Tags []Tag `gorm:"many2many:article_tags;association_autocreate:false"`
1717
Comment []Comment `gorm:"ForeignKey:ArticleID"`
18+
Favorites []User `gorm:"many2many:article_favorites;"`
1819
}
1920

2021
func (a *Article) UpdateSlug() {

database/models/user.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@ import (
77

88
type User struct {
99
gorm.Model
10-
Email string `gorm:"column:email;unique_index"`
11-
Username string `gorm:"column:username;unique_index"`
12-
Password string `gorm:"column:password; not null"`
13-
Bio string `gorm:"column:bio;size:1024"`
14-
Image string
10+
Email string `gorm:"column:email;unique_index"`
11+
Username string `gorm:"column:username;unique_index"`
12+
Password string `gorm:"column:password; not null"`
13+
Bio string `gorm:"column:bio;size:1024"`
14+
Image string
15+
Favorites []Article `gorm:"many2many:article_favorites;"`
1516
}
1617

1718
type Follow struct {

go.mod

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@ module gin-rest-api-example
33
go 1.14
44

55
require (
6+
github.com/docker/docker v0.7.3-0.20190506211059-b20a14b54661
7+
github.com/docker/go-connections v0.4.0
8+
github.com/google/uuid v1.1.1
69
github.com/gosimple/slug v1.9.0
710
github.com/jinzhu/gorm v1.9.12
11+
github.com/stretchr/testify v1.4.0
12+
github.com/testcontainers/testcontainers-go v0.5.1
813
)

go.sum

Lines changed: 135 additions & 0 deletions
Large diffs are not rendered by default.

main.go

Lines changed: 110 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package main
22

33
import (
4+
"encoding/json"
45
"fmt"
56
"gin-rest-api-example/database/models"
67
"gin-rest-api-example/repository"
@@ -15,19 +16,25 @@ func main() {
1516
if err != nil {
1617
log.Fatal(err)
1718
}
19+
db.LogMode(true)
1820
defer db.Close()
1921

2022
//db.DropTable(&models.Follow{}, &models.User{})
2123
//db.AutoMigrate(&models.Follow{}, &models.User{})
2224
//testUsers(db)
2325

24-
//db.DropTable(&models.Comment{}, &models.ArticleTag{}, &models.Tag{}, &models.ArticleFavorite{},
25-
// &models.Article{}, &models.Follow{}, &models.User{})
26-
//db.AutoMigrate(&models.Follow{}, &models.User{}, &models.Article{}, &models.ArticleFavorite{}, &models.Tag{},
27-
// &models.ArticleTag{}, &models.Comment{})
26+
db.DropTable(&models.Comment{}, &models.ArticleTag{}, &models.Tag{}, &models.ArticleFavorite{},
27+
&models.Article{}, &models.Follow{}, &models.User{})
28+
db.AutoMigrate(&models.Follow{}, &models.User{}, &models.Article{}, &models.ArticleFavorite{}, &models.Tag{},
29+
&models.ArticleTag{}, &models.Comment{})
2830
testArticles(db)
2931
}
3032

33+
// user : u1, u2
34+
// articles (title, tags, author, liked user)
35+
// - "title" / ["Tag1", "Tag2"] / u1 / u2
36+
// - "title2" / ["Tag1", "Tag3"] / u1 / u2
37+
// - "title3" / ["Tag3", "Tag4"] / u2 / u1
3138
func testArticles(db *gorm.DB) {
3239
userRepo := repository.NewUserRepository(db)
3340
articleRepo := repository.NewArticleRepository(db)
@@ -42,44 +49,85 @@ func testArticles(db *gorm.DB) {
4249
}
4350
_ = userRepo.Save(u1)
4451

52+
fmt.Println("Try to save user2")
53+
u2 := &models.User{
54+
55+
Username: "user2",
56+
Password: "user2",
57+
Bio: "user2 bio",
58+
Image: "user2 image",
59+
}
60+
_ = userRepo.Save(u2)
61+
4562
fmt.Println("Try to save article1")
4663
a := &models.Article{
4764
Title: "title",
4865
Description: "description",
4966
Body: "body",
5067
Author: *u1,
5168
AuthorID: u1.ID,
52-
Tags: []models.Tag{
69+
Tags: []models.Tag{
5370
{
54-
Name : "Tag1",
71+
Name: "Tag1",
5572
},
5673
{
57-
Name : "Tag2",
74+
Name: "Tag2",
5875
},
5976
},
60-
Comment: nil,
77+
Comment: nil,
6178
}
6279
a.UpdateSlug()
6380
_ = articleRepo.SaveArticle(a)
81+
articleRepo.UpdateFavorite(&models.ArticleFavorite{
82+
UserID: u2.ID,
83+
ArticleID: a.ID,
84+
})
6485

65-
fmt.Println("Try to save article1")
86+
fmt.Println("Try to save article2")
6687
a2 := &models.Article{
6788
Title: "title2",
6889
Description: "description2",
6990
Body: "body2",
7091
AuthorID: u1.ID,
71-
Tags: []models.Tag{
92+
Tags: []models.Tag{
7293
{
73-
Name : "Tag1",
94+
Name: "Tag1",
7495
},
7596
{
76-
Name : "Tag3",
97+
Name: "Tag3",
7798
},
7899
},
79-
Comment: nil,
100+
Comment: nil,
80101
}
81102
a2.UpdateSlug()
82103
_ = articleRepo.SaveArticle(a2)
104+
articleRepo.UpdateFavorite(&models.ArticleFavorite{
105+
UserID: u2.ID,
106+
ArticleID: a2.ID,
107+
})
108+
109+
fmt.Println("Try to save article3")
110+
a3 := &models.Article{
111+
Title: "title3",
112+
Description: "description3",
113+
Body: "body3",
114+
AuthorID: u2.ID,
115+
Tags: []models.Tag{
116+
{
117+
Name: "Tag3",
118+
},
119+
{
120+
Name: "Tag4",
121+
},
122+
},
123+
Comment: nil,
124+
}
125+
a3.UpdateSlug()
126+
_ = articleRepo.SaveArticle(a3)
127+
_ = articleRepo.UpdateFavorite(&models.ArticleFavorite{
128+
UserID: u1.ID,
129+
ArticleID: a3.ID,
130+
})
83131

84132
fmt.Println("Try to save comment1")
85133
c := &models.Comment{
@@ -88,6 +136,55 @@ func testArticles(db *gorm.DB) {
88136
AuthorID: u1.ID,
89137
}
90138
_ = articleRepo.SaveOne(c)
139+
140+
fmt.Println(">>>> FindArticleBySlug")
141+
find, _ := articleRepo.FindArticleBySlug(a.Slug)
142+
b, _ := json.Marshal(find)
143+
fmt.Println(string(b))
144+
145+
fmt.Println(">>>> FindArticles")
146+
articles, count, _ := articleRepo.FindArticles(repository.Pageable{
147+
Offset: 0,
148+
Limit: 1,
149+
})
150+
fmt.Println("total count :", count)
151+
for _, a := range articles {
152+
b, _ := json.Marshal(a)
153+
fmt.Println(string(b))
154+
}
155+
156+
fmt.Println(">>>> FindArticles by tag : Tag1")
157+
articles, count, _ = articleRepo.FindArticlesByTag("Tag1", repository.Pageable{
158+
Offset: 0,
159+
Limit: 1,
160+
})
161+
fmt.Println("total count :", count)
162+
for _, a := range articles {
163+
b, _ := json.Marshal(a)
164+
fmt.Println(string(b))
165+
}
166+
167+
fmt.Println(">>>> FindArticles by author : user1")
168+
articles, count, _ = articleRepo.FindArticlesByAuthor("user1", repository.Pageable{
169+
Offset: 0,
170+
Limit: 1,
171+
})
172+
fmt.Println("total count :", count)
173+
for _, a := range articles {
174+
b, _ := json.Marshal(a)
175+
fmt.Println(string(b))
176+
}
177+
178+
fmt.Println(">>>> FindArticles by favorited by", u2.Username)
179+
articles, count, _ = articleRepo.FindArticlesByFavoritedUsername(u2.Username, repository.Pageable{
180+
Offset: 0,
181+
Limit: 1,
182+
})
183+
fmt.Println("total count :", count)
184+
for _, a := range articles {
185+
b, _ := json.Marshal(a)
186+
fmt.Println(string(b))
187+
}
91188
}
92189

93190
func testUsers(db *gorm.DB) {

repository/interfaces.go

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,41 @@ type UserRepository interface {
4141
FindFollowing(user *models.User) ([]*models.User, error)
4242
}
4343

44-
type ArticleFilter struct {
45-
}
46-
4744
type ArticleRepository interface {
45+
// SaveOne save given interface
4846
SaveOne(data interface{}) error
47+
48+
// =================================
49+
// Articles
50+
// =================================
51+
52+
// SaveArticle save given article with tags
4953
SaveArticle(article *models.Article) error
54+
55+
// FindArticleBySlug returns a article with given slug or nil if empty
56+
FindArticleBySlug(slug string) (*models.Article, error)
57+
58+
// FindArticles return articles,count given pageable
59+
FindArticles(p Pageable) ([]models.Article, int, error)
60+
61+
// FindArticlesByTag returns articles, count given pageable and tag name
62+
FindArticlesByTag(tag string, p Pageable) ([]models.Article, int, error)
63+
64+
// FindArticlesByAuthor returns articles, count given pageable and author name
65+
FindArticlesByAuthor(username string, p Pageable) ([]models.Article, int, error)
66+
67+
// FindArticlesByFavoritedUsername returns articles, count given pageable and who favorited by username
68+
FindArticlesByFavoritedUsername(username string, p Pageable) ([]models.Article, int, error)
69+
70+
// =================================
71+
// Article favorites
72+
// =================================
73+
74+
// UpdateFavorite update favorite by given user and article
75+
UpdateFavorite(articleFavorite *models.ArticleFavorite) error
76+
77+
// =================================
78+
// Article comments
79+
// =================================
80+
5081
}

repository/repository_article.go

Lines changed: 88 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ func NewArticleRepository(db *gorm.DB) *articleRepository {
1616
}
1717
}
1818

19+
func (a *articleRepository) SaveOne(data interface{}) error {
20+
return a.db.Save(data).Error
21+
}
22+
1923
func (a *articleRepository) SaveArticle(article *models.Article) error {
2024
tx := a.db.Begin()
2125

@@ -44,6 +48,88 @@ func (a *articleRepository) SaveArticle(article *models.Article) error {
4448
return tx.Commit().Error
4549
}
4650

47-
func (a *articleRepository) SaveOne(data interface{}) error {
48-
return a.db.Save(data).Error
51+
func (a *articleRepository) FindArticleBySlug(slug string) (*models.Article, error) {
52+
var m models.Article
53+
err := a.db.Where(&models.Article{Slug: slug}).Preload("Favorites").Preload("Tags").Preload("Author").Find(&m).Error
54+
if err != nil {
55+
if gorm.IsRecordNotFoundError(err) {
56+
return nil, nil
57+
}
58+
return nil, err
59+
}
60+
return &m, err
61+
}
62+
63+
func (a *articleRepository) FindArticles(p Pageable) ([]models.Article, int, error) {
64+
var (
65+
articles []models.Article
66+
count int
67+
)
68+
a.db.Model(&articles).Count(&count)
69+
err := a.db.Preload("Favorites").Preload("Tags").Preload("Author").Offset(p.Offset).Limit(p.Limit).Order("created_at desc").Find(&articles).Error
70+
if err != nil {
71+
if gorm.IsRecordNotFoundError(err) {
72+
return nil, 0, nil
73+
}
74+
return nil, 0, err
75+
}
76+
return articles, count, nil
77+
}
78+
79+
func (a *articleRepository) FindArticlesByTag(tag string, p Pageable) ([]models.Article, int, error) {
80+
var (
81+
t models.Tag
82+
articles []models.Article
83+
count int
84+
)
85+
err := a.db.Where(&models.Tag{Name: tag}).First(&t).Error
86+
if err != nil {
87+
if gorm.IsRecordNotFoundError(err) {
88+
return nil, 0, nil
89+
}
90+
return nil, 0, err
91+
}
92+
a.db.Model(&t).Preload("Favorites").Preload("Tags").Preload("Author").Offset(p.Offset).Limit(p.Limit).Order("created_at desc").Association("Articles").Find(&articles)
93+
count = a.db.Model(&t).Association("Articles").Count()
94+
return articles, count, nil
95+
}
96+
97+
func (a *articleRepository) FindArticlesByAuthor(username string, p Pageable) ([]models.Article, int, error) {
98+
var (
99+
u models.User
100+
articles []models.Article
101+
count int
102+
)
103+
err := a.db.Where(&models.User{Username: username}).First(&u).Error
104+
if err != nil {
105+
if gorm.IsRecordNotFoundError(err) {
106+
return nil, 0, nil
107+
}
108+
return nil, 0, err
109+
}
110+
a.db.Where(&models.Article{AuthorID: u.ID}).Preload("Favorites").Preload("Tags").Preload("Author").Offset(p.Offset).Limit(p.Limit).Order("created_at desc").Find(&articles)
111+
a.db.Where(&models.Article{AuthorID: u.ID}).Model(&models.Article{}).Count(&count)
112+
return articles, count, nil
113+
}
114+
115+
func (a *articleRepository) FindArticlesByFavoritedUsername(username string, p Pageable) ([]models.Article, int, error) {
116+
var (
117+
u models.User
118+
articles []models.Article
119+
count int
120+
)
121+
err := a.db.Where(&models.User{Username: username}).First(&u).Error
122+
if err != nil {
123+
if gorm.IsRecordNotFoundError(err) {
124+
return nil, 0, nil
125+
}
126+
return nil, 0, err
127+
}
128+
a.db.Model(&u).Preload("Favorites", "user_id", u.ID).Preload("Tags").Preload("Author").Offset(p.Offset).Limit(p.Limit).Order("created_at desc").Find(&articles)
129+
a.db.Where(&models.ArticleFavorite{UserID: u.ID}).Model(&models.ArticleFavorite{}).Count(&count)
130+
return articles, count, nil
131+
}
132+
133+
func (a *articleRepository) UpdateFavorite(articleFavorite *models.ArticleFavorite) error {
134+
return a.db.Create(articleFavorite).Error
49135
}

repository/repository_user.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ func (u *userRepository) IsFollowing(user *models.User, follower *models.User) (
9797
return true, nil
9898
}
9999

100+
// TODO : refactor to use models
100101
func (u *userRepository) FindFollowers(user *models.User) ([]*models.User, error) {
101102
var followers []*models.User
102103
err := u.db.Table("users").
@@ -111,6 +112,7 @@ func (u *userRepository) FindFollowers(user *models.User) ([]*models.User, error
111112
return followers, nil
112113
}
113114

115+
// TODO : refactor to use models
114116
func (u *userRepository) FindFollowing(user *models.User) ([]*models.User, error) {
115117
var following []*models.User
116118
err := u.db.Table("users").

0 commit comments

Comments
 (0)