mongoid 2.0.0.alpha → 2.0.0.beta.5
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/mongoid.rb +11 -5
- data/lib/mongoid/associations.rb +112 -107
- data/lib/mongoid/associations/belongs_to_related.rb +2 -3
- data/lib/mongoid/associations/embedded_in.rb +12 -4
- data/lib/mongoid/associations/{embed_many.rb → embeds_many.rb} +101 -32
- data/lib/mongoid/associations/{embed_one.rb → embeds_one.rb} +10 -10
- data/lib/mongoid/associations/has_many_related.rb +51 -5
- data/lib/mongoid/associations/has_one_related.rb +9 -5
- data/lib/mongoid/associations/meta_data.rb +2 -1
- data/lib/mongoid/associations/options.rb +15 -6
- data/lib/mongoid/associations/proxy.rb +14 -21
- data/lib/mongoid/attributes.rb +34 -13
- data/lib/mongoid/callbacks.rb +1 -2
- data/lib/mongoid/collection.rb +4 -3
- data/lib/mongoid/collections.rb +41 -0
- data/lib/mongoid/collections/master.rb +3 -2
- data/lib/mongoid/collections/slaves.rb +3 -2
- data/lib/mongoid/components.rb +4 -1
- data/lib/mongoid/config.rb +163 -13
- data/lib/mongoid/contexts.rb +1 -2
- data/lib/mongoid/contexts/enumerable.rb +1 -1
- data/lib/mongoid/contexts/mongo.rb +1 -1
- data/lib/mongoid/contexts/paging.rb +10 -2
- data/lib/mongoid/criteria.rb +13 -22
- data/lib/mongoid/criterion/exclusion.rb +3 -3
- data/lib/mongoid/criterion/inclusion.rb +17 -0
- data/lib/mongoid/criterion/optional.rb +1 -1
- data/lib/mongoid/dirty.rb +253 -0
- data/lib/mongoid/document.rb +40 -85
- data/lib/mongoid/errors.rb +48 -1
- data/lib/mongoid/extensions.rb +11 -9
- data/lib/mongoid/extensions/big_decimal/conversions.rb +2 -2
- data/lib/mongoid/extensions/boolean/conversions.rb +8 -2
- data/lib/mongoid/extensions/date/conversions.rb +13 -4
- data/lib/mongoid/extensions/datetime/conversions.rb +1 -6
- data/lib/mongoid/extensions/float/conversions.rb +5 -1
- data/lib/mongoid/extensions/hash/assimilation.rb +12 -3
- data/lib/mongoid/extensions/hash/conversions.rb +34 -4
- data/lib/mongoid/extensions/integer/conversions.rb +5 -1
- data/lib/mongoid/extensions/nil/assimilation.rb +4 -0
- data/lib/mongoid/extensions/object/conversions.rb +3 -3
- data/lib/mongoid/extensions/string/conversions.rb +1 -1
- data/lib/mongoid/extensions/symbol/inflections.rb +5 -2
- data/lib/mongoid/extensions/time_conversions.rb +35 -0
- data/lib/mongoid/factory.rb +2 -1
- data/lib/mongoid/field.rb +15 -2
- data/lib/mongoid/fields.rb +1 -1
- data/lib/mongoid/identity.rb +3 -3
- data/lib/mongoid/indexes.rb +3 -3
- data/lib/mongoid/matchers.rb +1 -2
- data/lib/mongoid/memoization.rb +8 -2
- data/lib/mongoid/named_scope.rb +0 -5
- data/lib/mongoid/observable.rb +1 -1
- data/lib/mongoid/paths.rb +30 -22
- data/lib/mongoid/persistence.rb +218 -0
- data/lib/mongoid/persistence/command.rb +39 -0
- data/lib/mongoid/persistence/insert.rb +47 -0
- data/lib/mongoid/persistence/insert_embedded.rb +38 -0
- data/lib/mongoid/persistence/remove.rb +39 -0
- data/lib/mongoid/persistence/remove_all.rb +37 -0
- data/lib/mongoid/persistence/remove_embedded.rb +50 -0
- data/lib/mongoid/persistence/update.rb +63 -0
- data/lib/mongoid/railtie.rb +53 -0
- data/lib/mongoid/railties/database.rake +37 -0
- data/lib/mongoid/timestamps.rb +2 -2
- data/lib/mongoid/validations.rb +2 -2
- data/lib/mongoid/validations/associated.rb +2 -2
- data/lib/mongoid/validations/uniqueness.rb +13 -2
- data/lib/mongoid/version.rb +4 -0
- data/lib/mongoid/versioning.rb +3 -2
- data/lib/rails/generators/mongoid/config/config_generator.rb +41 -0
- data/lib/rails/generators/mongoid/config/templates/mongoid.yml +24 -0
- data/lib/rails/generators/mongoid/model/model_generator.rb +24 -0
- data/lib/rails/generators/mongoid/model/templates/model.rb +15 -0
- data/lib/rails/generators/mongoid_generator.rb +61 -0
- metadata +76 -301
- data/.gitignore +0 -6
- data/.watchr +0 -29
- data/Rakefile +0 -52
- data/VERSION +0 -1
- data/caliper.yml +0 -4
- data/lib/mongoid/collections/mimic.rb +0 -46
- data/lib/mongoid/commands.rb +0 -161
- data/lib/mongoid/commands/create.rb +0 -19
- data/lib/mongoid/commands/delete.rb +0 -16
- data/lib/mongoid/commands/delete_all.rb +0 -23
- data/lib/mongoid/commands/deletion.rb +0 -18
- data/lib/mongoid/commands/destroy.rb +0 -17
- data/lib/mongoid/commands/destroy_all.rb +0 -23
- data/lib/mongoid/commands/save.rb +0 -29
- data/lib/mongoid/extensions/time/conversions.rb +0 -18
- data/mongoid.gemspec +0 -408
- data/perf/benchmark.rb +0 -77
- data/spec/integration/mongoid/associations_spec.rb +0 -340
- data/spec/integration/mongoid/attributes_spec.rb +0 -22
- data/spec/integration/mongoid/commands_spec.rb +0 -227
- data/spec/integration/mongoid/contexts/enumerable_spec.rb +0 -33
- data/spec/integration/mongoid/criteria_spec.rb +0 -272
- data/spec/integration/mongoid/document_spec.rb +0 -650
- data/spec/integration/mongoid/extensions_spec.rb +0 -22
- data/spec/integration/mongoid/finders_spec.rb +0 -119
- data/spec/integration/mongoid/inheritance_spec.rb +0 -137
- data/spec/integration/mongoid/named_scope_spec.rb +0 -46
- data/spec/models/address.rb +0 -39
- data/spec/models/animal.rb +0 -6
- data/spec/models/callbacks.rb +0 -18
- data/spec/models/comment.rb +0 -8
- data/spec/models/country_code.rb +0 -6
- data/spec/models/employer.rb +0 -5
- data/spec/models/game.rb +0 -7
- data/spec/models/inheritance.rb +0 -56
- data/spec/models/location.rb +0 -5
- data/spec/models/mixed_drink.rb +0 -4
- data/spec/models/name.rb +0 -13
- data/spec/models/namespacing.rb +0 -11
- data/spec/models/patient.rb +0 -4
- data/spec/models/person.rb +0 -99
- data/spec/models/pet.rb +0 -7
- data/spec/models/pet_owner.rb +0 -6
- data/spec/models/phone.rb +0 -7
- data/spec/models/post.rb +0 -15
- data/spec/models/translation.rb +0 -5
- data/spec/models/vet_visit.rb +0 -5
- data/spec/spec.opts +0 -3
- data/spec/spec_helper.rb +0 -31
- data/spec/unit/mongoid/associations/belongs_to_related_spec.rb +0 -145
- data/spec/unit/mongoid/associations/embed_many_spec.rb +0 -516
- data/spec/unit/mongoid/associations/embed_one_spec.rb +0 -282
- data/spec/unit/mongoid/associations/embedded_in_spec.rb +0 -193
- data/spec/unit/mongoid/associations/has_many_related_spec.rb +0 -418
- data/spec/unit/mongoid/associations/has_one_related_spec.rb +0 -179
- data/spec/unit/mongoid/associations/meta_data_spec.rb +0 -88
- data/spec/unit/mongoid/associations/options_spec.rb +0 -192
- data/spec/unit/mongoid/associations_spec.rb +0 -595
- data/spec/unit/mongoid/attributes_spec.rb +0 -507
- data/spec/unit/mongoid/callbacks_spec.rb +0 -55
- data/spec/unit/mongoid/collection_spec.rb +0 -187
- data/spec/unit/mongoid/collections/cyclic_iterator_spec.rb +0 -75
- data/spec/unit/mongoid/collections/master_spec.rb +0 -41
- data/spec/unit/mongoid/collections/mimic_spec.rb +0 -43
- data/spec/unit/mongoid/collections/slaves_spec.rb +0 -81
- data/spec/unit/mongoid/commands/create_spec.rb +0 -31
- data/spec/unit/mongoid/commands/delete_all_spec.rb +0 -58
- data/spec/unit/mongoid/commands/delete_spec.rb +0 -38
- data/spec/unit/mongoid/commands/destroy_all_spec.rb +0 -21
- data/spec/unit/mongoid/commands/destroy_spec.rb +0 -51
- data/spec/unit/mongoid/commands/save_spec.rb +0 -107
- data/spec/unit/mongoid/commands_spec.rb +0 -270
- data/spec/unit/mongoid/config_spec.rb +0 -172
- data/spec/unit/mongoid/contexts/enumerable_spec.rb +0 -421
- data/spec/unit/mongoid/contexts/mongo_spec.rb +0 -682
- data/spec/unit/mongoid/contexts_spec.rb +0 -25
- data/spec/unit/mongoid/criteria_spec.rb +0 -824
- data/spec/unit/mongoid/criterion/complex_spec.rb +0 -19
- data/spec/unit/mongoid/criterion/exclusion_spec.rb +0 -91
- data/spec/unit/mongoid/criterion/inclusion_spec.rb +0 -219
- data/spec/unit/mongoid/criterion/optional_spec.rb +0 -319
- data/spec/unit/mongoid/cursor_spec.rb +0 -74
- data/spec/unit/mongoid/deprecation_spec.rb +0 -24
- data/spec/unit/mongoid/document_spec.rb +0 -818
- data/spec/unit/mongoid/errors_spec.rb +0 -103
- data/spec/unit/mongoid/extensions/array/accessors_spec.rb +0 -50
- data/spec/unit/mongoid/extensions/array/assimilation_spec.rb +0 -24
- data/spec/unit/mongoid/extensions/array/conversions_spec.rb +0 -35
- data/spec/unit/mongoid/extensions/array/parentization_spec.rb +0 -20
- data/spec/unit/mongoid/extensions/big_decimal/conversions_spec.rb +0 -22
- data/spec/unit/mongoid/extensions/binary/conversions_spec.rb +0 -22
- data/spec/unit/mongoid/extensions/boolean/conversions_spec.rb +0 -49
- data/spec/unit/mongoid/extensions/date/conversions_spec.rb +0 -102
- data/spec/unit/mongoid/extensions/datetime/conversions_spec.rb +0 -67
- data/spec/unit/mongoid/extensions/float/conversions_spec.rb +0 -61
- data/spec/unit/mongoid/extensions/hash/accessors_spec.rb +0 -184
- data/spec/unit/mongoid/extensions/hash/assimilation_spec.rb +0 -46
- data/spec/unit/mongoid/extensions/hash/conversions_spec.rb +0 -21
- data/spec/unit/mongoid/extensions/hash/criteria_helpers_spec.rb +0 -17
- data/spec/unit/mongoid/extensions/hash/scoping_spec.rb +0 -14
- data/spec/unit/mongoid/extensions/integer/conversions_spec.rb +0 -61
- data/spec/unit/mongoid/extensions/nil/assimilation_spec.rb +0 -24
- data/spec/unit/mongoid/extensions/object/conversions_spec.rb +0 -57
- data/spec/unit/mongoid/extensions/proc/scoping_spec.rb +0 -34
- data/spec/unit/mongoid/extensions/string/conversions_spec.rb +0 -17
- data/spec/unit/mongoid/extensions/string/inflections_spec.rb +0 -208
- data/spec/unit/mongoid/extensions/symbol/inflections_spec.rb +0 -91
- data/spec/unit/mongoid/extensions/time/conversions_spec.rb +0 -70
- data/spec/unit/mongoid/extras_spec.rb +0 -102
- data/spec/unit/mongoid/factory_spec.rb +0 -31
- data/spec/unit/mongoid/field_spec.rb +0 -143
- data/spec/unit/mongoid/fields_spec.rb +0 -181
- data/spec/unit/mongoid/finders_spec.rb +0 -404
- data/spec/unit/mongoid/identity_spec.rb +0 -109
- data/spec/unit/mongoid/indexes_spec.rb +0 -93
- data/spec/unit/mongoid/javascript_spec.rb +0 -48
- data/spec/unit/mongoid/matchers/all_spec.rb +0 -27
- data/spec/unit/mongoid/matchers/default_spec.rb +0 -27
- data/spec/unit/mongoid/matchers/exists_spec.rb +0 -56
- data/spec/unit/mongoid/matchers/gt_spec.rb +0 -39
- data/spec/unit/mongoid/matchers/gte_spec.rb +0 -49
- data/spec/unit/mongoid/matchers/in_spec.rb +0 -27
- data/spec/unit/mongoid/matchers/lt_spec.rb +0 -39
- data/spec/unit/mongoid/matchers/lte_spec.rb +0 -49
- data/spec/unit/mongoid/matchers/ne_spec.rb +0 -27
- data/spec/unit/mongoid/matchers/nin_spec.rb +0 -27
- data/spec/unit/mongoid/matchers/size_spec.rb +0 -27
- data/spec/unit/mongoid/matchers_spec.rb +0 -329
- data/spec/unit/mongoid/memoization_spec.rb +0 -75
- data/spec/unit/mongoid/named_scope_spec.rb +0 -123
- data/spec/unit/mongoid/observable_spec.rb +0 -46
- data/spec/unit/mongoid/paths_spec.rb +0 -124
- data/spec/unit/mongoid/scope_spec.rb +0 -240
- data/spec/unit/mongoid/state_spec.rb +0 -83
- data/spec/unit/mongoid/timestamps_spec.rb +0 -25
- data/spec/unit/mongoid/validations/associated_spec.rb +0 -103
- data/spec/unit/mongoid/validations/uniqueness_spec.rb +0 -47
- data/spec/unit/mongoid/validations_spec.rb +0 -190
- data/spec/unit/mongoid/versioning_spec.rb +0 -41
- data/spec/unit/mongoid_spec.rb +0 -46
data/lib/mongoid/contexts.rb
CHANGED
@@ -15,11 +15,10 @@ module Mongoid
|
|
15
15
|
#
|
16
16
|
# <tt>Contexts.context_for(criteria)</tt>
|
17
17
|
def self.context_for(criteria)
|
18
|
-
if criteria.klass.embedded
|
18
|
+
if criteria.klass.embedded?
|
19
19
|
return Contexts::Enumerable.new(criteria)
|
20
20
|
end
|
21
21
|
Contexts::Mongo.new(criteria)
|
22
22
|
end
|
23
|
-
|
24
23
|
end
|
25
24
|
end
|
@@ -6,7 +6,7 @@ module Mongoid #:nodoc:
|
|
6
6
|
attr_reader :criteria
|
7
7
|
|
8
8
|
delegate :blank?, :empty?, :first, :last, :to => :execute
|
9
|
-
delegate :documents, :options, :selector, :to => :criteria
|
9
|
+
delegate :klass, :documents, :options, :selector, :to => :criteria
|
10
10
|
|
11
11
|
# Return aggregation counts of the grouped documents. This will count by
|
12
12
|
# the first field provided in the fields array.
|
@@ -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
|
136
|
+
if klass.hereditary
|
137
137
|
criteria.in(:_type => criteria.klass._types)
|
138
138
|
end
|
139
139
|
criteria.enslave if klass.enslaved?
|
@@ -6,12 +6,20 @@ module Mongoid #:nodoc:
|
|
6
6
|
#
|
7
7
|
# Example:
|
8
8
|
#
|
9
|
-
# <tt>context.paginate</tt>
|
9
|
+
# <tt>context.paginate(:page => 6, :per_page => 25)</tt>
|
10
10
|
#
|
11
11
|
# Returns:
|
12
12
|
#
|
13
13
|
# A collection of documents paginated.
|
14
|
-
|
14
|
+
# All previous <tt>limit</tt> and <tt>skip</tt> call will be ignored.
|
15
|
+
def paginate(pager_options={})
|
16
|
+
if pager_options[:per_page]
|
17
|
+
options[:limit] = pager_options[:per_page].to_i
|
18
|
+
if pager_options[:page]
|
19
|
+
options[:skip] = (pager_options[:page].to_i - 1) * pager_options[:per_page].to_i
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
15
23
|
@collection ||= execute(true)
|
16
24
|
WillPaginate::Collection.create(page, per_page, count) do |pager|
|
17
25
|
pager.replace(@collection.to_a)
|
data/lib/mongoid/criteria.rb
CHANGED
@@ -28,25 +28,9 @@ module Mongoid #:nodoc:
|
|
28
28
|
attr_reader :collection, :ids, :klass, :options, :selector
|
29
29
|
attr_accessor :documents
|
30
30
|
|
31
|
-
delegate
|
32
|
-
|
33
|
-
|
34
|
-
:blank?,
|
35
|
-
:count,
|
36
|
-
:distinct,
|
37
|
-
:empty?,
|
38
|
-
:execute,
|
39
|
-
:first,
|
40
|
-
:group,
|
41
|
-
:id_criteria,
|
42
|
-
:last,
|
43
|
-
:max,
|
44
|
-
:min,
|
45
|
-
:one,
|
46
|
-
:page,
|
47
|
-
:paginate,
|
48
|
-
:per_page,
|
49
|
-
:sum, :to => :context
|
31
|
+
delegate :aggregate, :avg, :blank?, :count, :distinct, :empty?,
|
32
|
+
:execute, :first, :group, :id_criteria, :last, :max,
|
33
|
+
:min, :one, :page, :paginate, :per_page, :sum, :to => :context
|
50
34
|
|
51
35
|
# Concatinate the criteria with another enumerable. If the other is a
|
52
36
|
# +Criteria+ then it needs to get the collection from it.
|
@@ -190,14 +174,14 @@ module Mongoid #:nodoc:
|
|
190
174
|
klass = args[0]
|
191
175
|
params = args[1] || {}
|
192
176
|
unless params.is_a?(Hash)
|
193
|
-
return
|
177
|
+
return klass.criteria.id_criteria(params)
|
194
178
|
end
|
195
179
|
conditions = params.delete(:conditions) || {}
|
196
180
|
if conditions.include?(:id)
|
197
181
|
conditions[:_id] = conditions[:id]
|
198
182
|
conditions.delete(:id)
|
199
183
|
end
|
200
|
-
return
|
184
|
+
return klass.criteria.where(conditions).extras(params)
|
201
185
|
end
|
202
186
|
|
203
187
|
protected
|
@@ -233,7 +217,14 @@ module Mongoid #:nodoc:
|
|
233
217
|
#
|
234
218
|
# <tt>criteria.update_selector({ :field => "value" }, "$in")</tt>
|
235
219
|
def update_selector(attributes, operator)
|
236
|
-
attributes.each
|
220
|
+
attributes.each do |key, value|
|
221
|
+
unless @selector[key]
|
222
|
+
@selector[key] = { operator => value }
|
223
|
+
else
|
224
|
+
new_value = @selector[key].values.first + value
|
225
|
+
@selector[key] = { operator => new_value }
|
226
|
+
end
|
227
|
+
end; self
|
237
228
|
end
|
238
229
|
end
|
239
230
|
end
|
@@ -30,7 +30,7 @@ module Mongoid #:nodoc:
|
|
30
30
|
#
|
31
31
|
# Options:
|
32
32
|
#
|
33
|
-
#
|
33
|
+
# attributes: A +Hash+ where the key is the field name and the value is an
|
34
34
|
# +Array+ of values that none can match.
|
35
35
|
#
|
36
36
|
# Example:
|
@@ -40,8 +40,8 @@ module Mongoid #:nodoc:
|
|
40
40
|
# <tt>criteria.not_in(:field1 => ["value1", "value2"], :field2 => ["value1"])</tt>
|
41
41
|
#
|
42
42
|
# Returns: <tt>self</tt>
|
43
|
-
def not_in(
|
44
|
-
|
43
|
+
def not_in(attributes)
|
44
|
+
update_selector(attributes, "$nin")
|
45
45
|
end
|
46
46
|
|
47
47
|
# Adds a criterion to the +Criteria+ that specifies the fields that will
|
@@ -64,6 +64,23 @@ module Mongoid #:nodoc:
|
|
64
64
|
end
|
65
65
|
alias :any_in :in
|
66
66
|
|
67
|
+
# Adds a criterion to the +Criteria+ that specifies values to do
|
68
|
+
# geospacial searches by. The field must be indexed with the "2d" option.
|
69
|
+
#
|
70
|
+
# Options:
|
71
|
+
#
|
72
|
+
# attributes: A +Hash+ where the keys are the field names and the values are
|
73
|
+
# +Arrays+ of [latitude, longitude] pairs.
|
74
|
+
#
|
75
|
+
# Example:
|
76
|
+
#
|
77
|
+
# <tt>criteria.near(:field1 => [30, -44])</tt>
|
78
|
+
#
|
79
|
+
# Returns: <tt>self</tt>
|
80
|
+
def near(attributes = {})
|
81
|
+
update_selector(attributes, "$near")
|
82
|
+
end
|
83
|
+
|
67
84
|
# Adds a criterion to the +Criteria+ that specifies values that must
|
68
85
|
# be matched in order to return results. This is similar to a SQL "WHERE"
|
69
86
|
# clause. This is the actual selector that will be provided to MongoDB,
|
@@ -0,0 +1,253 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Mongoid #:nodoc:
|
3
|
+
module Dirty #:nodoc:
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
module InstanceMethods #:nodoc:
|
6
|
+
# Gets the changes for a specific field.
|
7
|
+
#
|
8
|
+
# Example:
|
9
|
+
#
|
10
|
+
# person = Person.new(:title => "Sir")
|
11
|
+
# person.title = "Madam"
|
12
|
+
# person.attribute_change("title") # [ "Sir", "Madam" ]
|
13
|
+
#
|
14
|
+
# Returns:
|
15
|
+
#
|
16
|
+
# An +Array+ containing the old and new values.
|
17
|
+
def attribute_change(name)
|
18
|
+
modifications[name]
|
19
|
+
end
|
20
|
+
|
21
|
+
# Determines if a specific field has chaged.
|
22
|
+
#
|
23
|
+
# Example:
|
24
|
+
#
|
25
|
+
# person = Person.new(:title => "Sir")
|
26
|
+
# person.title = "Madam"
|
27
|
+
# person.attribute_changed?("title") # true
|
28
|
+
#
|
29
|
+
# Returns:
|
30
|
+
#
|
31
|
+
# +true+ if changed, +false+ if not.
|
32
|
+
def attribute_changed?(name)
|
33
|
+
modifications.include?(name)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Gets the old value for a specific field.
|
37
|
+
#
|
38
|
+
# Example:
|
39
|
+
#
|
40
|
+
# person = Person.new(:title => "Sir")
|
41
|
+
# person.title = "Madam"
|
42
|
+
# person.attribute_was("title") # "Sir"
|
43
|
+
#
|
44
|
+
# Returns:
|
45
|
+
#
|
46
|
+
# The old field value.
|
47
|
+
def attribute_was(name)
|
48
|
+
change = modifications[name]
|
49
|
+
change ? change[0] : nil
|
50
|
+
end
|
51
|
+
|
52
|
+
# Gets the names of all the fields that have changed in the document.
|
53
|
+
#
|
54
|
+
# Example:
|
55
|
+
#
|
56
|
+
# person = Person.new(:title => "Sir")
|
57
|
+
# person.title = "Madam"
|
58
|
+
# person.changed # returns [ "title" ]
|
59
|
+
#
|
60
|
+
# Returns:
|
61
|
+
#
|
62
|
+
# An +Array+ of changed field names.
|
63
|
+
def changed
|
64
|
+
modifications.keys
|
65
|
+
end
|
66
|
+
|
67
|
+
# Alerts to whether the document has been modified or not.
|
68
|
+
#
|
69
|
+
# Example:
|
70
|
+
#
|
71
|
+
# person = Person.new(:title => "Sir")
|
72
|
+
# person.title = "Madam"
|
73
|
+
# person.changed? # returns true
|
74
|
+
#
|
75
|
+
# Returns:
|
76
|
+
#
|
77
|
+
# +true+ if changed, +false+ if not.
|
78
|
+
def changed?
|
79
|
+
!modifications.empty?
|
80
|
+
end
|
81
|
+
|
82
|
+
# Gets all the modifications that have happened to the object as a +Hash+
|
83
|
+
# with the keys being the names of the fields, and the values being an
|
84
|
+
# +Array+ with the old value and new value.
|
85
|
+
#
|
86
|
+
# Example:
|
87
|
+
#
|
88
|
+
# person = Person.new(:title => "Sir")
|
89
|
+
# person.title = "Madam"
|
90
|
+
# person.changes # returns { "title" => [ "Sir", "Madam" ] }
|
91
|
+
#
|
92
|
+
# Returns:
|
93
|
+
#
|
94
|
+
# A +Hash+ of changes.
|
95
|
+
def changes
|
96
|
+
modifications
|
97
|
+
end
|
98
|
+
|
99
|
+
# Call this method after save, so the changes can be properly switched.
|
100
|
+
#
|
101
|
+
# Example:
|
102
|
+
#
|
103
|
+
# <tt>person.move_changes</tt>
|
104
|
+
def move_changes
|
105
|
+
@previous_modifications = modifications.dup
|
106
|
+
@modifications = {}
|
107
|
+
end
|
108
|
+
|
109
|
+
# Gets all the new values for each of the changed fields, to be passed to
|
110
|
+
# a MongoDB $set modifier.
|
111
|
+
#
|
112
|
+
# Example:
|
113
|
+
#
|
114
|
+
# person = Person.new(:title => "Sir")
|
115
|
+
# person.title = "Madam"
|
116
|
+
# person.setters # returns { "title" => "Madam" }
|
117
|
+
#
|
118
|
+
# Returns:
|
119
|
+
#
|
120
|
+
# A +Hash+ of new values.
|
121
|
+
def setters
|
122
|
+
modifications.inject({}) do |sets, (field, changes)|
|
123
|
+
key = embedded? ? "#{_position}.#{field}" : field
|
124
|
+
sets[key] = changes[1]; sets
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
# Gets all the modifications that have happened to the object before the
|
129
|
+
# object was saved.
|
130
|
+
#
|
131
|
+
# Example:
|
132
|
+
#
|
133
|
+
# person = Person.new(:title => "Sir")
|
134
|
+
# person.title = "Madam"
|
135
|
+
# person.save!
|
136
|
+
# person.previous_changes # returns { "title" => [ "Sir", "Madam" ] }
|
137
|
+
#
|
138
|
+
# Returns:
|
139
|
+
#
|
140
|
+
# A +Hash+ of changes before save.
|
141
|
+
def previous_changes
|
142
|
+
@previous_modifications
|
143
|
+
end
|
144
|
+
|
145
|
+
# Resets a changed field back to its old value.
|
146
|
+
#
|
147
|
+
# Example:
|
148
|
+
#
|
149
|
+
# person = Person.new(:title => "Sir")
|
150
|
+
# person.title = "Madam"
|
151
|
+
# person.reset_attribute!("title")
|
152
|
+
# person.title # "Sir"
|
153
|
+
#
|
154
|
+
# Returns:
|
155
|
+
#
|
156
|
+
# The old field value.
|
157
|
+
def reset_attribute!(name)
|
158
|
+
value = attribute_was(name)
|
159
|
+
if value
|
160
|
+
@attributes[name] = value
|
161
|
+
modifications.delete(name)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
# Sets up the modifications hash. This occurs just after the document is
|
166
|
+
# instantiated.
|
167
|
+
#
|
168
|
+
# Example:
|
169
|
+
#
|
170
|
+
# <tt>document.setup_notifications</tt>
|
171
|
+
def setup_modifications
|
172
|
+
@accessed ||= {}
|
173
|
+
@modifications ||= {}
|
174
|
+
@previous_modifications ||= {}
|
175
|
+
end
|
176
|
+
|
177
|
+
# Reset all modifications for the document. This will wipe all the marked
|
178
|
+
# changes, but not reset the values.
|
179
|
+
#
|
180
|
+
# Example:
|
181
|
+
#
|
182
|
+
# <tt>document.reset_modifications</tt>
|
183
|
+
def reset_modifications
|
184
|
+
@accessed = {}
|
185
|
+
@modifications = {}
|
186
|
+
end
|
187
|
+
|
188
|
+
protected
|
189
|
+
|
190
|
+
# Audit the original value for a field that can be modified in place.
|
191
|
+
#
|
192
|
+
# Example:
|
193
|
+
#
|
194
|
+
# <tt>person.accessed("aliases", [ "007" ])</tt>
|
195
|
+
def accessed(name, value)
|
196
|
+
@accessed ||= {}
|
197
|
+
@accessed[name] = value.dup if (value.is_a?(Array) || value.is_a?(Hash)) && !@accessed.has_key?(name)
|
198
|
+
value
|
199
|
+
end
|
200
|
+
|
201
|
+
# Get all normal modifications plus in place potential changes.
|
202
|
+
#
|
203
|
+
# Example:
|
204
|
+
#
|
205
|
+
# <tt>person.modifications</tt>
|
206
|
+
#
|
207
|
+
# Returns:
|
208
|
+
#
|
209
|
+
# All changes to the document.
|
210
|
+
def modifications
|
211
|
+
@accessed.each_pair do |field, value|
|
212
|
+
current = @attributes[field]
|
213
|
+
@modifications[field] = [ value, current ] if current != value
|
214
|
+
end
|
215
|
+
@accessed.clear
|
216
|
+
@modifications
|
217
|
+
end
|
218
|
+
|
219
|
+
# Audit the change of a field's value.
|
220
|
+
#
|
221
|
+
# Example:
|
222
|
+
#
|
223
|
+
# <tt>person.modify("name", "Jack", "John")</tt>
|
224
|
+
def modify(name, old_value, new_value)
|
225
|
+
@attributes[name] = new_value
|
226
|
+
if @modifications && (old_value != new_value)
|
227
|
+
original = @modifications[name].first if @modifications[name]
|
228
|
+
@modifications[name] = [ (original || old_value), new_value ]
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
module ClassMethods #:nodoc:
|
234
|
+
# Add the dynamic dirty methods. These are custom methods defined on a
|
235
|
+
# field by field basis that wrap the dirty attribute methods.
|
236
|
+
#
|
237
|
+
# Example:
|
238
|
+
#
|
239
|
+
# person = Person.new(:title => "Sir")
|
240
|
+
# person.title = "Madam"
|
241
|
+
# person.title_change # [ "Sir", "Madam" ]
|
242
|
+
# person.title_changed? # true
|
243
|
+
# person.title_was # "Sir"
|
244
|
+
# person.reset_title!
|
245
|
+
def add_dirty_methods(name)
|
246
|
+
define_method("#{name}_change") { attribute_change(name) }
|
247
|
+
define_method("#{name}_changed?") { attribute_changed?(name) }
|
248
|
+
define_method("#{name}_was") { attribute_was(name) }
|
249
|
+
define_method("reset_#{name}!") { reset_attribute!(name) }
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
data/lib/mongoid/document.rb
CHANGED
@@ -5,16 +5,13 @@ module Mongoid #:nodoc:
|
|
5
5
|
included do
|
6
6
|
include Mongoid::Components
|
7
7
|
|
8
|
-
cattr_accessor :
|
9
|
-
|
10
|
-
self.embedded = false
|
8
|
+
cattr_accessor :primary_key, :hereditary
|
11
9
|
self.hereditary = false
|
12
|
-
self.collection_name = self.name.collectionize
|
13
10
|
|
14
11
|
attr_accessor :association_name, :_parent
|
15
12
|
attr_reader :new_record
|
16
13
|
|
17
|
-
delegate :
|
14
|
+
delegate :db, :primary_key, :to => "self.class"
|
18
15
|
end
|
19
16
|
|
20
17
|
module ClassMethods
|
@@ -23,17 +20,6 @@ module Mongoid #:nodoc:
|
|
23
20
|
collection.db
|
24
21
|
end
|
25
22
|
|
26
|
-
# Returns the collection associated with this +Document+. If the
|
27
|
-
# document is embedded, there will be no collection associated
|
28
|
-
# with it.
|
29
|
-
#
|
30
|
-
# Returns: <tt>Mongo::Collection</tt>
|
31
|
-
def collection
|
32
|
-
raise Errors::InvalidCollection.new(self) if embedded
|
33
|
-
self._collection ||= Mongoid::Collection.new(self, self.collection_name)
|
34
|
-
add_indexes; self._collection
|
35
|
-
end
|
36
|
-
|
37
23
|
# Perform default behavior but mark the hierarchy as being hereditary.
|
38
24
|
def inherited(subclass)
|
39
25
|
super(subclass)
|
@@ -51,6 +37,7 @@ module Mongoid #:nodoc:
|
|
51
37
|
if attributes["_id"] || allocating
|
52
38
|
document = allocate
|
53
39
|
document.instance_variable_set(:@attributes, attributes)
|
40
|
+
document.setup_modifications
|
54
41
|
return document
|
55
42
|
else
|
56
43
|
return new(attrs)
|
@@ -70,17 +57,7 @@ module Mongoid #:nodoc:
|
|
70
57
|
# end
|
71
58
|
def key(*fields)
|
72
59
|
self.primary_key = fields
|
73
|
-
|
74
|
-
end
|
75
|
-
|
76
|
-
# Macro for setting the collection name to store in.
|
77
|
-
#
|
78
|
-
# Example:
|
79
|
-
#
|
80
|
-
# <tt>Person.store_in :populdation</tt>
|
81
|
-
def store_in(name)
|
82
|
-
self.collection_name = name.to_s
|
83
|
-
self._collection = Mongoid::Collection.new(self, name.to_s)
|
60
|
+
set_callback :save, :before, :identify
|
84
61
|
end
|
85
62
|
|
86
63
|
# Returns all types to query for when using this class as the base.
|
@@ -91,7 +68,6 @@ module Mongoid #:nodoc:
|
|
91
68
|
# return the list of subclassses for an object
|
92
69
|
def subclasses_of(*superclasses) #:nodoc:
|
93
70
|
subclasses = []
|
94
|
-
|
95
71
|
superclasses.each do |sup|
|
96
72
|
ObjectSpace.each_object(class << sup; self; end) do |k|
|
97
73
|
if k != sup && (k.name.blank? || eval("defined?(::#{k}) && ::#{k}.object_id == k.object_id"))
|
@@ -99,18 +75,16 @@ module Mongoid #:nodoc:
|
|
99
75
|
end
|
100
76
|
end
|
101
77
|
end
|
102
|
-
|
103
78
|
subclasses
|
104
79
|
end
|
105
80
|
end
|
106
81
|
|
107
82
|
module InstanceMethods
|
108
|
-
# Performs equality checking on the
|
109
|
-
#
|
83
|
+
# Performs equality checking on the document ids. For more robust
|
84
|
+
# equality checking please override this method.
|
110
85
|
def ==(other)
|
111
86
|
return false unless other.is_a?(Document)
|
112
|
-
|
113
|
-
other.attributes.except(:modified_at).except(:created_at)
|
87
|
+
id == other.id
|
114
88
|
end
|
115
89
|
|
116
90
|
# Delegates to ==
|
@@ -124,6 +98,15 @@ module Mongoid #:nodoc:
|
|
124
98
|
id.hash
|
125
99
|
end
|
126
100
|
|
101
|
+
# Is inheritance in play here?
|
102
|
+
#
|
103
|
+
# Returns:
|
104
|
+
#
|
105
|
+
# <tt>true</tt> if inheritance used, <tt>false</tt> if not.
|
106
|
+
def hereditary?
|
107
|
+
!!self.hereditary
|
108
|
+
end
|
109
|
+
|
127
110
|
# Introduces a child object into the +Document+ object graph. This will
|
128
111
|
# set up the relationships between the parent and child and update the
|
129
112
|
# attributes of the parent +Document+.
|
@@ -157,24 +140,27 @@ module Mongoid #:nodoc:
|
|
157
140
|
# an empty +Hash+.
|
158
141
|
#
|
159
142
|
# If a primary key is defined, the document's id will be set to that key,
|
160
|
-
# otherwise it will be set to a fresh +
|
143
|
+
# otherwise it will be set to a fresh +BSON::ObjectID+ string.
|
161
144
|
#
|
162
145
|
# Options:
|
163
146
|
#
|
164
147
|
# attrs: The attributes +Hash+ to set up the document with.
|
165
148
|
def initialize(attrs = nil)
|
166
|
-
@attributes =
|
149
|
+
@attributes = default_attributes
|
167
150
|
process(attrs)
|
168
|
-
@
|
169
|
-
@new_record = true if id.nil?
|
151
|
+
@new_record = true
|
170
152
|
document = yield self if block_given?
|
171
153
|
identify
|
172
154
|
end
|
173
155
|
|
174
156
|
# Returns the class name plus its attributes.
|
175
157
|
def inspect
|
176
|
-
attrs = fields.map { |name, field| "#{name}: #{@attributes[name].inspect}" }
|
177
|
-
|
158
|
+
attrs = fields.map { |name, field| "#{name}: #{@attributes[name].inspect}" }
|
159
|
+
if Mongoid.allow_dynamic_fields
|
160
|
+
dynamic_keys = @attributes.keys - fields.keys - associations.keys - ["_id", "_type"]
|
161
|
+
attrs += dynamic_keys.map { |name| "#{name}: #{@attributes[name].inspect}" }
|
162
|
+
end
|
163
|
+
"#<#{self.class.name} _id: #{id}, #{attrs * ', '}>"
|
178
164
|
end
|
179
165
|
|
180
166
|
# Notify observers of an update.
|
@@ -211,8 +197,12 @@ module Mongoid #:nodoc:
|
|
211
197
|
|
212
198
|
# Reloads the +Document+ attributes from the database.
|
213
199
|
def reload
|
214
|
-
|
215
|
-
|
200
|
+
reloaded = collection.find_one(:_id => id)
|
201
|
+
if Mongoid.raise_not_found_error
|
202
|
+
raise Errors::DocumentNotFound.new(self.class, id) if reloaded.nil?
|
203
|
+
end
|
204
|
+
@attributes = {}.merge(reloaded || {})
|
205
|
+
self.associations.keys.each { |association_name| unmemoize(association_name) }; self
|
216
206
|
end
|
217
207
|
|
218
208
|
# Remove a child document from this parent +Document+. Will reset the
|
@@ -236,39 +226,9 @@ module Mongoid #:nodoc:
|
|
236
226
|
[ self ]
|
237
227
|
end
|
238
228
|
|
239
|
-
#
|
240
|
-
|
241
|
-
|
242
|
-
#
|
243
|
-
# Example:
|
244
|
-
#
|
245
|
-
# <tt>person.to_json</tt>
|
246
|
-
def to_json(options = nil)
|
247
|
-
attributes.to_json(options)
|
248
|
-
end
|
249
|
-
|
250
|
-
# Return an object to be encoded into a JSON string.
|
251
|
-
# Used by Rails 3's object->JSON chain to create JSON
|
252
|
-
# in a backend-agnostic way
|
253
|
-
#
|
254
|
-
# Example:
|
255
|
-
#
|
256
|
-
# <tt>person.as_json</tt>
|
257
|
-
def as_json(options = nil)
|
258
|
-
attributes
|
259
|
-
end
|
260
|
-
|
261
|
-
# Return this document as an object to be encoded as JSON,
|
262
|
-
# with any particular items modified on a per-encoder basis.
|
263
|
-
# Nothing special is required here since Mongoid bubbles up
|
264
|
-
# all the child associations to the parent attribute +Hash+
|
265
|
-
# using observers throughout the +Document+ lifecycle.
|
266
|
-
#
|
267
|
-
# Example:
|
268
|
-
#
|
269
|
-
# <tt>person.encode_json(encoder)</tt>
|
270
|
-
def encode_json(encoder)
|
271
|
-
attributes
|
229
|
+
# Returns nil if document is new, or an array of primary keys if not.
|
230
|
+
def to_key
|
231
|
+
new_record? ? nil : [ id ]
|
272
232
|
end
|
273
233
|
|
274
234
|
# Returns the id of the Document, used in Rails compatibility.
|
@@ -287,20 +247,15 @@ module Mongoid #:nodoc:
|
|
287
247
|
#
|
288
248
|
# This will also cause the observing +Document+ to notify it's parent if
|
289
249
|
# there is any.
|
290
|
-
def
|
250
|
+
def observe(child, clear = false)
|
291
251
|
name = child.association_name
|
292
252
|
attrs = child.instance_variable_get(:@attributes)
|
293
|
-
clear
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
protected
|
298
|
-
# apply default values to attributes - calling procs as required
|
299
|
-
def attributes_with_defaults(attributes = {})
|
300
|
-
default_values = defaults.merge(attributes)
|
301
|
-
default_values.each_pair do |key, val|
|
302
|
-
default_values[key] = val.call if val.respond_to?(:call)
|
253
|
+
if clear
|
254
|
+
@attributes.delete(name)
|
255
|
+
else
|
256
|
+
@attributes.insert(name, attrs) unless @attributes[name] && @attributes[name].include?(attrs)
|
303
257
|
end
|
258
|
+
notify
|
304
259
|
end
|
305
260
|
end
|
306
261
|
end
|