jchris / couchrest

A RESTful CouchDB client based on Heroku's RestClient and Couch.js - you want the version at http://github.com/couchrest/couchrest

couchrest / lib / couchrest / core / design.rb
100644 79 lines (68 sloc) 2.203 kb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
module CouchRest
  class Design < Document
    def view_by *keys
      opts = keys.pop if keys.last.is_a?(Hash)
      opts ||= {}
      self['views'] ||= {}
      method_name = "by_#{keys.join('_and_')}"
      
      if opts[:map]
        view = {}
        view['map'] = opts.delete(:map)
        if opts[:reduce]
          view['reduce'] = opts.delete(:reduce)
          opts[:reduce] = false
        end
        self['views'][method_name] = view
      else
        doc_keys = keys.collect{|k|"doc['#{k}']"} # this is where :require => 'doc.x == true' would show up
        key_emit = doc_keys.length == 1 ? "#{doc_keys.first}" : "[#{doc_keys.join(', ')}]"
        guards = opts.delete(:guards) || []
        guards.concat doc_keys
        map_function = <<-JAVASCRIPT
function(doc) {
if (#{guards.join(' && ')}) {
emit(#{key_emit}, null);
}
}
JAVASCRIPT
        self['views'][method_name] = {
          'map' => map_function
        }
      end
      self['views'][method_name]['couchrest-defaults'] = opts unless opts.empty?
      method_name
    end
    
    # Dispatches to any named view.
    # (using the database where this design doc was saved)
    def view view_name, query={}, &block
      view_on database, view_name, query, &block
    end
 
    # Dispatches to any named view in a specific database
    def view_on db, view_name, query={}, &block
      view_name = view_name.to_s
      view_slug = "#{name}/#{view_name}"
      defaults = (self['views'][view_name] && self['views'][view_name]["couchrest-defaults"]) || {}
      db.view(view_slug, defaults.merge(query), &block)
    end
 
    def name
      id.sub('_design/','') if id
    end
 
    def name= newname
      self['_id'] = "_design/#{newname}"
    end
 
    def save
      raise ArgumentError, "_design docs require a name" unless name && name.length > 0
      super
    end
 
    private
 
    # returns stored defaults if the there is a view named this in the design doc
    def has_view?(view)
      view = view.to_s
      self['views'][view] &&
        (self['views'][view]["couchrest-defaults"]||{})
    end
 
    def fetch_view view_name, opts, &block
      database.view(view_name, opts, &block)
    end
 
  end
  
end