mongoid 1.1.3 → 1.1.4
Sign up to get free protection for your applications and to get access to all the features.
- data/.watchr +20 -2
- data/VERSION +1 -1
- data/caliper.yml +4 -0
- data/lib/mongoid.rb +0 -1
- data/lib/mongoid/associations.rb +25 -13
- data/lib/mongoid/associations/belongs_to.rb +15 -17
- data/lib/mongoid/associations/belongs_to_related.rb +12 -14
- data/lib/mongoid/associations/has_many.rb +53 -35
- data/lib/mongoid/associations/has_many_related.rb +10 -15
- data/lib/mongoid/associations/has_one.rb +31 -30
- data/lib/mongoid/associations/has_one_related.rb +18 -20
- data/lib/mongoid/associations/options.rb +10 -0
- data/lib/mongoid/associations/proxy.rb +18 -1
- data/lib/mongoid/criteria.rb +9 -233
- data/lib/mongoid/criterion/complex.rb +21 -0
- data/lib/mongoid/criterion/exclusion.rb +63 -0
- data/lib/mongoid/criterion/inclusion.rb +91 -0
- data/lib/mongoid/criterion/optional.rb +96 -0
- data/lib/mongoid/document.rb +2 -2
- data/lib/mongoid/extensions/hash/accessors.rb +6 -0
- data/lib/mongoid/extensions/hash/criteria_helpers.rb +2 -2
- data/lib/mongoid/extensions/symbol/inflections.rb +1 -1
- data/mongoid.gemspec +53 -3
- data/spec/integration/mongoid/associations_spec.rb +41 -0
- data/spec/models/address.rb +39 -0
- data/spec/models/animal.rb +6 -0
- data/spec/models/comment.rb +8 -0
- data/spec/models/country_code.rb +6 -0
- data/spec/models/employer.rb +5 -0
- data/spec/models/game.rb +6 -0
- data/spec/models/inheritance.rb +56 -0
- data/spec/models/location.rb +5 -0
- data/spec/models/mixed_drink.rb +4 -0
- data/spec/models/name.rb +13 -0
- data/spec/models/namespacing.rb +11 -0
- data/spec/models/patient.rb +4 -0
- data/spec/models/person.rb +97 -0
- data/spec/models/pet.rb +7 -0
- data/spec/models/pet_owner.rb +6 -0
- data/spec/models/phone.rb +7 -0
- data/spec/models/post.rb +15 -0
- data/spec/models/translation.rb +5 -0
- data/spec/models/vet_visit.rb +5 -0
- data/spec/spec_helper.rb +9 -326
- data/spec/unit/mongoid/associations/belongs_to_related_spec.rb +26 -5
- data/spec/unit/mongoid/associations/belongs_to_spec.rb +96 -30
- data/spec/unit/mongoid/associations/has_many_related_spec.rb +32 -12
- data/spec/unit/mongoid/associations/has_many_spec.rb +48 -12
- data/spec/unit/mongoid/associations/has_one_related_spec.rb +29 -4
- data/spec/unit/mongoid/associations/has_one_spec.rb +46 -1
- data/spec/unit/mongoid/associations/options_spec.rb +58 -0
- data/spec/unit/mongoid/associations_spec.rb +58 -1
- data/spec/unit/mongoid/criteria_spec.rb +71 -735
- data/spec/unit/mongoid/criterion/complex_spec.rb +19 -0
- data/spec/unit/mongoid/criterion/exclusion_spec.rb +75 -0
- data/spec/unit/mongoid/criterion/inclusion_spec.rb +213 -0
- data/spec/unit/mongoid/criterion/optional_spec.rb +244 -0
- data/spec/unit/mongoid/extensions/hash/accessors_spec.rb +20 -0
- metadata +53 -3
- data/lib/mongoid/complex_criterion.rb +0 -10
data/.watchr
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
# Watchr is the preferred method to run specs automatically over rspactor for
|
2
|
+
# Mongoid. If you are using vim, you can add the file:
|
3
|
+
#
|
4
|
+
# ~/.vim/ftdetect/watchr.vim
|
5
|
+
#
|
6
|
+
# This should have only the following line in it:
|
7
|
+
#
|
8
|
+
# autocmd BufNewFile,BufRead *.watchr setf ruby
|
9
|
+
#
|
10
|
+
# This will enable vim to recognize this file as ruby code should you wish to
|
11
|
+
# edit it.
|
1
12
|
def run(cmd)
|
2
13
|
puts cmd
|
3
14
|
system cmd
|
@@ -7,5 +18,12 @@ def spec(file)
|
|
7
18
|
run "spec -O spec/spec.opts #{file}"
|
8
19
|
end
|
9
20
|
|
10
|
-
watch("spec/.*/*_spec\.rb")
|
11
|
-
|
21
|
+
watch("spec/.*/*_spec\.rb") do |match|
|
22
|
+
p match[0]
|
23
|
+
spec(match[0])
|
24
|
+
end
|
25
|
+
|
26
|
+
watch('lib/(.*/.*)\.rb') do |match|
|
27
|
+
p match[1]
|
28
|
+
spec("spec/unit/#{match[1]}_spec.rb")
|
29
|
+
end
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.1.
|
1
|
+
1.1.4
|
data/caliper.yml
ADDED
data/lib/mongoid.rb
CHANGED
data/lib/mongoid/associations.rb
CHANGED
@@ -59,14 +59,16 @@ module Mongoid # :nodoc:
|
|
59
59
|
# include Mongoid::Document
|
60
60
|
# belongs_to :person, :inverse_of => :addresses
|
61
61
|
# end
|
62
|
-
def belongs_to(name, options = {})
|
62
|
+
def belongs_to(name, options = {}, &block)
|
63
63
|
unless options.has_key?(:inverse_of)
|
64
64
|
raise Errors::InvalidOptions.new("Options for belongs_to association must include :inverse_of")
|
65
65
|
end
|
66
66
|
self.embedded = true
|
67
67
|
add_association(
|
68
68
|
Associations::BelongsTo,
|
69
|
-
Associations::Options.new(
|
69
|
+
Associations::Options.new(
|
70
|
+
options.merge(:name => name, :extend => block)
|
71
|
+
)
|
70
72
|
)
|
71
73
|
end
|
72
74
|
|
@@ -84,11 +86,13 @@ module Mongoid # :nodoc:
|
|
84
86
|
# belongs_to_related :person
|
85
87
|
# end
|
86
88
|
#
|
87
|
-
def belongs_to_related(name, options = {})
|
89
|
+
def belongs_to_related(name, options = {}, &block)
|
88
90
|
field "#{name.to_s}_id"
|
89
91
|
add_association(
|
90
92
|
Associations::BelongsToRelated,
|
91
|
-
Associations::Options.new(
|
93
|
+
Associations::Options.new(
|
94
|
+
options.merge(:name => name, :extend => block)
|
95
|
+
)
|
92
96
|
)
|
93
97
|
end
|
94
98
|
|
@@ -111,10 +115,12 @@ module Mongoid # :nodoc:
|
|
111
115
|
# include Mongoid::Document
|
112
116
|
# belongs_to :person, :inverse_of => :addresses
|
113
117
|
# end
|
114
|
-
def has_many(name, options = {})
|
118
|
+
def has_many(name, options = {}, &block)
|
115
119
|
add_association(
|
116
120
|
Associations::HasMany,
|
117
|
-
Associations::Options.new(
|
121
|
+
Associations::Options.new(
|
122
|
+
options.merge(:name => name, :extend => block)
|
123
|
+
)
|
118
124
|
)
|
119
125
|
end
|
120
126
|
|
@@ -132,10 +138,12 @@ module Mongoid # :nodoc:
|
|
132
138
|
# has_many_related :posts
|
133
139
|
# end
|
134
140
|
#
|
135
|
-
def has_many_related(name, options = {})
|
141
|
+
def has_many_related(name, options = {}, &block)
|
136
142
|
add_association(
|
137
143
|
Associations::HasManyRelated,
|
138
|
-
Associations::Options.new(
|
144
|
+
Associations::Options.new(
|
145
|
+
options.merge(:name => name, :parent_key => self.name.foreign_key, :extend => block)
|
146
|
+
)
|
139
147
|
)
|
140
148
|
before_save do |document|
|
141
149
|
document.update_associations(name)
|
@@ -161,8 +169,10 @@ module Mongoid # :nodoc:
|
|
161
169
|
# include Mongoid::Document
|
162
170
|
# belongs_to :person
|
163
171
|
# end
|
164
|
-
def has_one(name, options = {})
|
165
|
-
opts = Associations::Options.new(
|
172
|
+
def has_one(name, options = {}, &block)
|
173
|
+
opts = Associations::Options.new(
|
174
|
+
options.merge(:name => name, :extend => block)
|
175
|
+
)
|
166
176
|
type = Associations::HasOne
|
167
177
|
add_association(type, opts)
|
168
178
|
add_builder(type, opts)
|
@@ -182,10 +192,12 @@ module Mongoid # :nodoc:
|
|
182
192
|
# include Mongoid::Document
|
183
193
|
# has_one_related :game
|
184
194
|
# end
|
185
|
-
def has_one_related(name, options = {})
|
195
|
+
def has_one_related(name, options = {}, &block)
|
186
196
|
add_association(
|
187
197
|
Associations::HasOneRelated,
|
188
|
-
Associations::Options.new(
|
198
|
+
Associations::Options.new(
|
199
|
+
options.merge(:name => name, :parent_key => self.name.foreign_key, :extend => block)
|
200
|
+
)
|
189
201
|
)
|
190
202
|
before_save do |document|
|
191
203
|
document.update_association(name)
|
@@ -227,7 +239,7 @@ module Mongoid # :nodoc:
|
|
227
239
|
def add_builder(type, options)
|
228
240
|
name = options.name.to_s
|
229
241
|
define_method("build_#{name}") do |attrs|
|
230
|
-
reset(name) { type.new(self, attrs, options) }
|
242
|
+
reset(name) { type.new(self, attrs.stringify_keys, options) }
|
231
243
|
end
|
232
244
|
end
|
233
245
|
|
@@ -4,10 +4,8 @@ module Mongoid #:nodoc:
|
|
4
4
|
class BelongsTo #:nodoc:
|
5
5
|
include Proxy
|
6
6
|
|
7
|
-
attr_reader :document, :options
|
8
|
-
|
9
7
|
# Creates the new association by setting the internal
|
10
|
-
#
|
8
|
+
# target as the passed in Document. This should be the
|
11
9
|
# parent.
|
12
10
|
#
|
13
11
|
# All method calls on this object will then be delegated
|
@@ -15,22 +13,18 @@ module Mongoid #:nodoc:
|
|
15
13
|
#
|
16
14
|
# Options:
|
17
15
|
#
|
18
|
-
#
|
16
|
+
# target: The parent +Document+
|
19
17
|
# options: The association options
|
20
|
-
def initialize(
|
21
|
-
@
|
18
|
+
def initialize(target, options)
|
19
|
+
@target, @options = target, options
|
20
|
+
extends(options)
|
22
21
|
end
|
23
22
|
|
24
23
|
# Returns the parent document. The id param is present for
|
25
24
|
# compatibility with rails, however this could be overwritten
|
26
25
|
# in the future.
|
27
26
|
def find(id)
|
28
|
-
@
|
29
|
-
end
|
30
|
-
|
31
|
-
# Delegate all missing methods over to the parent +Document+.
|
32
|
-
def method_missing(name, *args, &block)
|
33
|
-
@document.send(name, *args, &block)
|
27
|
+
@target
|
34
28
|
end
|
35
29
|
|
36
30
|
class << self
|
@@ -43,8 +37,8 @@ module Mongoid #:nodoc:
|
|
43
37
|
# document: The parent +Document+
|
44
38
|
# options: The association options
|
45
39
|
def instantiate(document, options)
|
46
|
-
|
47
|
-
|
40
|
+
target = document._parent
|
41
|
+
target.nil? ? nil : new(target, options)
|
48
42
|
end
|
49
43
|
|
50
44
|
# Returns the macro used to create the association.
|
@@ -55,10 +49,14 @@ module Mongoid #:nodoc:
|
|
55
49
|
# Perform an update of the relationship of the parent and child. This
|
56
50
|
# is initialized by setting a parent object as the association on the
|
57
51
|
# +Document+. Will properly set a has_one or a has_many.
|
58
|
-
|
59
|
-
|
52
|
+
#
|
53
|
+
# Returns:
|
54
|
+
#
|
55
|
+
# A new +BelongsTo+ association proxy.
|
56
|
+
def update(target, child, options)
|
57
|
+
child.parentize(target, options.inverse_of)
|
60
58
|
child.notify
|
61
|
-
|
59
|
+
instantiate(child, options)
|
62
60
|
end
|
63
61
|
end
|
64
62
|
end
|
@@ -4,8 +4,6 @@ module Mongoid #:nodoc:
|
|
4
4
|
class BelongsToRelated #:nodoc:
|
5
5
|
include Proxy
|
6
6
|
|
7
|
-
attr_reader :document, :options
|
8
|
-
|
9
7
|
# Initializing a related association only requires looking up the object
|
10
8
|
# by its id.
|
11
9
|
#
|
@@ -13,13 +11,10 @@ module Mongoid #:nodoc:
|
|
13
11
|
#
|
14
12
|
# document: The +Document+ that contains the relationship.
|
15
13
|
# options: The association +Options+.
|
16
|
-
def initialize(document, foreign_key, options)
|
17
|
-
@
|
18
|
-
|
19
|
-
|
20
|
-
# Delegate all missing methods over to the +Document+.
|
21
|
-
def method_missing(name, *args)
|
22
|
-
@document.send(name, *args)
|
14
|
+
def initialize(document, foreign_key, options, target = nil)
|
15
|
+
@options = options
|
16
|
+
@target = target || options.klass.find(foreign_key)
|
17
|
+
extends(options)
|
23
18
|
end
|
24
19
|
|
25
20
|
class << self
|
@@ -31,9 +26,9 @@ module Mongoid #:nodoc:
|
|
31
26
|
#
|
32
27
|
# document: The +Document+ that contains the relationship.
|
33
28
|
# options: The association +Options+.
|
34
|
-
def instantiate(document, options)
|
29
|
+
def instantiate(document, options, target = nil)
|
35
30
|
foreign_key = document.send(options.foreign_key)
|
36
|
-
foreign_key.blank? ? nil : new(document, foreign_key, options)
|
31
|
+
foreign_key.blank? ? nil : new(document, foreign_key, options, target)
|
37
32
|
end
|
38
33
|
|
39
34
|
# Returns the macro used to create the association.
|
@@ -53,9 +48,12 @@ module Mongoid #:nodoc:
|
|
53
48
|
# Example:
|
54
49
|
#
|
55
50
|
# <tt>BelongsToRelated.update(game, person, options)</tt>
|
56
|
-
def update(
|
57
|
-
|
58
|
-
|
51
|
+
def update(target, parent, options)
|
52
|
+
if target
|
53
|
+
parent.send("#{options.foreign_key}=", target.id)
|
54
|
+
return instantiate(parent, options, target)
|
55
|
+
end
|
56
|
+
target
|
59
57
|
end
|
60
58
|
end
|
61
59
|
|
@@ -4,44 +4,43 @@ module Mongoid #:nodoc:
|
|
4
4
|
class HasMany
|
5
5
|
include Proxy
|
6
6
|
|
7
|
-
attr_accessor :association_name, :klass
|
7
|
+
attr_accessor :association_name, :klass
|
8
8
|
|
9
9
|
# Appends the object to the +Array+, setting its parent in
|
10
10
|
# the process.
|
11
11
|
def <<(*objects)
|
12
12
|
objects.flatten.each do |object|
|
13
13
|
object.parentize(@parent, @association_name)
|
14
|
-
@
|
14
|
+
@target << object
|
15
15
|
object.notify
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
+
alias :concat :<<
|
20
|
+
alias :push :<<
|
21
|
+
|
19
22
|
# Clears the association, and notifies the parents of the removal.
|
20
23
|
def clear
|
21
|
-
unless @
|
22
|
-
object = @
|
24
|
+
unless @target.empty?
|
25
|
+
object = @target.first
|
23
26
|
object.changed(true)
|
24
27
|
object.notify_observers(object, true)
|
25
|
-
@
|
28
|
+
@target.clear
|
26
29
|
end
|
27
30
|
end
|
28
31
|
|
29
|
-
# Appends the object to the +Array+, setting its parent in
|
30
|
-
# the process.
|
31
|
-
def concat(*objects)
|
32
|
-
self << objects
|
33
|
-
end
|
34
|
-
|
35
32
|
# Builds a new Document and adds it to the association collection. The
|
36
33
|
# document created will be of the same class as the others in the
|
37
34
|
# association, and the attributes will be passed into the constructor.
|
38
35
|
#
|
39
|
-
# Returns
|
36
|
+
# Returns:
|
37
|
+
#
|
38
|
+
# The newly created Document.
|
40
39
|
def build(attrs = {}, type = nil)
|
41
40
|
object = type ? type.instantiate : @klass.instantiate
|
42
41
|
object.parentize(@parent, @association_name)
|
43
42
|
object.write_attributes(attrs)
|
44
|
-
@
|
43
|
+
@target << object
|
45
44
|
object
|
46
45
|
end
|
47
46
|
|
@@ -50,7 +49,9 @@ module Mongoid #:nodoc:
|
|
50
49
|
# association, and the attributes will be passed into the constructor and
|
51
50
|
# the new object will then be saved.
|
52
51
|
#
|
53
|
-
# Returns
|
52
|
+
# Returns:
|
53
|
+
#
|
54
|
+
# Rhe newly created Document.
|
54
55
|
def create(attrs = {}, type = nil)
|
55
56
|
object = build(attrs, type)
|
56
57
|
object.save
|
@@ -58,10 +59,16 @@ module Mongoid #:nodoc:
|
|
58
59
|
end
|
59
60
|
|
60
61
|
# Finds a document in this association.
|
62
|
+
#
|
61
63
|
# If :all is passed, returns all the documents
|
64
|
+
#
|
62
65
|
# If an id is passed, will return the document for that id.
|
66
|
+
#
|
67
|
+
# Returns:
|
68
|
+
#
|
69
|
+
# Array or single Document.
|
63
70
|
def find(param)
|
64
|
-
return @
|
71
|
+
return @target if param == :all
|
65
72
|
return detect { |document| document.id == param }
|
66
73
|
end
|
67
74
|
|
@@ -72,27 +79,29 @@ module Mongoid #:nodoc:
|
|
72
79
|
#
|
73
80
|
# This then delegated all methods to the array class since this is
|
74
81
|
# essentially a proxy to an array itself.
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
82
|
+
#
|
83
|
+
# Options:
|
84
|
+
#
|
85
|
+
# parent: The parent document to the association.
|
86
|
+
# options: The association options.
|
87
|
+
def initialize(parent, options)
|
88
|
+
@parent, @association_name = parent, options.name
|
89
|
+
@klass, @options = options.klass, options
|
90
|
+
initialize_each(parent.raw_attributes[@association_name])
|
91
|
+
extends(options)
|
84
92
|
end
|
85
93
|
|
86
|
-
#
|
87
|
-
#
|
88
|
-
#
|
94
|
+
# If the target array does not respond to the supplied method then try to
|
95
|
+
# find a named scope or criteria on the class and send the call there.
|
96
|
+
#
|
97
|
+
# If the method exists on the array, use the default proxy behavior.
|
89
98
|
def method_missing(name, *args, &block)
|
90
|
-
unless @
|
99
|
+
unless @target.respond_to?(name)
|
91
100
|
criteria = @klass.send(name, *args)
|
92
|
-
criteria.documents = @
|
101
|
+
criteria.documents = @target
|
93
102
|
return criteria
|
94
103
|
end
|
95
|
-
|
104
|
+
super
|
96
105
|
end
|
97
106
|
|
98
107
|
# Used for setting associations via a nested attributes setter from the
|
@@ -101,16 +110,25 @@ module Mongoid #:nodoc:
|
|
101
110
|
# Options:
|
102
111
|
#
|
103
112
|
# attributes: A +Hash+ of integer keys and +Hash+ values.
|
113
|
+
#
|
114
|
+
# Returns:
|
115
|
+
#
|
116
|
+
# The newly build target Document.
|
104
117
|
def nested_build(attributes)
|
105
118
|
attributes.values.each do |attrs|
|
106
119
|
build(attrs)
|
107
120
|
end
|
108
121
|
end
|
109
122
|
|
110
|
-
|
111
|
-
# the
|
112
|
-
def
|
113
|
-
|
123
|
+
protected
|
124
|
+
# Initializes each of the attributes in the hash.
|
125
|
+
def initialize_each(attributes)
|
126
|
+
@target = attributes ? attributes.collect do |attrs|
|
127
|
+
klass = attrs.klass
|
128
|
+
child = klass ? klass.instantiate(attrs) : @klass.instantiate(attrs)
|
129
|
+
child.parentize(@parent, @association_name)
|
130
|
+
child
|
131
|
+
end : []
|
114
132
|
end
|
115
133
|
|
116
134
|
class << self
|
@@ -137,7 +155,7 @@ module Mongoid #:nodoc:
|
|
137
155
|
def update(children, parent, options)
|
138
156
|
parent.remove_attribute(options.name)
|
139
157
|
children.assimilate(parent, options)
|
140
|
-
|
158
|
+
instantiate(parent, options)
|
141
159
|
end
|
142
160
|
end
|
143
161
|
|
@@ -4,14 +4,12 @@ module Mongoid #:nodoc:
|
|
4
4
|
class HasManyRelated #:nodoc:
|
5
5
|
include Proxy
|
6
6
|
|
7
|
-
attr_reader :klass
|
8
|
-
|
9
7
|
# Appends the object to the +Array+, setting its parent in
|
10
8
|
# the process.
|
11
9
|
def <<(*objects)
|
12
10
|
objects.flatten.each do |object|
|
13
11
|
object.send("#{@foreign_key}=", @parent.id)
|
14
|
-
@
|
12
|
+
@target << object
|
15
13
|
object.save unless @parent.new_record?
|
16
14
|
end
|
17
15
|
end
|
@@ -24,7 +22,7 @@ module Mongoid #:nodoc:
|
|
24
22
|
def build(attributes = {})
|
25
23
|
name = @parent.class.to_s.underscore
|
26
24
|
object = @klass.instantiate(attributes.merge(name => @parent))
|
27
|
-
@
|
25
|
+
@target << object
|
28
26
|
object
|
29
27
|
end
|
30
28
|
|
@@ -59,15 +57,11 @@ module Mongoid #:nodoc:
|
|
59
57
|
#
|
60
58
|
# document: The +Document+ that contains the relationship.
|
61
59
|
# options: The association +Options+.
|
62
|
-
def initialize(document, options)
|
60
|
+
def initialize(document, options, target = nil)
|
63
61
|
@parent, @klass = document, options.klass
|
64
62
|
@foreign_key = document.class.to_s.foreign_key
|
65
|
-
@
|
66
|
-
|
67
|
-
|
68
|
-
# Delegate all missing methods over to the documents array.
|
69
|
-
def method_missing(name, *args, &block)
|
70
|
-
@documents.send(name, *args, &block)
|
63
|
+
@target = target || @klass.all(:conditions => { @foreign_key => document.id })
|
64
|
+
extends(options)
|
71
65
|
end
|
72
66
|
|
73
67
|
# Delegates to <<
|
@@ -82,8 +76,8 @@ module Mongoid #:nodoc:
|
|
82
76
|
#
|
83
77
|
# document: The +Document+ that contains the relationship.
|
84
78
|
# options: The association +Options+.
|
85
|
-
def instantiate(document, options)
|
86
|
-
new(document, options)
|
79
|
+
def instantiate(document, options, target = nil)
|
80
|
+
new(document, options, target)
|
87
81
|
end
|
88
82
|
|
89
83
|
# Returns the macro used to create the association.
|
@@ -103,9 +97,10 @@ module Mongoid #:nodoc:
|
|
103
97
|
# Example:
|
104
98
|
#
|
105
99
|
# <tt>RelatesToOne.update(game, person, options)</tt>
|
106
|
-
def update(
|
100
|
+
def update(target, document, options)
|
107
101
|
name = document.class.to_s.underscore
|
108
|
-
|
102
|
+
target.each { |child| child.send("#{name}=", document) }
|
103
|
+
instantiate(document, options, target)
|
109
104
|
end
|
110
105
|
end
|
111
106
|
|