Handle omitempty correctly for slices

We were generating broken code; fixes #43.  Also fixes a bug where
applying omitempty to the entire query was broken by e597cac74c.
This commit is contained in:
Ben Kraft
2021-06-01 15:49:42 -07:00
parent 589680f323
commit c2e7dc4e5b
7 changed files with 55 additions and 13 deletions
+3 -1
View File
@@ -43,7 +43,9 @@ type GenqlientDirective struct {
pos *ast.Position pos *ast.Position
// If set, this argument will be omitted if it's equal to its Go zero // If set, this argument will be omitted if it's equal to its Go zero
// value. For example, given the following query: // value, or is an empty slice.
//
// For example, given the following query:
// # @genqlient(omitempty: true) // # @genqlient(omitempty: true)
// query MyQuery(arg: String) { ... } // query MyQuery(arg: String) { ... }
// genqlient will generate a function // genqlient will generate a function
+3 -1
View File
@@ -60,6 +60,7 @@ type argument struct {
GoName string GoName string
GoType string GoType string
GraphQLName string GraphQLName string
IsSlice bool
Options *GenqlientDirective Options *GenqlientDirective
} }
@@ -127,7 +128,8 @@ func (g *generator) getArgument(
GraphQLName: graphQLName, GraphQLName: graphQLName,
GoName: lowerFirst(graphQLName), GoName: lowerFirst(graphQLName),
GoType: goType, GoType: goType,
Options: directive, IsSlice: arg.Type.Elem != nil,
Options: operationDirective.merge(directive),
}, nil }, nil
} }
+4
View File
@@ -31,10 +31,14 @@ func {{.Name}}(
} }
{{range .Args -}} {{range .Args -}}
{{if .Options.GetOmitempty -}} {{if .Options.GetOmitempty -}}
{{if .IsSlice -}}
if len({{.GoName}}) > 0 {
{{else -}}
{{/* zero_{{.GoType}} would be a better name, but {{.GoType}} would require {{/* zero_{{.GoType}} would be a better name, but {{.GoType}} would require
munging since it might be, say, `time.Time`. */}} munging since it might be, say, `time.Time`. */}}
var zero_{{.GoName}} {{.GoType}} var zero_{{.GoName}} {{.GoType}}
if {{.GoName}} != zero_{{.GoName}} { if {{.GoName}} != zero_{{.GoName}} {
{{end -}}
variables["{{.GraphQLName}}"] = {{.GoName}} variables["{{.GraphQLName}}"] = {{.GoName}}
} }
{{end}} {{end}}
+3 -3
View File
@@ -1,14 +1,14 @@
# @genqlient(omitempty: true) # @genqlient(omitempty: true)
query OmitEmptyQuery( query OmitEmptyQuery(
$query: UserQueryInput, $query: UserQueryInput,
$queries: [UserQueryInput],
$dt: DateTime, $dt: DateTime,
$tz: String, $tz: String,
# @genqlient(omitempty: false) # @genqlient(omitempty: false)
$tzNoOmitEmpty: String, $tzNoOmitEmpty: String,
) { ) {
user(query: $query) { user(query: $query) { id }
id users(query: $queries) { id }
}
maybeConvert(dt: $dt, tz: $tz) maybeConvert(dt: $dt, tz: $tz)
convert2: maybeConvert(dt: $dt, tz: $tzNoOmitEmpty) convert2: maybeConvert(dt: $dt, tz: $tzNoOmitEmpty)
} }
+39 -7
View File
@@ -15,9 +15,10 @@ type OmitEmptyQueryResponse struct {
// //
// See UserQueryInput for what stuff is supported. // See UserQueryInput for what stuff is supported.
// If query is null, returns the current user. // If query is null, returns the current user.
User OmitEmptyQueryUser `json:"user"` User OmitEmptyQueryUser `json:"user"`
MaybeConvert time.Time `json:"maybeConvert"` Users OmitEmptyQueryUsersUser `json:"users"`
Convert2 time.Time `json:"convert2"` MaybeConvert time.Time `json:"maybeConvert"`
Convert2 time.Time `json:"convert2"`
} }
// OmitEmptyQueryUser includes the requested fields of the GraphQL type User. // OmitEmptyQueryUser includes the requested fields of the GraphQL type User.
@@ -31,6 +32,17 @@ type OmitEmptyQueryUser struct {
Id mypkg.ID `json:"id"` Id mypkg.ID `json:"id"`
} }
// OmitEmptyQueryUsersUser includes the requested fields of the GraphQL type User.
// The GraphQL type's documentation follows.
//
// A User is a user!
type OmitEmptyQueryUsersUser struct {
// id is the user's ID.
//
// It is stable, unique, and opaque, like all good IDs.
Id mypkg.ID `json:"id"`
}
// Role is a type a user may have. // Role is a type a user may have.
type Role string type Role string
@@ -62,26 +74,46 @@ type UserQueryInput struct {
func OmitEmptyQuery( func OmitEmptyQuery(
client graphql.Client, client graphql.Client,
query UserQueryInput, query UserQueryInput,
queries []UserQueryInput,
dt time.Time, dt time.Time,
tz string, tz string,
tzNoOmitEmpty string, tzNoOmitEmpty string,
) (*OmitEmptyQueryResponse, error) { ) (*OmitEmptyQueryResponse, error) {
variables := map[string]interface{}{ variables := map[string]interface{}{
"query": query,
"dt": dt,
"tz": tz,
"tzNoOmitEmpty": tzNoOmitEmpty, "tzNoOmitEmpty": tzNoOmitEmpty,
} }
var zero_query UserQueryInput
if query != zero_query {
variables["query"] = query
}
if len(queries) > 0 {
variables["queries"] = queries
}
var zero_dt time.Time
if dt != zero_dt {
variables["dt"] = dt
}
var zero_tz string
if tz != zero_tz {
variables["tz"] = tz
}
var retval OmitEmptyQueryResponse var retval OmitEmptyQueryResponse
err := client.MakeRequest( err := client.MakeRequest(
nil, nil,
"OmitEmptyQuery", "OmitEmptyQuery",
` `
query OmitEmptyQuery ($query: UserQueryInput, $dt: DateTime, $tz: String, $tzNoOmitEmpty: String) { query OmitEmptyQuery ($query: UserQueryInput, $queries: [UserQueryInput], $dt: DateTime, $tz: String, $tzNoOmitEmpty: String) {
user(query: $query) { user(query: $query) {
id id
} }
users(query: $queries) {
id
}
maybeConvert(dt: $dt, tz: $tz) maybeConvert(dt: $dt, tz: $tz)
convert2: maybeConvert(dt: $dt, tz: $tzNoOmitEmpty) convert2: maybeConvert(dt: $dt, tz: $tzNoOmitEmpty)
} }
+1 -1
View File
@@ -2,7 +2,7 @@
"operations": [ "operations": [
{ {
"operationName": "OmitEmptyQuery", "operationName": "OmitEmptyQuery",
"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", "query": "\nquery OmitEmptyQuery ($query: UserQueryInput, $queries: [UserQueryInput], $dt: DateTime, $tz: String, $tzNoOmitEmpty: String) {\n\tuser(query: $query) {\n\t\tid\n\t}\n\tusers(query: $queries) {\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" "sourceLocation": "testdata/queries/Omitempty.graphql"
} }
] ]
+2
View File
@@ -99,6 +99,8 @@ type Query {
""" """
user(query: UserQueryInput): User user(query: UserQueryInput): User
users(query: [UserQueryInput]): User
"""usersWithRole looks a user up by role.""" """usersWithRole looks a user up by role."""
usersWithRole(role: Role!): [User!]! usersWithRole(role: Role!): [User!]!
root: Topic! root: Topic!