Johan Sørensen

CouchObject released!

CouchObject 0.0.1 is out, fresh from the sofa. Sit down, relax and read the RDoc.


$ sudo gem install couchobject

Since the last time I’ve taken it in a slightly different direction, focusing more on getting the basics up and running. You see, I’ve realised that CouchDb isn’t really perfect as a general OODB store (though, nothing is stopping you from storing an objects attributes in CouchDb, the Persistable module still does that). I’ll be waiting for GemStone and Rubinius for an awesome OODB. Instead CouchObject focus specifically on documents as it is right now:


>> CouchObject::Database.create!("http://localhost:8888", "roflcopters")
=> {"ok"=>true}
>> db = CouchObject::Database.open("http://localhost:8888/roflcopters")
=> #
>> db.all_documents
=> []

Creating and saving a document


>> doc = CouchObject::Document.new
=> #<CouchObject::Document:0x62708c @id=nil, @attributes={}, @revision=nil>
>> doc.engine_noise = "roflroflrofl"
=> "roflroflrofl"
>> doc.url = "http://www.thinkgeek.com/images/products/zoom/roflcopter.jpg"
=> "http://www.thinkgeek.com/images/products/zoom/roflcopter.jpg"
>> pp doc.save(db)
#<CouchObject::Response:0x4cd934
 @parsed_body=
  {"_rev"=>-1022899809, "_id"=>"4D91304BE683851F0E18871ADA6749D8", "ok"=>true},
 @response=#<Net::HTTPCreated 201 Created readbody=true>>

Get the same document by its id, and convert the response to a document (Just to illustrate it)


>> doc_we_created = db.get(doc.id).to_document
=> #"http://www.thinkgeek.com/images/products/zoom/roflcopter.jpg", "engine_noise"=>"roflroflrofl"}, @revision=-1022899809>
>> doc_we_created.engine_noise
=> "roflroflrofl"
>> doc_we_created.engine_noise = "ROFLROFLROFL"
=> "ROFLROFLROFL"
>> doc_we_created.save(db)
>> db.all_documents
=> [{"_rev"=>1353035433, "_id"=>"4D91304BE683851F0E18871ADA6749D8"}]

Sending a raw request to the db


>> response = db.post("_temp_view", <> pp response.to_document.rows.first
{"_rev"=>1353035433,
 "_id"=>"4D91304BE683851F0E18871ADA6749D8",
 "value"=>
  {"url"=>"http://www.thinkgeek.com/images/products/zoom/roflcopter.jpg",
   "_rev"=>1353035433,
   "_id"=>"4D91304BE683851F0E18871ADA6749D8",
   "engine_noise"=>"ROFLROFLROFL"}}

As you can see the API still needs some ironing out by means of more real world usage. You’ll notice that there’s no nice way of doing view of doing view “queries”. I really really want to create a more familiar Ruby DSL for defining views and sending of temporary views (like the one above). In particular it boils down to one or more of these things:

Since I’m lazy, I’m starting from the bottom, more on that later. Because I really want to say:


db.select{|doc| doc.title =~ /foo/ }

There’s a Git repository too


$ git clone git://gitorious.org/projects/couchobject/mainline.git

Patches? Yes please, release your inner couch potato.


Comments:

  1. rubyruy Says:


    Having played around with rb2js conversion myself, I can tell you that it is no simple task, and that although it’s possible it requires some pretty hefty concessions.

    The difference between how the two languages handle objects and “classes” lead to either inaccurate translation or needing to side-step JS’s native object handling entirely using a bulky run-time (as rb2js has done):

    rbSendMessage(RbRootObject.getConstant(‘Kernel’), ‘puts’, [s]);

    Eeek!

    Before even delving into the nuances of inheritance and meta-classes, consider the simple case of translating ruby “foo.bar”. Is it JS “foo.bar()” or “foo.bar” ? No way to know until run-time, hence the nasty mess above.

    And after you managed to implement ruby’s C-code as JS (which is essentially what the above is doing), you get to do it all again for all your favorite standard library classes!

    Aaaand after you did all THAT, you will have managed to implement one of the (relatively speaking yada yada) slowest production languages (ruby) into THE slowest production language (js) running in one of the slowest interpreters (spidermonkey). Ok i’m exagerating – but it’s going to be slow ;) Now I know, this thing will run via map/reduce over 500 commodity PCs that each cost less then a happy meal and you’ll only run it every now and then on an insert/update – but still that’s a positively silly amount of extra work for no good reason.

    I think option 3 is by far the best, especially since couchdb just shells out to spidermonkey and could just as easily shell out to ruby.

    Ambition IS pretty cool, but their approach deals with problems couchdb just doesn’t have ;)
    I think option 3

  2. johan Says:


    Indeed! Option 3 it was/it :)