mongoid 2.0.0.beta.20 → 2.0.0.rc.1
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/README.rdoc +8 -0
- data/Rakefile +51 -0
- data/lib/config/locales/nl.yml +39 -0
- data/lib/config/locales/ro.yml +1 -1
- data/lib/mongoid.rb +17 -17
- data/lib/mongoid/atomicity.rb +54 -22
- data/lib/mongoid/attributes.rb +145 -125
- data/lib/mongoid/callbacks.rb +7 -2
- data/lib/mongoid/collection.rb +49 -32
- data/lib/mongoid/collections.rb +0 -1
- data/lib/mongoid/components.rb +34 -29
- data/lib/mongoid/config.rb +207 -193
- data/lib/mongoid/config/database.rb +167 -0
- data/lib/mongoid/contexts.rb +2 -5
- data/lib/mongoid/contexts/enumerable.rb +30 -4
- data/lib/mongoid/contexts/ids.rb +2 -2
- data/lib/mongoid/contexts/mongo.rb +30 -5
- data/lib/mongoid/copyable.rb +44 -0
- data/lib/mongoid/criteria.rb +110 -56
- data/lib/mongoid/criterion/creational.rb +34 -0
- data/lib/mongoid/criterion/destructive.rb +37 -0
- data/lib/mongoid/criterion/exclusion.rb +3 -1
- data/lib/mongoid/criterion/inclusion.rb +59 -64
- data/lib/mongoid/criterion/inspection.rb +22 -0
- data/lib/mongoid/criterion/optional.rb +42 -54
- data/lib/mongoid/criterion/selector.rb +9 -0
- data/lib/mongoid/default_scope.rb +28 -0
- data/lib/mongoid/deprecation.rb +5 -5
- data/lib/mongoid/dirty.rb +4 -5
- data/lib/mongoid/document.rb +161 -114
- data/lib/mongoid/extensions.rb +7 -11
- data/lib/mongoid/extensions/array/parentization.rb +2 -2
- data/lib/mongoid/extensions/date/conversions.rb +1 -1
- data/lib/mongoid/extensions/hash/conversions.rb +0 -23
- data/lib/mongoid/extensions/nil/collectionization.rb +12 -0
- data/lib/mongoid/extensions/object/reflections.rb +17 -0
- data/lib/mongoid/extensions/object/yoda.rb +27 -0
- data/lib/mongoid/extensions/string/conversions.rb +23 -4
- data/lib/mongoid/extensions/time_conversions.rb +4 -4
- data/lib/mongoid/field.rb +30 -19
- data/lib/mongoid/fields.rb +15 -5
- data/lib/mongoid/finders.rb +19 -11
- data/lib/mongoid/hierarchy.rb +34 -28
- data/lib/mongoid/identity.rb +62 -20
- data/lib/mongoid/inspection.rb +58 -0
- data/lib/mongoid/matchers.rb +20 -0
- data/lib/mongoid/multi_database.rb +11 -0
- data/lib/mongoid/nested_attributes.rb +41 -0
- data/lib/mongoid/paranoia.rb +3 -4
- data/lib/mongoid/paths.rb +1 -1
- data/lib/mongoid/persistence.rb +89 -90
- data/lib/mongoid/persistence/command.rb +20 -4
- data/lib/mongoid/persistence/insert.rb +13 -11
- data/lib/mongoid/persistence/insert_embedded.rb +8 -6
- data/lib/mongoid/persistence/remove.rb +6 -4
- data/lib/mongoid/persistence/remove_all.rb +6 -4
- data/lib/mongoid/persistence/remove_embedded.rb +8 -6
- data/lib/mongoid/persistence/update.rb +12 -10
- data/lib/mongoid/railtie.rb +2 -2
- data/lib/mongoid/railties/database.rake +10 -9
- data/lib/mongoid/relations.rb +104 -0
- data/lib/mongoid/relations/accessors.rb +154 -0
- data/lib/mongoid/relations/auto_save.rb +34 -0
- data/lib/mongoid/relations/binding.rb +24 -0
- data/lib/mongoid/relations/bindings.rb +9 -0
- data/lib/mongoid/relations/bindings/embedded/in.rb +77 -0
- data/lib/mongoid/relations/bindings/embedded/many.rb +93 -0
- data/lib/mongoid/relations/bindings/embedded/one.rb +65 -0
- data/lib/mongoid/relations/bindings/referenced/in.rb +78 -0
- data/lib/mongoid/relations/bindings/referenced/many.rb +93 -0
- data/lib/mongoid/relations/bindings/referenced/many_to_many.rb +94 -0
- data/lib/mongoid/relations/bindings/referenced/one.rb +63 -0
- data/lib/mongoid/relations/builder.rb +41 -0
- data/lib/mongoid/relations/builders.rb +79 -0
- data/lib/mongoid/relations/builders/embedded/in.rb +25 -0
- data/lib/mongoid/relations/builders/embedded/many.rb +32 -0
- data/lib/mongoid/relations/builders/embedded/one.rb +26 -0
- data/lib/mongoid/relations/builders/nested_attributes/many.rb +116 -0
- data/lib/mongoid/relations/builders/nested_attributes/one.rb +135 -0
- data/lib/mongoid/relations/builders/referenced/in.rb +32 -0
- data/lib/mongoid/relations/builders/referenced/many.rb +26 -0
- data/lib/mongoid/relations/builders/referenced/many_to_many.rb +29 -0
- data/lib/mongoid/relations/builders/referenced/one.rb +30 -0
- data/lib/mongoid/relations/cascading.rb +55 -0
- data/lib/mongoid/relations/cascading/delete.rb +19 -0
- data/lib/mongoid/relations/cascading/destroy.rb +19 -0
- data/lib/mongoid/relations/cascading/nullify.rb +18 -0
- data/lib/mongoid/relations/cascading/strategy.rb +26 -0
- data/lib/mongoid/relations/cyclic.rb +97 -0
- data/lib/mongoid/relations/embedded/in.rb +172 -0
- data/lib/mongoid/relations/embedded/many.rb +450 -0
- data/lib/mongoid/relations/embedded/one.rb +169 -0
- data/lib/mongoid/relations/macros.rb +302 -0
- data/lib/mongoid/relations/many.rb +185 -0
- data/lib/mongoid/relations/metadata.rb +529 -0
- data/lib/mongoid/relations/nested_builder.rb +52 -0
- data/lib/mongoid/relations/one.rb +29 -0
- data/lib/mongoid/relations/polymorphic.rb +54 -0
- data/lib/mongoid/relations/proxy.rb +122 -0
- data/lib/mongoid/relations/referenced/in.rb +214 -0
- data/lib/mongoid/relations/referenced/many.rb +358 -0
- data/lib/mongoid/relations/referenced/many_to_many.rb +379 -0
- data/lib/mongoid/relations/referenced/one.rb +204 -0
- data/lib/mongoid/relations/reflections.rb +45 -0
- data/lib/mongoid/safe.rb +11 -1
- data/lib/mongoid/safety.rb +122 -97
- data/lib/mongoid/scope.rb +14 -9
- data/lib/mongoid/state.rb +37 -3
- data/lib/mongoid/timestamps.rb +11 -0
- data/lib/mongoid/validations.rb +42 -3
- data/lib/mongoid/validations/associated.rb +8 -5
- data/lib/mongoid/validations/uniqueness.rb +23 -2
- data/lib/mongoid/version.rb +1 -1
- data/lib/mongoid/versioning.rb +25 -16
- data/lib/rails/generators/mongoid/model/templates/model.rb +3 -1
- metadata +95 -80
- data/lib/mongoid/associations.rb +0 -364
- data/lib/mongoid/associations/embedded_in.rb +0 -74
- data/lib/mongoid/associations/embeds_many.rb +0 -299
- data/lib/mongoid/associations/embeds_one.rb +0 -111
- data/lib/mongoid/associations/foreign_key.rb +0 -35
- data/lib/mongoid/associations/meta_data.rb +0 -38
- data/lib/mongoid/associations/options.rb +0 -78
- data/lib/mongoid/associations/proxy.rb +0 -60
- data/lib/mongoid/associations/referenced_in.rb +0 -70
- data/lib/mongoid/associations/references_many.rb +0 -254
- data/lib/mongoid/associations/references_many_as_array.rb +0 -128
- data/lib/mongoid/associations/references_one.rb +0 -104
- data/lib/mongoid/extensions/array/accessors.rb +0 -17
- data/lib/mongoid/extensions/array/assimilation.rb +0 -26
- data/lib/mongoid/extensions/hash/accessors.rb +0 -42
- data/lib/mongoid/extensions/hash/assimilation.rb +0 -40
- data/lib/mongoid/extensions/nil/assimilation.rb +0 -17
- data/lib/mongoid/memoization.rb +0 -33
@@ -0,0 +1,167 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Mongoid #:nodoc:
|
3
|
+
module Config #:nodoc:
|
4
|
+
|
5
|
+
# This class handles the configuration and initialization of a mongodb
|
6
|
+
# database from options.
|
7
|
+
class Database < Hash
|
8
|
+
|
9
|
+
# Configure the database connections. This will return an array
|
10
|
+
# containing the master and an array of slaves.
|
11
|
+
#
|
12
|
+
# @example Configure the connection.
|
13
|
+
# db.configure
|
14
|
+
#
|
15
|
+
# @return [ Array<Mongo::DB, Array<Mongo:DB>> ] The Mongo databases.
|
16
|
+
#
|
17
|
+
# @since 2.0.0.rc.1
|
18
|
+
def configure
|
19
|
+
[ master.db(name), slaves.map { |slave| slave.db(name) } ]
|
20
|
+
end
|
21
|
+
|
22
|
+
# Create the new db configuration class.
|
23
|
+
#
|
24
|
+
# @example Initialize the class.
|
25
|
+
# Config::Database.new(
|
26
|
+
# false, "uri" => { "mongodb://durran:password@localhost:27017/mongoid" }
|
27
|
+
# )
|
28
|
+
#
|
29
|
+
# @param [ Hash ] options The configuration options.
|
30
|
+
#
|
31
|
+
# @option options [ String ] :database The database name.
|
32
|
+
# @option options [ String ] :host The database host.
|
33
|
+
# @option options [ String ] :password The password for authentication.
|
34
|
+
# @option options [ Integer ] :port The port for the database.
|
35
|
+
# @option options [ String ] :uri The uri for the database.
|
36
|
+
# @option options [ String ] :username The user for authentication.
|
37
|
+
#
|
38
|
+
# @since 2.0.0.rc.1
|
39
|
+
def initialize(options = {})
|
40
|
+
merge!(options)
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
# Do we need to authenticate against the database?
|
46
|
+
#
|
47
|
+
# @example Are we authenticating?
|
48
|
+
# db.authenticating?
|
49
|
+
#
|
50
|
+
# @return [ true, false ] True if auth is needed, false if not.
|
51
|
+
#
|
52
|
+
# @since 2.0.0.rc.1
|
53
|
+
def authenticating?
|
54
|
+
username || password
|
55
|
+
end
|
56
|
+
|
57
|
+
# Takes the supplied options in the hash and created a URI from them to
|
58
|
+
# pass to the Mongo connection object.
|
59
|
+
#
|
60
|
+
# @example Build the URI.
|
61
|
+
# db.build_uri
|
62
|
+
#
|
63
|
+
# @param [ Hash ] options The options to build with.
|
64
|
+
#
|
65
|
+
# @return [ String ] A mongo compliant URI string.
|
66
|
+
#
|
67
|
+
# @since 2.0.0.rc.1
|
68
|
+
def build_uri(options = {})
|
69
|
+
"mongodb://".tap do |base|
|
70
|
+
base << "#{username}:#{password}@" if authenticating?
|
71
|
+
base << "#{options["host"] || "localhost"}:#{options["port"] || 27017}"
|
72
|
+
base << "/#{self["database"]}" if authenticating?
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# Create the mongo master connection from either the supplied URI
|
77
|
+
# or a generated one, while setting pool size and logging.
|
78
|
+
#
|
79
|
+
# @example Create the connection.
|
80
|
+
# db.connection
|
81
|
+
#
|
82
|
+
# @return [ Mongo::Connection ] The mongo connection.
|
83
|
+
#
|
84
|
+
# @since 2.0.0.rc.1
|
85
|
+
def master
|
86
|
+
Mongo::Connection.from_uri(uri(self), optional).tap do |conn|
|
87
|
+
conn.apply_saved_authentication
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# Create the mongo slave connections from either the supplied URI
|
92
|
+
# or a generated one, while setting pool size and logging.
|
93
|
+
#
|
94
|
+
# @example Create the connection.
|
95
|
+
# db.connection
|
96
|
+
#
|
97
|
+
# @return [ Array<Mongo::Connection> ] The mongo slave connections.
|
98
|
+
#
|
99
|
+
# @since 2.0.0.rc.1
|
100
|
+
def slaves
|
101
|
+
(self["slaves"] || []).map do |options|
|
102
|
+
Mongo::Connection.from_uri(uri(options), optional(true)).tap do |conn|
|
103
|
+
conn.apply_saved_authentication
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# Convenience for accessing the hash via dot notation.
|
109
|
+
#
|
110
|
+
# @example Access a value in alternate syntax.
|
111
|
+
# db.host
|
112
|
+
#
|
113
|
+
# @return [ Object ] The value in the hash.
|
114
|
+
#
|
115
|
+
# @since 2.0.0.rc.1
|
116
|
+
def method_missing(name, *args, &block)
|
117
|
+
self[name.to_s]
|
118
|
+
end
|
119
|
+
|
120
|
+
# Get the name of the database, from either the URI supplied or the
|
121
|
+
# database value in the options.
|
122
|
+
#
|
123
|
+
# @example Get the database name.
|
124
|
+
# db.name
|
125
|
+
#
|
126
|
+
# @return [ String ] The database name.
|
127
|
+
#
|
128
|
+
# @since 2.0.0.rc.1
|
129
|
+
def name
|
130
|
+
db_name = URI.parse(uri(self)).path.to_s.sub("/", "")
|
131
|
+
db_name.blank? ? database : db_name
|
132
|
+
end
|
133
|
+
|
134
|
+
# Get the options used in creating the database connection.
|
135
|
+
#
|
136
|
+
# @example Get the options.
|
137
|
+
# db.options
|
138
|
+
#
|
139
|
+
# @param [ true, false ] slave Are the options for a slave db?
|
140
|
+
#
|
141
|
+
# @return [ Hash ] The hash of configuration options.
|
142
|
+
#
|
143
|
+
# @since 2.0.0.rc.1
|
144
|
+
def optional(slave = false)
|
145
|
+
{
|
146
|
+
:pool_size => pool_size,
|
147
|
+
:logger => Mongoid::Logger.new,
|
148
|
+
:slave_ok => slave
|
149
|
+
}
|
150
|
+
end
|
151
|
+
|
152
|
+
# Get a Mongo compliant URI for the database connection.
|
153
|
+
#
|
154
|
+
# @example Get the URI.
|
155
|
+
# db.uri
|
156
|
+
#
|
157
|
+
# @param [ Hash ] options The options hash.
|
158
|
+
#
|
159
|
+
# @return [ String ] The URI for the connection.
|
160
|
+
#
|
161
|
+
# @since 2.0.0.rc.1
|
162
|
+
def uri(options = {})
|
163
|
+
options["uri"] || build_uri(options)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
data/lib/mongoid/contexts.rb
CHANGED
@@ -14,11 +14,8 @@ module Mongoid
|
|
14
14
|
# Example:
|
15
15
|
#
|
16
16
|
# <tt>Contexts.context_for(criteria)</tt>
|
17
|
-
def self.context_for(criteria)
|
18
|
-
|
19
|
-
return Contexts::Enumerable.new(criteria)
|
20
|
-
end
|
21
|
-
Contexts::Mongo.new(criteria)
|
17
|
+
def self.context_for(criteria, embedded = false)
|
18
|
+
embedded ? Enumerable.new(criteria) : Mongo.new(criteria)
|
22
19
|
end
|
23
20
|
end
|
24
21
|
end
|
@@ -6,7 +6,7 @@ module Mongoid #:nodoc:
|
|
6
6
|
module Contexts #:nodoc:
|
7
7
|
class Enumerable
|
8
8
|
include Ids, Paging
|
9
|
-
|
9
|
+
attr_accessor :criteria
|
10
10
|
|
11
11
|
delegate :blank?, :empty?, :first, :last, :to => :execute
|
12
12
|
delegate :klass, :documents, :options, :selector, :to => :criteria
|
@@ -42,6 +42,32 @@ module Mongoid #:nodoc:
|
|
42
42
|
@count ||= filter.size
|
43
43
|
end
|
44
44
|
|
45
|
+
# Delete all the documents in the database matching the selector.
|
46
|
+
#
|
47
|
+
# @example Delete the documents.
|
48
|
+
# context.delete_all
|
49
|
+
#
|
50
|
+
# @return [ Integer ] The number of documents deleted.
|
51
|
+
#
|
52
|
+
# @since 2.0.0.rc.1
|
53
|
+
def delete_all
|
54
|
+
count.tap { filter.each(&:delete) }
|
55
|
+
end
|
56
|
+
alias :delete :delete_all
|
57
|
+
|
58
|
+
# Destroy all the documents in the database matching the selector.
|
59
|
+
#
|
60
|
+
# @example Destroy the documents.
|
61
|
+
# context.destroy_all
|
62
|
+
#
|
63
|
+
# @return [ Integer ] The number of documents destroyed.
|
64
|
+
#
|
65
|
+
# @since 2.0.0.rc.1
|
66
|
+
def destroy_all
|
67
|
+
count.tap { filter.each(&:destroy) }
|
68
|
+
end
|
69
|
+
alias :destroy :destroy_all
|
70
|
+
|
45
71
|
# Gets an array of distinct values for the supplied field across the
|
46
72
|
# entire array or the susbset given the criteria.
|
47
73
|
#
|
@@ -125,9 +151,9 @@ module Mongoid #:nodoc:
|
|
125
151
|
#
|
126
152
|
# The first document in the +Array+
|
127
153
|
def shift
|
128
|
-
|
129
|
-
|
130
|
-
|
154
|
+
first.tap do |document|
|
155
|
+
self.criteria = criteria.skip((options[:skip] || 0) + 1)
|
156
|
+
end
|
131
157
|
end
|
132
158
|
|
133
159
|
# Get the sum of the field values for all the documents.
|
data/lib/mongoid/contexts/ids.rb
CHANGED
@@ -13,9 +13,9 @@ module Mongoid #:nodoc:
|
|
13
13
|
#
|
14
14
|
# The single or multiple documents.
|
15
15
|
def id_criteria(params)
|
16
|
-
criteria.id(params)
|
16
|
+
self.criteria = criteria.id(params)
|
17
17
|
result = params.is_a?(Array) ? criteria.entries : one
|
18
|
-
if Mongoid.raise_not_found_error
|
18
|
+
if Mongoid.raise_not_found_error && !params.blank?
|
19
19
|
raise Errors::DocumentNotFound.new(klass, params) if result.blank?
|
20
20
|
end
|
21
21
|
return result
|
@@ -3,7 +3,7 @@ module Mongoid #:nodoc:
|
|
3
3
|
module Contexts #:nodoc:
|
4
4
|
class Mongo
|
5
5
|
include Ids, Paging
|
6
|
-
|
6
|
+
attr_accessor :criteria
|
7
7
|
|
8
8
|
delegate :klass, :options, :selector, :to => :criteria
|
9
9
|
|
@@ -51,7 +51,6 @@ module Mongoid #:nodoc:
|
|
51
51
|
def blank?
|
52
52
|
klass.collection.find_one(selector, { :fields => [ :_id ] }).nil?
|
53
53
|
end
|
54
|
-
|
55
54
|
alias :empty? :blank?
|
56
55
|
|
57
56
|
# Get the count of matching documents in the database for the context.
|
@@ -67,6 +66,32 @@ module Mongoid #:nodoc:
|
|
67
66
|
@count ||= klass.collection.find(selector, process_options).count
|
68
67
|
end
|
69
68
|
|
69
|
+
# Delete all the documents in the database matching the selector.
|
70
|
+
#
|
71
|
+
# @example Delete the documents.
|
72
|
+
# context.delete_all
|
73
|
+
#
|
74
|
+
# @return [ Integer ] The number of documents deleted.
|
75
|
+
#
|
76
|
+
# @since 2.0.0.rc.1
|
77
|
+
def delete_all
|
78
|
+
klass.delete_all(:conditions => selector)
|
79
|
+
end
|
80
|
+
alias :delete :delete_all
|
81
|
+
|
82
|
+
# Destroy all the documents in the database matching the selector.
|
83
|
+
#
|
84
|
+
# @example Destroy the documents.
|
85
|
+
# context.destroy_all
|
86
|
+
#
|
87
|
+
# @return [ Integer ] The number of documents destroyed.
|
88
|
+
#
|
89
|
+
# @since 2.0.0.rc.1
|
90
|
+
def destroy_all
|
91
|
+
klass.destroy_all(:conditions => selector)
|
92
|
+
end
|
93
|
+
alias :destroy :destroy_all
|
94
|
+
|
70
95
|
# Gets an array of distinct values for the supplied field across the
|
71
96
|
# entire collection or the susbset given the criteria.
|
72
97
|
#
|
@@ -134,10 +159,10 @@ module Mongoid #:nodoc:
|
|
134
159
|
def initialize(criteria)
|
135
160
|
@criteria = criteria
|
136
161
|
if klass.hereditary? && !criteria.selector.keys.include?(:_type)
|
137
|
-
criteria.in(:_type => criteria.klass._types)
|
162
|
+
@criteria = criteria.in(:_type => criteria.klass._types)
|
138
163
|
end
|
139
|
-
criteria.enslave if klass.enslaved?
|
140
|
-
criteria.cache if klass.cached?
|
164
|
+
@criteria.enslave if klass.enslaved?
|
165
|
+
@criteria.cache if klass.cached?
|
141
166
|
end
|
142
167
|
|
143
168
|
# Iterate over each +Document+ in the results. This can take an optional
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Mongoid #:nodoc:
|
3
|
+
module Copyable
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
COPYABLES = [
|
7
|
+
:@accessed,
|
8
|
+
:@attributes,
|
9
|
+
:@metadata,
|
10
|
+
:@modifications,
|
11
|
+
:@previous_modifications
|
12
|
+
]
|
13
|
+
|
14
|
+
protected
|
15
|
+
|
16
|
+
# Clone or dup the current +Document+. This will return all attributes with
|
17
|
+
# the exception of the document's id and versions, and will reset all the
|
18
|
+
# instance variables.
|
19
|
+
#
|
20
|
+
# Example:
|
21
|
+
#
|
22
|
+
# <tt>document.clone</tt>
|
23
|
+
# <tt>document.dup</tt>
|
24
|
+
#
|
25
|
+
# Options:
|
26
|
+
#
|
27
|
+
# other: The document getting cloned.
|
28
|
+
#
|
29
|
+
# Returns:
|
30
|
+
#
|
31
|
+
# A new document with all the attributes except id and versions
|
32
|
+
def initialize_copy(other)
|
33
|
+
instance_variables.each { |name| remove_instance_variable(name) }
|
34
|
+
COPYABLES.each do |name|
|
35
|
+
value = other.instance_variable_get(name)
|
36
|
+
instance_variable_set(name, value ? value.dup : nil)
|
37
|
+
end
|
38
|
+
@attributes.delete("_id")
|
39
|
+
@attributes.delete("versions")
|
40
|
+
@new_record = true
|
41
|
+
identify
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/lib/mongoid/criteria.rb
CHANGED
@@ -1,11 +1,15 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
+
require "mongoid/criterion/creational"
|
2
3
|
require "mongoid/criterion/complex"
|
4
|
+
require "mongoid/criterion/destructive"
|
3
5
|
require "mongoid/criterion/exclusion"
|
4
6
|
require "mongoid/criterion/inclusion"
|
7
|
+
require "mongoid/criterion/inspection"
|
5
8
|
require "mongoid/criterion/optional"
|
6
9
|
require "mongoid/criterion/selector"
|
7
10
|
|
8
11
|
module Mongoid #:nodoc:
|
12
|
+
|
9
13
|
# The +Criteria+ class is the core object needed in Mongoid to retrieve
|
10
14
|
# objects from the database. It is a DSL that essentially sets up the
|
11
15
|
# selector and options arguments that get passed on to a <tt>Mongo::Collection</tt>
|
@@ -21,13 +25,15 @@ module Mongoid #:nodoc:
|
|
21
25
|
#
|
22
26
|
# <tt>criteria.execute</tt>
|
23
27
|
class Criteria
|
28
|
+
include Enumerable
|
29
|
+
include Criterion::Creational
|
30
|
+
include Criterion::Destructive
|
24
31
|
include Criterion::Exclusion
|
25
32
|
include Criterion::Inclusion
|
33
|
+
include Criterion::Inspection
|
26
34
|
include Criterion::Optional
|
27
|
-
include Enumerable
|
28
35
|
|
29
|
-
|
30
|
-
attr_accessor :documents
|
36
|
+
attr_accessor :collection, :documents, :embedded, :ids, :klass, :options, :selector
|
31
37
|
|
32
38
|
delegate :aggregate, :avg, :blank?, :count, :distinct, :empty?,
|
33
39
|
:execute, :first, :group, :id_criteria, :last, :max,
|
@@ -69,7 +75,7 @@ module Mongoid #:nodoc:
|
|
69
75
|
# This will return an Enumerable context if the class is embedded,
|
70
76
|
# otherwise it will return a Mongo context for root classes.
|
71
77
|
def context
|
72
|
-
@context ||= Contexts.context_for(self)
|
78
|
+
@context ||= Contexts.context_for(self, embedded)
|
73
79
|
end
|
74
80
|
|
75
81
|
# Iterate over each +Document+ in the results. This can take an optional
|
@@ -79,8 +85,7 @@ module Mongoid #:nodoc:
|
|
79
85
|
#
|
80
86
|
# <tt>criteria.each { |doc| p doc }</tt>
|
81
87
|
def each(&block)
|
82
|
-
context.iterate(&block)
|
83
|
-
self
|
88
|
+
tap { context.iterate(&block) }
|
84
89
|
end
|
85
90
|
|
86
91
|
# Return true if the criteria has some Document or not
|
@@ -116,9 +121,9 @@ module Mongoid #:nodoc:
|
|
116
121
|
#
|
117
122
|
# type: One of :all, :first:, or :last
|
118
123
|
# klass: The class to execute on.
|
119
|
-
def initialize(klass)
|
120
|
-
@selector =
|
121
|
-
@options, @klass, @documents = {}, klass, []
|
124
|
+
def initialize(klass, embedded = false)
|
125
|
+
@selector = Criterion::Selector.new(klass)
|
126
|
+
@options, @klass, @documents, @embedded = {}, klass, [], embedded
|
122
127
|
end
|
123
128
|
|
124
129
|
# Merges another object into this +Criteria+. The other object may be a
|
@@ -133,9 +138,11 @@ module Mongoid #:nodoc:
|
|
133
138
|
#
|
134
139
|
# <tt>criteria.merge({ :conditions => { :title => "Sir" } })</tt>
|
135
140
|
def merge(other)
|
136
|
-
|
137
|
-
|
138
|
-
|
141
|
+
clone.tap do |crit|
|
142
|
+
crit.selector.update(other.selector)
|
143
|
+
crit.options.update(other.options)
|
144
|
+
crit.documents = other.documents
|
145
|
+
end
|
139
146
|
end
|
140
147
|
|
141
148
|
# Used for chaining +Criteria+ scopes together in the for of class methods
|
@@ -157,8 +164,6 @@ module Mongoid #:nodoc:
|
|
157
164
|
end
|
158
165
|
end
|
159
166
|
|
160
|
-
alias :to_ary :to_a
|
161
|
-
|
162
167
|
# Returns the selector and options as a +Hash+ that would be passed to a
|
163
168
|
# scope for use with named scopes.
|
164
169
|
def scoped
|
@@ -167,39 +172,74 @@ module Mongoid #:nodoc:
|
|
167
172
|
scope_options[:order_by] = sorting if sorting
|
168
173
|
{ :where => @selector }.merge(scope_options)
|
169
174
|
end
|
175
|
+
alias :to_ary :to_a
|
170
176
|
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
klass
|
189
|
-
|
190
|
-
|
191
|
-
|
177
|
+
class << self
|
178
|
+
|
179
|
+
# Encaspulates the behavior of taking arguments and parsing them into a
|
180
|
+
# finder type and a corresponding criteria object.
|
181
|
+
#
|
182
|
+
# Example:
|
183
|
+
#
|
184
|
+
# <tt>Criteria.parse!(Person, :all, :conditions => {})</tt>
|
185
|
+
#
|
186
|
+
# Options:
|
187
|
+
#
|
188
|
+
# klass: The klass to create the criteria for.
|
189
|
+
# args: An assortment of finder options.
|
190
|
+
#
|
191
|
+
# Returns:
|
192
|
+
#
|
193
|
+
# An Array with the type and criteria.
|
194
|
+
def parse!(klass, embedded, *args)
|
195
|
+
if args[0].nil?
|
196
|
+
Errors::InvalidOptions.new("Calling Document#find with nil is invalid")
|
197
|
+
end
|
198
|
+
type = args.delete_at(0) if args[0].is_a?(Symbol)
|
199
|
+
criteria = translate(klass, embedded, *args)
|
200
|
+
return [ type, criteria ]
|
192
201
|
end
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
202
|
+
|
203
|
+
# Translate the supplied arguments into a +Criteria+ object.
|
204
|
+
#
|
205
|
+
# If the passed in args is a single +String+, then it will
|
206
|
+
# construct an id +Criteria+ from it.
|
207
|
+
#
|
208
|
+
# If the passed in args are a type and a hash, then it will construct
|
209
|
+
# the +Criteria+ with the proper selector, options, and type.
|
210
|
+
#
|
211
|
+
# Options:
|
212
|
+
#
|
213
|
+
# args: either a +String+ or a +Symbol+, +Hash combination.
|
214
|
+
#
|
215
|
+
# Example:
|
216
|
+
#
|
217
|
+
# <tt>Criteria.translate(Person, "4ab2bc4b8ad548971900005c")</tt>
|
218
|
+
# <tt>Criteria.translate(Person, :conditions => { :field => "value"}, :limit => 20)</tt>
|
219
|
+
def translate(*args)
|
220
|
+
klass = args[0]
|
221
|
+
embedded = args[1]
|
222
|
+
params = args[2] || {}
|
223
|
+
unless params.is_a?(Hash)
|
224
|
+
return klass.criteria(embedded).id_criteria(params)
|
225
|
+
end
|
226
|
+
conditions = params.delete(:conditions) || {}
|
227
|
+
if conditions.include?(:id)
|
228
|
+
conditions[:_id] = conditions[:id]
|
229
|
+
conditions.delete(:id)
|
230
|
+
end
|
231
|
+
return klass.criteria(embedded).where(conditions).extras(params)
|
197
232
|
end
|
198
|
-
return klass.criteria.where(conditions).extras(params)
|
199
233
|
end
|
200
234
|
|
201
235
|
protected
|
202
236
|
|
237
|
+
# Return the entries of the other criteria or the object. Used for
|
238
|
+
# comparing criteria or an enumerable.
|
239
|
+
def comparable(other)
|
240
|
+
other.is_a?(Criteria) ? other.entries : other
|
241
|
+
end
|
242
|
+
|
203
243
|
# Filters the unused options out of the options +Hash+. Currently this
|
204
244
|
# takes into account the "page" and "per_page" options that would be passed
|
205
245
|
# in if using will_paginate.
|
@@ -218,10 +258,24 @@ module Mongoid #:nodoc:
|
|
218
258
|
end
|
219
259
|
end
|
220
260
|
|
221
|
-
#
|
222
|
-
#
|
223
|
-
|
224
|
-
|
261
|
+
# Clone or dup the current +Criteria+. This will return a new criteria with
|
262
|
+
# the selector, options, klass, embedded options, etc intact.
|
263
|
+
#
|
264
|
+
# Example:
|
265
|
+
#
|
266
|
+
# <tt>criteria.clone</tt>
|
267
|
+
# <tt>criteria.dup</tt>
|
268
|
+
#
|
269
|
+
# Options:
|
270
|
+
#
|
271
|
+
# other: The criteria getting cloned.
|
272
|
+
#
|
273
|
+
# Returns:
|
274
|
+
#
|
275
|
+
# A new identical criteria
|
276
|
+
def initialize_copy(other)
|
277
|
+
@selector = other.selector.dup
|
278
|
+
@options = other.options.dup
|
225
279
|
end
|
226
280
|
|
227
281
|
# Update the selector setting the operator on the value for each key in the
|
@@ -231,20 +285,20 @@ module Mongoid #:nodoc:
|
|
231
285
|
#
|
232
286
|
# <tt>criteria.update_selector({ :field => "value" }, "$in")</tt>
|
233
287
|
def update_selector(attributes, operator)
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
if @selector[key].has_key?(operator)
|
239
|
-
# add the value to the current operator
|
240
|
-
new_value = @selector[key].values.first + value
|
241
|
-
@selector[key] = { operator => new_value }
|
288
|
+
clone.tap do |crit|
|
289
|
+
attributes.each do |key, value|
|
290
|
+
unless crit.selector[key]
|
291
|
+
crit.selector[key] = { operator => value }
|
242
292
|
else
|
243
|
-
|
244
|
-
|
245
|
-
|
293
|
+
if crit.selector[key].has_key?(operator)
|
294
|
+
new_value = crit.selector[key].values.first + value
|
295
|
+
crit.selector[key] = { operator => new_value }
|
296
|
+
else
|
297
|
+
crit.selector[key][operator] = value
|
298
|
+
end
|
299
|
+
end
|
246
300
|
end
|
247
|
-
end
|
301
|
+
end
|
248
302
|
end
|
249
303
|
end
|
250
304
|
end
|