mongoid 2.2.6 → 2.3.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 +2 -858
- data/Rakefile +2 -5
- data/lib/mongoid.rb +1 -1
- data/lib/mongoid/attributes.rb +68 -18
- data/lib/mongoid/attributes/processing.rb +4 -3
- data/lib/mongoid/callbacks.rb +102 -0
- data/lib/mongoid/collection.rb +1 -1
- data/lib/mongoid/components.rb +2 -1
- data/lib/mongoid/contexts/enumerable.rb +0 -24
- data/lib/mongoid/contexts/mongo.rb +2 -2
- data/lib/mongoid/copyable.rb +3 -1
- data/lib/mongoid/criteria.rb +18 -10
- data/lib/mongoid/criterion/complex.rb +11 -0
- data/lib/mongoid/criterion/inclusion.rb +38 -7
- data/lib/mongoid/criterion/optional.rb +2 -7
- data/lib/mongoid/criterion/selector.rb +1 -0
- data/lib/mongoid/dirty.rb +19 -0
- data/lib/mongoid/document.rb +16 -12
- data/lib/mongoid/extensions/hash/criteria_helpers.rb +1 -1
- data/lib/mongoid/extensions/object/checks.rb +4 -1
- data/lib/mongoid/extensions/object_id/conversions.rb +4 -2
- data/lib/mongoid/extensions/string/inflections.rb +2 -2
- data/lib/mongoid/factory.rb +7 -2
- data/lib/mongoid/fields.rb +4 -10
- data/lib/mongoid/fields/serializable.rb +18 -2
- data/lib/mongoid/fields/serializable/integer.rb +17 -5
- data/lib/mongoid/fields/serializable/localized.rb +41 -0
- data/lib/mongoid/finders.rb +5 -4
- data/lib/mongoid/hierarchy.rb +87 -84
- data/lib/mongoid/identity.rb +4 -2
- data/lib/mongoid/keys.rb +2 -1
- data/lib/mongoid/logger.rb +1 -7
- data/lib/mongoid/matchers/and.rb +30 -0
- data/lib/mongoid/matchers/in.rb +1 -1
- data/lib/mongoid/matchers/nin.rb +1 -1
- data/lib/mongoid/matchers/strategies.rb +6 -4
- data/lib/mongoid/multi_parameter_attributes.rb +3 -2
- data/lib/mongoid/named_scope.rb +3 -13
- data/lib/mongoid/nested_attributes.rb +1 -1
- data/lib/mongoid/paranoia.rb +2 -3
- data/lib/mongoid/persistence.rb +9 -5
- data/lib/mongoid/persistence/atomic/operation.rb +1 -1
- data/lib/mongoid/persistence/deletion.rb +1 -1
- data/lib/mongoid/persistence/insertion.rb +1 -1
- data/lib/mongoid/persistence/modification.rb +1 -1
- data/lib/mongoid/railtie.rb +1 -1
- data/lib/mongoid/railties/database.rake +9 -1
- data/lib/mongoid/relations.rb +1 -0
- data/lib/mongoid/relations/accessors.rb +1 -1
- data/lib/mongoid/relations/builders.rb +6 -4
- data/lib/mongoid/relations/builders/referenced/many.rb +1 -23
- data/lib/mongoid/relations/builders/referenced/one.rb +1 -1
- data/lib/mongoid/relations/cascading.rb +5 -3
- data/lib/mongoid/relations/conversions.rb +35 -0
- data/lib/mongoid/relations/embedded/atomic.rb +3 -3
- data/lib/mongoid/relations/embedded/in.rb +1 -1
- data/lib/mongoid/relations/embedded/many.rb +16 -13
- data/lib/mongoid/relations/embedded/one.rb +3 -3
- data/lib/mongoid/relations/metadata.rb +19 -15
- data/lib/mongoid/relations/proxy.rb +4 -5
- data/lib/mongoid/relations/referenced/in.rb +1 -1
- data/lib/mongoid/relations/referenced/many.rb +12 -31
- data/lib/mongoid/relations/referenced/many_to_many.rb +4 -5
- data/lib/mongoid/relations/referenced/one.rb +6 -8
- data/lib/mongoid/relations/synchronization.rb +3 -5
- data/lib/mongoid/safety.rb +34 -4
- data/lib/mongoid/serialization.rb +20 -6
- data/lib/mongoid/threaded.rb +47 -0
- data/lib/mongoid/timestamps.rb +1 -0
- data/lib/mongoid/timestamps/created.rb +1 -8
- data/lib/mongoid/timestamps/timeless.rb +50 -0
- data/lib/mongoid/timestamps/updated.rb +2 -9
- data/lib/mongoid/validations.rb +0 -2
- data/lib/mongoid/validations/associated.rb +1 -2
- data/lib/mongoid/validations/uniqueness.rb +89 -36
- data/lib/mongoid/version.rb +1 -1
- data/lib/mongoid/versioning.rb +5 -6
- data/lib/rails/generators/mongoid_generator.rb +1 -1
- data/lib/rails/mongoid.rb +14 -5
- metadata +27 -23
data/lib/mongoid/hierarchy.rb
CHANGED
@@ -20,98 +20,101 @@ module Mongoid #:nodoc
|
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
@
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
23
|
+
module InstanceMethods #:nodoc:
|
24
|
+
|
25
|
+
# Get all child +Documents+ to this +Document+, going n levels deep if
|
26
|
+
# necessary. This is used when calling update persistence operations from
|
27
|
+
# the root document, where changes in the entire tree need to be
|
28
|
+
# determined. Note that persistence from the embedded documents will
|
29
|
+
# always be preferred, since they are optimized calls... This operation
|
30
|
+
# can get expensive in domains with large hierarchies.
|
31
|
+
#
|
32
|
+
# @example Get all the document's children.
|
33
|
+
# person._children
|
34
|
+
#
|
35
|
+
# @return [ Array<Document> ] All child documents in the hierarchy.
|
36
|
+
def _children
|
37
|
+
@_children ||=
|
38
|
+
[].tap do |children|
|
39
|
+
relations.each_pair do |name, metadata|
|
40
|
+
if metadata.embedded?
|
41
|
+
child = send(name)
|
42
|
+
child.to_a.each do |doc|
|
43
|
+
children.push(doc)
|
44
|
+
children.concat(doc._children) unless metadata.versioned?
|
45
|
+
end if child
|
46
|
+
end
|
44
47
|
end
|
45
48
|
end
|
46
|
-
|
47
|
-
end
|
49
|
+
end
|
48
50
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
51
|
+
# Determines if the document is a subclass of another document.
|
52
|
+
#
|
53
|
+
# @example Check if the document is a subclass
|
54
|
+
# Square.new.hereditary?
|
55
|
+
#
|
56
|
+
# @return [ true, false ] True if hereditary, false if not.
|
57
|
+
def hereditary?
|
58
|
+
self.class.hereditary?
|
59
|
+
end
|
58
60
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
61
|
+
# Sets up a child/parent association. This is used for newly created
|
62
|
+
# objects so they can be properly added to the graph.
|
63
|
+
#
|
64
|
+
# @example Set the parent document.
|
65
|
+
# document.parentize(parent)
|
66
|
+
#
|
67
|
+
# @param [ Document ] document The parent document.
|
68
|
+
#
|
69
|
+
# @return [ Document ] The parent document.
|
70
|
+
def parentize(document)
|
71
|
+
self._parent = document
|
72
|
+
end
|
71
73
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
74
|
+
# Remove a child document from this parent. If an embeds one then set to
|
75
|
+
# nil, otherwise remove from the embeds many.
|
76
|
+
#
|
77
|
+
# This is called from the +RemoveEmbedded+ persistence command.
|
78
|
+
#
|
79
|
+
# @example Remove the child.
|
80
|
+
# document.remove_child(child)
|
81
|
+
#
|
82
|
+
# @param [ Document ] child The child (embedded) document to remove.
|
83
|
+
#
|
84
|
+
# @since 2.0.0.beta.1
|
85
|
+
def remove_child(child)
|
86
|
+
name = child.metadata.name
|
87
|
+
child.embedded_one? ? remove_ivar(name) : send(name).delete_one(child)
|
88
|
+
end
|
87
89
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
90
|
+
# After children are persisted we can call this to move all their changes
|
91
|
+
# and flag them as persisted in one call.
|
92
|
+
#
|
93
|
+
# @example Reset the children.
|
94
|
+
# document.reset_persisted_children
|
95
|
+
#
|
96
|
+
# @return [ Array<Document> ] The children.
|
97
|
+
#
|
98
|
+
# @since 2.1.0
|
99
|
+
def reset_persisted_children
|
100
|
+
_children.each do |child|
|
101
|
+
child.move_changes
|
102
|
+
child.new_record = false
|
103
|
+
end
|
101
104
|
end
|
102
|
-
end
|
103
105
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
106
|
+
# Return the root document in the object graph. If the current document
|
107
|
+
# is the root object in the graph it will return self.
|
108
|
+
#
|
109
|
+
# @example Get the root document in the hierarchy.
|
110
|
+
# document._root
|
111
|
+
#
|
112
|
+
# @return [ Document ] The root document in the hierarchy.
|
113
|
+
def _root
|
114
|
+
object = self
|
115
|
+
while (object._parent) do object = object._parent; end
|
116
|
+
object || self
|
117
|
+
end
|
115
118
|
end
|
116
119
|
end
|
117
120
|
end
|
data/lib/mongoid/identity.rb
CHANGED
@@ -69,9 +69,11 @@ module Mongoid #:nodoc:
|
|
69
69
|
#
|
70
70
|
# @return [ Array<Object> ] The array of keys.
|
71
71
|
def compose
|
72
|
+
kf = document.key_formatter
|
72
73
|
document.primary_key.collect do |key|
|
73
|
-
document.attributes[key.to_s]
|
74
|
-
|
74
|
+
val = document.attributes[key.to_s]
|
75
|
+
val && kf ? kf.call(val) : val
|
76
|
+
end.compact
|
75
77
|
end
|
76
78
|
|
77
79
|
# Determines if the document stores the type information. This is if it is
|
data/lib/mongoid/keys.rb
CHANGED
@@ -9,7 +9,7 @@ module Mongoid #:nodoc:
|
|
9
9
|
attr_reader :identifier
|
10
10
|
|
11
11
|
included do
|
12
|
-
cattr_accessor :primary_key, :using_object_ids
|
12
|
+
cattr_accessor :primary_key, :using_object_ids, :key_formatter
|
13
13
|
self.using_object_ids = true
|
14
14
|
end
|
15
15
|
|
@@ -122,6 +122,7 @@ module Mongoid #:nodoc:
|
|
122
122
|
# @since 1.0.0
|
123
123
|
def key(*fields)
|
124
124
|
self.primary_key = fields
|
125
|
+
self.key_formatter = block_given? ? Proc.new : nil
|
125
126
|
identity(:type => String)
|
126
127
|
set_callback(:save, :around, :set_composite_key)
|
127
128
|
end
|
data/lib/mongoid/logger.rb
CHANGED
@@ -4,13 +4,7 @@ module Mongoid #:nodoc:
|
|
4
4
|
# The Mongoid logger which wraps some other ruby compliant logger class.
|
5
5
|
class Logger
|
6
6
|
|
7
|
-
delegate
|
8
|
-
:info,
|
9
|
-
:debug,
|
10
|
-
:error,
|
11
|
-
:fatal,
|
12
|
-
:level,
|
13
|
-
:unknown, :to => :logger, :allow_nil => true
|
7
|
+
delegate :info, :debug, :error, :fatal, :unknown, :to => :logger, :allow_nil => true
|
14
8
|
|
15
9
|
# Emit a warning log message.
|
16
10
|
#
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Mongoid #:nodoc:
|
3
|
+
module Matchers #:nodoc:
|
4
|
+
|
5
|
+
# Defines behavior for handling $or expressions in embedded documents.
|
6
|
+
class And < Default
|
7
|
+
|
8
|
+
# Does the supplied query match the attribute?
|
9
|
+
#
|
10
|
+
# @example Does this match?
|
11
|
+
# matcher.matches?("$and" => [ { field => value } ])
|
12
|
+
#
|
13
|
+
# @param [ Array ] conditions The or expression.
|
14
|
+
#
|
15
|
+
# @return [ true, false ] True if matches, false if not.
|
16
|
+
#
|
17
|
+
# @since 2.3.0
|
18
|
+
def matches?(conditions)
|
19
|
+
conditions.each do |condition|
|
20
|
+
condition.keys.each do |k|
|
21
|
+
key = k
|
22
|
+
value = condition[k]
|
23
|
+
return false unless Strategies.matcher(document, key, value).matches?(value)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
true
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/mongoid/matchers/in.rb
CHANGED
data/lib/mongoid/matchers/nin.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
require "mongoid/matchers/default"
|
3
3
|
require "mongoid/matchers/all"
|
4
|
+
require "mongoid/matchers/and"
|
4
5
|
require "mongoid/matchers/exists"
|
5
6
|
require "mongoid/matchers/gt"
|
6
7
|
require "mongoid/matchers/gte"
|
@@ -22,6 +23,7 @@ module Mongoid #:nodoc:
|
|
22
23
|
|
23
24
|
MATCHERS = {
|
24
25
|
"$all" => Matchers::All,
|
26
|
+
"$and" => Matchers::And,
|
25
27
|
"$exists" => Matchers::Exists,
|
26
28
|
"$gt" => Matchers::Gt,
|
27
29
|
"$gte" => Matchers::Gte,
|
@@ -51,10 +53,10 @@ module Mongoid #:nodoc:
|
|
51
53
|
if value.is_a?(Hash)
|
52
54
|
MATCHERS[value.keys.first].new(extract_attribute(document, key))
|
53
55
|
else
|
54
|
-
|
55
|
-
Matchers::Or.new(value, document)
|
56
|
-
|
57
|
-
Default.new(extract_attribute(document, key))
|
56
|
+
case key
|
57
|
+
when "$or" then Matchers::Or.new(value, document)
|
58
|
+
when "$and" then Matchers::And.new(value, document)
|
59
|
+
else Default.new(extract_attribute(document, key))
|
58
60
|
end
|
59
61
|
end
|
60
62
|
end
|
@@ -44,10 +44,11 @@ module Mongoid #:nodoc:
|
|
44
44
|
# person.process(:title => "sir", :age => 40)
|
45
45
|
#
|
46
46
|
# @param [ Hash ] attrs The attributes to set.
|
47
|
+
# @param [ Symbol ] role A role for scoped mass assignment.
|
47
48
|
# @param [ Boolean ] guard_protected_attributes False to skip mass assignment protection.
|
48
49
|
#
|
49
50
|
# @since 2.0.0.rc.7
|
50
|
-
def process(attrs = nil, guard_protected_attributes = true)
|
51
|
+
def process(attrs = nil, role = :default, guard_protected_attributes = true)
|
51
52
|
if attrs
|
52
53
|
errors = []
|
53
54
|
attributes = {}
|
@@ -81,7 +82,7 @@ module Mongoid #:nodoc:
|
|
81
82
|
)
|
82
83
|
end
|
83
84
|
|
84
|
-
super attributes, guard_protected_attributes
|
85
|
+
super attributes, role, guard_protected_attributes
|
85
86
|
else
|
86
87
|
super
|
87
88
|
end
|
data/lib/mongoid/named_scope.rb
CHANGED
@@ -125,20 +125,10 @@ module Mongoid #:nodoc:
|
|
125
125
|
|
126
126
|
protected
|
127
127
|
|
128
|
-
# Warns if overriding another scope or method.
|
129
|
-
#
|
130
|
-
# @example Warn if name exists.
|
131
|
-
# Model.valid_scope_name?("test")
|
132
|
-
#
|
133
|
-
# @param [ String, Symbol ] name The name of the scope.
|
134
128
|
def valid_scope_name?(name)
|
135
|
-
if scopes[name]
|
136
|
-
|
137
|
-
|
138
|
-
"Creating scope :#{name}. " +
|
139
|
-
"Overwriting existing method #{self.name}.#{name}."
|
140
|
-
)
|
141
|
-
end
|
129
|
+
if !scopes[name] && respond_to?(name, true)
|
130
|
+
Mongoid.logger.warn "Creating scope :#{name}. " \
|
131
|
+
"Overwriting existing method #{self.name}.#{name}." if Mongoid.logger
|
142
132
|
end
|
143
133
|
end
|
144
134
|
end
|
@@ -54,7 +54,7 @@ module Mongoid #:nodoc:
|
|
54
54
|
args.each do |name|
|
55
55
|
self.nested_attributes += [ "#{name}_attributes=" ]
|
56
56
|
define_method("#{name}_attributes=") do |attrs|
|
57
|
-
|
57
|
+
_assigning do
|
58
58
|
relation = relations[name.to_s]
|
59
59
|
relation.nested_builder(attrs, options).build(self)
|
60
60
|
end
|
data/lib/mongoid/paranoia.rb
CHANGED
@@ -45,7 +45,6 @@ module Mongoid #:nodoc:
|
|
45
45
|
#
|
46
46
|
# @return [ true ] True.
|
47
47
|
def remove(options = {})
|
48
|
-
return super if embedded? && respond_to?(:version_max) && version_max
|
49
48
|
now = Time.now
|
50
49
|
collection.update({ :_id => id }, { '$set' => { :deleted_at => now } })
|
51
50
|
@attributes["deleted_at"] = now
|
@@ -86,7 +85,7 @@ module Mongoid #:nodoc:
|
|
86
85
|
#
|
87
86
|
# @return [ Criteria ] The paranoid compliant criteria.
|
88
87
|
def criteria(embedded = false, scoped = true)
|
89
|
-
scoped ? super.
|
88
|
+
scoped ? super.merge({ :conditions => { :deleted_at => nil } }) : super
|
90
89
|
end
|
91
90
|
|
92
91
|
# Find deleted documents
|
@@ -98,7 +97,7 @@ module Mongoid #:nodoc:
|
|
98
97
|
#
|
99
98
|
# @return [ Criteria ] The deleted criteria.
|
100
99
|
def deleted
|
101
|
-
where(:deleted_at.
|
100
|
+
where(:deleted_at.ne => nil)
|
102
101
|
end
|
103
102
|
end
|
104
103
|
end
|
data/lib/mongoid/persistence.rb
CHANGED
@@ -163,11 +163,13 @@ module Mongoid #:nodoc:
|
|
163
163
|
# Person.create(:title => "Mr")
|
164
164
|
#
|
165
165
|
# @param [ Hash ] attributes The attributes to create with.
|
166
|
+
# @param [ Hash ] options A mass-assignment protection options. Supports
|
167
|
+
# :as and :without_protection
|
166
168
|
#
|
167
169
|
# @return [ Document ] The newly created document.
|
168
|
-
def create(attributes = {}, &block)
|
170
|
+
def create(attributes = {}, options = {}, &block)
|
169
171
|
creating do
|
170
|
-
new(attributes, &block).tap { |doc| doc.save }
|
172
|
+
new(attributes, options, &block).tap { |doc| doc.save }
|
171
173
|
end
|
172
174
|
end
|
173
175
|
|
@@ -180,11 +182,13 @@ module Mongoid #:nodoc:
|
|
180
182
|
# Person.create!(:title => "Mr")
|
181
183
|
#
|
182
184
|
# @param [ Hash ] attributes The attributes to create with.
|
185
|
+
# @param [ Hash ] options A mass-assignment protection options. Supports
|
186
|
+
# :as and :without_protection
|
183
187
|
#
|
184
188
|
# @return [ Document ] The newly created document.
|
185
|
-
def create!(attributes = {}, &block)
|
189
|
+
def create!(attributes = {}, options = {}, &block)
|
186
190
|
creating do
|
187
|
-
new(attributes, &block).tap do |doc|
|
191
|
+
new(attributes, options, &block).tap do |doc|
|
188
192
|
fail_validate!(doc) if doc.insert.errors.any?
|
189
193
|
fail_callback!(doc, :create!) if doc.new?
|
190
194
|
end
|
@@ -209,7 +213,7 @@ module Mongoid #:nodoc:
|
|
209
213
|
selector.merge!(:_type => name) if hereditary?
|
210
214
|
collection.find(selector).count.tap do
|
211
215
|
collection.remove(selector, Safety.merge_safety_options)
|
212
|
-
Threaded.
|
216
|
+
Threaded.clear_options!
|
213
217
|
end
|
214
218
|
end
|
215
219
|
|