Working on adding checksum support to design documents to handle updates

This commit is contained in:
Sam Lown 2011-04-13 15:42:28 +02:00
parent a6becd7305
commit 221e5a5470
8 changed files with 89 additions and 41 deletions

View file

@ -7,7 +7,7 @@ module CouchRest
module ClassMethods
def design_doc
@design_doc ||= Design.new(default_design_doc)
@design_doc ||= ::CouchRest::Design.new(default_design_doc)
end
# Use when something has been changed, like a view, so that on the next request
@ -90,24 +90,17 @@ module CouchRest
# Writes out a design_doc to a given database, returning the
# updated design doc
def update_design_doc(design_doc, db, force = false)
design_doc['couchrest-hash'] = design_doc.checksum
saved = stored_design_doc(db)
if saved
changes = force
design_doc['views'].each do |name, view|
if !compare_views(saved['views'][name], view)
changes = true
saved['views'][name] = view
end
end
if changes
if force || saved['couchrest-hash'] != design_doc['couchrest-hash']
saved.merge!(design_doc)
db.save_doc(saved)
end
design_doc
else
design_doc.database = db
design_doc.save
design_doc
db.save_doc(design_doc)
end
design_doc
end
# Return true if the two views match
@ -117,7 +110,7 @@ module CouchRest
end
end # module ClassMethods
end
end
end

View file

@ -90,6 +90,13 @@ module CouchRest
result ? all.last : limit(1).descending.all.last
end
# Return the number of documents in the currently defined result set.
# Use <tt>#count</tt> for the total number of documents regardless
# of the current limit defined.
def length
docs.length
end
# Perform a count operation based on the current view. If the view
# can be reduced, the reduce will be performed and return the first
# value. This is okay for most simple queries, but may provide
@ -383,30 +390,24 @@ module CouchRest
def execute
return self.result if result
raise "Database must be defined in model or view!" if use_database.nil?
retryable = true
# Remove the reduce value if its not needed
query.delete(:reduce) unless can_reduce?
begin
self.result = model.design_doc.view_on(use_database, name, query.reject{|k,v| v.nil?})
rescue RestClient::ResourceNotFound => e
if retryable
model.save_design_doc(use_database)
retryable = false
retry
else
raise e
end
end
# Save the design doc for the current database. This should be efficient
# and check for changes
model.save_design_doc(use_database)
self.result = model.design_doc.view_on(use_database, name, query.reject{|k,v| v.nil?})
end
# Class Methods
class << self
# Simplified view creation. A new view will be added to the
# provided model's design document using the name and options.
#
# If the view name starts with "by_" and +:by+ is not provided in
# the options, the new view's map method will be interpretted and
# the options, the new view's map method will be interpreted and
# generated automatically. For example:
#
# View.create(Meeting, "by_date_and_name")

View file

@ -0,0 +1,15 @@
CouchRest::Database.class_eval do
alias :delete_orig! :delete!
def delete!
clear_model_fresh_cache
delete_orig!
end
# If the database is deleted, ensure that the design docs will be refreshed.
def clear_model_fresh_cache
::CouchRest::Model::Base.subclasses.each{|klass| klass.req_design_doc_refresh if klass.respond_to?(:req_design_doc_refresh)}
end
end

View file

@ -0,0 +1,24 @@
CouchRest::Design.class_eval do
# Calculate a checksum of the Design document. Used for ensuring the latest
# version has been sent to the database.
#
# This will generate an flatterned, ordered array of all the elements of the
# design document, convert to string then generate an MD5 Hash. This should
# result in a consisitent Hash accross all platforms.
#
def checksum
# create a copy of basic elements
base = self.dup
base.delete('_id')
base.delete('_rev')
result = nil
flatten =
lambda{|v|
v.is_a?(Hash) ? v.flatten.map{|v| flatten.call(v)}.flatten : v
}
Digest::MD5.hexdigest(flatten.call(base).sort.join(''))
end
end