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 GQL and tests #56

Open
wants to merge 1 commit 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
132 changes: 123 additions & 9 deletions golden_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ var goldenSQL = []Golden{
{"prime with SQL", primeSqlIn, primeSqlOut},
}

var goldenGQL = []Golden{
{"prime with GQL", primeGqlIn, primeGqlOut},
}

var goldenJSONAndSQL = []Golden{
{"prime with JSONAndSQL", primeJsonAndSqlIn, primeJsonAndSqlOut},
}
Expand Down Expand Up @@ -887,6 +891,113 @@ func (i *Prime) Scan(value interface{}) error {
return nil
}
`
const primeGqlIn = `type Prime int
const (
p2 Prime = 2
p3 Prime = 3
p5 Prime = 5
p7 Prime = 7
p77 Prime = 7 // Duplicate; note that p77 doesn't appear below.
p11 Prime = 11
p13 Prime = 13
p17 Prime = 17
p19 Prime = 19
p23 Prime = 23
p29 Prime = 29
p37 Prime = 31
p41 Prime = 41
p43 Prime = 43
)
`

const primeGqlOut = `
const _PrimeName = "p2p3p5p7p11p13p17p19p23p29p37p41p43"

var _PrimeMap = map[Prime]string{
2: _PrimeName[0:2],
3: _PrimeName[2:4],
5: _PrimeName[4:6],
7: _PrimeName[6:8],
11: _PrimeName[8:11],
13: _PrimeName[11:14],
17: _PrimeName[14:17],
19: _PrimeName[17:20],
23: _PrimeName[20:23],
29: _PrimeName[23:26],
31: _PrimeName[26:29],
41: _PrimeName[29:32],
43: _PrimeName[32:35],
}

func (i Prime) String() string {
if str, ok := _PrimeMap[i]; ok {
return str
}
return fmt.Sprintf("Prime(%d)", i)
}

var _PrimeValues = []Prime{2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 41, 43}

var _PrimeNameToValueMap = map[string]Prime{
_PrimeName[0:2]: 2,
_PrimeName[2:4]: 3,
_PrimeName[4:6]: 5,
_PrimeName[6:8]: 7,
_PrimeName[8:11]: 11,
_PrimeName[11:14]: 13,
_PrimeName[14:17]: 17,
_PrimeName[17:20]: 19,
_PrimeName[20:23]: 23,
_PrimeName[23:26]: 29,
_PrimeName[26:29]: 31,
_PrimeName[29:32]: 41,
_PrimeName[32:35]: 43,
}

// PrimeString retrieves an enum value from the enum constants string name.
// Throws an error if the param is not part of the enum.
func PrimeString(s string) (Prime, error) {
if val, ok := _PrimeNameToValueMap[s]; ok {
return val, nil
}
return 0, fmt.Errorf("%s does not belong to Prime values", s)
}

// PrimeValues returns all values of the enum
func PrimeValues() []Prime {
return _PrimeValues
}

// IsAPrime returns "true" if the value is listed in the enum definition. "false" otherwise
func (i Prime) IsAPrime() bool {
_, ok := _PrimeMap[i]
return ok
}

func (i *Prime) UnmarshalGQL(v interface{}) error {
str, ok := v.(string)
if !ok {
bytes, ok := v.([]byte)
if !ok {
return fmt.Errorf("value is not a byte slice")
}

str = string(bytes[:])
}

val, err := PrimeString(str)
if err != nil {
return err
}

*i = val
return nil
}

func (i Prime) MarshalGQL(w io.Writer) {
_, _ = w.Write([]byte(strconv.Quote(f.String())))
}
`

const primeJsonAndSqlIn = `type Prime int
const (
Expand Down Expand Up @@ -1115,29 +1226,32 @@ func (i Prime) IsAPrime() bool {

func TestGolden(t *testing.T) {
for _, test := range golden {
runGoldenTest(t, test, false, false, false, false, "")
runGoldenTest(t, test, false, false, false, false, false, "")
}
for _, test := range goldenJSON {
runGoldenTest(t, test, true, false, false, false, "")
runGoldenTest(t, test, true, false, false, false, false, "")
}
for _, test := range goldenText {
runGoldenTest(t, test, false, false, false, true, "")
runGoldenTest(t, test, false, false, false, false, true, "")
}
for _, test := range goldenYAML {
runGoldenTest(t, test, false, true, false, false, "")
runGoldenTest(t, test, false, true, false, false, false, "")
}
for _, test := range goldenSQL {
runGoldenTest(t, test, false, false, true, false, "")
runGoldenTest(t, test, false, false, true, false, false, "")
}
for _, test := range goldenGQL {
runGoldenTest(t, test, false, false, false, true, false, "")
}
for _, test := range goldenJSONAndSQL {
runGoldenTest(t, test, true, false, true, false, "")
runGoldenTest(t, test, true, false, true, false, false, "")
}
for _, test := range goldenPrefix {
runGoldenTest(t, test, false, false, false, false, "Day")
runGoldenTest(t, test, false, false, false, false, false, "Day")
}
}

func runGoldenTest(t *testing.T, test Golden, generateJSON, generateYAML, generateSQL, generateText bool, prefix string) {
func runGoldenTest(t *testing.T, test Golden, generateJSON, generateYAML, generateSQL, generateGQL, generateText bool, prefix string) {
var g Generator
input := "package test\n" + test.input
file := test.name + ".go"
Expand All @@ -1164,7 +1278,7 @@ func runGoldenTest(t *testing.T, test Golden, generateJSON, generateYAML, genera
if len(tokens) != 3 {
t.Fatalf("%s: need type declaration on first line", test.name)
}
g.generate(tokens[1], generateJSON, generateYAML, generateSQL, generateText, "noop", prefix, false)
g.generate(tokens[1], generateJSON, generateYAML, generateSQL, generateGQL, generateText, "noop", prefix, false)
got := string(g.format())
if got != test.output {
t.Errorf("%s: got\n====\n%s====\nexpected\n====%s", test.name, got, test.output)
Expand Down
36 changes: 36 additions & 0 deletions gql.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package main

// Arguments to format are:
// [1]: type name
const unmarshalGqlMethod = `func (i *%[1]s) UnmarshalGQL(v interface{}) error {
str, ok := v.(string)
if !ok {
bytes, ok := v.([]byte)
if !ok {
return fmt.Errorf("value is not a byte slice")
}

str = string(bytes[:])
}

val, err := %[1]sString(str)
if err != nil {
return err
}

*i = val
return nil
}
`

const marshalGqlMethod = `func (i %[1]s) MarshalGQL(w io.Writer) {
_, _ = w.Write([]byte(strconv.Quote(i.String())))
}
`

func (g *Generator) addGqlMethods(typeName string) {
g.Printf("\n")
g.Printf(unmarshalGqlMethod, typeName)
g.Printf("\n\n")
g.Printf(marshalGqlMethod, typeName)
}
15 changes: 12 additions & 3 deletions stringer.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,15 @@ import (
"go/importer"
"go/token"
"go/types"
"golang.org/x/tools/go/packages"
"io/ioutil"
"log"
"os"
"path/filepath"
"sort"
"strings"

"golang.org/x/tools/go/packages"

"github.com/pascaldekloe/name"
)

Expand All @@ -44,6 +45,7 @@ func (af *arrayFlags) Set(value string) error {

var (
typeNames = flag.String("type", "", "comma-separated list of type names; must be set")
gql = flag.Bool("gql", false, "if true, the MarshalGQL and UnmarshalGQL interface of GQLGen will be implemented.")
sql = flag.Bool("sql", false, "if true, the Scanner and Valuer interface will be implemented.")
json = flag.Bool("json", false, "if true, json marshaling methods will be generated. Default: false")
yaml = flag.Bool("yaml", false, "if true, yaml marshaling methods will be generated. Default: false")
Expand Down Expand Up @@ -117,11 +119,15 @@ func main() {
if *json {
g.Printf("\t\"encoding/json\"\n")
}
if *gql {
g.Printf("\t\"io\"\n")
g.Printf("\t\"strconv\"\n")
}
g.Printf(")\n")

// Run generate for each type.
for _, typeName := range types {
g.generate(typeName, *json, *yaml, *sql, *text, *transformMethod, *trimPrefix, *lineComment)
g.generate(typeName, *json, *yaml, *sql, *gql, *text, *transformMethod, *trimPrefix, *lineComment)
}

// Format the output.
Expand Down Expand Up @@ -341,7 +347,7 @@ func (g *Generator) replaceValuesWithLineComment(values []Value) {
}

// generate produces the String method for the named type.
func (g *Generator) generate(typeName string, includeJSON, includeYAML, includeSQL, includeText bool, transformMethod string, trimPrefix string, lineComment bool) {
func (g *Generator) generate(typeName string, includeJSON, includeYAML, includeSQL, includeGQL, includeText bool, transformMethod string, trimPrefix string, lineComment bool) {
values := make([]Value, 0, 100)
for _, file := range g.pkg.files {
// Set the state for this run of the walker.
Expand Down Expand Up @@ -401,6 +407,9 @@ func (g *Generator) generate(typeName string, includeJSON, includeYAML, includeS
if includeSQL {
g.addValueAndScanMethod(typeName)
}
if includeGQL {
g.addGqlMethods(typeName)
}
}

// splitIntoRuns breaks the values into runs of contiguous sequences.
Expand Down