Skip to content

Commit

Permalink
add option to force using a pointer
Browse files Browse the repository at this point in the history
  • Loading branch information
benjaminjkraft committed Apr 12, 2021
1 parent 74411fa commit e597cac
Show file tree
Hide file tree
Showing 14 changed files with 351 additions and 65 deletions.
50 changes: 42 additions & 8 deletions generate/comments.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,31 @@ type GenqlientDirective struct {
// value otherwise.
//
// Only applicable to arguments of nullable types.
Omitempty bool
Omitempty *bool

// If set, this argument or field will use a pointer type in Go. Response
// types always use pointers, but otherwise we typically do not.
//
// This can be useful if it's a type you'll need to pass around (and want a
// pointer to save copies) or if you wish to distinguish between the Go
// zero value and null (for nullable fields).
Pointer *bool
}

func (g *GenqlientDirective) GetOmitempty() bool { return g.Omitempty != nil && *g.Omitempty }
func (g *GenqlientDirective) GetPointer() bool { return g.Pointer != nil && *g.Pointer }

func setBool(dst **bool, v *ast.Value) error {
ei, err := v.Value(nil) // no vars allowed
// TODO: here and below, put positions on these errors
if err != nil {
return fmt.Errorf("invalid boolean value %v: %w", v, err)
}
if b, ok := ei.(bool); ok {
*dst = &b
return nil
}
return fmt.Errorf("expected boolean, got non-boolean value %T(%v)", ei, ei)
}

func fromGraphQL(dir *ast.Directive) (*GenqlientDirective, error) {
Expand All @@ -61,13 +85,20 @@ func fromGraphQL(dir *ast.Directive) (*GenqlientDirective, error) {
}

var retval GenqlientDirective
var err error
for _, arg := range dir.Arguments {
switch arg.Name {
// TODO: reflect and struct tags?
case "omitempty":
retval.Omitempty = true
err = setBool(&retval.Omitempty, arg.Value)
case "pointer":
err = setBool(&retval.Pointer, arg.Value)
default:
return nil, fmt.Errorf("unknown argument %v for @genqlient", arg.Name)
}
if err != nil {
return nil, err
}
}
return &retval, nil
}
Expand All @@ -79,12 +110,12 @@ func (dir *GenqlientDirective) validate(node interface{}) error {
// whatever it is relevant to.
return nil
case *ast.VariableDefinition:
if dir.Omitempty && node.Type.NonNull {
if dir.Omitempty != nil && node.Type.NonNull {
return fmt.Errorf("omitempty may only be used on optional arguments")
}
return nil
case *ast.Field:
if dir.Omitempty {
if dir.Omitempty != nil {
return fmt.Errorf("omitempty is not appilcable to fields")
}
return nil
Expand All @@ -94,18 +125,21 @@ func (dir *GenqlientDirective) validate(node interface{}) error {
}

func (dir *GenqlientDirective) merge(other *GenqlientDirective) *GenqlientDirective {
if dir == nil {
return other
retval := *dir
if other.Omitempty != nil {
retval.Omitempty = other.Omitempty
}
if other.Pointer != nil {
retval.Pointer = other.Pointer
}
var retval GenqlientDirective
retval.Omitempty = dir.Omitempty || other.Omitempty
return &retval
}

func (g *generator) parsePrecedingComment(
node interface{},
pos *ast.Position,
) (comment string, directive *GenqlientDirective, err error) {
directive = new(GenqlientDirective)
var commentLines []string
sourceLines := strings.Split(pos.Src.Input, "\n")
for i := pos.Line - 1; i > 0; i-- {
Expand Down
14 changes: 5 additions & 9 deletions generate/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ type argument struct {
GoName string
GoType string
GraphQLName string
Omitempty bool
Options *GenqlientDirective
}

func newGenerator(config *Config, schema *ast.Schema) *generator {
Expand Down Expand Up @@ -117,22 +117,18 @@ func (g *generator) getArgument(
if err != nil {
return argument{}, err
}
directive = operationDirective.merge(directive)
omitempty := false
if directive != nil {
omitempty = directive.Omitempty
}

graphQLName := arg.Variable
goType, err := g.getTypeForInputType(opName, arg.Type)
goType, err := g.getTypeForInputType(
opName, arg.Type, directive, operationDirective)
if err != nil {
return argument{}, err
}
return argument{
GraphQLName: graphQLName,
GoName: lowerFirst(graphQLName),
GoType: goType,
Omitempty: omitempty,
Options: directive,
}, nil
}

Expand Down Expand Up @@ -163,7 +159,7 @@ func (g *generator) addOperation(op *ast.OperationDefinition) error {
}
}

responseName, err := g.getTypeForOperation(op)
responseName, err := g.getTypeForOperation(op, directive)
if err != nil {
return err
}
Expand Down
7 changes: 5 additions & 2 deletions generate/generate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,11 @@ func TestGenerate(t *testing.T) {
}

if string(content) != expectedContent {
t.Errorf("mismatch in %v\ngot:\n%v\nwant:\n%v\n",
filename, string(content), expectedContent)
t.Errorf("mismatch in %v", filename)
if testing.Verbose() {
t.Errorf("got:\n%v\nwant:\n%v\n",
string(content), expectedContent)
}
if update {
t.Log("Updating testdata dir to match")
err = ioutil.WriteFile(filepath.Join(dataDir, filename), content, 0o644)
Expand Down
6 changes: 4 additions & 2 deletions generate/operation.go.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,13 @@ func {{.Name}}(
{{- if .Args -}}
variables := map[string]interface{}{
{{range .Args -}}
"{{.GraphQLName}}": {{if .Omitempty}}nil{{else}}{{.GoName}}{{end}},
{{if not .Options.GetOmitempty -}}
"{{.GraphQLName}}": {{.GoName}},
{{end -}}
{{end}}
}
{{range .Args -}}
{{if .Omitempty -}}
{{if .Options.GetOmitempty -}}
{{/* zero_{{.GoType}} would be a better name, but {{.GoType}} would require
munging since it might be, say, `time.Time`. */}}
var zero_{{.GoName}} {{.GoType}}
Expand Down
3 changes: 3 additions & 0 deletions generate/testdata/queries/Omitempty.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@ query OmitEmptyQuery(
$query: UserQueryInput,
$dt: DateTime,
$tz: String,
# @genqlient(omitempty: false)
$tzNoOmitEmpty: String,
) {
user(query: $query) {
id
}
maybeConvert(dt: $dt, tz: $tz)
convert2: maybeConvert(dt: $dt, tz: $tzNoOmitEmpty)
}
27 changes: 8 additions & 19 deletions generate/testdata/queries/Omitempty.graphql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion generate/testdata/queries/Omitempty.graphql.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"operations": [
{
"operationName": "OmitEmptyQuery",
"query": "\nquery OmitEmptyQuery ($query: UserQueryInput, $dt: DateTime, $tz: String) {\n\tuser(query: $query) {\n\t\tid\n\t}\n\tmaybeConvert(dt: $dt, tz: $tz)\n}\n",
"query": "\nquery OmitEmptyQuery ($query: UserQueryInput, $dt: DateTime, $tz: String, $tzNoOmitEmpty: String) {\n\tuser(query: $query) {\n\t\tid\n\t}\n\tmaybeConvert(dt: $dt, tz: $tz)\n\tconvert2: maybeConvert(dt: $dt, tz: $tzNoOmitEmpty)\n}\n",
"sourceLocation": "testdata/queries/Omitempty.graphql"
}
]
Expand Down
20 changes: 20 additions & 0 deletions generate/testdata/queries/Pointers.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# @genqlient(pointer: true)
query PointersQuery(
$query: UserQueryInput,
# @genqlient(pointer: false)
$dt: DateTime,
$tz: String,
) {
user(query: $query) {
id
roles
name
emails
# @genqlient(pointer: false)
emailsNoPtr: emails
}
otherUser: user(query: $query) {
id
}
maybeConvert(dt: $dt, tz: $tz)
}
80 changes: 80 additions & 0 deletions generate/testdata/queries/Pointers.graphql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions generate/testdata/queries/Pointers.graphql.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"operations": [
{
"operationName": "PointersQuery",
"query": "\nquery PointersQuery ($query: UserQueryInput, $dt: DateTime, $tz: String) {\n\tuser(query: $query) {\n\t\tid\n\t\troles\n\t\tname\n\t\temails\n\t\temailsNoPtr: emails\n\t}\n\totherUser: user(query: $query) {\n\t\tid\n\t}\n\tmaybeConvert(dt: $dt, tz: $tz)\n}\n",
"sourceLocation": "testdata/queries/Pointers.graphql"
}
]
}
24 changes: 24 additions & 0 deletions generate/testdata/queries/PointersInline.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
query PointersQuery(
# @genqlient(pointer: true)
$query: UserQueryInput,
# @genqlient(pointer: true)
$dt: DateTime,
$tz: String,
) {
# @genqlient(pointer: true)
user(query: $query) {
id
roles
# @genqlient(pointer: true)
name
# @genqlient(pointer: true)
emails
# @genqlient(pointer: true)
emailsNoPtr: emails
}
# @genqlient(pointer: true)
otherUser: user(query: $query) {
id
}
maybeConvert(dt: $dt, tz: $tz)
}
Loading

0 comments on commit e597cac

Please sign in to comment.