Skip to content

Commit

Permalink
Merge pull request #1001 from go-kivik/moreCaching
Browse files Browse the repository at this point in the history
Detect conflicting key options
  • Loading branch information
flimzy authored Jun 19, 2024
2 parents afa4c34 + bd8a322 commit d30346c
Show file tree
Hide file tree
Showing 3 changed files with 212 additions and 14 deletions.
30 changes: 28 additions & 2 deletions x/sqlite/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -793,7 +793,7 @@ func (o optsMap) viewOptions(view string) (*viewOptions, error) {
return nil, err
}

return &viewOptions{
v := &viewOptions{
view: view,
limit: limit,
skip: skip,
Expand All @@ -815,5 +815,31 @@ func (o optsMap) viewOptions(view string) (*viewOptions, error) {
keys: keys,
sorted: sorted,
attEncodingInfo: attEncodingInfo,
}, nil
}
return v, v.validate()
}

func (v viewOptions) validate() error {
descendingModifier := 1
if v.descending {
descendingModifier = -1
}
if v.endkey != "" && v.startkey != "" && couchdbCmpString(v.startkey, v.endkey)*descendingModifier > 0 {
return &internal.Error{Status: http.StatusBadRequest, Message: fmt.Sprintf("no rows can match your key range, reverse your start_key and end_key or set descending=%v", !v.descending)}
}
if v.key != "" {
startFail := v.startkey != "" && couchdbCmpString(v.key, v.startkey)*descendingModifier < 0
endFail := v.endkey != "" && couchdbCmpString(v.key, v.endkey)*descendingModifier > 0
if startFail && v.endkey != "" || endFail && v.startkey != "" {
return &internal.Error{Status: http.StatusBadRequest, Message: "no rows can match your key range, change your start_key, end_key, or key"}
}
if startFail {
return &internal.Error{Status: http.StatusBadRequest, Message: fmt.Sprintf("no rows can match your key range, change your start_key or key or set descending=%v", !v.descending)}
}
if endFail {
return &internal.Error{Status: http.StatusBadRequest, Message: fmt.Sprintf("no rows can match your key range, reverse your end_key or key or set descending=%v", !v.descending)}
}
}

return nil
}
185 changes: 184 additions & 1 deletion x/sqlite/options_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -767,7 +767,190 @@ func Test_viewOptions(t *testing.T) {
wantErr: "invalid value for 'att_encoding_info': chicken",
wantStatus: http.StatusBadRequest,
})

tests.Add("keys + key", test{
options: kivik.Params(map[string]interface{}{
"key": "a",
"keys": []string{"b", "c"},
}),
wantErr: "`keys` is incompatible with `key`, `start_key` and `end_key`",
wantStatus: http.StatusBadRequest,
})
tests.Add("keys + endkey", test{
options: kivik.Params(map[string]interface{}{
"endkey": "a",
"keys": []string{"b", "c"},
}),
wantErr: "`keys` is incompatible with `key`, `start_key` and `end_key`",
wantStatus: http.StatusBadRequest,
})
tests.Add("keys + startkey", test{
options: kivik.Params(map[string]interface{}{
"startkey": "a",
"keys": []string{"b", "c"},
}),
wantErr: "`keys` is incompatible with `key`, `start_key` and `end_key`",
wantStatus: http.StatusBadRequest,
})
tests.Add("key & startkey conflict", test{
options: kivik.Params(map[string]interface{}{
"startkey": "d",
"key": "a",
}),
wantErr: "no rows can match your key range, change your start_key or key or set descending=true",
wantStatus: http.StatusBadRequest,
})
tests.Add("key & startkey no conflict", test{
options: kivik.Params(map[string]interface{}{
"startkey": "a",
"key": "a",
}),
want: &viewOptions{
limit: -1,
inclusiveEnd: true,
update: "true",
sorted: true,
startkey: `"a"`,
key: `"a"`,
},
})
tests.Add("key & startkey + descending", test{
options: kivik.Params(map[string]interface{}{
"startkey": "d",
"key": "a",
"descending": true,
}),
want: &viewOptions{
limit: -1,
inclusiveEnd: true,
update: "true",
sorted: true,
descending: true,
startkey: `"d"`,
key: `"a"`,
},
})
tests.Add("key & startkey + descending conflict", test{
options: kivik.Params(map[string]interface{}{
"startkey": "a",
"key": "b",
"descending": true,
}),
wantErr: "no rows can match your key range, change your start_key or key or set descending=false",
wantStatus: http.StatusBadRequest,
})
tests.Add("key & endkey conflict", test{
options: kivik.Params(map[string]interface{}{
"endkey": "a",
"key": "b",
}),
wantErr: "no rows can match your key range, reverse your end_key or key or set descending=true",
wantStatus: http.StatusBadRequest,
})
tests.Add("key & endkey no conflict", test{
options: kivik.Params(map[string]interface{}{
"endkey": "a",
"key": "a",
}),
want: &viewOptions{
limit: -1,
inclusiveEnd: true,
update: "true",
sorted: true,
endkey: `"a"`,
key: `"a"`,
},
})
tests.Add("key & endkey + descending", test{
options: kivik.Params(map[string]interface{}{
"endkey": "a",
"key": "b",
"descending": true,
}),
want: &viewOptions{
limit: -1,
inclusiveEnd: true,
update: "true",
sorted: true,
descending: true,
endkey: `"a"`,
key: `"b"`,
},
})
tests.Add("key & endkey + descending conflict", test{
options: kivik.Params(map[string]interface{}{
"endkey": "b",
"key": "a",
"descending": true,
}),
wantErr: "no rows can match your key range, reverse your end_key or key or set descending=false",
wantStatus: http.StatusBadRequest,
})
tests.Add("endkey and startkey conflict", test{
options: kivik.Params(map[string]interface{}{
"startkey": "z",
"endkey": "a",
}),
wantErr: "no rows can match your key range, reverse your start_key and end_key or set descending=true",
wantStatus: http.StatusBadRequest,
})
tests.Add("endkey and startkey no conflict", test{
options: kivik.Params(map[string]interface{}{
"startkey": "a",
"endkey": "z",
}),
want: &viewOptions{
limit: -1,
inclusiveEnd: true,
update: "true",
sorted: true,
startkey: `"a"`,
endkey: `"z"`,
},
})
tests.Add("endkey and startkey + descending conflict", test{
options: kivik.Params(map[string]interface{}{
"startkey": "a",
"endkey": "z",
"descending": true,
}),
wantErr: "no rows can match your key range, reverse your start_key and end_key or set descending=false",
wantStatus: http.StatusBadRequest,
})
tests.Add("endkey and startkey + descending no conflict", test{
options: kivik.Params(map[string]interface{}{
"startkey": "z",
"endkey": "a",
"descending": true,
}),
want: &viewOptions{
limit: -1,
inclusiveEnd: true,
update: "true",
sorted: true,
descending: true,
startkey: `"z"`,
endkey: `"a"`,
},
})
tests.Add("key falls outof range of startkey-endkey", test{
options: kivik.Params(map[string]interface{}{
"startkey": "a",
"endkey": "q",
"key": "z",
}),
wantErr: "no rows can match your key range, change your start_key, end_key, or key",
wantStatus: http.StatusBadRequest,
})
tests.Add("key falls outof range of startkey-endkey even when descending", test{
options: kivik.Params(map[string]interface{}{
"startkey": "a",
"endkey": "q",
"key": "z",
"descending": true,
}),
wantErr: "no rows can match your key range, reverse your start_key and end_key or set descending=false",
wantStatus: http.StatusBadRequest,
})
/*
stable (boolean) – Whether or not the view results should be returned from a stable set of shards. Default is false.
*/
Expand Down
11 changes: 0 additions & 11 deletions x/sqlite/query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2781,21 +2781,10 @@ func TestDBQuery(t *testing.T) {
},
}
})
tests.Add("key + keys", test{
ddoc: "_design/foo",
view: "_view/bar",
options: kivik.Params(map[string]interface{}{"key": "a", "keys": []string{"b", "c"}}),
wantErr: "`keys` is incompatible with `key`, `start_key` and `end_key`",
wantStatus: http.StatusBadRequest,
})

/*
TODO:
- cache invidual keys with keys=[...] + reduce/group
- key + start_key
- key + end_key
- key + startkey + descending
- key + endkey + descending
- reduce cache
- caches created with key, used for range
- inclusive vs non-inclusive end
Expand Down

0 comments on commit d30346c

Please sign in to comment.