From a1328211b04c7574c58497c909fc7889f29ea49a Mon Sep 17 00:00:00 2001 From: Sam Lown Date: Mon, 11 Jun 2012 20:48:36 +0200 Subject: [PATCH] Working on migration --- lib/couchrest/model/designs/design.rb | 87 +++++++++++++++++++++------ 1 file changed, 68 insertions(+), 19 deletions(-) diff --git a/lib/couchrest/model/designs/design.rb b/lib/couchrest/model/designs/design.rb index c6f9ee88..de332842 100644 --- a/lib/couchrest/model/designs/design.rb +++ b/lib/couchrest/model/designs/design.rb @@ -67,45 +67,94 @@ def sync!(db = nil) # 3. Wait until the view returns a result # 4. Copy over the original design doc # - # A status will be returned according to which method was used in - # the migration, if at all. The symbols are: + # If a block is provided, it will be called with the result of the migration: # # * :no_change - Nothing performed as there are no changes. # * :created - Add a new design doc as non existed # * :migrated - Migrated the existing design doc. # + # This can be used for progressivly printing the results of the migration. # - def migrate!(db = nil) - doc = load_from_database(db) + # After completion, either a "cleanup" Proc object will be provided to finalize + # the process and copy the document into place, or simply nil if no cleanup is + # required. For example: + # + # print "Synchronising Cat model designs: " + # callback = Cat.design_doc.migrate do |res| + # puts res.to_s + # end + # if callback + # puts "Cleaning up." + # callback.call + # end + # + def migrate(db = nil, &block) + doc = load_from_database(db) + cleanup = nil if !doc # no need to migrate, just save it - db.save_doc(to_hash) - :created + new_doc = to_hash.dup + db.save_doc(new_doc) + + result = :created else doc['couchrest-hash'] != checksum - # Migration required - doc.merge!(to_hash) - doc['_id'] = self['_id']+"_#{Time.now.to_i}" - db.save_doc(doc) + id = self['_id'] + "_migration" + + # Delete current migration if there is one + old_migration = db.get(id) + db.delete_doc(old_migration) if old_migration + + # Save new design doc + new_doc = doc.merge(to_hash) + new_doc['_id'] = id + new_doc.delete('_rev') + db.save_doc(new_doc) + + # Proc definition to copy the migration doc over the original + cleanup = Proc.new do + db.copy_doc(new_doc, doc) + db.delete_doc(new_doc) + self + end + result = :migrated + else + # Already up to date + result = :no_change + end + + if new_doc && !new_doc['views'].empty? # Create a view query and send - name = doc['views'].keys.first - view = doc['views'][name] + name = new_doc['views'].keys.first + view = new_doc['views'][name] params = {:limit => 1} - params[:reduce => false] if view['reduce'] + params[:reduce] = false if view['reduce'] db.view(name, params) + end - # When that finishes, copy the design doc back - db.copy_doc(doc['_id'], self['_id']) + # Provide the result in block + yield result if block_given? + + cleanup + end - :migrated + # Perform a single migration and inmediatly request a cleanup operation: + # + # print "Synchronising Cat model designs: " + # Cat.design_doc.migrate! do |res| + # puts res.to_s + # end + # + def migrate!(db = nil, &block) + callback = migrate(db, &block) + if callback.is_a?(Proc) + callback.call else - # Already up to date - :no_change + callback end end - def checksum sum = self['couchrest-hash'] if sum && (@_original_hash == to_hash)