mongoid 1.2.6 → 1.2.7
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 +1 -0
- data/lib/mongoid/associations.rb +1 -1
- data/lib/mongoid/attributes.rb +1 -0
- data/lib/mongoid/collection.rb +1 -1
- data/lib/mongoid/commands.rb +1 -1
- data/lib/mongoid/commands/delete_all.rb +2 -1
- data/lib/mongoid/commands/destroy_all.rb +1 -1
- data/lib/mongoid/components.rb +1 -0
- data/lib/mongoid/config.rb +3 -1
- data/lib/mongoid/contexts.rb +21 -0
- data/lib/mongoid/contexts/enumerable.rb +15 -12
- data/lib/mongoid/contexts/ids.rb +25 -0
- data/lib/mongoid/contexts/mongo.rb +25 -23
- data/lib/mongoid/contexts/paging.rb +2 -2
- data/lib/mongoid/criteria.rb +5 -43
- data/lib/mongoid/document.rb +1 -0
- data/lib/mongoid/enslavement.rb +38 -0
- data/lib/mongoid/fields.rb +5 -2
- data/lib/mongoid/identity.rb +7 -1
- data/lib/mongoid/named_scope.rb +2 -0
- data/mongoid.gemspec +8 -2
- data/spec/integration/mongoid/commands_spec.rb +2 -2
- data/spec/integration/mongoid/contexts/enumerable_spec.rb +13 -0
- data/spec/integration/mongoid/criteria_spec.rb +2 -2
- data/spec/integration/mongoid/document_spec.rb +5 -1
- data/spec/integration/mongoid/finders_spec.rb +85 -28
- data/spec/models/person.rb +1 -0
- data/spec/unit/mongoid/associations_spec.rb +12 -0
- data/spec/unit/mongoid/attributes_spec.rb +60 -51
- data/spec/unit/mongoid/collection_spec.rb +30 -0
- data/spec/unit/mongoid/commands/delete_all_spec.rb +3 -3
- data/spec/unit/mongoid/commands_spec.rb +16 -0
- data/spec/unit/mongoid/config_spec.rb +7 -0
- data/spec/unit/mongoid/contexts/enumerable_spec.rb +151 -11
- data/spec/unit/mongoid/contexts/mongo_spec.rb +168 -42
- data/spec/unit/mongoid/contexts_spec.rb +25 -0
- data/spec/unit/mongoid/criteria_spec.rb +49 -75
- data/spec/unit/mongoid/criterion/exclusion_spec.rb +3 -13
- data/spec/unit/mongoid/criterion/inclusion_spec.rb +17 -19
- data/spec/unit/mongoid/criterion/optional_spec.rb +25 -8
- data/spec/unit/mongoid/document_spec.rb +4 -0
- data/spec/unit/mongoid/enslavement_spec.rb +63 -0
- data/spec/unit/mongoid/extensions/array/conversions_spec.rb +2 -2
- data/spec/unit/mongoid/extensions/object/conversions_spec.rb +2 -2
- data/spec/unit/mongoid/extensions/proc/scoping_spec.rb +1 -1
- data/spec/unit/mongoid/fields_spec.rb +10 -0
- data/spec/unit/mongoid/finders_spec.rb +1 -1
- data/spec/unit/mongoid/identity_spec.rb +23 -3
- data/spec/unit/mongoid/named_scope_spec.rb +15 -2
- data/spec/unit/mongoid/scope_spec.rb +1 -1
- metadata +8 -2
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.2.
|
1
|
+
1.2.7
|
data/lib/mongoid.rb
CHANGED
data/lib/mongoid/associations.rb
CHANGED
@@ -240,7 +240,7 @@ module Mongoid # :nodoc:
|
|
240
240
|
def add_builder(type, options)
|
241
241
|
name = options.name.to_s
|
242
242
|
define_method("build_#{name}") do |attrs|
|
243
|
-
reset(name) { type.new(self, attrs.stringify_keys, options) }
|
243
|
+
reset(name) { type.new(self, (attrs || {}).stringify_keys, options) }
|
244
244
|
end
|
245
245
|
end
|
246
246
|
|
data/lib/mongoid/attributes.rb
CHANGED
data/lib/mongoid/collection.rb
CHANGED
data/lib/mongoid/commands.rb
CHANGED
@@ -14,8 +14,9 @@ module Mongoid #:nodoc:
|
|
14
14
|
#
|
15
15
|
# <tt>DeleteAll.execute(Person, :conditions => { :field => "value" })</tt>
|
16
16
|
def self.execute(klass, params = {})
|
17
|
+
safe = Mongoid.persist_in_safe_mode
|
17
18
|
collection = klass.collection
|
18
|
-
collection.remove((params[:conditions] || {}).merge(:_type => klass.name))
|
19
|
+
collection.remove((params[:conditions] || {}).merge(:_type => klass.name), :safe => safe)
|
19
20
|
end
|
20
21
|
end
|
21
22
|
end
|
@@ -16,7 +16,7 @@ module Mongoid #:nodoc:
|
|
16
16
|
def self.execute(klass, params)
|
17
17
|
conditions = params[:conditions] || {}
|
18
18
|
params[:conditions] = conditions.merge(:_type => klass.name)
|
19
|
-
klass.find(:all, params).each { |doc| Destroy.execute(doc) }
|
19
|
+
klass.find(:all, params).each { |doc| Destroy.execute(doc) }; true
|
20
20
|
end
|
21
21
|
end
|
22
22
|
end
|
data/lib/mongoid/components.rb
CHANGED
data/lib/mongoid/config.rb
CHANGED
@@ -8,7 +8,8 @@ module Mongoid #:nodoc
|
|
8
8
|
:reconnect_time,
|
9
9
|
:parameterize_keys,
|
10
10
|
:persist_in_safe_mode,
|
11
|
-
:raise_not_found_error
|
11
|
+
:raise_not_found_error,
|
12
|
+
:use_object_ids
|
12
13
|
|
13
14
|
# Defaults the configuration options to true.
|
14
15
|
def initialize
|
@@ -17,6 +18,7 @@ module Mongoid #:nodoc
|
|
17
18
|
@persist_in_safe_mode = true
|
18
19
|
@raise_not_found_error = true
|
19
20
|
@reconnect_time = 3
|
21
|
+
@use_object_ids = false
|
20
22
|
end
|
21
23
|
|
22
24
|
# Sets the Mongo::DB master database to be used. If the object trying to me
|
data/lib/mongoid/contexts.rb
CHANGED
@@ -1,4 +1,25 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
+
require "mongoid/contexts/ids"
|
2
3
|
require "mongoid/contexts/paging"
|
3
4
|
require "mongoid/contexts/enumerable"
|
4
5
|
require "mongoid/contexts/mongo"
|
6
|
+
|
7
|
+
module Mongoid
|
8
|
+
module Contexts
|
9
|
+
# Determines the context to be used for this criteria. If the class is an
|
10
|
+
# embedded document, then the context will be the array in the has_many
|
11
|
+
# association it is in. If the class is a root, then the database itself
|
12
|
+
# will be the context.
|
13
|
+
#
|
14
|
+
# Example:
|
15
|
+
#
|
16
|
+
# <tt>Contexts.context_for(criteria)</tt>
|
17
|
+
def self.context_for(criteria)
|
18
|
+
if criteria.klass.embedded
|
19
|
+
return Contexts::Enumerable.new(criteria)
|
20
|
+
end
|
21
|
+
Contexts::Mongo.new(criteria)
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
@@ -2,10 +2,11 @@
|
|
2
2
|
module Mongoid #:nodoc:
|
3
3
|
module Contexts #:nodoc:
|
4
4
|
class Enumerable
|
5
|
-
include Paging
|
6
|
-
attr_reader :
|
5
|
+
include Ids, Paging
|
6
|
+
attr_reader :criteria
|
7
7
|
|
8
8
|
delegate :first, :last, :to => :execute
|
9
|
+
delegate :documents, :options, :selector, :to => :criteria
|
9
10
|
|
10
11
|
# Return aggregation counts of the grouped documents. This will count by
|
11
12
|
# the first field provided in the fields array.
|
@@ -21,7 +22,7 @@ module Mongoid #:nodoc:
|
|
21
22
|
|
22
23
|
# Gets the number of documents in the array. Delegates to size.
|
23
24
|
def count
|
24
|
-
@count ||=
|
25
|
+
@count ||= documents.size
|
25
26
|
end
|
26
27
|
|
27
28
|
# Groups the documents by the first field supplied in the field options.
|
@@ -30,8 +31,8 @@ module Mongoid #:nodoc:
|
|
30
31
|
#
|
31
32
|
# A +Hash+ with field values as keys, arrays of documents as values.
|
32
33
|
def group
|
33
|
-
field =
|
34
|
-
|
34
|
+
field = options[:fields].first
|
35
|
+
documents.group_by { |doc| doc.send(field) }
|
35
36
|
end
|
36
37
|
|
37
38
|
# Enumerable implementation of execute. Returns matching documents for
|
@@ -41,7 +42,7 @@ module Mongoid #:nodoc:
|
|
41
42
|
#
|
42
43
|
# An +Array+ of documents that matched the selector.
|
43
44
|
def execute(paginating = false)
|
44
|
-
limit(
|
45
|
+
limit(documents.select { |document| document.matches?(selector) })
|
45
46
|
end
|
46
47
|
|
47
48
|
# Create the new enumerable context. This will need the selector and
|
@@ -50,9 +51,9 @@ module Mongoid #:nodoc:
|
|
50
51
|
#
|
51
52
|
# Example:
|
52
53
|
#
|
53
|
-
# <tt>Mongoid::Contexts::Enumerable.new(
|
54
|
-
def initialize(
|
55
|
-
@
|
54
|
+
# <tt>Mongoid::Contexts::Enumerable.new(criteria)</tt>
|
55
|
+
def initialize(criteria)
|
56
|
+
@criteria = criteria
|
56
57
|
end
|
57
58
|
|
58
59
|
# Get the largest value for the field in all the documents.
|
@@ -86,7 +87,7 @@ module Mongoid #:nodoc:
|
|
86
87
|
#
|
87
88
|
# The numerical sum of all the document field values.
|
88
89
|
def sum(field)
|
89
|
-
sum =
|
90
|
+
sum = documents.inject(nil) do |memo, doc|
|
90
91
|
value = doc.send(field)
|
91
92
|
memo ? memo += value : value
|
92
93
|
end
|
@@ -95,7 +96,7 @@ module Mongoid #:nodoc:
|
|
95
96
|
protected
|
96
97
|
# If the field exists, perform the comparison and set if true.
|
97
98
|
def determine(field, operator)
|
98
|
-
matching =
|
99
|
+
matching = documents.inject(nil) do |memo, doc|
|
99
100
|
value = doc.send(field)
|
100
101
|
(memo && memo.send(operator, value)) ? memo : value
|
101
102
|
end
|
@@ -103,9 +104,11 @@ module Mongoid #:nodoc:
|
|
103
104
|
|
104
105
|
# Limits the result set if skip and limit options.
|
105
106
|
def limit(documents)
|
106
|
-
skip, limit =
|
107
|
+
skip, limit = options[:skip], options[:limit]
|
107
108
|
if skip && limit
|
108
109
|
return documents.slice(skip, limit)
|
110
|
+
elsif limit
|
111
|
+
return documents.first(limit)
|
109
112
|
end
|
110
113
|
documents
|
111
114
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Mongoid #:nodoc:
|
3
|
+
module Contexts #:nodoc:
|
4
|
+
module Ids
|
5
|
+
# Return documents based on an id search. Will handle if a single id has
|
6
|
+
# been passed or mulitple ids.
|
7
|
+
#
|
8
|
+
# Example:
|
9
|
+
#
|
10
|
+
# context.id_criteria([1, 2, 3])
|
11
|
+
#
|
12
|
+
# Returns:
|
13
|
+
#
|
14
|
+
# The single or multiple documents.
|
15
|
+
def id_criteria(params)
|
16
|
+
criteria.id(params)
|
17
|
+
result = params.is_a?(Array) ? criteria.entries : one
|
18
|
+
if Mongoid.raise_not_found_error
|
19
|
+
raise Errors::DocumentNotFound.new(klass, params) if result.blank?
|
20
|
+
end
|
21
|
+
return result
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -2,8 +2,10 @@
|
|
2
2
|
module Mongoid #:nodoc:
|
3
3
|
module Contexts #:nodoc:
|
4
4
|
class Mongo
|
5
|
-
include Paging
|
6
|
-
attr_reader :
|
5
|
+
include Ids, Paging
|
6
|
+
attr_reader :criteria
|
7
|
+
|
8
|
+
delegate :klass, :options, :selector, :to => :criteria
|
7
9
|
|
8
10
|
AGGREGATE_REDUCE = "function(obj, prev) { prev.count++; }"
|
9
11
|
# Aggregate the context. This will take the internally built selector and options
|
@@ -19,7 +21,7 @@ module Mongoid #:nodoc:
|
|
19
21
|
#
|
20
22
|
# A +Hash+ with field values as keys, counts as values
|
21
23
|
def aggregate
|
22
|
-
|
24
|
+
klass.collection.group(options[:fields], selector, { :count => 0 }, AGGREGATE_REDUCE, true)
|
23
25
|
end
|
24
26
|
|
25
27
|
# Get the count of matching documents in the database for the context.
|
@@ -32,7 +34,7 @@ module Mongoid #:nodoc:
|
|
32
34
|
#
|
33
35
|
# An +Integer+ count of documents.
|
34
36
|
def count
|
35
|
-
@count ||=
|
37
|
+
@count ||= klass.collection.find(selector, process_options).count
|
36
38
|
end
|
37
39
|
|
38
40
|
# Execute the context. This will take the selector and options
|
@@ -48,7 +50,7 @@ module Mongoid #:nodoc:
|
|
48
50
|
#
|
49
51
|
# An enumerable +Cursor+.
|
50
52
|
def execute(paginating = false)
|
51
|
-
cursor =
|
53
|
+
cursor = klass.collection.find(selector, process_options)
|
52
54
|
if cursor
|
53
55
|
@count = cursor.count if paginating
|
54
56
|
cursor
|
@@ -71,15 +73,15 @@ module Mongoid #:nodoc:
|
|
71
73
|
#
|
72
74
|
# A +Hash+ with field values as keys, arrays of documents as values.
|
73
75
|
def group
|
74
|
-
|
75
|
-
|
76
|
-
|
76
|
+
klass.collection.group(
|
77
|
+
options[:fields],
|
78
|
+
selector,
|
77
79
|
{ :group => [] },
|
78
80
|
GROUP_REDUCE,
|
79
81
|
true
|
80
82
|
).collect do |docs|
|
81
83
|
docs["group"] = docs["group"].collect do |attrs|
|
82
|
-
Mongoid::Factory.build(
|
84
|
+
Mongoid::Factory.build(klass, attrs)
|
83
85
|
end
|
84
86
|
docs
|
85
87
|
end
|
@@ -90,11 +92,11 @@ module Mongoid #:nodoc:
|
|
90
92
|
#
|
91
93
|
# Example:
|
92
94
|
#
|
93
|
-
# <tt>Mongoid::Contexts::Mongo.new(
|
94
|
-
def initialize(
|
95
|
-
@
|
96
|
-
if klass.hereditary
|
97
|
-
|
95
|
+
# <tt>Mongoid::Contexts::Mongo.new(criteria)</tt>
|
96
|
+
def initialize(criteria)
|
97
|
+
@criteria = criteria
|
98
|
+
if criteria.klass.hereditary
|
99
|
+
criteria.in(:_type => criteria.klass._types)
|
98
100
|
end
|
99
101
|
end
|
100
102
|
|
@@ -114,8 +116,8 @@ module Mongoid #:nodoc:
|
|
114
116
|
sorting = opts[:sort]
|
115
117
|
sorting = [[:_id, :asc]] unless sorting
|
116
118
|
opts[:sort] = sorting.collect { |option| [ option[0], option[1].invert ] }
|
117
|
-
attributes =
|
118
|
-
attributes ? Mongoid::Factory.build(
|
119
|
+
attributes = klass.collection.find_one(selector, opts)
|
120
|
+
attributes ? Mongoid::Factory.build(klass, attributes) : nil
|
119
121
|
end
|
120
122
|
|
121
123
|
MAX_REDUCE = "function(obj, prev) { if (prev.max == 'start') { prev.max = obj.[field]; } " +
|
@@ -168,8 +170,8 @@ module Mongoid #:nodoc:
|
|
168
170
|
#
|
169
171
|
# The first document in the collection.
|
170
172
|
def one
|
171
|
-
attributes =
|
172
|
-
attributes ? Mongoid::Factory.build(
|
173
|
+
attributes = klass.collection.find_one(selector, process_options)
|
174
|
+
attributes ? Mongoid::Factory.build(klass, attributes) : nil
|
173
175
|
end
|
174
176
|
|
175
177
|
alias :first :one
|
@@ -196,9 +198,9 @@ module Mongoid #:nodoc:
|
|
196
198
|
# Common functionality for grouping operations. Currently used by min, max
|
197
199
|
# and sum. Will gsub the field name in the supplied reduce function.
|
198
200
|
def grouped(start, field, reduce)
|
199
|
-
collection =
|
201
|
+
collection = klass.collection.group(
|
200
202
|
nil,
|
201
|
-
|
203
|
+
selector,
|
202
204
|
{ start => "start" },
|
203
205
|
reduce.gsub("[field]", field),
|
204
206
|
true
|
@@ -209,12 +211,12 @@ module Mongoid #:nodoc:
|
|
209
211
|
# Filters the field list. If no fields have been supplied, then it will be
|
210
212
|
# empty. If fields have been defined then _type will be included as well.
|
211
213
|
def process_options
|
212
|
-
fields =
|
214
|
+
fields = options[:fields]
|
213
215
|
if fields && fields.size > 0 && !fields.include?(:_type)
|
214
216
|
fields << :_type
|
215
|
-
|
217
|
+
options[:fields] = fields
|
216
218
|
end
|
217
|
-
|
219
|
+
options.dup
|
218
220
|
end
|
219
221
|
|
220
222
|
end
|
@@ -25,7 +25,7 @@ module Mongoid #:nodoc:
|
|
25
25
|
#
|
26
26
|
# An +Integer+ page number.
|
27
27
|
def page
|
28
|
-
skips, limits =
|
28
|
+
skips, limits = options[:skip], options[:limit]
|
29
29
|
(skips && limits) ? (skips + limits) / limits : 1
|
30
30
|
end
|
31
31
|
|
@@ -35,7 +35,7 @@ module Mongoid #:nodoc:
|
|
35
35
|
#
|
36
36
|
# The +Integer+ number of documents in each page.
|
37
37
|
def per_page
|
38
|
-
(
|
38
|
+
(options[:limit] || 20).to_i
|
39
39
|
end
|
40
40
|
end
|
41
41
|
end
|
data/lib/mongoid/criteria.rb
CHANGED
@@ -35,6 +35,7 @@ module Mongoid #:nodoc:
|
|
35
35
|
:execute,
|
36
36
|
:first,
|
37
37
|
:group,
|
38
|
+
:id_criteria,
|
38
39
|
:last,
|
39
40
|
:max,
|
40
41
|
:min,
|
@@ -91,7 +92,7 @@ module Mongoid #:nodoc:
|
|
91
92
|
# This will return an Enumerable context if the class is embedded,
|
92
93
|
# otherwise it will return a Mongo context for root classes.
|
93
94
|
def context
|
94
|
-
@context ||=
|
95
|
+
@context ||= Contexts.context_for(self)
|
95
96
|
end
|
96
97
|
|
97
98
|
# Iterate over each +Document+ in the results. This can take an optional
|
@@ -101,7 +102,7 @@ module Mongoid #:nodoc:
|
|
101
102
|
#
|
102
103
|
# <tt>criteria.each { |doc| p doc }</tt>
|
103
104
|
def each(&block)
|
104
|
-
return
|
105
|
+
return caching(&block) if cached?
|
105
106
|
if block_given?
|
106
107
|
execute.each { |doc| yield doc }
|
107
108
|
end
|
@@ -134,10 +135,6 @@ module Mongoid #:nodoc:
|
|
134
135
|
# klass: The class to execute on.
|
135
136
|
def initialize(klass)
|
136
137
|
@selector, @options, @klass, @documents = {}, {}, klass, []
|
137
|
-
if klass.hereditary
|
138
|
-
@selector = { :_type => { "$in" => klass._types } }
|
139
|
-
@hereditary = true
|
140
|
-
end
|
141
138
|
end
|
142
139
|
|
143
140
|
# Merges another object into this +Criteria+. The other object may be a
|
@@ -204,29 +201,15 @@ module Mongoid #:nodoc:
|
|
204
201
|
klass = args[0]
|
205
202
|
params = args[1] || {}
|
206
203
|
unless params.is_a?(Hash)
|
207
|
-
return id_criteria(
|
204
|
+
return new(klass).id_criteria(params)
|
208
205
|
end
|
209
206
|
return new(klass).where(params.delete(:conditions) || {}).extras(params)
|
210
207
|
end
|
211
208
|
|
212
209
|
protected
|
213
|
-
# Determines the context to be used for this criteria. If the class is an
|
214
|
-
# embedded document, then thw context will be the array in the has_many
|
215
|
-
# association it is in. If the class is a root, then the database itself
|
216
|
-
# will be the context.
|
217
|
-
#
|
218
|
-
# Example:
|
219
|
-
#
|
220
|
-
# <tt>criteria#determine_context</tt>
|
221
|
-
def determine_context
|
222
|
-
if @klass.embedded
|
223
|
-
return Contexts::Enumerable.new(@selector, @options, @documents)
|
224
|
-
end
|
225
|
-
Contexts::Mongo.new(@selector, @options, @klass)
|
226
|
-
end
|
227
210
|
|
228
211
|
# Iterate over each +Document+ in the results and cache the collection.
|
229
|
-
def
|
212
|
+
def caching(&block)
|
230
213
|
@collection ||= execute
|
231
214
|
if block_given?
|
232
215
|
docs = []
|
@@ -272,26 +255,5 @@ module Mongoid #:nodoc:
|
|
272
255
|
def update_selector(attributes, operator)
|
273
256
|
attributes.each { |key, value| @selector[key] = { operator => value } }; self
|
274
257
|
end
|
275
|
-
|
276
|
-
class << self
|
277
|
-
# Create a criteria or single document based on an id search. Will handle
|
278
|
-
# if a single id has been passed or mulitple ids.
|
279
|
-
#
|
280
|
-
# Example:
|
281
|
-
#
|
282
|
-
# Criteria.id_criteria(Person, [1, 2, 3])
|
283
|
-
#
|
284
|
-
# Returns:
|
285
|
-
#
|
286
|
-
# The single or multiple documents.
|
287
|
-
def id_criteria(klass, params)
|
288
|
-
criteria = new(klass).id(params)
|
289
|
-
result = params.is_a?(String) ? criteria.one : criteria.entries
|
290
|
-
if Mongoid.raise_not_found_error
|
291
|
-
raise Errors::DocumentNotFound.new(klass, params) if result.blank?
|
292
|
-
end
|
293
|
-
return result
|
294
|
-
end
|
295
|
-
end
|
296
258
|
end
|
297
259
|
end
|