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,29 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Associations #:nodoc:
4
+ # This class contains metadata about association proxies.
5
+ class MetaData
6
+
7
+ attr_reader :association, :options
8
+
9
+ delegate :macro, :to => :association
10
+
11
+ # Delegate all methods on +Options+ to the options instance.
12
+ Associations::Options.public_instance_methods(false).each do |name|
13
+ define_method(name) { |*args| @options.send(name) }
14
+ end
15
+
16
+ # Create the new associations MetaData object, which holds the type of
17
+ # the association and its options, with convenience methods for getting
18
+ # that information.
19
+ #
20
+ # Options:
21
+ #
22
+ # association: The association type as a class instance.
23
+ # options: The association options
24
+ def initialize(association, options)
25
+ @association, @options = association, options
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,73 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Associations #:nodoc:
4
+ class Options #:nodoc:
5
+
6
+ # Create the new +Options+ object, which provides convenience methods for
7
+ # accessing values out of an options +Hash+.
8
+ def initialize(attributes = {})
9
+ @attributes = attributes
10
+ end
11
+
12
+ # Returns the extension if it exists, nil if not.
13
+ def extension
14
+ @attributes[:extend]
15
+ end
16
+
17
+ # Returns true is the options have extensions.
18
+ def extension?
19
+ !extension.nil?
20
+ end
21
+
22
+ # Return the foreign key based off the association name.
23
+ def foreign_key
24
+ if as
25
+ key = as.to_s.foreign_key
26
+ else
27
+ key = @attributes[:foreign_key] || klass.name.to_s.foreign_key
28
+ key.to_s
29
+ end
30
+
31
+ key
32
+ end
33
+
34
+ def foreign_type
35
+ name+"_type"
36
+ end
37
+
38
+ # Returns the name of the inverse_of association
39
+ def inverse_of
40
+ @attributes[:inverse_of]
41
+ end
42
+
43
+ def as
44
+ @attributes[:as]
45
+ end
46
+
47
+ # Return a +Class+ for the options. See #class_name
48
+ def klass
49
+ class_name.constantize
50
+ end
51
+
52
+ # Returns the class name from the options
53
+ def class_name
54
+ class_name = (@attributes[:class_name] ? @attributes[:class_name].to_s : name.to_s).classify
55
+ end
56
+
57
+ # Returns the association name of the options.
58
+ def name
59
+ @attributes[:name].to_s
60
+ end
61
+
62
+ # Returns whether or not this association is polymorphic.
63
+ def polymorphic
64
+ @attributes[:polymorphic] == true
65
+ end
66
+
67
+ # Used with references_many to save as array of ids.
68
+ def stored_as
69
+ @attributes[:stored_as]
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,33 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc
3
+ module Associations #:nodoc
4
+ class Proxy #:nodoc
5
+ instance_methods.each do |method|
6
+ undef_method(method) unless method =~ /(^__|^nil\?$|^send$|^object_id$|^extend$)/
7
+ end
8
+ attr_reader \
9
+ :options,
10
+ :target
11
+
12
+ # Default behavior of method missing should be to delegate all calls
13
+ # to the target of the proxy. This can be overridden in special cases.
14
+ def method_missing(name, *args, &block)
15
+ @target.send(name, *args, &block)
16
+ end
17
+
18
+ # If anonymous extensions are added this will take care of them.
19
+ def extends(options)
20
+ extend Module.new(&options.extension) if options.extension?
21
+ end
22
+
23
+ # Sets up the parent, klass, foreign_key, options
24
+ def setup(document, options)
25
+ @parent = document
26
+ @klass = options.klass
27
+ @options = options
28
+ @foreign_key = options.foreign_key
29
+ extends(options)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,71 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Associations #:nodoc:
4
+ # Represents a relational association to a "parent" object.
5
+ class ReferencedIn < Proxy
6
+
7
+ # Initializing a related association only requires looking up the object
8
+ # by its id.
9
+ #
10
+ # Options:
11
+ #
12
+ # document: The +Document+ that contains the relationship.
13
+ # options: The association +Options+.
14
+ def initialize(document, foreign_key, options, target = nil)
15
+ @options = options
16
+
17
+ if options.polymorphic
18
+ k = document.send(options.name+"_type").constantize
19
+
20
+ @target = k.find(foreign_key)
21
+ else
22
+ @target = target || options.klass.find(foreign_key)
23
+ end
24
+
25
+ extends(options)
26
+ end
27
+
28
+ class << self
29
+ # Instantiate a new +ReferencedIn+ or return nil if the foreign key is
30
+ # nil. It is preferrable to use this method over the traditional call
31
+ # to new.
32
+ #
33
+ # Options:
34
+ #
35
+ # document: The +Document+ that contains the relationship.
36
+ # options: The association +Options+.
37
+ def instantiate(document, options, target = nil)
38
+ foreign_key = document.send(options.foreign_key)
39
+ foreign_key.blank? ? nil : new(document, foreign_key, options, target)
40
+ end
41
+
42
+ # Returns the macro used to create the association.
43
+ def macro
44
+ :referenced_in
45
+ end
46
+
47
+ # Perform an update of the relationship of the parent and child. This
48
+ # will assimilate the child +Document+ into the parent's object graph.
49
+ #
50
+ # Options:
51
+ #
52
+ # target: The target(parent) object
53
+ # document: The +Document+ to update.
54
+ # options: The association +Options+
55
+ #
56
+ # Example:
57
+ #
58
+ # <tt>ReferencedIn.update(person, game, options)</tt>
59
+ def update(target, document, options)
60
+ document.send("#{options.foreign_key}=", target ? target.id : nil)
61
+
62
+ if options.polymorphic
63
+ document.send("#{options.foreign_type}=", target ? target.class.to_s : nil)
64
+ end
65
+
66
+ instantiate(document, options, target)
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,243 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Associations #:nodoc:
4
+ # Represents an relational one-to-many association with an object in a
5
+ # separate collection or database.
6
+ class ReferencesMany < Proxy
7
+
8
+ # Appends the object to the +Array+, setting its parent in
9
+ # the process.
10
+ def <<(*objects)
11
+ load_target
12
+ objects.flatten.each do |object|
13
+ object.send("#{@foreign_key}=", @parent.id)
14
+ @target << object
15
+ object.save unless @parent.new_record?
16
+ end
17
+ end
18
+
19
+ alias :concat :<<
20
+ alias :push :<<
21
+
22
+ # Builds a new Document and adds it to the association collection. The
23
+ # document created will be of the same class as the others in the
24
+ # association, and the attributes will be passed into the constructor.
25
+ #
26
+ # Returns the newly created object.
27
+ def build(attributes = nil)
28
+ load_target
29
+
30
+ if @foreign_type
31
+ name = @parent.class.to_s.underscore
32
+ object = @klass.instantiate(attributes.merge(@base.call.selector))
33
+ else
34
+ name = @parent.class.to_s.underscore
35
+ object = @klass.instantiate(attributes.merge(name => @parent))
36
+ end
37
+
38
+ @target << object
39
+ object
40
+ end
41
+
42
+ # Creates a new Document and adds it to the association collection. The
43
+ # document created will be of the same class as the others in the
44
+ # association, and the attributes will be passed into the constructor and
45
+ # the new object will then be saved.
46
+ #
47
+ # Returns the newly created object.
48
+ def create(attributes)
49
+ build(attributes).tap(&:save)
50
+ end
51
+
52
+ # Creates a new Document and adds it to the association collection. If
53
+ # validation fails an error is raised.
54
+ #
55
+ # Returns the newly created object.
56
+ def create!(attributes)
57
+ build(attributes).tap(&:save!)
58
+ end
59
+
60
+ # Delete all the associated objects.
61
+ #
62
+ # Example:
63
+ #
64
+ # <tt>person.posts.delete_all</tt>
65
+ #
66
+ # Returns:
67
+ #
68
+ # The number of objects deleted.
69
+ def delete_all(conditions = {})
70
+ remove(:delete_all, conditions[:conditions])
71
+ end
72
+
73
+ # Destroy all the associated objects.
74
+ #
75
+ # Example:
76
+ #
77
+ # <tt>person.posts.destroy_all</tt>
78
+ #
79
+ # Returns:
80
+ #
81
+ # The number of objects destroyed.
82
+ def destroy_all(conditions = {})
83
+ remove(:destroy_all, conditions[:conditions])
84
+ end
85
+
86
+ # Finds a document in this association.
87
+ # If an id is passed, will return the document for that id.
88
+ def find(*args)
89
+ args[1][:conditions].merge!(@foreign_key.to_sym => @parent.id) if args.size > 1
90
+ @klass.find(*args)
91
+ end
92
+
93
+ # Initializing a related association only requires looking up the objects
94
+ # by their ids.
95
+ #
96
+ # Options:
97
+ #
98
+ # document: The +Document+ that contains the relationship.
99
+ # options: The association +Options+.
100
+ def initialize(document, options, target = nil)
101
+ setup(document, options)
102
+ @parent, @klass, @options = document, options.klass, options
103
+
104
+ @foreign_key = options.foreign_key
105
+
106
+ pre_conditions = { @foreign_key => document.id }
107
+
108
+ if options.as
109
+ @foreign_type = options.as.to_s+"_type"
110
+
111
+ pre_conditions[@foreign_type] = document.class.to_s
112
+ end
113
+
114
+ @base = lambda { @klass.all(:conditions => pre_conditions) }
115
+
116
+ @target = target || @base.call
117
+ extends(options)
118
+ end
119
+
120
+ # Override the default behavior to allow the criteria to get reset on
121
+ # each call into the association.
122
+ #
123
+ # Example:
124
+ #
125
+ # person.posts.where(:title => "New")
126
+ # person.posts # resets the criteria
127
+ #
128
+ # Returns:
129
+ #
130
+ # A Criteria object or Array.
131
+ def method_missing(name, *args, &block)
132
+ @target = query.call unless @target.is_a?(Array)
133
+ @target.send(name, *args, &block)
134
+ end
135
+
136
+ # Used for setting associations via a nested attributes setter from the
137
+ # parent +Document+.
138
+ #
139
+ # Options:
140
+ #
141
+ # attributes: A +Hash+ of integer keys and +Hash+ values.
142
+ #
143
+ # Returns:
144
+ #
145
+ # The newly build target Document.
146
+ def nested_build(attributes, options = {})
147
+ attributes.each do |index, attrs|
148
+ begin
149
+ document = find(index.to_i)
150
+ if options && options[:allow_destroy] && attrs['_destroy']
151
+ @target.delete(document)
152
+ document.destroy
153
+ else
154
+ document.write_attributes(attrs)
155
+ end
156
+ rescue Errors::DocumentNotFound
157
+ build(attrs)
158
+ end
159
+ end
160
+ end
161
+
162
+ protected
163
+ # Load the target entries if the parent document is new.
164
+ def load_target
165
+ @target = @target.entries if @parent.new_record?
166
+ end
167
+
168
+ # The default query used for retrieving the documents from the database.
169
+ # In this case we use the common API between Mongoid, ActiveRecord, and
170
+ # DataMapper so we can do one-to-many relationships with data in other
171
+ # databases.
172
+ #
173
+ # Example:
174
+ #
175
+ # <tt>association.query</tt>
176
+ #
177
+ # Returns:
178
+ #
179
+ # A +Criteria+ if a Mongoid association.
180
+ # An +Array+ of objects if an ActiveRecord association
181
+ # A +Collection+ if a DataMapper association.
182
+ def query
183
+ @query ||= lambda { @klass.all(:conditions => { @foreign_key => @parent.id }) }
184
+ end
185
+
186
+ # Remove the objects based on conditions.
187
+ def remove(method, conditions)
188
+ selector = { @foreign_key => @parent.id }.merge(conditions || {})
189
+ removed = @klass.send(method, :conditions => selector)
190
+ reset; removed
191
+ end
192
+
193
+ # Reset the memoized association on the parent. This will execute the
194
+ # database query again.
195
+ #
196
+ # Example:
197
+ #
198
+ # <tt>association.reset</tt>
199
+ #
200
+ # Returns:
201
+ #
202
+ # See #query rdoc for return values.
203
+ def reset
204
+ @parent.send(:reset, @options.name) { query.call }
205
+ end
206
+
207
+ class << self
208
+ # Preferred method for creating the new +ReferencesMany+ association.
209
+ #
210
+ # Options:
211
+ #
212
+ # document: The +Document+ that contains the relationship.
213
+ # options: The association +Options+.
214
+ def instantiate(document, options, target = nil)
215
+ new(document, options, target)
216
+ end
217
+
218
+ # Returns the macro used to create the association.
219
+ def macro
220
+ :references_many
221
+ end
222
+
223
+ # Perform an update of the relationship of the parent and child. This
224
+ # will assimilate the child +Document+ into the parent's object graph.
225
+ #
226
+ # Options:
227
+ #
228
+ # related: The related object
229
+ # parent: The parent +Document+ to update.
230
+ # options: The association +Options+
231
+ #
232
+ # Example:
233
+ #
234
+ # <tt>RelatesToOne.update(game, person, options)</tt>
235
+ def update(target, document, options)
236
+ name = document.class.to_s.underscore
237
+ target.each { |child| child.send("#{name}=", document) }
238
+ instantiate(document, options, target)
239
+ end
240
+ end
241
+ end
242
+ end
243
+ end