Skip to content

Instantly share code, notes, and snippets.

@Slals
Last active March 3, 2017 23:03
Show Gist options
  • Save Slals/7c008242cc33073f02b24b5585e8b165 to your computer and use it in GitHub Desktop.
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.
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