Uploaded image for project: 'Go Driver'
  1. Go Driver
  2. GODRIVER-2696

Use an options pattern that doesn't require merging structs

    • Type: Icon: Improvement Improvement
    • Resolution: Fixed
    • Priority: Icon: Unknown Unknown
    • 2.0.0
    • Affects Version/s: None
    • Component/s: None
    • None
    • Major Change
    • Needed
    • Hide

      1. What would you like to communicate to the user about this feature?

      we’ve decided to abstract the merge functions by changing the options builder pattern to maintain a slice of setter functions, rather than setting data directly to an options object. Typical usage of options should not change, for example the following is still honored:

      opts1 := options.Client().SetAppName("appName")
      opts2 := options.Client().SetConnectTimeout(math.MaxInt64)
      
      _, err := mongo.Connect(opts1, opts2)
      if err != nil {
      	panic(err)
      }
      

      There are, however, two notable use cases that will change for users.

      Modifying Fields After Building

      The options builder is now a slice of setters, rather than a single options object. In order to modify the data after building, users will need to create a custom setter function and append the builder’s Opts slice:

      opts := options.Client().ApplyURI("mongodb://x:y@localhost:27017")
      
      // If the username is "x", use password "z"
      usernameSetter := func(opts *options.ClientOptions) error {
      if opts.Auth.Username == "x" {
          opts.Auth.Password = "z"
      }
      
      return nil
      }
      
      opts.Opts = append(opts.Opts, fn)
      

      Creating a slice of Options

      Using options created with the builder pattern as elements in a slice:

      opts1 := options.Client().SetAppName("appName")
      opts2 := options.Client().SetConnectTimeout(math.MaxInt64)
      
      // Option objects are "Listers" in V2, objects that hold a list of setters
      opts := []options.Lister[options.ClientOptions]{opts1, opts2}
      _, err := mongo.Connect(opts...)
      

      2. Would you like the user to see examples of the syntax and/or executable code and its output?
      This is not necessary since the general use case will not change.

      3. Which versions of the driver/connector does this apply to?
      V2

      Show
      1. What would you like to communicate to the user about this feature? we’ve decided to abstract the merge functions by changing the options builder pattern to maintain a slice of setter functions, rather than setting data directly to an options object. Typical usage of options should not change, for example the following is still honored: opts1 := options.Client().SetAppName( "appName" ) opts2 := options.Client().SetConnectTimeout(math.MaxInt64) _, err := mongo.Connect(opts1, opts2) if err != nil { panic(err) } There are, however, two notable use cases that will change for users. Modifying Fields After Building The options builder is now a slice of setters, rather than a single options object. In order to modify the data after building, users will need to create a custom setter function and append the builder’s Opts slice: opts := options.Client().ApplyURI( "mongodb: //x:y@localhost:27017" ) // If the username is "x" , use password "z" usernameSetter := func(opts *options.ClientOptions) error { if opts.Auth.Username == "x" { opts.Auth.Password = "z" } return nil } opts.Opts = append(opts.Opts, fn) Creating a slice of Options Using options created with the builder pattern as elements in a slice: opts1 := options.Client().SetAppName( "appName" ) opts2 := options.Client().SetConnectTimeout(math.MaxInt64) // Option objects are "Listers" in V2, objects that hold a list of setters opts := []options.Lister[options.ClientOptions]{opts1, opts2} _, err := mongo.Connect(opts...) 2. Would you like the user to see examples of the syntax and/or executable code and its output? This is not necessary since the general use case will not change. 3. Which versions of the driver/connector does this apply to? V2

      Currently we maintain many Merge*Options functions that merge options structs together. These are used to merge possibly many options structs passed to functions that accept a variadic argument of 0 or more options structs. While that function signature has the benefit of allowing users to pass or not pass options, maintaining the Merge*Options functions adds a significant maintenance burden and has resulted in numerous bugs.

      Find and implement an optional arguments pattern that doesn't require maintaining dedicated code for merging each type of option struct together when multiple options structs are provided.

      Definition of done:

      • Implement an optional arguments pattern that doesn't require maintaining dedicated code for merging each type of option struct together.
      • Remove all Merge*Options options struct merging functions in all packages.

            Assignee:
            preston.vasquez@mongodb.com Preston Vasquez
            Reporter:
            matt.dale@mongodb.com Matt Dale
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: