couch: github.com/patrickjuchli/couch Index | Files

package couch

import "github.com/patrickjuchli/couch"

Package couch implements a client for a CouchDB database.

Version 0.1 focuses on basic operations, proper conflict management, error handling and replication. Not part of this version are attachment handling, general statistics and optimizations, change detection and creating views. Most of the features are accessible using the generic Do() function, though.

Getting started:

cred := couch.NewCredentials("user_notsosafe", "password_withoutssl")
s := couch.NewServer("http://127.0.0.1:5984", cred)
db := s.Database("MyDatabase")

if !db.Exists() {
  db.Create()
}

Basics

Every document in CouchDB has to be identifiable by a document id and a revision id. Two types already implement this interface called Identifiable: Doc and DynamicDoc. Doc can be used as an anonymous field in your own struct. DynamicDoc is a type alias for map[string]interface{}, use it when your documents have no implicit schema at all. To make code examples easier to follow, there will be no explicit error handling in these examples even though it's fully supported throughout the API.

type Person struct {
  couch.Doc
  Name string
}

Insert() will create a new document if it doesn't have an id yet:

p := &Person{Name : "Peter"}
db.Insert(p)

After the operation the final id and revision id will be written back to p. That's why you can now just edit p and call Insert() again which will save the same document under a new revision.

p.Name = "Anna"
db.Insert(p)

After this edit, p will contain the latest revision id. Note that it is possible that this second edit fails because someone else edited and saved the same document in the meantime. You will be notified of this in form of an error and you should then first retrieve the latest document revision to see the changes of this lost update:

db.Retrieve(p.ID, p)

CouchDB doesn't edit documents in-place but adds a complete revision for each edit. That's why you will be correctly informed of any lost update.

Conflicts

Because CouchDB supports multi-master replication of databases, it is possible that conflicts like the one described above can't be avoided. CouchDB is not going to interrupt replication because of a lost update.

Let's say you have two instances running, maybe a central one and a mobile one and both are kept in sync by replication. Now let's assume you edit a document on your mobile DB and someone else edits the same document on the central DB. After you've come online again, you use bi-directional replication to sync the databases. CouchDB will now create a branch structure for your document, similar to version control systems. Your document has two conflicting revisions and in this case they can't necessarily be resolved automatically. This client helps you with a number of methods to resolve such an issue quickly. Read more about the conflict model http://docs.couchdb.org/en/latest/replication/conflicts.html

Continuing with above example, replicate the database:

anotherDB := s.Database("sharedBackup")
db.ReplicateTo(anotherDB, false)

Now, on the other database, edit the document (note that it has the same id there):

p.Name = "AnotherAnna"
anotherDB.Insert(p)

Now edit the document on the first database. Retrieve it first to make sure it has the correct revision id:

db.Retrieve(p.ID, p)
p.Name = "LatestAnna"
db.Insert(p)

Now replicate anotherDB back to our first database:

anotherDB.ReplicateTo(db, false)

Now we have two conflicting versions of a document. Only you as the editor can decide whether "LatestAnna" or "AnotherAnna" is correct. To detect this conflict there are a number of methods. First, you can just ask a document:

conflict, _ := db.ConflictFor(p.ID)

You probably want to have a look at the revisions in your preferred format, use Revisions() to unmarshal the revision data into a slice of a custom data type:

var revs []Person
conflict.Revisions(&revs)

Pick one of the revisions or create a new document to solve the conflict:

solution := &Person{Name:"Anna"}
conflict.SolveWith(solution)

That's it. You can detect conflicts like these throughout your database using:

num := db.ConflictsCount()
docIDs := db.Conflicts()

Error handling

Errors returned by CouchDB will be converted into a Go error. Its regular Error() method will then return a combination of the shortform (e.g. bad_request) as well as the longer and more specific description. To be able to identify a specific error within your application, use ErrorType() to get the shortform only.

Index

Package Files

conflict.go couch.go doc.go replication.go view.go

Variables

var (
    // Design document for conflicts view
    ConflictsDesignID = "conflicts"

    // Name of the view to query documents with conflicts
    ConflictsViewID = "all"
)

func Do Uses

func Do(url, method string, cred *Credentials, body, response interface{}) (*http.Response, error)

Generic CouchDB request. If CouchDB returns an error description, it will not be unmarshaled into response but returned as a regular Go error.

func ErrorType Uses

func ErrorType(err error) string

ErrorType returns the shortform of a CouchDB error, e.g. bad_request. If the error didn't originate from CouchDB, the function will return an empty string.

type Bulk Uses

type Bulk struct {
    Docs         []Identifiable `json:"docs"`
    AllOrNothing bool           `json:"all_or_nothing"`
}

Bulk is a document container for bulk operations.

func (*Bulk) Add Uses

func (bulk *Bulk) Add(doc Identifiable)

Add a document to a bulk of documents

func (*Bulk) Find Uses

func (bulk *Bulk) Find(id, rev string) Identifiable

Find a document in a bulk of documents

type Conflict Uses

type Conflict struct {
    // contains filtered or unexported fields
}

Describes a conflict between different document revisions. Opaque type, use associated methods.

func (*Conflict) Revisions Uses

func (c *Conflict) Revisions(v interface{})

Get all conflicting document revisions in a preferred format. It supports the same types for v as json.Unmarshal.

Revisions in a slice of structs:

var revs []MyStruct
conflict.Revisions(&revs)

Other examples:

var revs interface{}
var revs []map[string]interface{}

Note that map[string]interface{} will not work.

func (*Conflict) SolveWith Uses

func (c *Conflict) SolveWith(finalDoc Identifiable) error

Solves a conflict with a final document. It will set the revision id of the document to the final revision id that CouchDB will report once the operation is complete.

If the operation is successful, the conflict c will no longer hold any information about the formerly conflicting revisions.

Be aware that while you solve a conflict, another party might have done so right before you. In this case of a lost update you will receive an error. You should then ask about the state of the conflict again using db.ConflictFor(myDocID).

type Credentials Uses

type Credentials struct {
    // contains filtered or unexported fields
}

Credentials represents access credentials.

func NewCredentials Uses

func NewCredentials(user, password string) *Credentials

NewCredentials returns new credentials you can use for server and/or database operations.

type Database Uses

type Database struct {
    // contains filtered or unexported fields
}

Database represents a database of a CouchDB instance.

func (*Database) ConflictFor Uses

func (db *Database) ConflictFor(docID string) (*Conflict, error)

Get conflicting revisions for a document id. Returns nil if there are no conflicts.

func (*Database) Conflicts Uses

func (db *Database) Conflicts(forceView bool) (docIDs []string, err error)

Returns all conflicts in a database. To do so, a dedicated view is necessary at [db-url]/_design/conflicts/_view/all. If it doesn't exist and forceView is enabled, it will be automatically set up.

Note, that if the database is already large at that point, this operation can take a very long time. It's recommended to call this method or ConflictsCount() right after creating a new database.

func (*Database) ConflictsCount Uses

func (db *Database) ConflictsCount(forceView bool) (int, error)

Returns the number of conflicts, sets up view if forceView is enabled. See db.Conflicts() for possible issues around creating a view.

func (*Database) Create Uses

func (db *Database) Create() error

Create a new database on the CouchDB instance.

func (*Database) Cred Uses

func (db *Database) Cred() *Credentials

Cred returns the credentials associated with the database. If there aren't any it will return the ones associated with the server.

func (*Database) Delete Uses

func (db *Database) Delete(docID, revID string) error

Delete removes a document from the database.

func (*Database) DropDatabase Uses

func (db *Database) DropDatabase() error

DropDatabase deletes a database.

func (*Database) Exists Uses

func (db *Database) Exists() bool

Exists returns true if a database really exists.

func (*Database) HasView Uses

func (db *Database) HasView(designID, viewID string) bool

Checks if a view really exists

func (*Database) Insert Uses

func (db *Database) Insert(doc Identifiable) error

Insert a document as follows: If doc has an ID, it will edit the existing document, if not, create a new one. In case of an edit, the doc will be assigned the new revision id.

func (*Database) InsertBulk Uses

func (db *Database) InsertBulk(bulk *Bulk, allOrNothing bool) (*Bulk, error)

InsertBulk inserts a bulk of documents at once. This transaction can have two semantics, all-or-nothing or per-document. See http://docs.couchdb.org/en/latest/api/database/bulk-api.html#bulk-documents-transaction-semantics After the transaction the method may return a new bulk of documents that couldn't be inserted. If this is the case you will still get an error reporting the issue.

func (*Database) Name Uses

func (db *Database) Name() string

Name of database

func (*Database) Query Uses

func (db *Database) Query(designID, viewID string, options map[string]interface{}) (*ViewResult, error)

Query a view with options, see http://docs.couchdb.org/en/latest/api/ddoc/views.html#db-design-design-doc-view-view-name

func (*Database) ReplicateTo Uses

func (db *Database) ReplicateTo(target *Database, continuously bool) (*Replication, error)

Replicates given database to a target database. If the target database does not exist it will be created. The target database may be on a different host.

func (*Database) Retrieve Uses

func (db *Database) Retrieve(docID string, doc Identifiable) error

Retrieve gets the latest revision of a document, the result will be written into doc

func (*Database) RetrieveRevision Uses

func (db *Database) RetrieveRevision(docID, revID string, doc Identifiable) error

RetrieveRevision gets a specific revision of a document, the result will be written into doc

func (*Database) Server Uses

func (db *Database) Server() *Server

Server returns the CouchDB instance the database is located on.

func (*Database) SetCred Uses

func (db *Database) SetCred(c *Credentials)

SetCred sets the credentials used for operations with the database.

func (*Database) SyncWith Uses

func (db *Database) SyncWith(target *Database, continuously bool) (*Sync, error)

Synchronizes two databases by setting up two replications, one from given database to target and from target to given database. If the target database does not exist it will be created. The target database may be on a different host.

This method may be convenient but note that it is not atomic: Sync means that this method will first replicate db to target and then target to db. If the first one fails, both fail. If the first one works but the second doesn't, the first one will have executed nonetheless. If the sync has been set up to be continuous, the first continuous replication will be cancelled if the second one fails.

func (*Database) URL Uses

func (db *Database) URL() string

Url returns the absolute url to a database

type Doc Uses

type Doc struct {
    ID  string `json:"_id,omitempty"`
    Rev string `json:"_rev,omitempty"`
}

Doc defines a basic struct for CouchDB documents. Add it as an anonymous field to your custom struct.

func (*Doc) IDRev Uses

func (ref *Doc) IDRev() (id string, rev string)

Implement Identifiable

func (*Doc) SetIDRev Uses

func (ref *Doc) SetIDRev(id string, rev string)

Implement Identifiable

type DynamicDoc Uses

type DynamicDoc map[string]interface{}

DynamicDoc can be used for CouchDB documents without any implicit schema.

func (DynamicDoc) IDRev Uses

func (m DynamicDoc) IDRev() (id string, rev string)

Implement Identifiable

func (DynamicDoc) SetIDRev Uses

func (m DynamicDoc) SetIDRev(id string, rev string)

Implement Identifiable

type Identifiable Uses

type Identifiable interface {

    // SetIDRev sets the document id and revision id
    SetIDRev(id string, rev string)

    // IDRev returns the document id and revision id
    IDRev() (id string, rev string)
}

Identifiable is the only interface a data structure must satisfy to be used as a CouchDB document.

type Replication Uses

type Replication struct {
    // contains filtered or unexported fields
}

A replication from a source to a target

func (*Replication) Cancel Uses

func (repl *Replication) Cancel() error

Cancel a continuously running replication

func (*Replication) Continuous Uses

func (repl *Replication) Continuous() bool

Returns whether replication is running continuously or not

func (*Replication) IsActive Uses

func (repl *Replication) IsActive() (bool, error)

IsRunning returns whether a replication is currently active or not.

func (*Replication) SessionID Uses

func (repl *Replication) SessionID() string

func (*Replication) Source Uses

func (repl *Replication) Source() *Database

Returns replication source

func (*Replication) Target Uses

func (repl *Replication) Target() *Database

Returns replication target

type Server Uses

type Server struct {
    // contains filtered or unexported fields
}

Server represents a CouchDB instance.

func NewServer Uses

func NewServer(url string, cred *Credentials) *Server

NewServer returns a handle to a CouchDB instance.

func (*Server) ActiveTasks Uses

func (s *Server) ActiveTasks() ([]Task, error)

ActiveTasks returns all currently active tasks of a CouchDB instance.

func (*Server) Cred Uses

func (s *Server) Cred() *Credentials

Cred returns credentials associated with a CouchDB instance.

func (*Server) Database Uses

func (s *Server) Database(name string) *Database

Database returns a reference to a database. This method will not check if the database really exists.

func (*Server) URL Uses

func (s *Server) URL() string

URL returns the host (including its port) of a CouchDB instance.

type Sync Uses

type Sync struct {
    // contains filtered or unexported fields
}

A bidirectional replication

func (*Sync) Cancel Uses

func (sync *Sync) Cancel() error

Cancel a continuously running sync

func (*Sync) IsActive Uses

func (sync *Sync) IsActive() (bool, error)

IsActive returns whether a sync is active or not. A sync process consists of two replications. If one is active and the other isn't, you get an error message.

type Task Uses

type Task map[string]interface{}

Task describes an active task running on an instance, like a continuous replication or indexing.

func (Task) HasReplicationID Uses

func (t Task) HasReplicationID(id string) bool

HasReplicationID returns true if a task has a given replication id.

func (Task) IsReplication Uses

func (t Task) IsReplication() bool

IsReplication returns true if a task represents a replication.

type ViewResult Uses

type ViewResult struct {
    Offset uint64
    Rows   []ViewResultRow
}

Container for ViewResultRows

type ViewResultRow Uses

type ViewResultRow struct {
    ID    string
    Key   interface{}
    Value interface{}
}

A single view result

func (*ViewResultRow) ValueInt Uses

func (r *ViewResultRow) ValueInt() int

Package couch imports 9 packages (graph) and is imported by 1 packages. Updated 2017-04-14. Refresh now. Tools for package owners.