Module: CouchResource::View::ClassMethods

Defined in:
lib/couch_resource/view.rb

Instance Method Summary collapse

Instance Method Details

#define_design_document(design) ⇒ Object

Define design document if it does not exist on the server.



164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
# File 'lib/couch_resource/view.rb', line 164

def define_design_document(design)
  path = design_path(design)
  design_document         = read_inheritable_attribute(:design_documents)[design]
  design_revision_checked = read_inheritable_attribute(:design_revision_checked) || false
  logger.debug "Design Document Check"
  logger.debug "  check_design_revision_every_time = #{check_design_revision_every_time}"
  logger.debug "  design_revision_checked          = #{design_revision_checked}"
  #if self.check_view_every_access
  if self.check_design_revision_every_time || !design_revision_checked
    current_doc = get_design_document_from_server(design)
    # already exists
    if current_doc
      logger.debug "Design document is found and updates are being checked."
      logger.debug current_doc.to_json
      if match_views?(design_document[:views], current_doc[:views])
        logger.debug "Design document(#{path}) is the latest."
      else
        logger.debug "Design document(#{path}) is not the latest, should be updated."
        design_document[:_rev] = current_doc[:_rev]
        logger.debug "CouchResource::Connection#put #{path}"
        hash = connection.put(path, design_document.to_json)
        logger.debug hash.to_json
        design_document[:_rev] = hash[:rev]
      end
    else
      logger.debug "Design document not found so to put."
      design_document.delete(:_rev)
      logger.debug "CouchResource::Connection#put #{path}"
      logger.debug design_document.to_json
      hash = connection.put(path, design_document.to_json)
      logger.debug hash.to_json
      design_document[:_rev] = hash["rev"]
    end
    design_revision_checked = true
  else
    if design_document[:_rev].nil?
      begin
        hash = connection.put(design_path(design), design_document.to_json)
        design_document[:_rev] = hash[:rev]
      rescue CouchResource::PreconditionFailed
        # through the error.
        design_document[:_rev] = connection.get(design_path(design))[:_rev]
      end
    end
  end
end

#define_view_method(design, view) ⇒ Object



129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/couch_resource/view.rb', line 129

def define_view_method(design, view)
  method = <<-EOS
  def self.find_#{design}_#{view}(*args)
    options = args.extract_options!
    define_design_document("#{design.to_s}")
    case args.first
    when :first
      find_#{design}_#{view}_first(options)
    when :last
      find_#{design}_#{view}_last(options)
    else
      find_#{design}_#{view}_all(options)
    end
  end
EOS
  class_eval(method, __FILE__, __LINE__)

  [:all, :first, :last].each do |key|
    method = <<-EOS
    def self.find_#{design}_#{view}_#{key}(options = {})
      define_design_document("#{design.to_s}")
      find_#{key}("#{design}", :#{view}, options)
    end
EOS
    class_eval(method, __FILE__, __LINE__)
  end
end

#design_path(design, query_options = nil) ⇒ Object

Returns the design path specified by the design and view name.



22
23
24
25
26
# File 'lib/couch_resource/view.rb', line 22

def design_path(design, query_options=nil)
  design_fullname = get_design_fullname(design)
  # document_path("_design%2F#{design_fullname}", query_options)
  document_path("_design/#{design_fullname}", query_options)
end

#get_design_document_from_server(design) ⇒ Object



157
158
159
160
161
# File 'lib/couch_resource/view.rb', line 157

def get_design_document_from_server(design)
  path = design_path(design)
  logger.debug "CouchResource::Connection#get #{path}"
  connection.get(path) rescue nil
end

#get_design_fullname(design) ⇒ Object

Returns the full name of design document.



47
48
49
# File 'lib/couch_resource/view.rb', line 47

def get_design_fullname(design)
  "#{self.to_s}_#{design}"
end

#get_view_definition(design, view) ⇒ Object

Returns the view definition hash which contains :map key and :reduce key (optional).



52
53
54
55
56
57
# File 'lib/couch_resource/view.rb', line 52

def get_view_definition(design, view)
  design_documents = read_inheritable_attribute(:design_documents) || {}
  design_doc = design_documents[design.to_s]
  return nil unless design_doc
  return design_doc[:views][view]
end

#include_js(path, root = nil) ⇒ Object

Returns the string of the javascript file stored in the path The path is the relative path, root of which is the directory of the caller. The root can be also specified in the second argument.



115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/couch_resource/view.rb', line 115

def include_js(path, root = nil)
  # set root the current directory of the caller.
  if root.nil?
    from = caller.first
    if from =~ /^(.+?):(\d+)/
      root = File.dirname($1)
    else
      root = RAILS_ROOT
    end
  end
  fullpath = File.join(root, path)
  ERB.new(File.read(fullpath)).result(binding)
end

#view(design, views) ⇒ Object

Define view on the server access method for this class.

for example, the following code defines a design_document at _design/SomeDocument_my_design

class SomeDocument

view :my_design, :sample_view => {
  :map    => include_js("path/to/map.js")
  :reduce => include_js("path/to/reduce.js")
}

end

The design document include one view whose name is ‘sample_view’. And following 4 methods will be available in SomeDocument class.

SomeDocument.find_my_design_sample_view()
SomeDocument.find_my_design_sample_view_first()
SomeDocument.find_my_design_sample_view_last()
SomeDocument.find_my_design_sample_view_all()

The design document actually stored on the server at the first time when the above methods are invoked.



81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/couch_resource/view.rb', line 81

def view(design, views)
  # append prefix to design
  # Klass_design is a proper design document name
  design_fullname = get_design_fullname(design)

  design_document = {
    :_id       => "_design/#{design_fullname}",
    :language => "javascript",
    :views    => views
  }
  # Get the design document revision if already exists.
  logger.debug "Design Doc: get the existance revision."
  rev = connection.get(design_path(design))[:_rev] rescue nil
  design_document[:_rev] = rev if rev
  logger.debug "Design Doc: revision: #{rev || 'not found'}"

  # Update inheritable attribute for design_documents
  design_documents = read_inheritable_attribute(:design_documents) || {}
  design_documents[design.to_s] = design_document
  write_inheritable_attribute(:design_documents, design_documents)

  # define query method for each views
  # find_{design}_{view}(*args)   -- key is one of :all, :first, :last
  # find_{design}_{view}_all(options)
  # find_{design}_{view}_first(options)
  # find_{design}_{view}_last(options)
  views.each do |viewname, functions|
    define_view_method(design, viewname)
  end
end

#view_path(design, view, query_options = nil) ⇒ Object

returns the view path specified by the design and view name.



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/couch_resource/view.rb', line 29

def view_path(design, view, query_options=nil)
  design_fullname = get_design_fullname(design)
  view_options = {}
  if query_options
    # convert query args to json value
    [:key, :startkey, :endkey].each do |arg|
      view_options[arg] = query_options[arg].to_json if query_options.has_key?(arg)
    end

    # do not care
    [:include_docs, :update, :descending, :group, :startkey_docid, :endkey_docid, :count, :skip, :group_level].each do |arg|
      view_options[arg] = query_options[arg] if query_options.has_key?(arg)
    end
  end
  document_path(File.join("_view", design_fullname, view.to_s), view_options)
end