diff --git a/cmd/nonshy/main.go b/cmd/nonshy/main.go
index 3530e2c..b0a874d 100644
--- a/cmd/nonshy/main.go
+++ b/cmd/nonshy/main.go
@@ -261,6 +261,21 @@ func main() {
return err
}
+ return nil
+ },
+ },
+ {
+ Name: "photo-counts",
+ Usage: "repopulate cached Likes and Comment counts on photos",
+ Action: func(c *cli.Context) error {
+ initdb(c)
+
+ log.Info("Running BackfillPhotoCounts()")
+ err := backfill.BackfillPhotoCounts()
+ if err != nil {
+ return err
+ }
+
return nil
},
},
diff --git a/pkg/controller/api/likes.go b/pkg/controller/api/likes.go
index dc97c1b..2748225 100644
--- a/pkg/controller/api/likes.go
+++ b/pkg/controller/api/likes.go
@@ -204,6 +204,13 @@ func Likes() http.HandlerFunc {
}
}
+ // Refresh cached like counts.
+ if req.TableName == "photos" {
+ if err := models.UpdatePhotoCachedCounts(tableID); err != nil {
+ log.Error("UpdatePhotoCachedCount(%d): %s", tableID, err)
+ }
+ }
+
// Send success response.
SendJSON(w, http.StatusOK, Response{
OK: true,
diff --git a/pkg/controller/comment/post_comment.go b/pkg/controller/comment/post_comment.go
index 537c293..2d0f6b4 100644
--- a/pkg/controller/comment/post_comment.go
+++ b/pkg/controller/comment/post_comment.go
@@ -121,6 +121,14 @@ func PostComment() http.HandlerFunc {
// Log the change.
models.LogDeleted(&models.User{ID: comment.UserID}, currentUser, "comments", comment.ID, "Deleted a comment.", comment)
}
+
+ // Refresh cached like counts.
+ if tableName == "photos" {
+ if err := models.UpdatePhotoCachedCounts(tableID); err != nil {
+ log.Error("UpdatePhotoCachedCount(%d): %s", tableID, err)
+ }
+ }
+
templates.Redirect(w, fromURL)
return
}
@@ -174,6 +182,13 @@ func PostComment() http.HandlerFunc {
session.Flash(w, r, "Comment added!")
templates.Redirect(w, fromURL)
+ // Refresh cached comment counts.
+ if tableName == "photos" {
+ if err := models.UpdatePhotoCachedCounts(tableID); err != nil {
+ log.Error("UpdatePhotoCachedCount(%d): %s", tableID, err)
+ }
+ }
+
// Log the change.
models.LogCreated(currentUser, "comments", comment.ID, "Posted a new comment.\n\n---\n\n"+message)
diff --git a/pkg/controller/photo/site_gallery.go b/pkg/controller/photo/site_gallery.go
index a387afc..741ceeb 100644
--- a/pkg/controller/photo/site_gallery.go
+++ b/pkg/controller/photo/site_gallery.go
@@ -18,10 +18,8 @@ func SiteGallery() http.HandlerFunc {
var sortWhitelist = []string{
"created_at desc",
"created_at asc",
-
- // Custom (advanced) sort options.
- "by_likes",
- "by_comments",
+ "like_count desc",
+ "comment_count desc",
}
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
diff --git a/pkg/controller/photo/user_gallery.go b/pkg/controller/photo/user_gallery.go
index b73786e..47004f0 100644
--- a/pkg/controller/photo/user_gallery.go
+++ b/pkg/controller/photo/user_gallery.go
@@ -19,10 +19,8 @@ func UserPhotos() http.HandlerFunc {
"pinned desc nulls last, updated_at desc",
"created_at desc",
"created_at asc",
-
- // Custom (advanced) sort options.
- "by_likes",
- "by_comments",
+ "like_count desc",
+ "comment_count desc",
}
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
diff --git a/pkg/models/backfill/backfill_photo_counts.go b/pkg/models/backfill/backfill_photo_counts.go
new file mode 100644
index 0000000..50b726e
--- /dev/null
+++ b/pkg/models/backfill/backfill_photo_counts.go
@@ -0,0 +1,25 @@
+package backfill
+
+import (
+ "code.nonshy.com/nonshy/website/pkg/models"
+)
+
+// BackfillPhotoCounts recomputes the cached Likes and Comment counts on photos.
+func BackfillPhotoCounts() error {
+ res := models.DB.Exec(`
+ UPDATE photos
+ SET like_count = (
+ SELECT count(id)
+ FROM likes
+ WHERE table_name='photos'
+ AND table_id=photos.id
+ ),
+ comment_count = (
+ SELECT count(id)
+ FROM comments
+ WHERE table_name='photos'
+ AND table_id=photos.id
+ );
+ `)
+ return res.Error
+}
diff --git a/pkg/models/photo.go b/pkg/models/photo.go
index 3fbeeb9..bc47358 100644
--- a/pkg/models/photo.go
+++ b/pkg/models/photo.go
@@ -25,6 +25,8 @@ type Photo struct {
Gallery bool `gorm:"index"` // photo appears in the public gallery (if public)
Explicit bool `gorm:"index"` // is an explicit photo
Pinned bool `gorm:"index"` // user pins it to the front of their gallery
+ LikeCount int64 `gorm:"index"` // cache of 'likes' count
+ CommentCount int64 `gorm:"index"` // cache of comments count
CreatedAt time.Time `gorm:"index"`
UpdatedAt time.Time
}
@@ -135,24 +137,6 @@ func PaginateUserPhotos(userID uint64, conf UserGallery, pager *Pagination) ([]*
placeholders = append(placeholders, explicit[0])
}
- // Custom SORT parameters.
- switch pager.Sort {
- case "by_likes":
- pager.Sort = `(
- SELECT count(likes.id)
- FROM likes
- WHERE likes.table_name = 'photos'
- AND likes.table_id = photos.id
- ) DESC`
- case "by_comments":
- pager.Sort = `(
- SELECT count(comments.id)
- FROM comments
- WHERE comments.table_name = 'photos'
- AND comments.table_id = photos.id
- ) DESC NULLS LAST`
- }
-
query := DB.Where(
strings.Join(wheres, " AND "),
placeholders...,
@@ -690,38 +674,33 @@ func PaginateGalleryPhotos(user *User, conf Gallery, pager *Pagination) ([]*Phot
)
}
- // Get count pre-sorting.
- query.Model(&Photo{}).Count(&pager.Total)
-
- // Custom SORT parameters.
- switch pager.Sort {
- case "by_likes":
- query = query.Select(`
- photos.*,
- COUNT(likes.id) AS like_count
- `).Joins(
- "LEFT OUTER JOIN likes ON (likes.table_name='photos' AND likes.table_id=photos.id)",
- ).Where(
- "likes.table_name = 'photos' AND likes.table_id = photos.id",
- ).Group("photos.id")
- pager.Sort = `like_count DESC`
- case "by_comments":
- query = query.Select(`
- photos.*,
- COUNT(comments.id) AS comment_count
- `).Joins(
- "LEFT OUTER JOIN comments ON (comments.table_name='photos' AND comments.table_id=photos.id)",
- ).Where(
- "comments.table_name = 'photos' AND comments.table_id = photos.id",
- ).Group("photos.id")
- pager.Sort = `comment_count DESC`
- }
-
query = query.Order(pager.Sort)
+ query.Model(&Photo{}).Count(&pager.Total)
result := query.Offset(pager.GetOffset()).Limit(pager.PerPage).Find(&p)
return p, result.Error
}
+// UpdatePhotoCachedCounts will refresh the cached like/comment count on the photos table.
+func UpdatePhotoCachedCounts(photoID uint64) error {
+ res := DB.Exec(`
+ UPDATE photos
+ SET like_count = (
+ SELECT count(id)
+ FROM likes
+ WHERE table_name='photos'
+ AND table_id=photos.id
+ ),
+ comment_count = (
+ SELECT count(id)
+ FROM comments
+ WHERE table_name='photos'
+ AND table_id=photos.id
+ )
+ WHERE photos.id = ?;
+ `, photoID)
+ return res.Error
+}
+
// Save photo.
func (p *Photo) Save() error {
result := DB.Save(p)
diff --git a/web/templates/photo/gallery.html b/web/templates/photo/gallery.html
index 708eb73..105599c 100644
--- a/web/templates/photo/gallery.html
+++ b/web/templates/photo/gallery.html
@@ -414,8 +414,8 @@
{{end}}
-
-
+
+