add other session providers (#5963)
This commit is contained in:
parent
bf4badad1d
commit
9de871a0f8
160 changed files with 37644 additions and 66 deletions
231
vendor/github.com/couchbaselabs/go-couchbase/views.go
generated
vendored
Normal file
231
vendor/github.com/couchbaselabs/go-couchbase/views.go
generated
vendored
Normal file
|
@ -0,0 +1,231 @@
|
|||
package couchbase
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
)
|
||||
|
||||
// ViewRow represents a single result from a view.
|
||||
//
|
||||
// Doc is present only if include_docs was set on the request.
|
||||
type ViewRow struct {
|
||||
ID string
|
||||
Key interface{}
|
||||
Value interface{}
|
||||
Doc *interface{}
|
||||
}
|
||||
|
||||
// A ViewError is a node-specific error indicating a partial failure
|
||||
// within a view result.
|
||||
type ViewError struct {
|
||||
From string
|
||||
Reason string
|
||||
}
|
||||
|
||||
func (ve ViewError) Error() string {
|
||||
return "Node: " + ve.From + ", reason: " + ve.Reason
|
||||
}
|
||||
|
||||
// ViewResult holds the entire result set from a view request,
|
||||
// including the rows and the errors.
|
||||
type ViewResult struct {
|
||||
TotalRows int `json:"total_rows"`
|
||||
Rows []ViewRow
|
||||
Errors []ViewError
|
||||
}
|
||||
|
||||
func (b *Bucket) randomBaseURL() (*url.URL, error) {
|
||||
nodes := b.HealthyNodes()
|
||||
if len(nodes) == 0 {
|
||||
return nil, errors.New("no available couch rest URLs")
|
||||
}
|
||||
nodeNo := rand.Intn(len(nodes))
|
||||
node := nodes[nodeNo]
|
||||
|
||||
b.RLock()
|
||||
name := b.Name
|
||||
pool := b.pool
|
||||
b.RUnlock()
|
||||
|
||||
u, err := ParseURL(node.CouchAPIBase)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("config error: Bucket %q node #%d CouchAPIBase=%q: %v",
|
||||
name, nodeNo, node.CouchAPIBase, err)
|
||||
} else if pool != nil {
|
||||
u.User = pool.client.BaseURL.User
|
||||
}
|
||||
return u, err
|
||||
}
|
||||
|
||||
const START_NODE_ID = -1
|
||||
|
||||
func (b *Bucket) randomNextURL(lastNode int) (*url.URL, int, error) {
|
||||
nodes := b.HealthyNodes()
|
||||
if len(nodes) == 0 {
|
||||
return nil, -1, errors.New("no available couch rest URLs")
|
||||
}
|
||||
|
||||
var nodeNo int
|
||||
if lastNode == START_NODE_ID || lastNode >= len(nodes) {
|
||||
// randomly select a node if the value of lastNode is invalid
|
||||
nodeNo = rand.Intn(len(nodes))
|
||||
} else {
|
||||
// wrap around the node list
|
||||
nodeNo = (lastNode + 1) % len(nodes)
|
||||
}
|
||||
|
||||
b.RLock()
|
||||
name := b.Name
|
||||
pool := b.pool
|
||||
b.RUnlock()
|
||||
|
||||
node := nodes[nodeNo]
|
||||
u, err := ParseURL(node.CouchAPIBase)
|
||||
if err != nil {
|
||||
return nil, -1, fmt.Errorf("config error: Bucket %q node #%d CouchAPIBase=%q: %v",
|
||||
name, nodeNo, node.CouchAPIBase, err)
|
||||
} else if pool != nil {
|
||||
u.User = pool.client.BaseURL.User
|
||||
}
|
||||
return u, nodeNo, err
|
||||
}
|
||||
|
||||
// DocID is the document ID type for the startkey_docid parameter in
|
||||
// views.
|
||||
type DocID string
|
||||
|
||||
func qParam(k, v string) string {
|
||||
format := `"%s"`
|
||||
switch k {
|
||||
case "startkey_docid", "endkey_docid", "stale":
|
||||
format = "%s"
|
||||
}
|
||||
return fmt.Sprintf(format, v)
|
||||
}
|
||||
|
||||
// ViewURL constructs a URL for a view with the given ddoc, view name,
|
||||
// and parameters.
|
||||
func (b *Bucket) ViewURL(ddoc, name string,
|
||||
params map[string]interface{}) (string, error) {
|
||||
u, err := b.randomBaseURL()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
values := url.Values{}
|
||||
for k, v := range params {
|
||||
switch t := v.(type) {
|
||||
case DocID:
|
||||
values[k] = []string{string(t)}
|
||||
case string:
|
||||
values[k] = []string{qParam(k, t)}
|
||||
case int:
|
||||
values[k] = []string{fmt.Sprintf(`%d`, t)}
|
||||
case bool:
|
||||
values[k] = []string{fmt.Sprintf(`%v`, t)}
|
||||
default:
|
||||
b, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("unsupported value-type %T in Query, "+
|
||||
"json encoder said %v", t, err)
|
||||
}
|
||||
values[k] = []string{fmt.Sprintf(`%v`, string(b))}
|
||||
}
|
||||
}
|
||||
|
||||
if ddoc == "" && name == "_all_docs" {
|
||||
u.Path = fmt.Sprintf("/%s/_all_docs", b.GetName())
|
||||
} else {
|
||||
u.Path = fmt.Sprintf("/%s/_design/%s/_view/%s", b.GetName(), ddoc, name)
|
||||
}
|
||||
u.RawQuery = values.Encode()
|
||||
|
||||
return u.String(), nil
|
||||
}
|
||||
|
||||
// ViewCallback is called for each view invocation.
|
||||
var ViewCallback func(ddoc, name string, start time.Time, err error)
|
||||
|
||||
// ViewCustom performs a view request that can map row values to a
|
||||
// custom type.
|
||||
//
|
||||
// See the source to View for an example usage.
|
||||
func (b *Bucket) ViewCustom(ddoc, name string, params map[string]interface{},
|
||||
vres interface{}) (err error) {
|
||||
if SlowServerCallWarningThreshold > 0 {
|
||||
defer slowLog(time.Now(), "call to ViewCustom(%q, %q)", ddoc, name)
|
||||
}
|
||||
|
||||
if ViewCallback != nil {
|
||||
defer func(t time.Time) { ViewCallback(ddoc, name, t, err) }(time.Now())
|
||||
}
|
||||
|
||||
u, err := b.ViewURL(ddoc, name, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("GET", u, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ah := b.authHandler(false /* bucket not yet locked */)
|
||||
maybeAddAuth(req, ah)
|
||||
|
||||
res, err := doHTTPRequest(req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error starting view req at %v: %v", u, err)
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
if res.StatusCode != 200 {
|
||||
bod := make([]byte, 512)
|
||||
l, _ := res.Body.Read(bod)
|
||||
return fmt.Errorf("error executing view req at %v: %v - %s",
|
||||
u, res.Status, bod[:l])
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(res.Body)
|
||||
if err := json.Unmarshal(body, vres); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// View executes a view.
|
||||
//
|
||||
// The ddoc parameter is just the bare name of your design doc without
|
||||
// the "_design/" prefix.
|
||||
//
|
||||
// Parameters are string keys with values that correspond to couchbase
|
||||
// view parameters. Primitive should work fairly naturally (booleans,
|
||||
// ints, strings, etc...) and other values will attempt to be JSON
|
||||
// marshaled (useful for array indexing on on view keys, for example).
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// res, err := couchbase.View("myddoc", "myview", map[string]interface{}{
|
||||
// "group_level": 2,
|
||||
// "startkey_docid": []interface{}{"thing"},
|
||||
// "endkey_docid": []interface{}{"thing", map[string]string{}},
|
||||
// "stale": false,
|
||||
// })
|
||||
func (b *Bucket) View(ddoc, name string, params map[string]interface{}) (ViewResult, error) {
|
||||
vres := ViewResult{}
|
||||
|
||||
if err := b.ViewCustom(ddoc, name, params, &vres); err != nil {
|
||||
//error in accessing views. Retry once after a bucket refresh
|
||||
b.Refresh()
|
||||
return vres, b.ViewCustom(ddoc, name, params, &vres)
|
||||
} else {
|
||||
return vres, nil
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue