Documentation ¶
Overview ¶
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 ¶
- Variables
- func Do(url, method string, cred *Credentials, body, response interface{}) (*http.Response, error)
- func ErrorType(err error) string
- type Bulk
- type Conflict
- type Credentials
- type Database
- func (db *Database) ConflictFor(docID string) (*Conflict, error)
- func (db *Database) Conflicts(forceView bool) (docIDs []string, err error)
- func (db *Database) ConflictsCount(forceView bool) (int, error)
- func (db *Database) Create() error
- func (db *Database) Cred() *Credentials
- func (db *Database) Delete(docID, revID string) error
- func (db *Database) DropDatabase() error
- func (db *Database) Exists() bool
- func (db *Database) HasView(designID, viewID string) bool
- func (db *Database) Insert(doc Identifiable) error
- func (db *Database) InsertBulk(bulk *Bulk, allOrNothing bool) (*Bulk, error)
- func (db *Database) Name() string
- func (db *Database) Query(designID, viewID string, options map[string]interface{}) (*ViewResult, error)
- func (db *Database) ReplicateTo(target *Database, continuously bool) (*Replication, error)
- func (db *Database) Retrieve(docID string, doc Identifiable) error
- func (db *Database) RetrieveRevision(docID, revID string, doc Identifiable) error
- func (db *Database) Server() *Server
- func (db *Database) SetCred(c *Credentials)
- func (db *Database) SyncWith(target *Database, continuously bool) (*Sync, error)
- func (db *Database) URL() string
- type Doc
- type DynamicDoc
- type Identifiable
- type Replication
- type Server
- type Sync
- type Task
- type ViewResult
- type ViewResultRow
Constants ¶
This section is empty.
Variables ¶
var ( // Design document for conflicts view ConflictsDesignID = "conflicts" // Name of the view to query documents with conflicts ConflictsViewID = "all" )
Functions ¶
Types ¶
type Bulk ¶
type Bulk struct { Docs []Identifiable `json:"docs"` AllOrNothing bool `json:"all_or_nothing"` }
Bulk is a document container for bulk operations.
func (*Bulk) Find ¶
func (bulk *Bulk) Find(id, rev string) Identifiable
Find a document in a bulk of documents
type Conflict ¶
type Conflict struct {
// contains filtered or unexported fields
}
Describes a conflict between different document revisions. Opaque type, use associated methods.
func (*Conflict) Revisions ¶
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 ¶
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 ¶
type Credentials struct {
// contains filtered or unexported fields
}
Credentials represents access credentials.
func NewCredentials ¶
func NewCredentials(user, password string) *Credentials
NewCredentials returns new credentials you can use for server and/or database operations.
type Database ¶
type Database struct {
// contains filtered or unexported fields
}
Database represents a database of a CouchDB instance.
func (*Database) ConflictFor ¶
Get conflicting revisions for a document id. Returns nil if there are no conflicts.
func (*Database) Conflicts ¶
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 ¶
Returns the number of conflicts, sets up view if forceView is enabled. See db.Conflicts() for possible issues around creating a view.
func (*Database) Cred ¶
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) DropDatabase ¶
DropDatabase deletes a database.
func (*Database) Insert ¶
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 ¶
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) Query ¶
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 ¶
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 ¶
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 ¶
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) SetCred ¶
func (db *Database) SetCred(c *Credentials)
SetCred sets the credentials used for operations with the database.
func (*Database) SyncWith ¶
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.
type Doc ¶
Doc defines a basic struct for CouchDB documents. Add it as an anonymous field to your custom struct.
type DynamicDoc ¶
type DynamicDoc map[string]interface{}
DynamicDoc can be used for CouchDB documents without any implicit schema.
func (DynamicDoc) IDRev ¶
func (m DynamicDoc) IDRev() (id string, rev string)
Implement Identifiable
func (DynamicDoc) SetIDRev ¶
func (m DynamicDoc) SetIDRev(id string, rev string)
Implement Identifiable
type Identifiable ¶
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 ¶
type Replication struct {
// contains filtered or unexported fields
}
A replication from a source to a target
func (*Replication) Cancel ¶
func (repl *Replication) Cancel() error
Cancel a continuously running replication
func (*Replication) Continuous ¶
func (repl *Replication) Continuous() bool
Returns whether replication is running continuously or not
func (*Replication) IsActive ¶
func (repl *Replication) IsActive() (bool, error)
IsRunning returns whether a replication is currently active or not.
func (*Replication) SessionID ¶
func (repl *Replication) SessionID() string
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server represents a CouchDB instance.
func NewServer ¶
func NewServer(url string, cred *Credentials) *Server
NewServer returns a handle to a CouchDB instance.
func (*Server) ActiveTasks ¶
ActiveTasks returns all currently active tasks of a CouchDB instance.
func (*Server) Cred ¶
func (s *Server) Cred() *Credentials
Cred returns credentials associated with a CouchDB instance.
type Sync ¶
type Sync struct {
// contains filtered or unexported fields
}
A bidirectional replication
type Task ¶
type Task map[string]interface{}
Task describes an active task running on an instance, like a continuous replication or indexing.
func (Task) HasReplicationID ¶
HasReplicationID returns true if a task has a given replication id.
func (Task) IsReplication ¶
IsReplication returns true if a task represents a replication.
type ViewResult ¶
type ViewResult struct { Offset uint64 Rows []ViewResultRow }
Container for ViewResultRows
type ViewResultRow ¶
type ViewResultRow struct { ID string Key interface{} Value interface{} }
A single view result
func (*ViewResultRow) ValueInt ¶
func (r *ViewResultRow) ValueInt() int