Skip to content

Commit

Permalink
Handle different types of timestamp representations
Browse files Browse the repository at this point in the history
  • Loading branch information
ilmari-h committed Nov 12, 2024
1 parent acba0fa commit f4f9b08
Show file tree
Hide file tree
Showing 7 changed files with 155 additions and 16 deletions.
1 change: 1 addition & 0 deletions .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ jobs:
TAPESTRY_API_KEY: ${{ secrets.TAPESTRY_API_KEY }}
TAPESTRY_API_BASE_URL: ${{ secrets.TAPESTRY_API_BASE_URL }}
run: |
go test
cd tests
go test --run TestProfileOperations
go test --run TestContentOperations
Expand Down
8 changes: 4 additions & 4 deletions comments.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,10 @@ type CommentData struct {
}

type Comment struct {
Namespace string `json:"namespace"`
CreatedAt int64 `json:"created_at"`
Text string `json:"text"`
ID string `json:"id"`
Namespace string `json:"namespace"`
CreatedAt UnixTimestamp `json:"created_at"`
Text string `json:"text"`
ID string `json:"id"`
}

type Author struct {
Expand Down
57 changes: 57 additions & 0 deletions comments_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package tapestry

import (
"encoding/json"
"testing"
)

func TestComment_UnmarshalJSON(t *testing.T) {
tests := []struct {
name string
input string
want Comment
wantErr bool
}{
{
name: "regular integer timestamp",
input: `{"namespace":"test","created_at":1234567890,"text":"hello","id":"123"}`,
want: Comment{
Namespace: "test",
CreatedAt: 1234567890,
Text: "hello",
ID: "123",
},
},
{
name: "low/high timestamp",
input: `{"namespace":"test","created_at":{"low":-188638304,"high":402},"text":"hello","id":"456"}`,
want: Comment{
Namespace: "test",
CreatedAt: 1730683181984,
Text: "hello",
ID: "456",
},
},
{
name: "invalid timestamp format",
input: `{"namespace":"test","created_at":"invalid","text":"hello","id":"789"}`,
wantErr: true,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var got Comment
err := json.Unmarshal([]byte(tt.input), &got)

if (err != nil) != tt.wantErr {
t.Errorf("UnmarshalJSON() error = %v, wantErr %v", err, tt.wantErr)
return
}

if !tt.wantErr && got != tt.want {
t.Errorf("UnmarshalJSON() = %+v, want %+v", got, tt.want)
}
})
}
}
18 changes: 10 additions & 8 deletions contents.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,11 @@ type UpdateContentRequest struct {
}

type Content struct {
Namespace string `json:"namespace"`
ID string `json:"id"`
Description string `json:"description"`
Title string `json:"title"`
Namespace string `json:"namespace"`
ID string `json:"id"`
Description string `json:"description"`
Title string `json:"title"`
CreatedAt UnixTimestamp `json:"created_at"`
}

type CreateOrUpdateContentResponse struct{ Content }
Expand All @@ -36,10 +37,11 @@ type GetContentResponse struct {
}

type AuthorProfile struct {
ID string `json:"id"`
Username string `json:"username"`
Bio string `json:"bio"`
Image string `json:"image"`
ID string `json:"id"`
Username string `json:"username"`
Bio string `json:"bio"`
Image string `json:"image"`
CreatedAt UnixTimestamp `json:"created_at"`
}

type RequestingProfileSocialInfo struct {
Expand Down
9 changes: 5 additions & 4 deletions profiles.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,11 @@ type GetFollowingResponse struct {
}

type ProfileDetails struct {
ID string `json:"id"`
Username string `json:"username"`
Bio string `json:"bio,omitempty"`
Image string `json:"image,omitempty"`
ID string `json:"id"`
Username string `json:"username"`
Bio string `json:"bio,omitempty"`
Image string `json:"image,omitempty"`
CreatedAt UnixTimestamp `json:"created_at"`
}

type GetFollowingWhoFollowResponse struct {
Expand Down
31 changes: 31 additions & 0 deletions timestamp.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package tapestry

import (
"encoding/json"
"fmt"
)

// UnixTimestamp represents a unix timestamp that can be unmarshaled from either
// an integer or a 64 bit integer representation in object format
type UnixTimestamp int64

func (t *UnixTimestamp) UnmarshalJSON(data []byte) error {
// Try regular int64 first
var timestamp int64
if err := json.Unmarshal(data, &timestamp); err == nil {
*t = UnixTimestamp(timestamp)
return nil
}

// Try 64 bit integer representation
var tsObj struct {
Low int64 `json:"low"`
High int64 `json:"high"`
}
if err := json.Unmarshal(data, &tsObj); err != nil {
return fmt.Errorf("failed to unmarshal timestamp: %w", err)
}

*t = UnixTimestamp((tsObj.High << 32) | (tsObj.Low & 0xFFFFFFFF))
return nil
}
47 changes: 47 additions & 0 deletions timestamp_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package tapestry

import (
"encoding/json"
"testing"
)

func TestUnixTimestamp_UnmarshalJSON(t *testing.T) {
tests := []struct {
name string
input string
want UnixTimestamp
wantErr bool
}{
{
name: "regular integer timestamp",
input: "1234567890",
want: UnixTimestamp(1234567890),
},
{
name: "low/high timestamp",
input: `{"low":-188638304,"high":402}`,
want: UnixTimestamp(1730683181984),
},
{
name: "invalid format",
input: `"invalid"`,
wantErr: true,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var got UnixTimestamp
err := json.Unmarshal([]byte(tt.input), &got)

if (err != nil) != tt.wantErr {
t.Errorf("UnmarshalJSON() error = %v, wantErr %v", err, tt.wantErr)
return
}

if !tt.wantErr && got != tt.want {
t.Errorf("UnmarshalJSON() = %v, want %v", got, tt.want)
}
})
}
}

0 comments on commit f4f9b08

Please sign in to comment.