Leanback
Simple Ruby Interface to CouchDB. This current version is a complete re-write with a new API. I wrote this to use in my projects, I hope you find it useful.
Installation:
gem install leanback
Basic Operations:
Initialize leanback
my_database = Leanback::Couchdb.new(database: "my_database")
In the above code, my_database object will be used to perform operations on the couchDB database named "my_database". The above example assumes that the database is in admin party mode, since no username or password was provided.
If there is no admin party then a username and password is required to perform the operations.
A username and password can be included during initialization:
my_database = Leanback::Couchdb.new(database: "my_database", username: "obi", password: "abc1234")
By default, Leanback uses couchDB's default http address and port (http://127.0.0.1:5984), to use a different address and port, include it in the initialization:
my_database = Leanback::Couchdb.new(database: "my_database", address: "https://obi.iriscouch.com", port: "6984")
Create database:
my_database = Leanback::Couchdb.new(database: "my_database")
my_database.create
Delete database
my_database.delete
Create a document
my_database.create_doc("linda", firstname: "linda", lastname: "smith")
The created document inside couchDB will be:
{
"_id": "linda",
"_rev": "1-ff286690ab5b446a727840ce7420843a",
"firstname": "linda",
"lastname": "smith"
}
Delete the document with it's latest revision
my_database.delete_doc("linda", rev = "1-ff286690ab5b446a727840ce7420843a")
Delete the document without providing a revision
my_database.delete_doc!("linda")
delete_doc! with the bang, first fetches the document with the provided id, retrieves it's latest revision and then, deletes the document using the latest revision.
Fetch the document using its id
my_database.get_doc('linda')
Update the document
my_database.update_doc("linda", firstname: "nancy", lastname: "drew", _rev: "5-74894db03ef6d22e6a0e4ef90b5a85fb")
update_doc replaces the old document with the new data. A revision (_rev) must be provided in the data. The resulting document after the update will be
{
"_id": "linda",
"_rev": "6-950d16c8c39daa77fad11de85b9467fc",
"firstname": "nancy",
"lastname": "drew"
}
Edit parts of a document
my_database.edit_doc!("linda", lastname: "brown", phone: "777-777-7777")
The edited version of the document is now:
{
"_id": "linda",
"_rev": "7-e44206dd09d2740171576e5867fff7a1",
"firstname": "nancy",
"lastname": "brown",
"phone": "777-777-7777"
}
###Working with Desgin Documents and views
Create a design document
design_doc = {
language: "javascript",
views: {
by_gender: {
map: "function(doc){ if(doc.gender) emit(doc.gender); }"
}
}
}
my_database.create_doc "_design/my_doc", design_doc
Query a permanent view
my_database.view("_design/my_doc", "by_gender")
The view() method is used to query parmanent views. It takes the design document name and view name as arguments. It can also optionally take the following CouchDB query options in a hash as arguments: key, limit, skip, descending, include_docs, reduce, startkey, starkey_docid, endkey, endkey_docid, inclusive_end, stale, group, group_level.
To query a permanent view by key
my_database.view("_design/my_doc", "by_gender", key: '"male"')
The above example sends a query to the view using the key "male" and returns all documents with "gender" equal to "male".
To include actual documents in the query results, we can add include_docs to the query options
my_database.view("_design/my_doc", "by_gender", key: '"male"', include_docs: true)
To return results in descending order:
my_database.view("_design/my_doc", "by_gender", key: '"male"', descending: true)
To limit the number of documents returned from the query
my_database.view("_design/my_doc", "by_gender", limit: 4)
Skip some documents in the query
my_database.view("_design/my_doc", "by_gender", skip: 2)
Query views by startkey and endkey
design_doc = {
language: "javascript",
views: {
people_by_age: {
map: "function(doc){ if(doc.age) emit(doc.age); }"
}
}
}
my_database.create_doc "_design/ages", design_doc
my_database.view("_design/ages", "people_by_age", startkey: 20, endkey: 29)
The above returns documents with age between 20 and 29.
Another example to return documents with age 31 and over
my_database.view("_design/ages", "people_by_age", startkey: 31)
Working with compound startkey and endkey
my_database.view("_design/gender_city", "people_by_gender_and_city", startkey: ["female", "bronx", 25].to_s, endkey: ["female", "bronx", 25].to_s)
Dynamic Queries
Dynamic queries can be performed on documents using the where() helper method, example to fetch all documents that match the key/value pairs {city: "bronx", gender: "female"}
my_database.where(city: "bronx", gender: "female")
To fetch all documents that match the key/value pairs {state: "new york", fullname: ["susan", "Lee"]}
my_database.where(state: "new york", fullname: ["susan", "Lee"])
Similar to view(), the where() method also supports options skip, limit, descending. Example to return documents in descending order;
my_database.where({city: "bronx", gender: "female"}, descending: true)
Limit to one result
my_database.where({city: "bronx", gender: "female"}, limit: 1)
Calling the where() method, for the first time creates a view in the database for provided keys. Subsequent calls to where() will simply query the previously created view and return the documents. For example calling the method below:
my_database.where(city: "bronx", gender: "female")
Will add the following document to the database,
{
"_id": "_design/city_gender_keys_finder",
"_rev": "1-41fb3b17c8b99be176928e3ea5588935",
"language": "javascript",
"views": {
"find_by_keys_city_gender": {
"map": "function(doc){ if(doc.city && doc.gender) emit([doc.city,doc.gender]);}"
}
}
}
And then query it with:
/_design/city_gender_keys_finder/_view/find_by_keys_city_gender?endkey=["bronx", "female"]&include_docs=true&startkey=["bronx", "female"]
Subsequent method calls will simply query the view and return the documents. where() is just a convienient helper method.
Security Object:
Please note that this does not work with CouchDB 2, only works with CouchDB v1.6.1 and less. To set the security object for the database:
security_settings = {
admins: {names: ["david"], roles: ["admin"]},
readers: {names: ["david"],roles: ["admin"]}
}
my_database.security_object = security_settings
To retrieve the security object at anytime:
my_database.security_object
CouchDB Configuration
Please note that this does not work with CouchDB 2, only works with CouchDB v1.6.1 and less. CouchDB's configuration settings can be set using the set_config() method:
config = Leanback::Couchdb.new
config.set_config("section", "option", '"value"')
For example to set couchDB's couch_httpd_auth timeout value:
config.set_config("couch_httpd_auth", "timeout", '"1600"')
This sets the CouchDB auth timeout to 1600 seconds.
To retrieve the configuration:
config.get_config("couch_httpd_auth", "timeout")
To delete a configuration:
config.delete_config("section", "option")
A more useful example to add an admin user to couchDB with username and password;
config.set_config("admins", username = "james", password = '"abc123"')
This will add a CouchDB admin with username james, and password abc123. If couchDB was in admin party mode, this would end the party.
Exception handling
For CouchDB errors Leanback raises a Leanback::Exception object. This object has a response attribute which is a hash that contains the details of the error response from CouchDB. See an example below
begin
my_database.get_doc('dontexist')
rescue Leanback::CouchdbException => e
puts e.response.inspect
puts e.response[:error].inspect
puts e.response[:reason].inspect
end
API Specification
c = Leanback::Couchdb.new database: xxxxx, username: xxxxx, password: xxxx, address: xxxxx, port: xxxxx
c.create
c.delete
c.create_doc id, {}
c.delete_doc id, rev
c.delete_doc! id
c.update_doc id, {}
c.edit_doc! id, {}
c.get_doc id
options = { limit: x, skip: x, descending: x}
c.where {}, options
design_doc = {
language: "javascript",
views: {
get_emails: {
map: "function(doc){ if(doc.firstname && doc.email) emit(doc.id,{Name: doc.firstname, Email: doc.email}); }"
}
}
}
c.create_doc "_design/my_doc", design_doc
options = { limit: x, key: x, start_key: x, end_key: x, skip: x, descending: x, include_docs: boolean}
design_doc_name = "_design/my_doc"
view_name = "get_emails"
c.view design_doc_name, view_name, options
security_settings = {
admins: {names: ["david"], roles: ["admin"]},
readers: {names: ["david"],roles: ["admin"]}
}
c.security_object = security_settings
c.security_object
c = Leanback::Couchdb.new
c.set_config("couch_httpd_auth", "timeout", '"900"')
c.get_config("couch_httpd_auth", "timeout")
c.delete_config("section", "option")
Development Mode
Running Tests
docker-compose run --entrypoint "bundle exec rspec -fd spec/leanback_spec.rb" leanback
Supported Rubies
jruby-19mode, MRI 1.9.3 - 2.x
##License
MIT License.
##Copyright
Copyright (c) 2014 Obi Akubue.