niki/vendor/github.com/brianvoe/gofakeit/v6/lookup.go

512 lines
12 KiB
Go
Raw Normal View History

2024-04-26 19:30:35 +00:00
package gofakeit
import (
"encoding/json"
"fmt"
"math/rand"
"reflect"
"strconv"
"strings"
"sync"
)
// FuncLookups is the primary map array with mapping to all available data
var FuncLookups map[string]Info
var lockFuncLookups sync.Mutex
// MapParams is the values to pass into a lookup generate
type MapParams map[string]MapParamsValue
type MapParamsValue []string
// Info structures fields to better break down what each one generates
type Info struct {
Display string `json:"display"`
Category string `json:"category"`
Description string `json:"description"`
Example string `json:"example"`
Output string `json:"output"`
ContentType string `json:"content_type"`
Params []Param `json:"params"`
Any any `json:"any"`
Generate func(r *rand.Rand, m *MapParams, info *Info) (any, error) `json:"-"`
}
// Param is a breakdown of param requirements and type definition
type Param struct {
Field string `json:"field"`
Display string `json:"display"`
Type string `json:"type"`
Optional bool `json:"optional"`
Default string `json:"default"`
Options []string `json:"options"`
Description string `json:"description"`
}
// Field is used for defining what name and function you to generate for file outuputs
type Field struct {
Name string `json:"name"`
Function string `json:"function"`
Params MapParams `json:"params"`
}
func init() { initLookup() }
// init will add all the functions to MapLookups
func initLookup() {
addAddressLookup()
addAnimalLookup()
addAppLookup()
addAuthLookup()
addBeerLookup()
addBookLookup()
addCarLookup()
addCelebrityLookup()
addColorLookup()
addCompanyLookup()
addDatabaseSQLLookup()
addDateTimeLookup()
addEmojiLookup()
addErrorLookup()
addFileCSVLookup()
addFileJSONLookup()
addFileLookup()
addFileXMLLookup()
addFinanceLookup()
addFoodLookup()
addGameLookup()
addGenerateLookup()
addHackerLookup()
addHipsterLookup()
addHtmlLookup()
addImageLookup()
addInternetLookup()
addLanguagesLookup()
addLoremLookup()
addMinecraftLookup()
addMiscLookup()
addMovieLookup()
addNumberLookup()
addPaymentLookup()
addPersonLookup()
addProductLookup()
addSchoolLookup()
addStringLookup()
addTemplateLookup()
addWeightedLookup()
addWordAdjectiveLookup()
addWordAdverbLookup()
addWordConnectiveLookup()
addWordGeneralLookup()
addWordGrammerLookup()
addWordNounLookup()
addWordPhraseLookup()
addWordPrepositionLookup()
addWordPronounLookup()
addWordSentenceLookup()
addWordVerbLookup()
addWordCommentLookup()
addWordMiscLookup()
}
// internalFuncLookups is the internal map array with mapping to all available data
var internalFuncLookups map[string]Info = map[string]Info{
"fields": {
Description: "Example fields for generating csv, json, xml, etc",
Output: "gofakeit.Field",
Generate: func(r *rand.Rand, m *MapParams, info *Info) (any, error) {
function, _ := GetRandomSimpleFunc(r)
return Field{
Name: function,
Function: function,
}, nil
},
},
}
// NewMapParams will create a new MapParams
func NewMapParams() *MapParams {
return &MapParams{}
}
// Add will take in a field and value and add it to the map params type
func (m *MapParams) Add(field string, value string) {
_, ok := (*m)[field]
if !ok {
(*m)[field] = []string{value}
return
}
(*m)[field] = append((*m)[field], value)
}
// Get will return the array of string from the provided field
func (m *MapParams) Get(field string) []string {
return (*m)[field]
}
// Size will return the total size of the underlying map
func (m *MapParams) Size() int {
size := 0
for range *m {
size++
}
return size
}
// UnmarshalJSON will unmarshal the json into the []string
func (m *MapParamsValue) UnmarshalJSON(data []byte) error {
// check if the data is an array
// if so, marshal it into m
if data[0] == '[' {
var values []any
err := json.Unmarshal(data, &values)
if err != nil {
return err
}
// convert the values to array of strings
for _, value := range values {
typeOf := reflect.TypeOf(value).Kind().String()
if typeOf == "map" {
v, err := json.Marshal(value)
if err != nil {
return err
}
*m = append(*m, string(v))
} else {
*m = append(*m, fmt.Sprintf("%v", value))
}
}
return nil
}
// if not, then convert into a string and add it to m
var s any
if err := json.Unmarshal(data, &s); err != nil {
return err
}
*m = append(*m, fmt.Sprintf("%v", s))
return nil
}
func GetRandomSimpleFunc(r *rand.Rand) (string, Info) {
// Loop through all the functions and add them to a slice
var keys []string
for k, info := range FuncLookups {
// Only grab simple functions
if info.Params == nil {
keys = append(keys, k)
}
}
// Randomly grab a function from the slice
randomKey := randomString(r, keys)
// Return the function name and info
return randomKey, FuncLookups[randomKey]
}
// AddFuncLookup takes a field and adds it to map
func AddFuncLookup(functionName string, info Info) {
if FuncLookups == nil {
FuncLookups = make(map[string]Info)
}
// Check content type
if info.ContentType == "" {
info.ContentType = "text/plain"
}
lockFuncLookups.Lock()
FuncLookups[functionName] = info
lockFuncLookups.Unlock()
}
// GetFuncLookup will lookup
func GetFuncLookup(functionName string) *Info {
var info Info
var ok bool
// Check internal functions first
info, ok = internalFuncLookups[functionName]
if ok {
return &info
}
info, ok = FuncLookups[functionName]
if ok {
return &info
}
return nil
}
// RemoveFuncLookup will remove a function from lookup
func RemoveFuncLookup(functionName string) {
_, ok := FuncLookups[functionName]
if !ok {
return
}
lockFuncLookups.Lock()
delete(FuncLookups, functionName)
lockFuncLookups.Unlock()
}
// GetAny will retrieve Any field from Info
func (i *Info) GetAny(m *MapParams, field string) (any, error) {
_, value, err := i.GetField(m, field)
if err != nil {
return nil, err
}
var anyValue any
// Try to convert to int
valueInt, err := strconv.ParseInt(value[0], 10, 64)
if err == nil {
return int(valueInt), nil
}
// Try to convert to float
valueFloat, err := strconv.ParseFloat(value[0], 64)
if err == nil {
return valueFloat, nil
}
// Try to convert to boolean
valueBool, err := strconv.ParseBool(value[0])
if err == nil {
return valueBool, nil
}
err = json.Unmarshal([]byte(value[0]), &anyValue)
if err == nil {
return valueBool, nil
}
return value[0], nil
}
// GetMap will retrieve map[string]any field from data
func (i *Info) GetMap(m *MapParams, field string) (map[string]any, error) {
_, value, err := i.GetField(m, field)
if err != nil {
return nil, err
}
var mapValue map[string]any
err = json.Unmarshal([]byte(value[0]), &mapValue)
if err != nil {
return nil, fmt.Errorf("%s field could not parse to map[string]any", field)
}
return mapValue, nil
}
// GetField will retrieve field from data
func (i *Info) GetField(m *MapParams, field string) (*Param, []string, error) {
// Get param
var p *Param
for _, param := range i.Params {
if param.Field == field {
p = &param
break
}
}
if p == nil {
return nil, nil, fmt.Errorf("could not find param field %s", field)
}
// Get value from map
if m != nil {
value, ok := (*m)[field]
if !ok {
// If default isnt empty use default
if p.Default != "" {
return p, []string{p.Default}, nil
}
return nil, nil, fmt.Errorf("could not find field: %s", field)
}
return p, value, nil
} else if m == nil && p.Default != "" {
// If p.Type is []uint, then we need to convert it to []string
if strings.HasPrefix(p.Default, "[") {
// Remove [] from type
defaultClean := p.Default[1 : len(p.Default)-1]
// Split on comma
defaultSplit := strings.Split(defaultClean, ",")
return p, defaultSplit, nil
}
// If default isnt empty use default
return p, []string{p.Default}, nil
}
return nil, nil, fmt.Errorf("could not find field: %s", field)
}
// GetBool will retrieve boolean field from data
func (i *Info) GetBool(m *MapParams, field string) (bool, error) {
p, value, err := i.GetField(m, field)
if err != nil {
return false, err
}
// Try to convert to boolean
valueBool, err := strconv.ParseBool(value[0])
if err != nil {
return false, fmt.Errorf("%s field could not parse to bool value", p.Field)
}
return valueBool, nil
}
// GetInt will retrieve int field from data
func (i *Info) GetInt(m *MapParams, field string) (int, error) {
p, value, err := i.GetField(m, field)
if err != nil {
return 0, err
}
// Try to convert to int
valueInt, err := strconv.ParseInt(value[0], 10, 64)
if err != nil {
return 0, fmt.Errorf("%s field could not parse to int value", p.Field)
}
return int(valueInt), nil
}
// GetUint will retrieve uint field from data
func (i *Info) GetUint(m *MapParams, field string) (uint, error) {
p, value, err := i.GetField(m, field)
if err != nil {
return 0, err
}
// Try to convert to int
valueUint, err := strconv.ParseUint(value[0], 10, 64)
if err != nil {
return 0, fmt.Errorf("%s field could not parse to int value", p.Field)
}
return uint(valueUint), nil
}
// GetFloat32 will retrieve int field from data
func (i *Info) GetFloat32(m *MapParams, field string) (float32, error) {
p, value, err := i.GetField(m, field)
if err != nil {
return 0, err
}
// Try to convert to float
valueFloat, err := strconv.ParseFloat(value[0], 32)
if err != nil {
return 0, fmt.Errorf("%s field could not parse to float value", p.Field)
}
return float32(valueFloat), nil
}
// GetFloat64 will retrieve int field from data
func (i *Info) GetFloat64(m *MapParams, field string) (float64, error) {
p, value, err := i.GetField(m, field)
if err != nil {
return 0, err
}
// Try to convert to float
valueFloat, err := strconv.ParseFloat(value[0], 64)
if err != nil {
return 0, fmt.Errorf("%s field could not parse to float value", p.Field)
}
return valueFloat, nil
}
// GetString will retrieve string field from data
func (i *Info) GetString(m *MapParams, field string) (string, error) {
_, value, err := i.GetField(m, field)
if err != nil {
return "", err
}
return value[0], nil
}
// GetStringArray will retrieve []string field from data
func (i *Info) GetStringArray(m *MapParams, field string) ([]string, error) {
_, values, err := i.GetField(m, field)
if err != nil {
return nil, err
}
return values, nil
}
// GetIntArray will retrieve []int field from data
func (i *Info) GetIntArray(m *MapParams, field string) ([]int, error) {
_, value, err := i.GetField(m, field)
if err != nil {
return nil, err
}
var ints []int
for i := 0; i < len(value); i++ {
valueInt, err := strconv.ParseInt(value[i], 10, 64)
if err != nil {
return nil, fmt.Errorf("%s value could not parse to int", value[i])
}
ints = append(ints, int(valueInt))
}
return ints, nil
}
// GetUintArray will retrieve []uint field from data
func (i *Info) GetUintArray(m *MapParams, field string) ([]uint, error) {
_, value, err := i.GetField(m, field)
if err != nil {
return nil, err
}
var uints []uint
for i := 0; i < len(value); i++ {
valueUint, err := strconv.ParseUint(value[i], 10, 64)
if err != nil {
return nil, fmt.Errorf("%s value could not parse to uint", value[i])
}
uints = append(uints, uint(valueUint))
}
return uints, nil
}
// GetFloat32Array will retrieve []float field from data
func (i *Info) GetFloat32Array(m *MapParams, field string) ([]float32, error) {
_, value, err := i.GetField(m, field)
if err != nil {
return nil, err
}
var floats []float32
for i := 0; i < len(value); i++ {
valueFloat, err := strconv.ParseFloat(value[i], 32)
if err != nil {
return nil, fmt.Errorf("%s value could not parse to float", value[i])
}
floats = append(floats, float32(valueFloat))
}
return floats, nil
}