Skip to content

Commit

Permalink
feat: add method to print hash as string (#12)
Browse files Browse the repository at this point in the history
* feat: add EncodeString method on ID

* chore: add sonarcloud check
  • Loading branch information
indrasaputra committed May 25, 2021
1 parent 89b7216 commit 4743081
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 14 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
[![Workflow](https://github.com/indrasaputra/hashids/workflows/Test/badge.svg)](https://github.com/indrasaputra/hashids/actions)
[![codecov](https://codecov.io/gh/indrasaputra/hashids/branch/main/graph/badge.svg)](https://codecov.io/gh/indrasaputra/hashids)
[![Maintainability](https://api.codeclimate.com/v1/badges/2cd8202174459c1b5348/maintainability)](https://codeclimate.com/github/indrasaputra/hashids/maintainability)
[![Documentation](https://godoc.org/github.com/indrasaputra/hashids?status.svg)](http://godoc.org/github.com/indrasaputra/hashids)
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=indrasaputra_hashids&metric=alert_status)](https://sonarcloud.io/dashboard?id=indrasaputra_hashids)
[![Go Reference](https://pkg.go.dev/badge/github.com/indrasaputra/hashids.svg)](https://pkg.go.dev/github.com/indrasaputra/hashids)

Hashids is a package to convert ID into a random string to obfuscate the real ID from user.
In the implementation itself, the ID will still be an integer. But, when it is shown to the user,
Expand Down Expand Up @@ -62,4 +63,4 @@ The code above will fill the product's attributes like this:

## Limitation

For now, this package only support encoding to JSON and decoding from JSON.
For now, this package only support encoding to JSON, decoding from JSON, and encode as a string.
11 changes: 11 additions & 0 deletions hashids.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,17 @@ func (id *ID) UnmarshalJSON(hash []byte) error {
return nil
}

// EncodeString encodes ID to hashsids format and returns as a string.
// It ignores the error coming from encoding process.
// Thus, if there is any error during the process, it returns empty string.
func (id ID) EncodeString() string {
res, err := hasher.Encode(id)
if err != nil {
return ""
}
return string(res)
}

// Hash defines the contract to encode and decode the ID.
type Hash interface {
// Encode encodes the ID into a slice of byte.
Expand Down
28 changes: 16 additions & 12 deletions hashids_bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ import (
"github.com/indrasaputra/hashids"
)

const (
salt = "common-salt"
)

func BenchmarkID_MarshalJSON(b *testing.B) {
id := hashids.ID(66)
for i := 0; i < b.N; i++ {
Expand All @@ -22,28 +26,28 @@ func BenchmarkID_UnmarshalJSON(b *testing.B) {

func BenchmarkHashID_Encode(b *testing.B) {
b.Run("length: 5", func(b *testing.B) {
hash, _ := hashids.NewHashID(5, "common-salt")
hash, _ := hashids.NewHashID(5, salt)
for i := 0; i < b.N; i++ {
hash.Encode(hashids.ID(i))
}
})

b.Run("length: 10", func(b *testing.B) {
hash, _ := hashids.NewHashID(10, "common-salt")
hash, _ := hashids.NewHashID(10, salt)
for i := 0; i < b.N; i++ {
hash.Encode(hashids.ID(i))
}
})

b.Run("length: 15", func(b *testing.B) {
hash, _ := hashids.NewHashID(15, "common-salt")
hash, _ := hashids.NewHashID(15, salt)
for i := 0; i < b.N; i++ {
hash.Encode(hashids.ID(i))
}
})

b.Run("length: 20", func(b *testing.B) {
hash, _ := hashids.NewHashID(20, "common-salt")
hash, _ := hashids.NewHashID(20, salt)
for i := 0; i < b.N; i++ {
hash.Encode(hashids.ID(i))
}
Expand All @@ -52,31 +56,31 @@ func BenchmarkHashID_Encode(b *testing.B) {

func BenchmarkHashID_Decode(b *testing.B) {
b.Run("length: 5", func(b *testing.B) {
hash, _ := hashids.NewHashID(5, "common-salt")
hash, _ := hashids.NewHashID(5, salt)
res, _ := hash.Encode(100)
for i := 0; i < b.N; i++ {
hash.Decode(res)
}
})

b.Run("length: 10", func(b *testing.B) {
hash, _ := hashids.NewHashID(10, "common-salt")
hash, _ := hashids.NewHashID(10, salt)
res, _ := hash.Encode(100)
for i := 0; i < b.N; i++ {
hash.Decode(res)
}
})

b.Run("length: 15", func(b *testing.B) {
hash, _ := hashids.NewHashID(15, "common-salt")
hash, _ := hashids.NewHashID(15, salt)
res, _ := hash.Encode(100)
for i := 0; i < b.N; i++ {
hash.Decode(res)
}
})

b.Run("length: 20", func(b *testing.B) {
hash, _ := hashids.NewHashID(20, "common-salt")
hash, _ := hashids.NewHashID(20, salt)
res, _ := hash.Encode(100)
for i := 0; i < b.N; i++ {
hash.Decode(res)
Expand All @@ -94,31 +98,31 @@ func BenchmarkEncodeID(b *testing.B) {

func BenchmarkDecodeHash(b *testing.B) {
b.Run("length: 5", func(b *testing.B) {
hash, _ := hashids.NewHashID(5, "common-salt")
hash, _ := hashids.NewHashID(5, salt)
res, _ := hash.Encode(100)
for i := 0; i < b.N; i++ {
hashids.DecodeHash(res)
}
})

b.Run("length: 10", func(b *testing.B) {
hash, _ := hashids.NewHashID(10, "common-salt")
hash, _ := hashids.NewHashID(10, salt)
res, _ := hash.Encode(100)
for i := 0; i < b.N; i++ {
hashids.DecodeHash(res)
}
})

b.Run("length: 15", func(b *testing.B) {
hash, _ := hashids.NewHashID(15, "common-salt")
hash, _ := hashids.NewHashID(15, salt)
res, _ := hash.Encode(100)
for i := 0; i < b.N; i++ {
hashids.DecodeHash(res)
}
})

b.Run("length: 20", func(b *testing.B) {
hash, _ := hashids.NewHashID(20, "common-salt")
hash, _ := hashids.NewHashID(20, salt)
res, _ := hash.Encode(100)
for i := 0; i < b.N; i++ {
hashids.DecodeHash(res)
Expand Down
34 changes: 34 additions & 0 deletions hashids_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,40 @@ func TestID_MarshalAndUnmarshal(t *testing.T) {
})
}

func TestID_EncodeString(t *testing.T) {
t.Run("negative number can't be encoded and produces empty string", func(t *testing.T) {
ids := []hashids.ID{
hashids.ID(-1),
hashids.ID(-43),
hashids.ID(-66),
}

for _, id := range ids {
res := id.EncodeString()

assert.Empty(t, res)
}
})

t.Run("successfully encode positive number", func(t *testing.T) {
tables := []struct {
hash string
id hashids.ID
}{
{"oWx0b8DZ1a", 1},
{"EO19oA6vGx", 43},
{"J4r0MA20No", 66},
}

for _, table := range tables {
res := table.id.EncodeString()

assert.NotEmpty(t, res)
assert.Equal(t, table.hash, res)
}
})
}

func TestNewHashID(t *testing.T) {
t.Run("successfully create an instance of HashID", func(t *testing.T) {
tables := []struct {
Expand Down

0 comments on commit 4743081

Please sign in to comment.