lib/plucky/query.rb in plucky-0.5.2 vs lib/plucky/query.rb in plucky-0.6.0

- old
+ new

@@ -1,38 +1,45 @@ # encoding: UTF-8 +require 'set' require 'forwardable' + module Plucky class Query include Enumerable extend Forwardable - OptionKeys = [ + # Private + OptionKeys = Set[ :select, :offset, :order, # MM :fields, :skip, :limit, :sort, :hint, :snapshot, # Ruby Driver - :batch_size, :timeout, :transformer, # Ruby Driver - :max_scan, :show_disk_loc, :return_key, # Ruby Driver + :batch_size, :timeout, :max_scan, :return_key, # Ruby Driver + :transformer, :show_disk_loc, :comment, :read, # Ruby Driver + :tag_sets, :acceptable_latency, # Ruby Driver ] attr_reader :criteria, :options, :collection - def_delegator :criteria, :simple? - def_delegator :options, :fields? + + def_delegator :@criteria, :simple? + def_delegator :@options, :fields? def_delegators :to_a, :include? - def initialize(collection, opts={}) + # Public + def initialize(collection, query_options = {}) @collection, @options, @criteria = collection, OptionsHash.new, CriteriaHash.new - opts.each { |key, value| self[key] = value } + query_options.each { |key, value| self[key] = value } end - def initialize_copy(source) + def initialize_copy(original) super @criteria = @criteria.dup @options = @options.dup end + # Public def object_ids(*keys) - return criteria.object_ids if keys.empty? - criteria.object_ids = *keys + return @criteria.object_ids if keys.empty? + @criteria.object_ids = *keys self end # finder DSL methods to delegate to your model if you're building an ODM # e.g. MyModel.last needs to be equivalent to MyModel.query.last @@ -46,34 +53,43 @@ def paginate(opts={}) page = opts.delete(:page) limit = opts.delete(:per_page) || per_page query = clone.amend(opts) paginator = Pagination::Paginator.new(query.count, page, limit) - query.amend(:limit => paginator.limit, :skip => paginator.skip).all.tap do |docs| - docs.extend(Pagination::Decorator) - docs.paginator(paginator) - end + docs = query.amend({ + :limit => paginator.limit, + :skip => paginator.skip, + }).all + + docs.extend(Pagination::Decorator) + docs.paginator(paginator) + docs end def find_each(opts={}, &block) query = clone.amend(opts) - cursor = query.collection.find(query.criteria.to_hash, query.options.to_hash) + cursor = query.cursor + if block_given? cursor.each { |doc| yield doc } cursor.rewind! end + cursor end def find_one(opts={}) query = clone.amend(opts) - query.collection.find_one(query.criteria.to_hash, query.options.to_hash) + query.collection.find_one(query.criteria_hash, query.options_hash) end def find(*ids) return nil if ids.empty? - if ids.size == 1 && !ids[0].is_a?(Array) + + single_id_find = ids.size == 1 && !ids[0].is_a?(Array) + + if single_id_find first(:_id => ids[0]) else all(:_id => ids.flatten) end end @@ -94,49 +110,50 @@ find_each(&block) end def remove(opts={}, driver_opts={}) query = clone.amend(opts) - query.collection.remove(query.criteria.to_hash, driver_opts) + query.collection.remove(query.criteria_hash, driver_opts) end def count(opts={}) query = clone.amend(opts) - cursor = query.collection.find(query.criteria.to_hash, query.options.to_hash) + cursor = query.cursor cursor.count end def size count end def distinct(key, opts = {}) query = clone.amend(opts) - query.collection.distinct(key, query.criteria.to_hash) + query.collection.distinct(key, query.criteria_hash) end def fields(*args) clone.tap { |query| query.options[:fields] = *args } end def ignore(*args) - set_fields(args, 0) + set_field_inclusion(args, 0) end def only(*args) - set_fields(args, 1) + set_field_inclusion(args, 1) end def limit(count=nil) clone.tap { |query| query.options[:limit] = count } end def reverse clone.tap do |query| - query[:sort] = query[:sort].map do |s| - [s[0], -s[1]] - end unless query.options[:sort].nil? + sort = query[:sort] + unless sort.nil? + query.options[:sort] = sort.map { |s| [s[0], -s[1]] } + end end end def skip(count=nil) clone.tap { |query| query.options[:skip] = count } @@ -147,22 +164,20 @@ clone.tap { |query| query.options[:sort] = *args } end alias order sort def where(hash={}) - clone.tap do |query| - query.criteria.merge!(CriteriaHash.new(hash)) - end + clone.tap { |query| query.criteria.merge!(CriteriaHash.new(hash)) } end alias filter where def empty? count.zero? end - def exists?(options={}) - !count(options).zero? + def exists?(query_options={}) + !count(query_options).zero? end alias :exist? :exists? def to_a find_each.to_a @@ -170,60 +185,87 @@ end include DSL def update(document, driver_opts={}) query = clone - query.collection.update(query.criteria.to_hash, document, driver_opts) + query.collection.update(query.criteria_hash, document, driver_opts) end def amend(opts={}) opts.each { |key, value| self[key] = value } self end def [](key) - key = key.to_sym if key.respond_to?(:to_sym) - if OptionKeys.include?(key) - @options[key] - else - @criteria[key] - end + key = symbolized_key(key) + source = hash_for_key(key) + source[key] end def []=(key, value) - key = key.to_sym if key.respond_to?(:to_sym) - if OptionKeys.include?(key) - @options[key] = value - else - @criteria[key] = value - end + key = symbolized_key(key) + source = hash_for_key(key) + source[key] = value end def merge(other) - merged_criteria = criteria.merge(other.criteria).to_hash - merged_options = options.merge(other.options).to_hash + merged_criteria = @criteria.merge(other.criteria).to_hash + merged_options = @options.merge(other.options).to_hash clone.amend(merged_criteria).amend(merged_options) end def to_hash - criteria.to_hash.merge(options.to_hash) + criteria_hash.merge(options_hash) end def explain - collection.find(criteria.to_hash, options.to_hash).explain + @collection.find(criteria_hash, options_hash).explain end def inspect as_nice_string = to_hash.collect do |key, value| " #{key}: #{value.inspect}" end.sort.join(",") "#<#{self.class}#{as_nice_string}>" end + def criteria_hash + @criteria.to_hash + end + + def options_hash + @options.to_hash + end + + def cursor + @collection.find(criteria_hash, options_hash) + end + private - def set_fields(field_list, value) - the_fields = {} - field_list.each {|field| the_fields[field.to_sym] = value} - clone.tap { |query| query.options[:fields] = the_fields} + + # Private + def hash_for_key(key) + options_key?(key) ? @options : @criteria + end + + # Private + def symbolized_key(key) + if key.respond_to?(:to_sym) + key.to_sym + else + key + end + end + + # Private + def options_key?(key) + OptionKeys.include?(key) + end + + # Private + def set_field_inclusion(fields, value) + fields_option = {} + fields.each { |field| fields_option[symbolized_key(field)] = value } + clone.tap { |query| query.options[:fields] = fields_option } end end end