chhean-mongoid 2.0.1.beta1

Sign up to get free protection for your applications and to get access to all the features.
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