mongoid 1.2.7 → 1.2.8
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/lib/mongoid.rb +2 -1
- data/lib/mongoid/associations.rb +18 -14
- data/lib/mongoid/associations/has_many_related.rb +1 -1
- data/lib/mongoid/associations/meta_data.rb +28 -0
- data/lib/mongoid/associations/options.rb +1 -6
- data/lib/mongoid/attributes.rb +1 -1
- data/lib/mongoid/caching.rb +41 -0
- data/lib/mongoid/collection.rb +1 -0
- data/lib/mongoid/components.rb +1 -0
- data/lib/mongoid/config.rb +2 -0
- data/lib/mongoid/contexts/mongo.rb +8 -13
- data/lib/mongoid/criteria.rb +7 -2
- data/lib/mongoid/criterion/inclusion.rb +1 -0
- data/lib/mongoid/criterion/optional.rb +10 -2
- data/lib/mongoid/finders.rb +5 -23
- data/lib/mongoid/identity.rb +1 -1
- data/lib/mongoid/javascript.rb +21 -0
- data/lib/mongoid/javascript/functions.yml +37 -0
- data/mongoid.gemspec +12 -2
- data/spec/integration/mongoid/attributes_spec.rb +2 -2
- data/spec/integration/mongoid/commands_spec.rb +5 -3
- data/spec/integration/mongoid/criteria_spec.rb +27 -0
- data/spec/models/game.rb +2 -1
- data/spec/models/post.rb +1 -1
- data/spec/unit/mongoid/associations/has_many_related_spec.rb +5 -1
- data/spec/unit/mongoid/associations/meta_data_spec.rb +88 -0
- data/spec/unit/mongoid/associations/options_spec.rb +20 -19
- data/spec/unit/mongoid/associations_spec.rb +41 -7
- data/spec/unit/mongoid/caching_spec.rb +63 -0
- data/spec/unit/mongoid/collection_spec.rb +20 -4
- data/spec/unit/mongoid/config_spec.rb +7 -0
- data/spec/unit/mongoid/contexts/mongo_spec.rb +51 -12
- data/spec/unit/mongoid/criteria_spec.rb +23 -1
- data/spec/unit/mongoid/criterion/inclusion_spec.rb +8 -0
- data/spec/unit/mongoid/criterion/optional_spec.rb +0 -10
- data/spec/unit/mongoid/identity_spec.rb +24 -3
- data/spec/unit/mongoid/javascript_spec.rb +48 -0
- metadata +12 -2
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.2.
|
1
|
+
1.2.8
|
data/lib/mongoid.rb
CHANGED
@@ -38,8 +38,8 @@ require "active_support/time_with_zone"
|
|
38
38
|
require "will_paginate/collection"
|
39
39
|
require "mongo"
|
40
40
|
require "mongoid/associations"
|
41
|
-
require "mongoid/associations/options"
|
42
41
|
require "mongoid/attributes"
|
42
|
+
require "mongoid/caching"
|
43
43
|
require "mongoid/callbacks"
|
44
44
|
require "mongoid/collection"
|
45
45
|
require "mongoid/commands"
|
@@ -56,6 +56,7 @@ require "mongoid/fields"
|
|
56
56
|
require "mongoid/finders"
|
57
57
|
require "mongoid/identity"
|
58
58
|
require "mongoid/indexes"
|
59
|
+
require "mongoid/javascript"
|
59
60
|
require "mongoid/matchers"
|
60
61
|
require "mongoid/memoization"
|
61
62
|
require "mongoid/named_scope"
|
data/lib/mongoid/associations.rb
CHANGED
@@ -6,6 +6,8 @@ require "mongoid/associations/has_many"
|
|
6
6
|
require "mongoid/associations/has_many_related"
|
7
7
|
require "mongoid/associations/has_one"
|
8
8
|
require "mongoid/associations/has_one_related"
|
9
|
+
require "mongoid/associations/options"
|
10
|
+
require "mongoid/associations/meta_data"
|
9
11
|
|
10
12
|
module Mongoid # :nodoc:
|
11
13
|
module Associations #:nodoc:
|
@@ -28,13 +30,13 @@ module Mongoid # :nodoc:
|
|
28
30
|
|
29
31
|
# Updates all the one-to-many relational associations for the name.
|
30
32
|
def update_associations(name)
|
31
|
-
send(name).each { |doc| doc.save }
|
33
|
+
send(name).each { |doc| doc.save } if new_record?
|
32
34
|
end
|
33
35
|
|
34
36
|
# Update the one-to-one relational association for the name.
|
35
37
|
def update_association(name)
|
36
38
|
association = send(name)
|
37
|
-
association.save
|
39
|
+
association.save if new_record? && !association.nil?
|
38
40
|
end
|
39
41
|
end
|
40
42
|
|
@@ -87,14 +89,12 @@ module Mongoid # :nodoc:
|
|
87
89
|
# end
|
88
90
|
#
|
89
91
|
def belongs_to_related(name, options = {}, &block)
|
90
|
-
|
91
|
-
|
92
|
-
add_association(
|
93
|
-
Associations::BelongsToRelated,
|
94
|
-
Associations::Options.new(
|
95
|
-
options.merge(:name => name, :extend => block)
|
92
|
+
opts = Associations::Options.new(
|
93
|
+
options.merge(:name => name, :extend => block, :foreign_key => foreign_key(name, options))
|
96
94
|
)
|
97
|
-
)
|
95
|
+
add_association(Associations::BelongsToRelated, opts)
|
96
|
+
field opts.foreign_key
|
97
|
+
index opts.foreign_key unless self.embedded
|
98
98
|
end
|
99
99
|
|
100
100
|
# Adds the association from a parent document to its children. The name
|
@@ -140,10 +140,9 @@ module Mongoid # :nodoc:
|
|
140
140
|
# end
|
141
141
|
#
|
142
142
|
def has_many_related(name, options = {}, &block)
|
143
|
-
add_association(
|
144
|
-
Associations::HasManyRelated,
|
143
|
+
add_association(Associations::HasManyRelated,
|
145
144
|
Associations::Options.new(
|
146
|
-
options.merge(:name => name, :
|
145
|
+
options.merge(:name => name, :foreign_key => foreign_key(self.name, options), :extend => block)
|
147
146
|
)
|
148
147
|
)
|
149
148
|
before_save do |document|
|
@@ -197,7 +196,7 @@ module Mongoid # :nodoc:
|
|
197
196
|
add_association(
|
198
197
|
Associations::HasOneRelated,
|
199
198
|
Associations::Options.new(
|
200
|
-
options.merge(:name => name, :
|
199
|
+
options.merge(:name => name, :foreign_key => foreign_key(name, options), :extend => block)
|
201
200
|
)
|
202
201
|
)
|
203
202
|
before_save do |document|
|
@@ -226,7 +225,7 @@ module Mongoid # :nodoc:
|
|
226
225
|
# getters for the associations will perform the necessary memoization.
|
227
226
|
def add_association(type, options)
|
228
227
|
name = options.name.to_s
|
229
|
-
associations[name] = type
|
228
|
+
associations[name] = MetaData.new(type, options)
|
230
229
|
define_method(name) do
|
231
230
|
memoized(name) { type.instantiate(self, options) }
|
232
231
|
end
|
@@ -253,6 +252,11 @@ module Mongoid # :nodoc:
|
|
253
252
|
document.save; document
|
254
253
|
end
|
255
254
|
end
|
255
|
+
|
256
|
+
# Find the foreign key.
|
257
|
+
def foreign_key(name, options)
|
258
|
+
options[:foreign_key] || name.to_s.foreign_key
|
259
|
+
end
|
256
260
|
end
|
257
261
|
end
|
258
262
|
end
|
@@ -59,7 +59,7 @@ module Mongoid #:nodoc:
|
|
59
59
|
# options: The association +Options+.
|
60
60
|
def initialize(document, options, target = nil)
|
61
61
|
@parent, @klass = document, options.klass
|
62
|
-
@foreign_key =
|
62
|
+
@foreign_key = options.foreign_key
|
63
63
|
@target = target || @klass.all(:conditions => { @foreign_key => document.id })
|
64
64
|
extends(options)
|
65
65
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Mongoid #:nodoc:
|
3
|
+
module Associations #:nodoc:
|
4
|
+
class MetaData #:nodoc:
|
5
|
+
|
6
|
+
attr_reader :association, :options
|
7
|
+
|
8
|
+
delegate :macro, :to => :association
|
9
|
+
|
10
|
+
# Delegate all methods on +Options+ to the options instance.
|
11
|
+
Associations::Options.public_instance_methods(false).each do |name|
|
12
|
+
define_method(name) { |*args| @options.send(name) }
|
13
|
+
end
|
14
|
+
|
15
|
+
# Create the new associations MetaData object, which holds the type of
|
16
|
+
# the association and its options, with convenience methods for getting
|
17
|
+
# that information.
|
18
|
+
#
|
19
|
+
# Options:
|
20
|
+
#
|
21
|
+
# association: The association type as a class instance.
|
22
|
+
# options: The association options
|
23
|
+
def initialize(association, options)
|
24
|
+
@association, @options = association, options
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -21,7 +21,7 @@ module Mongoid #:nodoc:
|
|
21
21
|
|
22
22
|
# Return the foreign key based off the association name.
|
23
23
|
def foreign_key
|
24
|
-
name.to_s.foreign_key
|
24
|
+
@attributes[:foreign_key] || klass.name.to_s.foreign_key
|
25
25
|
end
|
26
26
|
|
27
27
|
# Returns the name of the inverse_of association
|
@@ -42,11 +42,6 @@ module Mongoid #:nodoc:
|
|
42
42
|
@attributes[:name].to_s
|
43
43
|
end
|
44
44
|
|
45
|
-
# Returns the parent foreign key association name.
|
46
|
-
def parent_key
|
47
|
-
@attributes[:parent_key]
|
48
|
-
end
|
49
|
-
|
50
45
|
# Returns whether or not this association is polymorphic.
|
51
46
|
def polymorphic
|
52
47
|
@attributes[:polymorphic] == true
|
data/lib/mongoid/attributes.rb
CHANGED
@@ -0,0 +1,41 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Mongoid #:nodoc:
|
3
|
+
module Caching #:nodoc:
|
4
|
+
def self.included(base)
|
5
|
+
base.class_eval do
|
6
|
+
extend ClassMethods
|
7
|
+
class_inheritable_accessor :cached
|
8
|
+
self.cached = false
|
9
|
+
|
10
|
+
delegate :cached?, :to => "self.class"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
module ClassMethods #:nodoc
|
15
|
+
# Sets caching on for this class. This class level configuration will
|
16
|
+
# default all queries to cache the results of the first iteration over
|
17
|
+
# the cursor into an internal array. This should only be used for queries
|
18
|
+
# that return a small number of results or have small documents, as after
|
19
|
+
# the first iteration the entire results will be stored in memory.
|
20
|
+
#
|
21
|
+
# Example:
|
22
|
+
#
|
23
|
+
# class Person
|
24
|
+
# include Mongoid::Document
|
25
|
+
# cache
|
26
|
+
# end
|
27
|
+
def cache
|
28
|
+
self.cached = true
|
29
|
+
end
|
30
|
+
|
31
|
+
# Determines if the class is cached or not.
|
32
|
+
#
|
33
|
+
# Returns:
|
34
|
+
#
|
35
|
+
# True if cached, false if not.
|
36
|
+
def cached?
|
37
|
+
self.cached == true
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/mongoid/collection.rb
CHANGED
data/lib/mongoid/components.rb
CHANGED
data/lib/mongoid/config.rb
CHANGED
@@ -8,6 +8,7 @@ module Mongoid #:nodoc
|
|
8
8
|
:reconnect_time,
|
9
9
|
:parameterize_keys,
|
10
10
|
:persist_in_safe_mode,
|
11
|
+
:persist_types,
|
11
12
|
:raise_not_found_error,
|
12
13
|
:use_object_ids
|
13
14
|
|
@@ -16,6 +17,7 @@ module Mongoid #:nodoc
|
|
16
17
|
@allow_dynamic_fields = true
|
17
18
|
@parameterize_keys = true
|
18
19
|
@persist_in_safe_mode = true
|
20
|
+
@persist_types = true
|
19
21
|
@raise_not_found_error = true
|
20
22
|
@reconnect_time = 3
|
21
23
|
@use_object_ids = false
|
@@ -7,7 +7,6 @@ module Mongoid #:nodoc:
|
|
7
7
|
|
8
8
|
delegate :klass, :options, :selector, :to => :criteria
|
9
9
|
|
10
|
-
AGGREGATE_REDUCE = "function(obj, prev) { prev.count++; }"
|
11
10
|
# Aggregate the context. This will take the internally built selector and options
|
12
11
|
# and pass them on to the Ruby driver's +group()+ method on the collection. The
|
13
12
|
# collection itself will be retrieved from the class provided, and once the
|
@@ -21,7 +20,7 @@ module Mongoid #:nodoc:
|
|
21
20
|
#
|
22
21
|
# A +Hash+ with field values as keys, counts as values
|
23
22
|
def aggregate
|
24
|
-
klass.collection.group(options[:fields], selector, { :count => 0 },
|
23
|
+
klass.collection.group(options[:fields], selector, { :count => 0 }, Javascript.aggregate, true)
|
25
24
|
end
|
26
25
|
|
27
26
|
# Get the count of matching documents in the database for the context.
|
@@ -59,7 +58,6 @@ module Mongoid #:nodoc:
|
|
59
58
|
end
|
60
59
|
end
|
61
60
|
|
62
|
-
GROUP_REDUCE = "function(obj, prev) { prev.group.push(obj); }"
|
63
61
|
# Groups the context. This will take the internally built selector and options
|
64
62
|
# and pass them on to the Ruby driver's +group()+ method on the collection. The
|
65
63
|
# collection itself will be retrieved from the class provided, and once the
|
@@ -77,7 +75,7 @@ module Mongoid #:nodoc:
|
|
77
75
|
options[:fields],
|
78
76
|
selector,
|
79
77
|
{ :group => [] },
|
80
|
-
|
78
|
+
Javascript.group,
|
81
79
|
true
|
82
80
|
).collect do |docs|
|
83
81
|
docs["group"] = docs["group"].collect do |attrs|
|
@@ -95,9 +93,11 @@ module Mongoid #:nodoc:
|
|
95
93
|
# <tt>Mongoid::Contexts::Mongo.new(criteria)</tt>
|
96
94
|
def initialize(criteria)
|
97
95
|
@criteria = criteria
|
98
|
-
if
|
96
|
+
if klass.hereditary && Mongoid.persist_types
|
99
97
|
criteria.in(:_type => criteria.klass._types)
|
100
98
|
end
|
99
|
+
criteria.enslave if klass.enslaved?
|
100
|
+
criteria.cache if klass.cached?
|
101
101
|
end
|
102
102
|
|
103
103
|
# Return the last result for the +Context+. Essentially does a find_one on
|
@@ -120,8 +120,6 @@ module Mongoid #:nodoc:
|
|
120
120
|
attributes ? Mongoid::Factory.build(klass, attributes) : nil
|
121
121
|
end
|
122
122
|
|
123
|
-
MAX_REDUCE = "function(obj, prev) { if (prev.max == 'start') { prev.max = obj.[field]; } " +
|
124
|
-
"if (prev.max < obj.[field]) { prev.max = obj.[field]; } }"
|
125
123
|
# Return the max value for a field.
|
126
124
|
#
|
127
125
|
# This will take the internally built selector and options
|
@@ -137,11 +135,9 @@ module Mongoid #:nodoc:
|
|
137
135
|
#
|
138
136
|
# A numeric max value.
|
139
137
|
def max(field)
|
140
|
-
grouped(:max, field.to_s,
|
138
|
+
grouped(:max, field.to_s, Javascript.max)
|
141
139
|
end
|
142
140
|
|
143
|
-
MIN_REDUCE = "function(obj, prev) { if (prev.min == 'start') { prev.min = obj.[field]; } " +
|
144
|
-
"if (prev.min > obj.[field]) { prev.min = obj.[field]; } }"
|
145
141
|
# Return the min value for a field.
|
146
142
|
#
|
147
143
|
# This will take the internally built selector and options
|
@@ -157,7 +153,7 @@ module Mongoid #:nodoc:
|
|
157
153
|
#
|
158
154
|
# A numeric minimum value.
|
159
155
|
def min(field)
|
160
|
-
grouped(:min, field.to_s,
|
156
|
+
grouped(:min, field.to_s, Javascript.min)
|
161
157
|
end
|
162
158
|
|
163
159
|
# Return the first result for the +Context+.
|
@@ -176,7 +172,6 @@ module Mongoid #:nodoc:
|
|
176
172
|
|
177
173
|
alias :first :one
|
178
174
|
|
179
|
-
SUM_REDUCE = "function(obj, prev) { if (prev.sum == 'start') { prev.sum = 0; } prev.sum += obj.[field]; }"
|
180
175
|
# Sum the context.
|
181
176
|
#
|
182
177
|
# This will take the internally built selector and options
|
@@ -192,7 +187,7 @@ module Mongoid #:nodoc:
|
|
192
187
|
#
|
193
188
|
# A numeric value that is the sum.
|
194
189
|
def sum(field)
|
195
|
-
grouped(:sum, field.to_s,
|
190
|
+
grouped(:sum, field.to_s, Javascript.sum)
|
196
191
|
end
|
197
192
|
|
198
193
|
# Common functionality for grouping operations. Currently used by min, max
|
data/lib/mongoid/criteria.rb
CHANGED
@@ -165,7 +165,7 @@ module Mongoid #:nodoc:
|
|
165
165
|
# Returns: <tt>Criteria</tt>
|
166
166
|
def method_missing(name, *args)
|
167
167
|
if @klass.respond_to?(name)
|
168
|
-
new_scope = @klass.send(name)
|
168
|
+
new_scope = @klass.send(name, *args)
|
169
169
|
new_scope.merge(self)
|
170
170
|
return new_scope
|
171
171
|
else
|
@@ -203,7 +203,12 @@ module Mongoid #:nodoc:
|
|
203
203
|
unless params.is_a?(Hash)
|
204
204
|
return new(klass).id_criteria(params)
|
205
205
|
end
|
206
|
-
|
206
|
+
conditions = params.delete(:conditions) || {}
|
207
|
+
if conditions.include?(:id)
|
208
|
+
conditions[:_id] = conditions[:id]
|
209
|
+
conditions.delete(:id)
|
210
|
+
end
|
211
|
+
return new(klass).where(conditions).extras(params)
|
207
212
|
end
|
208
213
|
|
209
214
|
protected
|
@@ -61,6 +61,7 @@ module Mongoid #:nodoc:
|
|
61
61
|
def in(attributes = {})
|
62
62
|
update_selector(attributes, "$in")
|
63
63
|
end
|
64
|
+
alias any_in in
|
64
65
|
|
65
66
|
# Adds a criterion to the +Criteria+ that specifies values that must
|
66
67
|
# be matched in order to return results. This is similar to a SQL "WHERE"
|
@@ -20,8 +20,7 @@ module Mongoid #:nodoc:
|
|
20
20
|
#
|
21
21
|
# <tt>criteria.cached?</tt>
|
22
22
|
def cached?
|
23
|
-
@
|
24
|
-
@cached == true
|
23
|
+
@options[:cache] == true
|
25
24
|
end
|
26
25
|
|
27
26
|
# Flags the criteria to execute against a read-only slave in the pool
|
@@ -34,6 +33,15 @@ module Mongoid #:nodoc:
|
|
34
33
|
@options.merge!(:enslave => true); self
|
35
34
|
end
|
36
35
|
|
36
|
+
# Will return true if the criteria is enslaved.
|
37
|
+
#
|
38
|
+
# Example:
|
39
|
+
#
|
40
|
+
# <tt>criteria.enslaved?</tt>
|
41
|
+
def enslaved?
|
42
|
+
@options[:enslave] == true
|
43
|
+
end
|
44
|
+
|
37
45
|
# Adds a criterion to the +Criteria+ that specifies additional options
|
38
46
|
# to be passed to the Ruby driver, in the exact format for the driver.
|
39
47
|
#
|
data/lib/mongoid/finders.rb
CHANGED
@@ -112,27 +112,9 @@ module Mongoid #:nodoc:
|
|
112
112
|
#
|
113
113
|
# Returns: <tt>Float</tt> max value.
|
114
114
|
def max(field)
|
115
|
-
|
115
|
+
criteria.max(field)
|
116
116
|
end
|
117
117
|
|
118
|
-
# Will execute a +Criteria+ based on the +DynamicFinder+ that gets
|
119
|
-
# generated.
|
120
|
-
#
|
121
|
-
# Options:
|
122
|
-
#
|
123
|
-
# name: The finder method name
|
124
|
-
# args: The arguments to pass to the method.
|
125
|
-
#
|
126
|
-
# Example:
|
127
|
-
#
|
128
|
-
# <tt>Person.find_all_by_title_and_age("Sir", 30)</tt>
|
129
|
-
# def method_missing(name, *args)
|
130
|
-
# dyna = DynamicFinder.new(name, *args)
|
131
|
-
# finder, conditions = dyna.finder, dyna.conditions
|
132
|
-
# results = find(finder, :conditions => conditions)
|
133
|
-
# results ? results : dyna.create(self)
|
134
|
-
# end
|
135
|
-
|
136
118
|
# Convenience method for returning the min value of a field.
|
137
119
|
#
|
138
120
|
# Options:
|
@@ -145,7 +127,7 @@ module Mongoid #:nodoc:
|
|
145
127
|
#
|
146
128
|
# Returns: <tt>Float</tt> min value.
|
147
129
|
def min(field)
|
148
|
-
|
130
|
+
criteria.min(field)
|
149
131
|
end
|
150
132
|
|
151
133
|
# Find all documents in paginated fashion given the supplied arguments.
|
@@ -179,7 +161,7 @@ module Mongoid #:nodoc:
|
|
179
161
|
#
|
180
162
|
# Returns: <tt>Criteria</tt>
|
181
163
|
def only(*args)
|
182
|
-
|
164
|
+
criteria.only(*args)
|
183
165
|
end
|
184
166
|
|
185
167
|
# Convenience method for returning the sum of a specified field for all
|
@@ -195,7 +177,7 @@ module Mongoid #:nodoc:
|
|
195
177
|
#
|
196
178
|
# Returns: <tt>Float</tt> of the sum.
|
197
179
|
def sum(field)
|
198
|
-
|
180
|
+
criteria.sum(field)
|
199
181
|
end
|
200
182
|
|
201
183
|
# Entry point for creating a new criteria from a Document. This will
|
@@ -212,7 +194,7 @@ module Mongoid #:nodoc:
|
|
212
194
|
#
|
213
195
|
# Returns: <tt>Criteria</tt>
|
214
196
|
def where(selector = nil)
|
215
|
-
|
197
|
+
criteria.where(selector)
|
216
198
|
end
|
217
199
|
|
218
200
|
protected
|