mongoid 3.0.23 → 3.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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?
|