mongoid 2.0.0.beta.20 → 2.0.0.rc.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|