mongo_doc_rails2 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +5 -0
- data/.gitignore +8 -0
- data/HISTORY.md +11 -0
- data/LICENSE +20 -0
- data/README.textile +185 -0
- data/Rakefile +188 -0
- data/TODO +40 -0
- data/VERSION +1 -0
- data/data/.gitignore +2 -0
- data/examples/simple_document.rb +46 -0
- data/examples/simple_object.rb +34 -0
- data/features/collections.feature +9 -0
- data/features/embed_hash.feature +16 -0
- data/features/finders.feature +76 -0
- data/features/indexes.feature +28 -0
- data/features/mongodb.yml +7 -0
- data/features/mongodoc_base.feature +128 -0
- data/features/new_record.feature +36 -0
- data/features/partial_updates.feature +95 -0
- data/features/removing_documents.feature +68 -0
- data/features/saving_an_object.feature +15 -0
- data/features/scopes.feature +66 -0
- data/features/step_definitions/collection_steps.rb +17 -0
- data/features/step_definitions/document_steps.rb +149 -0
- data/features/step_definitions/documents.rb +40 -0
- data/features/step_definitions/embed_hash_steps.rb +6 -0
- data/features/step_definitions/finder_steps.rb +15 -0
- data/features/step_definitions/index_steps.rb +10 -0
- data/features/step_definitions/json_steps.rb +9 -0
- data/features/step_definitions/object_steps.rb +50 -0
- data/features/step_definitions/objects.rb +24 -0
- data/features/step_definitions/partial_update_steps.rb +31 -0
- data/features/step_definitions/query_steps.rb +66 -0
- data/features/step_definitions/removing_documents_steps.rb +14 -0
- data/features/step_definitions/scope_steps.rb +18 -0
- data/features/step_definitions/string_casting_steps.rb +29 -0
- data/features/step_definitions/util_steps.rb +7 -0
- data/features/string_casting.feature +10 -0
- data/features/support/support.rb +10 -0
- data/features/using_criteria.feature +142 -0
- data/lib/mongo_doc.rb +12 -0
- data/lib/mongo_doc/associations.rb +109 -0
- data/lib/mongo_doc/associations/collection_proxy.rb +121 -0
- data/lib/mongo_doc/associations/document_proxy.rb +65 -0
- data/lib/mongo_doc/associations/hash_proxy.rb +102 -0
- data/lib/mongo_doc/associations/proxy_base.rb +48 -0
- data/lib/mongo_doc/attributes.rb +84 -0
- data/lib/mongo_doc/bson.rb +31 -0
- data/lib/mongo_doc/collection.rb +82 -0
- data/lib/mongo_doc/connection.rb +88 -0
- data/lib/mongo_doc/contexts.rb +31 -0
- data/lib/mongo_doc/contexts/ids.rb +41 -0
- data/lib/mongo_doc/contexts/mongo.rb +272 -0
- data/lib/mongo_doc/criteria.rb +70 -0
- data/lib/mongo_doc/cursor.rb +32 -0
- data/lib/mongo_doc/document.rb +205 -0
- data/lib/mongo_doc/ext.rb +16 -0
- data/lib/mongo_doc/ext/array.rb +5 -0
- data/lib/mongo_doc/ext/binary.rb +7 -0
- data/lib/mongo_doc/ext/boolean_class.rb +17 -0
- data/lib/mongo_doc/ext/date.rb +19 -0
- data/lib/mongo_doc/ext/date_time.rb +17 -0
- data/lib/mongo_doc/ext/dbref.rb +7 -0
- data/lib/mongo_doc/ext/hash.rb +7 -0
- data/lib/mongo_doc/ext/min_max_keys.rb +13 -0
- data/lib/mongo_doc/ext/nil_class.rb +5 -0
- data/lib/mongo_doc/ext/numeric.rb +17 -0
- data/lib/mongo_doc/ext/object.rb +19 -0
- data/lib/mongo_doc/ext/object_id.rb +7 -0
- data/lib/mongo_doc/ext/regexp.rb +5 -0
- data/lib/mongo_doc/ext/string.rb +5 -0
- data/lib/mongo_doc/ext/symbol.rb +5 -0
- data/lib/mongo_doc/ext/time.rb +9 -0
- data/lib/mongo_doc/finders.rb +38 -0
- data/lib/mongo_doc/index.rb +46 -0
- data/lib/mongo_doc/matchers.rb +35 -0
- data/lib/mongo_doc/root.rb +26 -0
- data/lib/mongo_doc/scope.rb +64 -0
- data/lib/mongo_doc/validations.rb +12 -0
- data/lib/mongo_doc/validations/macros.rb +11 -0
- data/lib/mongo_doc/validations/validates_embedded.rb +13 -0
- data/lib/mongoid/contexts/enumerable.rb +151 -0
- data/lib/mongoid/contexts/paging.rb +42 -0
- data/lib/mongoid/criteria.rb +239 -0
- data/lib/mongoid/criterion/complex.rb +21 -0
- data/lib/mongoid/criterion/exclusion.rb +65 -0
- data/lib/mongoid/criterion/inclusion.rb +93 -0
- data/lib/mongoid/criterion/optional.rb +136 -0
- data/lib/mongoid/extensions/hash/criteria_helpers.rb +20 -0
- data/lib/mongoid/extensions/symbol/inflections.rb +36 -0
- data/lib/mongoid/matchers/all.rb +11 -0
- data/lib/mongoid/matchers/default.rb +26 -0
- data/lib/mongoid/matchers/exists.rb +13 -0
- data/lib/mongoid/matchers/gt.rb +11 -0
- data/lib/mongoid/matchers/gte.rb +11 -0
- data/lib/mongoid/matchers/in.rb +11 -0
- data/lib/mongoid/matchers/lt.rb +11 -0
- data/lib/mongoid/matchers/lte.rb +11 -0
- data/lib/mongoid/matchers/ne.rb +11 -0
- data/lib/mongoid/matchers/nin.rb +11 -0
- data/lib/mongoid/matchers/size.rb +11 -0
- data/mongo_doc_rails2.gemspec +237 -0
- data/mongod.example.yml +2 -0
- data/mongodb.example.yml +14 -0
- data/perf/mongo_doc_object.rb +83 -0
- data/perf/mongo_document.rb +84 -0
- data/perf/ruby_driver.rb +49 -0
- data/script/console +8 -0
- data/spec/array_including_argument_matcher.rb +62 -0
- data/spec/associations/collection_proxy_spec.rb +233 -0
- data/spec/associations/document_proxy_spec.rb +45 -0
- data/spec/associations/hash_proxy_spec.rb +181 -0
- data/spec/associations/proxy_base_spec.rb +92 -0
- data/spec/associations_spec.rb +218 -0
- data/spec/attributes_accessor_spec.rb +33 -0
- data/spec/attributes_spec.rb +145 -0
- data/spec/bson_matchers.rb +54 -0
- data/spec/bson_spec.rb +196 -0
- data/spec/collection_spec.rb +169 -0
- data/spec/connection_spec.rb +147 -0
- data/spec/contexts/ids_spec.rb +49 -0
- data/spec/contexts/mongo_spec.rb +235 -0
- data/spec/contexts_spec.rb +56 -0
- data/spec/criteria_spec.rb +69 -0
- data/spec/cursor_spec.rb +91 -0
- data/spec/document_ext.rb +9 -0
- data/spec/document_spec.rb +553 -0
- data/spec/embedded_save_spec.rb +73 -0
- data/spec/ext_spec.rb +89 -0
- data/spec/finders_spec.rb +61 -0
- data/spec/hash_matchers.rb +27 -0
- data/spec/index_spec.rb +79 -0
- data/spec/matchers_spec.rb +342 -0
- data/spec/mongodb.yml +6 -0
- data/spec/mongodb_pairs.yml +8 -0
- data/spec/new_record_spec.rb +128 -0
- data/spec/root_spec.rb +41 -0
- data/spec/scope_spec.rb +79 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +14 -0
- data/spec/validations_spec.rb +30 -0
- metadata +346 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
class Object
|
|
2
|
+
define_method :singleton_class, instance_method(:metaclass) unless respond_to?(:singleton_class)
|
|
3
|
+
|
|
4
|
+
def to_bson(*args)
|
|
5
|
+
{MongoDoc::BSON::CLASS_KEY => self.class.name}.tap do |bson_hash|
|
|
6
|
+
instance_variables.each do |name|
|
|
7
|
+
bson_hash[name[1..-1]] = instance_variable_get(name).to_bson(args)
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.bson_create(bson_hash, options = {})
|
|
13
|
+
allocate.tap do |obj|
|
|
14
|
+
bson_hash.each do |name, value|
|
|
15
|
+
obj.instance_variable_set("@#{name}", MongoDoc::BSON.decode(value, options))
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
require 'mongo_doc/criteria'
|
|
2
|
+
|
|
3
|
+
module MongoDoc
|
|
4
|
+
module Finders
|
|
5
|
+
def self.extended(base)
|
|
6
|
+
base.extend(Criteria) unless base === Criteria
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
# Find a +Document+ based on id (+String+ or +BSON::ObjectID+)
|
|
10
|
+
#
|
|
11
|
+
# <tt>Person.find('1')</tt>
|
|
12
|
+
# <tt>Person.find(obj_id_1, obj_id_2)</tt>
|
|
13
|
+
def find(*args)
|
|
14
|
+
criteria.id(*args)
|
|
15
|
+
end
|
|
16
|
+
#
|
|
17
|
+
# Find all +Document+s in the collections
|
|
18
|
+
#
|
|
19
|
+
# <tt>Person.find_all</tt>
|
|
20
|
+
def find_all
|
|
21
|
+
criteria
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Find a +Document+ based on id (+String+ or +BSON::ObjectID+)
|
|
25
|
+
# or conditions
|
|
26
|
+
#
|
|
27
|
+
# <tt>Person.find_one('1')</tt>
|
|
28
|
+
# <tt>Person.find_one(:where => {:age.gt > 25})</tt>
|
|
29
|
+
def find_one(conditions_or_id)
|
|
30
|
+
if Hash === conditions_or_id
|
|
31
|
+
Mongoid::Criteria.translate(self, conditions_or_id).one
|
|
32
|
+
else
|
|
33
|
+
Mongoid::Criteria.translate(self, conditions_or_id)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
module MongoDoc
|
|
2
|
+
module Index
|
|
3
|
+
|
|
4
|
+
DIRECTION = { :asc => Mongo::ASCENDING,
|
|
5
|
+
:desc => Mongo::DESCENDING,
|
|
6
|
+
:geo2d => Mongo::GEO2D }
|
|
7
|
+
OPTIONS = [:min, :max, :background, :unique, :dropDups]
|
|
8
|
+
|
|
9
|
+
# Create an index on a collection.
|
|
10
|
+
#
|
|
11
|
+
# For compound indexes, pass pairs of fields and
|
|
12
|
+
# directions (+:asc+, +:desc+) as a hash.
|
|
13
|
+
#
|
|
14
|
+
# For a unique index, pass the option +:unique => true+.
|
|
15
|
+
# To create the index in the background, pass the options +:background => true+.
|
|
16
|
+
# If you want to remove duplicates from existing records when creating the
|
|
17
|
+
# unique index, pass the option +:dropDups => true+
|
|
18
|
+
#
|
|
19
|
+
# For GeoIndexing, specify the minimum and maximum longitude and latitude
|
|
20
|
+
# values with the +:min+ and +:max+ options.
|
|
21
|
+
#
|
|
22
|
+
# <tt>Person.index(:last_name)</tt>
|
|
23
|
+
# <tt>Person.index(:ssn, :unique => true)</tt>
|
|
24
|
+
# <tt>Person.index(:first_name => :asc, :last_name => :asc)</tt>
|
|
25
|
+
# <tt>Person.index(:first_name => :asc, :last_name => :asc, :unique => true)</tt>
|
|
26
|
+
def index(*args)
|
|
27
|
+
options_and_fields = args.extract_options!
|
|
28
|
+
if args.any?
|
|
29
|
+
collection.create_index(args.first, options_and_fields)
|
|
30
|
+
else
|
|
31
|
+
fields = options_and_fields.except(*OPTIONS)
|
|
32
|
+
options = options_and_fields.slice(*OPTIONS)
|
|
33
|
+
collection.create_index(to_mongo_direction(fields), options)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
protected
|
|
38
|
+
def to_mongo_direction(fields_hash)
|
|
39
|
+
fields_hash.to_a.map {|field| [field.first, direction(field.last)]}
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def direction(dir)
|
|
43
|
+
DIRECTION[dir] || Mongo::ASCENDING
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
require "mongoid/matchers/default"
|
|
2
|
+
require "mongoid/matchers/all"
|
|
3
|
+
require "mongoid/matchers/exists"
|
|
4
|
+
require "mongoid/matchers/gt"
|
|
5
|
+
require "mongoid/matchers/gte"
|
|
6
|
+
require "mongoid/matchers/in"
|
|
7
|
+
require "mongoid/matchers/lt"
|
|
8
|
+
require "mongoid/matchers/lte"
|
|
9
|
+
require "mongoid/matchers/ne"
|
|
10
|
+
require "mongoid/matchers/nin"
|
|
11
|
+
require "mongoid/matchers/size"
|
|
12
|
+
|
|
13
|
+
module MongoDoc #:nodoc:
|
|
14
|
+
module Matchers
|
|
15
|
+
# Determines if this document has the attributes to match the supplied
|
|
16
|
+
# MongoDB selector. Used for matching on embedded associations.
|
|
17
|
+
def matches?(selector)
|
|
18
|
+
selector.each_pair do |key, value|
|
|
19
|
+
return false unless matcher(key, value).matches?(value)
|
|
20
|
+
end
|
|
21
|
+
true
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
protected
|
|
25
|
+
# Get the matcher for the supplied key and value. Will determine the class
|
|
26
|
+
# name from the key.
|
|
27
|
+
def matcher(key, value)
|
|
28
|
+
if value.is_a?(Hash)
|
|
29
|
+
name = "Mongoid::Matchers::#{value.keys.first.gsub("$", "").camelize}"
|
|
30
|
+
return name.constantize.new(send(key))
|
|
31
|
+
end
|
|
32
|
+
Mongoid::Matchers::Default.new(send(key))
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module MongoDoc
|
|
2
|
+
module Root
|
|
3
|
+
|
|
4
|
+
attr_reader :_root
|
|
5
|
+
|
|
6
|
+
%w(_modifier_path _selector_path).each do |getter|
|
|
7
|
+
module_eval(<<-RUBY, __FILE__, __LINE__)
|
|
8
|
+
def #{getter}
|
|
9
|
+
@#{getter} ||= ''
|
|
10
|
+
end
|
|
11
|
+
RUBY
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
%w(_modifier_path _root _selector_path).each do |setter|
|
|
15
|
+
module_eval(<<-RUBY, __FILE__, __LINE__)
|
|
16
|
+
def #{setter}=(value)
|
|
17
|
+
@#{setter} = value
|
|
18
|
+
_associations.each do|a|
|
|
19
|
+
association = send(a)
|
|
20
|
+
association.#{setter} = value if association
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
RUBY
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Based on ActiveRecord::NamedScope
|
|
2
|
+
module MongoDoc
|
|
3
|
+
module Scope
|
|
4
|
+
def scopes
|
|
5
|
+
read_inheritable_attribute(:scopes) || write_inheritable_attribute(:scopes, {})
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def scope(name, *args, &block)
|
|
9
|
+
options = args.extract_options!
|
|
10
|
+
raise ArgumentError if args.size != 1
|
|
11
|
+
criteria = args.first
|
|
12
|
+
name = name.to_sym
|
|
13
|
+
scopes[name] = lambda do |parent_scope, *args|
|
|
14
|
+
CriteriaProxy.new(parent_scope, Mongoid::Criteria === criteria ? criteria : criteria.call(*args), options, &block)
|
|
15
|
+
end
|
|
16
|
+
(class << self; self; end).class_eval <<-EOT
|
|
17
|
+
def #{name}(*args)
|
|
18
|
+
scopes[:#{name}].call(self, *args)
|
|
19
|
+
end
|
|
20
|
+
EOT
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
class CriteriaProxy
|
|
24
|
+
attr_accessor :criteria, :klass, :parent_scope
|
|
25
|
+
|
|
26
|
+
delegate :scopes, :to => :parent_scope
|
|
27
|
+
|
|
28
|
+
def initialize(parent_scope, criteria, options, &block)
|
|
29
|
+
[options.delete(:extend)].flatten.each { |extension| extend extension } if options.include?(:extend)
|
|
30
|
+
extend Module.new(&block) if block_given?
|
|
31
|
+
if CriteriaProxy === parent_scope
|
|
32
|
+
chained = Mongoid::Criteria.new(klass)
|
|
33
|
+
chained.merge(parent_scope)
|
|
34
|
+
chained.merge(criteria)
|
|
35
|
+
self.criteria = chained
|
|
36
|
+
self.klass = criteria.klass
|
|
37
|
+
else
|
|
38
|
+
self.criteria = criteria
|
|
39
|
+
self.klass = parent_scope
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
self.parent_scope = parent_scope
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def respond_to?(method, include_private = false)
|
|
46
|
+
return true if scopes.include?(method)
|
|
47
|
+
criteria.respond_to?(method, include_private)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
private
|
|
51
|
+
|
|
52
|
+
def method_missing(method, *args, &block)
|
|
53
|
+
if scopes.include?(method)
|
|
54
|
+
scopes[method].call(self, *args)
|
|
55
|
+
else
|
|
56
|
+
chained = Mongoid::Criteria.new(klass)
|
|
57
|
+
chained.merge(criteria)
|
|
58
|
+
chained.send(method, *args, &block)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module Mongoid #:nodoc:
|
|
3
|
+
module Contexts #:nodoc:
|
|
4
|
+
class Enumerable
|
|
5
|
+
include Ids, Paging
|
|
6
|
+
attr_reader :criteria
|
|
7
|
+
|
|
8
|
+
delegate :blank?, :empty?, :first, :last, :to => :execute
|
|
9
|
+
delegate :documents, :options, :selector, :to => :criteria
|
|
10
|
+
|
|
11
|
+
# Return aggregation counts of the grouped documents. This will count by
|
|
12
|
+
# the first field provided in the fields array.
|
|
13
|
+
#
|
|
14
|
+
# Returns:
|
|
15
|
+
#
|
|
16
|
+
# A +Hash+ with field values as keys, count as values
|
|
17
|
+
def aggregate
|
|
18
|
+
counts = {}
|
|
19
|
+
group.each_pair { |key, value| counts[key] = value.size }
|
|
20
|
+
counts
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Get the average value for the supplied field.
|
|
24
|
+
#
|
|
25
|
+
# Example:
|
|
26
|
+
#
|
|
27
|
+
# <tt>context.avg(:age)</tt>
|
|
28
|
+
#
|
|
29
|
+
# Returns:
|
|
30
|
+
#
|
|
31
|
+
# A numeric value that is the average.
|
|
32
|
+
def avg(field)
|
|
33
|
+
total = sum(field)
|
|
34
|
+
total ? (total.to_f / count) : nil
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Gets the number of documents in the array. Delegates to size.
|
|
38
|
+
def count
|
|
39
|
+
@count ||= documents.size
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Gets an array of distinct values for the supplied field across the
|
|
43
|
+
# entire array or the susbset given the criteria.
|
|
44
|
+
#
|
|
45
|
+
# Example:
|
|
46
|
+
#
|
|
47
|
+
# <tt>context.distinct(:title)</tt>
|
|
48
|
+
def distinct(field)
|
|
49
|
+
execute.collect { |doc| doc.send(field) }.uniq
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Enumerable implementation of execute. Returns matching documents for
|
|
53
|
+
# the selector, and adds options if supplied.
|
|
54
|
+
#
|
|
55
|
+
# Returns:
|
|
56
|
+
#
|
|
57
|
+
# An +Array+ of documents that matched the selector.
|
|
58
|
+
def execute(paginating = false)
|
|
59
|
+
limit(documents.select { |document| document.matches?(selector) })
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Groups the documents by the first field supplied in the field options.
|
|
63
|
+
#
|
|
64
|
+
# Returns:
|
|
65
|
+
#
|
|
66
|
+
# A +Hash+ with field values as keys, arrays of documents as values.
|
|
67
|
+
def group
|
|
68
|
+
field = options[:fields].first
|
|
69
|
+
documents.group_by { |doc| doc.send(field) }
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Create the new enumerable context. This will need the selector and
|
|
73
|
+
# options from a +Criteria+ and a documents array that is the underlying
|
|
74
|
+
# array of embedded documents from a has many association.
|
|
75
|
+
#
|
|
76
|
+
# Example:
|
|
77
|
+
#
|
|
78
|
+
# <tt>Mongoid::Contexts::Enumerable.new(criteria)</tt>
|
|
79
|
+
def initialize(criteria)
|
|
80
|
+
@criteria = criteria
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Iterate over each +Document+ in the results. This can take an optional
|
|
84
|
+
# block to pass to each argument in the results.
|
|
85
|
+
#
|
|
86
|
+
# Example:
|
|
87
|
+
#
|
|
88
|
+
# <tt>context.iterate { |doc| p doc }</tt>
|
|
89
|
+
def iterate(&block)
|
|
90
|
+
execute.each(&block)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Get the largest value for the field in all the documents.
|
|
94
|
+
#
|
|
95
|
+
# Returns:
|
|
96
|
+
#
|
|
97
|
+
# The numerical largest value.
|
|
98
|
+
def max(field)
|
|
99
|
+
determine(field, :>=)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# Get the smallest value for the field in all the documents.
|
|
103
|
+
#
|
|
104
|
+
# Returns:
|
|
105
|
+
#
|
|
106
|
+
# The numerical smallest value.
|
|
107
|
+
def min(field)
|
|
108
|
+
determine(field, :<=)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Get one document.
|
|
112
|
+
#
|
|
113
|
+
# Returns:
|
|
114
|
+
#
|
|
115
|
+
# The first document in the +Array+
|
|
116
|
+
alias :one :first
|
|
117
|
+
|
|
118
|
+
# Get the sum of the field values for all the documents.
|
|
119
|
+
#
|
|
120
|
+
# Returns:
|
|
121
|
+
#
|
|
122
|
+
# The numerical sum of all the document field values.
|
|
123
|
+
def sum(field)
|
|
124
|
+
sum = documents.inject(nil) do |memo, doc|
|
|
125
|
+
value = doc.send(field)
|
|
126
|
+
memo ? memo += value : value
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
protected
|
|
131
|
+
# If the field exists, perform the comparison and set if true.
|
|
132
|
+
def determine(field, operator)
|
|
133
|
+
matching = documents.inject(nil) do |memo, doc|
|
|
134
|
+
value = doc.send(field)
|
|
135
|
+
(memo && memo.send(operator, value)) ? memo : value
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# Limits the result set if skip and limit options.
|
|
140
|
+
def limit(documents)
|
|
141
|
+
skip, limit = options[:skip], options[:limit]
|
|
142
|
+
if skip && limit
|
|
143
|
+
return documents.slice(skip, limit)
|
|
144
|
+
elsif limit
|
|
145
|
+
return documents.first(limit)
|
|
146
|
+
end
|
|
147
|
+
documents
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|