mongoid 4.0.0.alpha2 → 4.0.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +55 -0
- data/README.md +3 -3
- data/lib/config/locales/en.yml +13 -0
- data/lib/mongoid.rb +3 -1
- data/lib/mongoid/atomic.rb +1 -1
- data/lib/mongoid/atomic/paths/embedded/many.rb +1 -1
- data/lib/mongoid/atomic/paths/embedded/one.rb +1 -1
- data/lib/mongoid/attributes.rb +23 -1
- data/lib/mongoid/attributes/processing.rb +1 -1
- data/lib/mongoid/composable.rb +3 -2
- data/lib/mongoid/contextual/command.rb +0 -26
- data/lib/mongoid/contextual/geo_near.rb +1 -1
- data/lib/mongoid/contextual/mongo.rb +6 -29
- data/lib/mongoid/contextual/text_search.rb +3 -5
- data/lib/mongoid/criteria.rb +1 -1
- data/lib/mongoid/criteria/modifiable.rb +27 -7
- data/lib/mongoid/criteria/permission.rb +70 -0
- data/lib/mongoid/document.rb +5 -6
- data/lib/mongoid/errors.rb +2 -0
- data/lib/mongoid/errors/document_not_destroyed.rb +25 -0
- data/lib/mongoid/errors/readonly_document.rb +24 -0
- data/lib/mongoid/extensions/boolean.rb +1 -0
- data/lib/mongoid/extensions/hash.rb +1 -1
- data/lib/mongoid/factory.rb +5 -3
- data/lib/mongoid/fields.rb +32 -0
- data/lib/mongoid/fields/localized.rb +1 -1
- data/lib/mongoid/fields/standard.rb +1 -1
- data/lib/mongoid/findable.rb +1 -0
- data/lib/mongoid/interceptable.rb +11 -6
- data/lib/mongoid/log_subscriber.rb +34 -1
- data/lib/mongoid/persistable/deletable.rb +1 -0
- data/lib/mongoid/persistable/destroyable.rb +7 -2
- data/lib/mongoid/persistable/updatable.rb +27 -26
- data/lib/mongoid/query_cache.rb +246 -0
- data/lib/mongoid/railties/database.rake +4 -26
- data/lib/mongoid/relations.rb +8 -22
- data/lib/mongoid/relations/accessors.rb +0 -3
- data/lib/mongoid/relations/binding.rb +1 -1
- data/lib/mongoid/relations/bindings/embedded/in.rb +1 -1
- data/lib/mongoid/relations/eager.rb +5 -6
- data/lib/mongoid/relations/eager/base.rb +97 -5
- data/lib/mongoid/relations/eager/belongs_to.rb +1 -0
- data/lib/mongoid/relations/eager/has_and_belongs_to_many.rb +16 -9
- data/lib/mongoid/relations/eager/has_many.rb +1 -0
- data/lib/mongoid/relations/eager/has_one.rb +1 -0
- data/lib/mongoid/relations/embedded/batchable.rb +1 -1
- data/lib/mongoid/relations/embedded/in.rb +4 -4
- data/lib/mongoid/relations/embedded/many.rb +7 -5
- data/lib/mongoid/relations/embedded/one.rb +1 -1
- data/lib/mongoid/relations/macros.rb +1 -0
- data/lib/mongoid/relations/marshalable.rb +3 -3
- data/lib/mongoid/relations/proxy.rb +12 -10
- data/lib/mongoid/relations/referenced/in.rb +2 -2
- data/lib/mongoid/relations/referenced/many.rb +9 -9
- data/lib/mongoid/relations/referenced/many_to_many.rb +7 -7
- data/lib/mongoid/relations/referenced/one.rb +4 -4
- data/lib/mongoid/{state.rb → stateful.rb} +13 -1
- data/lib/mongoid/tasks/database.rake +31 -0
- data/lib/mongoid/tasks/database.rb +107 -0
- data/lib/mongoid/threaded.rb +0 -47
- data/lib/mongoid/validatable/uniqueness.rb +4 -16
- data/lib/mongoid/version.rb +1 -1
- data/lib/rails/generators/mongoid/config/templates/mongoid.yml +0 -3
- data/lib/rails/mongoid.rb +0 -124
- data/spec/app/models/edit.rb +5 -0
- data/spec/app/models/even.rb +7 -0
- data/spec/app/models/line_item.rb +1 -1
- data/spec/app/models/note.rb +2 -0
- data/spec/app/models/odd.rb +7 -0
- data/spec/app/models/record.rb +5 -0
- data/spec/app/models/wiki_page.rb +1 -1
- data/spec/mongoid/attributes_spec.rb +76 -1
- data/spec/mongoid/changeable_spec.rb +6 -2
- data/spec/mongoid/contextual/mongo_spec.rb +3 -1
- data/spec/mongoid/contextual/text_search_spec.rb +3 -1
- data/spec/mongoid/criteria/modifiable_spec.rb +192 -0
- data/spec/mongoid/criteria_spec.rb +6 -2
- data/spec/mongoid/errors/document_not_destroyed_spec.rb +33 -0
- data/spec/mongoid/errors/readonly_document_spec.rb +29 -0
- data/spec/mongoid/fields/localized_spec.rb +15 -0
- data/spec/mongoid/fields_spec.rb +88 -2
- data/spec/mongoid/log_subscriber_spec.rb +3 -3
- data/spec/mongoid/persistable/deletable_spec.rb +14 -1
- data/spec/mongoid/persistable/destroyable_spec.rb +45 -1
- data/spec/mongoid/persistable/savable_spec.rb +34 -5
- data/spec/mongoid/query_cache_spec.rb +197 -0
- data/spec/mongoid/relations/bindings/embedded/in_spec.rb +2 -2
- data/spec/mongoid/relations/builders/referenced/many_spec.rb +1 -1
- data/spec/mongoid/relations/eager/has_and_belongs_to_many_spec.rb +11 -37
- data/spec/mongoid/relations/eager/has_one_spec.rb +1 -1
- data/spec/mongoid/relations/embedded/in_spec.rb +1 -1
- data/spec/mongoid/relations/embedded/many_spec.rb +10 -10
- data/spec/mongoid/relations/embedded/one_spec.rb +10 -2
- data/spec/mongoid/relations/referenced/in_spec.rb +1 -1
- data/spec/mongoid/relations/referenced/many_spec.rb +37 -2
- data/spec/mongoid/relations/touchable_spec.rb +20 -0
- data/spec/mongoid/{state_spec.rb → stateful_spec.rb} +26 -1
- data/spec/mongoid/tasks/database_rake_spec.rb +285 -0
- data/spec/mongoid/tasks/database_spec.rb +148 -0
- data/spec/mongoid/validatable/uniqueness_spec.rb +7 -0
- data/spec/rails/mongoid_spec.rb +0 -316
- data/spec/spec_helper.rb +1 -0
- metadata +30 -8
@@ -0,0 +1,31 @@
|
|
1
|
+
namespace :db do
|
2
|
+
namespace :mongoid do
|
3
|
+
task :load_models do
|
4
|
+
end
|
5
|
+
|
6
|
+
desc "Create the indexes defined on your mongoid models"
|
7
|
+
task :create_indexes => [:environment, :load_models] do
|
8
|
+
::Mongoid::Tasks::Database.create_indexes
|
9
|
+
end
|
10
|
+
|
11
|
+
desc "Remove indexes that exist in the database but aren't specified on the models"
|
12
|
+
task :remove_undefined_indexes => [:environment, :load_models] do
|
13
|
+
::Mongoid::Tasks::Database.remove_undefined_indexes
|
14
|
+
end
|
15
|
+
|
16
|
+
desc "Remove the indexes defined on your mongoid models without questions!"
|
17
|
+
task :remove_indexes => [:environment, :load_models] do
|
18
|
+
::Mongoid::Tasks::Database.remove_indexes
|
19
|
+
end
|
20
|
+
|
21
|
+
desc "Drops the default session"
|
22
|
+
task :drop => :environment do
|
23
|
+
::Mongoid::Sessions.default.drop
|
24
|
+
end
|
25
|
+
|
26
|
+
desc "Drop all collections except the system collections"
|
27
|
+
task :purge => :environment do
|
28
|
+
::Mongoid.purge!
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Mongoid
|
3
|
+
module Tasks
|
4
|
+
module Database
|
5
|
+
extend self
|
6
|
+
|
7
|
+
# Create indexes for each model given the provided globs and the class is
|
8
|
+
# not embedded.
|
9
|
+
#
|
10
|
+
# @example Create all the indexes.
|
11
|
+
# Mongoid::Tasks::Database.create_indexes
|
12
|
+
#
|
13
|
+
# @return [ Array<Class> ] The indexed models.
|
14
|
+
#
|
15
|
+
# @since 2.1.0
|
16
|
+
def create_indexes(models = ::Mongoid.models)
|
17
|
+
models.each do |model|
|
18
|
+
next if model.index_specifications.empty?
|
19
|
+
unless model.embedded?
|
20
|
+
model.create_indexes
|
21
|
+
logger.info("MONGOID: Created indexes on #{model}:")
|
22
|
+
model.index_specifications.each do |spec|
|
23
|
+
logger.info("MONGOID: Index: #{spec.key}, Options: #{spec.options}")
|
24
|
+
end
|
25
|
+
model
|
26
|
+
else
|
27
|
+
logger.info("MONGOID: Index ignored on: #{model}, please define in the root model.")
|
28
|
+
nil
|
29
|
+
end
|
30
|
+
end.compact
|
31
|
+
end
|
32
|
+
|
33
|
+
# Return the list of indexes by model that exist in the database but aren't
|
34
|
+
# specified on the models.
|
35
|
+
#
|
36
|
+
# @example Return the list of unused indexes.
|
37
|
+
# Mongoid::Tasks::Database.undefined_indexes
|
38
|
+
#
|
39
|
+
# @return Hash{Class => Array(Hash)} The list of undefined indexes by model.
|
40
|
+
def undefined_indexes(models = ::Mongoid.models)
|
41
|
+
undefined_by_model = {}
|
42
|
+
|
43
|
+
models.each do |model|
|
44
|
+
unless model.embedded?
|
45
|
+
model.collection.indexes.each do |index|
|
46
|
+
# ignore default index
|
47
|
+
unless index['name'] == '_id_'
|
48
|
+
key = index['key'].symbolize_keys
|
49
|
+
spec = model.index_specification(key)
|
50
|
+
unless spec
|
51
|
+
# index not specified
|
52
|
+
undefined_by_model[model] ||= []
|
53
|
+
undefined_by_model[model] << index
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
undefined_by_model
|
61
|
+
end
|
62
|
+
|
63
|
+
# Remove indexes that exist in the database but aren't specified on the
|
64
|
+
# models.
|
65
|
+
#
|
66
|
+
# @example Remove undefined indexes.
|
67
|
+
# Mongoid::Tasks::Database.remove_undefined_indexes
|
68
|
+
#
|
69
|
+
# @return [ Hash{Class => Array(Hash)}] The list of indexes that were removed by model.
|
70
|
+
#
|
71
|
+
# @since 4.0.0
|
72
|
+
def remove_undefined_indexes(models = ::Mongoid.models)
|
73
|
+
undefined_indexes(models).each do |model, indexes|
|
74
|
+
indexes.each do |index|
|
75
|
+
key = index['key'].symbolize_keys
|
76
|
+
model.collection.indexes.drop(key)
|
77
|
+
logger.info("MONGOID: Removing index: #{index['name']} on #{model}.")
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Remove indexes for each model given the provided globs and the class is
|
83
|
+
# not embedded.
|
84
|
+
#
|
85
|
+
# @example Remove all the indexes.
|
86
|
+
# Mongoid::Tasks::Database.remove_indexes
|
87
|
+
#
|
88
|
+
# @return [ Array<Class> ] The un-indexed models.
|
89
|
+
#
|
90
|
+
def remove_indexes(models = ::Mongoid.models)
|
91
|
+
models.each do |model|
|
92
|
+
next if model.embedded?
|
93
|
+
indexes = model.collection.indexes.map{ |doc| doc["name"] }
|
94
|
+
indexes.delete_one("_id_")
|
95
|
+
model.remove_indexes
|
96
|
+
logger.info("MONGOID: Removing indexes on: #{model} for: #{indexes.join(', ')}.")
|
97
|
+
model
|
98
|
+
end.compact
|
99
|
+
end
|
100
|
+
|
101
|
+
private
|
102
|
+
def logger
|
103
|
+
@logger ||= Logger.new($stdout)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
data/lib/mongoid/threaded.rb
CHANGED
@@ -150,53 +150,6 @@ module Mongoid
|
|
150
150
|
validations_for(document.class).delete_one(document.id)
|
151
151
|
end
|
152
152
|
|
153
|
-
# Get the field selection options from the current thread.
|
154
|
-
#
|
155
|
-
# @example Get the field selection options.
|
156
|
-
# Threaded.selection
|
157
|
-
#
|
158
|
-
# @param [ Integer ] criteria_instance_id The criteria instance id.
|
159
|
-
#
|
160
|
-
# @return [ Hash ] The field selection.
|
161
|
-
#
|
162
|
-
# @since 2.4.4
|
163
|
-
def selection(criteria_instance_id)
|
164
|
-
selections = Thread.current["[mongoid][selections]"]
|
165
|
-
selections[criteria_instance_id] if selections
|
166
|
-
end
|
167
|
-
|
168
|
-
# Set the field selection on the current thread.
|
169
|
-
#
|
170
|
-
# @example Set the field selection.
|
171
|
-
# Threaded.set_selection(Person, { field: 1 })
|
172
|
-
#
|
173
|
-
# @param [ Integer ] criteria_instance_id The criteria instance id.
|
174
|
-
# @param [ Hash ] value The current field selection.
|
175
|
-
#
|
176
|
-
# @return [ Hash ] The field selection.
|
177
|
-
#
|
178
|
-
# @since 2.4.4
|
179
|
-
def set_selection(criteria_instance_id, value)
|
180
|
-
Thread.current["[mongoid][selections]"] ||= {}
|
181
|
-
Thread.current["[mongoid][selections]"][criteria_instance_id] = value
|
182
|
-
end
|
183
|
-
|
184
|
-
# Delete the field selection on the current thread.
|
185
|
-
#
|
186
|
-
# @example Delete the field selection.
|
187
|
-
# Threaded.delete_selection(Person)
|
188
|
-
#
|
189
|
-
# @param [ Integer ] criteria_instance_id The criteria instance id.
|
190
|
-
#
|
191
|
-
# @return [ Boolean ] Whether there was a field selection.
|
192
|
-
#
|
193
|
-
# @since 3.0.7
|
194
|
-
def delete_selection(criteria_instance_id)
|
195
|
-
selections = Thread.current["[mongoid][selections]"]
|
196
|
-
return false unless selections
|
197
|
-
!!selections.delete(criteria_instance_id)
|
198
|
-
end
|
199
|
-
|
200
153
|
# Get the global session override.
|
201
154
|
#
|
202
155
|
# @example Get the global session override.
|
@@ -26,20 +26,6 @@ module Mongoid
|
|
26
26
|
class UniquenessValidator < ActiveModel::EachValidator
|
27
27
|
include Queryable
|
28
28
|
|
29
|
-
attr_reader :klass
|
30
|
-
|
31
|
-
# Unfortunately, we have to tie Uniqueness validators to a class.
|
32
|
-
#
|
33
|
-
# @example Setup the validator.
|
34
|
-
# UniquenessValidator.new.setup(Person)
|
35
|
-
#
|
36
|
-
# @param [ Class ] klass The class getting validated.
|
37
|
-
#
|
38
|
-
# @since 1.0.0
|
39
|
-
def setup(klass)
|
40
|
-
@klass = klass
|
41
|
-
end
|
42
|
-
|
43
29
|
# Validate the document for uniqueness violations.
|
44
30
|
#
|
45
31
|
# @example Validate the document.
|
@@ -241,7 +227,7 @@ module Mongoid
|
|
241
227
|
def to_validate(document, attribute, value)
|
242
228
|
metadata = document.relations[attribute.to_s]
|
243
229
|
if metadata && metadata.stores_foreign_key?
|
244
|
-
[ metadata.foreign_key, value.id ]
|
230
|
+
[ metadata.foreign_key, value && value.id ]
|
245
231
|
else
|
246
232
|
[ attribute, value ]
|
247
233
|
end
|
@@ -280,7 +266,9 @@ module Mongoid
|
|
280
266
|
#
|
281
267
|
# @since 2.4.10
|
282
268
|
def validate_root(document, attribute, value)
|
283
|
-
|
269
|
+
klass = document.class
|
270
|
+
klass = klass.superclass while !klass.validators.include?(self)
|
271
|
+
criteria = create_criteria(klass, document, attribute, value)
|
284
272
|
criteria = criteria.merge(options[:conditions].call) if options[:conditions]
|
285
273
|
|
286
274
|
if criteria.with(persistence_options(criteria)).exists?
|
data/lib/mongoid/version.rb
CHANGED
@@ -29,9 +29,6 @@ development:
|
|
29
29
|
# retry_interval: 1
|
30
30
|
# Configure Mongoid specific options. (optional)
|
31
31
|
options:
|
32
|
-
# Enable the identity map, needed for eager loading. (default: false)
|
33
|
-
# identity_map_enabled: false
|
34
|
-
|
35
32
|
# Includes the root model name in json serialization. (default: false)
|
36
33
|
# include_root_in_json: false
|
37
34
|
|
data/lib/rails/mongoid.rb
CHANGED
@@ -3,100 +3,6 @@ module Rails
|
|
3
3
|
module Mongoid
|
4
4
|
extend self
|
5
5
|
|
6
|
-
# Create indexes for each model given the provided globs and the class is
|
7
|
-
# not embedded.
|
8
|
-
#
|
9
|
-
# @example Create all the indexes.
|
10
|
-
# Rails::Mongoid.create_indexes
|
11
|
-
#
|
12
|
-
# @return [ Array<Class> ] The indexed models.
|
13
|
-
#
|
14
|
-
# @since 2.1.0
|
15
|
-
def create_indexes
|
16
|
-
::Mongoid.models.each do |model|
|
17
|
-
next if model.index_specifications.empty?
|
18
|
-
unless model.embedded?
|
19
|
-
model.create_indexes
|
20
|
-
logger.info("MONGOID: Created indexes on #{model}:")
|
21
|
-
model.index_specifications.each do |spec|
|
22
|
-
logger.info("MONGOID: Index: #{spec.key}, Options: #{spec.options}")
|
23
|
-
end
|
24
|
-
model
|
25
|
-
else
|
26
|
-
logger.info("MONGOID: Index ignored on: #{model}, please define in the root model.")
|
27
|
-
nil
|
28
|
-
end
|
29
|
-
end.compact
|
30
|
-
end
|
31
|
-
|
32
|
-
# Return the list of indexes by model that exist in the database but aren't
|
33
|
-
# specified on the models.
|
34
|
-
#
|
35
|
-
# @example Return the list of unused indexes.
|
36
|
-
# Rails::Mongoid.undefined_indexes
|
37
|
-
#
|
38
|
-
# @return Hash{Class => Array(Hash)} The list of undefined indexes by model.
|
39
|
-
def undefined_indexes
|
40
|
-
undefined_by_model = {}
|
41
|
-
|
42
|
-
::Mongoid.models.each do |model|
|
43
|
-
unless model.embedded?
|
44
|
-
model.collection.indexes.each do |index|
|
45
|
-
# ignore default index
|
46
|
-
unless index['name'] == '_id_'
|
47
|
-
key = index['key'].symbolize_keys
|
48
|
-
spec = model.index_specification(key)
|
49
|
-
unless spec
|
50
|
-
# index not specified
|
51
|
-
undefined_by_model[model] ||= []
|
52
|
-
undefined_by_model[model] << index
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
undefined_by_model
|
60
|
-
end
|
61
|
-
|
62
|
-
# Remove indexes that exist in the database but aren't specified on the
|
63
|
-
# models.
|
64
|
-
#
|
65
|
-
# @example Remove undefined indexes.
|
66
|
-
# Rails::Mongoid.remove_undefined_indexes
|
67
|
-
#
|
68
|
-
# @return [ Hash{Class => Array(Hash)}] The list of indexes that were removed by model.
|
69
|
-
#
|
70
|
-
# @since 4.0.0
|
71
|
-
def remove_undefined_indexes
|
72
|
-
undefined_indexes.each do |model, indexes|
|
73
|
-
indexes.each do |index|
|
74
|
-
key = index['key'].symbolize_keys
|
75
|
-
model.collection.indexes.drop(key)
|
76
|
-
logger.info("MONGOID: Removing index: #{index['name']} on #{model}.")
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
# Remove indexes for each model given the provided globs and the class is
|
82
|
-
# not embedded.
|
83
|
-
#
|
84
|
-
# @example Remove all the indexes.
|
85
|
-
# Rails::Mongoid.remove_indexes
|
86
|
-
#
|
87
|
-
# @return [ Array<Class> ] The un-indexed models.
|
88
|
-
#
|
89
|
-
def remove_indexes
|
90
|
-
::Mongoid.models.each do |model|
|
91
|
-
next if model.embedded?
|
92
|
-
indexes = model.collection.indexes.map{ |doc| doc["name"] }
|
93
|
-
indexes.delete_one("_id_")
|
94
|
-
model.remove_indexes
|
95
|
-
logger.info("MONGOID: Removing indexes on: #{model} for: #{indexes.join(', ')}.")
|
96
|
-
model
|
97
|
-
end.compact
|
98
|
-
end
|
99
|
-
|
100
6
|
# Use the application configuration to get every model and require it, so
|
101
7
|
# that indexing and inheritance work in both development and production
|
102
8
|
# with the same results.
|
@@ -146,35 +52,5 @@ module Rails
|
|
146
52
|
Logger.new($stdout).warn(e.message)
|
147
53
|
end
|
148
54
|
end
|
149
|
-
|
150
|
-
# Given the provided file name, determine the model and return the class.
|
151
|
-
#
|
152
|
-
# @example Determine the model from the file.
|
153
|
-
# Rails::Mongoid.determine_model("app/models/person.rb")
|
154
|
-
#
|
155
|
-
# @param [ String ] file The filename.
|
156
|
-
#
|
157
|
-
# @return [ Class ] The model.
|
158
|
-
#
|
159
|
-
# @since 2.1.0
|
160
|
-
def determine_model(file, logger)
|
161
|
-
return nil unless file =~ /app\/models\/(.*).rb$/
|
162
|
-
return nil unless logger
|
163
|
-
|
164
|
-
model_path = $1.split('/')
|
165
|
-
begin
|
166
|
-
parts = model_path.map { |path| path.camelize }
|
167
|
-
name = parts.join("::")
|
168
|
-
klass = name.constantize
|
169
|
-
rescue NameError, LoadError
|
170
|
-
logger.info("MONGOID: Attempted to constantize #{name}, trying without namespacing.")
|
171
|
-
klass = parts.last.constantize rescue nil
|
172
|
-
end
|
173
|
-
klass if klass && klass.ancestors.include?(::Mongoid::Document)
|
174
|
-
end
|
175
|
-
|
176
|
-
def logger
|
177
|
-
@logger ||= Logger.new($stdout)
|
178
|
-
end
|
179
55
|
end
|
180
56
|
end
|
data/spec/app/models/note.rb
CHANGED
data/spec/app/models/record.rb
CHANGED
@@ -6,8 +6,8 @@ class WikiPage
|
|
6
6
|
field :transient_property, type: String
|
7
7
|
field :author, type: String
|
8
8
|
field :description, type: String, localize: true
|
9
|
-
max_versions 5
|
10
9
|
|
10
|
+
embeds_many :edits, validate: false
|
11
11
|
has_many :comments, dependent: :destroy, validate: false
|
12
12
|
has_many :child_pages, class_name: "WikiPage", dependent: :delete, inverse_of: :parent_pages
|
13
13
|
belongs_to :parent_pages, class_name: "WikiPage", inverse_of: :child_pages
|