...

Source file src/github.com/go-kivik/kivik/v4/options.go

Documentation: github.com/go-kivik/kivik/v4

     1  // Licensed under the Apache License, Version 2.0 (the "License"); you may not
     2  // use this file except in compliance with the License. You may obtain a copy of
     3  // the License at
     4  //
     5  //  http://www.apache.org/licenses/LICENSE-2.0
     6  //
     7  // Unless required by applicable law or agreed to in writing, software
     8  // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
     9  // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
    10  // License for the specific language governing permissions and limitations under
    11  // the License.
    12  
    13  package kivik
    14  
    15  import (
    16  	"fmt"
    17  	"net/url"
    18  	"strconv"
    19  	"strings"
    20  	"time"
    21  
    22  	"github.com/go-kivik/kivik/v4/driver"
    23  )
    24  
    25  // Option is a Kivik or driver option.
    26  //
    27  // Most methods/endpoints take query parameters which are passed as part of
    28  // the query URL, as documented in the official CouchDB documentation. You can
    29  // use [Params] or [Param] to set arbitrary query parameters. Backend drivers
    30  // may provide their own special-purpose options as well.
    31  type Option interface {
    32  	// Apply applies the option to target, if target is of the expected type.
    33  	// Unexpected/recognized target types should be ignored.
    34  	Apply(target interface{})
    35  }
    36  
    37  var _ Option = (driver.Options)(nil)
    38  
    39  type multiOptions []Option
    40  
    41  var _ Option = (multiOptions)(nil)
    42  
    43  func (o multiOptions) Apply(t interface{}) {
    44  	for _, opt := range o {
    45  		if opt != nil {
    46  			opt.Apply(t)
    47  		}
    48  	}
    49  }
    50  
    51  func (o multiOptions) String() string {
    52  	parts := make([]string, 0, len(o))
    53  	for _, opt := range o {
    54  		if o != nil {
    55  			if part := fmt.Sprintf("%s", opt); part != "" {
    56  				parts = append(parts, part)
    57  			}
    58  		}
    59  	}
    60  	return strings.Join(parts, ",")
    61  }
    62  
    63  type params map[string]interface{}
    64  
    65  // Apply applies o to target. The following target types are supported:
    66  //
    67  //   - map[string]interface{}
    68  //   - *url.Values
    69  func (o params) Apply(target interface{}) {
    70  	switch t := target.(type) {
    71  	case map[string]interface{}:
    72  		for k, v := range o {
    73  			t[k] = v
    74  		}
    75  	case *url.Values:
    76  		for key, i := range o {
    77  			var values []string
    78  			switch v := i.(type) {
    79  			case string:
    80  				values = []string{v}
    81  			case []string:
    82  				values = v
    83  			case bool:
    84  				values = []string{fmt.Sprintf("%t", v)}
    85  			case int, uint, uint8, uint16, uint32, uint64, int8, int16, int32, int64:
    86  				values = []string{fmt.Sprintf("%d", v)}
    87  			case float64:
    88  				values = []string{strconv.FormatFloat(v, 'f', -1, 64)}
    89  			case float32:
    90  				values = []string{strconv.FormatFloat(float64(v), 'f', -1, 32)}
    91  			default:
    92  				panic(fmt.Sprintf("kivik: unknown option type: %T", v))
    93  			}
    94  			for _, value := range values {
    95  				t.Add(key, value)
    96  			}
    97  		}
    98  	}
    99  }
   100  
   101  func (o params) String() string {
   102  	if len(o) == 0 {
   103  		return ""
   104  	}
   105  	return fmt.Sprintf("%v", map[string]interface{}(o))
   106  }
   107  
   108  // Params allows passing a collection of key/value pairs as query parameter
   109  // options.
   110  func Params(p map[string]interface{}) Option {
   111  	return params(p)
   112  }
   113  
   114  // Param sets a single key/value pair as a query parameter.
   115  func Param(key string, value interface{}) Option {
   116  	return params{key: value}
   117  }
   118  
   119  // Rev is a convenience function to set the revision. A less verbose alternative
   120  // to Param("rev", rev).
   121  func Rev(rev string) Option {
   122  	return params{"rev": rev}
   123  }
   124  
   125  // IncludeDocs instructs the query to include documents. A less verbose
   126  // alternative to Param("include_docs", true).
   127  func IncludeDocs() Option {
   128  	return params{"include_docs": true}
   129  }
   130  
   131  type durationParam struct {
   132  	key   string
   133  	value time.Duration
   134  }
   135  
   136  var _ Option = durationParam{}
   137  
   138  // Apply supports map[string]interface{} and *url.Values targets.
   139  func (p durationParam) Apply(target interface{}) {
   140  	switch t := target.(type) {
   141  	case map[string]interface{}:
   142  		t[p.key] = fmt.Sprintf("%d", p.value/time.Millisecond)
   143  	case *url.Values:
   144  		t.Add(p.key, fmt.Sprintf("%d", p.value/time.Millisecond))
   145  	}
   146  }
   147  
   148  func (p durationParam) String() string {
   149  	return fmt.Sprintf("[%s=%s]", p.key, p.value)
   150  }
   151  
   152  // Duration is a convenience function for setting query parameters from
   153  // [time.Duration] values. The duration will be converted to milliseconds when
   154  // passed as a query parameter.
   155  //
   156  // For example, Duration("heartbeat", 15 * time.Second) will result in appending
   157  // ?heartbeat=15000 to the query.
   158  func Duration(key string, dur time.Duration) Option {
   159  	return durationParam{
   160  		key:   key,
   161  		value: dur,
   162  	}
   163  }
   164  

View as plain text