Skip to content

Commit

Permalink
Parse "null" time on go prior 1.8
Browse files Browse the repository at this point in the history
  • Loading branch information
mxpv committed Aug 21, 2017
1 parent f0b6229 commit a990f6e
Show file tree
Hide file tree
Showing 9 changed files with 146 additions and 90 deletions.
48 changes: 23 additions & 25 deletions campaign.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package patreon

import "time"

// CampaignDefaultRelations specifies default includes for Campaign.
const CampaignDefaultRelations = "rewards,creator,goals"

Expand All @@ -11,29 +9,29 @@ type Campaign struct {
Type string `json:"type"`
Id string `json:"id"`
Attributes struct {
Summary string `json:"summary"`
CreationName string `json:"creation_name"`
DisplayPatronGoals bool `json:"display_patron_goals"`
PayPerName string `json:"pay_per_name"`
OneLiner string `json:"one_liner"`
MainVideoEmbed string `json:"main_video_embed"`
MainVideoURL string `json:"main_video_url"`
ImageSmallURL string `json:"image_small_url"`
ImageURL string `json:"image_url"`
ThanksVideoURL string `json:"thanks_video_url"`
ThanksEmbed string `json:"thanks_embed"`
ThanksMsg string `json:"thanks_msg"`
IsChargedImmediately bool `json:"is_charged_immediately"`
IsMonthly bool `json:"is_monthly"`
IsNsfw bool `json:"is_nsfw"`
IsPlural bool `json:"is_plural"`
CreatedAt time.Time `json:"created_at"`
PublishedAt time.Time `json:"published_at"`
PledgeURL string `json:"pledge_url"`
PledgeSum int `json:"pledge_sum"`
PatronCount int `json:"patron_count"`
CreationCount int `json:"creation_count"`
OutstandingPaymentAmountCents int `json:"outstanding_payment_amount_cents"`
Summary string `json:"summary"`
CreationName string `json:"creation_name"`
DisplayPatronGoals bool `json:"display_patron_goals"`
PayPerName string `json:"pay_per_name"`
OneLiner string `json:"one_liner"`
MainVideoEmbed string `json:"main_video_embed"`
MainVideoURL string `json:"main_video_url"`
ImageSmallURL string `json:"image_small_url"`
ImageURL string `json:"image_url"`
ThanksVideoURL string `json:"thanks_video_url"`
ThanksEmbed string `json:"thanks_embed"`
ThanksMsg string `json:"thanks_msg"`
IsChargedImmediately bool `json:"is_charged_immediately"`
IsMonthly bool `json:"is_monthly"`
IsNsfw bool `json:"is_nsfw"`
IsPlural bool `json:"is_plural"`
CreatedAt NullTime `json:"created_at"`
PublishedAt NullTime `json:"published_at"`
PledgeURL string `json:"pledge_url"`
PledgeSum int `json:"pledge_sum"`
PatronCount int `json:"patron_count"`
CreationCount int `json:"creation_count"`
OutstandingPaymentAmountCents int `json:"outstanding_payment_amount_cents"`
} `json:"attributes"`
Relationships struct {
Categories *CategoriesRelationship `json:"categories,omitempty"`
Expand Down
18 changes: 8 additions & 10 deletions card.go
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
package patreon

import "time"

// Card represents Patreon's credit card or paypal account.
type Card struct {
Type string `json:"type"`
Id string `json:"id"`
Attributes struct {
// PayPal
CardType string `json:"card_type"`
CreatedAt time.Time `json:"created_at"`
ExpirationDate time.Time `json:"expiration_date"`
HasFailedPayment bool `json:"has_a_failed_payment"`
IsVerified bool `json:"is_verified"`
Number string `json:"number"`
PaymentToken string `json:"payment_token"`
PaymentTokenID int `json:"payment_token_id"`
CardType string `json:"card_type"`
CreatedAt NullTime `json:"created_at"`
ExpirationDate NullTime `json:"expiration_date"`
HasFailedPayment bool `json:"has_a_failed_payment"`
IsVerified bool `json:"is_verified"`
Number string `json:"number"`
PaymentToken string `json:"payment_token"`
PaymentTokenID int `json:"payment_token_id"`
} `json:"attributes"`
Relationships struct {
User *UserRelationship `json:"user"`
Expand Down
16 changes: 7 additions & 9 deletions goal.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
package patreon

import "time"

// Goal represents a Patreon's goal.
type Goal struct {
Type string `json:"type"`
Id string `json:"id"`
Attributes struct {
Amount int `json:"amount"`
AmountCents int `json:"amount_cents"`
CompletedPercentage int `json:"completed_percentage"`
CreatedAt time.Time `json:"created_at"`
ReachedAt time.Time `json:"reached_at"`
Title string `json:"title"`
Description string `json:"description"`
Amount int `json:"amount"`
AmountCents int `json:"amount_cents"`
CompletedPercentage int `json:"completed_percentage"`
CreatedAt NullTime `json:"created_at"`
ReachedAt NullTime `json:"reached_at"`
Title string `json:"title"`
Description string `json:"description"`
} `json:"attributes"`
}
2 changes: 2 additions & 0 deletions includes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@ func TestParseIncludes(t *testing.T) {
pledge, ok := includes.Items[4].(*Pledge)
require.True(t, ok)
require.Equal(t, 100, pledge.Attributes.AmountCents)
require.True(t, pledge.Attributes.CreatedAt.Valid)
require.Equal(t, time.Date(2017, 6, 20, 23, 21, 34, 514822000, time.UTC).Unix(), pledge.Attributes.CreatedAt.Unix())
require.False(t, pledge.Attributes.DeclinedSince.Valid)
require.True(t, pledge.Attributes.PatronPaysFees)
require.Equal(t, 100, pledge.Attributes.PledgeCapCents)

Expand Down
36 changes: 36 additions & 0 deletions null_time.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package patreon

import (
"encoding/json"
"strings"
"time"
)

// NullTime represents a time.Time that may be JSON "null".
// golang prior 1.8 doesn't support this scenario (fails with error: parsing time "null" as ""2006-01-02T15:04:05Z07:00"": cannot parse "null" as """)
type NullTime struct {
time.Time
Valid bool
}

// MarshalJSON implements json.Marshaler, it will encode null if this time is null.
func (t *NullTime) MarshalJSON() ([]byte, error) {
if !t.Valid {
return []byte("null"), nil
}
return t.Time.MarshalJSON()
}

// UnmarshalJSON implements json.Unmarshaler with JSON "null" support
func (t *NullTime) UnmarshalJSON(data []byte) error {
s := string(data)
if strings.EqualFold(s, "null") {
t.Valid = false
return nil
}

err := json.Unmarshal(data, &t.Time)
t.Valid = err == nil

return err
}
30 changes: 30 additions & 0 deletions null_time_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package patreon

import (
"encoding/json"
"testing"
"time"

"github.com/stretchr/testify/require"
)

func TestNullTime_parseValidTime(t *testing.T) {
s := &struct {
Time NullTime `json:"time"`
}{}

err := json.Unmarshal([]byte(`{ "time": "2017-06-20T23:21:34.514822+00:00" }`), s)
require.NoError(t, err)
require.True(t, s.Time.Valid)
require.Equal(t, time.Date(2017, 6, 20, 23, 21, 34, 514822000, time.UTC).Unix(), s.Time.Time.Unix())
}

func TestNullTime_parseInvalidTime(t *testing.T) {
s := &struct {
Time NullTime `json:"time"`
}{}

err := json.Unmarshal([]byte(`{ "time": null }`), s)
require.NoError(t, err)
require.False(t, s.Time.Valid)
}
12 changes: 5 additions & 7 deletions pledge.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package patreon

import "time"

// PledgeDefaultRelations specifies default includes for Pledge.
const PledgeDefaultRelations = "patron,reward,creator,address,pledge_vat_location"

Expand All @@ -11,11 +9,11 @@ type Pledge struct {
Type string `json:"type"`
Id string `json:"id"`
Attributes struct {
AmountCents int `json:"amount_cents"`
CreatedAt time.Time `json:"created_at"`
DeclinedSince time.Time `json:"declined_since"`
PledgeCapCents int `json:"pledge_cap_cents"`
PatronPaysFees bool `json:"patron_pays_fees"`
AmountCents int `json:"amount_cents"`
CreatedAt NullTime `json:"created_at"`
DeclinedSince NullTime `json:"declined_since"`
PledgeCapCents int `json:"pledge_cap_cents"`
PatronPaysFees bool `json:"patron_pays_fees"`
} `json:"attributes"`
Relationships struct {
Patron *PatronRelationship `json:"patron"`
Expand Down
32 changes: 15 additions & 17 deletions reward.go
Original file line number Diff line number Diff line change
@@ -1,26 +1,24 @@
package patreon

import "time"

// Reward represents a Patreon's reward.
type Reward struct {
Type string `json:"type"`
Id string `json:"id"`
Attributes struct {
Amount int `json:"amount"`
AmountCents int `json:"amount_cents"`
CreatedAt time.Time `json:"created_at"`
DeletedAt time.Time `json:"deleted_at"`
EditedAt time.Time `json:"edited_at"`
Description string `json:"description"`
ImageURL string `json:"image_url"`
PatronCount int `json:"patron_count"`
PostCount int `json:"post_count"`
Published bool `json:"published"`
PublishedAt time.Time `json:"published_at"`
RequiresShipping bool `json:"requires_shipping"`
Title string `json:"title"`
UnpublishedAt time.Time `json:"unpublished_at"`
URL string `json:"url"`
Amount int `json:"amount"`
AmountCents int `json:"amount_cents"`
CreatedAt NullTime `json:"created_at"`
DeletedAt NullTime `json:"deleted_at"`
EditedAt NullTime `json:"edited_at"`
Description string `json:"description"`
ImageURL string `json:"image_url"`
PatronCount int `json:"patron_count"`
PostCount int `json:"post_count"`
Published bool `json:"published"`
PublishedAt NullTime `json:"published_at"`
RequiresShipping bool `json:"requires_shipping"`
Title string `json:"title"`
UnpublishedAt NullTime `json:"unpublished_at"`
URL string `json:"url"`
} `json:"attributes"`
}
42 changes: 20 additions & 22 deletions user.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package patreon

import "time"

// UserDefaultRelations specifies default includes for User.
const UserDefaultRelations = "campaign,pledges"

Expand All @@ -11,26 +9,26 @@ type User struct {
Type string `json:"type"`
Id string `json:"id"`
Attributes struct {
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
FullName string `json:"full_name"`
Vanity string `json:"vanity"`
Email string `json:"email"`
About string `json:"about"`
FacebookId string `json:"facebook_id"`
Gender int `json:"gender"`
HasPassword bool `json:"has_password"`
ImageURL string `json:"image_url"`
ThumbURL string `json:"thumb_url"`
YouTube string `json:"youtube"`
Twitter string `json:"twitter"`
Facebook string `json:"facebook"`
IsEmailVerified bool `json:"is_email_verified"`
IsSuspended bool `json:"is_suspended"`
IsDeleted bool `json:"is_deleted"`
IsNuked bool `json:"is_nuked"`
Created time.Time `json:"created"`
URL string `json:"url"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
FullName string `json:"full_name"`
Vanity string `json:"vanity"`
Email string `json:"email"`
About string `json:"about"`
FacebookId string `json:"facebook_id"`
Gender int `json:"gender"`
HasPassword bool `json:"has_password"`
ImageURL string `json:"image_url"`
ThumbURL string `json:"thumb_url"`
YouTube string `json:"youtube"`
Twitter string `json:"twitter"`
Facebook string `json:"facebook"`
IsEmailVerified bool `json:"is_email_verified"`
IsSuspended bool `json:"is_suspended"`
IsDeleted bool `json:"is_deleted"`
IsNuked bool `json:"is_nuked"`
Created NullTime `json:"created"`
URL string `json:"url"`
} `json:"attributes"`
Relationships struct {
Pledges *PledgesRelationship `json:"pledges,omitempty"`
Expand Down

0 comments on commit a990f6e

Please sign in to comment.