# encoding: utf-8 module Mongoid #:nodoc: module Contexts #:nodoc: class Enumerable include Ids, Paging attr_reader :criteria delegate :blank?, :empty?, :first, :last, :to => :execute delegate :documents, :options, :selector, :to => :criteria # Return aggregation counts of the grouped documents. This will count by # the first field provided in the fields array. # # Returns: # # A +Hash+ with field values as keys, count as values def aggregate counts = {} group.each_pair { |key, value| counts[key] = value.size } counts end # Gets the number of documents in the array. Delegates to size. def count @count ||= documents.size end # Enumerable implementation of execute. Returns matching documents for # the selector, and adds options if supplied. # # Returns: # # An +Array+ of documents that matched the selector. def execute(paginating = false) limit(documents.select { |document| document.matches?(selector) }) end # Groups the documents by the first field supplied in the field options. # # Returns: # # A +Hash+ with field values as keys, arrays of documents as values. def group field = options[:fields].first documents.group_by { |doc| doc.send(field) } end # Create the new enumerable context. This will need the selector and # options from a +Criteria+ and a documents array that is the underlying # array of embedded documents from a has many association. # # Example: # # Mongoid::Contexts::Enumerable.new(criteria) def initialize(criteria) @criteria = criteria end # Iterate over each +Document+ in the results. This can take an optional # block to pass to each argument in the results. # # Example: # # context.iterate { |doc| p doc } def iterate(&block) execute.each(&block) end # Get the largest value for the field in all the documents. # # Returns: # # The numerical largest value. def max(field) determine(field, :>=) end # Get the smallest value for the field in all the documents. # # Returns: # # The numerical smallest value. def min(field) determine(field, :<=) end # Get one document. # # Returns: # # The first document in the +Array+ alias :one :first # Get the sum of the field values for all the documents. # # Returns: # # The numerical sum of all the document field values. def sum(field) sum = documents.inject(nil) do |memo, doc| value = doc.send(field) memo ? memo += value : value end end protected # If the field exists, perform the comparison and set if true. def determine(field, operator) matching = documents.inject(nil) do |memo, doc| value = doc.send(field) (memo && memo.send(operator, value)) ? memo : value end end # Limits the result set if skip and limit options. def limit(documents) skip, limit = options[:skip], options[:limit] if skip && limit return documents.slice(skip, limit) elsif limit return documents.first(limit) end documents end end end end