1
2
3
4
5
6
7
8
9
10
11
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 }
156
View as plain text