mongomodel 0.2.20 → 0.3.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/Gemfile +1 -1
- data/bin/console +2 -0
- data/lib/mongomodel.rb +10 -7
- data/lib/mongomodel/attributes/mongo.rb +3 -2
- data/lib/mongomodel/attributes/typecasting.rb +6 -1
- data/lib/mongomodel/concerns/associations.rb +0 -61
- data/lib/mongomodel/concerns/associations/base/association.rb +1 -2
- data/lib/mongomodel/concerns/associations/belongs_to.rb +8 -3
- data/lib/mongomodel/concerns/associations/has_many_by_foreign_key.rb +7 -3
- data/lib/mongomodel/concerns/associations/has_many_by_ids.rb +5 -1
- data/lib/mongomodel/document.rb +1 -0
- data/lib/mongomodel/document/collection_modifiers.rb +83 -0
- data/lib/mongomodel/document/optimistic_locking.rb +1 -1
- data/lib/mongomodel/document/persistence.rb +4 -5
- data/lib/mongomodel/log_subscriber.rb +48 -0
- data/lib/mongomodel/railtie.rb +8 -0
- data/lib/mongomodel/railties/controller_runtime.rb +33 -0
- data/lib/mongomodel/support/collection.rb +1 -1
- data/lib/mongomodel/support/configuration.rb +1 -2
- data/lib/mongomodel/support/instrumented_collection.rb +122 -0
- data/lib/mongomodel/support/mongo_options.rb +18 -4
- data/lib/mongomodel/support/reference.rb +48 -6
- data/lib/mongomodel/support/scope.rb +8 -3
- data/lib/mongomodel/support/scope/finder_methods.rb +3 -2
- data/lib/mongomodel/support/scope/load_methods.rb +13 -0
- data/lib/mongomodel/support/scope/query_methods.rb +1 -1
- data/lib/mongomodel/support/types.rb +13 -10
- data/lib/mongomodel/support/types/array.rb +1 -1
- data/lib/mongomodel/support/types/hash.rb +1 -1
- data/lib/mongomodel/support/types/rational.rb +42 -0
- data/lib/mongomodel/tasks/database.rake +54 -2
- data/lib/mongomodel/version.rb +1 -1
- data/spec/mongomodel/attributes/store_spec.rb +15 -2
- data/spec/mongomodel/concerns/logging_spec.rb +1 -1
- data/spec/mongomodel/document/collection_modifiers_spec.rb +103 -0
- data/spec/mongomodel/document/persistence_spec.rb +3 -3
- data/spec/mongomodel/mongomodel_spec.rb +1 -1
- data/spec/mongomodel/support/scope_spec.rb +5 -1
- data/spec/support/helpers/document_finder_stubs.rb +4 -4
- metadata +13 -6
data/Gemfile
CHANGED
data/bin/console
CHANGED
data/lib/mongomodel.rb
CHANGED
@@ -5,6 +5,7 @@ require 'mongo'
|
|
5
5
|
|
6
6
|
require 'mongomodel/support/core_extensions'
|
7
7
|
require 'mongomodel/support/exceptions'
|
8
|
+
require 'mongomodel/log_subscriber'
|
8
9
|
|
9
10
|
require 'active_support/core_ext/module/attribute_accessors'
|
10
11
|
|
@@ -38,6 +39,7 @@ module MongoModel
|
|
38
39
|
autoload :Types, 'mongomodel/support/types'
|
39
40
|
autoload :Configuration, 'mongomodel/support/configuration'
|
40
41
|
autoload :DynamicFinder, 'mongomodel/support/dynamic_finder'
|
42
|
+
autoload :InstrumentedCollection, 'mongomodel/support/instrumented_collection'
|
41
43
|
|
42
44
|
autoload :Collection, 'mongomodel/support/collection'
|
43
45
|
autoload :Map, 'mongomodel/support/map'
|
@@ -72,13 +74,14 @@ module MongoModel
|
|
72
74
|
end
|
73
75
|
|
74
76
|
module DocumentExtensions
|
75
|
-
autoload :Persistence,
|
76
|
-
autoload :OptimisticLocking,
|
77
|
-
autoload :DynamicFinders,
|
78
|
-
autoload :Indexes,
|
79
|
-
autoload :Scopes,
|
80
|
-
autoload :Validations,
|
81
|
-
autoload :Callbacks,
|
77
|
+
autoload :Persistence, 'mongomodel/document/persistence'
|
78
|
+
autoload :OptimisticLocking, 'mongomodel/document/optimistic_locking'
|
79
|
+
autoload :DynamicFinders, 'mongomodel/document/dynamic_finders'
|
80
|
+
autoload :Indexes, 'mongomodel/document/indexes'
|
81
|
+
autoload :Scopes, 'mongomodel/document/scopes'
|
82
|
+
autoload :Validations, 'mongomodel/document/validations'
|
83
|
+
autoload :Callbacks, 'mongomodel/document/callbacks'
|
84
|
+
autoload :CollectionModifiers, 'mongomodel/document/collection_modifiers'
|
82
85
|
end
|
83
86
|
|
84
87
|
mattr_accessor :logger
|
@@ -26,10 +26,11 @@ module MongoModel
|
|
26
26
|
|
27
27
|
if property
|
28
28
|
child = store(property.name, property.from_mongo(v))
|
29
|
-
child.parent_document = instance if child.respond_to?(:parent_document=)
|
30
29
|
else
|
31
|
-
|
30
|
+
child = store(k.to_sym, v)
|
32
31
|
end
|
32
|
+
|
33
|
+
child.parent_document = instance if child.respond_to?(:parent_document=)
|
33
34
|
end
|
34
35
|
end
|
35
36
|
|
@@ -27,10 +27,15 @@ module MongoModel
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def before_type_cast(key)
|
30
|
-
values_before_typecast[key]
|
30
|
+
values_before_typecast[key]
|
31
31
|
end
|
32
32
|
|
33
33
|
private
|
34
|
+
def store(key, value)
|
35
|
+
values_before_typecast[key] = value
|
36
|
+
super(key, value)
|
37
|
+
end
|
38
|
+
|
34
39
|
def typecast(key, value)
|
35
40
|
unless value.nil?
|
36
41
|
property = properties[key]
|
@@ -40,64 +40,3 @@ module MongoModel
|
|
40
40
|
end
|
41
41
|
end
|
42
42
|
end
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
#
|
47
|
-
# belongs_to :user
|
48
|
-
# => property :user_id
|
49
|
-
# belongs_to :author, :class_name => 'User'
|
50
|
-
# => property :author_id
|
51
|
-
# belongs_to :commentable, :polymorphic => true
|
52
|
-
# => property :commentable_id
|
53
|
-
# => property :commentable_type
|
54
|
-
#
|
55
|
-
|
56
|
-
#
|
57
|
-
# has_many :contributors, :class_name => 'User', :foreign_key => :publication_id
|
58
|
-
# has_many :comments, :as => :commentable
|
59
|
-
# has_many :roles
|
60
|
-
#
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
#
|
66
|
-
# Documents and EmbeddedDocuments can:
|
67
|
-
# - belong to any Document
|
68
|
-
# - have many Documents by ids
|
69
|
-
#
|
70
|
-
# Documents can also:
|
71
|
-
# - have many Documents by foreign key
|
72
|
-
#
|
73
|
-
|
74
|
-
# class Author < Document; end
|
75
|
-
#
|
76
|
-
# class Comment < Document
|
77
|
-
# # Creates properties :commentable_id and :commentable_type
|
78
|
-
# belongs_to :commentable, :polymorphic => true
|
79
|
-
# end
|
80
|
-
#
|
81
|
-
# class Page < EmbeddedDocument
|
82
|
-
# # Creates property :editor_id
|
83
|
-
# belongs_to :editor, :class => 'Author'
|
84
|
-
#
|
85
|
-
# # Creates property :related_article_ids
|
86
|
-
# has_many :related_articles, :class => 'Article'
|
87
|
-
#
|
88
|
-
# # Polymorphic association, uses commentable_id/commentable_type on Comment class
|
89
|
-
# has_many :comments, :as => :commentable
|
90
|
-
# end
|
91
|
-
#
|
92
|
-
# class Article < Document
|
93
|
-
# # Creates property :author_id
|
94
|
-
# belongs_to :author
|
95
|
-
#
|
96
|
-
# # Creates property :recommended_by_ids
|
97
|
-
# has_many :recommended_by, :by => :ids, :class => 'Author'
|
98
|
-
#
|
99
|
-
# # Creates property :parent_article_id
|
100
|
-
# belongs_to :parent_article, :class => 'Article'
|
101
|
-
# # Uses parent_article_id property on referenced class
|
102
|
-
# has_many :child_articles, :by => :foreign_key, :foreign_key => :parent_article_id, :class => 'Article'
|
103
|
-
# end
|
@@ -2,16 +2,16 @@ module MongoModel
|
|
2
2
|
module Associations
|
3
3
|
class BelongsTo < Base::Definition
|
4
4
|
def foreign_key
|
5
|
-
:"#{name}_id"
|
5
|
+
@foreign_key ||= :"#{name}_id"
|
6
6
|
end
|
7
7
|
|
8
8
|
def type_key
|
9
|
-
:"#{name}_type"
|
9
|
+
@type_key ||= :"#{name}_type"
|
10
10
|
end
|
11
11
|
|
12
12
|
properties do |association|
|
13
13
|
property association.foreign_key, MongoModel::Reference, :internal => true
|
14
|
-
property association.type_key,
|
14
|
+
property association.type_key, String, :internal => true if association.polymorphic?
|
15
15
|
end
|
16
16
|
|
17
17
|
methods do |association|
|
@@ -64,6 +64,11 @@ module MongoModel
|
|
64
64
|
def find_target
|
65
65
|
target_class.find(target_id) if target_id && target_class
|
66
66
|
end
|
67
|
+
|
68
|
+
protected
|
69
|
+
def proxy_class
|
70
|
+
Base::Proxy
|
71
|
+
end
|
67
72
|
end
|
68
73
|
end
|
69
74
|
end
|
@@ -2,11 +2,11 @@ module MongoModel
|
|
2
2
|
module Associations
|
3
3
|
class HasManyByForeignKey < Base::Definition
|
4
4
|
def foreign_key
|
5
|
-
options[:foreign_key] || :"#{inverse_of}_id"
|
5
|
+
@foreign_key ||= options[:foreign_key] || :"#{inverse_of}_id"
|
6
6
|
end
|
7
7
|
|
8
8
|
def inverse_of
|
9
|
-
options[:inverse_of] || owner.to_s.demodulize.underscore.singularize.to_sym
|
9
|
+
@inverse_of ||= options[:inverse_of] || owner.to_s.demodulize.underscore.singularize.to_sym
|
10
10
|
end
|
11
11
|
|
12
12
|
def define!
|
@@ -88,7 +88,7 @@ module MongoModel
|
|
88
88
|
end
|
89
89
|
|
90
90
|
def scoped
|
91
|
-
definition.scope.where(foreign_key => instance.id)
|
91
|
+
definition.scope.where(foreign_key => instance.id).on_load { |doc| set_inverse_association(doc) }
|
92
92
|
end
|
93
93
|
|
94
94
|
protected
|
@@ -107,6 +107,10 @@ module MongoModel
|
|
107
107
|
def ensure_class(array)
|
108
108
|
array.is_a?(Array) ? array.each { |i| super(i) } : super
|
109
109
|
end
|
110
|
+
|
111
|
+
def proxy_class
|
112
|
+
Proxy
|
113
|
+
end
|
110
114
|
end
|
111
115
|
|
112
116
|
class Proxy < Base::Proxy
|
@@ -2,7 +2,7 @@ module MongoModel
|
|
2
2
|
module Associations
|
3
3
|
class HasManyByIds < Base::Definition
|
4
4
|
def property_name
|
5
|
-
:"#{singular_name}_ids"
|
5
|
+
@property_name ||= :"#{singular_name}_ids"
|
6
6
|
end
|
7
7
|
|
8
8
|
def define!
|
@@ -78,6 +78,10 @@ module MongoModel
|
|
78
78
|
def ensure_class(array)
|
79
79
|
array.is_a?(Array) ? array.each { |i| super(i) } : super
|
80
80
|
end
|
81
|
+
|
82
|
+
def proxy_class
|
83
|
+
Proxy
|
84
|
+
end
|
81
85
|
end
|
82
86
|
|
83
87
|
class Proxy < Base::Proxy
|
data/lib/mongomodel/document.rb
CHANGED
@@ -7,6 +7,7 @@ module MongoModel
|
|
7
7
|
class Document < EmbeddedDocument
|
8
8
|
include DocumentExtensions::Persistence
|
9
9
|
include DocumentExtensions::OptimisticLocking
|
10
|
+
include DocumentExtensions::CollectionModifiers
|
10
11
|
|
11
12
|
extend DocumentExtensions::DynamicFinders
|
12
13
|
include DocumentExtensions::Indexes
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module MongoModel
|
2
|
+
module DocumentExtensions
|
3
|
+
module CollectionModifiers
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
module ClassMethods
|
7
|
+
# Post.increase!(:hits => 1, :available => -1)
|
8
|
+
def increase!(args)
|
9
|
+
collection_modifier_update('$inc', args)
|
10
|
+
end
|
11
|
+
|
12
|
+
# Post.set!(:hits => 0, :available => 100)
|
13
|
+
def set!(args)
|
14
|
+
collection_modifier_update('$set', args)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Post.unset!(:hits, :available)
|
18
|
+
def unset!(*args)
|
19
|
+
values = args.each_with_object({}) { |key, hash| hash[key.to_s] = 1 }
|
20
|
+
collection_modifier_update('$unset', values)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Post.push!(:tags => 'xxx')
|
24
|
+
def push!(args)
|
25
|
+
collection_modifier_update('$push', args)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Post.push_all!(:tags => ['xxx', 'yyy', 'zzz'])
|
29
|
+
def push_all!(args)
|
30
|
+
collection_modifier_update('$pushAll', args)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Post.add_to_set!(:tags => 'xxx')
|
34
|
+
def add_to_set!(args)
|
35
|
+
collection_modifier_update('$addToSet', args)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Post.pull!(:tags => 'xxx')
|
39
|
+
def pull!(args)
|
40
|
+
collection_modifier_update('$pull', args)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Post.pull_all!(:tags => ['xxx', 'yyy', 'zzz'])
|
44
|
+
def pull_all!(args)
|
45
|
+
collection_modifier_update('$pullAll', args)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Post.pop!(:tags)
|
49
|
+
def pop!(*args)
|
50
|
+
values = args.each_with_object({}) { |key, hash| hash[key.to_s] = 1 }
|
51
|
+
collection_modifier_update('$pop', values)
|
52
|
+
end
|
53
|
+
|
54
|
+
# Post.shift!(:tags, :data)
|
55
|
+
def shift!(*args)
|
56
|
+
values = args.each_with_object({}) { |key, hash| hash[key.to_s] = -1 }
|
57
|
+
collection_modifier_update('$pop', values)
|
58
|
+
end
|
59
|
+
|
60
|
+
# requires mongodb 1.7.2
|
61
|
+
# Post.rename!(:tags => :tag_collection)
|
62
|
+
def rename!(args)
|
63
|
+
collection_modifier_update('$rename', args)
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
def collection_modifier_update(modifier, args)
|
68
|
+
selector = MongoModel::MongoOptions.new(self, scoped.finder_options).selector
|
69
|
+
collection.update(selector, { modifier => args.stringify_keys! }, :multi => true)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
module InstanceMethods
|
74
|
+
delegate :increase!, :set!, :unset!, :push!, :push_all!, :add_to_set!, :pull!, :pull_all!, :pop!, :shift!, :rename!, :to => :instance_scope
|
75
|
+
|
76
|
+
private
|
77
|
+
def instance_scope
|
78
|
+
self.class.where(:id => id)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -30,7 +30,7 @@ module MongoModel
|
|
30
30
|
def save_to_collection
|
31
31
|
if locking_enabled? && _lock_version > 1
|
32
32
|
begin
|
33
|
-
collection.update({ '_id' => id, '_lock_version' => _lock_version-1 }, to_mongo)
|
33
|
+
collection.update({ '_id' => id.to_mongo, '_lock_version' => _lock_version-1 }, to_mongo)
|
34
34
|
success = database.get_last_error['updatedExisting']
|
35
35
|
|
36
36
|
self._lock_version -= 1 unless success
|
@@ -85,9 +85,9 @@ module MongoModel
|
|
85
85
|
end
|
86
86
|
end
|
87
87
|
|
88
|
-
def from_mongo(
|
88
|
+
def from_mongo(hash)
|
89
89
|
instance = super
|
90
|
-
instance.send(:instantiate
|
90
|
+
instance.send(:instantiate) if instance
|
91
91
|
instance
|
92
92
|
end
|
93
93
|
|
@@ -108,7 +108,7 @@ module MongoModel
|
|
108
108
|
end
|
109
109
|
|
110
110
|
def collection
|
111
|
-
@_collection ||= database.collection(collection_name)
|
111
|
+
@_collection ||= InstrumentedCollection.new(database.collection(collection_name))
|
112
112
|
end
|
113
113
|
|
114
114
|
def database
|
@@ -146,8 +146,7 @@ module MongoModel
|
|
146
146
|
false
|
147
147
|
end
|
148
148
|
|
149
|
-
def instantiate
|
150
|
-
attributes.load!(document)
|
149
|
+
def instantiate
|
151
150
|
set_new_record(false)
|
152
151
|
end
|
153
152
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module MongoModel
|
2
|
+
class LogSubscriber < ActiveSupport::LogSubscriber
|
3
|
+
def self.runtime=(value)
|
4
|
+
Thread.current["mongomodel_runtime"] = value
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.runtime
|
8
|
+
Thread.current["mongomodel_runtime"] ||= 0
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.reset_runtime
|
12
|
+
rt, self.runtime = runtime, 0
|
13
|
+
rt
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize
|
17
|
+
super
|
18
|
+
@odd_or_even = false
|
19
|
+
end
|
20
|
+
|
21
|
+
def query(event)
|
22
|
+
self.class.runtime += event.duration
|
23
|
+
return unless logger.debug?
|
24
|
+
|
25
|
+
collection = '%s (%.1fms)' % [event.payload[:collection], event.duration]
|
26
|
+
query = event.payload[:query]
|
27
|
+
|
28
|
+
if odd?
|
29
|
+
collection = color(collection, CYAN, true)
|
30
|
+
query = color(query, nil, true)
|
31
|
+
else
|
32
|
+
collection = color(collection, MAGENTA, true)
|
33
|
+
end
|
34
|
+
|
35
|
+
debug " #{collection} #{query}"
|
36
|
+
end
|
37
|
+
|
38
|
+
def odd?
|
39
|
+
@odd_or_even = !@odd_or_even
|
40
|
+
end
|
41
|
+
|
42
|
+
def logger
|
43
|
+
MongoModel.logger
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
MongoModel::LogSubscriber.attach_to :mongomodel
|
data/lib/mongomodel/railtie.rb
CHANGED
@@ -26,6 +26,14 @@ module MongoModel
|
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
|
+
# Expose database runtime to controller for logging.
|
30
|
+
initializer "mongomodel.log_runtime" do |app|
|
31
|
+
require "mongomodel/railties/controller_runtime"
|
32
|
+
ActiveSupport.on_load(:action_controller) do
|
33
|
+
include MongoModel::Railties::ControllerRuntime
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
29
37
|
initializer "mongomodel.passenger_forking" do |app|
|
30
38
|
if defined?(PhusionPassenger)
|
31
39
|
PhusionPassenger.on_event(:starting_worker_process) do |forked|
|