mongoid 2.0.0.rc.7 → 2.0.0.rc.8

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 (90) hide show
  1. data/lib/config/locales/en.yml +3 -0
  2. data/lib/config/locales/id.yml +46 -0
  3. data/lib/config/locales/ja.yml +40 -0
  4. data/lib/config/locales/vi.yml +45 -0
  5. data/lib/mongoid.rb +5 -3
  6. data/lib/mongoid/attributes.rb +24 -63
  7. data/lib/mongoid/attributes/processing.rb +5 -2
  8. data/lib/mongoid/callbacks.rb +10 -0
  9. data/lib/mongoid/collection.rb +24 -0
  10. data/lib/mongoid/collections/master.rb +14 -6
  11. data/lib/mongoid/collections/operations.rb +1 -1
  12. data/lib/mongoid/collections/retry.rb +39 -0
  13. data/lib/mongoid/collections/slaves.rb +26 -10
  14. data/lib/mongoid/components.rb +4 -4
  15. data/lib/mongoid/config.rb +6 -3
  16. data/lib/mongoid/contexts.rb +0 -1
  17. data/lib/mongoid/contexts/enumerable.rb +19 -7
  18. data/lib/mongoid/contexts/mongo.rb +9 -5
  19. data/lib/mongoid/copyable.rb +10 -8
  20. data/lib/mongoid/criteria.rb +83 -61
  21. data/lib/mongoid/criterion/builder.rb +34 -0
  22. data/lib/mongoid/criterion/creational.rb +2 -2
  23. data/lib/mongoid/criterion/exclusion.rb +58 -32
  24. data/lib/mongoid/criterion/inclusion.rb +49 -10
  25. data/lib/mongoid/criterion/optional.rb +1 -1
  26. data/lib/mongoid/criterion/selector.rb +80 -11
  27. data/lib/mongoid/cursor.rb +6 -1
  28. data/lib/mongoid/default_scope.rb +27 -19
  29. data/lib/mongoid/document.rb +26 -1
  30. data/lib/mongoid/errors.rb +1 -0
  31. data/lib/mongoid/errors/mixed_relations.rb +37 -0
  32. data/lib/mongoid/extensions/object_id/conversions.rb +7 -4
  33. data/lib/mongoid/factory.rb +1 -1
  34. data/lib/mongoid/field.rb +47 -30
  35. data/lib/mongoid/fields.rb +9 -2
  36. data/lib/mongoid/finders.rb +15 -49
  37. data/lib/mongoid/identity.rb +6 -4
  38. data/lib/mongoid/keys.rb +85 -31
  39. data/lib/mongoid/multi_parameter_attributes.rb +2 -2
  40. data/lib/mongoid/named_scope.rb +129 -28
  41. data/lib/mongoid/observer.rb +36 -0
  42. data/lib/mongoid/paranoia.rb +3 -3
  43. data/lib/mongoid/paths.rb +1 -1
  44. data/lib/mongoid/persistence.rb +2 -0
  45. data/lib/mongoid/persistence/atomic.rb +88 -0
  46. data/lib/mongoid/persistence/atomic/add_to_set.rb +30 -0
  47. data/lib/mongoid/persistence/atomic/inc.rb +28 -0
  48. data/lib/mongoid/persistence/atomic/operation.rb +44 -0
  49. data/lib/mongoid/persistence/atomic/pull_all.rb +33 -0
  50. data/lib/mongoid/persistence/atomic/push.rb +28 -0
  51. data/lib/mongoid/railtie.rb +13 -1
  52. data/lib/mongoid/relations.rb +1 -0
  53. data/lib/mongoid/relations/accessors.rb +20 -2
  54. data/lib/mongoid/relations/builders/embedded/one.rb +1 -0
  55. data/lib/mongoid/relations/builders/nested_attributes/many.rb +17 -6
  56. data/lib/mongoid/relations/builders/referenced/many.rb +2 -1
  57. data/lib/mongoid/relations/builders/referenced/one.rb +1 -0
  58. data/lib/mongoid/relations/embedded/atomic.rb +86 -0
  59. data/lib/mongoid/relations/embedded/atomic/operation.rb +63 -0
  60. data/lib/mongoid/relations/embedded/atomic/pull.rb +65 -0
  61. data/lib/mongoid/relations/embedded/atomic/push_all.rb +59 -0
  62. data/lib/mongoid/relations/embedded/atomic/set.rb +61 -0
  63. data/lib/mongoid/relations/embedded/atomic/unset.rb +41 -0
  64. data/lib/mongoid/relations/embedded/many.rb +57 -25
  65. data/lib/mongoid/relations/macros.rb +6 -4
  66. data/lib/mongoid/relations/many.rb +51 -10
  67. data/lib/mongoid/relations/metadata.rb +4 -2
  68. data/lib/mongoid/relations/proxy.rb +39 -24
  69. data/lib/mongoid/relations/referenced/many.rb +47 -26
  70. data/lib/mongoid/relations/referenced/many_to_many.rb +47 -14
  71. data/lib/mongoid/relations/referenced/one.rb +14 -0
  72. data/lib/mongoid/sharding.rb +51 -0
  73. data/lib/mongoid/state.rb +3 -2
  74. data/lib/mongoid/timestamps.rb +5 -29
  75. data/lib/mongoid/timestamps/created.rb +31 -0
  76. data/lib/mongoid/timestamps/updated.rb +33 -0
  77. data/lib/mongoid/validations.rb +10 -3
  78. data/lib/mongoid/validations/referenced.rb +58 -0
  79. data/lib/mongoid/version.rb +1 -1
  80. data/lib/mongoid/versioning.rb +67 -5
  81. data/lib/rails/generators/mongoid/model/templates/model.rb +2 -0
  82. data/lib/rails/generators/mongoid/observer/observer_generator.rb +17 -0
  83. data/lib/rails/generators/mongoid/observer/templates/observer.rb +4 -0
  84. data/lib/rails/generators/mongoid_generator.rb +10 -1
  85. data/lib/rails/mongoid.rb +1 -0
  86. metadata +29 -8
  87. data/lib/mongoid/contexts/ids.rb +0 -25
  88. data/lib/mongoid/modifiers.rb +0 -24
  89. data/lib/mongoid/modifiers/command.rb +0 -18
  90. data/lib/mongoid/modifiers/inc.rb +0 -24
@@ -113,7 +113,7 @@ module Mongoid #:nodoc:
113
113
  # @return [ Document ] A new document.
114
114
  def initialize(attrs = nil)
115
115
  @new_record = true
116
- @attributes = default_attributes
116
+ @attributes = apply_default_attributes
117
117
  process(attrs) do |document|
118
118
  yield self if block_given?
119
119
  identify
@@ -147,6 +147,7 @@ module Mongoid #:nodoc:
147
147
  raise Errors::DocumentNotFound.new(self.class, id) if reloaded.nil?
148
148
  end
149
149
  @attributes = {}.merge(reloaded || {})
150
+ apply_default_attributes
150
151
  reset_modifications
151
152
  tap do
152
153
  relations.keys.each do |name|
@@ -233,7 +234,9 @@ module Mongoid #:nodoc:
233
234
  if attributes["_id"]
234
235
  allocate.tap do |doc|
235
236
  doc.instance_variable_set(:@attributes, attributes)
237
+ doc.send(:apply_default_attributes)
236
238
  doc.setup_modifications
239
+ doc.run_callbacks(:initialize) { doc }
237
240
  end
238
241
  else
239
242
  new(attrs)
@@ -255,5 +258,27 @@ module Mongoid #:nodoc:
255
258
  :mongoid
256
259
  end
257
260
  end
261
+
262
+ # Freezes the internal attributes of the document.
263
+ #
264
+ # @example Freeze the document
265
+ # document.freeze
266
+ #
267
+ # @return [ Document ] The document.
268
+ def freeze
269
+ raw_attributes.freeze
270
+ self
271
+ end
272
+
273
+ # Checks if the document is frozen
274
+ #
275
+ # @example Check if frozen
276
+ # document.frozen?
277
+ #
278
+ # @return [ true, false ] True if frozen, else false.
279
+ def frozen?
280
+ raw_attributes.frozen?
281
+ end
282
+
258
283
  end
259
284
  end
@@ -6,6 +6,7 @@ require "mongoid/errors/invalid_database"
6
6
  require "mongoid/errors/invalid_field"
7
7
  require "mongoid/errors/invalid_options"
8
8
  require "mongoid/errors/invalid_type"
9
+ require "mongoid/errors/mixed_relations"
9
10
  require "mongoid/errors/too_many_nested_attribute_records"
10
11
  require "mongoid/errors/unsaved_document"
11
12
  require "mongoid/errors/unsupported_version"
@@ -0,0 +1,37 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc
3
+ module Errors #:nodoc
4
+
5
+ # This error is raised when trying to reference an embedded document from
6
+ # a document in another collection that is not it's parent.
7
+ #
8
+ # @example An illegal reference to an embedded document.
9
+ # class Post
10
+ # include Mongoid::Document
11
+ # references_many :addresses
12
+ # end
13
+ #
14
+ # class Address
15
+ # include Mongoid::Document
16
+ # embedded_in :person
17
+ # referenced_in :post
18
+ # end
19
+ #
20
+ # @since 2.0.0
21
+ class MixedRelations < MongoidError
22
+
23
+ attr_reader :root_klass, :embedded_klass
24
+
25
+ def initialize(root_klass, embedded_klass)
26
+ @root_klass, @embedded_klass = root_klass, embedded_klass
27
+
28
+ super(
29
+ translate(
30
+ "mixed_relations",
31
+ { :root => root_klass, :embedded => embedded_klass }
32
+ )
33
+ )
34
+ end
35
+ end
36
+ end
37
+ end
@@ -42,6 +42,8 @@ module Mongoid #:nodoc:
42
42
  # Convert the supplied arguments to object ids based on the class
43
43
  # settings.
44
44
  #
45
+ # @todo Durran: This method can be refactored.
46
+ #
45
47
  # @example Convert a string to an object id
46
48
  # BSON::ObjectId.convert(Person, "4c52c439931a90ab29000003")
47
49
  #
@@ -64,16 +66,17 @@ module Mongoid #:nodoc:
64
66
  return args if args.is_a?(BSON::ObjectId) || !klass.using_object_ids?
65
67
  case args
66
68
  when ::String
67
- BSON::ObjectId.from_string(args)
69
+ args.blank? ? nil : BSON::ObjectId.from_string(args)
68
70
  when ::Array
69
- args.map do |arg|
71
+ args.reject(&:blank?).map do |arg|
70
72
  convert(klass, arg)
71
73
  end
72
74
  when ::Hash
73
75
  args.tap do |hash|
74
- args.each_pair do |key, value|
76
+ hash.each_pair do |key, value|
77
+ next unless key.to_s =~ /id/
75
78
  begin
76
- args[key] = convert(klass, value)
79
+ hash[key] = convert(klass, value)
77
80
  rescue BSON::InvalidObjectId; end
78
81
  end
79
82
  end
@@ -14,7 +14,7 @@ module Mongoid #:nodoc:
14
14
  def self.build(klass, attributes)
15
15
  attrs = {}.merge(attributes)
16
16
  type = attrs["_type"]
17
- type ? type.constantize.instantiate(attrs) : klass.instantiate(attrs)
17
+ type.present? ? type.constantize.instantiate(attrs) : klass.instantiate(attrs)
18
18
  end
19
19
  end
20
20
  end
@@ -1,34 +1,40 @@
1
1
  # encoding: utf-8
2
2
  module Mongoid #:nodoc:
3
+
4
+ # Defines the behaviour for defined fields in the document.
3
5
  class Field
4
- attr_reader :copyable, :klass, :label, :name, :options, :type
6
+
7
+ attr_accessor :type
8
+ attr_reader :copyable, :klass, :label, :name, :options
5
9
 
6
10
  # Get the default value for the field.
7
11
  #
8
- # Returns:
12
+ # @example Get the default.
13
+ # field.default
9
14
  #
10
- # The typecast default value.
15
+ # @return [ Object ] The typecast default value.
16
+ #
17
+ # @since 1.0.0
11
18
  def default
12
19
  copy.respond_to?(:call) ? copy : set(copy)
13
20
  end
14
21
 
15
- # Create the new field with a name and optional additional options. Valid
16
- # options are :default
22
+ # Create the new field with a name and optional additional options.
17
23
  #
18
- # Options:
24
+ # @example Create the new field.
25
+ # Field.new(:name, :type => String)
19
26
  #
20
- # name: The name of the field as a +Symbol+.
21
- # options: A +Hash+ of options for the field.
27
+ # @param [ Hash ] options The field options.
22
28
  #
23
- # Example:
29
+ # @option options [ Class ] :type The class of the field.
30
+ # @option options [ Object ] :default The default value for the field.
31
+ # @option options [ String ] :label The field's label.
24
32
  #
25
- # <tt>Field.new(:score, :default => 0)</tt>
33
+ # @since 1.0.0
26
34
  def initialize(name, options = {})
27
- check_name!(name)
28
35
  @type = options[:type] || Object
29
- @name, @default = name, options[:default]
36
+ @name, @default, @label = name, options[:default], options[:label]
30
37
  @copyable = (@default.is_a?(Array) || @default.is_a?(Hash))
31
- @label = options[:label]
32
38
  @options = options
33
39
  check_default!
34
40
  end
@@ -40,19 +46,20 @@ module Mongoid #:nodoc:
40
46
  # If the field is an identity field, ie an id, it performs the necessary
41
47
  # cast.
42
48
  #
43
- # Example:
49
+ # @example Get the setter value.
50
+ # field.set("New Value")
44
51
  #
45
- # <tt>field.set("New Value")</tt>
52
+ # @param [ Object ] object The value to cast to a database value.
46
53
  #
47
- # Returns:
54
+ # @return [ Object ] The typecast value.
48
55
  #
49
- # The new value.
56
+ # @since 1.0.0
50
57
  def set(object)
51
58
  unless options[:identity]
52
59
  type.set(object)
53
60
  else
54
61
  if object.blank?
55
- type.set(object)
62
+ type.set(object) if object.is_a?(Array)
56
63
  else
57
64
  options[:metadata].constraint.convert(object)
58
65
  end
@@ -61,30 +68,40 @@ module Mongoid #:nodoc:
61
68
 
62
69
  # Used for retrieving the object out of the attributes hash.
63
70
  #
64
- # Example:
71
+ # @example Get the value.
72
+ # field.get("Value")
65
73
  #
66
- # <tt>field.get("Value")</tt>
74
+ # @param [ Object ] The object to cast from the database.
67
75
  #
68
- # Returns:
76
+ # @return [ Object ] The converted value.
69
77
  #
70
- # The converted value.
78
+ # @since 1.0.0
71
79
  def get(object)
72
80
  type.get(object)
73
81
  end
74
82
 
75
83
  protected
76
- # Slightly faster default check.
84
+
85
+ # Copy the default value if copyable.
86
+ #
87
+ # @example Copy the default.
88
+ # field.copy
89
+ #
90
+ # @return [ Object ] The copied object or the original.
91
+ #
92
+ # @since 1.0.0
77
93
  def copy
78
94
  copyable ? @default.dup : @default
79
95
  end
80
96
 
81
- # Check if the name is valid.
82
- def check_name!(name)
83
- if Mongoid.destructive_fields.include?(name.to_s)
84
- raise Mongoid::Errors::InvalidField.new(name)
85
- end
86
- end
87
-
97
+ # Checks if the default value is of the same type as the field.
98
+ #
99
+ # @example Check the default value.
100
+ # field.check_default!
101
+ #
102
+ # @raise [ Errors::InvalidType ] If the types differ.
103
+ #
104
+ # @since 1.0.0
88
105
  def check_default!
89
106
  return if @default.is_a?(Proc)
90
107
  if !@default.nil? && !@default.is_a?(type)
@@ -9,11 +9,17 @@ module Mongoid #:nodoc
9
9
  # Set up the class attributes that must be available to all subclasses.
10
10
  # These include defaults, fields
11
11
  delegate :defaults, :fields, :to => "self.class"
12
+
13
+ field(:_type, :type => String)
14
+ field(:_id, :type => BSON::ObjectId)
15
+
16
+ alias :id :_id
17
+ alias :id= :_id=
12
18
  end
13
19
 
14
20
  module ClassMethods #:nodoc
15
21
 
16
- # Defines all the fields that are accessable on the Document
22
+ # Defines all the fields that are accessible on the Document
17
23
  # For each field that is defined, a getter and setter will be
18
24
  # added as an instance method to the Document.
19
25
  #
@@ -71,7 +77,7 @@ module Mongoid #:nodoc
71
77
  end
72
78
 
73
79
  # When inheriting, we want to copy the fields from the parent class and
74
- # set the on the child to start, mimicing the behaviour of the old
80
+ # set the on the child to start, mimicking the behaviour of the old
75
81
  # class_inheritable_accessor that was deprecated in Rails edge.
76
82
  #
77
83
  # @example Inherit from this class.
@@ -81,6 +87,7 @@ module Mongoid #:nodoc
81
87
  #
82
88
  # @since 2.0.0.rc.6
83
89
  def inherited(subclass)
90
+ super
84
91
  subclass.fields = fields.dup
85
92
  end
86
93
 
@@ -1,12 +1,15 @@
1
1
  # encoding: utf-8
2
2
  module Mongoid #:nodoc:
3
- module Finders #:nodoc:
3
+
4
+ # This module defines the finder methods that hang off the document at the
5
+ # class level.
6
+ module Finders
4
7
 
5
8
  # Delegate to the criteria methods that are natural for creating a new
6
9
  # criteria.
7
10
  [ :all_in, :any_in, :any_of, :asc, :ascending, :avg, :desc, :descending,
8
11
  :excludes, :limit, :max, :min, :not_in, :only, :order_by,
9
- :skip, :sum, :where, :update, :update_all, :near ].each do |name|
12
+ :skip, :sum, :without, :where, :update, :update_all, :near ].each do |name|
10
13
  define_method(name) do |*args|
11
14
  criteria.send(name, *args)
12
15
  end
@@ -28,7 +31,7 @@ module Mongoid #:nodoc:
28
31
  #
29
32
  # <tt>Person.count(:conditions => { :attribute => "value" })</tt>
30
33
  def count(*args)
31
- Criteria.translate(self, false, *args).count
34
+ find(:all, *args).count
32
35
  end
33
36
 
34
37
  # Returns true if there are on document in database based on the
@@ -36,17 +39,7 @@ module Mongoid #:nodoc:
36
39
  #
37
40
  # <tt>Person.exists?(:conditions => { :attribute => "value" })</tt>
38
41
  def exists?(*args)
39
- Criteria.translate(self, false, *args).limit(1).count == 1
40
- end
41
-
42
- # Helper to initialize a new +Criteria+ object for this class, or return
43
- # the currently scoped +Criteria+ object.
44
- #
45
- # Example:
46
- #
47
- # <tt>Person.criteria</tt>
48
- def criteria(embedded = false)
49
- scope_stack.last || Criteria.new(self, embedded)
42
+ find(:all, *args).limit(1).count == 1
50
43
  end
51
44
 
52
45
  # Find a +Document+ in several different ways.
@@ -71,16 +64,7 @@ module Mongoid #:nodoc:
71
64
  #
72
65
  # A document or criteria.
73
66
  def find(*args)
74
- raise Errors::InvalidOptions.new(
75
- :calling_document_find_with_nil_is_invalid, {}
76
- ) if args[0].nil?
77
- type, criteria = Criteria.parse!(self, false, *args)
78
- case type
79
- when :first then return criteria.one
80
- when :last then return criteria.last
81
- else
82
- return criteria
83
- end
67
+ criteria.find(*args)
84
68
  end
85
69
 
86
70
  # Find the first +Document+ given the conditions, or creates a new document
@@ -91,8 +75,8 @@ module Mongoid #:nodoc:
91
75
  # args: A +Hash+ of attributes
92
76
  #
93
77
  # <tt>Person.find_or_create_by(:attribute => "value")</tt>
94
- def find_or_create_by(attrs = {})
95
- find_or(:create, attrs)
78
+ def find_or_create_by(attrs = {}, &block)
79
+ find_or(:create, attrs, &block)
96
80
  end
97
81
 
98
82
  # Find the first +Document+ given the conditions, or instantiates a new document
@@ -103,8 +87,8 @@ module Mongoid #:nodoc:
103
87
  # args: A +Hash+ of attributes
104
88
  #
105
89
  # <tt>Person.find_or_initialize_by(:attribute => "value")</tt>
106
- def find_or_initialize_by(attrs = {})
107
- find_or(:new, attrs)
90
+ def find_or_initialize_by(attrs = {}, &block)
91
+ find_or(:new, attrs, &block)
108
92
  end
109
93
 
110
94
  # Find the first +Document+ given the conditions.
@@ -143,31 +127,13 @@ module Mongoid #:nodoc:
143
127
  #
144
128
  # Returns paginated array of docs.
145
129
  def paginate(params = {})
146
- Criteria.translate(self, false, params).paginate
130
+ find(:all, params).paginate
147
131
  end
148
132
 
149
133
  protected
150
134
  # Find the first object or create/initialize it.
151
- def find_or(method, attrs = {})
152
- first(:conditions => attrs) || send(method, attrs)
153
- end
154
-
155
- # Initializes and returns the current scope stack.
156
- def scope_stack
157
- scope_stack_for = Thread.current[:mongoid_scope_stack] ||= {}
158
- scope_stack_for[object_id] ||= []
159
- end
160
-
161
- # Pushes the provided criteria onto the scope stack, and removes it after the
162
- # provided block is yielded.
163
- def with_scope(criteria)
164
- scope_stack = self.scope_stack
165
- scope_stack << criteria
166
- begin
167
- yield criteria
168
- ensure
169
- scope_stack.pop
170
- end
135
+ def find_or(method, attrs = {}, &block)
136
+ first(:conditions => attrs) || send(method, attrs, &block)
171
137
  end
172
138
  end
173
139
  end
@@ -12,8 +12,7 @@ module Mongoid #:nodoc:
12
12
  # @example Create the id and set the type.
13
13
  # identity.create
14
14
  def create
15
- identify
16
- type
15
+ identify.tap { type }
17
16
  end
18
17
 
19
18
  # Create the new identity generator - this will be expanded in the future
@@ -49,8 +48,11 @@ module Mongoid #:nodoc:
49
48
  # @example Set the id.
50
49
  # identity.identify
51
50
  def identify
52
- document.id = compose.join(" ").identify if document.primary_key
53
- document.id = generate_id if document.id.blank?
51
+ if !document.embedded? || Mongoid.embedded_object_id
52
+ document.id = compose.join(" ").identify if document.primary_key
53
+ document.id = generate_id if document.id.blank?
54
+ end
55
+ document.id
54
56
  end
55
57
 
56
58
  # Set the _type field on the document if the document is hereditary or in a