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,11 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Matchers #:nodoc:
4
+ class Nin < Default
5
+ # Return true if the attribute is not in the value list.
6
+ def matches?(value)
7
+ !value.values.first.include?(@attribute)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Matchers #:nodoc:
4
+ class Size < Default
5
+ # Return true if the attribute size is equal to the first value.
6
+ def matches?(value)
7
+ @attribute.size == value.values.first
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,33 @@
1
+ module Mongoid #:nodoc
2
+ module Memoization
3
+
4
+ # Handles cases when accessing an association that should be memoized in
5
+ # the Mongoid specific manner. Does not memoize nil values though
6
+ def memoized(name, &block)
7
+ var = "@#{name}"
8
+ if instance_variable_defined?(var)
9
+ return instance_variable_get(var)
10
+ end
11
+ value = yield
12
+ instance_variable_set(var, value) if value
13
+ end
14
+
15
+ # Removes an memozied association if it exists
16
+ def unmemoize(name)
17
+ var = "@#{name}"
18
+ remove_instance_variable(var) if instance_variable_defined?(var)
19
+ end
20
+
21
+ # Mongoid specific behavior is to remove the memoized object when setting
22
+ # the association, or if it wasn't previously memoized it will get set.
23
+ def reset(name, &block)
24
+ var = "@#{name}"
25
+ value = yield
26
+ if instance_variable_defined?(var)
27
+ remove_instance_variable(var)
28
+ else
29
+ instance_variable_set(var, value)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,37 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module NamedScope
4
+ # Creates a named_scope for the +Document+, similar to ActiveRecord's
5
+ # named_scopes. +NamedScopes+ are proxied +Criteria+ objects that can be
6
+ # chained.
7
+ #
8
+ # Example:
9
+ #
10
+ # class Person
11
+ # include Mongoid::Document
12
+ # field :active, :type => Boolean
13
+ # field :count, :type => Integer
14
+ #
15
+ # named_scope :active, :where => { :active => true }
16
+ # named_scope :count_gt_one, :where => { :count.gt => 1 }
17
+ # named_scope :at_least_count, lambda { |count| { :where => { :count.gt => count } } }
18
+ # end
19
+ def named_scope(name, options = {}, &block)
20
+ name = name.to_sym
21
+ scopes[name] = lambda do |parent, *args|
22
+ Scope.new(parent, options.scoped(*args), &block)
23
+ end
24
+ (class << self; self; end).class_eval <<-EOT
25
+ def #{name}(*args)
26
+ scopes[:#{name}].call(self, *args)
27
+ end
28
+ EOT
29
+ end
30
+ alias :scope :named_scope
31
+
32
+ # Return the scopes or default to an empty +Hash+.
33
+ def scopes
34
+ read_inheritable_attribute(:scopes) || write_inheritable_attribute(:scopes, {})
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,30 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Observable #:nodoc:
4
+ extend ActiveSupport::Concern
5
+ included do
6
+ attr_reader :observers
7
+ end
8
+
9
+ # Add an observer to this object. This mimics the standard Ruby observable
10
+ # library.
11
+ #
12
+ # Example:
13
+ #
14
+ # <tt>address.add_observer(person)</tt>
15
+ def add_observer(object)
16
+ @observers ||= []
17
+ @observers.push(object)
18
+ end
19
+
20
+ # Notify all the objects observing this object of an update. All observers
21
+ # need to respond to the update method in order to handle this.
22
+ #
23
+ # Example:
24
+ #
25
+ # <tt>document.notify_observers(self)</tt>
26
+ def notify_observers(*args)
27
+ @observers.dup.each { |observer| observer.observe(*args) } if @observers
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,62 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Paths #:nodoc:
4
+ extend ActiveSupport::Concern
5
+ included do
6
+ cattr_accessor :__path
7
+ attr_accessor :_index
8
+ end
9
+ module InstanceMethods
10
+ # Get the insertion modifier for the document. Will be nil on root
11
+ # documents, $set on embeds_one, $push on embeds_many.
12
+ #
13
+ # Example:
14
+ #
15
+ # <tt>name.inserter</tt>
16
+ def _inserter
17
+ embedded? ? (embedded_many? ? "$push" : "$set") : nil
18
+ end
19
+
20
+ # Return the path to this +Document+ in JSON notation, used for atomic
21
+ # updates via $set in MongoDB.
22
+ #
23
+ # Example:
24
+ #
25
+ # <tt>address.path # returns "addresses"</tt>
26
+ def _path
27
+ _position.sub!(/\.\d+$/, '') || _position
28
+ end
29
+ alias :_pull :_path
30
+
31
+ # Returns the positional operator of this document for modification.
32
+ #
33
+ # Example:
34
+ #
35
+ # <tt>address.position</tt>
36
+ def _position
37
+ locator = _index ? (new_record? ? "" : ".#{_index}") : ""
38
+ embedded? ? "#{_parent._position}#{"." unless _parent._position.blank?}#{@association_name}#{locator}" : ""
39
+ end
40
+
41
+ # Get the removal modifier for the document. Will be nil on root
42
+ # documents, $unset on embeds_one, $set on embeds_many.
43
+ #
44
+ # Example:
45
+ #
46
+ # <tt>name.remover</tt>
47
+ def _remover
48
+ embedded? ? (_index ? "$pull" : "$unset") : nil
49
+ end
50
+
51
+ # Return the selector for this document to be matched exactly for use
52
+ # with MongoDB's $ operator.
53
+ #
54
+ # Example:
55
+ #
56
+ # <tt>address.selector</tt>
57
+ def _selector
58
+ embedded? ? _parent._selector.merge("#{_path}._id" => id) : { "_id" => id }
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,218 @@
1
+ # encoding: utf-8
2
+ require "mongoid/persistence/command"
3
+ require "mongoid/persistence/insert"
4
+ require "mongoid/persistence/insert_embedded"
5
+ require "mongoid/persistence/remove"
6
+ require "mongoid/persistence/remove_all"
7
+ require "mongoid/persistence/remove_embedded"
8
+ require "mongoid/persistence/update"
9
+
10
+ module Mongoid #:nodoc:
11
+ # The persistence module is a mixin to provide database accessor methods for
12
+ # the document. These correspond to the appropriate accessors on a
13
+ # +Mongo::Collection+ and retain the same DSL.
14
+ #
15
+ # Examples:
16
+ #
17
+ # <tt>document.insert</tt>
18
+ # <tt>document.update</tt>
19
+ # <tt>document.upsert</tt>
20
+ module Persistence
21
+ extend ActiveSupport::Concern
22
+ module InstanceMethods #:nodoc:
23
+ # Remove the +Document+ from the datbase with callbacks.
24
+ #
25
+ # Example:
26
+ #
27
+ # <tt>document.destroy</tt>
28
+ #
29
+ # TODO: Will get rid of other #destroy once new persistence complete.
30
+ def destroy
31
+ run_callbacks(:destroy) { self.destroyed = true if _remove }
32
+ end
33
+
34
+ # Insert a new +Document+ into the database. Will return the document
35
+ # itself whether or not the save was successful.
36
+ #
37
+ # Example:
38
+ #
39
+ # <tt>document.insert</tt>
40
+ def insert(validate = true)
41
+ Insert.new(self, validate).persist
42
+ end
43
+
44
+ # Remove the +Document+ from the datbase.
45
+ #
46
+ # Example:
47
+ #
48
+ # <tt>document._remove</tt>
49
+ #
50
+ # TODO: Will get rid of other #remove once observable pattern killed.
51
+ def _remove
52
+ Remove.new(self).persist
53
+ end
54
+
55
+ alias :delete :_remove
56
+
57
+ # Save the document - will perform an insert if the document is new, and
58
+ # update if not. If a validation error occurs a
59
+ # Mongoid::Errors::Validations error will get raised.
60
+ #
61
+ # Example:
62
+ #
63
+ # <tt>document.save!</tt>
64
+ #
65
+ # Returns:
66
+ #
67
+ # +true+ if validation passed, will raise error otherwise.
68
+ def save!
69
+ self.class.fail_validate!(self) unless upsert; true
70
+ end
71
+
72
+ # Update the +Document+ in the datbase.
73
+ #
74
+ # Example:
75
+ #
76
+ # <tt>document.update</tt>
77
+ def update(validate = true)
78
+ Update.new(self, validate).persist
79
+ end
80
+
81
+ # Update the +Document+ attributes in the datbase.
82
+ #
83
+ # Example:
84
+ #
85
+ # <tt>document.update_attributes(:title => "Sir")</tt>
86
+ #
87
+ # Returns:
88
+ #
89
+ # +true+ if validation passed, +false+ if not.
90
+ def update_attributes(attributes = {})
91
+ write_attributes(attributes); update
92
+ end
93
+
94
+ # Update the +Document+ attributes in the datbase.
95
+ #
96
+ # Example:
97
+ #
98
+ # <tt>document.update_attributes(:title => "Sir")</tt>
99
+ #
100
+ # Returns:
101
+ #
102
+ # +true+ if validation passed, raises an error if not
103
+ def update_attributes!(attributes = {})
104
+ write_attributes(attributes)
105
+ result = update
106
+ self.class.fail_validate!(self) unless result
107
+ result
108
+ end
109
+
110
+ # Upsert the document - will perform an insert if the document is new, and
111
+ # update if not.
112
+ #
113
+ # Example:
114
+ #
115
+ # <tt>document.upsert</tt>
116
+ #
117
+ # Returns:
118
+ #
119
+ # A +Boolean+ for updates.
120
+ def upsert(validate = true)
121
+ validate = parse_validate(validate)
122
+ if new_record?
123
+ insert(validate).persisted?
124
+ else
125
+ update(validate)
126
+ end
127
+ end
128
+
129
+ # Save is aliased so that users familiar with active record can have some
130
+ # semblance of a familiar API.
131
+ #
132
+ # Example:
133
+ #
134
+ # <tt>document.save</tt>
135
+ alias :save :upsert
136
+
137
+ protected
138
+ # Alternative validation params.
139
+ def parse_validate(validate)
140
+ if validate.is_a?(Hash) && validate.has_key?(:validate)
141
+ validate = validate[:validate]
142
+ end
143
+ validate
144
+ end
145
+ end
146
+
147
+ module ClassMethods #:nodoc:
148
+
149
+ # Create a new +Document+. This will instantiate a new document and
150
+ # insert it in a single call. Will always return the document
151
+ # whether save passed or not.
152
+ #
153
+ # Example:
154
+ #
155
+ # <tt>Person.create(:title => "Mr")</tt>
156
+ #
157
+ # Returns: the +Document+.
158
+ def create(attributes = {})
159
+ new(attributes).tap(&:insert)
160
+ end
161
+
162
+ # Create a new +Document+. This will instantiate a new document and
163
+ # insert it in a single call. Will always return the document
164
+ # whether save passed or not, and if validation fails an error will be
165
+ # raise.
166
+ #
167
+ # Example:
168
+ #
169
+ # <tt>Person.create!(:title => "Mr")</tt>
170
+ #
171
+ # Returns: the +Document+.
172
+ def create!(attributes = {})
173
+ document = new(attributes)
174
+ fail_validate!(document) if document.insert.errors.any?
175
+ document
176
+ end
177
+
178
+ # Delete all documents given the supplied conditions. If no conditions
179
+ # are passed, the entire collection will be dropped for performance
180
+ # benefits. Does not fire any callbacks.
181
+ #
182
+ # Example:
183
+ #
184
+ # <tt>Person.delete_all(:conditions => { :title => "Sir" })</tt>
185
+ # <tt>Person.delete_all</tt>
186
+ #
187
+ # Returns: true or raises an error.
188
+ def delete_all(conditions = {})
189
+ RemoveAll.new(
190
+ self,
191
+ false,
192
+ conditions[:conditions] || {}
193
+ ).persist
194
+ end
195
+
196
+ # Delete all documents given the supplied conditions. If no conditions
197
+ # are passed, the entire collection will be dropped for performance
198
+ # benefits. Fires the destroy callbacks if conditions were passed.
199
+ #
200
+ # Example:
201
+ #
202
+ # <tt>Person.destroy_all(:conditions => { :title => "Sir" })</tt>
203
+ # <tt>Person.destroy_all</tt>
204
+ #
205
+ # Returns: true or raises an error.
206
+ def destroy_all(conditions = {})
207
+ documents = all(conditions)
208
+ count = documents.count
209
+ documents.each { |doc| doc.destroy }; count
210
+ end
211
+
212
+ # Raise an error if validation failed.
213
+ def fail_validate!(document)
214
+ raise Errors::Validations.new(document.errors)
215
+ end
216
+ end
217
+ end
218
+ end
@@ -0,0 +1,39 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Persistence #:nodoc:
4
+ # Persistence commands extend from this class to get basic functionality on
5
+ # initialization.
6
+ class Command
7
+ attr_reader \
8
+ :collection,
9
+ :document,
10
+ :klass,
11
+ :options,
12
+ :selector,
13
+ :validate
14
+
15
+ # Initialize the persistence +Command+.
16
+ #
17
+ # Options:
18
+ #
19
+ # document_or_class: The +Document+ or +Class+ to get the collection.
20
+ # validate: Is the document to be validated.
21
+ # selector: Optional selector to use in query.
22
+ #
23
+ # Example:
24
+ #
25
+ # <tt>DeleteAll.new(Person, false, {})</tt>
26
+ def initialize(document_or_class, validate = true, selector = {})
27
+ if document_or_class.is_a?(Mongoid::Document)
28
+ @document = document_or_class
29
+ @collection = @document.embedded? ? @document._root.collection : @document.collection
30
+ else
31
+ @klass = document_or_class
32
+ @collection = @klass.collection
33
+ end
34
+ @selector, @validate = selector, validate
35
+ @options = { :safe => Mongoid.persist_in_safe_mode }
36
+ end
37
+ end
38
+ end
39
+ end