mongoid 2.0.0.beta.5 → 2.0.0.beta.7
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.
- data/lib/mongoid.rb +10 -2
- data/lib/mongoid/associations.rb +82 -58
- data/lib/mongoid/associations/embeds_one.rb +6 -6
- data/lib/mongoid/associations/foreign_key.rb +35 -0
- data/lib/mongoid/associations/meta_data.rb +9 -0
- data/lib/mongoid/associations/options.rb +1 -1
- data/lib/mongoid/associations/proxy.rb +9 -0
- data/lib/mongoid/associations/{belongs_to_related.rb → referenced_in.rb} +6 -5
- data/lib/mongoid/associations/{has_many_related.rb → references_many.rb} +69 -26
- data/lib/mongoid/associations/references_many_as_array.rb +78 -0
- data/lib/mongoid/associations/{has_one_related.rb → references_one.rb} +16 -2
- data/lib/mongoid/atomicity.rb +42 -0
- data/lib/mongoid/attributes.rb +148 -146
- data/lib/mongoid/callbacks.rb +5 -1
- data/lib/mongoid/collections.rb +31 -1
- data/lib/mongoid/components.rb +4 -1
- data/lib/mongoid/config.rb +2 -1
- data/lib/mongoid/criteria.rb +9 -0
- data/lib/mongoid/dirty.rb +211 -212
- data/lib/mongoid/document.rb +126 -185
- data/lib/mongoid/extensions.rb +5 -0
- data/lib/mongoid/extensions/array/conversions.rb +3 -5
- data/lib/mongoid/extensions/hash/conversions.rb +19 -22
- data/lib/mongoid/extensions/object/conversions.rb +3 -5
- data/lib/mongoid/extensions/set/conversions.rb +20 -0
- data/lib/mongoid/field.rb +11 -0
- data/lib/mongoid/finders.rb +8 -0
- data/lib/mongoid/hierarchy.rb +76 -0
- data/lib/mongoid/identity.rb +37 -29
- data/lib/mongoid/paths.rb +46 -47
- data/lib/mongoid/persistence.rb +111 -113
- data/lib/mongoid/persistence/insert.rb +1 -1
- data/lib/mongoid/persistence/insert_embedded.rb +10 -5
- data/lib/mongoid/persistence/remove_all.rb +3 -2
- data/lib/mongoid/persistence/update.rb +8 -3
- data/lib/mongoid/railtie.rb +3 -0
- data/lib/mongoid/railties/database.rake +33 -18
- data/lib/mongoid/timestamps.rb +9 -12
- data/lib/mongoid/validations/uniqueness.rb +16 -4
- data/lib/mongoid/version.rb +1 -1
- data/lib/mongoid/versioning.rb +10 -11
- data/lib/rails/generators/mongoid/config/config_generator.rb +0 -16
- metadata +64 -24
@@ -0,0 +1,20 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Mongoid #:nodoc:
|
3
|
+
module Extensions #:nodoc:
|
4
|
+
module Set #:nodoc:
|
5
|
+
# This module converts set into mongoid related objects.
|
6
|
+
module Conversions #:nodoc:
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
module ClassMethods #:nodoc:
|
10
|
+
def get(value)
|
11
|
+
::Set.new(value)
|
12
|
+
end
|
13
|
+
def set(value)
|
14
|
+
value
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/mongoid/field.rb
CHANGED
@@ -12,6 +12,15 @@ module Mongoid #:nodoc:
|
|
12
12
|
!!@accessible
|
13
13
|
end
|
14
14
|
|
15
|
+
# Get the declared options for this field
|
16
|
+
#
|
17
|
+
# Returns:
|
18
|
+
#
|
19
|
+
# a hash of options
|
20
|
+
def options
|
21
|
+
@options
|
22
|
+
end
|
23
|
+
|
15
24
|
# Get the default value for the field.
|
16
25
|
#
|
17
26
|
# Returns:
|
@@ -38,6 +47,8 @@ module Mongoid #:nodoc:
|
|
38
47
|
@copyable = (@default.is_a?(Array) || @default.is_a?(Hash))
|
39
48
|
@type = options[:type] || String
|
40
49
|
@accessible = options.has_key?(:accessible) ? options[:accessible] : true
|
50
|
+
|
51
|
+
@options = options
|
41
52
|
end
|
42
53
|
|
43
54
|
# Used for setting an object in the attributes hash. If nil is provided the
|
data/lib/mongoid/finders.rb
CHANGED
@@ -30,6 +30,14 @@ module Mongoid #:nodoc:
|
|
30
30
|
Criteria.translate(self, *args).count
|
31
31
|
end
|
32
32
|
|
33
|
+
# Returns true if there are on document in database based on the
|
34
|
+
# provided arguments.
|
35
|
+
#
|
36
|
+
# <tt>Person.exists?(:first, :conditions => { :attribute => "value" })</tt>
|
37
|
+
def exists?(*args)
|
38
|
+
Criteria.translate(self, *args).limit(1).count == 1
|
39
|
+
end
|
40
|
+
|
33
41
|
# Helper to initialize a new +Criteria+ object for this class.
|
34
42
|
#
|
35
43
|
# Example:
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Mongoid #:nodoc
|
3
|
+
module Hierarchy #:nodoc
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
included do
|
6
|
+
cattr_accessor :hereditary
|
7
|
+
self.hereditary = false
|
8
|
+
|
9
|
+
attr_accessor :_parent
|
10
|
+
end
|
11
|
+
|
12
|
+
module InstanceMethods #:nodoc:
|
13
|
+
|
14
|
+
# Get all child +Documents+ to this +Document+, going n levels deep if
|
15
|
+
# necessary. This is used when calling update persistence operations from
|
16
|
+
# the root document, where changes in the entire tree need to be
|
17
|
+
# determined. Note that persistence from the embedded documents will
|
18
|
+
# always be preferred, since they are optimized calls... This operation
|
19
|
+
# can get expensive in domains with large hierarchies.
|
20
|
+
#
|
21
|
+
# Example:
|
22
|
+
#
|
23
|
+
# <tt>person._children</tt>
|
24
|
+
#
|
25
|
+
# Returns:
|
26
|
+
#
|
27
|
+
# All child +Documents+ to this +Document+ in the entire hierarchy.
|
28
|
+
def _children
|
29
|
+
associations.inject([]) do |children, (name, metadata)|
|
30
|
+
if metadata.embedded? && name != "versions"
|
31
|
+
child = send(name)
|
32
|
+
child.to_a.each do |doc|
|
33
|
+
children.push(doc).concat(doc._children)
|
34
|
+
end unless child.blank?
|
35
|
+
end
|
36
|
+
children
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Is inheritance in play here?
|
41
|
+
#
|
42
|
+
# Returns:
|
43
|
+
#
|
44
|
+
# <tt>true</tt> if inheritance used, <tt>false</tt> if not.
|
45
|
+
def hereditary?
|
46
|
+
!!self.hereditary
|
47
|
+
end
|
48
|
+
|
49
|
+
# Sets up a child/parent association. This is used for newly created
|
50
|
+
# objects so they can be properly added to the graph and have the parent
|
51
|
+
# observers set up properly.
|
52
|
+
#
|
53
|
+
# Options:
|
54
|
+
#
|
55
|
+
# abject: The parent object that needs to be set for the child.
|
56
|
+
# association_name: The name of the association for the child.
|
57
|
+
#
|
58
|
+
# Example:
|
59
|
+
#
|
60
|
+
# <tt>address.parentize(person, :addresses)</tt>
|
61
|
+
def parentize(object, association_name)
|
62
|
+
self._parent = object
|
63
|
+
self.association_name = association_name.to_s
|
64
|
+
add_observer(object)
|
65
|
+
end
|
66
|
+
|
67
|
+
# Return the root +Document+ in the object graph. If the current +Document+
|
68
|
+
# is the root object in the graph it will return self.
|
69
|
+
def _root
|
70
|
+
object = self
|
71
|
+
while (object._parent) do object = object._parent; end
|
72
|
+
object || self
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
data/lib/mongoid/identity.rb
CHANGED
@@ -1,39 +1,47 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
module Mongoid #:nodoc:
|
3
3
|
class Identity #:nodoc:
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
4
|
+
# Create the identity for the +Document+.
|
5
|
+
#
|
6
|
+
# The id will be set in either in the form of a Mongo
|
7
|
+
# +ObjectID+ or a composite key set up by defining a key on the document.
|
8
|
+
#
|
9
|
+
# The _type will be set to the document's class name.
|
10
|
+
def create
|
11
|
+
identify!; type!
|
12
|
+
end
|
13
|
+
|
14
|
+
# Create the new identity generator - this will be expanded in the future
|
15
|
+
# to support pk generators.
|
16
|
+
#
|
17
|
+
# Options:
|
18
|
+
#
|
19
|
+
# document: The document to generate an id for.
|
20
|
+
def initialize(document)
|
21
|
+
@document = document
|
22
|
+
end
|
14
23
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
24
|
+
protected
|
25
|
+
# Return the proper id for the document.
|
26
|
+
def generate_id
|
27
|
+
id = BSON::ObjectID.new
|
28
|
+
Mongoid.use_object_ids ? id : id.to_s
|
29
|
+
end
|
21
30
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
31
|
+
# Set the id for the document.
|
32
|
+
def identify!
|
33
|
+
@document.id = compose.join(" ").identify if @document.primary_key
|
34
|
+
@document.id = generate_id if @document.id.blank?
|
35
|
+
end
|
27
36
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
37
|
+
# Set the _type field on the @document.ment.
|
38
|
+
def type!
|
39
|
+
@document._type = @document.class.name if @document.hereditary?
|
40
|
+
end
|
32
41
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
end
|
42
|
+
# Generates the composite key for a @document.ment.
|
43
|
+
def compose
|
44
|
+
@document.primary_key.collect { |key| @document.attributes[key] }.reject { |val| val.nil? }
|
37
45
|
end
|
38
46
|
end
|
39
47
|
end
|
data/lib/mongoid/paths.rb
CHANGED
@@ -6,57 +6,56 @@ module Mongoid #:nodoc:
|
|
6
6
|
cattr_accessor :__path
|
7
7
|
attr_accessor :_index
|
8
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
9
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
alias :_pull :_path
|
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
|
30
19
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
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
|
40
30
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
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
50
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
end
|
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 }
|
60
59
|
end
|
61
60
|
end
|
62
61
|
end
|
data/lib/mongoid/persistence.rb
CHANGED
@@ -19,129 +19,127 @@ module Mongoid #:nodoc:
|
|
19
19
|
# <tt>document.upsert</tt>
|
20
20
|
module Persistence
|
21
21
|
extend ActiveSupport::Concern
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
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
|
22
|
+
# Remove the +Document+ from the datbase with callbacks.
|
23
|
+
#
|
24
|
+
# Example:
|
25
|
+
#
|
26
|
+
# <tt>document.destroy</tt>
|
27
|
+
#
|
28
|
+
# TODO: Will get rid of other #destroy once new persistence complete.
|
29
|
+
def destroy
|
30
|
+
run_callbacks(:destroy) { self.destroyed = true if _remove }
|
31
|
+
end
|
43
32
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
end
|
33
|
+
# Insert a new +Document+ into the database. Will return the document
|
34
|
+
# itself whether or not the save was successful.
|
35
|
+
#
|
36
|
+
# Example:
|
37
|
+
#
|
38
|
+
# <tt>document.insert</tt>
|
39
|
+
def insert(validate = true)
|
40
|
+
Insert.new(self, validate).persist
|
41
|
+
end
|
54
42
|
|
55
|
-
|
43
|
+
# Remove the +Document+ from the datbase.
|
44
|
+
#
|
45
|
+
# Example:
|
46
|
+
#
|
47
|
+
# <tt>document._remove</tt>
|
48
|
+
#
|
49
|
+
# TODO: Will get rid of other #remove once observable pattern killed.
|
50
|
+
def _remove
|
51
|
+
Remove.new(self).persist
|
52
|
+
end
|
56
53
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
54
|
+
alias :delete :_remove
|
55
|
+
|
56
|
+
# Save the document - will perform an insert if the document is new, and
|
57
|
+
# update if not. If a validation error occurs a
|
58
|
+
# Mongoid::Errors::Validations error will get raised.
|
59
|
+
#
|
60
|
+
# Example:
|
61
|
+
#
|
62
|
+
# <tt>document.save!</tt>
|
63
|
+
#
|
64
|
+
# Returns:
|
65
|
+
#
|
66
|
+
# +true+ if validation passed, will raise error otherwise.
|
67
|
+
def save!
|
68
|
+
self.class.fail_validate!(self) unless upsert; true
|
69
|
+
end
|
71
70
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
71
|
+
# Update the +Document+ in the datbase.
|
72
|
+
#
|
73
|
+
# Example:
|
74
|
+
#
|
75
|
+
# <tt>document.update</tt>
|
76
|
+
def update(validate = true)
|
77
|
+
Update.new(self, validate).persist
|
78
|
+
end
|
80
79
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
80
|
+
# Update the +Document+ attributes in the datbase.
|
81
|
+
#
|
82
|
+
# Example:
|
83
|
+
#
|
84
|
+
# <tt>document.update_attributes(:title => "Sir")</tt>
|
85
|
+
#
|
86
|
+
# Returns:
|
87
|
+
#
|
88
|
+
# +true+ if validation passed, +false+ if not.
|
89
|
+
def update_attributes(attributes = {})
|
90
|
+
write_attributes(attributes); update
|
91
|
+
end
|
93
92
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
93
|
+
# Update the +Document+ attributes in the datbase.
|
94
|
+
#
|
95
|
+
# Example:
|
96
|
+
#
|
97
|
+
# <tt>document.update_attributes(:title => "Sir")</tt>
|
98
|
+
#
|
99
|
+
# Returns:
|
100
|
+
#
|
101
|
+
# +true+ if validation passed, raises an error if not
|
102
|
+
def update_attributes!(attributes = {})
|
103
|
+
write_attributes(attributes)
|
104
|
+
result = update
|
105
|
+
self.class.fail_validate!(self) unless result
|
106
|
+
result
|
107
|
+
end
|
109
108
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
end
|
109
|
+
# Upsert the document - will perform an insert if the document is new, and
|
110
|
+
# update if not.
|
111
|
+
#
|
112
|
+
# Example:
|
113
|
+
#
|
114
|
+
# <tt>document.upsert</tt>
|
115
|
+
#
|
116
|
+
# Returns:
|
117
|
+
#
|
118
|
+
# A +Boolean+ for updates.
|
119
|
+
def upsert(validate = true)
|
120
|
+
validate = parse_validate(validate)
|
121
|
+
if new_record?
|
122
|
+
insert(validate).persisted?
|
123
|
+
else
|
124
|
+
update(validate)
|
127
125
|
end
|
126
|
+
end
|
128
127
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
end
|
143
|
-
validate
|
128
|
+
# Save is aliased so that users familiar with active record can have some
|
129
|
+
# semblance of a familiar API.
|
130
|
+
#
|
131
|
+
# Example:
|
132
|
+
#
|
133
|
+
# <tt>document.save</tt>
|
134
|
+
alias :save :upsert
|
135
|
+
|
136
|
+
protected
|
137
|
+
# Alternative validation params.
|
138
|
+
def parse_validate(validate)
|
139
|
+
if validate.is_a?(Hash) && validate.has_key?(:validate)
|
140
|
+
validate = validate[:validate]
|
144
141
|
end
|
142
|
+
validate
|
145
143
|
end
|
146
144
|
|
147
145
|
module ClassMethods #:nodoc:
|