mongoid 2.0.0.beta.15 → 2.0.0.beta.16
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/lib/config/locales/en.yml +40 -0
- data/lib/config/locales/es.yml +41 -0
- data/lib/config/locales/fr.yml +42 -0
- data/lib/config/locales/it.yml +39 -0
- data/lib/config/locales/pl.yml +39 -0
- data/lib/config/locales/pt.yml +40 -0
- data/lib/config/locales/sv.yml +40 -0
- data/lib/mongoid.rb +7 -2
- data/lib/mongoid/associations.rb +16 -9
- data/lib/mongoid/associations/embedded_in.rb +11 -0
- data/lib/mongoid/associations/embeds_many.rb +28 -2
- data/lib/mongoid/associations/embeds_one.rb +18 -2
- data/lib/mongoid/associations/proxy.rb +28 -1
- data/lib/mongoid/associations/referenced_in.rb +10 -0
- data/lib/mongoid/associations/references_many.rb +10 -7
- data/lib/mongoid/associations/references_many_as_array.rb +29 -0
- data/lib/mongoid/associations/references_one.rb +9 -1
- data/lib/mongoid/attributes.rb +13 -3
- data/lib/mongoid/callbacks.rb +1 -0
- data/lib/mongoid/collections.rb +1 -1
- data/lib/mongoid/components.rb +1 -0
- data/lib/mongoid/config.rb +16 -1
- data/lib/mongoid/contexts/enumerable.rb +28 -1
- data/lib/mongoid/contexts/enumerable/sort.rb +43 -0
- data/lib/mongoid/contexts/mongo.rb +13 -1
- data/lib/mongoid/criteria.rb +4 -2
- data/lib/mongoid/criterion/inclusion.rb +22 -1
- data/lib/mongoid/criterion/optional.rb +14 -39
- data/lib/mongoid/criterion/selector.rb +65 -0
- data/lib/mongoid/document.rb +5 -11
- data/lib/mongoid/errors.rb +10 -130
- data/lib/mongoid/errors/document_not_found.rb +29 -0
- data/lib/mongoid/errors/invalid_collection.rb +19 -0
- data/lib/mongoid/errors/invalid_database.rb +20 -0
- data/lib/mongoid/errors/invalid_field.rb +19 -0
- data/lib/mongoid/errors/invalid_options.rb +16 -0
- data/lib/mongoid/errors/invalid_type.rb +26 -0
- data/lib/mongoid/errors/mongoid_error.rb +27 -0
- data/lib/mongoid/errors/too_many_nested_attribute_records.rb +21 -0
- data/lib/mongoid/errors/unsupported_version.rb +21 -0
- data/lib/mongoid/errors/validations.rb +22 -0
- data/lib/mongoid/extensions/hash/assimilation.rb +1 -1
- data/lib/mongoid/extensions/hash/criteria_helpers.rb +5 -3
- data/lib/mongoid/extensions/object/conversions.rb +5 -1
- data/lib/mongoid/extensions/objectid/conversions.rb +43 -1
- data/lib/mongoid/field.rb +13 -6
- data/lib/mongoid/finders.rb +1 -1
- data/lib/mongoid/hierarchy.rb +9 -4
- data/lib/mongoid/identity.rb +2 -2
- data/lib/mongoid/indexes.rb +1 -1
- data/lib/mongoid/matchers/default.rb +1 -1
- data/lib/mongoid/modifiers.rb +24 -0
- data/lib/mongoid/modifiers/command.rb +18 -0
- data/lib/mongoid/modifiers/inc.rb +24 -0
- data/lib/mongoid/persistence/command.rb +2 -10
- data/lib/mongoid/persistence/remove_all.rb +1 -1
- data/lib/mongoid/railtie.rb +2 -0
- data/lib/mongoid/railties/database.rake +102 -11
- data/lib/mongoid/railties/document.rb +12 -0
- data/lib/mongoid/safe.rb +13 -0
- data/lib/mongoid/safety.rb +12 -0
- data/lib/mongoid/validations.rb +0 -4
- data/lib/mongoid/version.rb +1 -1
- data/lib/mongoid/versioning.rb +11 -1
- metadata +55 -28
- data/lib/mongoid/validations/locale/en.yml +0 -5
@@ -58,9 +58,14 @@ module Mongoid #:nodoc:
|
|
58
58
|
#
|
59
59
|
# A new target document.
|
60
60
|
def nested_build(attributes, options = nil)
|
61
|
-
|
61
|
+
options ||= {}
|
62
|
+
_destroy = Boolean.set(attributes.delete('_destroy'))
|
63
|
+
if options[:allow_destroy] && _destroy
|
64
|
+
@target = nil
|
65
|
+
elsif @target.present? || !options[:update_only]
|
62
66
|
@target.write_attributes(attributes)
|
63
|
-
end
|
67
|
+
end
|
68
|
+
target
|
64
69
|
end
|
65
70
|
|
66
71
|
class << self
|
@@ -89,6 +94,17 @@ module Mongoid #:nodoc:
|
|
89
94
|
child.assimilate(parent, options)
|
90
95
|
new(parent, options, child.is_a?(Hash) ? nil : child)
|
91
96
|
end
|
97
|
+
|
98
|
+
# Validate the options passed to the embeds one macro, to encapsulate
|
99
|
+
# the behavior in this class instead of the associations module.
|
100
|
+
#
|
101
|
+
# Options:
|
102
|
+
#
|
103
|
+
# options: Thank you captain obvious.
|
104
|
+
def validate_options(options = {})
|
105
|
+
check_dependent_not_allowed!(options)
|
106
|
+
check_inverse_not_allowed!(options)
|
107
|
+
end
|
92
108
|
end
|
93
109
|
end
|
94
110
|
end
|
@@ -3,7 +3,7 @@ module Mongoid #:nodoc
|
|
3
3
|
module Associations #:nodoc
|
4
4
|
class Proxy #:nodoc
|
5
5
|
instance_methods.each do |method|
|
6
|
-
undef_method(method) unless method =~ /(^__|^
|
6
|
+
undef_method(method) unless method =~ /(^__|^send$|^object_id$|^extend$)/
|
7
7
|
end
|
8
8
|
attr_reader \
|
9
9
|
:options,
|
@@ -28,6 +28,33 @@ module Mongoid #:nodoc
|
|
28
28
|
@foreign_key = options.foreign_key
|
29
29
|
extends(options)
|
30
30
|
end
|
31
|
+
|
32
|
+
protected
|
33
|
+
class << self
|
34
|
+
def check_dependent_not_allowed!(options)
|
35
|
+
if options.has_key?(:dependent)
|
36
|
+
raise Errors::InvalidOptions.new(
|
37
|
+
"dependent_only_references_one_or_many", {}
|
38
|
+
)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def check_inverse_not_allowed!(options)
|
43
|
+
if options.has_key?(:inverse_of)
|
44
|
+
raise Errors::InvalidOptions.new(
|
45
|
+
"association_cant_have_inverse_of", {}
|
46
|
+
)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def check_inverse_must_be_defined!(options)
|
51
|
+
unless options.has_key?(:inverse_of)
|
52
|
+
raise Errors::InvalidOptions.new(
|
53
|
+
"embedded_in_must_have_inverse_of", {}
|
54
|
+
)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
31
58
|
end
|
32
59
|
end
|
33
60
|
end
|
@@ -54,6 +54,16 @@ module Mongoid #:nodoc:
|
|
54
54
|
document.send("#{options.foreign_key}=", target ? target.id : nil)
|
55
55
|
new(document, options, target)
|
56
56
|
end
|
57
|
+
|
58
|
+
# Validate the options passed to the referenced in macro, to encapsulate
|
59
|
+
# the behavior in this class instead of the associations module.
|
60
|
+
#
|
61
|
+
# Options:
|
62
|
+
#
|
63
|
+
# options: Thank you captain obvious.
|
64
|
+
def validate_options(options = {})
|
65
|
+
check_dependent_not_allowed!(options)
|
66
|
+
end
|
57
67
|
end
|
58
68
|
end
|
59
69
|
end
|
@@ -227,19 +227,22 @@ module Mongoid #:nodoc:
|
|
227
227
|
protected
|
228
228
|
def determine_name(document, options)
|
229
229
|
target = document.class
|
230
|
-
|
231
230
|
if (inverse = options.inverse_of) && inverse.is_a?(Array)
|
232
231
|
inverse = [*inverse].detect { |name| target.respond_to?(name) }
|
233
232
|
end
|
234
|
-
|
235
233
|
if !inverse
|
236
|
-
association = options
|
237
|
-
|
238
|
-
|
239
|
-
inverse = association.name if association
|
234
|
+
association = detect_association(target, options, false)
|
235
|
+
association = detect_association(target, options, true) if association.blank?
|
236
|
+
inferred = association.name if association
|
240
237
|
end
|
238
|
+
inverse || inferred || target.to_s.underscore
|
239
|
+
end
|
241
240
|
|
242
|
-
|
241
|
+
def detect_association(target, options, with_class_name = false)
|
242
|
+
association = options.klass.associations.values.detect do |metadata|
|
243
|
+
metadata.options.klass == target &&
|
244
|
+
(with_class_name ? true : metadata.options[:class_name].nil?)
|
245
|
+
end
|
243
246
|
end
|
244
247
|
end
|
245
248
|
end
|
@@ -34,6 +34,7 @@ module Mongoid #:nodoc:
|
|
34
34
|
@target << object
|
35
35
|
object.save unless @parent.new_record?
|
36
36
|
end
|
37
|
+
@parent.save unless @parent.new_record?
|
37
38
|
end
|
38
39
|
|
39
40
|
alias :concat :<<
|
@@ -50,6 +51,34 @@ module Mongoid #:nodoc:
|
|
50
51
|
push(document); document
|
51
52
|
end
|
52
53
|
|
54
|
+
# Destroy all the associated objects.
|
55
|
+
#
|
56
|
+
# Example:
|
57
|
+
#
|
58
|
+
# <tt>person.posts.destroy_all</tt>
|
59
|
+
#
|
60
|
+
# Returns:
|
61
|
+
#
|
62
|
+
# The number of objects destroyed.
|
63
|
+
def destroy_all(conditions = {})
|
64
|
+
removed = query.call.destroy_all(:conditions => conditions)
|
65
|
+
reset; removed
|
66
|
+
end
|
67
|
+
|
68
|
+
# Delete all the associated objects.
|
69
|
+
#
|
70
|
+
# Example:
|
71
|
+
#
|
72
|
+
# <tt>person.posts.delete_all</tt>
|
73
|
+
#
|
74
|
+
# Returns:
|
75
|
+
#
|
76
|
+
# The number of objects deleted.
|
77
|
+
def delete_all(conditions = {})
|
78
|
+
removed = query.call.delete_all(:conditions => conditions)
|
79
|
+
reset; removed
|
80
|
+
end
|
81
|
+
|
53
82
|
protected
|
54
83
|
|
55
84
|
# Find the inverse key for the supplied document.
|
@@ -61,7 +61,15 @@ module Mongoid #:nodoc:
|
|
61
61
|
#
|
62
62
|
# A new target document.
|
63
63
|
def nested_build(attributes, options = nil)
|
64
|
-
|
64
|
+
options ||= {}
|
65
|
+
_destroy = Boolean.set(attributes.delete('_destroy'))
|
66
|
+
if options[:allow_destroy] && _destroy
|
67
|
+
@target.destroy
|
68
|
+
@target = nil
|
69
|
+
elsif @target.present? || !options[:update_only]
|
70
|
+
build(attributes)
|
71
|
+
end
|
72
|
+
@target
|
65
73
|
end
|
66
74
|
|
67
75
|
class << self
|
data/lib/mongoid/attributes.rb
CHANGED
@@ -29,6 +29,11 @@ module Mongoid #:nodoc:
|
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
|
+
# Override respond_to? so it responds properly for dynamic attributes
|
33
|
+
def respond_to?(sym)
|
34
|
+
(Mongoid.allow_dynamic_fields && @attributes && @attributes.has_key?(sym.to_s)) || super
|
35
|
+
end
|
36
|
+
|
32
37
|
# Process the provided attributes casting them to their proper values if a
|
33
38
|
# field exists for them on the +Document+. This will be limited to only the
|
34
39
|
# attributes provided in the suppied +Hash+ so that no extra nil values get
|
@@ -123,8 +128,7 @@ module Mongoid #:nodoc:
|
|
123
128
|
# there is any.
|
124
129
|
def write_attribute(name, value)
|
125
130
|
access = name.to_s
|
126
|
-
|
127
|
-
modify(access, @attributes[access], typed_value)
|
131
|
+
modify(access, @attributes[access], typed_value_for(access, value))
|
128
132
|
notify if !id.blank? && new_record?
|
129
133
|
end
|
130
134
|
|
@@ -152,11 +156,17 @@ module Mongoid #:nodoc:
|
|
152
156
|
alias :attributes= :write_attributes
|
153
157
|
|
154
158
|
protected
|
159
|
+
|
160
|
+
# Return the typecast value for a field.
|
161
|
+
def typed_value_for(key, value)
|
162
|
+
fields.has_key?(key) ? fields[key].set(value) : value
|
163
|
+
end
|
164
|
+
|
155
165
|
# apply default values to attributes - calling procs as required
|
156
166
|
def default_attributes
|
157
167
|
default_values = defaults
|
158
168
|
default_values.each_pair do |key, val|
|
159
|
-
default_values[key] = val.call if val.respond_to?(:call)
|
169
|
+
default_values[key] = typed_value_for(key, val.call) if val.respond_to?(:call)
|
160
170
|
end
|
161
171
|
default_values || {}
|
162
172
|
end
|
data/lib/mongoid/callbacks.rb
CHANGED
data/lib/mongoid/collections.rb
CHANGED
data/lib/mongoid/components.rb
CHANGED
data/lib/mongoid/config.rb
CHANGED
@@ -169,6 +169,21 @@ module Mongoid #:nodoc
|
|
169
169
|
end
|
170
170
|
end
|
171
171
|
|
172
|
+
# Adds a new I18n locale file to the load path
|
173
|
+
#
|
174
|
+
# Example:
|
175
|
+
#
|
176
|
+
# Add portuguese locale
|
177
|
+
# <tt>Mongoid::config.add_language('pt')</tt>
|
178
|
+
#
|
179
|
+
# Adds all available languages
|
180
|
+
# <tt>Mongoid::Config.add_language('*')</tt>
|
181
|
+
def add_language(language_code = nil)
|
182
|
+
Dir[File.join(File.dirname(__FILE__), "..", "config", "locales", "#{language_code}.yml")].each do |file|
|
183
|
+
I18n.load_path << File.expand_path(file)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
172
187
|
# Convenience method for connecting to the master database after forking a
|
173
188
|
# new process.
|
174
189
|
#
|
@@ -177,7 +192,7 @@ module Mongoid #:nodoc
|
|
177
192
|
# <tt>Mongoid.reconnect!</tt>
|
178
193
|
def reconnect!(now = true)
|
179
194
|
if now
|
180
|
-
master.connection.
|
195
|
+
master.connection.connect
|
181
196
|
else
|
182
197
|
# We set a @reconnect flag so that #master knows to reconnect the next
|
183
198
|
# time the connection is accessed.
|
@@ -1,4 +1,7 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'mongoid/contexts/enumerable/sort'
|
4
|
+
|
2
5
|
module Mongoid #:nodoc:
|
3
6
|
module Contexts #:nodoc:
|
4
7
|
class Enumerable
|
@@ -56,7 +59,7 @@ module Mongoid #:nodoc:
|
|
56
59
|
#
|
57
60
|
# An +Array+ of documents that matched the selector.
|
58
61
|
def execute(paginating = false)
|
59
|
-
limit(filter) || []
|
62
|
+
limit(sort(filter)) || []
|
60
63
|
end
|
61
64
|
|
62
65
|
# Groups the documents by the first field supplied in the field options.
|
@@ -115,6 +118,18 @@ module Mongoid #:nodoc:
|
|
115
118
|
# The first document in the +Array+
|
116
119
|
alias :one :first
|
117
120
|
|
121
|
+
# Get one document and tell the criteria to skip this record on
|
122
|
+
# successive calls.
|
123
|
+
#
|
124
|
+
# Returns:
|
125
|
+
#
|
126
|
+
# The first document in the +Array+
|
127
|
+
def shift
|
128
|
+
document = first
|
129
|
+
criteria.skip((options[:skip] || 0) + 1)
|
130
|
+
document
|
131
|
+
end
|
132
|
+
|
118
133
|
# Get the sum of the field values for all the documents.
|
119
134
|
#
|
120
135
|
# Returns:
|
@@ -148,9 +163,21 @@ module Mongoid #:nodoc:
|
|
148
163
|
return documents.slice(skip, limit)
|
149
164
|
elsif limit
|
150
165
|
return documents.first(limit)
|
166
|
+
elsif skip
|
167
|
+
return documents.slice(skip..-1)
|
151
168
|
end
|
152
169
|
documents
|
153
170
|
end
|
171
|
+
|
172
|
+
# Sorts the result set if sort options have been set.
|
173
|
+
def sort(documents)
|
174
|
+
return documents if options[:sort].blank?
|
175
|
+
documents.sort_by do |document|
|
176
|
+
options[:sort].map do |key, direction|
|
177
|
+
Sort.new(document.read_attribute(key), direction)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
154
181
|
end
|
155
182
|
end
|
156
183
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Mongoid #:nodoc:
|
3
|
+
module Contexts #:nodoc:
|
4
|
+
class Enumerable
|
5
|
+
class Sort
|
6
|
+
attr_reader :value, :direction
|
7
|
+
|
8
|
+
# Create a new sorting object. This requires a value and a sort
|
9
|
+
# direction of +:asc+ or +:desc+.
|
10
|
+
def initialize(value, direction)
|
11
|
+
@value = value
|
12
|
+
@direction = direction
|
13
|
+
end
|
14
|
+
|
15
|
+
# Return +true+ if the direction is +:asc+, otherwise false.
|
16
|
+
def ascending?
|
17
|
+
direction == :asc
|
18
|
+
end
|
19
|
+
|
20
|
+
# Compare two +Sort+ objects against each other, taking into
|
21
|
+
# consideration the direction of the sorting.
|
22
|
+
def <=>(other)
|
23
|
+
cmp = compare(value, other.value)
|
24
|
+
ascending? ? cmp : cmp * -1
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
# Compare two values allowing for nil values.
|
30
|
+
def compare(a, b)
|
31
|
+
case
|
32
|
+
when a.nil?
|
33
|
+
b.nil? ? 0 : 1
|
34
|
+
when b.nil?
|
35
|
+
-1
|
36
|
+
else
|
37
|
+
a <=> b
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -133,7 +133,7 @@ module Mongoid #:nodoc:
|
|
133
133
|
# <tt>Mongoid::Contexts::Mongo.new(criteria)</tt>
|
134
134
|
def initialize(criteria)
|
135
135
|
@criteria = criteria
|
136
|
-
if klass.hereditary && !criteria.selector.keys.include?(:_type)
|
136
|
+
if klass.hereditary? && !criteria.selector.keys.include?(:_type)
|
137
137
|
criteria.in(:_type => criteria.klass._types)
|
138
138
|
end
|
139
139
|
criteria.enslave if klass.enslaved?
|
@@ -225,6 +225,18 @@ module Mongoid #:nodoc:
|
|
225
225
|
|
226
226
|
alias :first :one
|
227
227
|
|
228
|
+
# Return the first result for the +Context+ and skip it
|
229
|
+
# for successive calls.
|
230
|
+
#
|
231
|
+
# Returns:
|
232
|
+
#
|
233
|
+
# The first document in the collection.
|
234
|
+
def shift
|
235
|
+
document = first
|
236
|
+
criteria.skip((options[:skip] || 0) + 1)
|
237
|
+
document
|
238
|
+
end
|
239
|
+
|
228
240
|
# Sum the context.
|
229
241
|
#
|
230
242
|
# This will take the internally built selector and options
|
data/lib/mongoid/criteria.rb
CHANGED
@@ -3,6 +3,7 @@ require "mongoid/criterion/complex"
|
|
3
3
|
require "mongoid/criterion/exclusion"
|
4
4
|
require "mongoid/criterion/inclusion"
|
5
5
|
require "mongoid/criterion/optional"
|
6
|
+
require "mongoid/criterion/selector"
|
6
7
|
|
7
8
|
module Mongoid #:nodoc:
|
8
9
|
# The +Criteria+ class is the core object needed in Mongoid to retrieve
|
@@ -30,7 +31,7 @@ module Mongoid #:nodoc:
|
|
30
31
|
|
31
32
|
delegate :aggregate, :avg, :blank?, :count, :distinct, :empty?,
|
32
33
|
:execute, :first, :group, :id_criteria, :last, :max,
|
33
|
-
:min, :one, :page, :paginate, :per_page, :sum, :to => :context
|
34
|
+
:min, :one, :page, :paginate, :per_page, :shift, :sum, :to => :context
|
34
35
|
|
35
36
|
# Concatinate the criteria with another enumerable. If the other is a
|
36
37
|
# +Criteria+ then it needs to get the collection from it.
|
@@ -116,7 +117,8 @@ module Mongoid #:nodoc:
|
|
116
117
|
# type: One of :all, :first:, or :last
|
117
118
|
# klass: The class to execute on.
|
118
119
|
def initialize(klass)
|
119
|
-
@selector
|
120
|
+
@selector = Mongoid::Criterion::Selector.new(klass)
|
121
|
+
@options, @klass, @documents = {}, klass, []
|
120
122
|
end
|
121
123
|
|
122
124
|
# Merges another object into this +Criteria+. The other object may be a
|
@@ -43,6 +43,27 @@ module Mongoid #:nodoc:
|
|
43
43
|
where(selector)
|
44
44
|
end
|
45
45
|
|
46
|
+
# Adds a criterion to the +Criteria+ that specifies a set of expressions
|
47
|
+
# to match if any of them return true. This is a $or query in MongoDB and
|
48
|
+
# is similar to a SQL OR. This is named #any_of and aliased "or" for
|
49
|
+
# readability.
|
50
|
+
#
|
51
|
+
# Options:
|
52
|
+
#
|
53
|
+
# selector: Multiple +Hash+ expressions that any can match.
|
54
|
+
#
|
55
|
+
# Example:
|
56
|
+
#
|
57
|
+
# <tt>criteria.any_of({ :field1 => "value" }, { :field2 => "value2" })</tt>
|
58
|
+
#
|
59
|
+
# Returns: <tt>self</tt>
|
60
|
+
def any_of(*args)
|
61
|
+
criterion = @selector["$or"] || []
|
62
|
+
@selector["$or"] = criterion.concat(args)
|
63
|
+
self
|
64
|
+
end
|
65
|
+
alias :or :any_of
|
66
|
+
|
46
67
|
# Adds a criterion to the +Criteria+ that specifies values where any can
|
47
68
|
# be matched in order to return results. This is similar to an SQL "IN"
|
48
69
|
# clause. The MongoDB conditional operator that will be used is "$in".
|
@@ -89,7 +110,7 @@ module Mongoid #:nodoc:
|
|
89
110
|
#
|
90
111
|
# Options:
|
91
112
|
#
|
92
|
-
#
|
113
|
+
# selector: A +Hash+ that must match the attributes of the +Document+.
|
93
114
|
#
|
94
115
|
# Example:
|
95
116
|
#
|