Repository: bxcodec/faker
Pull request #77 (2019-10-10 13:01:20)

feat(faker): unique data generation
Refer to issue #76 

- Added a `unique` tag to generate unique data.
    - Call `ResetUnique()` after generating a dataset to forget all already generated values
- Added tests for the new feature
- Added unique support for `Lorem` generator as a proposal for the single fake data functions. My implementation is redundant. **Any feedback would be appreciated before implementing it to the other single fake data functions.**
    - Call `SetGenerateUniqueValues(true)` to enable unique data generation on single fake data functions
    - Call `SetGenerateUniqueValues(false)` to disable it
    - Call `ResetUnique()` to forget all already generated values

This change shouldn't break backwards compatibility.

TODO:

- [x] Update documentation
- [x] Implement unique handling in all single fake data functions


bxcodec: Any updates on this PR @System-Glitch 
System-Glitch: @bxcodec Well I was waiting for feedback on the single fake data functions before continuing.
System-Glitch: ```go    
if generateUniqueValues {
	v, err := generateUnique(PARAGRAPH, func() interface{} {
		return i.paragraph()
	})
	if err != nil {
		panic(err)
	}
	return v.(string)
}
```
This part is redundant. It has to be there for every single fake data function. Maybe you have an idea to make it better?

I though about another function to factor this.
```go
func singleUnique(dataType string, fn func() interface{}) (interface{}, error) {
	v, err := generateUnique(dataType, fn)
	if err != nil {
		panic(err)
	}
	return v
}
```
That would shorten a single fake data function like this.
```go    
func Word() string {
	i := Lorem{}
	if generateUniqueValues {
		return singleUnique(WORD, func() interface{} {
			return i.paragraph()
		}).(string)
	}

	return i.word()
}
```
System-Glitch: PR is ready to be merged.
bxcodec: Thanks for the PR @System-Glitch  👍 

Patch:
diff --git a/README.md b/README.md
index e571257..ab54382 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@
 
 Struct Data Fake Generator
 
-Faker  will generate you a fake data based on your Struct.
+Faker will generate you a fake data based on your Struct.
 
 [![Build Status](https://travis-ci.org/bxcodec/faker.svg?branch=master)](https://travis-ci.org/bxcodec/faker)
 [![codecov](https://codecov.io/gh/bxcodec/faker/branch/master/graph/badge.svg)](https://codecov.io/gh/bxcodec/faker)
diff --git a/SingleFakeData.md b/SingleFakeData.md
index ba17e39..90457de 100644
--- a/SingleFakeData.md
+++ b/SingleFakeData.md
@@ -84,6 +84,7 @@ faker.Name()				// => Mrs. Casandra Kiehn
 ---
 
 ```go
+faker.Phonenumber() // -> 201-886-0269
 faker.TollFreePhoneNumber() // => (777) 831-964572
 faker.E164PhoneNumber()		// => +724891571063
 ```
@@ -97,3 +98,14 @@ faker.UUIDHyphenated()		// => 8f8e4463-9560-4a38-9b0c-ef24481e4e27
 faker.UUIDDigit()			// => 90ea6479fd0e4940af741f0a87596b73
 ```
 
+### Unique values
+
+---
+
+```go
+faker.SetGenerateUniqueValues(true) // Enable unique data generation on single fake data functions
+faker.Word()
+//...
+faker.SetGenerateUniqueValues(false) // Disable unique data generation on single fake data functions
+faker.ResetUnique() // Forget all generated unique values
+```
diff --git a/WithStructTag.md b/WithStructTag.md
index ce9d073..a89d661 100644
--- a/WithStructTag.md
+++ b/WithStructTag.md
@@ -64,6 +64,9 @@ Supported tag:
 **Skip :**
 * \-
 
+**Unique :**
+* unique
+
 ```go
 
 package main
@@ -272,3 +275,24 @@ Result:
     MIint:map[7:7 5:7 8:8 9:5 6:5]
 }
 ```
+## Unique values
+
+```go
+// SomeStruct ...
+type SomeStruct struct {
+	Word string `faker:"word,unique"`
+}
+
+func main() {
+
+	for i := 0 ; i < 5 ; i++ { // Generate 5 structs having a unique word
+		a := SomeStruct{}
+		err := faker.FakeData(&a)
+		if err != nil {
+			fmt.Println(err)
+		}
+		fmt.Printf("%+v", a)
+	}
+	faker.ResetUnique() // Forget all generated unique values. Allows to start generating another unrelated dataset.
+}
+```
\ No newline at end of file
diff --git a/address.go b/address.go
index 6ef4b3d..340bb94 100644
--- a/address.go
+++ b/address.go
@@ -32,14 +32,14 @@ type Addresser interface {
 // Address struct
 type Address struct{}
 
-func (i Address) latitute() float32 {
+func (i Address) latitude() float32 {
 	return (rand.Float32() * 180) - 90
 }
 
 // Latitude sets latitude of the address
 func (i Address) Latitude(v reflect.Value) (interface{}, error) {
 	kind := v.Kind()
-	val := i.latitute()
+	val := i.latitude()
 	if kind == reflect.Float32 {
 		return val, nil
 	}
@@ -62,12 +62,16 @@ func (i Address) Longitude(v reflect.Value) (interface{}, error) {
 
 // Longitude get fake longitude randomly
 func Longitude() float64 {
-	address := Address{}
-	return float64(address.longitude())
+	return singleFakeData(LONGITUDE, func() interface{} {
+		address := Address{}
+		return float64(address.longitude())
+	}).(float64)
 }
 
 // Latitude get fake latitude randomly
 func Latitude() float64 {
-	address := Address{}
-	return float64(address.latitute())
+	return singleFakeData(LATITUDE, func() interface{} {
+		address := Address{}
+		return float64(address.latitude())
+	}).(float64)
 }
diff --git a/datetime.go b/datetime.go
index b8615c0..448c2d6 100644
--- a/datetime.go
+++ b/datetime.go
@@ -661,8 +661,10 @@ func (d DateTime) UnixTime(v reflect.Value) (interface{}, error) {
 
 // UnixTime get unix time randomly
 func UnixTime() int64 {
-	datetime := DateTime{}
-	return datetime.unixtime()
+	return singleFakeData(UnixTimeTag, func() interface{} {
+		datetime := DateTime{}
+		return datetime.unixtime()
+	}).(int64)
 }
 
 func (d DateTime) date() string {
@@ -676,8 +678,10 @@ func (d DateTime) Date(v reflect.Value) (interface{}, error) {
 
 // Date get fake date in string randomly
 func Date() string {
-	datetime := DateTime{}
-	return datetime.date()
+	return singleFakeData(DATE, func() interface{} {
+		datetime := DateTime{}
+		return datetime.date()
+	}).(string)
 }
 
 func (d DateTime) time() string {
@@ -691,8 +695,10 @@ func (d DateTime) Time(v reflect.Value) (interface{}, error) {
 
 // TimeString get time randomly in string format
 func TimeString() string {
-	datetime := DateTime{}
-	return datetime.time()
+	return singleFakeData(TIME, func() interface{} {
+		datetime := DateTime{}
+		return datetime.time()
+	}).(string)
 }
 
 func (d DateTime) monthName() string {
@@ -706,8 +712,10 @@ func (d DateTime) MonthName(v reflect.Value) (interface{}, error) {
 
 // MonthName get month name randomly in string format
 func MonthName() string {
-	datetime := DateTime{}
-	return datetime.monthName()
+	return singleFakeData(MonthNameTag, func() interface{} {
+		datetime := DateTime{}
+		return datetime.monthName()
+	}).(string)
 }
 
 func (d DateTime) year() string {
@@ -721,8 +729,10 @@ func (d DateTime) Year(v reflect.Value) (interface{}, error) {
 
 // YearString get year randomly in string format
 func YearString() string {
-	datetime := DateTime{}
-	return datetime.year()
+	return singleFakeData(YEAR, func() interface{} {
+		datetime := DateTime{}
+		return datetime.year()
+	}).(string)
 }
 
 func (d DateTime) dayOfWeek() string {
@@ -736,8 +746,10 @@ func (d DateTime) DayOfWeek(v reflect.Value) (interface{}, error) {
 
 // DayOfWeek get day of week randomly in string format
 func DayOfWeek() string {
-	datetime := DateTime{}
-	return datetime.dayOfWeek()
+	return singleFakeData(DayOfWeekTag, func() interface{} {
+		datetime := DateTime{}
+		return datetime.dayOfWeek()
+	}).(string)
 }
 
 func (d DateTime) dayOfMonth() string {
@@ -751,8 +763,10 @@ func (d DateTime) DayOfMonth(v reflect.Value) (interface{}, error) {
 
 // DayOfMonth get month randomly in string format
 func DayOfMonth() string {
-	datetime := DateTime{}
-	return datetime.dayOfMonth()
+	return singleFakeData(DayOfMonthTag, func() interface{} {
+		datetime := DateTime{}
+		return datetime.dayOfMonth()
+	}).(string)
 }
 
 func (d DateTime) timestamp() string {
@@ -766,8 +780,10 @@ func (d DateTime) Timestamp(v reflect.Value) (interface{}, error) {
 
 // Timestamp get timestamp randomly in string format: 2006-01-02 15:04:05
 func Timestamp() string {
-	datetime := DateTime{}
-	return datetime.timestamp()
+	return singleFakeData(TIMESTAMP, func() interface{} {
+		datetime := DateTime{}
+		return datetime.timestamp()
+	}).(string)
 }
 
 func (d DateTime) century() string {
@@ -781,8 +797,10 @@ func (d DateTime) Century(v reflect.Value) (interface{}, error) {
 
 // Century get century randomly in string
 func Century() string {
-	datetime := DateTime{}
-	return datetime.century()
+	return singleFakeData(CENTURY, func() interface{} {
+		datetime := DateTime{}
+		return datetime.century()
+	}).(string)
 }
 
 func (d DateTime) timezone() string {
@@ -796,8 +814,10 @@ func (d DateTime) TimeZone(v reflect.Value) (interface{}, error) {
 
 // Timezone get timezone randomly in string
 func Timezone() string {
-	datetime := DateTime{}
-	return datetime.timezone()
+	return singleFakeData(TIMEZONE, func() interface{} {
+		datetime := DateTime{}
+		return datetime.timezone()
+	}).(string)
 }
 
 func (d DateTime) period() string {
@@ -811,8 +831,10 @@ func (d DateTime) TimePeriod(v reflect.Value) (interface{}, error) {
 
 // Timeperiod get timeperiod randomly in string (AM/PM)
 func Timeperiod() string {
-	datetime := DateTime{}
-	return datetime.period()
+	return singleFakeData(TimePeriodTag, func() interface{} {
+		datetime := DateTime{}
+		return datetime.period()
+	}).(string)
 }
 
 // RandomUnixTime is a helper function returning random Unix time
diff --git a/faker.go b/faker.go
index e71714b..42f280d 100644
--- a/faker.go
+++ b/faker.go
@@ -11,6 +11,8 @@ import (
 	"strings"
 	"sync"
 	"time"
+
+	"github.com/bxcodec/faker/v3/support/slice"
 )
 
 var (
@@ -25,6 +27,10 @@ var (
 	nBoundary = numberBoundary{start: 0, end: 100}
 	//Sets the random size for slices and maps.
 	randomSize = 100
+	// Sets the single fake data generator to generate unique values
+	generateUniqueValues = false
+	// Unique values are kept in memory so the generator retries if the value already exists
+	uniqueValues = map[string][]interface{}{}
 )
 
 type numberBoundary struct {
@@ -37,9 +43,11 @@ const (
 	letterIdxBits         = 6                    // 6 bits to represent a letter index
 	letterIdxMask         = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
 	letterIdxMax          = 63 / letterIdxBits   // # of letter indices fitting in 63 bits
+	maxRetry              = 10000                // max number of retry for unique values
 	letterBytes           = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
 	tagName               = "faker"
 	keep                  = "keep"
+	unique                = "unique"
 	ID                    = "uuid_digit"
 	HyphenatedID          = "uuid_hyphenated"
 	EmailTag              = "email"
@@ -198,6 +206,7 @@ var (
 	ErrMoreArguments       = "Passed more arguments than is possible : (%d)"
 	ErrNotSupportedPointer = "Use sample:=new(%s)\n faker.FakeData(sample) instead"
 	ErrSmallerThanZero     = "Size:%d is smaller than zero."
+	ErrUniqueFailure       = "Failed to generate a unique value for field \"%s\""
 
 	ErrStartValueBiggerThanEnd = "Start value can not be bigger than end value."
 	ErrWrongFormattedTag       = "Tag \"%s\" is not written properly"
@@ -209,6 +218,17 @@ func init() {
 	rand.Seed(time.Now().UnixNano())
 }
 
+// ResetUnique is used to forget generated unique values.
+// Call this when you're done generating a dataset.
+func ResetUnique() {
+	uniqueValues = map[string][]interface{}{}
+}
+
+// SetGenerateUniqueValues allows to set the single fake data generator functions to generate unique data.
+func SetGenerateUniqueValues(unique bool) {
+	generateUniqueValues = unique
+}
+
 // SetNilIfLenIsZero allows to set nil for the slice and maps, if size is 0.
 func SetNilIfLenIsZero(setNil bool) {
 	shouldSetNil = setNil
@@ -352,6 +372,7 @@ func getValue(a interface{}) (reflect.Value, error) {
 		default:
 			originalDataVal := reflect.ValueOf(a)
 			v := reflect.New(t).Elem()
+			retry := 0 // error if cannot generate unique value after maxRetry tries
 			for i := 0; i < v.NumField(); i++ {
 				if !v.Field(i).CanSet() {
 					continue // to avoid panic to set on unexported field in struct
@@ -390,6 +411,24 @@ func getValue(a interface{}) (reflect.Value, error) {
 					}
 				}
 
+				if tags.unique {
+
+					if retry >= maxRetry {
+						return reflect.Value{}, fmt.Errorf(ErrUniqueFailure, reflect.TypeOf(a).Field(i).Name)
+					}
+
+					value := v.Field(i).Interface()
+					if slice.ContainsValue(uniqueValues[tags.fieldType], value) { // Retry if unique value already found
+						i--
+						retry++
+						continue
+					}
+					retry = 0
+					uniqueValues[tags.fieldType] = append(uniqueValues[tags.fieldType], value)
+				} else {
+					retry = 0
+				}
+
 			}
 			return v, nil
 		}
@@ -489,23 +528,29 @@ func decodeTags(typ reflect.Type, i int) structTag {
 	tags := strings.Split(typ.Field(i).Tag.Get(tagName), ",")
 
 	keepOriginal := false
+	uni := false
 	res := make([]string, 0)
 	for _, tag := range tags {
 		if tag == keep {
 			keepOriginal = true
 			continue
+		} else if tag == unique {
+			uni = true
+			continue
 		}
 		res = append(res, tag)
 	}
 
 	return structTag{
 		fieldType:    strings.Join(res, ","),
+		unique:       uni,
 		keepOriginal: keepOriginal,
 	}
 }
 
 type structTag struct {
 	fieldType    string
+	unique       bool
 	keepOriginal bool
 }
 
@@ -821,3 +866,25 @@ func RandomInt(parameters ...int) (p []int, err error) {
 	}
 	return p, err
 }
+
+func generateUnique(dataType string, fn func() interface{}) (interface{}, error) {
+	for i := 0; i < maxRetry; i++ {
+		value := fn()
+		if !slice.ContainsValue(uniqueValues[dataType], value) { // Retry if unique value already found
+			uniqueValues[dataType] = append(uniqueValues[dataType], value)
+			return value, nil
+		}
+	}
+	return reflect.Value{}, fmt.Errorf(ErrUniqueFailure, dataType)
+}
+
+func singleFakeData(dataType string, fn func() interface{}) interface{} {
+	if generateUniqueValues {
+		v, err := generateUnique(dataType, fn)
+		if err != nil {
+			panic(err)
+		}
+		return v
+	}
+	return fn()
+}
diff --git a/internet.go b/internet.go
index a9ac2b2..ffc96e1 100644
--- a/internet.go
+++ b/internet.go
@@ -67,8 +67,10 @@ func (internet Internet) Email(v reflect.Value) (interface{}, error) {
 
 // Email get email randomly in string
 func Email() string {
-	i := Internet{}
-	return i.email()
+	return singleFakeData(EmailTag, func() interface{} {
+		i := Internet{}
+		return i.email()
+	}).(string)
 }
 
 func (internet Internet) macAddress() string {
@@ -86,8 +88,10 @@ func (internet Internet) MacAddress(v reflect.Value) (interface{}, error) {
 
 // MacAddress get mac address randomly in string
 func MacAddress() string {
-	i := Internet{}
-	return i.macAddress()
+	return singleFakeData(MacAddressTag, func() interface{} {
+		i := Internet{}
+		return i.macAddress()
+	}).(string)
 }
 
 func (internet Internet) domainName() string {
@@ -101,8 +105,10 @@ func (internet Internet) DomainName(v reflect.Value) (interface{}, error) {
 
 // DomainName get email domain name in string
 func DomainName() string {
-	i := Internet{}
-	return i.domainName()
+	return singleFakeData(DomainNameTag, func() interface{} {
+		i := Internet{}
+		return i.domainName()
+	}).(string)
 }
 
 func (internet Internet) url() string {
@@ -121,8 +127,10 @@ func (internet Internet) URL(v reflect.Value) (interface{}, error) {
 
 // URL get Url randomly in string
 func URL() string {
-	i := Internet{}
-	return i.url()
+	return singleFakeData(URLTag, func() interface{} {
+		i := Internet{}
+		return i.url()
+	}).(string)
 }
 
 func (internet Internet) username() string {
@@ -136,8 +144,10 @@ func (internet Internet) UserName(v reflect.Value) (interface{}, error) {
 
 // Username get username randomly in string
 func Username() string {
-	i := Internet{}
-	return i.username()
+	return singleFakeData(UserNameTag, func() interface{} {
+		i := Internet{}
+		return i.username()
+	}).(string)
 }
 
 func (internet Internet) ipv4() string {
@@ -156,8 +166,10 @@ func (internet Internet) IPv4(v reflect.Value) (interface{}, error) {
 
 // IPv4 get IPv4 randomly in string
 func IPv4() string {
-	i := Internet{}
-	return i.ipv4()
+	return singleFakeData(IPV4Tag, func() interface{} {
+		i := Internet{}
+		return i.ipv4()
+	}).(string)
 }
 
 func (internet Internet) ipv6() string {
@@ -176,8 +188,10 @@ func (internet Internet) IPv6(v reflect.Value) (interface{}, error) {
 
 // IPv6 get IPv6 randomly in string
 func IPv6() string {
-	i := Internet{}
-	return i.ipv6()
+	return singleFakeData(IPV6Tag, func() interface{} {
+		i := Internet{}
+		return i.ipv6()
+	}).(string)
 }
 
 func (internet Internet) password() string {
@@ -191,6 +205,8 @@ func (internet Internet) Password(v reflect.Value) (interface{}, error) {
 
 // Password get password randomly in string
 func Password() string {
-	i := Internet{}
-	return i.password()
+	return singleFakeData(PASSWORD, func() interface{} {
+		i := Internet{}
+		return i.password()
+	}).(string)
 }
diff --git a/lorem.go b/lorem.go
index c5e099a..8ce2342 100644
--- a/lorem.go
+++ b/lorem.go
@@ -87,7 +87,9 @@ func (l Lorem) Word(v reflect.Value) (interface{}, error) {
 // Word get a word randomly in string
 func Word() string {
 	i := Lorem{}
-	return i.word()
+	return singleFakeData(WORD, func() interface{} {
+		return i.word()
+	}).(string)
 }
 
 func (l Lorem) sentence() string {
@@ -116,7 +118,9 @@ func (l Lorem) Sentence(v reflect.Value) (interface{}, error) {
 // Sentence get a sentence randomly in string
 func Sentence() string {
 	i := Lorem{}
-	return i.sentence()
+	return singleFakeData(SENTENCE, func() interface{} {
+		return i.sentence()
+	}).(string)
 }
 
 func (l Lorem) paragraph() string {
@@ -139,5 +143,7 @@ func (l Lorem) Paragraph(v reflect.Value) (interface{}, error) {
 // Paragraph get a paragraph randomly in string
 func Paragraph() string {
 	i := Lorem{}
-	return i.paragraph()
+	return singleFakeData(PARAGRAPH, func() interface{} {
+		return i.paragraph()
+	}).(string)
 }
diff --git a/payment.go b/payment.go
index 37927d8..5625464 100644
--- a/payment.go
+++ b/payment.go
@@ -78,8 +78,10 @@ func (p Payment) CreditCardType(v reflect.Value) (interface{}, error) {
 
 // CCType get a credit card type randomly in string (VISA, MasterCard, etc)
 func CCType() string {
-	p := Payment{}
-	return p.cctype()
+	return singleFakeData(CreditCardType, func() interface{} {
+		p := Payment{}
+		return p.cctype()
+	}).(string)
 }
 
 func (p Payment) ccnumber() string {
@@ -102,6 +104,8 @@ func (p Payment) CreditCardNumber(v reflect.Value) (interface{}, error) {
 
 // CCNumber get a credit card number randomly in string (VISA, MasterCard, etc)
 func CCNumber() string {
-	p := Payment{}
-	return p.ccnumber()
+	return singleFakeData(CreditCardNumber, func() interface{} {
+		p := Payment{}
+		return p.ccnumber()
+	}).(string)
 }
diff --git a/person.go b/person.go
index f09f3d4..5b4b650 100644
--- a/person.go
+++ b/person.go
@@ -139,8 +139,10 @@ func (p Person) TitleMale(v reflect.Value) (interface{}, error) {
 
 // TitleMale get a title male randomly in string ("Mr.", "Dr.", "Prof.", "Lord", "King", "Prince")
 func TitleMale() string {
-	p := Person{}
-	return p.titlemale()
+	return singleFakeData(TitleMaleTag, func() interface{} {
+		p := Person{}
+		return p.titlemale()
+	}).(string)
 }
 
 func (p Person) titleFemale() string {
@@ -154,8 +156,10 @@ func (p Person) TitleFeMale(v reflect.Value) (interface{}, error) {
 
 // TitleFemale get a title female randomly in string ("Mrs.", "Ms.", "Miss", "Dr.", "Prof.", "Lady", "Queen", "Princess")
 func TitleFemale() string {
-	p := Person{}
-	return p.titleFemale()
+	return singleFakeData(TitleFemaleTag, func() interface{} {
+		p := Person{}
+		return p.titleFemale()
+	}).(string)
 }
 
 func (p Person) firstname() string {
@@ -169,8 +173,10 @@ func (p Person) FirstName(v reflect.Value) (interface{}, error) {
 
 // FirstName get fake firstname
 func FirstName() string {
-	p := Person{}
-	return p.firstname()
+	return singleFakeData(FirstNameTag, func() interface{} {
+		p := Person{}
+		return p.firstname()
+	}).(string)
 }
 
 func (p Person) firstnamemale() string {
@@ -184,8 +190,10 @@ func (p Person) FirstNameMale(v reflect.Value) (interface{}, error) {
 
 // FirstNameMale get fake firstname for male
 func FirstNameMale() string {
-	p := Person{}
-	return p.firstnamemale()
+	return singleFakeData(FirstNameMaleTag, func() interface{} {
+		p := Person{}
+		return p.firstnamemale()
+	}).(string)
 }
 
 func (p Person) firstnamefemale() string {
@@ -199,8 +207,10 @@ func (p Person) FirstNameFemale(v reflect.Value) (interface{}, error) {
 
 // FirstNameFemale get fake firstname for female
 func FirstNameFemale() string {
-	p := Person{}
-	return p.firstnamefemale()
+	return singleFakeData(FirstNameFemaleTag, func() interface{} {
+		p := Person{}
+		return p.firstnamefemale()
+	}).(string)
 }
 
 func (p Person) lastname() string {
@@ -214,8 +224,10 @@ func (p Person) LastName(v reflect.Value) (interface{}, error) {
 
 // LastName get fake lastname
 func LastName() string {
-	p := Person{}
-	return p.lastname()
+	return singleFakeData(LastNameTag, func() interface{} {
+		p := Person{}
+		return p.lastname()
+	}).(string)
 }
 
 func (p Person) name() string {
@@ -232,6 +244,8 @@ func (p Person) Name(v reflect.Value) (interface{}, error) {
 
 // Name get fake name
 func Name() string {
-	p := Person{}
-	return p.name()
+	return singleFakeData(NAME, func() interface{} {
+		p := Person{}
+		return p.name()
+	}).(string)
 }
diff --git a/phone.go b/phone.go
index 6ff08cf..3c20383 100644
--- a/phone.go
+++ b/phone.go
@@ -51,8 +51,10 @@ func (p Phone) PhoneNumber(v reflect.Value) (interface{}, error) {
 
 // Phonenumber get fake phone number
 func Phonenumber() string {
-	p := Phone{}
-	return p.phonenumber()
+	return singleFakeData(PhoneNumber, func() interface{} {
+		p := Phone{}
+		return p.phonenumber()
+	}).(string)
 }
 
 func (p Phone) tollfreephonenumber() string {
@@ -76,8 +78,10 @@ func (p Phone) TollFreePhoneNumber(v reflect.Value) (interface{}, error) {
 
 // TollFreePhoneNumber get fake TollFreePhoneNumber
 func TollFreePhoneNumber() string {
-	p := Phone{}
-	return p.tollfreephonenumber()
+	return singleFakeData(TollFreeNumber, func() interface{} {
+		p := Phone{}
+		return p.tollfreephonenumber()
+	}).(string)
 }
 
 func (p Phone) e164PhoneNumber() string {
@@ -98,6 +102,8 @@ func (p Phone) E164PhoneNumber(v reflect.Value) (interface{}, error) {
 
 // E164PhoneNumber get fake E164PhoneNumber
 func E164PhoneNumber() string {
-	p := Phone{}
-	return p.e164PhoneNumber()
+	return singleFakeData(E164PhoneNumberTag, func() interface{} {
+		p := Phone{}
+		return p.e164PhoneNumber()
+	}).(string)
 }
diff --git a/price.go b/price.go
index 04fe01f..71641fa 100644
--- a/price.go
+++ b/price.go
@@ -71,8 +71,10 @@ func (p Price) Currency(v reflect.Value) (interface{}, error) {
 
 // Currency get fake Currency (IDR, USD)
 func Currency() string {
-	p := Price{}
-	return p.currency()
+	return singleFakeData(CurrencyTag, func() interface{} {
+		p := Price{}
+		return p.currency()
+	}).(string)
 }
 
 func (p Price) amount() float64 {
@@ -104,8 +106,10 @@ func (p Price) AmountWithCurrency(v reflect.Value) (interface{}, error) {
 
 // AmountWithCurrency get fake AmountWithCurrency  USD 49257.100
 func AmountWithCurrency() string {
-	p := Price{}
-	return p.amountwithcurrency()
+	return singleFakeData(AmountWithCurrencyTag, func() interface{} {
+		p := Price{}
+		return p.amountwithcurrency()
+	}).(string)
 }
 
 // precision | a helper function to set precision of price
diff --git a/support/slice/helpers.go b/support/slice/helpers.go
index ab21e96..1a28ddf 100644
--- a/support/slice/helpers.go
+++ b/support/slice/helpers.go
@@ -15,6 +15,16 @@ func Contains(slice []string, item string) bool {
 	return ok
 }
 
+// ContainsValue check if value exists in slice, no matter its type
+func ContainsValue(slice []interface{}, value interface{}) bool {
+	for _, v := range slice {
+		if v == value {
+			return true
+		}
+	}
+	return false
+}
+
 // IntToString Convert slice int to slice string
 func IntToString(intSl []int) (str []string) {
 	for i := range intSl {
diff --git a/uuid.go b/uuid.go
index 49b5c15..3009c4a 100644
--- a/uuid.go
+++ b/uuid.go
@@ -59,9 +59,11 @@ func (u UUID) Hyphenated(v reflect.Value) (interface{}, error) {
 
 // UUIDHyphenated get fake Hyphenated UUID
 func UUIDHyphenated() string {
-	u := UUID{}
-	res, _ := u.hyphenated()
-	return res
+	return singleFakeData(HyphenatedID, func() interface{} {
+		u := UUID{}
+		res, _ := u.hyphenated()
+		return res
+	}).(string)
 }
 
 func (u UUID) digit() (string, error) {
@@ -80,7 +82,9 @@ func (u UUID) Digit(v reflect.Value) (interface{}, error) {
 
 // UUIDDigit get fake Digit UUID
 func UUIDDigit() string {
-	u := UUID{}
-	res, _ := u.digit()
-	return res
+	return singleFakeData(ID, func() interface{} {
+		u := UUID{}
+		res, _ := u.digit()
+		return res
+	}).(string)
 }


Test patch:
diff --git a/faker_test.go b/faker_test.go
index 3762b73..cc02748 100644
--- a/faker_test.go
+++ b/faker_test.go
@@ -920,7 +920,6 @@ func TestItThrowsAnErrorWhenKeepIsUsedOnIncomparableType(t *testing.T) {
 	withSlice := TypeStructWithSlice{}
 	withArray := TypeStructWithArray{}
 
-
 	for _, item := range []interface{}{withArray, withStruct, withSlice} {
 		err := FakeData(&item)
 		if err == nil {
@@ -954,3 +953,68 @@ func TestItThrowsAnErrorWhenZeroValueWithKeepAndUnsupportedTagIsUsed(t *testing.
 		t.Errorf("expected error, but got nil")
 	}
 }
+
+func TestUnique(t *testing.T) {
+	type UniqueStruct struct {
+		StringVal string `faker:"word,unique"`
+		IntVal    int    `faker:"unique"`
+	}
+
+	for i := 0; i < 50; i++ {
+		val := UniqueStruct{}
+		FakeData(&val)
+	}
+
+	found := []interface{}{}
+	for _, v := range uniqueValues["word"] {
+		for _, f := range found {
+			if f == v {
+				t.Errorf("expected unique values, found \"%s\" at least twice", v)
+				ResetUnique()
+				return
+			}
+		}
+		found = append(found, v)
+	}
+
+	ResetUnique()
+}
+
+func TestUniqueReset(t *testing.T) {
+	type String struct {
+		StringVal string `faker:"word,unique"`
+	}
+
+	for i := 0; i < 20; i++ {
+		val := String{}
+		FakeData(&val)
+	}
+
+	ResetUnique()
+	length := len(uniqueValues)
+	if length > 0 {
+		t.Errorf("expected empty uniqueValues map, but got a length of %d", length)
+	}
+}
+
+func TestUniqueFailure(t *testing.T) {
+	type String struct {
+		StringVal string `faker:"word,unique"`
+	}
+
+	hasError := false
+	length := len(wordList) + 1
+	for i := 0; i < length; i++ {
+		val := String{}
+		err := FakeData(&val)
+		if err != nil {
+			hasError = true
+			break
+		}
+	}
+
+	ResetUnique()
+	if !hasError {
+		t.Errorf("expected error, but got nil")
+	}
+}
diff --git a/lorem_test.go b/lorem_test.go
index 46247dc..6416a4a 100644
--- a/lorem_test.go
+++ b/lorem_test.go
@@ -66,3 +66,51 @@ func TestFakeParagraph(t *testing.T) {
 		t.Error("Expected paragraph")
 	}
 }
+
+func TestUniqueWord(t *testing.T) {
+	SetGenerateUniqueValues(true)
+	word := Word()
+	ResetUnique()
+	SetGenerateUniqueValues(false)
+	if !slice.Contains(wordList, word) {
+		t.Error("Expected word from slice wordList")
+	}
+}
+
+func TestUniqueWordPanic(t *testing.T) {
+	defer func() {
+		if r := recover(); r == nil {
+			t.Errorf("expected panic, but didn't")
+		}
+		ResetUnique()
+		SetGenerateUniqueValues(false)
+	}()
+
+	SetGenerateUniqueValues(true)
+	length := len(wordList) + 1
+	for i := 0; i < length; i++ {
+		Word()
+	}
+	ResetUnique()
+	SetGenerateUniqueValues(false)
+}
+
+func TestUniqueSentence(t *testing.T) {
+	SetGenerateUniqueValues(true)
+	res := Sentence()
+	ResetUnique()
+	SetGenerateUniqueValues(false)
+	if res == "" || !strings.HasSuffix(res, ".") {
+		t.Error("Expected sentence")
+	}
+}
+
+func TestUniqueParagraph(t *testing.T) {
+	SetGenerateUniqueValues(true)
+	res := Paragraph()
+	ResetUnique()
+	SetGenerateUniqueValues(false)
+	if res == "" || !strings.HasSuffix(res, ".") {
+		t.Error("Expected paragraph")
+	}
+}