github.com/maeglindeveloper/gqlgen@v0.13.1-0.20210413081235-57808b12a0a0/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 Query {
    13  	updateUser(id: ID!, changes: UserChanges!): User
    14  }
    15  
    16  type 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 *queryResolver) 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  We often use the mapstructure library to directly apply these changesets directly to the object using reflection:
    40  ```go
    41  
    42  func ApplyChanges(changes map[string]interface{}, to interface{}) error {
    43  	dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
    44  		ErrorUnused: true,
    45  		TagName:     "json",
    46  		Result:      to,
    47  		ZeroFields:  true,
    48  		// This is needed to get mapstructure to call the gqlgen unmarshaler func for custom scalars (eg Date)
    49  		DecodeHook: func(a reflect.Type, b reflect.Type, v interface{}) (interface{}, error) {
    50  			if reflect.PtrTo(b).Implements(reflect.TypeOf((*graphql.Unmarshaler)(nil)).Elem()) {
    51  				resultType := reflect.New(b)
    52  				result := resultType.MethodByName("UnmarshalGQL").Call([]reflect.Value{reflect.ValueOf(v)})
    53  				err, _ := result[0].Interface().(error)
    54  				return resultType.Elem().Interface(), err
    55  			}
    56  
    57  			return v, nil
    58  		},
    59  	})
    60  
    61  	if err != nil {
    62  		return err
    63  	}
    64  
    65  	return dec.Decode(changes)
    66  }
    67  ```