stonegao-mongoid 2.0.0.rc.6
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/LICENSE +20 -0
- data/README.rdoc +50 -0
- data/Rakefile +51 -0
- data/lib/config/locales/bg.yml +44 -0
- data/lib/config/locales/de.yml +44 -0
- data/lib/config/locales/en.yml +45 -0
- data/lib/config/locales/es.yml +44 -0
- data/lib/config/locales/fr.yml +45 -0
- data/lib/config/locales/hu.yml +47 -0
- data/lib/config/locales/it.yml +42 -0
- data/lib/config/locales/kr.yml +68 -0
- data/lib/config/locales/nl.yml +42 -0
- data/lib/config/locales/pl.yml +42 -0
- data/lib/config/locales/pt-br.yml +43 -0
- data/lib/config/locales/pt.yml +43 -0
- data/lib/config/locales/ro.yml +49 -0
- data/lib/config/locales/sv.yml +43 -0
- data/lib/config/locales/zh-CN.yml +34 -0
- data/lib/mongoid/atomicity.rb +111 -0
- data/lib/mongoid/attributes.rb +251 -0
- data/lib/mongoid/callbacks.rb +13 -0
- data/lib/mongoid/collection.rb +137 -0
- data/lib/mongoid/collections/cyclic_iterator.rb +34 -0
- data/lib/mongoid/collections/master.rb +29 -0
- data/lib/mongoid/collections/operations.rb +42 -0
- data/lib/mongoid/collections/slaves.rb +45 -0
- data/lib/mongoid/collections.rb +70 -0
- data/lib/mongoid/components.rb +45 -0
- data/lib/mongoid/config/database.rb +167 -0
- data/lib/mongoid/config/replset_database.rb +48 -0
- data/lib/mongoid/config.rb +343 -0
- data/lib/mongoid/contexts/enumerable/sort.rb +43 -0
- data/lib/mongoid/contexts/enumerable.rb +226 -0
- data/lib/mongoid/contexts/ids.rb +25 -0
- data/lib/mongoid/contexts/mongo.rb +345 -0
- data/lib/mongoid/contexts/paging.rb +50 -0
- data/lib/mongoid/contexts.rb +21 -0
- data/lib/mongoid/copyable.rb +44 -0
- data/lib/mongoid/criteria.rb +325 -0
- data/lib/mongoid/criterion/complex.rb +34 -0
- data/lib/mongoid/criterion/creational.rb +34 -0
- data/lib/mongoid/criterion/exclusion.rb +67 -0
- data/lib/mongoid/criterion/inclusion.rb +134 -0
- data/lib/mongoid/criterion/inspection.rb +20 -0
- data/lib/mongoid/criterion/optional.rb +213 -0
- data/lib/mongoid/criterion/selector.rb +74 -0
- data/lib/mongoid/cursor.rb +81 -0
- data/lib/mongoid/default_scope.rb +28 -0
- data/lib/mongoid/dirty.rb +251 -0
- data/lib/mongoid/document.rb +256 -0
- 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/unsaved_document.rb +23 -0
- data/lib/mongoid/errors/unsupported_version.rb +21 -0
- data/lib/mongoid/errors/validations.rb +24 -0
- data/lib/mongoid/errors.rb +12 -0
- data/lib/mongoid/extensions/array/conversions.rb +23 -0
- data/lib/mongoid/extensions/array/parentization.rb +13 -0
- data/lib/mongoid/extensions/big_decimal/conversions.rb +19 -0
- data/lib/mongoid/extensions/binary/conversions.rb +17 -0
- data/lib/mongoid/extensions/boolean/conversions.rb +27 -0
- data/lib/mongoid/extensions/date/conversions.rb +25 -0
- data/lib/mongoid/extensions/datetime/conversions.rb +12 -0
- data/lib/mongoid/extensions/false_class/equality.rb +13 -0
- data/lib/mongoid/extensions/float/conversions.rb +20 -0
- data/lib/mongoid/extensions/hash/conversions.rb +19 -0
- data/lib/mongoid/extensions/hash/criteria_helpers.rb +22 -0
- data/lib/mongoid/extensions/hash/scoping.rb +12 -0
- data/lib/mongoid/extensions/integer/conversions.rb +20 -0
- data/lib/mongoid/extensions/nil/collectionization.rb +12 -0
- data/lib/mongoid/extensions/object/conversions.rb +25 -0
- data/lib/mongoid/extensions/object/reflections.rb +17 -0
- data/lib/mongoid/extensions/object/yoda.rb +27 -0
- data/lib/mongoid/extensions/object_id/conversions.rb +57 -0
- data/lib/mongoid/extensions/proc/scoping.rb +12 -0
- data/lib/mongoid/extensions/set/conversions.rb +20 -0
- data/lib/mongoid/extensions/string/conversions.rb +34 -0
- data/lib/mongoid/extensions/string/inflections.rb +97 -0
- data/lib/mongoid/extensions/symbol/conversions.rb +21 -0
- data/lib/mongoid/extensions/symbol/inflections.rb +40 -0
- data/lib/mongoid/extensions/time_conversions.rb +38 -0
- data/lib/mongoid/extensions/true_class/equality.rb +13 -0
- data/lib/mongoid/extensions.rb +116 -0
- data/lib/mongoid/extras.rb +61 -0
- data/lib/mongoid/factory.rb +20 -0
- data/lib/mongoid/field.rb +95 -0
- data/lib/mongoid/fields.rb +138 -0
- data/lib/mongoid/finders.rb +173 -0
- data/lib/mongoid/hierarchy.rb +85 -0
- data/lib/mongoid/identity.rb +89 -0
- data/lib/mongoid/indexes.rb +38 -0
- data/lib/mongoid/inspection.rb +58 -0
- data/lib/mongoid/javascript/functions.yml +37 -0
- data/lib/mongoid/javascript.rb +21 -0
- data/lib/mongoid/json.rb +16 -0
- data/lib/mongoid/keys.rb +77 -0
- data/lib/mongoid/logger.rb +18 -0
- data/lib/mongoid/matchers/all.rb +11 -0
- data/lib/mongoid/matchers/default.rb +27 -0
- data/lib/mongoid/matchers/exists.rb +13 -0
- data/lib/mongoid/matchers/gt.rb +11 -0
- data/lib/mongoid/matchers/gte.rb +11 -0
- data/lib/mongoid/matchers/in.rb +11 -0
- data/lib/mongoid/matchers/lt.rb +11 -0
- data/lib/mongoid/matchers/lte.rb +11 -0
- data/lib/mongoid/matchers/ne.rb +11 -0
- data/lib/mongoid/matchers/nin.rb +11 -0
- data/lib/mongoid/matchers/size.rb +11 -0
- data/lib/mongoid/matchers.rb +55 -0
- data/lib/mongoid/modifiers/command.rb +18 -0
- data/lib/mongoid/modifiers/inc.rb +24 -0
- data/lib/mongoid/modifiers.rb +24 -0
- data/lib/mongoid/multi_database.rb +11 -0
- data/lib/mongoid/multi_parameter_attributes.rb +80 -0
- data/lib/mongoid/named_scope.rb +36 -0
- data/lib/mongoid/nested_attributes.rb +43 -0
- data/lib/mongoid/paranoia.rb +103 -0
- data/lib/mongoid/paths.rb +61 -0
- data/lib/mongoid/persistence/command.rb +59 -0
- data/lib/mongoid/persistence/insert.rb +53 -0
- data/lib/mongoid/persistence/insert_embedded.rb +42 -0
- data/lib/mongoid/persistence/remove.rb +44 -0
- data/lib/mongoid/persistence/remove_all.rb +40 -0
- data/lib/mongoid/persistence/remove_embedded.rb +48 -0
- data/lib/mongoid/persistence/update.rb +76 -0
- data/lib/mongoid/persistence.rb +237 -0
- data/lib/mongoid/railtie.rb +129 -0
- data/lib/mongoid/railties/database.rake +171 -0
- data/lib/mongoid/railties/document.rb +12 -0
- data/lib/mongoid/relations/accessors.rb +157 -0
- data/lib/mongoid/relations/auto_save.rb +34 -0
- data/lib/mongoid/relations/binding.rb +26 -0
- data/lib/mongoid/relations/bindings/embedded/in.rb +82 -0
- data/lib/mongoid/relations/bindings/embedded/many.rb +98 -0
- data/lib/mongoid/relations/bindings/embedded/one.rb +66 -0
- data/lib/mongoid/relations/bindings/referenced/in.rb +74 -0
- data/lib/mongoid/relations/bindings/referenced/many.rb +96 -0
- data/lib/mongoid/relations/bindings/referenced/many_to_many.rb +99 -0
- data/lib/mongoid/relations/bindings/referenced/one.rb +66 -0
- data/lib/mongoid/relations/bindings.rb +9 -0
- data/lib/mongoid/relations/builder.rb +42 -0
- data/lib/mongoid/relations/builders/embedded/in.rb +25 -0
- data/lib/mongoid/relations/builders/embedded/many.rb +32 -0
- data/lib/mongoid/relations/builders/embedded/one.rb +26 -0
- data/lib/mongoid/relations/builders/nested_attributes/many.rb +116 -0
- data/lib/mongoid/relations/builders/nested_attributes/one.rb +135 -0
- data/lib/mongoid/relations/builders/referenced/in.rb +32 -0
- data/lib/mongoid/relations/builders/referenced/many.rb +26 -0
- data/lib/mongoid/relations/builders/referenced/many_to_many.rb +29 -0
- data/lib/mongoid/relations/builders/referenced/one.rb +30 -0
- data/lib/mongoid/relations/builders.rb +79 -0
- data/lib/mongoid/relations/cascading/delete.rb +19 -0
- data/lib/mongoid/relations/cascading/destroy.rb +19 -0
- data/lib/mongoid/relations/cascading/nullify.rb +18 -0
- data/lib/mongoid/relations/cascading/strategy.rb +26 -0
- data/lib/mongoid/relations/cascading.rb +55 -0
- data/lib/mongoid/relations/constraint.rb +45 -0
- data/lib/mongoid/relations/cyclic.rb +97 -0
- data/lib/mongoid/relations/embedded/in.rb +173 -0
- data/lib/mongoid/relations/embedded/many.rb +483 -0
- data/lib/mongoid/relations/embedded/one.rb +170 -0
- data/lib/mongoid/relations/macros.rb +306 -0
- data/lib/mongoid/relations/many.rb +171 -0
- data/lib/mongoid/relations/metadata.rb +533 -0
- data/lib/mongoid/relations/nested_builder.rb +68 -0
- data/lib/mongoid/relations/one.rb +47 -0
- data/lib/mongoid/relations/polymorphic.rb +54 -0
- data/lib/mongoid/relations/proxy.rb +128 -0
- data/lib/mongoid/relations/referenced/in.rb +216 -0
- data/lib/mongoid/relations/referenced/many.rb +443 -0
- data/lib/mongoid/relations/referenced/many_to_many.rb +344 -0
- data/lib/mongoid/relations/referenced/one.rb +206 -0
- data/lib/mongoid/relations/reflections.rb +45 -0
- data/lib/mongoid/relations.rb +105 -0
- data/lib/mongoid/safe.rb +23 -0
- data/lib/mongoid/safety.rb +207 -0
- data/lib/mongoid/scope.rb +31 -0
- data/lib/mongoid/serialization.rb +99 -0
- data/lib/mongoid/state.rb +66 -0
- data/lib/mongoid/timestamps.rb +38 -0
- data/lib/mongoid/validations/associated.rb +42 -0
- data/lib/mongoid/validations/uniqueness.rb +85 -0
- data/lib/mongoid/validations.rb +117 -0
- data/lib/mongoid/version.rb +4 -0
- data/lib/mongoid/versioning.rb +51 -0
- data/lib/mongoid.rb +139 -0
- data/lib/rails/generators/mongoid/config/config_generator.rb +25 -0
- data/lib/rails/generators/mongoid/config/templates/mongoid.yml +23 -0
- data/lib/rails/generators/mongoid/model/model_generator.rb +24 -0
- data/lib/rails/generators/mongoid/model/templates/model.rb +17 -0
- data/lib/rails/generators/mongoid_generator.rb +61 -0
- data/lib/rails/mongoid.rb +57 -0
- metadata +380 -0
data/lib/mongoid/safe.rb
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module Mongoid #:nodoc:
|
|
3
|
+
|
|
4
|
+
# Contains behaviour for determining if Mongoid is in safe mode.
|
|
5
|
+
module Safe
|
|
6
|
+
|
|
7
|
+
# Determine based on configuration if we are persisting in safe mode or
|
|
8
|
+
# not.
|
|
9
|
+
#
|
|
10
|
+
# The query option will always override the global configuration.
|
|
11
|
+
#
|
|
12
|
+
# @example Are we in safe mode?
|
|
13
|
+
# document.safe_mode?(:safe => true)
|
|
14
|
+
#
|
|
15
|
+
# @param [ Hash ] options Persistence options.
|
|
16
|
+
#
|
|
17
|
+
# @return [ true, false ] True if in safe mode, false if not.
|
|
18
|
+
def safe_mode?(options)
|
|
19
|
+
safe = options[:safe]
|
|
20
|
+
safe.nil? ? Mongoid.persist_in_safe_mode : safe
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module Mongoid #:nodoc:
|
|
3
|
+
|
|
4
|
+
# The +Safety+ module is used to provide a DSL to execute database operations
|
|
5
|
+
# in safe mode on a per query basis, either from the +Document+ class level
|
|
6
|
+
# or instance level.
|
|
7
|
+
module Safety
|
|
8
|
+
extend ActiveSupport::Concern
|
|
9
|
+
|
|
10
|
+
# Execute the following class-level persistence operation in safe mode.
|
|
11
|
+
#
|
|
12
|
+
# @example Upsert in safe mode.
|
|
13
|
+
# person.safely.upsert
|
|
14
|
+
#
|
|
15
|
+
# @example Destroy in safe mode with w and fsync options.
|
|
16
|
+
# person.safely(:w => 2, :fsync => true).destroy
|
|
17
|
+
#
|
|
18
|
+
# @param [ Hash ] options The safe mode options.
|
|
19
|
+
#
|
|
20
|
+
# @option options [ Integer ] :w The number of nodes to write to.
|
|
21
|
+
# @option options [ Integer ] :wtimeout Time to wait for return from all
|
|
22
|
+
# nodes.
|
|
23
|
+
# @option options [ true, false ] :fsync Should a fsync occur.
|
|
24
|
+
#
|
|
25
|
+
# @return [ Proxy ] The safety proxy.
|
|
26
|
+
def safely(safety = true)
|
|
27
|
+
Proxy.new(self, safety)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
module ClassMethods #:nodoc:
|
|
31
|
+
|
|
32
|
+
# Execute the following class-level persistence operation in safe mode.
|
|
33
|
+
#
|
|
34
|
+
# @example Create in safe mode.
|
|
35
|
+
# Person.safely.create(:name => "John")
|
|
36
|
+
#
|
|
37
|
+
# @example Delete all in safe mode with options.
|
|
38
|
+
# Person.safely(:w => 2, :fsync => true).delete_all
|
|
39
|
+
#
|
|
40
|
+
# @param [ Hash ] options The safe mode options.
|
|
41
|
+
#
|
|
42
|
+
# @option options [ Integer ] :w The number of nodes to write to.
|
|
43
|
+
# @option options [ Integer ] :wtimeout Time to wait for return from all
|
|
44
|
+
# nodes.
|
|
45
|
+
# @option options [ true, false ] :fsync Should a fsync occur.
|
|
46
|
+
#
|
|
47
|
+
# @return [ Proxy ] The safety proxy.
|
|
48
|
+
def safely(safety = true)
|
|
49
|
+
Proxy.new(self, safety)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# When this class proxies a document or class, the next persistence
|
|
54
|
+
# operation executed on it will query in safe mode.
|
|
55
|
+
#
|
|
56
|
+
# Operations that took a hash of attributes had to be somewhat duplicated
|
|
57
|
+
# here since we do not want to allow a :safe attribute to be included in
|
|
58
|
+
# the args. This is because safe could be a common attribute name and we
|
|
59
|
+
# don't want the collision between the attribute and determining whether or
|
|
60
|
+
# not safe mode is allowed.
|
|
61
|
+
class Proxy
|
|
62
|
+
|
|
63
|
+
attr_reader :target, :safety_options
|
|
64
|
+
|
|
65
|
+
# Create a new +Document+. This will instantiate a new document and
|
|
66
|
+
# insert it in a single call. Will always return the document
|
|
67
|
+
# whether save passed or not.
|
|
68
|
+
#
|
|
69
|
+
# @example Safely create a document.
|
|
70
|
+
# Person.safely.create(:title => "Mr")
|
|
71
|
+
#
|
|
72
|
+
# @param [ Hash ] attributes The attributes to create with.
|
|
73
|
+
#
|
|
74
|
+
# @return [ Document ] The new document.
|
|
75
|
+
def create(attributes = {})
|
|
76
|
+
target.new(attributes).tap { |doc| doc.insert(:safe => safety_options) }
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Create a new +Document+. This will instantiate a new document and
|
|
80
|
+
# insert it in a single call. Will always return the document
|
|
81
|
+
# whether save passed or not, and if validation fails an error will be
|
|
82
|
+
# raise.
|
|
83
|
+
#
|
|
84
|
+
# @example Safely create a document.
|
|
85
|
+
# Person.safely.create!(:title => "Mr")
|
|
86
|
+
#
|
|
87
|
+
# @param [ Hash ] attributes The attributes to create with.
|
|
88
|
+
#
|
|
89
|
+
# @raise [ Errors::Validations ] If validation failed.
|
|
90
|
+
#
|
|
91
|
+
# @return [ Document ] If validation passed.
|
|
92
|
+
def create!(attributes = {})
|
|
93
|
+
target.new(attributes).tap do |document|
|
|
94
|
+
fail_validate!(document) if document.insert(:safe => safety_options).errors.any?
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Delete all documents given the supplied conditions. If no conditions
|
|
99
|
+
# are passed, the entire collection will be dropped for performance
|
|
100
|
+
# benefits. Does not fire any callbacks.
|
|
101
|
+
#
|
|
102
|
+
# @example Delete all documents.
|
|
103
|
+
# Person.safely.delete_all
|
|
104
|
+
#
|
|
105
|
+
# @example Conditionally delete all documents.
|
|
106
|
+
# Person.safely.delete_all(:conditions => { :title => "Sir" })
|
|
107
|
+
#
|
|
108
|
+
# @param [ Hash ] conditions The conditions to delete with.
|
|
109
|
+
#
|
|
110
|
+
# @return [ Integer ] The number of documents deleted.
|
|
111
|
+
def delete_all(conditions = {})
|
|
112
|
+
Mongoid::Persistence::RemoveAll.new(
|
|
113
|
+
target,
|
|
114
|
+
{ :validate => false, :safe => safety_options },
|
|
115
|
+
conditions[:conditions] || {}
|
|
116
|
+
).persist
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# destroy all documents given the supplied conditions. If no conditions
|
|
120
|
+
# are passed, the entire collection will be dropped for performance
|
|
121
|
+
# benefits. Fires the destroy callbacks if conditions were passed.
|
|
122
|
+
#
|
|
123
|
+
# @example destroy all documents.
|
|
124
|
+
# Person.safely.destroy_all
|
|
125
|
+
#
|
|
126
|
+
# @example Conditionally destroy all documents.
|
|
127
|
+
# Person.safely.destroy_all(:conditions => { :title => "Sir" })
|
|
128
|
+
#
|
|
129
|
+
# @param [ Hash ] conditions The conditions to destroy with.
|
|
130
|
+
#
|
|
131
|
+
# @return [ Integer ] The number of documents destroyd.
|
|
132
|
+
def destroy_all(conditions = {})
|
|
133
|
+
documents = target.all(conditions)
|
|
134
|
+
documents.count.tap do |count|
|
|
135
|
+
documents.each { |doc| doc.destroy(:safe => safety_options) }
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# Increment the field by the provided value, else if it doesn't exists set
|
|
140
|
+
# it to that value.
|
|
141
|
+
#
|
|
142
|
+
# @example Safely increment a field.
|
|
143
|
+
# person.safely.inc(:age, 1)
|
|
144
|
+
#
|
|
145
|
+
# @param [ Symbol, String ] field The field to increment.
|
|
146
|
+
# @param [ Integer ] value The value to increment by.
|
|
147
|
+
# @param [ Hash ] options Options to pass through to the driver.
|
|
148
|
+
def inc(field, value, options = {})
|
|
149
|
+
target.inc(field, value, :safe => safety_options)
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# Create the new +Proxy+.
|
|
153
|
+
#
|
|
154
|
+
# @example Create the proxy.
|
|
155
|
+
# Proxy.new(document, :w => 3)
|
|
156
|
+
#
|
|
157
|
+
# @param [ Document, Class ] target Either the class or the instance.
|
|
158
|
+
# @param [ true, Hash ] safety_options The options.
|
|
159
|
+
def initialize(target, safety_options)
|
|
160
|
+
@target = target
|
|
161
|
+
@safety_options = safety_options
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# We will use method missing to proxy calls to the target.
|
|
165
|
+
#
|
|
166
|
+
# @example Save safely.
|
|
167
|
+
# person.safely.save
|
|
168
|
+
#
|
|
169
|
+
# @param [ Array ] *args The arguments to pass on.
|
|
170
|
+
def method_missing(*args)
|
|
171
|
+
name = args[0]
|
|
172
|
+
attributes = args[1] || {}
|
|
173
|
+
target.send(name, attributes.merge(:safe => safety_options))
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# Update the +Document+ attributes in the datbase.
|
|
177
|
+
#
|
|
178
|
+
# @example Safely update attributes.
|
|
179
|
+
# person.safely.update_attributes(:title => "Sir")
|
|
180
|
+
#
|
|
181
|
+
# @param [ Hash ] attributes The attributes to update.
|
|
182
|
+
#
|
|
183
|
+
# @return [ true, false ] Whether the document was saved.
|
|
184
|
+
def update_attributes(attributes = {})
|
|
185
|
+
target.write_attributes(attributes)
|
|
186
|
+
target.update(:safe => safety_options)
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# Update the +Document+ attributes in the datbase.
|
|
190
|
+
#
|
|
191
|
+
# @example Safely update attributes.
|
|
192
|
+
# person.safely.update_attributes(:title => "Sir")
|
|
193
|
+
#
|
|
194
|
+
# @param [ Hash ] attributes The attributes to update.
|
|
195
|
+
#
|
|
196
|
+
# @raise [ Errors::Validations ] If validation failed.
|
|
197
|
+
#
|
|
198
|
+
# @return [ true ] If the document was saved.
|
|
199
|
+
def update_attributes!(attributes = {})
|
|
200
|
+
target.write_attributes(attributes)
|
|
201
|
+
update(:safe => safety_options).tap do |result|
|
|
202
|
+
target.class.fail_validate!(target) unless result
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module Mongoid #:nodoc:
|
|
3
|
+
# This module handles behaviour for defining scopes on classes.
|
|
4
|
+
class Scope
|
|
5
|
+
attr_reader :conditions, :extensions
|
|
6
|
+
|
|
7
|
+
# Create the new +Scope+. If a block is passed in, this Scope will store
|
|
8
|
+
# the block for future calls to #extend.
|
|
9
|
+
#
|
|
10
|
+
# @example Create a new scope.
|
|
11
|
+
# Scope.new(:title => "Sir")
|
|
12
|
+
#
|
|
13
|
+
# @param [ Hash ] conditions The scoping limitations.
|
|
14
|
+
def initialize(conditions = {}, &block)
|
|
15
|
+
@conditions = conditions
|
|
16
|
+
@extensions = Module.new(&block) if block_given?
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Extend a supplied criteria.
|
|
20
|
+
#
|
|
21
|
+
# @example Extend the criteria.
|
|
22
|
+
# scope.extend(criteria)
|
|
23
|
+
#
|
|
24
|
+
# @param [ Criteria } criteria A mongoid criteria to extend.
|
|
25
|
+
#
|
|
26
|
+
# @return [ Criteria ] The new criteria object.
|
|
27
|
+
def extend(criteria)
|
|
28
|
+
extensions ? criteria.extend(extensions) : criteria
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module Mongoid # :nodoc:
|
|
3
|
+
|
|
4
|
+
# This module provides the extra behaviour for including relations in JSON
|
|
5
|
+
# and XML serialization.
|
|
6
|
+
module Serialization
|
|
7
|
+
extend ActiveSupport::Concern
|
|
8
|
+
include ActiveModel::Serialization
|
|
9
|
+
|
|
10
|
+
# Gets the document as a serializable hash, used by ActiveModel's JSON and
|
|
11
|
+
# XML serializers. This override is just to be able to pass the :include
|
|
12
|
+
# and :except options to get associations in the hash.
|
|
13
|
+
#
|
|
14
|
+
# @example Get the serializable hash.
|
|
15
|
+
# document.serializable_hash
|
|
16
|
+
#
|
|
17
|
+
# @example Get the serializable hash with options.
|
|
18
|
+
# document.serializable_hash(:include => :addresses)
|
|
19
|
+
#
|
|
20
|
+
# @param [ Hash ] options The options to pass.
|
|
21
|
+
#
|
|
22
|
+
# @option options [ Symbol ] :include What relations to include
|
|
23
|
+
# @option options [ Symbol ] :only Limit the fields to only these.
|
|
24
|
+
# @option options [ Symbol ] :except Dont include these fields.
|
|
25
|
+
#
|
|
26
|
+
# @return [ Hash ] The document, ready to be serialized.
|
|
27
|
+
#
|
|
28
|
+
# @since 2.0.0.rc.6
|
|
29
|
+
def serializable_hash(options = nil)
|
|
30
|
+
options ||= {}
|
|
31
|
+
super(options).tap do |attrs|
|
|
32
|
+
serialize_relations(attrs, options) if options[:include]
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
# For each of the provided include options, get the relation needed and
|
|
39
|
+
# provide it in the hash.
|
|
40
|
+
#
|
|
41
|
+
# @example Serialize the included relations.
|
|
42
|
+
# document.serialize_relations({}, :include => :addresses)
|
|
43
|
+
#
|
|
44
|
+
# @param [ Hash ] attributes The attributes to serialize.
|
|
45
|
+
# @param [ Hash ] options The serialization options.
|
|
46
|
+
#
|
|
47
|
+
# @option options [ Symbol ] :include What relations to include
|
|
48
|
+
# @option options [ Symbol ] :only Limit the fields to only these.
|
|
49
|
+
# @option options [ Symbol ] :except Dont include these fields.
|
|
50
|
+
#
|
|
51
|
+
# @since 2.0.0.rc.6
|
|
52
|
+
def serialize_relations(attributes = {}, options = {})
|
|
53
|
+
inclusions = options.delete(:include)
|
|
54
|
+
relation_names(inclusions).each do |name|
|
|
55
|
+
metadata = relations[name.to_s]
|
|
56
|
+
relation = send(metadata.name, false, :eager => true)
|
|
57
|
+
if relation
|
|
58
|
+
attributes[metadata.name.to_s] =
|
|
59
|
+
relation.serializable_hash(relation_options(inclusions, options, name))
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Since the inclusions can be a hash, symbol, or array of symbols, this is
|
|
65
|
+
# provided as a convenience to parse out the names.
|
|
66
|
+
#
|
|
67
|
+
# @example Get the relation names.
|
|
68
|
+
# document.relation_names(:include => [ :addresses ])
|
|
69
|
+
#
|
|
70
|
+
# @param [ Hash, Symbol, Array<Symbol ] inclusions The inclusions.
|
|
71
|
+
#
|
|
72
|
+
# @return [ Array<Symbol> ] The names of the included relations.
|
|
73
|
+
#
|
|
74
|
+
# @since 2.0.0.rc.6
|
|
75
|
+
def relation_names(inclusions)
|
|
76
|
+
inclusions.is_a?(Hash) ? inclusions.keys : Array.wrap(inclusions)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Since the inclusions can be a hash, symbol, or array of symbols, this is
|
|
80
|
+
# provided as a convenience to parse out the options.
|
|
81
|
+
#
|
|
82
|
+
# @example Get the relation options.
|
|
83
|
+
# document.relation_names(:include => [ :addresses ])
|
|
84
|
+
#
|
|
85
|
+
# @param [ Hash, Symbol, Array<Symbol ] inclusions The inclusions.
|
|
86
|
+
# @param [ Symbol ] name The name of the relation.
|
|
87
|
+
#
|
|
88
|
+
# @return [ Hash ] The options for the relation.
|
|
89
|
+
#
|
|
90
|
+
# @since 2.0.0.rc.6
|
|
91
|
+
def relation_options(inclusions, options, name)
|
|
92
|
+
if inclusions.is_a?(Hash)
|
|
93
|
+
inclusions[name]
|
|
94
|
+
else
|
|
95
|
+
{ :except => options[:except], :only => options[:only] }
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module Mongoid #:nodoc:
|
|
3
|
+
|
|
4
|
+
# This module contains the behaviour for getting the various states a
|
|
5
|
+
# document can transition through.
|
|
6
|
+
module State
|
|
7
|
+
|
|
8
|
+
# Returns true if the +Document+ has not been persisted to the database,
|
|
9
|
+
# false if it has. This is determined by the variable @new_record
|
|
10
|
+
# and NOT if the object has an id.
|
|
11
|
+
#
|
|
12
|
+
# @example Is the document new?
|
|
13
|
+
# person.new_record?
|
|
14
|
+
#
|
|
15
|
+
# @return [ true, false ] True if new, false if not.
|
|
16
|
+
def new_record?
|
|
17
|
+
@new_record == true
|
|
18
|
+
end
|
|
19
|
+
alias :new? :new_record?
|
|
20
|
+
|
|
21
|
+
# Sets the new_record boolean - used after document is saved.
|
|
22
|
+
#
|
|
23
|
+
# @example Set whether the document is new.
|
|
24
|
+
# person.new_record = true
|
|
25
|
+
#
|
|
26
|
+
# @param [ true, false ] saved The value to set for new_record.
|
|
27
|
+
#
|
|
28
|
+
# @return [ true, false ] The new_record value.
|
|
29
|
+
def new_record=(saved)
|
|
30
|
+
@new_record = saved
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Checks if the document has been saved to the database.
|
|
34
|
+
#
|
|
35
|
+
# @example Is the document persisted?
|
|
36
|
+
# person.persisted?
|
|
37
|
+
#
|
|
38
|
+
# @return [ true, false ] True if persisted, false if not.
|
|
39
|
+
def persisted?
|
|
40
|
+
!new_record?
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Returns true if the +Document+ has been succesfully destroyed, and false
|
|
44
|
+
# if it hasn't. This is determined by the variable @destroyed and NOT
|
|
45
|
+
# by checking the database.
|
|
46
|
+
#
|
|
47
|
+
# @example Is the document destroyed?
|
|
48
|
+
# person.destroyed?
|
|
49
|
+
#
|
|
50
|
+
# @return [ true, false ] True if destroyed, false if not.
|
|
51
|
+
def destroyed?
|
|
52
|
+
@destroyed == true
|
|
53
|
+
end
|
|
54
|
+
alias :deleted? :destroyed?
|
|
55
|
+
|
|
56
|
+
# Sets the destroyed boolean - used after document is destroyed.
|
|
57
|
+
#
|
|
58
|
+
# @example Set the destroyed flag.
|
|
59
|
+
# person.destroyed = true
|
|
60
|
+
#
|
|
61
|
+
# @return [ true, false ] The value set for destroyed.
|
|
62
|
+
def destroyed=(destroyed)
|
|
63
|
+
@destroyed = destroyed && true
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module Mongoid #:nodoc:
|
|
3
|
+
|
|
4
|
+
# This module handles the behaviour for setting up document created at and
|
|
5
|
+
# updated at timestamps.
|
|
6
|
+
module Timestamps
|
|
7
|
+
extend ActiveSupport::Concern
|
|
8
|
+
|
|
9
|
+
included do
|
|
10
|
+
field :created_at, :type => Time
|
|
11
|
+
field :updated_at, :type => Time
|
|
12
|
+
|
|
13
|
+
set_callback :create, :before, :set_created_at
|
|
14
|
+
set_callback :save, :before, :set_updated_at
|
|
15
|
+
|
|
16
|
+
class_attribute :record_timestamps
|
|
17
|
+
self.record_timestamps = true
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Update the created_at field on the Document to the current time. This is
|
|
21
|
+
# only called on create.
|
|
22
|
+
#
|
|
23
|
+
# @example Set the created at time.
|
|
24
|
+
# person.set_created_at
|
|
25
|
+
def set_created_at
|
|
26
|
+
self.created_at = Time.now.utc if !created_at
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Update the updated_at field on the Document to the current time.
|
|
30
|
+
# This is only called on create and on save.
|
|
31
|
+
#
|
|
32
|
+
# @example Set the updated at time.
|
|
33
|
+
# person.set_updated_at
|
|
34
|
+
def set_updated_at
|
|
35
|
+
self.updated_at = Time.now.utc
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module Mongoid #:nodoc:
|
|
3
|
+
module Validations #:nodoc:
|
|
4
|
+
|
|
5
|
+
# Validates whether or not an association is valid or not. Will correctly
|
|
6
|
+
# handle has one and has many associations.
|
|
7
|
+
#
|
|
8
|
+
# @example Set up the association validations.
|
|
9
|
+
#
|
|
10
|
+
# class Person
|
|
11
|
+
# include Mongoid::Document
|
|
12
|
+
# embeds_one :name
|
|
13
|
+
# embeds_many :addresses
|
|
14
|
+
#
|
|
15
|
+
# validates_associated :name, :addresses
|
|
16
|
+
# end
|
|
17
|
+
class AssociatedValidator < ActiveModel::EachValidator
|
|
18
|
+
|
|
19
|
+
# Validates that the associations provided are either all nil or all
|
|
20
|
+
# valid. If neither is true then the appropriate errors will be added to
|
|
21
|
+
# the parent document.
|
|
22
|
+
#
|
|
23
|
+
# @example Validate the association.
|
|
24
|
+
# validator.validate_each(document, :name, name)
|
|
25
|
+
#
|
|
26
|
+
# @param [ Document ] document The document to validate.
|
|
27
|
+
# @param [ Symbol ] attribute The relation to validate.
|
|
28
|
+
# @param [ Object ] value The value of the relation.
|
|
29
|
+
def validate_each(document, attribute, value)
|
|
30
|
+
unless document.validated?
|
|
31
|
+
document.validated = true
|
|
32
|
+
valid = value.to_a.collect { |doc| doc.nil? || doc.valid? }.all?
|
|
33
|
+
document.validated = false
|
|
34
|
+
return if valid
|
|
35
|
+
document.errors.add(attribute, :invalid, options.merge(:value => value))
|
|
36
|
+
else
|
|
37
|
+
document.validated = false
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module Mongoid #:nodoc:
|
|
3
|
+
module Validations #:nodoc:
|
|
4
|
+
|
|
5
|
+
# Validates whether or not a field is unique against the documents in the
|
|
6
|
+
# database.
|
|
7
|
+
#
|
|
8
|
+
# @example Define the uniqueness validator.
|
|
9
|
+
#
|
|
10
|
+
# class Person
|
|
11
|
+
# include Mongoid::Document
|
|
12
|
+
# field :title
|
|
13
|
+
#
|
|
14
|
+
# validates_uniqueness_of :title
|
|
15
|
+
# end
|
|
16
|
+
class UniquenessValidator < ActiveModel::EachValidator
|
|
17
|
+
|
|
18
|
+
# Unfortunately, we have to tie Uniqueness validators to a class.
|
|
19
|
+
def setup(klass)
|
|
20
|
+
@klass = klass
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Validate the document for uniqueness violations.
|
|
24
|
+
#
|
|
25
|
+
# @example Validate the document.
|
|
26
|
+
# validate_each(person, :title, "Sir")
|
|
27
|
+
#
|
|
28
|
+
# @param [ Document ] document The document to validate.
|
|
29
|
+
# @param [ Symbol ] attribute The field to validate on.
|
|
30
|
+
# @param [ Object ] value The value of the field.
|
|
31
|
+
#
|
|
32
|
+
# @todo Durran: This method needs refactoring.
|
|
33
|
+
def validate_each(document, attribute, value)
|
|
34
|
+
if document.embedded?
|
|
35
|
+
return if document._parent.nil?
|
|
36
|
+
criteria = document._parent.send(document.metadata.name)
|
|
37
|
+
# If the parent document embeds_one, no need to validate uniqueness
|
|
38
|
+
return if criteria.is_a?(Mongoid::Document)
|
|
39
|
+
criteria = criteria.where(attribute => unique_search_value(value), :_id => {'$ne' => document._id})
|
|
40
|
+
else
|
|
41
|
+
criteria = @klass.where(attribute => unique_search_value(value))
|
|
42
|
+
unless document.new_record?
|
|
43
|
+
criteria = criteria.where(:_id => {'$ne' => document._id})
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
Array.wrap(options[:scope]).each do |item|
|
|
48
|
+
criteria = criteria.where(item => document.attributes[item])
|
|
49
|
+
end
|
|
50
|
+
if criteria.exists?
|
|
51
|
+
document.errors.add(
|
|
52
|
+
attribute,
|
|
53
|
+
:taken,
|
|
54
|
+
options.except(:case_sensistive, :scope).merge(:value => value)
|
|
55
|
+
)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
protected
|
|
60
|
+
|
|
61
|
+
# Determine if the primary key has changed on the document.
|
|
62
|
+
#
|
|
63
|
+
# @example Has the key changed?
|
|
64
|
+
# key_changed?(document)
|
|
65
|
+
#
|
|
66
|
+
# @param [ Document ] document The document to check.
|
|
67
|
+
#
|
|
68
|
+
# @return [ true, false ] True if changed, false if not.
|
|
69
|
+
def key_changed?(document)
|
|
70
|
+
(document.primary_key || {}).each do |key|
|
|
71
|
+
return true if document.send("#{key}_changed?")
|
|
72
|
+
end; false
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# ensure :case_sensitive is true by default
|
|
76
|
+
def unique_search_value(value)
|
|
77
|
+
if options[:case_sensitive] == false
|
|
78
|
+
value ? Regexp.new("^#{Regexp.escape(value.to_s)}$", Regexp::IGNORECASE) : nil
|
|
79
|
+
else
|
|
80
|
+
value
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|