mongoid 3.0.23 → 3.1.0
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/CHANGELOG.md +253 -9
- data/LICENSE +1 -1
- data/README.md +4 -1
- data/lib/config/locales/en.yml +7 -6
- data/lib/mongoid.rb +18 -1
- data/lib/mongoid/atomic.rb +22 -20
- data/lib/mongoid/atomic/paths/embedded.rb +19 -5
- data/lib/mongoid/atomic/paths/root.rb +1 -1
- data/lib/mongoid/atomic/positionable.rb +73 -0
- data/lib/mongoid/attributes.rb +63 -1
- data/lib/mongoid/callbacks.rb +58 -4
- data/lib/mongoid/components.rb +8 -3
- data/lib/mongoid/config.rb +71 -23
- data/lib/mongoid/contextual.rb +2 -1
- data/lib/mongoid/contextual/aggregable/mongo.rb +27 -63
- data/lib/mongoid/contextual/atomic.rb +4 -3
- data/lib/mongoid/contextual/find_and_modify.rb +1 -1
- data/lib/mongoid/contextual/geo_near.rb +238 -0
- data/lib/mongoid/contextual/map_reduce.rb +12 -1
- data/lib/mongoid/contextual/memory.rb +36 -31
- data/lib/mongoid/contextual/mongo.rb +147 -91
- data/lib/mongoid/contextual/queryable.rb +25 -0
- data/lib/mongoid/copyable.rb +4 -1
- data/lib/mongoid/criteria.rb +23 -275
- data/lib/mongoid/criterion/findable.rb +179 -0
- data/lib/mongoid/criterion/modifiable.rb +191 -0
- data/lib/mongoid/criterion/scoping.rb +11 -6
- data/lib/mongoid/document.rb +7 -56
- data/lib/mongoid/equality.rb +66 -0
- data/lib/mongoid/errors/mongoid_error.rb +7 -3
- data/lib/mongoid/extensions/array.rb +13 -1
- data/lib/mongoid/extensions/date.rb +9 -2
- data/lib/mongoid/extensions/hash.rb +38 -2
- data/lib/mongoid/extensions/nil_class.rb +12 -0
- data/lib/mongoid/extensions/object.rb +24 -0
- data/lib/mongoid/extensions/string.rb +14 -2
- data/lib/mongoid/extensions/time.rb +4 -1
- data/lib/mongoid/fields.rb +49 -5
- data/lib/mongoid/fields/foreign_key.rb +12 -0
- data/lib/mongoid/fields/standard.rb +12 -0
- data/lib/mongoid/finders.rb +8 -0
- data/lib/mongoid/hierarchy.rb +19 -1
- data/lib/mongoid/indexes.rb +30 -4
- data/lib/mongoid/indexes/validators/options.rb +12 -2
- data/lib/mongoid/inspection.rb +2 -1
- data/lib/mongoid/matchers/strategies.rb +5 -5
- data/lib/mongoid/observer.rb +27 -36
- data/lib/mongoid/persistence.rb +42 -17
- data/lib/mongoid/persistence/atomic.rb +10 -5
- data/lib/mongoid/persistence/atomic/operation.rb +26 -9
- data/lib/mongoid/persistence/atomic/unset.rb +1 -1
- data/lib/mongoid/persistence/operations/embedded/insert.rb +5 -2
- data/lib/mongoid/persistence/operations/embedded/remove.rb +5 -2
- data/lib/mongoid/persistence/operations/update.rb +7 -3
- data/lib/mongoid/railties/database.rake +12 -19
- data/lib/mongoid/relations.rb +2 -0
- data/lib/mongoid/relations/accessors.rb +30 -8
- data/lib/mongoid/relations/binding.rb +5 -1
- data/lib/mongoid/relations/bindings/referenced/in.rb +1 -1
- data/lib/mongoid/relations/bindings/referenced/many_to_many.rb +3 -3
- data/lib/mongoid/relations/counter_cache.rb +107 -0
- data/lib/mongoid/relations/embedded/batchable.rb +13 -4
- data/lib/mongoid/relations/embedded/many.rb +30 -1
- data/lib/mongoid/relations/macros.rb +2 -0
- data/lib/mongoid/relations/marshalable.rb +0 -1
- data/lib/mongoid/relations/metadata.rb +63 -11
- data/lib/mongoid/relations/options.rb +1 -0
- data/lib/mongoid/relations/proxy.rb +45 -2
- data/lib/mongoid/relations/referenced/in.rb +11 -2
- data/lib/mongoid/relations/referenced/many.rb +31 -3
- data/lib/mongoid/relations/referenced/many_to_many.rb +31 -3
- data/lib/mongoid/relations/referenced/one.rb +1 -1
- data/lib/mongoid/relations/targets/enumerable.rb +5 -1
- data/lib/mongoid/relations/touchable.rb +35 -6
- data/lib/mongoid/reloading.rb +5 -3
- data/lib/mongoid/scoping.rb +2 -2
- data/lib/mongoid/sessions.rb +57 -7
- data/lib/mongoid/sessions/factory.rb +22 -1
- data/lib/mongoid/threaded.rb +4 -30
- data/lib/mongoid/threaded/lifecycle.rb +12 -12
- data/lib/mongoid/timestamps.rb +1 -0
- data/lib/mongoid/timestamps/created.rb +2 -0
- data/lib/mongoid/timestamps/created/short.rb +19 -0
- data/lib/mongoid/timestamps/short.rb +10 -0
- data/lib/mongoid/timestamps/updated.rb +2 -0
- data/lib/mongoid/timestamps/updated/short.rb +19 -0
- data/lib/mongoid/validations.rb +2 -0
- data/lib/mongoid/validations/queryable.rb +2 -2
- data/lib/mongoid/validations/uniqueness.rb +1 -18
- data/lib/mongoid/version.rb +1 -1
- data/lib/rails/generators/mongoid/model/model_generator.rb +1 -0
- data/lib/rails/generators/mongoid/model/templates/model.rb.tt +3 -0
- data/lib/rails/mongoid.rb +53 -29
- data/lib/support/ruby_version.rb +26 -0
- metadata +18 -7
@@ -0,0 +1,66 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Mongoid
|
3
|
+
|
4
|
+
# This module contains the behaviour of Mongoid's clone/dup of documents.
|
5
|
+
module Equality
|
6
|
+
|
7
|
+
# Default comparison is via the string version of the id.
|
8
|
+
#
|
9
|
+
# @example Compare two documents.
|
10
|
+
# person <=> other_person
|
11
|
+
#
|
12
|
+
# @param [ Document ] other The document to compare with.
|
13
|
+
#
|
14
|
+
# @return [ Integer ] -1, 0, 1.
|
15
|
+
#
|
16
|
+
# @since 1.0.0
|
17
|
+
def <=>(other)
|
18
|
+
attributes["_id"].to_s <=> other.attributes["_id"].to_s
|
19
|
+
end
|
20
|
+
|
21
|
+
# Performs equality checking on the document ids. For more robust
|
22
|
+
# equality checking please override this method.
|
23
|
+
#
|
24
|
+
# @example Compare for equality.
|
25
|
+
# document == other
|
26
|
+
#
|
27
|
+
# @param [ Document, Object ] other The other object to compare with.
|
28
|
+
#
|
29
|
+
# @return [ true, false ] True if the ids are equal, false if not.
|
30
|
+
#
|
31
|
+
# @since 1.0.0
|
32
|
+
def ==(other)
|
33
|
+
self.class == other.class &&
|
34
|
+
attributes["_id"] == other.attributes["_id"]
|
35
|
+
end
|
36
|
+
|
37
|
+
# Performs class equality checking.
|
38
|
+
#
|
39
|
+
# @example Compare the classes.
|
40
|
+
# document === other
|
41
|
+
#
|
42
|
+
# @param [ Document, Object ] other The other object to compare with.
|
43
|
+
#
|
44
|
+
# @return [ true, false ] True if the classes are equal, false if not.
|
45
|
+
#
|
46
|
+
# @since 1.0.0
|
47
|
+
def ===(other)
|
48
|
+
other.class == Class ? self.class === other : self == other
|
49
|
+
end
|
50
|
+
|
51
|
+
# Delegates to ==. Used when needing checks in hashes.
|
52
|
+
#
|
53
|
+
# @example Perform equality checking.
|
54
|
+
# document.eql?(other)
|
55
|
+
#
|
56
|
+
# @param [ Document, Object ] other The object to check against.
|
57
|
+
#
|
58
|
+
# @return [ true, false ] True if equal, false if not.
|
59
|
+
#
|
60
|
+
# @since 1.0.0
|
61
|
+
def eql?(other)
|
62
|
+
self == (other)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
@@ -18,9 +18,13 @@ module Mongoid
|
|
18
18
|
#
|
19
19
|
# @since 3.0.0
|
20
20
|
def compose_message(key, attributes)
|
21
|
-
|
22
|
-
|
23
|
-
|
21
|
+
@problem = problem(key, attributes)
|
22
|
+
@summary = summary(key, attributes)
|
23
|
+
@resolution = resolution(key, attributes)
|
24
|
+
|
25
|
+
"\nProblem:\n #{@problem}"+
|
26
|
+
"\nSummary:\n #{@summary}"+
|
27
|
+
"\nResolution:\n #{@resolution}"
|
24
28
|
end
|
25
29
|
|
26
30
|
private
|
@@ -53,6 +53,18 @@ module Mongoid
|
|
53
53
|
::Time.configured.local(*self)
|
54
54
|
end
|
55
55
|
|
56
|
+
# Check if the array is part of a blank relation criteria.
|
57
|
+
#
|
58
|
+
# @example Is the array blank criteria?
|
59
|
+
# [].blank_criteria?
|
60
|
+
#
|
61
|
+
# @return [ true, false ] If the array is blank criteria.
|
62
|
+
#
|
63
|
+
# @since 3.1.0
|
64
|
+
def blank_criteria?
|
65
|
+
any?(&:blank_criteria?)
|
66
|
+
end
|
67
|
+
|
56
68
|
# Is the array a set of multiple arguments in a method?
|
57
69
|
#
|
58
70
|
# @example Is this multi args?
|
@@ -62,7 +74,7 @@ module Mongoid
|
|
62
74
|
#
|
63
75
|
# @since 3.0.0
|
64
76
|
def multi_arged?
|
65
|
-
first.resizable? || size > 1
|
77
|
+
!first.is_a?(Hash) && first.resizable? || size > 1
|
66
78
|
end
|
67
79
|
|
68
80
|
# Turn the object from the ruby type we deal with to a Mongo friendly
|
@@ -3,6 +3,9 @@ module Mongoid
|
|
3
3
|
module Extensions
|
4
4
|
module Date
|
5
5
|
|
6
|
+
# Constant for epoch - used when passing invalid times.
|
7
|
+
EPOCH = ::Date.new(1970, 1, 1)
|
8
|
+
|
6
9
|
# Convert the date into a time.
|
7
10
|
#
|
8
11
|
# @example Convert the date to a time.
|
@@ -57,8 +60,12 @@ module Mongoid
|
|
57
60
|
# @since 3.0.0
|
58
61
|
def mongoize(object)
|
59
62
|
unless object.blank?
|
60
|
-
|
61
|
-
|
63
|
+
begin
|
64
|
+
time = object.__mongoize_time__
|
65
|
+
::Time.utc(time.year, time.month, time.day)
|
66
|
+
rescue ArgumentError
|
67
|
+
EPOCH
|
68
|
+
end
|
62
69
|
end
|
63
70
|
end
|
64
71
|
end
|
@@ -35,18 +35,33 @@ module Mongoid
|
|
35
35
|
# @return [ Hash ] A new consolidated hash.
|
36
36
|
#
|
37
37
|
# @since 3.0.0
|
38
|
-
def __consolidate__
|
38
|
+
def __consolidate__(klass)
|
39
39
|
consolidated = {}
|
40
40
|
each_pair do |key, value|
|
41
41
|
if key =~ /\$/
|
42
|
+
value.each_pair do |_key, _value|
|
43
|
+
value[_key] = mongoize_for(klass, _key, _value)
|
44
|
+
end
|
42
45
|
(consolidated[key] ||= {}).merge!(value)
|
43
46
|
else
|
44
|
-
(consolidated["$set"] ||= {}).merge!(key => value)
|
47
|
+
(consolidated["$set"] ||= {}).merge!(key => mongoize_for(klass, key, value))
|
45
48
|
end
|
46
49
|
end
|
47
50
|
consolidated
|
48
51
|
end
|
49
52
|
|
53
|
+
# Check if the hash is part of a blank relation criteria.
|
54
|
+
#
|
55
|
+
# @example Is the hash blank criteria?
|
56
|
+
# {}.blank_criteria?
|
57
|
+
#
|
58
|
+
# @return [ true, false ] If the hash is blank criteria.
|
59
|
+
#
|
60
|
+
# @since 3.1.0
|
61
|
+
def blank_criteria?
|
62
|
+
self == { "_id" => { "$in" => [] }}
|
63
|
+
end
|
64
|
+
|
50
65
|
# Deletes an id value from the hash.
|
51
66
|
#
|
52
67
|
# @example Delete an id value.
|
@@ -135,6 +150,27 @@ module Mongoid
|
|
135
150
|
criteria
|
136
151
|
end
|
137
152
|
|
153
|
+
private
|
154
|
+
|
155
|
+
# Mongoize for the klass, key and value.
|
156
|
+
#
|
157
|
+
# @api private
|
158
|
+
#
|
159
|
+
# @example Mongoize for the klass, field and value.
|
160
|
+
# {}.mongoize_for(Band, "name", "test")
|
161
|
+
#
|
162
|
+
# @param [ Class ] klass The model class.
|
163
|
+
# @param [ String, Symbol ] The field key.
|
164
|
+
# @param [ Object ] value The value to mongoize.
|
165
|
+
#
|
166
|
+
# @return [ Object ] The mongoized value.
|
167
|
+
#
|
168
|
+
# @since 3.1.0
|
169
|
+
def mongoize_for(klass, key, value)
|
170
|
+
field = klass.fields[key.to_s]
|
171
|
+
field ? field.mongoize(value) : value
|
172
|
+
end
|
173
|
+
|
138
174
|
module ClassMethods
|
139
175
|
|
140
176
|
# Turn the object from the ruby type we deal with to a Mongo friendly
|
@@ -3,6 +3,18 @@ module Mongoid
|
|
3
3
|
module Extensions
|
4
4
|
module NilClass
|
5
5
|
|
6
|
+
# Try to form a setter from this object.
|
7
|
+
#
|
8
|
+
# @example Try to form a setter.
|
9
|
+
# object.__setter__
|
10
|
+
#
|
11
|
+
# @return [ nil ] Always nil.
|
12
|
+
#
|
13
|
+
# @since 3.1.0
|
14
|
+
def __setter__
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
6
18
|
# Get the name of a nil collection.
|
7
19
|
#
|
8
20
|
# @example Get the nil name.
|
@@ -40,6 +40,18 @@ module Mongoid
|
|
40
40
|
self
|
41
41
|
end
|
42
42
|
|
43
|
+
# Try to form a setter from this object.
|
44
|
+
#
|
45
|
+
# @example Try to form a setter.
|
46
|
+
# object.__setter__
|
47
|
+
#
|
48
|
+
# @return [ String ] The object as a string plus =.
|
49
|
+
#
|
50
|
+
# @since 3.1.0
|
51
|
+
def __setter__
|
52
|
+
"#{self}="
|
53
|
+
end
|
54
|
+
|
43
55
|
# Get the value of the object as a mongo friendy sort value.
|
44
56
|
#
|
45
57
|
# @example Get the object as sort criteria.
|
@@ -64,6 +76,18 @@ module Mongoid
|
|
64
76
|
self
|
65
77
|
end
|
66
78
|
|
79
|
+
# Check if the object is part of a blank relation criteria.
|
80
|
+
#
|
81
|
+
# @example Is the object blank criteria?
|
82
|
+
# "".blank_criteria?
|
83
|
+
#
|
84
|
+
# @return [ true, false ] If the object is blank criteria.
|
85
|
+
#
|
86
|
+
# @since 3.1.0
|
87
|
+
def blank_criteria?
|
88
|
+
false
|
89
|
+
end
|
90
|
+
|
67
91
|
# Do or do not, there is no try. -- Yoda.
|
68
92
|
#
|
69
93
|
# @example Do or do not.
|
@@ -81,7 +81,7 @@ module Mongoid
|
|
81
81
|
#
|
82
82
|
# @since 3.0.0
|
83
83
|
def numeric?
|
84
|
-
true if Float(self) rescue
|
84
|
+
true if Float(self) rescue false
|
85
85
|
end
|
86
86
|
|
87
87
|
# Get the string as a getter string.
|
@@ -93,7 +93,7 @@ module Mongoid
|
|
93
93
|
#
|
94
94
|
# @since 1.0.0
|
95
95
|
def reader
|
96
|
-
delete("=")
|
96
|
+
delete("=").sub(/\_before\_type\_cast$/, '')
|
97
97
|
end
|
98
98
|
|
99
99
|
# Convert the string to an array with the string in it.
|
@@ -132,6 +132,18 @@ module Mongoid
|
|
132
132
|
/[@$"]/ !~ to_sym.inspect
|
133
133
|
end
|
134
134
|
|
135
|
+
# Does the string end with _before_type_cast?
|
136
|
+
#
|
137
|
+
# @example Is the string a setter method?
|
138
|
+
# "price_before_type_cast".before_type_cast?
|
139
|
+
#
|
140
|
+
# @return [ true, false ] If the string ends with "_before_type_cast"
|
141
|
+
#
|
142
|
+
# @since 3.1.0
|
143
|
+
def before_type_cast?
|
144
|
+
ends_with?("_before_type_cast")
|
145
|
+
end
|
146
|
+
|
135
147
|
# Is the object not to be converted to bson on criteria creation?
|
136
148
|
#
|
137
149
|
# @example Is the object unconvertable?
|
@@ -3,6 +3,9 @@ module Mongoid
|
|
3
3
|
module Extensions
|
4
4
|
module Time
|
5
5
|
|
6
|
+
# Constant for epoch - used when passing invalid times.
|
7
|
+
EPOCH = ::Time.utc(1970, 1, 1, 0, 0, 0)
|
8
|
+
|
6
9
|
# Turn the object from the ruby type we deal with to a Mongo friendly
|
7
10
|
# type.
|
8
11
|
#
|
@@ -73,7 +76,7 @@ module Mongoid
|
|
73
76
|
::Time.at(time.to_i, time.usec).utc
|
74
77
|
end
|
75
78
|
rescue ArgumentError
|
76
|
-
|
79
|
+
EPOCH
|
77
80
|
end
|
78
81
|
end
|
79
82
|
end
|
data/lib/mongoid/fields.rb
CHANGED
@@ -23,7 +23,6 @@ module Mongoid
|
|
23
23
|
self.pre_processed_defaults = []
|
24
24
|
self.post_processed_defaults = []
|
25
25
|
|
26
|
-
field(:_type, default: ->{ self.class.name if hereditary? }, type: String)
|
27
26
|
field(
|
28
27
|
:_id,
|
29
28
|
default: ->{ Moped::BSON::ObjectId.new },
|
@@ -77,7 +76,7 @@ module Mongoid
|
|
77
76
|
unless attributes.has_key?(name)
|
78
77
|
if field = fields[name]
|
79
78
|
default = field.eval_default(self)
|
80
|
-
unless default.nil?
|
79
|
+
unless default.nil? || field.lazy?
|
81
80
|
attribute_will_change!(name)
|
82
81
|
attributes[name] = default
|
83
82
|
end
|
@@ -126,6 +125,21 @@ module Mongoid
|
|
126
125
|
self.class.database_field_name(name)
|
127
126
|
end
|
128
127
|
|
128
|
+
# Is the provided field a lazy evaluation?
|
129
|
+
#
|
130
|
+
# @example If the field is lazy settable.
|
131
|
+
# doc.lazy_settable?(field, nil)
|
132
|
+
#
|
133
|
+
# @param [ Field ] field The field.
|
134
|
+
# @param [ Object ] value The current value.
|
135
|
+
#
|
136
|
+
# @return [ true, false ] If we set the field lazily.
|
137
|
+
#
|
138
|
+
# @since 3.1.0
|
139
|
+
def lazy_settable?(field, value)
|
140
|
+
!frozen? && value.nil? && field.lazy?
|
141
|
+
end
|
142
|
+
|
129
143
|
# Is the document using object ids?
|
130
144
|
#
|
131
145
|
# @note Refactored from using delegate for class load performance.
|
@@ -336,6 +350,7 @@ module Mongoid
|
|
336
350
|
# person.name #=> returns the field
|
337
351
|
# person.name = "" #=> sets the field
|
338
352
|
# person.name? #=> Is the field present?
|
353
|
+
# person.name_before_type_cast #=> returns the field before type cast
|
339
354
|
#
|
340
355
|
# @param [ Symbol ] name The name of the field.
|
341
356
|
# @param [ Symbol ] meth The name of the accessor.
|
@@ -346,6 +361,7 @@ module Mongoid
|
|
346
361
|
field = fields[name]
|
347
362
|
|
348
363
|
create_field_getter(name, meth, field)
|
364
|
+
create_field_getter_before_type_cast(name, meth)
|
349
365
|
create_field_setter(name, meth, field)
|
350
366
|
create_field_check(name, meth)
|
351
367
|
|
@@ -369,9 +385,37 @@ module Mongoid
|
|
369
385
|
def create_field_getter(name, meth, field)
|
370
386
|
generated_methods.module_eval do
|
371
387
|
re_define_method(meth) do
|
372
|
-
|
373
|
-
|
374
|
-
|
388
|
+
raw = read_attribute(name)
|
389
|
+
if lazy_settable?(field, raw)
|
390
|
+
write_attribute(name, field.eval_default(self))
|
391
|
+
else
|
392
|
+
value = field.demongoize(raw)
|
393
|
+
attribute_will_change!(name) if value.resizable?
|
394
|
+
value
|
395
|
+
end
|
396
|
+
end
|
397
|
+
end
|
398
|
+
end
|
399
|
+
|
400
|
+
# Create the getter_before_type_cast method for the provided field. If
|
401
|
+
# the attribute has been assigned, return the attribute before it was
|
402
|
+
# type cast. Otherwise, delegate to the getter.
|
403
|
+
#
|
404
|
+
# @example Create the getter_before_type_cast.
|
405
|
+
# Model.create_field_getter_before_type_cast("name", "name")
|
406
|
+
#
|
407
|
+
# @param [ String ] name The name of the attribute.
|
408
|
+
# @param [ String ] meth The name of the method.
|
409
|
+
#
|
410
|
+
# @since 3.1.0
|
411
|
+
def create_field_getter_before_type_cast(name, meth)
|
412
|
+
generated_methods.module_eval do
|
413
|
+
re_define_method("#{meth}_before_type_cast") do
|
414
|
+
if has_attribute_before_type_cast?(name)
|
415
|
+
read_attribute_before_type_cast(name)
|
416
|
+
else
|
417
|
+
send meth
|
418
|
+
end
|
375
419
|
end
|
376
420
|
end
|
377
421
|
end
|
@@ -69,6 +69,18 @@ module Mongoid
|
|
69
69
|
end
|
70
70
|
end
|
71
71
|
|
72
|
+
# Does this field do lazy default evaluation?
|
73
|
+
#
|
74
|
+
# @example Is the field lazy?
|
75
|
+
# field.lazy?
|
76
|
+
#
|
77
|
+
# @return [ true, false ] If the field is lazy.
|
78
|
+
#
|
79
|
+
# @since 3.1.0
|
80
|
+
def lazy?
|
81
|
+
type.resizable?
|
82
|
+
end
|
83
|
+
|
72
84
|
# Mongoize the object into the Mongo friendly value.
|
73
85
|
#
|
74
86
|
# @example Mongoize the object.
|
@@ -95,6 +95,18 @@ module Mongoid
|
|
95
95
|
end
|
96
96
|
end
|
97
97
|
|
98
|
+
# Does this field do lazy default evaluation?
|
99
|
+
#
|
100
|
+
# @example Is the field lazy?
|
101
|
+
# field.lazy?
|
102
|
+
#
|
103
|
+
# @return [ true, false ] If the field is lazy.
|
104
|
+
#
|
105
|
+
# @since 3.1.0
|
106
|
+
def lazy?
|
107
|
+
false
|
108
|
+
end
|
109
|
+
|
98
110
|
# Is the field localized or not?
|
99
111
|
#
|
100
112
|
# @example Is the field localized?
|