2010-06-20 22:01:11 +02:00
|
|
|
# encoding: utf-8
|
2009-01-30 03:45:01 +01:00
|
|
|
module CouchRest
|
2010-06-20 22:01:11 +02:00
|
|
|
module Model
|
2009-01-30 03:45:01 +01:00
|
|
|
module DesignDoc
|
2010-08-18 20:00:03 +02:00
|
|
|
extend ActiveSupport::Concern
|
2011-04-17 02:46:33 +02:00
|
|
|
|
2009-01-30 03:45:01 +01:00
|
|
|
module ClassMethods
|
2011-04-17 02:46:33 +02:00
|
|
|
|
2009-03-27 21:22:10 +01:00
|
|
|
def design_doc
|
2011-11-29 00:47:13 +01:00
|
|
|
@design_doc ||= if auto_update_design_doc
|
|
|
|
::CouchRest::Design.new(default_design_doc)
|
|
|
|
else
|
2011-12-01 17:19:15 +01:00
|
|
|
stored_design_doc || ::CouchRest::Design.new(default_design_doc)
|
2011-11-29 00:47:13 +01:00
|
|
|
end
|
2009-03-27 21:22:10 +01:00
|
|
|
end
|
2011-04-17 02:46:33 +02:00
|
|
|
|
2009-01-30 03:45:01 +01:00
|
|
|
def design_doc_id
|
|
|
|
"_design/#{design_doc_slug}"
|
|
|
|
end
|
|
|
|
|
|
|
|
def design_doc_slug
|
2010-04-06 19:51:17 +02:00
|
|
|
self.to_s
|
2009-01-30 03:45:01 +01:00
|
|
|
end
|
|
|
|
|
2011-04-17 20:55:28 +02:00
|
|
|
def design_doc_uri(db = database)
|
|
|
|
"#{db.root}/#{design_doc_id}"
|
2009-01-30 03:45:01 +01:00
|
|
|
end
|
|
|
|
|
2010-04-07 23:00:51 +02:00
|
|
|
# Retreive the latest version of the design document directly
|
2011-04-17 02:46:33 +02:00
|
|
|
# from the database. This is never cached and will return nil if
|
|
|
|
# the design is not present.
|
|
|
|
#
|
|
|
|
# Use this method if you'd like to compare revisions [_rev] which
|
|
|
|
# is not stored in the normal design doc.
|
2010-04-07 23:00:51 +02:00
|
|
|
def stored_design_doc(db = database)
|
2011-04-17 02:46:33 +02:00
|
|
|
db.get(design_doc_id)
|
|
|
|
rescue RestClient::ResourceNotFound
|
|
|
|
nil
|
2009-03-27 12:27:37 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
# Save the design doc onto a target database in a thread-safe way,
|
|
|
|
# not modifying the model's design_doc
|
2010-04-07 23:00:51 +02:00
|
|
|
#
|
|
|
|
# See also save_design_doc! to always save the design doc even if there
|
|
|
|
# are no changes.
|
|
|
|
def save_design_doc(db = database, force = false)
|
2011-04-17 02:46:33 +02:00
|
|
|
update_design_doc(db, force)
|
2010-04-07 23:00:51 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
# Force the update of the model's design_doc even if it hasn't changed.
|
|
|
|
def save_design_doc!(db = database)
|
|
|
|
save_design_doc(db, true)
|
2009-03-27 12:27:37 +01:00
|
|
|
end
|
|
|
|
|
2011-04-17 02:46:33 +02:00
|
|
|
private
|
2010-04-06 19:51:17 +02:00
|
|
|
|
2011-04-17 02:46:33 +02:00
|
|
|
def design_doc_cache
|
|
|
|
Thread.current[:couchrest_design_cache] ||= {}
|
2010-04-06 19:51:17 +02:00
|
|
|
end
|
2011-04-17 02:46:33 +02:00
|
|
|
def design_doc_cache_checksum(db)
|
2011-04-17 20:55:28 +02:00
|
|
|
design_doc_cache[design_doc_uri(db)]
|
2011-04-17 02:46:33 +02:00
|
|
|
end
|
|
|
|
def set_design_doc_cache_checksum(db, checksum)
|
2011-04-17 20:55:28 +02:00
|
|
|
design_doc_cache[design_doc_uri(db)] = checksum
|
2011-04-17 02:46:33 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
# Writes out a design_doc to a given database if forced
|
|
|
|
# or the stored checksum is not the same as the current
|
|
|
|
# generated checksum.
|
|
|
|
#
|
|
|
|
# Returns the original design_doc provided, but does
|
|
|
|
# not update it with the revision.
|
|
|
|
def update_design_doc(db, force = false)
|
|
|
|
return design_doc unless force || auto_update_design_doc
|
2010-04-06 19:51:17 +02:00
|
|
|
|
2011-04-17 02:46:33 +02:00
|
|
|
# Grab the design doc's checksum
|
|
|
|
checksum = design_doc.checksum!
|
|
|
|
|
|
|
|
# If auto updates enabled, check checksum cache
|
|
|
|
return design_doc if auto_update_design_doc && design_doc_cache_checksum(db) == checksum
|
|
|
|
|
2011-12-01 17:19:15 +01:00
|
|
|
retries = 1
|
|
|
|
begin
|
|
|
|
# Load up the stored doc (if present), update, and save
|
|
|
|
saved = stored_design_doc(db)
|
|
|
|
if saved
|
|
|
|
if force || saved['couchrest-hash'] != checksum
|
|
|
|
saved.merge!(design_doc)
|
|
|
|
db.save_doc(saved)
|
|
|
|
@design_doc = saved # update memo to point to the document we actually saved
|
|
|
|
end
|
|
|
|
else
|
|
|
|
design_doc.delete('_rev') # This is a new document and so doesn't have a revision yet
|
|
|
|
db.save_doc(design_doc)
|
2009-01-30 03:45:01 +01:00
|
|
|
end
|
2011-12-01 17:19:15 +01:00
|
|
|
rescue RestClient::Conflict
|
|
|
|
# if we get a conflict retry the operation...
|
|
|
|
raise if retries < 1
|
|
|
|
retries -= 1
|
|
|
|
retry
|
2009-01-30 03:45:01 +01:00
|
|
|
end
|
2011-04-17 02:46:33 +02:00
|
|
|
|
|
|
|
# Ensure checksum cached for next attempt if using auto updates
|
|
|
|
set_design_doc_cache_checksum(db, checksum) if auto_update_design_doc
|
2011-04-13 15:42:28 +02:00
|
|
|
design_doc
|
2009-01-30 03:45:01 +01:00
|
|
|
end
|
2010-04-07 23:00:51 +02:00
|
|
|
|
2011-04-17 02:46:33 +02:00
|
|
|
def default_design_doc
|
|
|
|
{
|
|
|
|
"_id" => design_doc_id,
|
|
|
|
"language" => "javascript",
|
|
|
|
"views" => {
|
|
|
|
'all' => {
|
|
|
|
'map' => "function(doc) {
|
|
|
|
if (doc['#{self.model_type_key}'] == '#{self.to_s}') {
|
|
|
|
emit(doc['_id'],1);
|
|
|
|
}
|
|
|
|
}"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
2009-01-30 03:45:01 +01:00
|
|
|
end # module ClassMethods
|
2011-04-13 15:42:28 +02:00
|
|
|
|
2009-01-30 03:45:01 +01:00
|
|
|
end
|
|
|
|
end
|
2010-04-06 19:51:17 +02:00
|
|
|
end
|