Here's Looking At You, Child. RSS

[pyramid]

Y HALO THAR.

Welcome to my super great blog. This is where I keep track of everything that goes on in the world. Everything.

Disclaimer: Every post on this site is absolutely not the thing that my employer says I should say. They always think the exact opposite thing that I do. Every damn time. Also, this site is NOT the express written consent of the NFL and the FOX network.

Archive

Feb
8th
Mon
permalink

Easy document revisions with RelaxDB

I’ve been using CouchDB/RelaxDB for a project I’m working on, and I wanted an easy way to access CouchDB’s document versioning for my models. Here’s what I came up with.

Without going into too much detail, CouchDB doesn’t update documents in place, instead it creates a new document with the same ID and a new revision string. This gives you access to a rudimentary versioning system (which they warn you not to rely on, BTW.)

This functionality is perfect for the project I’m working on, which runs some tests at a regular interval and stores the results in CouchDB. I can then generate nice graphs based on the history of each object, so i can see how these test results have changed over time.

I messed with RelaxDB for Ruby for a little while to get this whole revisiony thing to work. For those familiar with RelaxDB, it exposes RelaxDB.load(_id, :revs=>true) for you, but due to limitations in Couch, you can’t get the :revs from a view, only directly loading an object. So to get around this, I mixed a revisions method into the Document class:

$YOUR_PROJECT/relaxdb/revisions.rb:
module RelaxDB

  class Document
    property :_revisions
    property :_revs_info

    def revisions(params={})
      RelaxDB.load(self._id,:revs_info=>true)._revs_info.collect do |rev|
        RelaxDB.load(self._id, :rev=>rev['rev']) if rev['status'] == 'available'
      end
    end

  end

end

Now, inside of your models.rb, you can just include it:

$YOUR_PROJECT/models.rb:
 
require 'relaxdb'
require 'relaxdb/revisions'
class MyModel < RelaxDB::Document
  property :name
  property :description
  view_by :name
end 

And then you can simply do this:

>> mm = MyModel.new(:name=>'Thing One')
=> #<MyModel:2165734660, _id: "96579a10-f749-012c-7654-001b63ac5fc7", name: "Thing One">
>> mm.save!
=> #<MyModel:2165734660, _id: "96579a10-f749-012c-7654-001b63ac5fc7", _rev: "1-160033dfbccd3327ffcffe94e5cd63f8", name: "Thing One">
>> mm.name = 'Changed Thing'
=> "Changed Thing"
>> mm.save!
=> #<MyModel:2165734660, _id: "96579a10-f749-012c-7654-001b63ac5fc7", _rev: "2-8a95904a579942d6add4fd9e7b272165", name: "Changed Thing">
>> mm.revisions
=> [#<MyModel:2165559880, _id: "96579a10-f749-012c-7654-001b63ac5fc7", _rev: "2-8a95904a579942d6add4fd9e7b272165", name: "Changed Thing">, #<MyModel:2165545120, _id: "96579a10-f749-012c-7654-001b63ac5fc7", _rev: "1-160033dfbccd3327ffcffe94e5cd63f8", name: "Thing One">]

Nifty!