summaryrefslogtreecommitdiff
path: root/srv/src
diff options
context:
space:
mode:
Diffstat (limited to 'srv/src')
-rw-r--r--srv/src/api/render.go17
-rw-r--r--srv/src/api/tpl/index.html8
-rw-r--r--srv/src/post/post.go26
-rw-r--r--srv/src/post/post_test.go41
4 files changed, 83 insertions, 9 deletions
diff --git a/srv/src/api/render.go b/srv/src/api/render.go
index b2ca3c8..6359505 100644
--- a/srv/src/api/render.go
+++ b/srv/src/api/render.go
@@ -59,7 +59,7 @@ func (a *api) renderIndexHandler() http.Handler {
return
}
- posts, _, err := a.params.PostStore.Get(page, pageCount)
+ posts, hasMore, err := a.params.PostStore.WithOrderDesc().Get(page, pageCount)
if err != nil {
apiutil.InternalServerError(
rw, r, fmt.Errorf("fetching page %d of posts: %w", page, err),
@@ -68,9 +68,20 @@ func (a *api) renderIndexHandler() http.Handler {
}
tplData := struct {
- Posts []post.StoredPost
+ Posts []post.StoredPost
+ PrevPage, NextPage int
}{
- Posts: posts,
+ Posts: posts,
+ PrevPage: -1,
+ NextPage: -1,
+ }
+
+ if page > 0 {
+ tplData.PrevPage = page - 1
+ }
+
+ if hasMore {
+ tplData.NextPage = page + 1
}
if err := tpl.Execute(rw, tplData); err != nil {
diff --git a/srv/src/api/tpl/index.html b/srv/src/api/tpl/index.html
index 240df92..b71dc01 100644
--- a/srv/src/api/tpl/index.html
+++ b/srv/src/api/tpl/index.html
@@ -17,4 +17,12 @@
</ul>
{{ end }}
+{{ if ge .PrevPage 0 }}
+<a href="?p={{ .PrevPage}}">Previous</a>
+{{ end }}
+
+{{ if ge .NextPage 0 }}
+<a href="?p={{ .NextPage}}">Next</a>
+{{ end }}
+
{{ template "base.html" . }}
diff --git a/srv/src/post/post.go b/srv/src/post/post.go
index 30ded15..cadfcfc 100644
--- a/srv/src/post/post.go
+++ b/srv/src/post/post.go
@@ -74,21 +74,33 @@ type Store interface {
// ascending, or empty slice.
GetByTag(tag string) ([]StoredPost, error)
+ // WithOrderDesc will return a Store whose Get operations return Posts in
+ // time descending order, rather than ascending.
+ WithOrderDesc() Store
+
// Delete will delete the StoredPost with the given ID.
Delete(id string) error
}
type store struct {
- db *sql.DB
+ db *sql.DB
+ order string
}
// NewStore initializes a new Store using an existing SQLDB.
func NewStore(db *SQLDB) Store {
return &store{
- db: db.db,
+ db: db.db,
+ order: "ASC",
}
}
+func (s *store) WithOrderDesc() Store {
+ s2 := *s
+ s2.order = "DESC"
+ return &s2
+}
+
// if the callback returns an error then the transaction is aborted.
func (s *store) withTx(cb func(*sql.Tx) error) error {
@@ -185,15 +197,17 @@ func (s *store) get(
[]StoredPost, error,
) {
- query := `
- SELECT
+ query := fmt.Sprintf(
+ `SELECT
p.id, p.title, p.description, p.series, pt.tag,
p.published_at, p.last_updated_at,
p.body
FROM posts p
LEFT JOIN post_tags pt ON (p.id = pt.post_id)
- ` + where + `
- ORDER BY p.published_at ASC, p.title ASC`
+ `+where+`
+ ORDER BY p.published_at %s, p.title %s`,
+ s.order, s.order,
+ )
if limit > 0 {
query += fmt.Sprintf(" LIMIT %d", limit)
diff --git a/srv/src/post/post_test.go b/srv/src/post/post_test.go
index 55a29ea..c5587c8 100644
--- a/srv/src/post/post_test.go
+++ b/srv/src/post/post_test.go
@@ -187,6 +187,47 @@ func TestStore(t *testing.T) {
assertPostsEqual(t, posts[4:], gotPosts)
})
+ t.Run("get_desc", func(t *testing.T) {
+ h := newStoreTestHarness(t)
+ h.store = h.store.WithOrderDesc()
+
+ now := h.clock.Now().UTC()
+
+ posts := []StoredPost{
+ h.testStoredPost(3),
+ h.testStoredPost(2),
+ h.testStoredPost(1),
+ h.testStoredPost(0),
+ }
+
+ for _, post := range posts {
+ assert.NoError(t, h.store.Set(post.Post, now))
+ }
+
+ gotPosts, hasMore, err := h.store.Get(0, 2)
+ assert.NoError(t, err)
+ assert.True(t, hasMore)
+ assertPostsEqual(t, posts[:2], gotPosts)
+
+ gotPosts, hasMore, err = h.store.Get(1, 2)
+ assert.NoError(t, err)
+ assert.False(t, hasMore)
+ assertPostsEqual(t, posts[2:4], gotPosts)
+
+ posts = append([]StoredPost{h.testStoredPost(4)}, posts...)
+ assert.NoError(t, h.store.Set(posts[0].Post, now))
+
+ gotPosts, hasMore, err = h.store.Get(1, 2)
+ assert.NoError(t, err)
+ assert.True(t, hasMore)
+ assertPostsEqual(t, posts[2:4], gotPosts)
+
+ gotPosts, hasMore, err = h.store.Get(2, 2)
+ assert.NoError(t, err)
+ assert.False(t, hasMore)
+ assertPostsEqual(t, posts[4:], gotPosts)
+ })
+
t.Run("get_by_series", func(t *testing.T) {
h := newStoreTestHarness(t)