diff --git a/srv/src/post/store.go b/srv/src/post/store.go index 2898315..3f044e2 100644 --- a/srv/src/post/store.go +++ b/srv/src/post/store.go @@ -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) } diff --git a/srv/src/post/store_test.go b/srv/src/post/store_test.go index 1890511..9b0ee45 100644 --- a/srv/src/post/store_test.go +++ b/srv/src/post/store_test.go @@ -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")