Last active
March 3, 2017 23:03
-
-
Save Slals/7c008242cc33073f02b24b5585e8b165 to your computer and use it in GitHub Desktop.
Use hashed ID for database without storing the hash and keeping the default serial in the database in Golang.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"encoding/json" | |
"github.com/speps/go-hashids" | |
) | |
func initHasher() *hashids.HashID { | |
hashConf := hashids.NewData() | |
hashConf.Salt = "very_special_key" | |
hashConf.MinLength = 8 // Hash ID length, 8 means a hash ID such as xxxxxxxx | |
return hashids.NewWithData(hashConf) | |
} | |
// DecodeHash returns the decoded id | |
func DecodeHash(hash string) (int64, error) { | |
hasher := initHasher() | |
id, err := hasher.DecodeInt64WithError(hash) | |
if err != nil { | |
return 0, err | |
} | |
return id[0], nil | |
} | |
// HashID hashes int64 id and returns a unique string | |
func HashID(id int64) (string, error) { | |
hasher := initHasher() | |
return hasher.EncodeInt64([]int64{id}) | |
} | |
// ID is a custom type for hashed IDs | |
type ID struct { | |
ValueEncoded string | |
ValueDecoded uint64 | |
} | |
// InitID returns an ID | |
func InitID(data interface{}) ID { | |
switch data.(type) { | |
case string: | |
encV := data.(string) | |
decV, _ := DecodeHash(encV) | |
return ID{ | |
ValueEncoded: encV, | |
ValueDecoded: uint64(decV), | |
} | |
case uint64: | |
decV := data.(uint64) | |
encV, _ := HashID(int64(decV)) | |
return ID{ | |
ValueEncoded: encV, | |
ValueDecoded: decV, | |
} | |
} | |
return ID{ | |
ValueEncoded: "", | |
ValueDecoded: 0, | |
} | |
} | |
// MarshalJSON marshals custom ID | |
func (id ID) MarshalJSON() ([]byte, error) { | |
// We want to marshal the hashed ID | |
return json.Marshal(id.ValueEncoded) | |
} | |
// UnmarshalJSON unmarshals ID | |
func (id *ID) UnmarshalJSON(data []byte) error { | |
var x *string | |
if err := json.Unmarshal(data, &x); err != nil { | |
return err | |
} | |
if x != nil { | |
id.ValueEncoded = *x | |
decode, err := DecodeHash(id.ValueEncoded) | |
if err != nil { | |
return err | |
} | |
id.ValueDecoded = uint64(decode) | |
} else { | |
id.ValueEncoded = "" | |
id.ValueDecoded = 0 | |
} | |
return nil | |
} | |
// Scan implements the Scanner interface | |
// Allows to directly get the hashed ID after retrieving the data from the database | |
func (id *ID) Scan(value interface{}) error { | |
encode, err := HashID(value.(int64)) | |
if err != nil { | |
return err | |
} | |
id.ValueDecoded = uint64(value.(int64)) | |
id.ValueEncoded = encode | |
return nil | |
} | |
// Value implements the driver Valuer interface | |
func (id ID) Value() (driver.Value, error) { | |
return id.ValueDecoded, nil | |
} | |
func main() { | |
var book struct { | |
ID ID `json:"id"` | |
} | |
id := InitID(10) | |
fmt.Print(id) // { E1G6x5Yq 10 } | |
book.ID = id | |
json.Marshal(book) | |
// {"id": "E1G6x5Yq"} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment