mongo_mapper 0.8.6 → 0.9.0
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/UPGRADES +10 -0
- data/bin/mmconsole +0 -1
- data/examples/identity_map/automatic.rb +1 -7
- data/examples/plugins.rb +9 -9
- data/examples/safe.rb +43 -0
- data/lib/mongo_mapper.rb +46 -33
- data/lib/mongo_mapper/document.rb +33 -32
- data/lib/mongo_mapper/embedded_document.rb +22 -22
- data/lib/mongo_mapper/locale/en.yml +5 -0
- data/lib/mongo_mapper/middleware/identity_map.rb +16 -0
- data/lib/mongo_mapper/plugins.rb +16 -3
- data/lib/mongo_mapper/plugins/accessible.rb +2 -0
- data/lib/mongo_mapper/plugins/active_model.rb +18 -0
- data/lib/mongo_mapper/plugins/associations.rb +37 -42
- data/lib/mongo_mapper/plugins/associations/base.rb +14 -50
- data/lib/mongo_mapper/plugins/associations/belongs_to_association.rb +58 -0
- data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +6 -1
- data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +30 -2
- data/lib/mongo_mapper/plugins/associations/embedded_collection.rb +4 -0
- data/lib/mongo_mapper/plugins/associations/in_array_proxy.rb +12 -6
- data/lib/mongo_mapper/plugins/associations/many_association.rb +67 -0
- data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +5 -5
- data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +1 -1
- data/lib/mongo_mapper/plugins/associations/one_association.rb +20 -0
- data/lib/mongo_mapper/plugins/associations/one_embedded_proxy.rb +5 -0
- data/lib/mongo_mapper/plugins/associations/one_proxy.rb +7 -7
- data/lib/mongo_mapper/plugins/associations/proxy.rb +2 -2
- data/lib/mongo_mapper/plugins/caching.rb +3 -1
- data/lib/mongo_mapper/plugins/callbacks.rb +12 -221
- data/lib/mongo_mapper/plugins/clone.rb +3 -1
- data/lib/mongo_mapper/plugins/dirty.rb +38 -91
- data/lib/mongo_mapper/plugins/document.rb +4 -2
- data/lib/mongo_mapper/plugins/dynamic_querying.rb +2 -0
- data/lib/mongo_mapper/plugins/embedded_callbacks.rb +43 -0
- data/lib/mongo_mapper/plugins/embedded_document.rb +16 -9
- data/lib/mongo_mapper/plugins/equality.rb +2 -0
- data/lib/mongo_mapper/plugins/identity_map.rb +4 -2
- data/lib/mongo_mapper/plugins/indexes.rb +2 -0
- data/lib/mongo_mapper/plugins/inspect.rb +3 -1
- data/lib/mongo_mapper/plugins/keys.rb +28 -22
- data/lib/mongo_mapper/plugins/keys/key.rb +12 -6
- data/lib/mongo_mapper/plugins/logger.rb +2 -0
- data/lib/mongo_mapper/plugins/modifiers.rb +3 -1
- data/lib/mongo_mapper/plugins/pagination.rb +2 -0
- data/lib/mongo_mapper/plugins/persistence.rb +2 -0
- data/lib/mongo_mapper/plugins/protected.rb +2 -0
- data/lib/mongo_mapper/plugins/querying.rb +5 -4
- data/lib/mongo_mapper/plugins/rails.rb +3 -5
- data/lib/mongo_mapper/plugins/safe.rb +2 -0
- data/lib/mongo_mapper/plugins/sci.rb +2 -0
- data/lib/mongo_mapper/plugins/scopes.rb +2 -0
- data/lib/mongo_mapper/plugins/serialization.rb +67 -46
- data/lib/mongo_mapper/plugins/timestamps.rb +3 -1
- data/lib/mongo_mapper/plugins/userstamps.rb +2 -0
- data/lib/mongo_mapper/plugins/validations.rb +40 -24
- data/lib/mongo_mapper/railtie.rb +49 -0
- data/lib/mongo_mapper/railtie/database.rake +60 -0
- data/lib/mongo_mapper/support/descendant_appends.rb +11 -11
- data/lib/mongo_mapper/translation.rb +10 -0
- data/lib/mongo_mapper/version.rb +1 -1
- data/lib/rails/generators/mongo_mapper/config/config_generator.rb +24 -0
- data/lib/rails/generators/mongo_mapper/config/templates/mongo.yml +18 -0
- data/lib/rails/generators/mongo_mapper/model/model_generator.rb +23 -0
- data/lib/rails/generators/mongo_mapper/model/templates/model.rb +11 -0
- data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +1 -0
- data/test/functional/associations/test_belongs_to_proxy.rb +131 -1
- data/test/functional/associations/test_in_array_proxy.rb +30 -0
- data/test/functional/associations/test_many_documents_proxy.rb +30 -2
- data/test/functional/associations/test_many_embedded_proxy.rb +33 -0
- data/test/functional/associations/test_many_polymorphic_proxy.rb +1 -0
- data/test/functional/associations/test_one_embedded_proxy.rb +21 -2
- data/test/functional/associations/test_one_proxy.rb +49 -9
- data/test/functional/test_associations.rb +2 -0
- data/test/functional/test_caching.rb +3 -2
- data/test/functional/test_callbacks.rb +25 -18
- data/test/functional/test_dirty.rb +123 -1
- data/test/functional/test_document.rb +26 -2
- data/test/functional/test_embedded_document.rb +68 -2
- data/test/functional/test_identity_map.rb +3 -4
- data/test/functional/test_querying.rb +11 -0
- data/test/functional/test_userstamps.rb +2 -2
- data/test/functional/test_validations.rb +31 -29
- data/test/models.rb +10 -0
- data/test/test_active_model_lint.rb +1 -1
- data/test/test_helper.rb +9 -10
- data/test/unit/associations/test_base.rb +24 -100
- data/test/unit/associations/test_belongs_to_association.rb +29 -0
- data/test/unit/associations/test_many_association.rb +63 -0
- data/test/unit/associations/test_one_association.rb +18 -0
- data/test/unit/serializers/test_json_serializer.rb +0 -1
- data/test/unit/test_descendant_appends.rb +8 -16
- data/test/unit/test_document.rb +4 -9
- data/test/unit/test_dynamic_finder.rb +1 -1
- data/test/unit/test_embedded_document.rb +51 -18
- data/test/unit/test_identity_map_middleware.rb +34 -0
- data/test/unit/test_inspect.rb +22 -0
- data/test/unit/test_key.rb +21 -1
- data/test/unit/test_keys.rb +0 -2
- data/test/unit/test_plugins.rb +106 -20
- data/test/unit/test_rails.rb +8 -8
- data/test/unit/test_serialization.rb +116 -1
- data/test/unit/test_translation.rb +27 -0
- data/test/unit/test_validations.rb +66 -81
- metadata +103 -43
- data/examples/identity_map/middleware.rb +0 -14
- data/lib/mongo_mapper/plugins/descendants.rb +0 -17
- data/rails/init.rb +0 -19
@@ -2,9 +2,7 @@
|
|
2
2
|
module MongoMapper
|
3
3
|
module Plugins
|
4
4
|
module Rails
|
5
|
-
|
6
|
-
model.extend ActiveModel::Naming if defined?(ActiveModel)
|
7
|
-
end
|
5
|
+
extend ActiveSupport::Concern
|
8
6
|
|
9
7
|
module InstanceMethods
|
10
8
|
def to_param
|
@@ -27,8 +25,8 @@ module MongoMapper
|
|
27
25
|
self[name]
|
28
26
|
end
|
29
27
|
|
30
|
-
def
|
31
|
-
|
28
|
+
def read_attribute_before_type_cast(name)
|
29
|
+
read_key_before_type_cast(name)
|
32
30
|
end
|
33
31
|
|
34
32
|
def write_attribute(name, value)
|
@@ -1,73 +1,94 @@
|
|
1
1
|
# encoding: UTF-8
|
2
|
-
require '
|
2
|
+
require 'active_model/serializers/json'
|
3
|
+
require 'active_model/serializers/xml'
|
3
4
|
|
4
5
|
module MongoMapper
|
5
6
|
module Plugins
|
6
7
|
module Serialization
|
7
|
-
|
8
|
-
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
|
10
|
+
included do
|
11
|
+
include ::ActiveModel::Serializers::JSON
|
12
|
+
include ::ActiveModel::Serializers::Xml
|
13
|
+
self.include_root_in_json = false
|
9
14
|
end
|
10
15
|
|
11
16
|
module InstanceMethods
|
12
|
-
def
|
17
|
+
def serializable_attributes
|
18
|
+
attributes.keys.map { |k| k.to_s } + ['id'] - ['_id']
|
19
|
+
end
|
20
|
+
|
21
|
+
def serializable_hash(options = nil)
|
13
22
|
options ||= {}
|
14
|
-
unless options[:only]
|
15
|
-
methods = [options.delete(:methods)].flatten.compact
|
16
|
-
methods << :id
|
17
|
-
options[:methods] = methods.uniq
|
18
|
-
end
|
19
23
|
|
20
|
-
|
21
|
-
except
|
22
|
-
options[:except] = except
|
24
|
+
options[:only] = Array.wrap(options[:only]).map { |k| k.to_s }
|
25
|
+
options[:except] = Array.wrap(options[:except]).map { |k| k.to_s }
|
23
26
|
|
24
|
-
|
25
|
-
hash = begin
|
26
|
-
options[:only] = Array.wrap(options[:only]).map { |n| n.to_s }
|
27
|
-
options[:except] = Array.wrap(options[:except]).map { |n| n.to_s }
|
27
|
+
attribute_names = serializable_attributes
|
28
28
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
end
|
29
|
+
if options[:only].any?
|
30
|
+
attribute_names &= options[:only]
|
31
|
+
elsif options[:except].any?
|
32
|
+
attribute_names -= options[:except]
|
33
|
+
end
|
35
34
|
|
36
|
-
|
37
|
-
|
38
|
-
|
35
|
+
attribute_names += Array.wrap(options[:methods]).map { |m| m.to_s }.select do |method|
|
36
|
+
respond_to?(method)
|
37
|
+
end
|
38
|
+
|
39
|
+
hash = attribute_names.sort.inject({}) do |hash, name|
|
40
|
+
value = send(name)
|
41
|
+
hash[name] = if value.is_a?(Array)
|
42
|
+
value.map {|v| v.respond_to?(:serializable_hash) ? v.serializable_hash : v }
|
43
|
+
elsif value.respond_to?(:serializable_hash)
|
44
|
+
value.serializable_hash
|
45
|
+
else
|
46
|
+
value
|
39
47
|
end
|
48
|
+
hash
|
49
|
+
end
|
40
50
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
51
|
+
serializable_add_includes(options) do |association, records, opts|
|
52
|
+
hash[association.to_s] = records.is_a?(Array) ?
|
53
|
+
records.map { |r| r.serializable_hash(opts) } :
|
54
|
+
records.serializable_hash(opts)
|
45
55
|
end
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
56
|
+
|
57
|
+
hash
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def serializable_add_includes(options = {})
|
63
|
+
return unless include_associations = options.delete(:include)
|
64
|
+
|
65
|
+
base_only_or_except = { :except => options[:except],
|
66
|
+
:only => options[:only] }
|
67
|
+
|
68
|
+
include_has_options = include_associations.is_a?(Hash)
|
69
|
+
associations = include_has_options ? include_associations.keys : Array.wrap(include_associations)
|
70
|
+
|
71
|
+
associations.each do |association|
|
72
|
+
records = get_proxy(self.class.associations[association])
|
73
|
+
unless records.nil?
|
74
|
+
association_options = include_has_options ? include_associations[association] : base_only_or_except
|
75
|
+
opts = options.merge(association_options)
|
76
|
+
yield(association, records, opts)
|
59
77
|
end
|
60
78
|
end
|
61
79
|
|
62
|
-
|
63
|
-
hash = { ActiveSupport::Inflector.underscore(ActiveSupport::Inflector.demodulize(self.class.name)).gsub(/:.*/,'') => hash } if include_root_in_json
|
64
|
-
hash
|
80
|
+
options[:include] = include_associations
|
65
81
|
end
|
82
|
+
|
66
83
|
end
|
67
84
|
|
68
85
|
module ClassMethods
|
69
86
|
def from_json(json)
|
70
|
-
self.new
|
87
|
+
self.new.from_json(json)
|
88
|
+
end
|
89
|
+
|
90
|
+
def from_xml(xml)
|
91
|
+
self.new.from_xml(xml)
|
71
92
|
end
|
72
93
|
end
|
73
94
|
|
@@ -2,6 +2,8 @@
|
|
2
2
|
module MongoMapper
|
3
3
|
module Plugins
|
4
4
|
module Timestamps
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
5
7
|
module ClassMethods
|
6
8
|
def timestamps!
|
7
9
|
key :created_at, Time
|
@@ -13,7 +15,7 @@ module MongoMapper
|
|
13
15
|
module InstanceMethods
|
14
16
|
def update_timestamps
|
15
17
|
now = Time.now.utc
|
16
|
-
self[:created_at] = now if
|
18
|
+
self[:created_at] = now if !persisted? && !created_at?
|
17
19
|
self[:updated_at] = now
|
18
20
|
end
|
19
21
|
end
|
@@ -2,30 +2,44 @@
|
|
2
2
|
module MongoMapper
|
3
3
|
module Plugins
|
4
4
|
module Validations
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
include ::ActiveModel::Validations
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
def validates_uniqueness_of(*attr_names)
|
11
|
+
validates_with UniquenessValidator, _merge_attributes(attr_names)
|
9
12
|
end
|
10
|
-
end
|
11
13
|
|
12
|
-
|
13
|
-
|
14
|
-
add_validations(args, Validations::ValidatesUniquenessOf)
|
14
|
+
def validates_associated(*attr_names)
|
15
|
+
validates_with AssociatedValidator, _merge_attributes(attr_names)
|
15
16
|
end
|
16
17
|
end
|
17
18
|
|
18
|
-
class
|
19
|
-
|
20
|
-
|
19
|
+
class UniquenessValidator < ::ActiveModel::EachValidator
|
20
|
+
def initialize(options)
|
21
|
+
super(options.reverse_merge(:case_sensitive => true))
|
22
|
+
end
|
23
|
+
|
24
|
+
def setup(klass)
|
25
|
+
@klass = klass
|
26
|
+
end
|
27
|
+
|
28
|
+
def validate_each(record, attribute, value)
|
29
|
+
conditions = scope_conditions(record)
|
21
30
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
31
|
+
if options[:case_sensitive]
|
32
|
+
conditions[attribute] = value
|
33
|
+
else
|
34
|
+
conditions[attribute] = /^#{Regexp.escape(value.to_s)}$/i
|
35
|
+
end
|
36
|
+
|
37
|
+
# Make sure we're not including the current document in the query
|
38
|
+
conditions[:_id.ne] = record._id if record._id
|
39
|
+
|
40
|
+
if @klass.exists?(conditions)
|
41
|
+
record.errors.add(attribute, :taken, options.except(:case_sensitive, :scope).merge(:value => value))
|
42
|
+
end
|
29
43
|
end
|
30
44
|
|
31
45
|
def message(instance)
|
@@ -33,18 +47,20 @@ module MongoMapper
|
|
33
47
|
end
|
34
48
|
|
35
49
|
def scope_conditions(instance)
|
36
|
-
|
37
|
-
Array(scope).inject({}) do |conditions, key|
|
50
|
+
Array(options[:scope] || []).inject({}) do |conditions, key|
|
38
51
|
conditions.merge(key => instance[key])
|
39
52
|
end
|
40
53
|
end
|
54
|
+
end
|
41
55
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
56
|
+
class AssociatedValidator < ::ActiveModel::EachValidator
|
57
|
+
def validate_each(record, attribute, value)
|
58
|
+
if !Array.wrap(value).all? { |c| c.nil? || c.valid? }
|
59
|
+
record.errors.add(attribute, :invalid, :default => options[:message], :value => value)
|
60
|
+
end
|
46
61
|
end
|
47
62
|
end
|
63
|
+
|
48
64
|
end
|
49
65
|
end
|
50
66
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require "mongo_mapper"
|
2
|
+
require "rails"
|
3
|
+
require "active_model/railtie"
|
4
|
+
|
5
|
+
module MongoMapper
|
6
|
+
# = MongoMapper Railtie
|
7
|
+
class Railtie < Rails::Railtie
|
8
|
+
|
9
|
+
config.mongo_mapper = ActiveSupport::OrderedOptions.new
|
10
|
+
|
11
|
+
rake_tasks do
|
12
|
+
load "mongo_mapper/railtie/database.rake"
|
13
|
+
end
|
14
|
+
|
15
|
+
initializer "mongo_mapper.set_configs" do |app|
|
16
|
+
ActiveSupport.on_load(:mongo_mapper) do
|
17
|
+
app.config.mongo_mapper.each do |k,v|
|
18
|
+
send "#{k}=", v
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# This sets the database configuration and establishes the connection.
|
24
|
+
initializer "mongo_mapper.initialize_database" do |app|
|
25
|
+
config_file = Rails.root.join('config/mongo.yml')
|
26
|
+
if config_file.file?
|
27
|
+
config = YAML.load(ERB.new(config_file.read).result)
|
28
|
+
MongoMapper.setup(config, Rails.env, :logger => Rails.logger)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Clear the identity map after each request
|
33
|
+
initializer "mongo_mapper.clear_identity_map" do |app|
|
34
|
+
app.config.middleware.use 'MongoMapper::Middleware::IdentityMap'
|
35
|
+
end
|
36
|
+
|
37
|
+
initializer "mongo_mapper.prepare_dispatcher" do |app|
|
38
|
+
# See http://groups.google.com/group/mongomapper/browse_thread/thread/68f62e8eda43b43a/4841dba76938290c
|
39
|
+
# to_prepare is called before each request in development mode and the first request in production.
|
40
|
+
ActionDispatch::Callbacks.to_prepare do
|
41
|
+
unless app.config.cache_classes
|
42
|
+
# Rails reloading was making descendants fill up and leak memory, these make sure they get cleared
|
43
|
+
ActiveSupport::DescendantsTracker.clear
|
44
|
+
MongoMapper::Plugins::IdentityMap.models.clear
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
namespace :db do
|
2
|
+
|
3
|
+
if not Rake::Task.task_defined?("db:drop")
|
4
|
+
desc 'Drops all the collections for the database for the current Rails.env'
|
5
|
+
task :drop => :environment do
|
6
|
+
MongoMapper.database.collections.select {|c| c.name !~ /system/ }.each(&:drop)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
if not Rake::Task.task_defined?("db:seed")
|
11
|
+
# if another ORM has defined db:seed, don't run it twice.
|
12
|
+
desc 'Load the seed data from db/seeds.rb'
|
13
|
+
task :seed => :environment do
|
14
|
+
seed_file = File.join(Rails.root, 'db', 'seeds.rb')
|
15
|
+
load(seed_file) if File.exist?(seed_file)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
if not Rake::Task.task_defined?("db:setup")
|
20
|
+
desc 'Create the database, and initialize with the seed data'
|
21
|
+
task :setup => [ 'db:create', 'db:seed' ]
|
22
|
+
end
|
23
|
+
|
24
|
+
if not Rake::Task.task_defined?("db:reseed")
|
25
|
+
desc 'Delete data and seed'
|
26
|
+
task :reseed => [ 'db:drop', 'db:seed' ]
|
27
|
+
end
|
28
|
+
|
29
|
+
if not Rake::Task.task_defined?("db:create")
|
30
|
+
task :create => :environment do
|
31
|
+
# noop
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
if not Rake::Task.task_defined?("db:migrate")
|
36
|
+
task :migrate => :environment do
|
37
|
+
# noop
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
if not Rake::Task.task_defined?("db:schema:load")
|
42
|
+
namespace :schema do
|
43
|
+
task :load do
|
44
|
+
# noop
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
if not Rake::Task.task_defined?("db:test:prepare")
|
50
|
+
namespace :test do
|
51
|
+
task :prepare => :environment do
|
52
|
+
MongoMapper.connect('test')
|
53
|
+
MongoMapper.database.collections.select {|c| c.name !~ /system/ }.each(&:drop)
|
54
|
+
MongoMapper.connect(Rails.env)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
task 'test:prepare' => 'db:test:prepare'
|
@@ -4,29 +4,29 @@ require 'set'
|
|
4
4
|
module MongoMapper
|
5
5
|
module Support
|
6
6
|
module DescendantAppends
|
7
|
-
def included(model)
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
def descendants
|
15
|
-
@descendants ||= Set.new
|
7
|
+
def included(model = nil, &block)
|
8
|
+
if model
|
9
|
+
extra_extensions.each { |extension| model.extend(extension) }
|
10
|
+
extra_inclusions.each { |inclusion| model.send(:include, inclusion) }
|
11
|
+
direct_descendants << model
|
12
|
+
end
|
13
|
+
super
|
16
14
|
end
|
17
15
|
|
18
16
|
# @api public
|
19
17
|
def append_extensions(*extensions)
|
18
|
+
warn "[DEPRECATED] append_extensions is deprecated. Use #plugin with a module that extends ActiveSupport::Concern."
|
20
19
|
extra_extensions.concat(extensions)
|
21
|
-
|
20
|
+
direct_descendants.each do |model|
|
22
21
|
extensions.each { |extension| model.extend(extension) }
|
23
22
|
end
|
24
23
|
end
|
25
24
|
|
26
25
|
# @api public
|
27
26
|
def append_inclusions(*inclusions)
|
27
|
+
warn "[DEPRECATED] append_inclusions is deprecated. Use #plugin with a module that extends ActiveSupport::Concern."
|
28
28
|
extra_inclusions.concat(inclusions)
|
29
|
-
|
29
|
+
direct_descendants.each do |model|
|
30
30
|
inclusions.each { |inclusion| model.send(:include, inclusion) }
|
31
31
|
end
|
32
32
|
end
|