mongoid 2.0.0.rc.6 → 2.0.0.rc.7
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +2 -2
- data/lib/config/locales/bg.yml +3 -6
- data/lib/config/locales/de.yml +2 -5
- data/lib/config/locales/en.yml +2 -5
- data/lib/config/locales/es.yml +2 -5
- data/lib/config/locales/fr.yml +2 -5
- data/lib/config/locales/hu.yml +2 -5
- data/lib/config/locales/it.yml +2 -5
- data/lib/config/locales/kr.yml +2 -5
- data/lib/config/locales/nl.yml +2 -5
- data/lib/config/locales/pl.yml +2 -5
- data/lib/config/locales/pt-br.yml +2 -5
- data/lib/config/locales/pt.yml +2 -5
- data/lib/config/locales/ro.yml +2 -5
- data/lib/config/locales/ru.yml +41 -0
- data/lib/config/locales/sv.yml +2 -5
- data/lib/config/locales/zh-CN.yml +3 -6
- data/lib/mongoid/atomicity.rb +2 -2
- data/lib/mongoid/attributes.rb +40 -69
- data/lib/mongoid/attributes/processing.rb +142 -0
- data/lib/mongoid/collections.rb +1 -0
- data/lib/mongoid/components.rb +1 -1
- data/lib/mongoid/config.rb +0 -1
- data/lib/mongoid/contexts/mongo.rb +13 -9
- data/lib/mongoid/criteria.rb +15 -1
- data/lib/mongoid/criterion/inclusion.rb +36 -11
- data/lib/mongoid/criterion/inspection.rb +3 -1
- data/lib/mongoid/criterion/optional.rb +2 -2
- data/lib/mongoid/dirty.rb +1 -0
- data/lib/mongoid/document.rb +11 -5
- data/lib/mongoid/extensions/integer/conversions.rb +2 -2
- data/lib/mongoid/extensions/object_id/conversions.rb +62 -32
- data/lib/mongoid/field.rb +5 -2
- data/lib/mongoid/identity.rb +2 -1
- data/lib/mongoid/matchers.rb +5 -32
- data/lib/mongoid/matchers/default.rb +53 -10
- data/lib/mongoid/matchers/or.rb +30 -0
- data/lib/mongoid/matchers/strategies.rb +63 -0
- data/lib/mongoid/multi_parameter_attributes.rb +4 -2
- data/lib/mongoid/nested_attributes.rb +8 -0
- data/lib/mongoid/persistence.rb +2 -1
- data/lib/mongoid/persistence/insert.rb +3 -3
- data/lib/mongoid/persistence/insert_embedded.rb +2 -1
- data/lib/mongoid/relations.rb +2 -1
- data/lib/mongoid/relations/bindings/referenced/many_to_many.rb +4 -2
- data/lib/mongoid/relations/builders/nested_attributes/many.rb +2 -0
- data/lib/mongoid/relations/cascading.rb +1 -1
- data/lib/mongoid/relations/cascading/nullify.rb +1 -1
- data/lib/mongoid/relations/constraint.rb +42 -0
- data/lib/mongoid/relations/cyclic.rb +6 -0
- data/lib/mongoid/relations/embedded/many.rb +4 -4
- data/lib/mongoid/relations/macros.rb +1 -1
- data/lib/mongoid/relations/many.rb +1 -0
- data/lib/mongoid/relations/metadata.rb +12 -4
- data/lib/mongoid/relations/nested_builder.rb +1 -3
- data/lib/mongoid/relations/referenced/many.rb +11 -18
- data/lib/mongoid/relations/referenced/many_to_many.rb +19 -32
- data/lib/mongoid/relations/referenced/one.rb +3 -1
- data/lib/mongoid/timestamps.rb +1 -1
- data/lib/mongoid/validations/associated.rb +11 -9
- data/lib/mongoid/validations/uniqueness.rb +1 -1
- data/lib/mongoid/version.rb +1 -1
- data/lib/mongoid/versioning.rb +2 -2
- metadata +9 -4
data/lib/mongoid/field.rb
CHANGED
@@ -51,8 +51,11 @@ module Mongoid #:nodoc:
|
|
51
51
|
unless options[:identity]
|
52
52
|
type.set(object)
|
53
53
|
else
|
54
|
-
|
55
|
-
|
54
|
+
if object.blank?
|
55
|
+
type.set(object)
|
56
|
+
else
|
57
|
+
options[:metadata].constraint.convert(object)
|
58
|
+
end
|
56
59
|
end
|
57
60
|
end
|
58
61
|
|
data/lib/mongoid/identity.rb
CHANGED
data/lib/mongoid/matchers.rb
CHANGED
@@ -1,15 +1,5 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
require "mongoid/matchers/
|
3
|
-
require "mongoid/matchers/all"
|
4
|
-
require "mongoid/matchers/exists"
|
5
|
-
require "mongoid/matchers/gt"
|
6
|
-
require "mongoid/matchers/gte"
|
7
|
-
require "mongoid/matchers/in"
|
8
|
-
require "mongoid/matchers/lt"
|
9
|
-
require "mongoid/matchers/lte"
|
10
|
-
require "mongoid/matchers/ne"
|
11
|
-
require "mongoid/matchers/nin"
|
12
|
-
require "mongoid/matchers/size"
|
2
|
+
require "mongoid/matchers/strategies"
|
13
3
|
|
14
4
|
module Mongoid #:nodoc:
|
15
5
|
|
@@ -28,28 +18,11 @@ module Mongoid #:nodoc:
|
|
28
18
|
# @return [ true, false ] True if matches, false if not.
|
29
19
|
def matches?(selector)
|
30
20
|
selector.each_pair do |key, value|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
protected
|
36
|
-
|
37
|
-
# Get the matcher for the supplied key and value. Will determine the class
|
38
|
-
# name from the key.
|
39
|
-
#
|
40
|
-
# @example Get the matcher.
|
41
|
-
# document.matcher(:title, { "$in" => [ "test" ] })
|
42
|
-
#
|
43
|
-
# @param [ Symbol, String ] key The field name.
|
44
|
-
# @param [ Object, Hash ] The value or selector.
|
45
|
-
#
|
46
|
-
# @return [ Matcher ] The matcher.
|
47
|
-
def matcher(key, value)
|
48
|
-
if value.is_a?(Hash)
|
49
|
-
name = "Mongoid::Matchers::#{value.keys.first.gsub("$", "").camelize}"
|
50
|
-
return name.constantize.new(attributes[key])
|
21
|
+
unless Strategies.matcher(self, key, value).matches?(value)
|
22
|
+
return false
|
23
|
+
end
|
51
24
|
end
|
52
|
-
|
25
|
+
return true
|
53
26
|
end
|
54
27
|
end
|
55
28
|
end
|
@@ -1,26 +1,69 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
module Mongoid #:nodoc:
|
3
3
|
module Matchers #:nodoc:
|
4
|
+
|
5
|
+
# Contains all the default behavior for checking for matching documents
|
6
|
+
# given MongoDB expressions.
|
4
7
|
class Default
|
8
|
+
|
9
|
+
attr_accessor :attribute, :document
|
10
|
+
|
5
11
|
# Creating a new matcher only requires the value.
|
6
|
-
|
7
|
-
|
12
|
+
#
|
13
|
+
# @example Create a new matcher.
|
14
|
+
# Default.new("attribute")
|
15
|
+
#
|
16
|
+
# @param [ Object ] attribute The current attribute to check against.
|
17
|
+
#
|
18
|
+
# @since 1.0.0
|
19
|
+
def initialize(attribute, document = nil)
|
20
|
+
@attribute, @document = attribute, document
|
8
21
|
end
|
9
|
-
|
22
|
+
|
23
|
+
# Return true if the attribute and value are equal, or if it is an array
|
24
|
+
# if the value is included.
|
25
|
+
#
|
26
|
+
# @example Does this value match?
|
27
|
+
# default.matches?("value")
|
28
|
+
#
|
29
|
+
# @param [ Object ] value The value to check if it matches.
|
30
|
+
#
|
31
|
+
# @return [ true, false ] True if matches, false if not.
|
32
|
+
#
|
33
|
+
# @since 1.0.0
|
10
34
|
def matches?(value)
|
11
|
-
|
12
|
-
@attribute.include?(value) : value === @attribute
|
35
|
+
attribute.is_a?(Array) ? attribute.include?(value) : value === attribute
|
13
36
|
end
|
14
37
|
|
15
38
|
protected
|
16
|
-
|
17
|
-
|
18
|
-
|
39
|
+
|
40
|
+
# Convenience method for getting the first value in a hash.
|
41
|
+
#
|
42
|
+
# @example Get the first value.
|
43
|
+
# matcher.first(:test => "value")
|
44
|
+
#
|
45
|
+
# @param [ Hash ] hash The has to pull from.
|
46
|
+
#
|
47
|
+
# @return [ Object ] The first value.
|
48
|
+
#
|
49
|
+
# @since 1.0.0
|
50
|
+
def first(hash)
|
51
|
+
hash.values.first
|
19
52
|
end
|
20
53
|
|
21
|
-
# If object exists then compare,
|
54
|
+
# If object exists then compare the two, otherwise return false
|
55
|
+
#
|
56
|
+
# @example Determine if we can compare.
|
57
|
+
# matcher.determine("test", "$in")
|
58
|
+
#
|
59
|
+
# @param [ Object ] value The value to compare with.
|
60
|
+
# @param [ Symbol, String ] operator The comparison operation.
|
61
|
+
#
|
62
|
+
# @return [ true, false ] The comparison or false.
|
63
|
+
#
|
64
|
+
# @since 1.0.0
|
22
65
|
def determine(value, operator)
|
23
|
-
|
66
|
+
attribute ? attribute.send(operator, first(value)) : false
|
24
67
|
end
|
25
68
|
end
|
26
69
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Mongoid #:nodoc:
|
3
|
+
module Matchers #:nodoc:
|
4
|
+
|
5
|
+
# Defines behavior for handling $or expressions in embedded documents.
|
6
|
+
class Or < Default
|
7
|
+
|
8
|
+
# Does the supplied query match the attribute?
|
9
|
+
#
|
10
|
+
# @example Does this match?
|
11
|
+
# matcher.matches?("$or" => [ { field => value } ])
|
12
|
+
#
|
13
|
+
# @param [ Array ] conditions The or expression.
|
14
|
+
#
|
15
|
+
# @return [ true, false ] True if matches, false if not.
|
16
|
+
#
|
17
|
+
# @since 2.0.0.rc.7
|
18
|
+
def matches?(conditions)
|
19
|
+
conditions.each do |condition|
|
20
|
+
key = condition.keys.first
|
21
|
+
value = condition.values.first
|
22
|
+
if Strategies.matcher(document, key, value).matches?(value)
|
23
|
+
return true
|
24
|
+
end
|
25
|
+
end
|
26
|
+
return false
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "mongoid/matchers/default"
|
3
|
+
require "mongoid/matchers/all"
|
4
|
+
require "mongoid/matchers/exists"
|
5
|
+
require "mongoid/matchers/gt"
|
6
|
+
require "mongoid/matchers/gte"
|
7
|
+
require "mongoid/matchers/in"
|
8
|
+
require "mongoid/matchers/lt"
|
9
|
+
require "mongoid/matchers/lte"
|
10
|
+
require "mongoid/matchers/ne"
|
11
|
+
require "mongoid/matchers/nin"
|
12
|
+
require "mongoid/matchers/or"
|
13
|
+
require "mongoid/matchers/size"
|
14
|
+
|
15
|
+
module Mongoid #:nodoc:
|
16
|
+
module Matchers #:nodoc:
|
17
|
+
|
18
|
+
# This module is responsible for returning the correct matcher given a
|
19
|
+
# MongoDB query expression.
|
20
|
+
module Strategies
|
21
|
+
extend self
|
22
|
+
|
23
|
+
MATCHERS = {
|
24
|
+
"$all" => Matchers::All,
|
25
|
+
"$exists" => Matchers::Exists,
|
26
|
+
"$gt" => Matchers::Gt,
|
27
|
+
"$gte" => Matchers::Gte,
|
28
|
+
"$in" => Matchers::In,
|
29
|
+
"$lt" => Matchers::Lt,
|
30
|
+
"$lte" => Matchers::Lte,
|
31
|
+
"$ne" => Matchers::Ne,
|
32
|
+
"$nin" => Matchers::Nin,
|
33
|
+
"$or" => Matchers::Or,
|
34
|
+
"$size" => Matchers::Size
|
35
|
+
}
|
36
|
+
|
37
|
+
# Get the matcher for the supplied key and value. Will determine the class
|
38
|
+
# name from the key.
|
39
|
+
#
|
40
|
+
# @example Get the matcher.
|
41
|
+
# document.matcher(:title, { "$in" => [ "test" ] })
|
42
|
+
#
|
43
|
+
# @param [ Document ] document The document to check.
|
44
|
+
# @param [ Symbol, String ] key The field name.
|
45
|
+
# @param [ Object, Hash ] The value or selector.
|
46
|
+
#
|
47
|
+
# @return [ Matcher ] The matcher.
|
48
|
+
#
|
49
|
+
# @since 2.0.0.rc.7
|
50
|
+
def matcher(document, key, value)
|
51
|
+
if value.is_a?(Hash)
|
52
|
+
MATCHERS[value.keys.first].new(document.attributes[key])
|
53
|
+
else
|
54
|
+
if key == "$or"
|
55
|
+
Matchers::Or.new(value, document)
|
56
|
+
else
|
57
|
+
Default.new(document.attributes[key])
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
module Mongoid #:nodoc:
|
3
|
+
|
4
|
+
# @todo: Durran: This module needs an overhaul.
|
3
5
|
module MultiParameterAttributes
|
4
6
|
module Errors
|
5
7
|
# Raised when an error occurred while doing a mass assignment to an attribute through the
|
@@ -64,9 +66,9 @@ module Mongoid #:nodoc:
|
|
64
66
|
|
65
67
|
def instantiate_object(klass, values_with_empty_parameters)
|
66
68
|
return nil if values_with_empty_parameters.all? { |v| v.nil? }
|
67
|
-
|
69
|
+
|
68
70
|
values = values_with_empty_parameters.collect { |v| v.nil? ? 1 : v }
|
69
|
-
|
71
|
+
|
70
72
|
if klass == DateTime || klass == Date || klass == Time
|
71
73
|
klass.send(:convert_to_time, values)
|
72
74
|
elsif klass
|
@@ -3,6 +3,13 @@ module Mongoid #:nodoc:
|
|
3
3
|
module NestedAttributes
|
4
4
|
extend ActiveSupport::Concern
|
5
5
|
|
6
|
+
included do
|
7
|
+
class_attribute :nested_attributes
|
8
|
+
self.nested_attributes = []
|
9
|
+
|
10
|
+
delegate :nested_attributes, :to => "self.class"
|
11
|
+
end
|
12
|
+
|
6
13
|
module ClassMethods
|
7
14
|
REJECT_ALL_BLANK_PROC = proc { |attributes| attributes.all? { |_, value| value.blank? } }
|
8
15
|
|
@@ -32,6 +39,7 @@ module Mongoid #:nodoc:
|
|
32
39
|
options = args.extract_options!
|
33
40
|
options[:reject_if] = REJECT_ALL_BLANK_PROC if options[:reject_if] == :all_blank
|
34
41
|
args.each do |name|
|
42
|
+
self.nested_attributes += [ "#{name}_attributes=" ]
|
35
43
|
define_method("#{name}_attributes=") do |attrs|
|
36
44
|
relation = relations[name.to_s]
|
37
45
|
relation.nested_builder(attrs, options).build(self)
|
data/lib/mongoid/persistence.rb
CHANGED
@@ -55,6 +55,7 @@ module Mongoid #:nodoc:
|
|
55
55
|
# @return [ TrueClass ] True.
|
56
56
|
def remove(options = {})
|
57
57
|
if Remove.new(self, options).persist
|
58
|
+
raw_attributes.freeze
|
58
59
|
self.destroyed = true
|
59
60
|
cascade!
|
60
61
|
end; true
|
@@ -71,7 +72,7 @@ module Mongoid #:nodoc:
|
|
71
72
|
#
|
72
73
|
# @return [ true, false ] True if validation passed.
|
73
74
|
def save!(options = {})
|
74
|
-
self.class.fail_validate!(self) unless upsert; true
|
75
|
+
self.class.fail_validate!(self) unless upsert(options); true
|
75
76
|
end
|
76
77
|
|
77
78
|
# Update the document in the datbase.
|
@@ -25,8 +25,8 @@ module Mongoid #:nodoc:
|
|
25
25
|
# The +Document+, whether the insert succeeded or not.
|
26
26
|
def persist
|
27
27
|
return document if validate && document.invalid?(:create)
|
28
|
-
document.run_callbacks(:
|
29
|
-
document.run_callbacks(:
|
28
|
+
document.run_callbacks(:save) do
|
29
|
+
document.run_callbacks(:create) do
|
30
30
|
if insert
|
31
31
|
document.new_record = false
|
32
32
|
document._children.each { |child| child.new_record = false }
|
@@ -45,7 +45,7 @@ module Mongoid #:nodoc:
|
|
45
45
|
options.merge(:validate => validate)
|
46
46
|
).persist
|
47
47
|
else
|
48
|
-
collection.insert(document.
|
48
|
+
collection.insert(document.as_document, options)
|
49
49
|
end
|
50
50
|
end
|
51
51
|
end
|
@@ -31,9 +31,10 @@ module Mongoid #:nodoc:
|
|
31
31
|
if parent.new_record?
|
32
32
|
parent.insert
|
33
33
|
else
|
34
|
-
update = { document._inserter => { document._position => document.
|
34
|
+
update = { document._inserter => { document._position => document.as_document } }
|
35
35
|
collection.update(parent._selector, update, options.merge(:multi => false))
|
36
36
|
document.new_record = false
|
37
|
+
document.move_changes
|
37
38
|
end
|
38
39
|
document
|
39
40
|
end
|
data/lib/mongoid/relations.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
require "mongoid/relations/accessors"
|
3
3
|
require "mongoid/relations/auto_save"
|
4
4
|
require "mongoid/relations/cascading"
|
5
|
+
require "mongoid/relations/constraint"
|
5
6
|
require "mongoid/relations/cyclic"
|
6
7
|
require "mongoid/relations/proxy"
|
7
8
|
require "mongoid/relations/bindings"
|
@@ -50,7 +51,7 @@ module Mongoid # :nodoc:
|
|
50
51
|
#
|
51
52
|
# @since 2.0.0.rc.1
|
52
53
|
def embedded?
|
53
|
-
_parent.present?
|
54
|
+
cyclic ? _parent.present? : self.class.embedded?
|
54
55
|
end
|
55
56
|
|
56
57
|
# Determine if the document is part of an embeds_many relation.
|
@@ -50,7 +50,7 @@ module Mongoid # :nodoc:
|
|
50
50
|
inverse,
|
51
51
|
false,
|
52
52
|
OPTIONS
|
53
|
-
).push(base, :continue => false)
|
53
|
+
).push(base, :binding => true, :continue => false)
|
54
54
|
end
|
55
55
|
end
|
56
56
|
end
|
@@ -88,7 +88,9 @@ module Mongoid # :nodoc:
|
|
88
88
|
if options[:continue]
|
89
89
|
inverse = metadata.inverse(target)
|
90
90
|
if inverse
|
91
|
-
doc.do_or_do_not(
|
91
|
+
doc.do_or_do_not(
|
92
|
+
inverse, false, OPTIONS
|
93
|
+
).delete(base, :binding => true, :continue => false)
|
92
94
|
end
|
93
95
|
end
|
94
96
|
end
|
@@ -106,6 +106,8 @@ module Mongoid # :nodoc:
|
|
106
106
|
document = existing.find(convert_id(attrs[:id]))
|
107
107
|
destroyable?(attrs) ? document.destroy : document.update_attributes(attrs)
|
108
108
|
else
|
109
|
+
# @todo: Durran: Tell the push not to save the base and call it
|
110
|
+
# after all processing is done. This is related to #581.
|
109
111
|
existing.push(metadata.klass.new(attrs)) unless destroyable?(attrs)
|
110
112
|
end
|
111
113
|
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Mongoid # :nodoc:
|
3
|
+
module Relations #:nodoc:
|
4
|
+
|
5
|
+
# Used for converting foreign key values to the correct type based on the
|
6
|
+
# types of ids that the document stores.
|
7
|
+
#
|
8
|
+
# @note Durran: The name of this class is this way to match the metadata
|
9
|
+
# getter, and foreign_key was already taken there.
|
10
|
+
class Constraint
|
11
|
+
attr_reader :metadata
|
12
|
+
|
13
|
+
# Create the new constraint with the metadata.
|
14
|
+
#
|
15
|
+
# @example Instantiate the constraint.
|
16
|
+
# Constraint.new(metdata)
|
17
|
+
#
|
18
|
+
# @param [ Metadata ] metadata The metadata of the relation.
|
19
|
+
#
|
20
|
+
# @since 2.0.0.rc.7
|
21
|
+
def initialize(metadata)
|
22
|
+
@metadata = metadata
|
23
|
+
end
|
24
|
+
|
25
|
+
# Convert the supplied object to the appropriate type to set as the
|
26
|
+
# foreign key for a relation.
|
27
|
+
#
|
28
|
+
# @example Convert the object.
|
29
|
+
# constraint.convert("12345")
|
30
|
+
#
|
31
|
+
# @param [ Object ] object The object to convert.
|
32
|
+
#
|
33
|
+
# @return [ Object ] The object cast to the correct type.
|
34
|
+
#
|
35
|
+
# @since 2.0.0.rc.7
|
36
|
+
def convert(object)
|
37
|
+
return object if metadata.polymorphic?
|
38
|
+
BSON::ObjectId.convert(metadata.klass, object)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|