/
kivik.go
153 lines (135 loc) · 4.28 KB
/
kivik.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
package kivik
import (
"context"
"encoding/json"
"github.com/imdario/mergo"
"github.com/flimzy/kivik/driver"
"github.com/flimzy/kivik/errors"
)
// Client is a client connection handle to a CouchDB-like server.
type Client struct {
dsn string
driverName string
driverClient driver.Client
}
// Options is a collection of options. The keys and values are backend specific.
type Options map[string]interface{}
func mergeOptions(otherOpts ...Options) (Options, error) {
var options Options
for _, opts := range otherOpts {
if err := mergo.MergeWithOverwrite(&options, opts); err != nil {
return nil, err
}
}
return options, nil
}
// New creates a new client object specified by its database driver name
// and a driver-specific data source name.
func New(ctx context.Context, driverName, dataSourceName string) (*Client, error) {
driversMu.RLock()
driveri, ok := drivers[driverName]
driversMu.RUnlock()
if !ok {
return nil, errors.Statusf(StatusBadRequest, "kivik: unknown driver %q (forgotten import?)", driverName)
}
client, err := driveri.NewClient(ctx, dataSourceName)
if err != nil {
return nil, err
}
return &Client{
dsn: dataSourceName,
driverName: driverName,
driverClient: client,
}, nil
}
// Driver returns the name of the driver string used to connect this client.
func (c *Client) Driver() string {
return c.driverName
}
// DSN returns the data source name used to connect this client.
func (c *Client) DSN() string {
return c.dsn
}
// Version represents a server version response.
type Version struct {
// Version is the version number reported by the server or backend.
Version string
// Vendor is the vendor string reported by the server or backend.
Vendor string
// RawResponse is the raw response body returned by the server, useful if
// you need additional backend-specific information.
//
// For the format of this document, see
// http://docs.couchdb.org/en/2.0.0/api/server/common.html#get
RawResponse json.RawMessage
}
// Version returns version and vendor info about the backend.
func (c *Client) Version(ctx context.Context) (*Version, error) {
ver, err := c.driverClient.Version(ctx)
if err != nil {
return nil, err
}
return &Version{
Version: ver.Version,
Vendor: ver.Vendor,
RawResponse: ver.RawResponse,
}, nil
}
// DB returns a handle to the requested database. Any options parameters
// passed are merged, with later values taking precidence.
func (c *Client) DB(ctx context.Context, dbName string, options ...Options) (*DB, error) {
opts, err := mergeOptions(options...)
if err != nil {
return nil, err
}
db, err := c.driverClient.DB(ctx, dbName, opts)
return &DB{
client: c,
name: dbName,
driverDB: db,
}, err
}
// AllDBs returns a list of all databases.
func (c *Client) AllDBs(ctx context.Context, options ...Options) ([]string, error) {
opts, err := mergeOptions(options...)
if err != nil {
return nil, err
}
return c.driverClient.AllDBs(ctx, opts)
}
// DBExists returns true if the specified database exists.
func (c *Client) DBExists(ctx context.Context, dbName string, options ...Options) (bool, error) {
opts, err := mergeOptions(options...)
if err != nil {
return false, err
}
return c.driverClient.DBExists(ctx, dbName, opts)
}
// CreateDB creates a DB of the requested name.
func (c *Client) CreateDB(ctx context.Context, dbName string, options ...Options) error {
opts, err := mergeOptions(options...)
if err != nil {
return err
}
return c.driverClient.CreateDB(ctx, dbName, opts)
}
// DestroyDB deletes the requested DB.
func (c *Client) DestroyDB(ctx context.Context, dbName string, options ...Options) error {
opts, err := mergeOptions(options...)
if err != nil {
return err
}
return c.driverClient.DestroyDB(ctx, dbName, opts)
}
// Authenticate authenticates the client with the passed authenticator, which
// is driver-specific. If the driver does not understand the authenticator, an
// error will be returned.
func (c *Client) Authenticate(ctx context.Context, a interface{}) error {
if auth, ok := c.driverClient.(driver.Authenticator); ok {
return auth.Authenticate(ctx, a)
}
return errors.Status(StatusNotImplemented, "kivik: driver does not support authentication")
}
func missingArg(arg string) error {
return errors.Statusf(StatusBadRequest, "kivik: %s required", arg)
}