github.com/99designs/gqlgen@v0.17.45/docs/content/reference/changesets.md (about)

     1  ---
     2  linkTitle: Changesets
     3  title: Using maps as changesets
     4  description: Falling back to map[string]interface{} to allow for presence checks.
     5  menu: { main: { parent: 'reference', weight: 10 } }
     6  ---
     7  
     8  Occasionally you need to distinguish presence from nil (undefined vs null). In gqlgen we do this using maps:
     9  
    10  
    11  ```graphql
    12  type Mutation {
    13  	updateUser(id: ID!, changes: UserChanges!): User
    14  }
    15  
    16  input UserChanges {
    17  	name: String
    18  	email: String
    19  }
    20  ```
    21  
    22  Then in config set the backing type to `map[string]interface{}`
    23  ```yaml
    24  models:
    25    UserChanges:
    26      model: "map[string]interface{}"
    27  ```
    28  
    29  After running go generate you should end up with a resolver that looks like this:
    30  ```go
    31  func (r *mutationResolver) UpdateUser(ctx context.Context, id int, changes map[string]interface{}) (*User, error) {
    32  	u := fetchFromDb(id)
    33  	/// apply the changes
    34  	saveToDb(u)
    35  	return u, nil
    36  }
    37  ```
    38  
    39  Please note that map values are automatically coerced to the types defined in the schema.
    40  This means that optional, nested inputs or scalars will conform to their expected types.
    41  
    42  We often use the mapstructure library to directly apply these changesets directly to the object using reflection:
    43  ```go
    44  
    45  func ApplyChanges(changes map[string]interface{}, to interface{}) error {
    46  	dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
    47  		ErrorUnused: true,
    48  		TagName:     "json",
    49  		Result:      to,
    50  		ZeroFields:  true,
    51  		// This is needed to get mapstructure to call the gqlgen unmarshaler func for custom scalars (eg Date)
    52  		DecodeHook: func(a reflect.Type, b reflect.Type, v interface{}) (interface{}, error) {
    53  			if reflect.PtrTo(b).Implements(reflect.TypeOf((*graphql.Unmarshaler)(nil)).Elem()) {
    54  				resultType := reflect.New(b)
    55  				result := resultType.MethodByName("UnmarshalGQL").Call([]reflect.Value{reflect.ValueOf(v)})
    56  				err, _ := result[0].Interface().(error)
    57  				return resultType.Elem().Interface(), err
    58  			}
    59  
    60  			return v, nil
    61  		},
    62  	})
    63  
    64  	if err != nil {
    65  		return err
    66  	}
    67  
    68  	return dec.Decode(changes)
    69  }
    70  ```