lib/exegesis/design.rb in mattly-exegesis-0.2.0 vs lib/exegesis/design.rb in mattly-exegesis-0.2.1

- old
+ new

@@ -1,8 +1,9 @@ require 'pathname' module Exegesis class Design + include Exegesis::Document def self.design_directory= dir @design_directory = Pathname.new(dir) end @@ -34,59 +35,81 @@ '_id' => "_design/#{design_name}", 'views' => {} } end + def self.views + @views ||= canonical_design['views'].keys + end + + def self.reduceable? view_name + view_name = view_name.to_s + views.include?(view_name) && canonical_design['views'][view_name].has_key?('reduce') + end + def self.view name, default_options={} - define_method name do |key, *opts| - view name, key, opts.first, default_options + define_method name do |*opts| + options = parse_opts opts.shift, opts.first, default_options + Exegesis::DocumentCollection.new(call_view(name, options), database) end end def self.docs name, default_options={} - default_options = {:include_docs => true, :reduce => false}.merge(default_options) + view_name = default_options.delete(:view) || name + raise ArgumentError, "missing view #{view_name}" unless views.include?(view_name.to_s) + if [:reduce, :group, :group_level].any? {|key| default_options.has_key?(key)} + raise ArgumentError, "cannot reduce (:group, :group_level, :reduce) on a docs view" + end + + default_options = {:include_docs => true}.merge(default_options) + default_options.update({:reduce => false}) if reduceable?(view_name) + define_method name do |*opts| key = opts.shift options = parse_opts key, opts.first, default_options - response = call_view name, options - ids = [] - response.inject([]) do |memo, doc| - unless ids.include?(doc['id']) - ids << doc['id'] - memo << Exegesis.instantiate(doc['doc'], database) - end - memo - end + Exegesis::DocumentCollection.new(call_view(view_name, options), database) end end def self.hash name, default_options={} - default_options = {:group => true}.merge(default_options) view_name = default_options.delete(:view) || name + raise ArgumentError, "missing view #{view_name}" unless views.include?(view_name.to_s) + raise NameError, "Cannot return a hash for views without a reduce function" unless reduceable?(view_name) + if default_options.has_key?(:group) && default_options[:group] == false + raise ArgumentError, "cannot turn off grouping for a hash view" + end + + default_options = {:group => true}.merge(default_options) + define_method name do |*opts| - key = opts.shift - options = parse_opts key, opts.first, default_options - options.delete(:group) if options[:key] + options = parse_opts opts.shift, opts.first, default_options + + if options.has_key?(:group) && options[:group] == false + raise ArgumentError, "cannot turn off grouping for a hash view" + end + + if options[:key] + options.delete(:group) + options.delete(:group_level) + end response = call_view view_name, options if response.size == 1 && response.first['key'].nil? response.first['value'] else response.inject({}) do |memo, row| - if ! memo.has_key?(row['key']) - memo[row['key']] = row['value'] - end - memo + memo.update(row['key'] => row['value']) end end end end def initialize db begin - super db.get("_design/#{design_name}"), db + super db.raw_get("_design/#{design_name}") + self.database = db rescue RestClient::ResourceNotFound db.put("_design/#{design_name}", self.class.canonical_design) retry end unless self['views'] == self.class.canonical_design['views'] @@ -111,10 +134,11 @@ def parse_opts key, opts={}, defaults={} opts = straighten_args key, opts, defaults parse_key opts parse_keys opts parse_range opts + parse_reduce opts opts end private @@ -146,9 +170,21 @@ end def parse_range opts if opts[:startkey] || opts[:endkey] raise ArgumentError, "both a startkey and endkey must be specified if either is" unless opts[:startkey] && opts[:endkey] + end + end + + def parse_reduce opts + if opts.has_key?(:group) + opts[:group_level] = opts.delete(:group) if opts[:group].is_a?(Numeric) + end + if opts.keys.any? {|key| [:group, :group_level].include?(key) } + raise ArgumentError, "cannot include_docs when reducing" if opts[:include_docs] + if opts.has_key?(:reduce) && opts[:reduce] == false + raise ArgumentError, "cannot reduce=false when either group or group_level is present" + end end end end end \ No newline at end of file