mongoid 1.2.6 → 1.2.7
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/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
|