github.com/go-kivik/kivik/v4@v4.3.2/options.go (about) 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 }