chhean-mongoid 2.0.1.beta1

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.
Files changed (117) hide show
  1. data/MIT_LICENSE +20 -0
  2. data/README.rdoc +49 -0
  3. data/lib/mongoid.rb +139 -0
  4. data/lib/mongoid/associations.rb +327 -0
  5. data/lib/mongoid/associations/embedded_in.rb +72 -0
  6. data/lib/mongoid/associations/embeds_many.rb +262 -0
  7. data/lib/mongoid/associations/embeds_one.rb +95 -0
  8. data/lib/mongoid/associations/foreign_key.rb +35 -0
  9. data/lib/mongoid/associations/meta_data.rb +29 -0
  10. data/lib/mongoid/associations/options.rb +73 -0
  11. data/lib/mongoid/associations/proxy.rb +33 -0
  12. data/lib/mongoid/associations/referenced_in.rb +71 -0
  13. data/lib/mongoid/associations/references_many.rb +243 -0
  14. data/lib/mongoid/associations/references_many_as_array.rb +78 -0
  15. data/lib/mongoid/associations/references_one.rb +116 -0
  16. data/lib/mongoid/attributes.rb +226 -0
  17. data/lib/mongoid/callbacks.rb +17 -0
  18. data/lib/mongoid/collection.rb +120 -0
  19. data/lib/mongoid/collections.rb +41 -0
  20. data/lib/mongoid/collections/cyclic_iterator.rb +34 -0
  21. data/lib/mongoid/collections/master.rb +29 -0
  22. data/lib/mongoid/collections/operations.rb +41 -0
  23. data/lib/mongoid/collections/slaves.rb +45 -0
  24. data/lib/mongoid/components.rb +32 -0
  25. data/lib/mongoid/config.rb +237 -0
  26. data/lib/mongoid/contexts.rb +24 -0
  27. data/lib/mongoid/contexts/enumerable.rb +151 -0
  28. data/lib/mongoid/contexts/ids.rb +25 -0
  29. data/lib/mongoid/contexts/mongo.rb +285 -0
  30. data/lib/mongoid/contexts/paging.rb +50 -0
  31. data/lib/mongoid/criteria.rb +230 -0
  32. data/lib/mongoid/criterion/complex.rb +21 -0
  33. data/lib/mongoid/criterion/exclusion.rb +65 -0
  34. data/lib/mongoid/criterion/inclusion.rb +110 -0
  35. data/lib/mongoid/criterion/optional.rb +136 -0
  36. data/lib/mongoid/cursor.rb +82 -0
  37. data/lib/mongoid/deprecation.rb +22 -0
  38. data/lib/mongoid/dirty.rb +254 -0
  39. data/lib/mongoid/document.rb +264 -0
  40. data/lib/mongoid/errors.rb +124 -0
  41. data/lib/mongoid/extensions.rb +106 -0
  42. data/lib/mongoid/extensions/array/accessors.rb +17 -0
  43. data/lib/mongoid/extensions/array/aliasing.rb +4 -0
  44. data/lib/mongoid/extensions/array/assimilation.rb +26 -0
  45. data/lib/mongoid/extensions/array/conversions.rb +27 -0
  46. data/lib/mongoid/extensions/array/parentization.rb +13 -0
  47. data/lib/mongoid/extensions/big_decimal/conversions.rb +19 -0
  48. data/lib/mongoid/extensions/binary/conversions.rb +17 -0
  49. data/lib/mongoid/extensions/boolean/conversions.rb +22 -0
  50. data/lib/mongoid/extensions/date/conversions.rb +24 -0
  51. data/lib/mongoid/extensions/datetime/conversions.rb +12 -0
  52. data/lib/mongoid/extensions/float/conversions.rb +20 -0
  53. data/lib/mongoid/extensions/hash/accessors.rb +38 -0
  54. data/lib/mongoid/extensions/hash/assimilation.rb +39 -0
  55. data/lib/mongoid/extensions/hash/conversions.rb +45 -0
  56. data/lib/mongoid/extensions/hash/criteria_helpers.rb +20 -0
  57. data/lib/mongoid/extensions/hash/scoping.rb +12 -0
  58. data/lib/mongoid/extensions/integer/conversions.rb +20 -0
  59. data/lib/mongoid/extensions/nil/assimilation.rb +17 -0
  60. data/lib/mongoid/extensions/object/conversions.rb +27 -0
  61. data/lib/mongoid/extensions/objectid/conversions.rb +15 -0
  62. data/lib/mongoid/extensions/proc/scoping.rb +12 -0
  63. data/lib/mongoid/extensions/set/conversions.rb +20 -0
  64. data/lib/mongoid/extensions/string/conversions.rb +15 -0
  65. data/lib/mongoid/extensions/string/inflections.rb +97 -0
  66. data/lib/mongoid/extensions/symbol/inflections.rb +39 -0
  67. data/lib/mongoid/extensions/time_conversions.rb +35 -0
  68. data/lib/mongoid/extras.rb +61 -0
  69. data/lib/mongoid/factory.rb +20 -0
  70. data/lib/mongoid/field.rb +80 -0
  71. data/lib/mongoid/fields.rb +61 -0
  72. data/lib/mongoid/finders.rb +144 -0
  73. data/lib/mongoid/identity.rb +39 -0
  74. data/lib/mongoid/indexes.rb +27 -0
  75. data/lib/mongoid/javascript.rb +21 -0
  76. data/lib/mongoid/javascript/functions.yml +37 -0
  77. data/lib/mongoid/matchers.rb +35 -0
  78. data/lib/mongoid/matchers/all.rb +11 -0
  79. data/lib/mongoid/matchers/default.rb +26 -0
  80. data/lib/mongoid/matchers/exists.rb +13 -0
  81. data/lib/mongoid/matchers/gt.rb +11 -0
  82. data/lib/mongoid/matchers/gte.rb +11 -0
  83. data/lib/mongoid/matchers/in.rb +11 -0
  84. data/lib/mongoid/matchers/lt.rb +11 -0
  85. data/lib/mongoid/matchers/lte.rb +11 -0
  86. data/lib/mongoid/matchers/ne.rb +11 -0
  87. data/lib/mongoid/matchers/nin.rb +11 -0
  88. data/lib/mongoid/matchers/size.rb +11 -0
  89. data/lib/mongoid/memoization.rb +33 -0
  90. data/lib/mongoid/named_scope.rb +37 -0
  91. data/lib/mongoid/observable.rb +30 -0
  92. data/lib/mongoid/paths.rb +62 -0
  93. data/lib/mongoid/persistence.rb +218 -0
  94. data/lib/mongoid/persistence/command.rb +39 -0
  95. data/lib/mongoid/persistence/insert.rb +47 -0
  96. data/lib/mongoid/persistence/insert_embedded.rb +38 -0
  97. data/lib/mongoid/persistence/remove.rb +39 -0
  98. data/lib/mongoid/persistence/remove_all.rb +37 -0
  99. data/lib/mongoid/persistence/remove_embedded.rb +50 -0
  100. data/lib/mongoid/persistence/update.rb +63 -0
  101. data/lib/mongoid/railtie.rb +54 -0
  102. data/lib/mongoid/railties/database.rake +37 -0
  103. data/lib/mongoid/scope.rb +75 -0
  104. data/lib/mongoid/state.rb +32 -0
  105. data/lib/mongoid/timestamps.rb +27 -0
  106. data/lib/mongoid/validations.rb +51 -0
  107. data/lib/mongoid/validations/associated.rb +32 -0
  108. data/lib/mongoid/validations/locale/en.yml +4 -0
  109. data/lib/mongoid/validations/uniqueness.rb +50 -0
  110. data/lib/mongoid/version.rb +4 -0
  111. data/lib/mongoid/versioning.rb +27 -0
  112. data/lib/rails/generators/mongoid/config/config_generator.rb +41 -0
  113. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +24 -0
  114. data/lib/rails/generators/mongoid/model/model_generator.rb +24 -0
  115. data/lib/rails/generators/mongoid/model/templates/model.rb +15 -0
  116. data/lib/rails/generators/mongoid_generator.rb +61 -0
  117. metadata +284 -0
@@ -0,0 +1,72 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Associations #:nodoc:
4
+ # Represents an association that is embedded within another document in the
5
+ # database, either as one or many.
6
+ class EmbeddedIn < Proxy
7
+
8
+ # Creates the new association by setting the internal
9
+ # target as the passed in Document. This should be the
10
+ # parent.
11
+ #
12
+ # All method calls on this object will then be delegated
13
+ # to the internal document itself.
14
+ #
15
+ # Options:
16
+ #
17
+ # target: The parent +Document+
18
+ # options: The association options
19
+ def initialize(target, options)
20
+ @target, @options = target, options
21
+ extends(options)
22
+ end
23
+
24
+ # Returns the parent document. The id param is present for
25
+ # compatibility with rails, however this could be overwritten
26
+ # in the future.
27
+ def find(id)
28
+ @target
29
+ end
30
+
31
+ class << self
32
+ # Creates the new association by setting the internal
33
+ # document as the passed in Document. This should be the
34
+ # parent.
35
+ #
36
+ # Options:
37
+ #
38
+ # document: The parent +Document+
39
+ # options: The association options
40
+ def instantiate(document, options)
41
+ target = document._parent
42
+ target.nil? ? nil : new(target, options)
43
+ end
44
+
45
+ # Returns the macro used to create the association.
46
+ def macro
47
+ :embedded_in
48
+ end
49
+
50
+ # Perform an update of the relationship of the parent and child. This
51
+ # is initialized by setting a parent object as the association on the
52
+ # +Document+. Will properly set an embeds_one or an embeds_many.
53
+ #
54
+ # Returns:
55
+ #
56
+ # A new +EmbeddedIn+ association proxy.
57
+ def update(target, child, options)
58
+ child.parentize(target, determine_name(target, options))
59
+ child.notify
60
+ instantiate(child, options)
61
+ end
62
+
63
+ protected
64
+ def determine_name(target, options)
65
+ inverse = options.inverse_of
66
+ return inverse unless inverse.is_a?(Array)
67
+ inverse.detect { |name| target.respond_to?(name) }
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,262 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Associations #:nodoc:
4
+ # Represents embedding many documents within a parent document, which will
5
+ # be an array as the underlying storage mechanism.
6
+ class EmbedsMany < Proxy
7
+
8
+ attr_accessor :association_name, :klass
9
+
10
+ # Appends the object to the +Array+, setting its parent in
11
+ # the process.
12
+ def <<(*documents)
13
+ documents.flatten.each do |doc|
14
+ doc.parentize(@parent, @association_name)
15
+ @target << doc
16
+ doc._index = @target.size - 1
17
+ doc.notify
18
+ end
19
+ end
20
+
21
+ alias :concat :<<
22
+ alias :push :<<
23
+
24
+ # Builds a new Document and adds it to the association collection. The
25
+ # document created will be of the same class as the others in the
26
+ # association, and the attributes will be passed into the constructor.
27
+ #
28
+ # Returns:
29
+ #
30
+ # The newly created Document.
31
+ def build(attrs = {}, type = nil)
32
+ document = type ? type.instantiate : @klass.instantiate
33
+ document.parentize(@parent, @association_name)
34
+ document.write_attributes(attrs)
35
+ @target << document
36
+ document._index = @target.size - 1
37
+ document
38
+ end
39
+
40
+ # Clears the association, and notifies the parents of the removal.
41
+ def clear
42
+ unless @target.empty?
43
+ document = @target.first
44
+ document.notify_observers(document, true)
45
+ @target.clear
46
+ end
47
+ end
48
+
49
+ # Creates a new Document and adds it to the association collection. The
50
+ # document created will be of the same class as the others in the
51
+ # association, and the attributes will be passed into the constructor and
52
+ # the new object will then be saved.
53
+ #
54
+ # Returns:
55
+ #
56
+ # The newly created Document.
57
+ def create(attrs = {}, type = nil)
58
+ build(attrs, type).tap(&:save)
59
+ end
60
+
61
+ # Creates a new Document and adds it to the association collection. The
62
+ # document created will be of the same class as the others in the
63
+ # association, and the attributes will be passed into the constructor and
64
+ # the new object will then be saved. If validation fails an error will
65
+ # get raised.
66
+ #
67
+ # Returns:
68
+ #
69
+ # The newly created Document.
70
+ def create!(attrs = {}, type = nil)
71
+ document = create(attrs, type)
72
+ errors = document.errors
73
+ raise Errors::Validations.new(errors) unless errors.empty?
74
+ document
75
+ end
76
+
77
+ # Delete all the documents in the association without running callbacks.
78
+ #
79
+ # Example:
80
+ #
81
+ # <tt>addresses.delete_all</tt>
82
+ #
83
+ # Returns:
84
+ #
85
+ # The number of documents deleted.
86
+ def delete_all(conditions = {})
87
+ remove(:delete, conditions)
88
+ end
89
+
90
+ # Delete all the documents in the association and run destroy callbacks.
91
+ #
92
+ # Example:
93
+ #
94
+ # <tt>addresses.destroy_all</tt>
95
+ #
96
+ # Returns:
97
+ #
98
+ # The number of documents destroyed.
99
+ def destroy_all(conditions = {})
100
+ remove(:destroy, conditions)
101
+ end
102
+
103
+ # Finds a document in this association.
104
+ #
105
+ # If :all is passed, returns all the documents
106
+ #
107
+ # If an id is passed, will return the document for that id.
108
+ #
109
+ # Returns:
110
+ #
111
+ # Array or single Document.
112
+ def find(param)
113
+ return @target if param == :all
114
+ return detect { |document| document.id == param }
115
+ end
116
+
117
+ # Creates the new association by finding the attributes in
118
+ # the parent document with its name, and instantiating a
119
+ # new document for each one found. These will then be put in an
120
+ # internal array.
121
+ #
122
+ # This then delegated all methods to the array class since this is
123
+ # essentially a proxy to an array itself.
124
+ #
125
+ # Options:
126
+ #
127
+ # parent: The parent document to the association.
128
+ # options: The association options.
129
+ def initialize(parent, options, target_array = nil)
130
+ @parent, @association_name = parent, options.name
131
+ @klass, @options = options.klass, options
132
+ if target_array
133
+ build_children_from_target_array(target_array)
134
+ else
135
+ build_children_from_attributes(parent.raw_attributes[@association_name])
136
+ end
137
+ extends(options)
138
+ end
139
+
140
+
141
+
142
+ # If the target array does not respond to the supplied method then try to
143
+ # find a named scope or criteria on the class and send the call there.
144
+ #
145
+ # If the method exists on the array, use the default proxy behavior.
146
+ def method_missing(name, *args, &block)
147
+ unless @target.respond_to?(name)
148
+ object = @klass.send(name, *args)
149
+ object.documents = @target
150
+ return object
151
+ end
152
+ super
153
+ end
154
+
155
+ # Used for setting associations via a nested attributes setter from the
156
+ # parent +Document+.
157
+ #
158
+ # Options:
159
+ #
160
+ # attributes: A +Hash+ of integer keys and +Hash+ values.
161
+ #
162
+ # Returns:
163
+ #
164
+ # The newly build target Document.
165
+ def nested_build(attributes, options = {})
166
+ attributes.each do |index, attrs|
167
+ if document = detect { |document| document._index == index.to_i }
168
+ if options && options[:allow_destroy] && attrs['_destroy']
169
+ @target.delete(document)
170
+ document.destroy
171
+ else
172
+ document.write_attributes(attrs)
173
+ end
174
+ else
175
+ build(attrs)
176
+ end
177
+ end
178
+ end
179
+
180
+ # Paginate the association. Will create a new criteria, set the documents
181
+ # on it and execute in an enumerable context.
182
+ #
183
+ # Options:
184
+ #
185
+ # options: A +Hash+ of pagination options.
186
+ #
187
+ # Returns:
188
+ #
189
+ # A +WillPaginate::Collection+.
190
+ def paginate(options)
191
+ criteria = Mongoid::Criteria.translate(@klass, options)
192
+ criteria.documents = @target
193
+ criteria.paginate(options)
194
+ end
195
+
196
+ protected
197
+ # Initializes each of the attributes in the hash.
198
+ def build_children_from_attributes(attributes)
199
+ @target = []
200
+ if attributes
201
+ attributes.each_with_index do |attrs, index|
202
+ klass = attrs.klass
203
+ child = klass ? klass.instantiate(attrs) : @klass.instantiate(attrs)
204
+ child.parentize(@parent, @association_name)
205
+ child._index = index
206
+ @target << child
207
+ end
208
+ end
209
+ end
210
+
211
+ # Initializes the target array from an existing array of documents.
212
+ def build_children_from_target_array(target_array)
213
+ @target = target_array
214
+ @target.each_with_index do |child, index|
215
+ child._index = index
216
+ end
217
+ end
218
+
219
+ # Removes documents based on a method.
220
+ def remove(method, conditions)
221
+ criteria = @klass.find(conditions || {})
222
+ criteria.documents = @target
223
+ count = criteria.size
224
+ criteria.each do |doc|
225
+ @target.delete(doc); doc.send(method)
226
+ end; count
227
+ end
228
+
229
+ class << self
230
+
231
+ # Preferred method of creating a new +EmbedsMany+ association. It will
232
+ # delegate to new.
233
+ #
234
+ # Options:
235
+ #
236
+ # document: The parent +Document+
237
+ # options: The association options
238
+ def instantiate(document, options, target_array = nil)
239
+ new(document, options, target_array)
240
+ end
241
+
242
+ # Returns the macro used to create the association.
243
+ def macro
244
+ :embeds_many
245
+ end
246
+
247
+ # Perform an update of the relationship of the parent and child. This
248
+ # is initialized by setting the has_many to the supplied +Enumerable+
249
+ # and setting up the parentization.
250
+ def update(children, parent, options)
251
+ parent.raw_attributes.delete(options.name)
252
+ children.assimilate(parent, options)
253
+ if children && children.first.is_a?(Mongoid::Document)
254
+ instantiate(parent, options, children)
255
+ else
256
+ instantiate(parent, options)
257
+ end
258
+ end
259
+ end
260
+ end
261
+ end
262
+ end
@@ -0,0 +1,95 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Associations #:nodoc:
4
+ # Represents an association that is embedded in a parent document as a
5
+ # one-to-one relationship.
6
+ class EmbedsOne < Proxy
7
+
8
+ # Build a new object for the association.
9
+ def build(attrs = {}, type = nil)
10
+ @target = attrs.assimilate(@parent, @options, type); self
11
+ end
12
+
13
+ # Creates the new association by finding the attributes in
14
+ # the parent document with its name, and instantiating a
15
+ # new document for it.
16
+ #
17
+ # All method calls on this object will then be delegated
18
+ # to the internal document itself.
19
+ #
20
+ # Options:
21
+ #
22
+ # document: The parent +Document+
23
+ # attributes: The attributes of the target object.
24
+ # options: The association options.
25
+ #
26
+ # Returns:
27
+ #
28
+ # A new +HashOne+ association proxy.
29
+ def initialize(document, attrs, options)
30
+ @parent, @options = document, options
31
+ @target = attrs.assimilate(@parent, @options, attrs.klass)
32
+ extends(options)
33
+ end
34
+
35
+ # Used for setting the association via a nested attributes setter on the
36
+ # parent +Document+. Called when using accepts_nested_attributes_for.
37
+ #
38
+ # Options:
39
+ #
40
+ # attributes: The attributes for the new association
41
+ #
42
+ # Returns:
43
+ #
44
+ # A new target document.
45
+ def nested_build(attributes, options = nil)
46
+ build(attributes) unless @target.blank? && options[:update_only]
47
+ end
48
+
49
+ class << self
50
+ # Preferred method of instantiating a new +EmbedsOne+, since nil values
51
+ # will be handled properly.
52
+ #
53
+ # Options:
54
+ #
55
+ # document: The parent +Document+
56
+ # options: The association options.
57
+ #
58
+ # Returns:
59
+ #
60
+ # A new +EmbedsOne+ association proxy.
61
+ def instantiate(document, options)
62
+ attributes = document.raw_attributes[options.name]
63
+ return nil if attributes.blank?
64
+ new(document, attributes, options)
65
+ end
66
+
67
+ # Returns the macro used to create the association.
68
+ def macro
69
+ :embeds_one
70
+ end
71
+
72
+ # Perform an update of the relationship of the parent and child. This
73
+ # will assimilate the child +Document+ into the parent's object graph.
74
+ #
75
+ # Options:
76
+ #
77
+ # child: The child +Document+ or +Hash+.
78
+ # parent: The parent +Document+ to update.
79
+ # options: The association +Options+
80
+ #
81
+ # Example:
82
+ #
83
+ # <tt>EmbedsOne.update({:first_name => "Hank"}, person, options)</tt>
84
+ #
85
+ # Returns:
86
+ #
87
+ # A new +EmbedsOne+ association proxy.
88
+ def update(child, parent, options)
89
+ child.assimilate(parent, options)
90
+ instantiate(parent, options)
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,35 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Associations #:nodoc:
4
+ module ForeignKey #:nodoc:
5
+ extend ActiveSupport::Concern
6
+
7
+ module ClassMethods #:nodoc:
8
+ # Determine the value for the foreign key constriant field in the
9
+ # database, based on the type of association or if the actual value was
10
+ # supplied as an option.
11
+ #
12
+ # Example:
13
+ #
14
+ # <tt>contraint(:posts, {}, :references_one)</tt>
15
+ #
16
+ # Returns
17
+ #
18
+ # A +String+ for the foreign key field.
19
+ def constraint(name, options, association)
20
+ key = options[:foreign_key]
21
+
22
+ # Always return the supplied foreign_key option if it was supplied -
23
+ # the user should always be ble to override.
24
+ return key.to_s if key
25
+
26
+ case association
27
+ when :one, :many then self.name.foreign_key
28
+ when :many_as_array then "#{name.to_s.singularize}_ids"
29
+ else name.to_s.foreign_key
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end