Use custom type UnixTimestamp instead of repeating boilerplate code over and over.

This commit is contained in:
Howl 2016-07-06 22:32:30 +02:00
parent ff1d2fa1c3
commit 09523369b7
6 changed files with 95 additions and 76 deletions

View File

@ -2,7 +2,6 @@ package v1
import ( import (
"database/sql" "database/sql"
"time"
"git.zxq.co/ripple/rippleapi/common" "git.zxq.co/ripple/rippleapi/common"
) )
@ -19,7 +18,7 @@ type beatmap struct {
HitLength int `json:"hit_length"` HitLength int `json:"hit_length"`
Ranked int `json:"ranked"` Ranked int `json:"ranked"`
RankedStatusFrozen int `json:"ranked_status_frozen"` RankedStatusFrozen int `json:"ranked_status_frozen"`
LatestUpdate time.Time `json:"latest_update"` LatestUpdate common.UnixTimestamp `json:"latest_update"`
} }
type beatmapMayOrMayNotExist struct { type beatmapMayOrMayNotExist struct {
@ -34,7 +33,7 @@ type beatmapMayOrMayNotExist struct {
HitLength *int HitLength *int
Ranked *int Ranked *int
RankedStatusFrozen *int RankedStatusFrozen *int
LatestUpdate *time.Time LatestUpdate *common.UnixTimestamp
} }
func (b *beatmapMayOrMayNotExist) toBeatmap() *beatmap { func (b *beatmapMayOrMayNotExist) toBeatmap() *beatmap {
@ -146,21 +145,17 @@ func getSet(md common.MethodData, setID int) common.CodeMessager {
} }
var r beatmapSetResponse var r beatmapSetResponse
for rows.Next() { for rows.Next() {
var ( var b beatmap
b beatmap
rawLatestUpdate int64
)
err = rows.Scan( err = rows.Scan(
&b.BeatmapID, &b.BeatmapsetID, &b.BeatmapMD5, &b.BeatmapID, &b.BeatmapsetID, &b.BeatmapMD5,
&b.SongName, &b.AR, &b.OD, &b.Difficulty, &b.MaxCombo, &b.SongName, &b.AR, &b.OD, &b.Difficulty, &b.MaxCombo,
&b.HitLength, &b.Ranked, &b.RankedStatusFrozen, &b.HitLength, &b.Ranked, &b.RankedStatusFrozen,
&rawLatestUpdate, &b.LatestUpdate,
) )
if err != nil { if err != nil {
md.Err(err) md.Err(err)
continue continue
} }
b.LatestUpdate = time.Unix(rawLatestUpdate, 0)
r.Beatmaps = append(r.Beatmaps, b) r.Beatmaps = append(r.Beatmaps, b)
} }
r.Code = 200 r.Code = 200
@ -168,15 +163,12 @@ func getSet(md common.MethodData, setID int) common.CodeMessager {
} }
func getBeatmap(md common.MethodData, beatmapID int) common.CodeMessager { func getBeatmap(md common.MethodData, beatmapID int) common.CodeMessager {
var ( var b beatmap
b beatmap
rawLatestUpdate int64
)
err := md.DB.QueryRow(baseBeatmapSelect+"WHERE beatmap_id = ? LIMIT 1", beatmapID).Scan( err := md.DB.QueryRow(baseBeatmapSelect+"WHERE beatmap_id = ? LIMIT 1", beatmapID).Scan(
&b.BeatmapID, &b.BeatmapsetID, &b.BeatmapMD5, &b.BeatmapID, &b.BeatmapsetID, &b.BeatmapMD5,
&b.SongName, &b.AR, &b.OD, &b.Difficulty, &b.MaxCombo, &b.SongName, &b.AR, &b.OD, &b.Difficulty, &b.MaxCombo,
&b.HitLength, &b.Ranked, &b.RankedStatusFrozen, &b.HitLength, &b.Ranked, &b.RankedStatusFrozen,
&rawLatestUpdate, &b.LatestUpdate,
) )
switch { switch {
case err == sql.ErrNoRows: case err == sql.ErrNoRows:
@ -185,7 +177,6 @@ func getBeatmap(md common.MethodData, beatmapID int) common.CodeMessager {
md.Err(err) md.Err(err)
return Err500 return Err500
} }
b.LatestUpdate = time.Unix(rawLatestUpdate, 0)
var r beatmapResponse var r beatmapResponse
r.Code = 200 r.Code = 200
r.beatmap = b r.beatmap = b

View File

@ -2,7 +2,6 @@ package v1
import ( import (
"database/sql" "database/sql"
"time"
"git.zxq.co/ripple/rippleapi/common" "git.zxq.co/ripple/rippleapi/common"
) )
@ -87,18 +86,13 @@ ORDER BY users_relationships.id`
func friendPuts(md common.MethodData, row *sql.Rows) (user friendData) { func friendPuts(md common.MethodData, row *sql.Rows) (user friendData) {
var err error var err error
registeredOn := int64(0)
latestActivity := int64(0)
var showcountry bool var showcountry bool
err = row.Scan(&user.ID, &user.Username, &registeredOn, &user.Privileges, &latestActivity, &user.UsernameAKA, &user.Country, &showcountry) err = row.Scan(&user.ID, &user.Username, &user.RegisteredOn, &user.Privileges, &user.LatestActivity, &user.UsernameAKA, &user.Country, &showcountry)
if err != nil { if err != nil {
md.Err(err) md.Err(err)
return return
} }
user.RegisteredOn = time.Unix(registeredOn, 0)
user.LatestActivity = time.Unix(latestActivity, 0)
// If the user wants to stay anonymous, don't show their country. // If the user wants to stay anonymous, don't show their country.
// This can be overriden if we have the ReadConfidential privilege and the user we are accessing is the token owner. // This can be overriden if we have the ReadConfidential privilege and the user we are accessing is the token owner.
if !(showcountry || (md.User.Privileges.HasPrivilegeReadConfidential() && user.ID == md.ID())) { if !(showcountry || (md.User.Privileges.HasPrivilegeReadConfidential() && user.ID == md.ID())) {

View File

@ -2,7 +2,6 @@ package v1
import ( import (
"fmt" "fmt"
"time"
"git.zxq.co/ripple/rippleapi/common" "git.zxq.co/ripple/rippleapi/common"
) )
@ -48,12 +47,10 @@ func LeaderboardGET(md common.MethodData) common.CodeMessager {
for rows.Next() { for rows.Next() {
var ( var (
u leaderboardUser u leaderboardUser
register int64
latestActivity int64
showCountry bool showCountry bool
) )
err := rows.Scan( err := rows.Scan(
&u.ID, &u.Username, &register, &u.Privileges, &latestActivity, &u.ID, &u.Username, &u.RegisteredOn, &u.Privileges, &u.LatestActivity,
&u.UsernameAKA, &u.Country, &showCountry, &u.UsernameAKA, &u.Country, &showCountry,
&u.PlayStyle, &u.FavouriteMode, &u.PlayStyle, &u.FavouriteMode,
@ -69,8 +66,6 @@ func LeaderboardGET(md common.MethodData) common.CodeMessager {
if !showCountry { if !showCountry {
u.Country = "XX" u.Country = "XX"
} }
u.RegisteredOn = time.Unix(register, 0)
u.LatestActivity = time.Unix(latestActivity, 0)
resp.Users = append(resp.Users, u) resp.Users = append(resp.Users, u)
} }
resp.Code = 200 resp.Code = 200

View File

@ -5,7 +5,6 @@ import (
"database/sql" "database/sql"
"strconv" "strconv"
"strings" "strings"
"time"
"git.zxq.co/ripple/ocl" "git.zxq.co/ripple/ocl"
"git.zxq.co/ripple/rippleapi/common" "git.zxq.co/ripple/rippleapi/common"
@ -15,9 +14,9 @@ type userData struct {
ID int `json:"id"` ID int `json:"id"`
Username string `json:"username"` Username string `json:"username"`
UsernameAKA string `json:"username_aka"` UsernameAKA string `json:"username_aka"`
RegisteredOn time.Time `json:"registered_on"` RegisteredOn common.UnixTimestamp `json:"registered_on"`
Privileges uint64 `json:"privileges"` Privileges uint64 `json:"privileges"`
LatestActivity time.Time `json:"latest_activity"` LatestActivity common.UnixTimestamp `json:"latest_activity"`
Country string `json:"country"` Country string `json:"country"`
} }
@ -49,12 +48,11 @@ func userPuts(md common.MethodData, row *sql.Row) common.CodeMessager {
var err error var err error
var user userPutsUserData var user userPutsUserData
var ( var showCountry bool
registeredOn int64 err = row.Scan(
latestActivity int64 &user.ID, &user.Username, &user.RegisteredOn, &user.Privileges, &user.LatestActivity,
showCountry bool &user.UsernameAKA, &user.Country, &showCountry,
) )
err = row.Scan(&user.ID, &user.Username, &registeredOn, &user.Privileges, &latestActivity, &user.UsernameAKA, &user.Country, &showCountry)
switch { switch {
case err == sql.ErrNoRows: case err == sql.ErrNoRows:
return common.SimpleResponse(404, "No such user was found!") return common.SimpleResponse(404, "No such user was found!")
@ -63,9 +61,6 @@ func userPuts(md common.MethodData, row *sql.Row) common.CodeMessager {
return Err500 return Err500
} }
user.RegisteredOn = time.Unix(registeredOn, 0)
user.LatestActivity = time.Unix(latestActivity, 0)
user.Country = genCountry(md, user.ID, showCountry, user.Country) user.Country = genCountry(md, user.ID, showCountry, user.Country)
user.Code = 200 user.Code = 200
@ -194,11 +189,9 @@ LIMIT 1
badges string badges string
country string country string
showCountry bool showCountry bool
registeredOn int64
latestActivity int64
) )
err := md.DB.QueryRow(query, param).Scan( err := md.DB.QueryRow(query, param).Scan(
&r.ID, &r.Username, &registeredOn, &r.Privileges, &latestActivity, &r.ID, &r.Username, &r.RegisteredOn, &r.Privileges, &r.LatestActivity,
&r.UsernameAKA, &badges, &country, &showCountry, &r.UsernameAKA, &badges, &country, &showCountry,
&r.PlayStyle, &r.FavouriteMode, &r.PlayStyle, &r.FavouriteMode,
@ -230,9 +223,6 @@ LIMIT 1
r.Country = genCountry(md, r.ID, showCountry, country) r.Country = genCountry(md, r.ID, showCountry, country)
r.Badges = badgesToArray(badges) r.Badges = badgesToArray(badges)
r.RegisteredOn = time.Unix(registeredOn, 0)
r.LatestActivity = time.Unix(latestActivity, 0)
for _, m := range []*modeData{&r.STD, &r.Taiko, &r.CTB, &r.Mania} { for _, m := range []*modeData{&r.STD, &r.Taiko, &r.CTB, &r.Mania} {
m.Level = ocl.GetLevelPrecise(int64(m.TotalScore)) m.Level = ocl.GetLevelPrecise(int64(m.TotalScore))
} }

View File

@ -131,7 +131,6 @@ func scoresPuts(md common.MethodData, whereClause string, params ...interface{})
us userScore us userScore
t string t string
b beatmapMayOrMayNotExist b beatmapMayOrMayNotExist
rawLatestUpdate *int64
) )
err = rows.Scan( err = rows.Scan(
&us.ID, &us.BeatmapMD5, &us.Score, &us.ID, &us.BeatmapMD5, &us.Score,
@ -144,7 +143,7 @@ func scoresPuts(md common.MethodData, whereClause string, params ...interface{})
&b.BeatmapID, &b.BeatmapsetID, &b.BeatmapMD5, &b.BeatmapID, &b.BeatmapsetID, &b.BeatmapMD5,
&b.SongName, &b.AR, &b.OD, &b.Difficulty, &b.SongName, &b.AR, &b.OD, &b.Difficulty,
&b.MaxCombo, &b.HitLength, &b.Ranked, &b.MaxCombo, &b.HitLength, &b.Ranked,
&b.RankedStatusFrozen, &rawLatestUpdate, &b.RankedStatusFrozen, &b.LatestUpdate,
) )
if err != nil { if err != nil {
md.Err(err) md.Err(err)
@ -156,11 +155,6 @@ func scoresPuts(md common.MethodData, whereClause string, params ...interface{})
md.Err(err) md.Err(err)
return Err500 return Err500
} }
if rawLatestUpdate != nil {
// fml i should have used an inner join
xd := time.Unix(*rawLatestUpdate, 0)
b.LatestUpdate = &xd
}
us.Beatmap = b.toBeatmap() us.Beatmap = b.toBeatmap()
scores = append(scores, us) scores = append(scores, us)
} }

55
common/unix_timestamp.go Normal file
View File

@ -0,0 +1,55 @@
package common
import (
"errors"
"strconv"
"time"
)
// UnixTimestamp is simply a time.Time, but can be used to convert an
// unix timestamp in the database into a native time.Time.
type UnixTimestamp time.Time
// Scan decodes src into an unix timestamp.
func (u *UnixTimestamp) Scan(src interface{}) error {
if u == nil {
return errors.New("rippleapi/common: UnixTimestamp is nil")
}
switch src := src.(type) {
case int64:
*u = UnixTimestamp(time.Unix(src, 0))
case float64:
*u = UnixTimestamp(time.Unix(int64(src), 0))
case string:
return u._string(src)
case []byte:
return u._string(string(src))
case nil:
// Nothing, leave zero value on timestamp
default:
return errors.New("rippleapi/common: unhandleable type")
}
return nil
}
func (u *UnixTimestamp) _string(s string) error {
ts, err := strconv.Atoi(s)
if err != nil {
return err
}
*u = UnixTimestamp(time.Unix(int64(ts), 0))
return nil
}
// MarshalJSON -> time.Time.MarshalJSON
func (u UnixTimestamp) MarshalJSON() ([]byte, error) {
return time.Time(u).MarshalJSON()
}
// UnmarshalJSON -> time.Time.UnmarshalJSON
func (u *UnixTimestamp) UnmarshalJSON(x []byte) error {
t := new(time.Time)
err := t.UnmarshalJSON(x)
*u = UnixTimestamp(*t)
return err
}