Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add cli flags -nosort and -omitempty #66

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion gojson/gojson.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ var (
tags = flag.String("tags", "fmt", "comma seperated list of the tags to put on the struct, default is the same as fmt")
forceFloats = flag.Bool("forcefloats", false, "[experimental] force float64 type for integral values")
subStruct = flag.Bool("subStruct", false, "create types for sub-structs (default is false)")
nosort = flag.Bool("nosort", false, "dont sort fields of generated structs (default is false)")
omitempty = flag.Bool("omitempty", false, "add omitempty flag in field tag (default is false)")
)

func main() {
Expand Down Expand Up @@ -108,7 +110,7 @@ func main() {
parser = ParseYaml
}

if output, err := Generate(input, parser, *name, *pkg, tagList, *subStruct, convertFloats); err != nil {
if output, err := Generate(input, parser, *name, *pkg, tagList, *subStruct, convertFloats, *nosort, *omitempty); err != nil {
fmt.Fprintln(os.Stderr, "error parsing", err)
os.Exit(1)
} else {
Expand Down
2 changes: 1 addition & 1 deletion json-to-array_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func TestExampleArray(t *testing.T) {
t.Fatalf("error reading example_array.go: %s", err)
}

actual, err := Generate(i, ParseJson, "Users", "gojson", []string{"json"}, false, true)
actual, err := Generate(i, ParseJson, "Users", "gojson", []string{"json"}, false, true, false, false)
if err != nil {
t.Fatal(err)
}
Expand Down
40 changes: 24 additions & 16 deletions json-to-struct.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ func readFile(input io.Reader) ([]byte, error) {
}

// Generate a struct definition given a JSON string representation of an object and a name structName.
func Generate(input io.Reader, parser Parser, structName, pkgName string, tags []string, subStruct bool, convertFloats bool) ([]byte, error) {
func Generate(input io.Reader, parser Parser, structName, pkgName string, tags []string, subStruct bool, convertFloats bool, nosort bool, omitempty bool) ([]byte, error) {
var subStructMap map[string]string = nil
if subStruct {
subStructMap = make(map[string]string)
Expand All @@ -220,7 +220,7 @@ func Generate(input io.Reader, parser Parser, structName, pkgName string, tags [
src := fmt.Sprintf("package %s\n\ntype %s %s\n",
pkgName,
structName,
typeForValue(iresult, structName, tags, subStructMap, convertFloats))
typeForValue(iresult, structName, tags, subStructMap, convertFloats, nosort, omitempty))
formatted, err := format.Source([]byte(src))
if err != nil {
err = fmt.Errorf("error formatting: %s, was formatting\n%s", err, src)
Expand All @@ -233,14 +233,16 @@ func Generate(input io.Reader, parser Parser, structName, pkgName string, tags [
src := fmt.Sprintf("package %s\ntype %s %s}",
pkgName,
structName,
generateTypes(result, structName, tags, 0, subStructMap, convertFloats))
generateTypes(result, structName, tags, 0, subStructMap, convertFloats, nosort, omitempty))

keys := make([]string, 0, len(subStructMap))
for key := range subStructMap {
keys = append(keys, key)
}

sort.Strings(keys)
if !nosort {
sort.Strings(keys)
}

for _, k := range keys {
src = fmt.Sprintf("%v\n\ntype %v %v", src, subStructMap[k], k)
Expand All @@ -264,18 +266,20 @@ func convertKeysToStrings(obj map[interface{}]interface{}) map[string]interface{
}

// Generate go struct entries for a map[string]interface{} structure
func generateTypes(obj map[string]interface{}, structName string, tags []string, depth int, subStructMap map[string]string, convertFloats bool) string {
func generateTypes(obj map[string]interface{}, structName string, tags []string, depth int, subStructMap map[string]string, convertFloats bool, nosort bool, omitempty bool) string {
structure := "struct {"

keys := make([]string, 0, len(obj))
for key := range obj {
keys = append(keys, key)
}
sort.Strings(keys)
if !nosort {
sort.Strings(keys)
}

for _, key := range keys {
value := obj[key]
valueType := typeForValue(value, structName, tags, subStructMap, convertFloats)
valueType := typeForValue(value, structName, tags, subStructMap, convertFloats, nosort, omitempty)

//value = mergeElements(value)

Expand All @@ -285,9 +289,9 @@ func generateTypes(obj map[string]interface{}, structName string, tags []string,
if len(value) > 0 {
sub := ""
if v, ok := value[0].(map[interface{}]interface{}); ok {
sub = generateTypes(convertKeysToStrings(v), structName, tags, depth+1, subStructMap, convertFloats) + "}"
sub = generateTypes(convertKeysToStrings(v), structName, tags, depth+1, subStructMap, convertFloats, nosort, omitempty) + "}"
} else if v, ok := value[0].(map[string]interface{}); ok {
sub = generateTypes(v, structName, tags, depth+1, subStructMap, convertFloats) + "}"
sub = generateTypes(v, structName, tags, depth+1, subStructMap, convertFloats, nosort, omitempty) + "}"
}

if sub != "" {
Expand All @@ -307,7 +311,7 @@ func generateTypes(obj map[string]interface{}, structName string, tags []string,
}
}
case map[interface{}]interface{}:
sub := generateTypes(convertKeysToStrings(value), structName, tags, depth+1, subStructMap, convertFloats) + "}"
sub := generateTypes(convertKeysToStrings(value), structName, tags, depth+1, subStructMap, convertFloats, nosort, omitempty) + "}"
subName := sub

if subStructMap != nil {
Expand All @@ -321,7 +325,7 @@ func generateTypes(obj map[string]interface{}, structName string, tags []string,
}
valueType = subName
case map[string]interface{}:
sub := generateTypes(value, structName, tags, depth+1, subStructMap, convertFloats) + "}"
sub := generateTypes(value, structName, tags, depth+1, subStructMap, convertFloats, nosort, omitempty) + "}"
subName := sub

if subStructMap != nil {
Expand All @@ -341,7 +345,11 @@ func generateTypes(obj map[string]interface{}, structName string, tags []string,

tagList := make([]string, 0)
for _, t := range tags {
tagList = append(tagList, fmt.Sprintf("%s:\"%s\"", t, key))
tKey := key
if omitempty {
tKey += ",omitempty"
}
tagList = append(tagList, fmt.Sprintf("%s:\"%s\"", t, tKey))
}

structure += fmt.Sprintf("\n%s %s `%s`",
Expand Down Expand Up @@ -470,21 +478,21 @@ func lintFieldName(name string) string {
}

// generate an appropriate struct type entry
func typeForValue(value interface{}, structName string, tags []string, subStructMap map[string]string, convertFloats bool) string {
func typeForValue(value interface{}, structName string, tags []string, subStructMap map[string]string, convertFloats bool, nosort bool, omitempty bool) string {
//Check if this is an array
if objects, ok := value.([]interface{}); ok {
types := make(map[reflect.Type]bool, 0)
for _, o := range objects {
types[reflect.TypeOf(o)] = true
}
if len(types) == 1 {
return "[]" + typeForValue(mergeElements(objects).([]interface{})[0], structName, tags, subStructMap, convertFloats)
return "[]" + typeForValue(mergeElements(objects).([]interface{})[0], structName, tags, subStructMap, convertFloats, nosort, omitempty)
}
return "[]interface{}"
} else if object, ok := value.(map[interface{}]interface{}); ok {
return generateTypes(convertKeysToStrings(object), structName, tags, 0, subStructMap, convertFloats) + "}"
return generateTypes(convertKeysToStrings(object), structName, tags, 0, subStructMap, convertFloats, nosort, omitempty) + "}"
} else if object, ok := value.(map[string]interface{}); ok {
return generateTypes(object, structName, tags, 0, subStructMap, convertFloats) + "}"
return generateTypes(object, structName, tags, 0, subStructMap, convertFloats, nosort, omitempty) + "}"
} else if reflect.TypeOf(value) == nil {
return "interface{}"
}
Expand Down
14 changes: 7 additions & 7 deletions json-to-struct_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,31 +12,31 @@ import (
// It does not (yet) test for correctness of the end result
func TestSimpleJson(t *testing.T) {
i := strings.NewReader(`{"foo" : "bar"}`)
if _, err := Generate(i, ParseJson, "TestStruct", "gojson", []string{"json"}, false, true); err != nil {
if _, err := Generate(i, ParseJson, "TestStruct", "gojson", []string{"json"}, false, true, false, false); err != nil {
t.Error("Generate() error:", err)
}
}

// TestNullableJson tests that a null JSON value is handled properly
func TestNullableJson(t *testing.T) {
i := strings.NewReader(`{"foo" : "bar", "baz" : null}`)
if _, err := Generate(i, ParseJson, "TestStruct", "gojson", []string{"json"}, false, true); err != nil {
if _, err := Generate(i, ParseJson, "TestStruct", "gojson", []string{"json"}, false, true, false, false); err != nil {
t.Error("Generate() error:", err)
}
}

// TestSimpleArray tests that an array without conflicting types is handled correctly
func TestSimpleArray(t *testing.T) {
i := strings.NewReader(`{"foo" : [{"bar": 24}, {"bar" : 42}]}`)
if _, err := Generate(i, ParseJson, "TestStruct", "gojson", []string{"json"}, false, true); err != nil {
if _, err := Generate(i, ParseJson, "TestStruct", "gojson", []string{"json"}, false, true, false, false); err != nil {
t.Error("Generate() error:", err)
}
}

// TestInvalidFieldChars tests that a document with invalid field chars is handled correctly
func TestInvalidFieldChars(t *testing.T) {
i := strings.NewReader(`{"f.o-o" : 42}`)
if _, err := Generate(i, ParseJson, "TestStruct", "gojson", []string{"json"}, false, true); err != nil {
if _, err := Generate(i, ParseJson, "TestStruct", "gojson", []string{"json"}, false, true, false, false); err != nil {
t.Error("Generate() error:", err)
}
}
Expand Down Expand Up @@ -80,7 +80,7 @@ func TestInferFloatInt(t *testing.T) {
t.Fatalf("error reading expected_floats.go.out: %s", err)
}

actual, err := Generate(f, ParseJson, "Stats", "gojson", []string{"json"}, false, true)
actual, err := Generate(f, ParseJson, "Stats", "gojson", []string{"json"}, false, true, false, false)
if err != nil {
t.Error(err)
}
Expand All @@ -104,7 +104,7 @@ func TestYamlNumbers(t *testing.T) {
t.Fatalf("error reading expected_numbers.go.out: %s", err)
}

actual, err := Generate(f, ParseYaml, "Stats", "gojson", []string{"yaml"}, false, false)
actual, err := Generate(f, ParseYaml, "Stats", "gojson", []string{"yaml"}, false, false, false, false)
if err != nil {
t.Error(err)
}
Expand All @@ -126,7 +126,7 @@ func TestExample(t *testing.T) {
t.Error("error reading expected_output_test.go", err)
}

actual, err := Generate(i, ParseJson, "User", "gojson", []string{"json"}, false, true)
actual, err := Generate(i, ParseJson, "User", "gojson", []string{"json"}, false, true, false, false)
if err != nil {
t.Error(err)
}
Expand Down