Wednesday, March 3, 2010

Command Line Dump of CouchDB Design Documents

‹prev | My Chain | next›

I am very close to marking off another item on my couch_docs 1.1 TODO list:
  • Better command line experience.
    • Should default to current directory.
    • Should print help without args / better format
  • Should use the bulk docs
  • Should support the !json and !code macros from couchapp
  • Should support a flag to only work on design docs (mostly for export).
  • Should create the DB if it doesn't already exist
Yesterday I BDD'd the ability to dump CouchDB design document to the file system. All that should be left is a command line switch or two so that only design documents or only "regular" documents are dumped.

The command line interface to the couch-docs command should accept a -d switch to exclusively dump design documents:
cstrom@whitefall:~/repos/couch_docs$ ./bin/couch-docs -h
Usage: couch-docs push|dump [OPTIONS] couchdb_url [target_dir]

If a target_dir is not specified, the current working directory will be used.

Push options:
-R, --destructive Drop the couchdb_uri (if it exists) and create a new database
-b, --bulk [BATCH_SIZE=1000] Use bulk insert when pushing new documents

Dump options:
-d, --design Only dump design documents
-D, --data Only dump data documents

Common options:
-v, --version Show version
-h, --help Show this message
I would like that switch to tell the CouchDocs.dump() method to dump only design documents. In such a case, the regular document directory object should not be told to store any documents. In RSpec form:
    it "should not dump regular docs when asked for only design docs" do
@store.stub!(:map).
and_return([{'foo' => 'bar'}])

@dir.
should_not_receive(:store_document)

CouchDocs.dump("uri", "fixtures", :design)
end
That fails with a bad arity message because dump only accepts 2 arguments:
1)
ArgumentError in 'CouchDocs dumping CouchDB documents to a directory should not dump regular docs when asked for only design docs'
wrong number of arguments (3 for 2)
./spec/couch_docs_spec.rb:99:in `dump'
./spec/couch_docs_spec.rb:99:
I am in the change-the-message part of the change-the-message-or-make-it-pass cycle. I add a third, optional argument to dump and the message is now:
1)
Spec::Mocks::MockExpectationError in 'CouchDocs dumping CouchDB documents to a directory should not dump regular docs when asked for only design docs'
Mock "Document Directory" expected :store_document with ({"foo"=>"bar"}) 0 times, but received it once
./spec/couch_docs_spec.rb:99:
Now, I can make the spec pass by using a null directory object in the presence of the :design flag:
  def self.dump(db_uri, dir, only=nil)
null_dir = OpenStruct.new(:store_document => nil)

doc_dir = (only == :design) ?
null_dir : DocumentDirectory.new(dir)


design_dir = DesignDirectory.new(dir)

store = Store.new(db_uri)
store.map.each do |doc|
doc.delete('_rev')
(doc['_id'] =~ /^_design/ ? design_dir : doc_dir).
store_document(doc)
end
end
I do something similar in the presence of a :doc symbol. The nice thing about this approach is that when the optional third argument is nil, the method continues to behave as before (and my specs confirm this).

After BDD'ing the command line and I am ready to test things out for real. I change to a "dump" sub-directory of my "tmp" directory, make sure that nothing is there, then use the couch-docs command to dump the design documents:
cstrom@whitefall:~/tmp/dump$ ls
cstrom@whitefall:~/tmp/dump$ couch-docs dump http://localhost:5984/test -d
cstrom@whitefall:~/tmp/dump$ find
.
./_design
./_design/meals
./_design/meals/views
./_design/meals/views/by_year
./_design/meals/views/by_year/map.js
./_design/meals/views/by_date
...
Yay!

I also try this out on my development database but experience two problems: the dump of the couchapp design document is not working and it takes forever. I will investigate those two issues tomorrow.

Day #31

1 comment:

  1. This is interesting. Keep up the good work. I'm currently writing one in node.js too, that grabs all design documents and then pumps them into files so I can keep a backup copy of them (after running them through uglify's beautifier).

    ReplyDelete