github.com/go-kivik/kivik/v4@v4.3.2/couchdb/find.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 couchdb 14 15 import ( 16 "context" 17 "encoding/json" 18 "fmt" 19 "net/http" 20 21 "github.com/go-kivik/kivik/v4/couchdb/chttp" 22 "github.com/go-kivik/kivik/v4/driver" 23 ) 24 25 const ( 26 pathIndex = "_index" 27 ) 28 29 func (d *db) CreateIndex(ctx context.Context, ddoc, name string, index interface{}, options driver.Options) error { 30 opts := map[string]interface{}{} 31 options.Apply(opts) 32 reqPath := partPath(pathIndex) 33 options.Apply(reqPath) 34 indexObj, err := deJSONify(index) 35 if err != nil { 36 return err 37 } 38 parameters := struct { 39 Index interface{} `json:"index"` 40 Ddoc string `json:"ddoc,omitempty"` 41 Name string `json:"name,omitempty"` 42 }{ 43 Index: indexObj, 44 Ddoc: ddoc, 45 Name: name, 46 } 47 chttpOpts := &chttp.Options{ 48 Body: chttp.EncodeBody(parameters), 49 } 50 _, err = d.Client.DoError(ctx, http.MethodPost, d.path(reqPath.String()), chttpOpts) 51 return err 52 } 53 54 func (d *db) GetIndexes(ctx context.Context, options driver.Options) ([]driver.Index, error) { 55 opts := map[string]interface{}{} 56 options.Apply(opts) 57 reqPath := partPath(pathIndex) 58 options.Apply(reqPath) 59 var result struct { 60 Indexes []driver.Index `json:"indexes"` 61 } 62 err := d.Client.DoJSON(ctx, http.MethodGet, d.path(reqPath.String()), nil, &result) 63 return result.Indexes, err 64 } 65 66 func (d *db) DeleteIndex(ctx context.Context, ddoc, name string, options driver.Options) error { 67 opts := map[string]interface{}{} 68 options.Apply(opts) 69 if ddoc == "" { 70 return missingArg("ddoc") 71 } 72 if name == "" { 73 return missingArg("name") 74 } 75 reqPath := partPath(pathIndex) 76 options.Apply(reqPath) 77 path := fmt.Sprintf("%s/%s/json/%s", reqPath, ddoc, name) 78 _, err := d.Client.DoError(ctx, http.MethodDelete, d.path(path), nil) 79 return err 80 } 81 82 func (d *db) Find(ctx context.Context, query interface{}, options driver.Options) (driver.Rows, error) { 83 opts := map[string]interface{}{} 84 options.Apply(opts) 85 reqPath := partPath("_find") 86 options.Apply(reqPath) 87 chttpOpts := &chttp.Options{ 88 GetBody: chttp.BodyEncoder(query), 89 Header: http.Header{ 90 chttp.HeaderIdempotencyKey: []string{}, 91 }, 92 } 93 resp, err := d.Client.DoReq(ctx, http.MethodPost, d.path(reqPath.String()), chttpOpts) 94 if err != nil { 95 return nil, err 96 } 97 if err = chttp.ResponseError(resp); err != nil { 98 return nil, err 99 } 100 return newFindRows(ctx, resp.Body), nil 101 } 102 103 type queryPlan struct { 104 DBName string `json:"dbname"` 105 Index map[string]interface{} `json:"index"` 106 Selector map[string]interface{} `json:"selector"` 107 Options map[string]interface{} `json:"opts"` 108 Limit int64 `json:"limit"` 109 Skip int64 `json:"skip"` 110 Fields fields `json:"fields"` 111 Range map[string]interface{} `json:"range"` 112 } 113 114 type fields []interface{} 115 116 func (f *fields) UnmarshalJSON(data []byte) error { 117 if string(data) == `"all_fields"` { 118 return nil 119 } 120 var i []interface{} 121 if err := json.Unmarshal(data, &i); err != nil { 122 return err 123 } 124 newFields := make([]interface{}, len(i)) 125 copy(newFields, i) 126 *f = newFields 127 return nil 128 } 129 130 func (d *db) Explain(ctx context.Context, query interface{}, options driver.Options) (*driver.QueryPlan, error) { 131 opts := map[string]interface{}{} 132 options.Apply(opts) 133 reqPath := partPath("_explain") 134 options.Apply(reqPath) 135 chttpOpts := &chttp.Options{ 136 GetBody: chttp.BodyEncoder(query), 137 Header: http.Header{ 138 chttp.HeaderIdempotencyKey: []string{}, 139 }, 140 } 141 var plan queryPlan 142 if err := d.Client.DoJSON(ctx, http.MethodPost, d.path(reqPath.String()), chttpOpts, &plan); err != nil { 143 return nil, err 144 } 145 return &driver.QueryPlan{ 146 DBName: plan.DBName, 147 Index: plan.Index, 148 Selector: plan.Selector, 149 Options: plan.Options, 150 Limit: plan.Limit, 151 Skip: plan.Skip, 152 Fields: plan.Fields, 153 Range: plan.Range, 154 }, nil 155 }