1
2
3
4
5
6
7
8
9
10
11
12
13 package db
14
15 import (
16 "context"
17 "fmt"
18 "sort"
19
20 "gitlab.com/flimzy/testy"
21
22 "github.com/go-kivik/kivik/v4"
23 "github.com/go-kivik/kivik/v4/kiviktest/kt"
24 )
25
26 func init() {
27 kt.Register("Query", query)
28 }
29
30 func query(ctx *kt.Context) {
31 ctx.RunRW(func(ctx *kt.Context) {
32 testQueryRW(ctx)
33 })
34 }
35
36 func testQueryRW(ctx *kt.Context) {
37 if ctx.Admin == nil {
38
39 return
40 }
41 dbName, expected, err := setUpQueryTest(ctx)
42 if err != nil {
43 ctx.Errorf("Failed to set up temp db: %s", err)
44 }
45 ctx.Run("group", func(ctx *kt.Context) {
46 ctx.RunAdmin(func(ctx *kt.Context) {
47 doQueryTest(ctx, ctx.Admin, dbName, 0, expected)
48 })
49 ctx.RunNoAuth(func(ctx *kt.Context) {
50 doQueryTest(ctx, ctx.NoAuth, dbName, 0, expected)
51 })
52 })
53 }
54
55 var ddoc = map[string]interface{}{
56 "_id": "_design/testddoc",
57 "language": "javascript",
58 "views": map[string]interface{}{
59 "testview": map[string]interface{}{
60 "map": `function(doc) {
61 if (doc.include) {
62 emit(doc._id, doc.index);
63 }
64 }`,
65 },
66 },
67 }
68
69 func setUpQueryTest(ctx *kt.Context) (dbName string, docIDs []string, err error) {
70 dbName = ctx.TestDB()
71 db := ctx.Admin.DB(dbName, ctx.Options("db"))
72 if err := db.Err(); err != nil {
73 return dbName, nil, fmt.Errorf("fialed to connect to db: %w", err)
74 }
75 if _, err := db.Put(context.Background(), ddoc["_id"].(string), ddoc); err != nil {
76 return dbName, nil, fmt.Errorf("fialed to create design doc: %w", err)
77 }
78 const maxDocs = 10
79 docIDs = make([]string, maxDocs)
80 for i := range docIDs {
81 id := ctx.TestDBName()
82 doc := struct {
83 ID string `json:"id"`
84 Include bool `json:"include"`
85 Index int `json:"index"`
86 }{
87 ID: id,
88 Include: true,
89 Index: i,
90 }
91 if _, err := db.Put(context.Background(), doc.ID, doc); err != nil {
92 return dbName, nil, fmt.Errorf("failed to create doc: %w", err)
93 }
94 docIDs[i] = id
95 }
96 sort.Strings(docIDs)
97 return dbName, docIDs, nil
98 }
99
100 func doQueryTest(ctx *kt.Context, client *kivik.Client, dbName string, expOffset int64, expected []string) {
101 ctx.Run("WithDocs", func(ctx *kt.Context) {
102 doQueryTestWithDocs(ctx, client, dbName, expOffset, expected)
103 })
104 ctx.Run("WithoutDocs", func(ctx *kt.Context) {
105 doQueryTestWithoutDocs(ctx, client, dbName, expOffset, expected)
106 })
107 }
108
109 func doQueryTestWithoutDocs(ctx *kt.Context, client *kivik.Client, dbName string, expOffset int64, expected []string) {
110 ctx.Parallel()
111 db := client.DB(dbName, ctx.Options("db"))
112
113
114 if err := db.Err(); err != nil && !ctx.IsExpectedSuccess(err) {
115 return
116 }
117
118 rows := db.Query(context.Background(), "testddoc", "testview")
119 if !ctx.IsExpectedSuccess(rows.Err()) {
120 return
121 }
122 docIDs := make([]string, 0, len(expected))
123 var scanTested bool
124 for rows.Next() {
125 id, _ := rows.ID()
126 docIDs = append(docIDs, id)
127 if !scanTested {
128 scanTested = true
129 ctx.Run("ScanDoc", func(ctx *kt.Context) {
130 var i interface{}
131 ctx.CheckError(rows.ScanDoc(&i))
132 })
133 ctx.Run("ScanValue", func(ctx *kt.Context) {
134 var i interface{}
135 ctx.CheckError(rows.ScanValue(&i))
136 })
137 }
138 }
139 meta, err := rows.Metadata()
140 if err != nil {
141 ctx.Fatalf("Failed to fetch row: %s", rows.Err())
142 }
143 if d := testy.DiffTextSlices(expected, docIDs); d != nil {
144 ctx.Errorf("Unexpected document IDs returned:\n%s\n", d)
145 }
146 if expOffset != meta.Offset {
147 ctx.Errorf("offset: Expected %d, got %d", expOffset, meta.Offset)
148 }
149 if int64(len(expected)) != meta.TotalRows {
150 ctx.Errorf("total rows: Expected %d, got %d", len(expected), meta.TotalRows)
151 }
152 }
153
154 func doQueryTestWithDocs(ctx *kt.Context, client *kivik.Client, dbName string, expOffset int64, expected []string) {
155 ctx.Parallel()
156 db := client.DB(dbName, ctx.Options("db"))
157
158
159 if err := db.Err(); err != nil && !ctx.IsExpectedSuccess(err) {
160 return
161 }
162 opts := kivik.Params(map[string]interface{}{
163 "include_docs": true,
164 "update_seq": true,
165 })
166
167 rows := db.Query(context.Background(), "testddoc", "testview", opts)
168 if !ctx.IsExpectedSuccess(rows.Err()) {
169 return
170 }
171 docIDs := make([]string, 0, len(expected))
172 for rows.Next() {
173 var doc struct {
174 ID string `json:"_id"`
175 Rev string `json:"_rev"`
176 Index int `json:"index"`
177 }
178 if err := rows.ScanDoc(&doc); err != nil {
179 ctx.Errorf("Failed to scan doc: %s", err)
180 }
181 var value int
182 if err := rows.ScanValue(&value); err != nil {
183 ctx.Errorf("Failed to scan value: %s", err)
184 }
185 if value != doc.Index {
186 ctx.Errorf("doc._rev = %d, but value = %d", doc.Index, value)
187 }
188 id, _ := rows.ID()
189 if doc.ID != id {
190 ctx.Errorf("doc._id = %s, but rows.ID = %s", doc.ID, id)
191 }
192 docIDs = append(docIDs, id)
193 }
194 meta, err := rows.Metadata()
195 if err != nil {
196 ctx.Fatalf("Failed to fetch row: %s", rows.Err())
197 }
198 if d := testy.DiffTextSlices(expected, docIDs); d != nil {
199 ctx.Errorf("Unexpected document IDs returned:\n%s\n", d)
200 }
201 if expOffset != meta.Offset {
202 ctx.Errorf("offset: Expected %d, got %d", expOffset, meta.Offset)
203 }
204 ctx.Run("UpdateSeq", func(ctx *kt.Context) {
205 if meta.UpdateSeq == "" {
206 ctx.Errorf("Expected updated sequence")
207 }
208 })
209 if int64(len(expected)) != meta.TotalRows {
210 ctx.Errorf("total rows: Expected %d, got %d", len(expected), meta.TotalRows)
211 }
212 }
213
View as plain text