forked from ebhomengo/niki
1
0
Fork 0
niki/vendor/github.com/brianvoe/gofakeit/v6/json.go

550 lines
9.0 KiB
Go
Raw Normal View History

2024-04-26 19:30:35 +00:00
package gofakeit
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"math/rand"
"reflect"
"strconv"
)
// JSONOptions defines values needed for json generation
2024-04-26 19:30:35 +00:00
type JSONOptions struct {
Type string `json:"type" xml:"type" fake:"{randomstring:[array,object]}"` // array or object
RowCount int `json:"row_count" xml:"row_count" fake:"{number:1,10}"`
Indent bool `json:"indent" xml:"indent"`
Fields []Field `json:"fields" xml:"fields" fake:"{fields}"`
2024-04-26 19:30:35 +00:00
}
type jsonKeyVal struct {
Key string
2024-04-26 19:30:35 +00:00
Value any
}
type jsonOrderedKeyVal []*jsonKeyVal
func (okv jsonOrderedKeyVal) MarshalJSON() ([]byte, error) {
2024-04-26 19:30:35 +00:00
var buf bytes.Buffer
buf.WriteString("{")
2024-04-26 19:30:35 +00:00
for i, kv := range okv {
2024-04-26 19:30:35 +00:00
// Add comma to all except last one
2024-04-26 19:30:35 +00:00
if i != 0 {
2024-04-26 19:30:35 +00:00
buf.WriteString(",")
2024-04-26 19:30:35 +00:00
}
// Marshal key and write
2024-04-26 19:30:35 +00:00
key, err := json.Marshal(kv.Key)
2024-04-26 19:30:35 +00:00
if err != nil {
2024-04-26 19:30:35 +00:00
return nil, err
2024-04-26 19:30:35 +00:00
}
2024-04-26 19:30:35 +00:00
buf.Write(key)
// Write colon separator
2024-04-26 19:30:35 +00:00
buf.WriteString(":")
// Marshal value and write
2024-04-26 19:30:35 +00:00
val, err := json.Marshal(kv.Value)
2024-04-26 19:30:35 +00:00
if err != nil {
2024-04-26 19:30:35 +00:00
return nil, err
2024-04-26 19:30:35 +00:00
}
2024-04-26 19:30:35 +00:00
buf.Write(val)
2024-04-26 19:30:35 +00:00
}
2024-04-26 19:30:35 +00:00
buf.WriteString("}")
return buf.Bytes(), nil
2024-04-26 19:30:35 +00:00
}
// JSON generates an object or an array of objects in json format.
2024-04-26 19:30:35 +00:00
// A nil JSONOptions returns a randomly structured JSON.
2024-04-26 19:30:35 +00:00
func JSON(jo *JSONOptions) ([]byte, error) { return jsonFunc(globalFaker, jo) }
// JSON generates an object or an array of objects in json format.
2024-04-26 19:30:35 +00:00
// A nil JSONOptions returns a randomly structured JSON.
2024-04-26 19:30:35 +00:00
func (f *Faker) JSON(jo *JSONOptions) ([]byte, error) { return jsonFunc(f, jo) }
// JSON generates an object or an array of objects in json format
2024-04-26 19:30:35 +00:00
func jsonFunc(f *Faker, jo *JSONOptions) ([]byte, error) {
2024-04-26 19:30:35 +00:00
if jo == nil {
2024-04-26 19:30:35 +00:00
// We didn't get a JSONOptions, so create a new random one
2024-04-26 19:30:35 +00:00
err := f.Struct(&jo)
2024-04-26 19:30:35 +00:00
if err != nil {
2024-04-26 19:30:35 +00:00
return nil, err
2024-04-26 19:30:35 +00:00
}
2024-04-26 19:30:35 +00:00
}
// Check to make sure they passed in a type
2024-04-26 19:30:35 +00:00
if jo.Type != "array" && jo.Type != "object" {
2024-04-26 19:30:35 +00:00
return nil, errors.New("invalid type, must be array or object")
2024-04-26 19:30:35 +00:00
}
if jo.Fields == nil || len(jo.Fields) <= 0 {
2024-04-26 19:30:35 +00:00
return nil, errors.New("must pass fields in order to build json object(s)")
2024-04-26 19:30:35 +00:00
}
if jo.Type == "object" {
2024-04-26 19:30:35 +00:00
v := make(jsonOrderedKeyVal, len(jo.Fields))
// Loop through fields and add to them to map[string]any
2024-04-26 19:30:35 +00:00
for i, field := range jo.Fields {
2024-04-26 19:30:35 +00:00
if field.Function == "autoincrement" {
2024-04-26 19:30:35 +00:00
// Object only has one
2024-04-26 19:30:35 +00:00
v[i] = &jsonKeyVal{Key: field.Name, Value: 1}
2024-04-26 19:30:35 +00:00
continue
2024-04-26 19:30:35 +00:00
}
// Get function info
2024-04-26 19:30:35 +00:00
funcInfo := GetFuncLookup(field.Function)
2024-04-26 19:30:35 +00:00
if funcInfo == nil {
2024-04-26 19:30:35 +00:00
return nil, errors.New("invalid function, " + field.Function + " does not exist")
2024-04-26 19:30:35 +00:00
}
// Call function value
2024-04-26 19:30:35 +00:00
value, err := funcInfo.Generate(f.Rand, &field.Params, funcInfo)
2024-04-26 19:30:35 +00:00
if err != nil {
2024-04-26 19:30:35 +00:00
return nil, err
2024-04-26 19:30:35 +00:00
}
if _, ok := value.([]byte); ok {
2024-04-26 19:30:35 +00:00
// If it's a slice, unmarshal it into an interface
2024-04-26 19:30:35 +00:00
var val any
2024-04-26 19:30:35 +00:00
err := json.Unmarshal(value.([]byte), &val)
2024-04-26 19:30:35 +00:00
if err != nil {
2024-04-26 19:30:35 +00:00
return nil, err
2024-04-26 19:30:35 +00:00
}
2024-04-26 19:30:35 +00:00
value = val
2024-04-26 19:30:35 +00:00
}
v[i] = &jsonKeyVal{Key: field.Name, Value: value}
}
// Marshal into bytes
2024-04-26 19:30:35 +00:00
if jo.Indent {
2024-04-26 19:30:35 +00:00
j, _ := json.MarshalIndent(v, "", " ")
2024-04-26 19:30:35 +00:00
return j, nil
2024-04-26 19:30:35 +00:00
}
j, _ := json.Marshal(v)
2024-04-26 19:30:35 +00:00
return j, nil
2024-04-26 19:30:35 +00:00
}
if jo.Type == "array" {
2024-04-26 19:30:35 +00:00
// Make sure you set a row count
2024-04-26 19:30:35 +00:00
if jo.RowCount <= 0 {
2024-04-26 19:30:35 +00:00
return nil, errors.New("must have row count")
2024-04-26 19:30:35 +00:00
}
v := make([]jsonOrderedKeyVal, jo.RowCount)
for i := 0; i < int(jo.RowCount); i++ {
2024-04-26 19:30:35 +00:00
vr := make(jsonOrderedKeyVal, len(jo.Fields))
// Loop through fields and add to them to map[string]any
2024-04-26 19:30:35 +00:00
for ii, field := range jo.Fields {
2024-04-26 19:30:35 +00:00
if field.Function == "autoincrement" {
2024-04-26 19:30:35 +00:00
vr[ii] = &jsonKeyVal{Key: field.Name, Value: i + 1} // +1 because index starts with 0
2024-04-26 19:30:35 +00:00
continue
2024-04-26 19:30:35 +00:00
}
// Get function info
2024-04-26 19:30:35 +00:00
funcInfo := GetFuncLookup(field.Function)
2024-04-26 19:30:35 +00:00
if funcInfo == nil {
2024-04-26 19:30:35 +00:00
return nil, errors.New("invalid function, " + field.Function + " does not exist")
2024-04-26 19:30:35 +00:00
}
// Call function value
2024-04-26 19:30:35 +00:00
value, err := funcInfo.Generate(f.Rand, &field.Params, funcInfo)
2024-04-26 19:30:35 +00:00
if err != nil {
2024-04-26 19:30:35 +00:00
return nil, err
2024-04-26 19:30:35 +00:00
}
if _, ok := value.([]byte); ok {
2024-04-26 19:30:35 +00:00
// If it's a slice, unmarshal it into an interface
2024-04-26 19:30:35 +00:00
var val any
2024-04-26 19:30:35 +00:00
err := json.Unmarshal(value.([]byte), &val)
2024-04-26 19:30:35 +00:00
if err != nil {
2024-04-26 19:30:35 +00:00
return nil, err
2024-04-26 19:30:35 +00:00
}
2024-04-26 19:30:35 +00:00
value = val
2024-04-26 19:30:35 +00:00
}
vr[ii] = &jsonKeyVal{Key: field.Name, Value: value}
2024-04-26 19:30:35 +00:00
}
v[i] = vr
2024-04-26 19:30:35 +00:00
}
// Marshal into bytes
2024-04-26 19:30:35 +00:00
if jo.Indent {
2024-04-26 19:30:35 +00:00
j, _ := json.MarshalIndent(v, "", " ")
2024-04-26 19:30:35 +00:00
return j, nil
2024-04-26 19:30:35 +00:00
}
j, _ := json.Marshal(v)
2024-04-26 19:30:35 +00:00
return j, nil
2024-04-26 19:30:35 +00:00
}
return nil, errors.New("invalid type, must be array or object")
2024-04-26 19:30:35 +00:00
}
func addFileJSONLookup() {
2024-04-26 19:30:35 +00:00
AddFuncLookup("json", Info{
Display: "JSON",
Category: "file",
2024-04-26 19:30:35 +00:00
Description: "Format for structured data interchange used in programming, returns an object or an array of objects",
2024-04-26 19:30:35 +00:00
Example: `[
2024-04-26 19:30:35 +00:00
{ "first_name": "Markus", "last_name": "Moen", "password": "Dc0VYXjkWABx" },
2024-04-26 19:30:35 +00:00
{ "first_name": "Osborne", "last_name": "Hilll", "password": "XPJ9OVNbs5lm" },
2024-04-26 19:30:35 +00:00
{ "first_name": "Mertie", "last_name": "Halvorson", "password": "eyl3bhwfV8wA" }
2024-04-26 19:30:35 +00:00
]`,
Output: "[]byte",
2024-04-26 19:30:35 +00:00
ContentType: "application/json",
2024-04-26 19:30:35 +00:00
Params: []Param{
2024-04-26 19:30:35 +00:00
{Field: "type", Display: "Type", Type: "string", Default: "object", Options: []string{"object", "array"}, Description: "Type of JSON, object or array"},
2024-04-26 19:30:35 +00:00
{Field: "rowcount", Display: "Row Count", Type: "int", Default: "100", Description: "Number of rows in JSON array"},
2024-04-26 19:30:35 +00:00
{Field: "indent", Display: "Indent", Type: "bool", Default: "false", Description: "Whether or not to add indents and newlines"},
2024-04-26 19:30:35 +00:00
{Field: "fields", Display: "Fields", Type: "[]Field", Description: "Fields containing key name and function to run in json format"},
},
2024-04-26 19:30:35 +00:00
Generate: func(r *rand.Rand, m *MapParams, info *Info) (any, error) {
2024-04-26 19:30:35 +00:00
jo := JSONOptions{}
typ, err := info.GetString(m, "type")
2024-04-26 19:30:35 +00:00
if err != nil {
2024-04-26 19:30:35 +00:00
return nil, err
2024-04-26 19:30:35 +00:00
}
2024-04-26 19:30:35 +00:00
jo.Type = typ
rowcount, err := info.GetInt(m, "rowcount")
2024-04-26 19:30:35 +00:00
if err != nil {
2024-04-26 19:30:35 +00:00
return nil, err
2024-04-26 19:30:35 +00:00
}
2024-04-26 19:30:35 +00:00
jo.RowCount = rowcount
indent, err := info.GetBool(m, "indent")
2024-04-26 19:30:35 +00:00
if err != nil {
2024-04-26 19:30:35 +00:00
return nil, err
2024-04-26 19:30:35 +00:00
}
2024-04-26 19:30:35 +00:00
jo.Indent = indent
fieldsStr, err := info.GetStringArray(m, "fields")
2024-04-26 19:30:35 +00:00
if err != nil {
2024-04-26 19:30:35 +00:00
return nil, err
2024-04-26 19:30:35 +00:00
}
// Check to make sure fields has length
2024-04-26 19:30:35 +00:00
if len(fieldsStr) > 0 {
2024-04-26 19:30:35 +00:00
jo.Fields = make([]Field, len(fieldsStr))
for i, f := range fieldsStr {
2024-04-26 19:30:35 +00:00
// Unmarshal fields string into fields array
2024-04-26 19:30:35 +00:00
err = json.Unmarshal([]byte(f), &jo.Fields[i])
2024-04-26 19:30:35 +00:00
if err != nil {
2024-04-26 19:30:35 +00:00
return nil, err
2024-04-26 19:30:35 +00:00
}
2024-04-26 19:30:35 +00:00
}
2024-04-26 19:30:35 +00:00
}
f := &Faker{Rand: r}
2024-04-26 19:30:35 +00:00
return jsonFunc(f, &jo)
2024-04-26 19:30:35 +00:00
},
})
2024-04-26 19:30:35 +00:00
}
// encoding/json.RawMessage is a special case of []byte
2024-04-26 19:30:35 +00:00
// it cannot be handled as a reflect.Array/reflect.Slice
2024-04-26 19:30:35 +00:00
// because it needs additional structure in the output
2024-04-26 19:30:35 +00:00
func rJsonRawMessage(f *Faker, t reflect.Type, v reflect.Value, tag string, size int) error {
2024-04-26 19:30:35 +00:00
b, err := f.JSON(nil)
2024-04-26 19:30:35 +00:00
if err != nil {
2024-04-26 19:30:35 +00:00
return err
2024-04-26 19:30:35 +00:00
}
v.SetBytes(b)
2024-04-26 19:30:35 +00:00
return nil
2024-04-26 19:30:35 +00:00
}
// encoding/json.Number is a special case of string
2024-04-26 19:30:35 +00:00
// that represents a JSON number literal.
2024-04-26 19:30:35 +00:00
// It cannot be handled as a string because it needs to
2024-04-26 19:30:35 +00:00
// represent an integer or a floating-point number.
2024-04-26 19:30:35 +00:00
func rJsonNumber(f *Faker, t reflect.Type, v reflect.Value, tag string, size int) error {
2024-04-26 19:30:35 +00:00
var ret json.Number
var numberType string
if tag == "" {
2024-04-26 19:30:35 +00:00
numberType = f.RandomString([]string{"int", "float"})
switch numberType {
2024-04-26 19:30:35 +00:00
case "int":
2024-04-26 19:30:35 +00:00
retInt := f.Int16()
2024-04-26 19:30:35 +00:00
ret = json.Number(strconv.Itoa(int(retInt)))
2024-04-26 19:30:35 +00:00
case "float":
2024-04-26 19:30:35 +00:00
retFloat := f.Float64()
2024-04-26 19:30:35 +00:00
ret = json.Number(strconv.FormatFloat(retFloat, 'f', -1, 64))
2024-04-26 19:30:35 +00:00
}
2024-04-26 19:30:35 +00:00
} else {
2024-04-26 19:30:35 +00:00
fName, fParams := parseNameAndParamsFromTag(tag)
2024-04-26 19:30:35 +00:00
info := GetFuncLookup(fName)
2024-04-26 19:30:35 +00:00
if info == nil {
2024-04-26 19:30:35 +00:00
return fmt.Errorf("invalid function, %s does not exist", fName)
2024-04-26 19:30:35 +00:00
}
// Parse map params
2024-04-26 19:30:35 +00:00
mapParams := parseMapParams(info, fParams)
valueIface, err := info.Generate(f.Rand, mapParams, info)
2024-04-26 19:30:35 +00:00
if err != nil {
2024-04-26 19:30:35 +00:00
return err
2024-04-26 19:30:35 +00:00
}
switch value := valueIface.(type) {
2024-04-26 19:30:35 +00:00
case int:
2024-04-26 19:30:35 +00:00
ret = json.Number(strconv.FormatInt(int64(value), 10))
2024-04-26 19:30:35 +00:00
case int8:
2024-04-26 19:30:35 +00:00
ret = json.Number(strconv.FormatInt(int64(value), 10))
2024-04-26 19:30:35 +00:00
case int16:
2024-04-26 19:30:35 +00:00
ret = json.Number(strconv.FormatInt(int64(value), 10))
2024-04-26 19:30:35 +00:00
case int32:
2024-04-26 19:30:35 +00:00
ret = json.Number(strconv.FormatInt(int64(value), 10))
2024-04-26 19:30:35 +00:00
case int64:
2024-04-26 19:30:35 +00:00
ret = json.Number(strconv.FormatInt(int64(value), 10))
2024-04-26 19:30:35 +00:00
case uint:
2024-04-26 19:30:35 +00:00
ret = json.Number(strconv.FormatUint(uint64(value), 10))
2024-04-26 19:30:35 +00:00
case uint8:
2024-04-26 19:30:35 +00:00
ret = json.Number(strconv.FormatUint(uint64(value), 10))
2024-04-26 19:30:35 +00:00
case uint16:
2024-04-26 19:30:35 +00:00
ret = json.Number(strconv.FormatUint(uint64(value), 10))
2024-04-26 19:30:35 +00:00
case uint32:
2024-04-26 19:30:35 +00:00
ret = json.Number(strconv.FormatUint(uint64(value), 10))
2024-04-26 19:30:35 +00:00
case uint64:
2024-04-26 19:30:35 +00:00
ret = json.Number(strconv.FormatUint(uint64(value), 10))
2024-04-26 19:30:35 +00:00
case float32:
2024-04-26 19:30:35 +00:00
ret = json.Number(strconv.FormatFloat(float64(value), 'f', -1, 64))
2024-04-26 19:30:35 +00:00
case float64:
2024-04-26 19:30:35 +00:00
ret = json.Number(strconv.FormatFloat(float64(value), 'f', -1, 64))
2024-04-26 19:30:35 +00:00
default:
2024-04-26 19:30:35 +00:00
return fmt.Errorf("invalid type, %s is not a valid type for json.Number", reflect.TypeOf(value))
2024-04-26 19:30:35 +00:00
}
2024-04-26 19:30:35 +00:00
}
2024-04-26 19:30:35 +00:00
v.Set(reflect.ValueOf(ret))
2024-04-26 19:30:35 +00:00
return nil
2024-04-26 19:30:35 +00:00
}