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