Use unix timestamps for post.Store
This commit is contained in:
parent
f7d72adfb5
commit
c99b37c5b3
@ -6,10 +6,10 @@ import (
|
||||
"fmt"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
_ "github.com/mattn/go-sqlite3" // we need dis
|
||||
migrate "github.com/rubenv/sql-migrate"
|
||||
"github.com/tilinna/clock"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -23,8 +23,8 @@ var (
|
||||
type StoredPost struct {
|
||||
Post
|
||||
|
||||
PublishedAt Date
|
||||
LastUpdatedAt Date
|
||||
PublishedAt time.Time
|
||||
LastUpdatedAt time.Time
|
||||
}
|
||||
|
||||
// URL returns the relative URL of the StoredPost.
|
||||
@ -32,9 +32,9 @@ func (p StoredPost) URL() string {
|
||||
return path.Join(
|
||||
fmt.Sprintf(
|
||||
"%d/%0d/%0d",
|
||||
p.PublishedAt.Year,
|
||||
p.PublishedAt.Month,
|
||||
p.PublishedAt.Day,
|
||||
p.PublishedAt.Year(),
|
||||
p.PublishedAt.Month(),
|
||||
p.PublishedAt.Day(),
|
||||
),
|
||||
p.ID+".html",
|
||||
)
|
||||
@ -45,7 +45,7 @@ type Store interface {
|
||||
|
||||
// Set sets the Post data into the storage, keyed by the Post's ID. It
|
||||
// overwrites a previous Post with the same ID, if there was one.
|
||||
Set(Post) error
|
||||
Set(post Post, now time.Time) error
|
||||
|
||||
// Get returns count StoredPosts, sorted time descending, offset by the given page
|
||||
// number. The returned boolean indicates if there are more pages or not.
|
||||
@ -102,8 +102,6 @@ type StoreParams struct {
|
||||
|
||||
// Path to the file the database will be stored at.
|
||||
DBFilePath string
|
||||
|
||||
Clock clock.Clock
|
||||
}
|
||||
|
||||
type store struct {
|
||||
@ -136,7 +134,7 @@ func (s *store) Close() error {
|
||||
return s.db.Close()
|
||||
}
|
||||
|
||||
// if the callback returns an error then the transaction is aborted
|
||||
// if the callback returns an error then the transaction is aborted.
|
||||
func (s *store) withTx(cb func(*sql.Tx) error) error {
|
||||
|
||||
tx, err := s.db.Begin()
|
||||
@ -164,9 +162,12 @@ func (s *store) withTx(cb func(*sql.Tx) error) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *store) Set(post Post) error {
|
||||
func (s *store) Set(post Post, now time.Time) error {
|
||||
return s.withTx(func(tx *sql.Tx) error {
|
||||
currentDate := DateFromTime(s.params.Clock.Now())
|
||||
|
||||
nowTS := now.Unix()
|
||||
|
||||
nowSql := sql.NullInt64{Int64: nowTS, Valid: !now.IsZero()}
|
||||
|
||||
_, err := tx.Exec(
|
||||
`INSERT INTO posts (
|
||||
@ -184,9 +185,9 @@ func (s *store) Set(post Post) error {
|
||||
post.Title,
|
||||
post.Description,
|
||||
&sql.NullString{String: post.Series, Valid: post.Series != ""},
|
||||
currentDate,
|
||||
nowSql,
|
||||
post.Body,
|
||||
currentDate,
|
||||
nowSql,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
@ -257,13 +258,14 @@ func (s *store) get(
|
||||
for rows.Next() {
|
||||
|
||||
var (
|
||||
post StoredPost
|
||||
series, tag sql.NullString
|
||||
post StoredPost
|
||||
series, tag sql.NullString
|
||||
publishedAt, lastUpdatedAt sql.NullInt64
|
||||
)
|
||||
|
||||
err := rows.Scan(
|
||||
&post.ID, &post.Title, &post.Description, &series, &tag,
|
||||
&post.PublishedAt, &post.LastUpdatedAt,
|
||||
&publishedAt, &lastUpdatedAt,
|
||||
&post.Body,
|
||||
)
|
||||
|
||||
@ -283,6 +285,14 @@ func (s *store) get(
|
||||
|
||||
post.Series = series.String
|
||||
|
||||
if publishedAt.Valid {
|
||||
post.PublishedAt = time.Unix(publishedAt.Int64, 0).UTC()
|
||||
}
|
||||
|
||||
if lastUpdatedAt.Valid {
|
||||
post.LastUpdatedAt = time.Unix(lastUpdatedAt.Int64, 0).UTC()
|
||||
}
|
||||
|
||||
posts = append(posts, post)
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,7 @@ type storeTestHarness struct {
|
||||
|
||||
func newStoreTestHarness(t *testing.T) storeTestHarness {
|
||||
|
||||
clock := clock.NewMock(time.Now().Truncate(1 * time.Hour))
|
||||
clock := clock.NewMock(time.Now().UTC().Truncate(1 * time.Hour))
|
||||
|
||||
tmpFile, err := ioutil.TempFile(os.TempDir(), "mediocre-blog-post-store-test-")
|
||||
if err != nil {
|
||||
@ -48,7 +48,6 @@ func newStoreTestHarness(t *testing.T) storeTestHarness {
|
||||
|
||||
store, err := NewStore(StoreParams{
|
||||
DBFilePath: tmpFilePath,
|
||||
Clock: clock,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
|
||||
@ -66,7 +65,7 @@ func (h *storeTestHarness) testStoredPost(i int) StoredPost {
|
||||
post := testPost(i)
|
||||
return StoredPost{
|
||||
Post: post,
|
||||
PublishedAt: DateFromTime(h.clock.Now()),
|
||||
PublishedAt: h.clock.Now(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -101,41 +100,41 @@ func TestStore(t *testing.T) {
|
||||
t.Run("set_get_delete", func(t *testing.T) {
|
||||
h := newStoreTestHarness(t)
|
||||
|
||||
nowDate := DateFromTime(h.clock.Now())
|
||||
now := h.clock.Now().UTC()
|
||||
|
||||
post := testPost(0)
|
||||
post.Tags = []string{"foo", "bar"}
|
||||
|
||||
assert.NoError(t, h.store.Set(post))
|
||||
assert.NoError(t, h.store.Set(post, now))
|
||||
|
||||
gotPost, err := h.store.GetByID(post.ID)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assertPostEqual(t, StoredPost{
|
||||
Post: post,
|
||||
PublishedAt: nowDate,
|
||||
PublishedAt: now,
|
||||
}, gotPost)
|
||||
|
||||
// we will now try updating the post on a different day, and ensure it
|
||||
// updates properly
|
||||
|
||||
h.clock.Add(24 * time.Hour)
|
||||
newNowDate := DateFromTime(h.clock.Now())
|
||||
newNow := h.clock.Now().UTC()
|
||||
|
||||
post.Title = "something else"
|
||||
post.Series = "whatever"
|
||||
post.Body = "anything"
|
||||
post.Tags = []string{"bar", "baz"}
|
||||
|
||||
assert.NoError(t, h.store.Set(post))
|
||||
assert.NoError(t, h.store.Set(post, newNow))
|
||||
|
||||
gotPost, err = h.store.GetByID(post.ID)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assertPostEqual(t, StoredPost{
|
||||
Post: post,
|
||||
PublishedAt: nowDate,
|
||||
LastUpdatedAt: newNowDate,
|
||||
PublishedAt: now,
|
||||
LastUpdatedAt: newNow,
|
||||
}, gotPost)
|
||||
|
||||
// delete the post, it should go away
|
||||
@ -148,6 +147,8 @@ func TestStore(t *testing.T) {
|
||||
t.Run("get", func(t *testing.T) {
|
||||
h := newStoreTestHarness(t)
|
||||
|
||||
now := h.clock.Now().UTC()
|
||||
|
||||
posts := []StoredPost{
|
||||
h.testStoredPost(0),
|
||||
h.testStoredPost(1),
|
||||
@ -156,7 +157,7 @@ func TestStore(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, post := range posts {
|
||||
assert.NoError(t, h.store.Set(post.Post))
|
||||
assert.NoError(t, h.store.Set(post.Post, now))
|
||||
}
|
||||
|
||||
gotPosts, hasMore, err := h.store.Get(0, 2)
|
||||
@ -170,7 +171,7 @@ func TestStore(t *testing.T) {
|
||||
assertPostsEqual(t, posts[2:4], gotPosts)
|
||||
|
||||
posts = append(posts, h.testStoredPost(4))
|
||||
assert.NoError(t, h.store.Set(posts[4].Post))
|
||||
assert.NoError(t, h.store.Set(posts[4].Post, now))
|
||||
|
||||
gotPosts, hasMore, err = h.store.Get(1, 2)
|
||||
assert.NoError(t, err)
|
||||
@ -186,6 +187,8 @@ func TestStore(t *testing.T) {
|
||||
t.Run("get_by_series", func(t *testing.T) {
|
||||
h := newStoreTestHarness(t)
|
||||
|
||||
now := h.clock.Now().UTC()
|
||||
|
||||
posts := []StoredPost{
|
||||
h.testStoredPost(0),
|
||||
h.testStoredPost(1),
|
||||
@ -198,7 +201,7 @@ func TestStore(t *testing.T) {
|
||||
posts[2].Series = "bar"
|
||||
|
||||
for _, post := range posts {
|
||||
assert.NoError(t, h.store.Set(post.Post))
|
||||
assert.NoError(t, h.store.Set(post.Post, now))
|
||||
}
|
||||
|
||||
fooPosts, err := h.store.GetBySeries("foo")
|
||||
@ -218,6 +221,8 @@ func TestStore(t *testing.T) {
|
||||
|
||||
h := newStoreTestHarness(t)
|
||||
|
||||
now := h.clock.Now().UTC()
|
||||
|
||||
posts := []StoredPost{
|
||||
h.testStoredPost(0),
|
||||
h.testStoredPost(1),
|
||||
@ -230,7 +235,7 @@ func TestStore(t *testing.T) {
|
||||
posts[2].Tags = []string{"bar"}
|
||||
|
||||
for _, post := range posts {
|
||||
assert.NoError(t, h.store.Set(post.Post))
|
||||
assert.NoError(t, h.store.Set(post.Post, now))
|
||||
}
|
||||
|
||||
fooPosts, err := h.store.GetByTag("foo")
|
||||
|
Loading…
Reference in New Issue
Block a user