Skip to content

Commit 3ae0090

Browse files
author
Sri Krishna Paritala
committed
First Commit
0 parents  commit 3ae0090

File tree

7 files changed

+181
-0
lines changed

7 files changed

+181
-0
lines changed

.gitignore

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Binaries for programs and plugins
2+
*.exe
3+
*.exe~
4+
*.dll
5+
*.so
6+
*.dylib
7+
8+
# Test binary, build with `go test -c`
9+
*.test
10+
11+
# Output of the go coverage tool, specifically when used with LiteIDE
12+
*.out
13+
14+
# IDE preferences
15+
.idea/
16+
.vscode/

.travis.yml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
language: go
2+
3+
go:
4+
- 1.10.x
5+
- 1.11.x
6+
- tip
7+
8+
install:
9+
- go get -u golang.org/x/tools/cmd/goimports
10+
- go get -u github.com/golang/lint/golint
11+
12+
script:
13+
- go get -d -t ./...
14+
- go vet ./...
15+
- golint ./...
16+
- go test ./...
17+
- >
18+
goimports -d -e ./ | grep '.*' && { echo; echo "Aborting due to non-empty goimports output."; exit 1; } || :

README.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# idgen
2+
3+
Generates url safe lexically sorted random ids with a prefix in go. Inspired from Stripe.
4+
5+
## Usage
6+
7+
```go
8+
package main
9+
10+
import (
11+
"fmt"
12+
13+
"github.com/srikrsna/idgen"
14+
)
15+
16+
func main() {
17+
id := idgen.New("cus")
18+
fmt.Println(id)
19+
// Output: cus_0000XSNJG0MQJHBF4QX1EFD6Y3
20+
}
21+
```
22+
23+
### Depends on
24+
25+
[oklog/ulid](https://github.com/oklog/ulid)

go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module github.com/srikrsna/idgen
2+
3+
require github.com/oklog/ulid v1.3.1

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
2+
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=

id.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package idgen
2+
3+
import (
4+
"io"
5+
"math/rand"
6+
"sync"
7+
"time"
8+
9+
"github.com/oklog/ulid"
10+
)
11+
12+
// New generates a lexically sorted, url safe Id with a prefix.
13+
// Eg: cus_JSfjkdjf333j46, i.e. {prefix}-{ulid}
14+
func New(prefix string) string {
15+
ent := getEntropy()
16+
res := prefix + "_" + ulid.MustNew(ulid.Now(), ent).String()
17+
putEntropy(ent)
18+
return res
19+
}
20+
21+
var entropyPool = sync.Pool{
22+
New: func() interface{} {
23+
return ulid.Monotonic(rand.New(rand.NewSource(time.Now().UnixNano())), 0)
24+
},
25+
}
26+
27+
func getEntropy() io.Reader {
28+
return entropyPool.Get().(io.Reader)
29+
}
30+
31+
func putEntropy(r io.Reader) {
32+
entropyPool.Put(r)
33+
}
34+
35+
// PrefixGenerator generates a new id with the given prefix
36+
type PrefixGenerator struct {
37+
Prefix string
38+
}
39+
40+
func (p PrefixGenerator) New() string {
41+
return New(p.Prefix)
42+
}

id_test.go

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package idgen_test
2+
3+
import (
4+
"fmt"
5+
"net/url"
6+
"strings"
7+
"testing"
8+
9+
"github.com/oklog/ulid"
10+
11+
"github.com/srikrsna/idgen"
12+
)
13+
14+
func TestPrefix(t *testing.T) {
15+
prefix := "cus"
16+
testPrefix(t, idgen.New(prefix), prefix)
17+
}
18+
19+
func TestULID(t *testing.T) {
20+
id := idgen.New("cus")
21+
if _, err := ulid.Parse(id[len("cus_"):]); err != nil {
22+
t.Errorf("func New not generating ulids: %v", err)
23+
}
24+
}
25+
26+
func TestURLSafe(t *testing.T) {
27+
for range [20]struct{}{} {
28+
id := idgen.New("cus")
29+
30+
if url.PathEscape(id) != id {
31+
t.Errorf("value generated by New is not url path safe, expected: %s, got: %s", url.PathEscape(id), id)
32+
}
33+
34+
if url.QueryEscape(id) != id {
35+
t.Errorf("value generated by New is not url query safe, expected: %s, got: %s", url.QueryEscape(id), id)
36+
}
37+
}
38+
}
39+
40+
func TestPrefixGenerator_New(t *testing.T) {
41+
const prefix = "cus"
42+
pg := idgen.PrefixGenerator{
43+
Prefix: prefix,
44+
}
45+
testPrefix(t, pg.New() ,prefix)
46+
}
47+
48+
func testPrefix(t *testing.T, id, prefix string) {
49+
t.Helper()
50+
if !strings.HasPrefix(id, prefix+"_") {
51+
t.Errorf("New should return a ulid with the given prefix, expected: cus, got: %s", id)
52+
}
53+
}
54+
55+
func ExampleNew() {
56+
id := idgen.New("cus")
57+
58+
fmt.Println(id[:4])
59+
60+
// Output: cus_
61+
}
62+
63+
func BenchmarkNew(b *testing.B) {
64+
for i := 0; i < b.N; i++ {
65+
_ = idgen.New("cus")
66+
}
67+
}
68+
69+
func BenchmarkNewParallel(b *testing.B) {
70+
b.RunParallel(func(pb *testing.PB) {
71+
for pb.Next() {
72+
_ = idgen.New("cus")
73+
}
74+
})
75+
}

0 commit comments

Comments
 (0)