Skip to content

Commit

Permalink
Fix parse and write the default values in the input value definition (#…
Browse files Browse the repository at this point in the history
…53)

* add test

* fix parse and write the default value in arg definitions

* add test

* fix handling default value in input object

* rename Arg.TypeExt -> Arg.DefaultValue

* fix handling multiple default values in argument definitions

* add test

* fix handling multiple default values in input object

* printing directives in order by name

* clean up
  • Loading branch information
mununki authored Apr 2, 2024
1 parent 95d8997 commit dffc14f
Show file tree
Hide file tree
Showing 8 changed files with 185 additions and 28 deletions.
35 changes: 18 additions & 17 deletions lib/graphql.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,27 +64,28 @@ type Type struct {
}

type Arg struct {
Name string
Type string
TypeExt *string // in case of enum e.g. admin(role: Role = ADMIN): Admin!
Null bool
IsList bool
IsListNull bool
Directives []*Directive
Descriptions *[]string
Name string
Type string
DefaultValues *[]string // in case of default values e.g. admin(role: Role = ADMIN): Admin!
Null bool
IsList bool
IsListNull bool
Directives []*Directive
Descriptions *[]string
}

type Field struct {
BaseFileInfo
Name string
Args []*Arg
Type string
Null bool
IsList bool
IsListNull bool
Directives []*Directive
Descriptions *[]string
Comments *[]string
Name string
Args []*Arg
Type string
Null bool
IsList bool
IsListNull bool
DefaultValues *[]string
Directives []*Directive
Descriptions *[]string
Comments *[]string
}

type Scalar struct {
Expand Down
35 changes: 35 additions & 0 deletions lib/lex.go
Original file line number Diff line number Diff line change
Expand Up @@ -489,3 +489,38 @@ func (l *lexer) consumeIdent(includings ...tokenType) (*token, *[]string) {
return tok, &comments
}
}

/*
The `consumeIdent` function treats tokString as a comment.
If you want to scan the tokString for ident, you can use the consumeIdentInclString function.
e.g. scan "woonki" for ident here
test(name: String = "woonki"): Bool
*/
func (l *lexer) consumeIdentInclString(includings ...tokenType) (*token, *[]string) {
comments := []string{}
includings = append(includings, tokString)

for {
tok := l.next()
if tok.typ == tokSingleLineComment || tok.typ == tokBlockString {
comments = append(comments, tok.String())
continue
}

isIncluded := false
for _, incl := range includings {
if tok.typ == incl {
isIncluded = true
break
}
}

if tok.typ != tokIdent && !isIncluded {
errorf(`%s:%d:%d: unexpected "%s"`, l.filename, l.line, l.col, tok.String())
}
l.skipSpace()
return tok, &comments
}
}
32 changes: 26 additions & 6 deletions lib/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,23 +64,43 @@ func (p *Parser) parseArgs() []*Arg {
} else {
arg.IsListNull = true
}
} else {
typ, _ := p.lex.consumeIdent()
arg.Type = typ.String()

if p.lex.peek() == '=' {
p.lex.consumeToken(tokEqual)
tex, _ := p.lex.consumeIdent()
te := tex.String()
arg.TypeExt = &te
defaultValues := []string{}
if p.lex.peek() == '[' {
p.lex.consumeIdent(tokLBracket)
for p.lex.peek() != ']' {
tex, _ := p.lex.consumeIdentInclString(tokNumber)
te := tex.String()
defaultValues = append(defaultValues, te)
if p.lex.peek() == ',' {
p.lex.consumeToken(tokComma)
}
}
p.lex.consumeIdent(tokRBracket)
arg.DefaultValues = &defaultValues
}
}
} else {
typ, _ := p.lex.consumeIdent()
arg.Type = typ.String()

if p.lex.peek() == '!' {
arg.Null = false
p.lex.consumeToken(tokBang)
} else {
arg.Null = true
}

if p.lex.peek() == '=' {
p.lex.consumeToken(tokEqual)
tex, _ := p.lex.consumeIdentInclString(tokNumber)
te := tex.String()
defaultValues := []string{}
defaultValues = append(defaultValues, te)
arg.DefaultValues = &defaultValues
}
}
arg.Directives = p.parseDirectives()

Expand Down
26 changes: 26 additions & 0 deletions lib/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,23 @@ func (s *Schema) Parse(p *Parser) {
} else {
fd.IsListNull = true
}
if p.lex.peek() == '=' {
p.lex.consumeToken(tokEqual)
defaultValues := []string{}
if p.lex.peek() == '[' {
p.lex.consumeIdent(tokLBracket)
for p.lex.peek() != ']' {
tex, _ := p.lex.consumeIdentInclString(tokNumber)
te := tex.String()
defaultValues = append(defaultValues, te)
if p.lex.peek() == ',' {
p.lex.consumeToken(tokComma)
}
}
p.lex.consumeIdent(tokRBracket)
fd.DefaultValues = &defaultValues
}
}
} else {
fd.IsList = false
fd.IsListNull = false
Expand All @@ -330,6 +347,15 @@ func (s *Schema) Parse(p *Parser) {
} else {
fd.Null = true
}

if p.lex.peek() == '=' {
p.lex.consumeToken(tokEqual)
tex, _ := p.lex.consumeIdentInclString(tokNumber)
te := tex.String()
defaultValues := []string{}
defaultValues = append(defaultValues, te)
fd.DefaultValues = &defaultValues
}
}

fd.Directives = p.parseDirectives()
Expand Down
42 changes: 38 additions & 4 deletions lib/write.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package lib

import (
"sort"
"strings"
)

Expand Down Expand Up @@ -237,7 +238,17 @@ func (ms *MergedSchema) WriteSchema(s *Schema) string {
if p.IsList && !p.IsListNull {
ms.buf.WriteString("!")
}

if p.DefaultValues != nil {
if p.IsList {
ms.buf.WriteString(" = ")
ms.buf.WriteString("[")
ms.stitchDefaultValues(p.DefaultValues)
ms.buf.WriteString("]")
} else {
ms.buf.WriteString(" = ")
ms.stitchDefaultValues(p.DefaultValues)
}
}
ms.stitchDirectives(p.Directives)

ms.buf.WriteString("\n")
Expand Down Expand Up @@ -278,14 +289,23 @@ func (ms *MergedSchema) stitchArgument(a *Arg, l int, i int) {
if !a.IsListNull {
ms.buf.WriteString("!")
}
if a.DefaultValues != nil {
ms.buf.WriteString(" = ")
ms.buf.WriteString("[")
ms.stitchDefaultValues(a.DefaultValues)
ms.buf.WriteString("]")
}
ms.stitchDirectives(a.Directives)
} else {
ms.buf.WriteString(a.Type)
if a.TypeExt != nil {
ms.buf.WriteString(" = " + *a.TypeExt)
}
if !a.Null {
ms.buf.WriteString("!")
}
if a.DefaultValues != nil {
ms.buf.WriteString(" = ")
ms.stitchDefaultValues(a.DefaultValues)
}
ms.stitchDirectives(a.Directives)
}

if l <= 2 && i != l-1 {
Expand All @@ -297,6 +317,9 @@ func (ms *MergedSchema) stitchArgument(a *Arg, l int, i int) {
}

func (ms *MergedSchema) stitchDirectives(a []*Directive) {
sort.SliceStable(a, func(i, j int) bool {
return a[i].Name > a[j].Name
})
if l := len(a); l > 0 {
for _, a := range a {
ms.buf.WriteString(" @" + a.Name)
Expand All @@ -311,6 +334,17 @@ func (ms *MergedSchema) stitchDirectives(a []*Directive) {
}
}

func (ms *MergedSchema) stitchDefaultValues(a *[]string) {
if l := len(*a); l > 0 {
for i, v := range *a {
ms.buf.WriteString(v)
if i < l-1 {
ms.buf.WriteString(", ")
}
}
}
}

func (ms *MergedSchema) stitchDirectiveArgument(a *DirectiveArg, l int, i int) {
if l > 2 {
ms.addIndent(2)
Expand Down
22 changes: 22 additions & 0 deletions test/default_value/generated.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
type Query {
test1(X: Int = 20): Int
test2(X: Int! = 20): Int
test3(X: User = ADMIN): Int
test4(X: String! = "user"): Int
test5(X: String = "user" @deprecated): Int
test6(X: String = "user" @deprecated, Y: String! = "operator" @unique): Int
test7(X: [Int] = [20]): Int
test8(X: [Int] = [20, 30]): Int
test9(X: [User!]! = [ADMIN]): Int
test10(X: [String!] = ["user"]): Int
test11(X: [String] = ["user", "user1"] @deprecated): Int
test12(X: [String] = ["user", "user1"] @deprecated, Y: String! = "operator" @unique): Int
}




input User {
name: String! = "woonki"
nicknames: [String!]! = ["mununki", "arnold"]
}
19 changes: 19 additions & 0 deletions test/default_value/schema/a.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
type Query {
test1(X: Int = 20): Int
test2(X: Int! = 20): Int
test3(X: User = ADMIN): Int
test4(X: String! = "user"): Int
test5(X: String = "user" @deprecated): Int
test6(X: String = "user" @deprecated, Y: String! = "operator" @unique): Int
test7(X: [Int] = [20]): Int
test8(X: [Int] = [20, 30]): Int
test9(X: [User!]! = [ADMIN]): Int
test10(X: [String!] = ["user"]): Int
test11(X: [String] = ["user", "user1"] @deprecated): Int
test12(X: [String] = ["user", "user1"] @deprecated, Y: String! = "operator" @unique): Int
}

input User {
name: String! = "woonki"
nicknames: [String!]! = ["mununki", "arnold"]
}
2 changes: 1 addition & 1 deletion test/object_extension/generated.graphql
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
type Person implements Node @talkable @walkable {
type Person implements Node @walkable @talkable {
id: ID!
createTime: Time!
updateTime: Time!
Expand Down

0 comments on commit dffc14f

Please sign in to comment.