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

Generate uuid.UUID members for uuid jsonschema format #4

Open
wants to merge 3 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
47 changes: 38 additions & 9 deletions generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,28 @@ type Generator struct {
resolver *RefResolver
Structs map[string]Struct
Aliases map[string]Field
// provides the mapping of "string field with explicitly specified `format`"
// to Go typed member of the generated struct for this format
customStringTypes map[string]stringFormatType
// cache for reference types; k=url v=type
refs map[string]string
anonCount int
}

type stringFormatType struct {
PackageName string
TypeName string
}

// New creates an instance of a generator which will produce structs.
func New(schemas ...*Schema) *Generator {
return &Generator{
schemas: schemas,
resolver: NewRefResolver(schemas),
Structs: make(map[string]Struct),
Aliases: make(map[string]Field),
refs: make(map[string]string),
schemas: schemas,
resolver: NewRefResolver(schemas),
Structs: make(map[string]Struct),
Aliases: make(map[string]Field),
refs: make(map[string]string),
customStringTypes: formatCustomTypes(),
}
}

Expand Down Expand Up @@ -59,6 +68,19 @@ func (g *Generator) CreateTypes(conventions map[string]string) (err error) {
return
}

func formatCustomTypes() map[string]stringFormatType {
return map[string]stringFormatType{
"date-time": {
PackageName: "time",
TypeName: "time.Time",
},
"uuid": {
PackageName: "github.com/google/uuid",
TypeName: "uuid.UUID",
},
}
}

// process a block of definitions
func (g *Generator) processDefinitions(schema *Schema, conventions map[string]string) error {
for key, subSchema := range schema.Definitions {
Expand Down Expand Up @@ -108,7 +130,7 @@ func (g *Generator) processSchema(schemaName string, schema *Schema, conventions
}
switch schemaType {
case "object":
rv, err := g.processObject(name, schema, conventions)
rv, err := g.processObject(name, schema, conventions, g.customStringTypes)
if err != nil {
return "", err
}
Expand Down Expand Up @@ -175,7 +197,12 @@ func (g *Generator) processArray(name string, schema *Schema, conventions map[st
// name: name of the struct (calculated by caller)
// schema: detail incl properties & child objects
// returns: generated type
func (g *Generator) processObject(name string, schema *Schema, conventions map[string]string) (typ string, err error) {
func (g *Generator) processObject(
name string,
schema *Schema,
conventions map[string]string,
customTypes map[string]stringFormatType,
) (typ string, err error) {
strct := Struct{
ID: schema.ID(),
Name: name,
Expand All @@ -201,8 +228,10 @@ func (g *Generator) processObject(name string, schema *Schema, conventions map[s
Description: prop.Description,
Format: prop.Format,
}
if f.Type == "string" && f.Format == "date-time" {
strct.importTypes = append(strct.importTypes, "time")
if f.Type == "string" && f.Format != "" {
if customTypeForFormat, ok := customTypes[f.Format]; ok {
strct.importTypes = append(strct.importTypes, customTypeForFormat.PackageName)
}
}
if f.Required {
strct.GenerateCode = true
Expand Down
13 changes: 13 additions & 0 deletions generator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -813,6 +813,19 @@ func TestImportTypeDetection(t *testing.T) {
},
},
expect: []string{"time"},
}, {
name: "string/uuid imports uuid",
input: &Schema{
Title: "example",
TypeValue: "object",
Properties: map[string]*Schema{
"key": {
TypeValue: "string",
Format: "uuid",
},
},
},
expect: []string{"uuid"},
}}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
Expand Down
4 changes: 4 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
module github.com/elastic/go-json-schema-generate

go 1.15

require (
github.com/google/uuid v1.4.0 // indirect
)
6 changes: 4 additions & 2 deletions output.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,10 @@ func Output(w io.Writer, g *Generator, pkg string, skipCode bool, esdoc bool) {
ftype := f.Type
if ftype == "int" {
ftype = "int64"
} else if ftype == "string" && f.Format == "date-time" {
ftype = "time.Time"
} else if ftype == "string" && f.Format != "" {
if customStringType, ok := g.customStringTypes[f.Format]; ok {
ftype = customStringType.TypeName
}
}
if f.Format == "raw" {
ftype = "json.RawMessage"
Expand Down
17 changes: 17 additions & 0 deletions test/uuid.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "UUID",
"description": "A json schema with a uuid property",
"type": "object",
"properties": {
"id": {
"description": "A UUID",
"type": "string",
"format": "uuid"
}
},
"required": [
"id"
]
}

25 changes: 25 additions & 0 deletions test/uuid_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package test

import (
"encoding/json"
uuidGen "github.com/elastic/go-json-schema-generate/test/uuid_gen"
"github.com/google/uuid"
"testing"
)

func TestUUID(t *testing.T) {
data := []byte(`{
"id": "f1c85b8a-3872-40d1-84db-6c0cb9c3ca23"
}`)
uuidStruct := &uuidGen.UUID{}
if err := json.Unmarshal(data, &uuidStruct); err != nil {
t.Fatal(err)
}
expectedUUID, err := uuid.Parse("f1c85b8a-3872-40d1-84db-6c0cb9c3ca23")
if err != nil {
t.Fatal(err)
}
if uuidStruct.Id != expectedUUID {
t.Errorf("expected uuid to be %s got %s", expectedUUID.String(), uuidStruct.Id.String())
}
}