1
2
3
4
5
6
7
8
9
10
11
12
13 package memorydb
14
15 import (
16 "bytes"
17 "context"
18 "encoding/json"
19 "errors"
20 "io"
21 "net/http"
22 "strings"
23
24 "github.com/go-kivik/kivik/v4/driver"
25 "github.com/go-kivik/kivik/v4/x/mango"
26 )
27
28 var errFindNotImplemented = errors.New("find feature not yet implemented")
29
30 type findQuery struct {
31 Selector *mango.Selector `json:"selector"`
32 Limit int64 `json:"limit"`
33 Skip int64 `json:"skip"`
34 Sort []string `json:"sort"`
35 Fields []string `json:"fields"`
36 UseIndex indexSpec `json:"use_index"`
37 }
38
39 type indexSpec struct {
40 ddoc string
41 index string
42 }
43
44 func (i *indexSpec) UnmarshalJSON(data []byte) error {
45 if data[0] == '"' {
46 return json.Unmarshal(data, &i.ddoc)
47 }
48 var values []string
49 if err := json.Unmarshal(data, &values); err != nil {
50 return err
51 }
52 const maxValues = 2
53 if len(values) == 0 || len(values) > maxValues {
54 return errors.New("invalid index specification")
55 }
56 i.ddoc = values[0]
57 if len(values) == maxValues {
58 i.index = values[1]
59 }
60 return nil
61 }
62
63 var _ driver.Finder = &db{}
64
65 func (d *db) CreateIndex(context.Context, string, string, interface{}, driver.Options) error {
66 return errFindNotImplemented
67 }
68
69 func (d *db) GetIndexes(context.Context, driver.Options) ([]driver.Index, error) {
70 return nil, errFindNotImplemented
71 }
72
73 func (d *db) DeleteIndex(context.Context, string, string, driver.Options) error {
74 return errFindNotImplemented
75 }
76
77 func (d *db) Find(ctx context.Context, query interface{}, _ driver.Options) (driver.Rows, error) {
78 if exists, _ := d.DBExists(ctx, d.dbName, nil); !exists {
79 return nil, statusError{status: http.StatusNotFound, error: errors.New("database does not exist")}
80 }
81 queryJSON, err := toJSON(query)
82 if err != nil {
83 return nil, err
84 }
85 fq := &findQuery{}
86 if err := json.NewDecoder(queryJSON).Decode(&fq); err != nil {
87 return nil, err
88 }
89 if fq == nil || fq.Selector == nil {
90 return nil, errors.New("Missing required key: selector")
91 }
92 fields := make(map[string]struct{}, len(fq.Fields))
93 for _, field := range fq.Fields {
94 fields[field] = struct{}{}
95 }
96 rows := &findResults{
97 resultSet: resultSet{
98 docIDs: make([]string, 0),
99 revs: make([]*revision, 0),
100 },
101 fields: fields,
102 }
103 for docID := range d.db.docs {
104 if doc, found := d.db.latestRevision(docID); found {
105 var cd couchDoc
106 if err := json.Unmarshal(doc.data, &cd); err != nil {
107 panic(err)
108 }
109 if fq.Selector.Match(map[string]interface{}(cd)) {
110 rows.docIDs = append(rows.docIDs, docID)
111 rows.revs = append(rows.revs, doc)
112 }
113 }
114 }
115 rows.offset = 0
116 rows.totalRows = int64(len(rows.docIDs))
117 return rows, nil
118 }
119
120 func (d *db) Explain(context.Context, interface{}, driver.Options) (*driver.QueryPlan, error) {
121 return nil, errFindNotImplemented
122 }
123
124 type findResults struct {
125 resultSet
126 fields map[string]struct{}
127 }
128
129 var (
130 _ driver.Rows = &findResults{}
131 _ driver.RowsWarner = &findResults{}
132 )
133
134 func (r *findResults) Warning() string {
135 return "no matching index found, create an index to optimize query time"
136 }
137
138 func (r *findResults) Next(row *driver.Row) error {
139 if r.revs == nil || len(r.revs) == 0 {
140 return io.EOF
141 }
142 row.ID, r.docIDs = r.docIDs[0], r.docIDs[1:]
143 doc, err := r.filterDoc(r.revs[0].data)
144 if err != nil {
145 return err
146 }
147 row.Doc = bytes.NewReader(doc)
148 r.revs = r.revs[1:]
149 return nil
150 }
151
152 func (r *findResults) filterDoc(data []byte) ([]byte, error) {
153 if len(r.fields) == 0 {
154 return data, nil
155 }
156 var intermediateDoc map[string]interface{}
157 if err := json.Unmarshal(data, &intermediateDoc); err != nil {
158 return nil, err
159 }
160 for field := range intermediateDoc {
161 if _, ok := r.fields[field]; !ok {
162 delete(intermediateDoc, field)
163 }
164 }
165 return json.Marshal(intermediateDoc)
166 }
167
168
169
170 func toJSON(i interface{}) (io.Reader, error) {
171 switch t := i.(type) {
172 case string:
173 return strings.NewReader(t), nil
174 case []byte:
175 return bytes.NewReader(t), nil
176 case json.RawMessage:
177 return bytes.NewReader(t), nil
178 default:
179 buf := &bytes.Buffer{}
180 err := json.NewEncoder(buf).Encode(i)
181 return buf, err
182 }
183 }
184
View as plain text