require 'digest/md5' module CouchRest module Mixins module DesignDoc def self.included(base) base.extend(ClassMethods) end module ClassMethods attr_accessor :design_doc, :design_doc_slug_cache, :design_doc_fresh def design_doc @design_doc ||= Design.new(default_design_doc) end def design_doc_id "_design/#{design_doc_slug}" end def design_doc_slug return design_doc_slug_cache if (design_doc_slug_cache && design_doc_fresh) funcs = [] design_doc['views'].each do |name, view| funcs << "#{name}/#{view['map']}#{view['reduce']}" end self.design_doc_slug_cache = self.to_s end def default_design_doc { "language" => "javascript", "views" => { 'all' => { 'map' => "function(doc) { if (doc['couchrest-type'] == '#{self.to_s}') { emit(null,1); } }", 'reduce' => "function(keys, values) { return sum(values); }" } } } end def refresh_design_doc reset_design_doc save_design_doc end # Save the design doc onto the default database, and update the # design_doc attribute def save_design_doc reset_design_doc unless design_doc_fresh self.design_doc = update_design_doc(design_doc) end # Save the design doc onto a target database in a thread-safe way, # not modifying the model's design_doc def save_design_doc_on(db) update_design_doc(Design.new(design_doc), db) end private def reset_design_doc current = self.database.get(design_doc_id) rescue nil design_doc['_id'] = design_doc_id if current.nil? design_doc.delete('_rev') else design_doc['_rev'] = current['_rev'] end self.design_doc_fresh = true end # Writes out a design_doc to a given database, returning the # updated design doc def update_design_doc(design_doc, db = database) saved = db.get(design_doc['_id']) rescue nil if saved design_doc['views'].each do |name, view| saved['views'][name] = view end db.save_doc(saved) saved else design_doc.database = db design_doc.save design_doc end end end # module ClassMethods end end end