Skip to content

Commit a3a7ebe

Browse files
authored
feat(generate): Added UUID V7 generator (#260)
1 parent c3f0f2e commit a3a7ebe

File tree

8 files changed

+292
-7
lines changed

8 files changed

+292
-7
lines changed

generate/README.md

+56-6
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,10 @@
99
> Generation module based on [Google UUID](https://github.com/google/uuid).
1010
1111
<!-- TOC -->
12-
1312
* [Installation](#installation)
1413
* [Documentation](#documentation)
15-
* [UUID](#uuid)
16-
14+
* [UUID V4](#uuid-v4)
15+
* [UUID V7](#uuid-v7)
1716
<!-- TOC -->
1817

1918
## Installation
@@ -24,11 +23,11 @@ go get github.com/ankorstore/yokai/generate
2423

2524
## Documentation
2625

27-
### UUID
26+
### UUID V4
2827

29-
This module provides an [UuidGenerator](uuid/generator.go) interface, allowing to generate UUIDs.
28+
This module provides an [UuidGenerator](uuid/generator.go) interface, allowing to generate UUIDs V4.
3029

31-
The `DefaultUuidGenerator` is based on [Google UUID](https://github.com/google/uuid).
30+
The `DefaultUuidGenerator` implementing it is based on [Google UUID](https://github.com/google/uuid).
3231

3332
```go
3433
package main
@@ -70,4 +69,55 @@ func main() {
7069
generator := uuid.NewDefaultUuidGeneratorFactory().Create()
7170
fmt.Printf("uuid: %s", generator.Generate()) // uuid: dcb5d8b3-4517-4957-a42c-604d11758561
7271
}
72+
```
73+
74+
### UUID V7
75+
76+
This module provides an [UuidV7Generator](uuidv7/generator.go) interface, allowing to generate UUIDs V7.
77+
78+
The `DefaultUuidV7Generator` implementing it is based on [Google UUID](https://github.com/google/uuid).
79+
80+
```go
81+
package main
82+
83+
import (
84+
"fmt"
85+
86+
"github.com/ankorstore/yokai/generate/uuidv7"
87+
uuidv7test "github.com/ankorstore/yokai/generate/generatetest/uuidv7"
88+
)
89+
90+
func main() {
91+
// default UUID V7 generator
92+
generator := uuidv7.NewDefaultUuidV7Generator()
93+
uuid, _ := generator.Generate()
94+
fmt.Printf("uuid: %s", uuid.String()) // uuid: 018fdd68-1b41-7eb0-afad-57f45297c7c1
95+
96+
// test UUID generator (with deterministic value for testing, requires valid UUID v7)
97+
testGenerator, _ := uuidv7test.NewTestUuidV7Generator("018fdd7d-1576-7a21-900e-1399637bd1a1")
98+
uuid, _ = testGenerator.Generate()
99+
fmt.Printf("uuid: %s", uuid.String()) // uuid: 018fdd7d-1576-7a21-900e-1399637bd1a1
100+
}
101+
```
102+
103+
The module also provides a [UuidV7GeneratorFactory](uuidv7/factory.go) interface, to create
104+
the [UuidV7Generator](uuidv7/generator.go) instances.
105+
106+
The `DefaultUuidV7GeneratorFactory` generates `DefaultUuidV7Generator` instances.
107+
108+
```go
109+
package main
110+
111+
import (
112+
"fmt"
113+
114+
"github.com/ankorstore/yokai/generate/uuidv7"
115+
)
116+
117+
func main() {
118+
// default UUID generator factory
119+
generator := uuidv7.NewDefaultUuidV7GeneratorFactory().Create()
120+
uuid, _ := generator.Generate()
121+
fmt.Printf("uuid: %s", uuid.String()) // uuid: 018fdd68-1b41-7eb0-afad-57f45297c7c1
122+
}
73123
```
+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package uuid
2+
3+
import googleuuid "github.com/google/uuid"
4+
5+
// TestUuidV7Generator is a [UuidV7Generator] implementation allowing deterministic generations (for testing).
6+
type TestUuidV7Generator struct {
7+
value string
8+
}
9+
10+
// NewTestUuidV7Generator returns a [TestUuidGenerator], implementing [UuidGenerator].
11+
//
12+
// It accepts a value that will be used for deterministic generation results.
13+
func NewTestUuidV7Generator(value string) (*TestUuidV7Generator, error) {
14+
err := googleuuid.Validate(value)
15+
if err != nil {
16+
return nil, err
17+
}
18+
19+
return &TestUuidV7Generator{
20+
value: value,
21+
}, nil
22+
}
23+
24+
// SetValue sets the value to use for deterministic generations.
25+
func (g *TestUuidV7Generator) SetValue(value string) error {
26+
err := googleuuid.Validate(value)
27+
if err != nil {
28+
return err
29+
}
30+
31+
g.value = value
32+
33+
return nil
34+
}
35+
36+
// Generate returns the configured deterministic value.
37+
func (g *TestUuidV7Generator) Generate() (googleuuid.UUID, error) {
38+
return googleuuid.Parse(g.value)
39+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package uuid_test
2+
3+
import (
4+
"testing"
5+
6+
uuidv7test "github.com/ankorstore/yokai/generate/generatetest/uuidv7"
7+
"github.com/ankorstore/yokai/generate/uuidv7"
8+
"github.com/stretchr/testify/assert"
9+
)
10+
11+
const (
12+
uuid1 = "018fdd7d-1576-7a21-900e-1399637bd1a1"
13+
uuid2 = "018fdd7d-1576-76ff-944b-39bd474b0ea9"
14+
uuid3 = "018fdd7d-1576-7b53-a364-7b96dcc158c9"
15+
)
16+
17+
func TestNewTestUuidV7Generator(t *testing.T) {
18+
t.Parallel()
19+
20+
generator, err := uuidv7test.NewTestUuidV7Generator(uuid1)
21+
assert.NoError(t, err)
22+
23+
assert.IsType(t, &uuidv7test.TestUuidV7Generator{}, generator)
24+
assert.Implements(t, (*uuidv7.UuidV7Generator)(nil), generator)
25+
}
26+
27+
func TestGenerateSuccess(t *testing.T) {
28+
t.Parallel()
29+
30+
generator, err := uuidv7test.NewTestUuidV7Generator(uuid2)
31+
assert.NoError(t, err)
32+
33+
value1, err := generator.Generate()
34+
assert.NoError(t, err)
35+
36+
value2, err := generator.Generate()
37+
assert.NoError(t, err)
38+
39+
assert.Equal(t, uuid2, value1.String())
40+
assert.Equal(t, uuid2, value2.String())
41+
42+
err = generator.SetValue(uuid3)
43+
assert.NoError(t, err)
44+
45+
value1, err = generator.Generate()
46+
assert.NoError(t, err)
47+
48+
value2, err = generator.Generate()
49+
assert.NoError(t, err)
50+
51+
assert.Equal(t, uuid3, value1.String())
52+
assert.Equal(t, uuid3, value2.String())
53+
}
54+
55+
func TestGenerateFailure(t *testing.T) {
56+
t.Parallel()
57+
58+
_, err := uuidv7test.NewTestUuidV7Generator("invalid")
59+
assert.Error(t, err)
60+
assert.Contains(t, err.Error(), "invalid UUID length: 7")
61+
62+
generator, err := uuidv7test.NewTestUuidV7Generator(uuid1)
63+
assert.NoError(t, err)
64+
65+
err = generator.SetValue("invalid")
66+
assert.Error(t, err)
67+
assert.Contains(t, err.Error(), "invalid UUID length: 7")
68+
}

generate/uuid/factory.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ type UuidGeneratorFactory interface {
99
type DefaultUuidGeneratorFactory struct{}
1010

1111
// NewDefaultUuidGeneratorFactory returns a [DefaultUuidGeneratorFactory], implementing [UuidGeneratorFactory].
12-
func NewDefaultUuidGeneratorFactory() UuidGeneratorFactory {
12+
func NewDefaultUuidGeneratorFactory() *DefaultUuidGeneratorFactory {
1313
return &DefaultUuidGeneratorFactory{}
1414
}
1515

generate/uuidv7/factory.go

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package uuidv7
2+
3+
// UuidV7GeneratorFactory is the interface for [UuidV7Generator] factories.
4+
type UuidV7GeneratorFactory interface {
5+
Create() UuidV7Generator
6+
}
7+
8+
// DefaultUuidV7GeneratorFactory is the default [UuidV7GeneratorFactory] implementation.
9+
type DefaultUuidV7GeneratorFactory struct{}
10+
11+
// NewDefaultUuidV7GeneratorFactory returns a [DefaultUuidV7GeneratorFactory], implementing [UuidV7GeneratorFactory].
12+
func NewDefaultUuidV7GeneratorFactory() UuidV7GeneratorFactory {
13+
return &DefaultUuidV7GeneratorFactory{}
14+
}
15+
16+
// Create returns a new [UuidV7Generator].
17+
func (g *DefaultUuidV7GeneratorFactory) Create() UuidV7Generator {
18+
return NewDefaultUuidV7Generator()
19+
}

generate/uuidv7/factory_test.go

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package uuidv7_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/ankorstore/yokai/generate/uuidv7"
7+
googleuuid "github.com/google/uuid"
8+
"github.com/stretchr/testify/assert"
9+
)
10+
11+
func TestNewDefaultUuidV7GeneratorFactory(t *testing.T) {
12+
t.Parallel()
13+
14+
factory := uuidv7.NewDefaultUuidV7GeneratorFactory()
15+
16+
assert.IsType(t, &uuidv7.DefaultUuidV7GeneratorFactory{}, factory)
17+
assert.Implements(t, (*uuidv7.UuidV7GeneratorFactory)(nil), factory)
18+
}
19+
20+
func TestCreate(t *testing.T) {
21+
t.Parallel()
22+
23+
generator := uuidv7.NewDefaultUuidV7GeneratorFactory().Create()
24+
25+
uuid1, err := generator.Generate()
26+
assert.NoError(t, err)
27+
28+
uuid2, err := generator.Generate()
29+
assert.NoError(t, err)
30+
31+
assert.NotEqual(t, uuid1, uuid2)
32+
33+
parsedValue1, err := googleuuid.Parse(uuid1.String())
34+
assert.NoError(t, err)
35+
36+
parsedValue2, err := googleuuid.Parse(uuid2.String())
37+
assert.NoError(t, err)
38+
39+
assert.NotEqual(t, parsedValue1.String(), parsedValue2.String())
40+
41+
assert.Equal(t, uuid1.String(), parsedValue1.String())
42+
assert.Equal(t, uuid2.String(), parsedValue2.String())
43+
}

generate/uuidv7/generator.go

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package uuidv7
2+
3+
import googleuuid "github.com/google/uuid"
4+
5+
// UuidV7Generator is the interface for UUID v7 generators.
6+
type UuidV7Generator interface {
7+
Generate() (googleuuid.UUID, error)
8+
}
9+
10+
// DefaultUuidV7Generator is the default [UuidGenerator] implementation.
11+
type DefaultUuidV7Generator struct{}
12+
13+
// NewDefaultUuidV7Generator returns a [DefaultUuidGenerator], implementing [UuidGenerator].
14+
func NewDefaultUuidV7Generator() *DefaultUuidV7Generator {
15+
return &DefaultUuidV7Generator{}
16+
}
17+
18+
// Generate returns a new UUID V7, using [Google UUID].
19+
//
20+
// [Google UUID]: https://github.com/google/uuid
21+
func (g *DefaultUuidV7Generator) Generate() (googleuuid.UUID, error) {
22+
return googleuuid.NewV7()
23+
}

generate/uuidv7/generator_test.go

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package uuidv7_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/ankorstore/yokai/generate/uuidv7"
7+
googleuuid "github.com/google/uuid"
8+
"github.com/stretchr/testify/assert"
9+
)
10+
11+
func TestNewDefaultUuidV7Generator(t *testing.T) {
12+
t.Parallel()
13+
14+
generator := uuidv7.NewDefaultUuidV7Generator()
15+
16+
assert.IsType(t, &uuidv7.DefaultUuidV7Generator{}, generator)
17+
assert.Implements(t, (*uuidv7.UuidV7Generator)(nil), generator)
18+
}
19+
20+
func TestGenerate(t *testing.T) {
21+
t.Parallel()
22+
23+
generator := uuidv7.NewDefaultUuidV7Generator()
24+
25+
uuid1, err := generator.Generate()
26+
assert.NoError(t, err)
27+
28+
uuid2, err := generator.Generate()
29+
assert.NoError(t, err)
30+
31+
assert.NotEqual(t, uuid1.String(), uuid2.String())
32+
33+
parsedUuid1, err := googleuuid.Parse(uuid1.String())
34+
assert.NoError(t, err)
35+
36+
parsedUuid2, err := googleuuid.Parse(uuid2.String())
37+
assert.NoError(t, err)
38+
39+
assert.NotEqual(t, parsedUuid1.String(), parsedUuid2.String())
40+
41+
assert.Equal(t, uuid1.String(), parsedUuid1.String())
42+
assert.Equal(t, uuid2.String(), parsedUuid2.String())
43+
}

0 commit comments

Comments
 (0)