numon 0.0.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/.gitignore +10 -0
- data/LICENSE +20 -0
- data/README.rdoc +31 -0
- data/Rakefile +52 -0
- data/bin/mmconsole +60 -0
- data/lib/mongo_mapper.rb +138 -0
- data/lib/mongo_mapper/document.rb +359 -0
- data/lib/mongo_mapper/embedded_document.rb +61 -0
- data/lib/mongo_mapper/plugins.rb +34 -0
- data/lib/mongo_mapper/plugins/associations.rb +105 -0
- data/lib/mongo_mapper/plugins/associations/base.rb +123 -0
- data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +30 -0
- data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +25 -0
- data/lib/mongo_mapper/plugins/associations/collection.rb +21 -0
- data/lib/mongo_mapper/plugins/associations/embedded_collection.rb +39 -0
- data/lib/mongo_mapper/plugins/associations/in_array_proxy.rb +144 -0
- data/lib/mongo_mapper/plugins/associations/many_documents_as_proxy.rb +28 -0
- data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +120 -0
- data/lib/mongo_mapper/plugins/associations/many_embedded_polymorphic_proxy.rb +31 -0
- data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +23 -0
- data/lib/mongo_mapper/plugins/associations/many_polymorphic_proxy.rb +13 -0
- data/lib/mongo_mapper/plugins/associations/one_proxy.rb +68 -0
- data/lib/mongo_mapper/plugins/associations/proxy.rb +118 -0
- data/lib/mongo_mapper/plugins/callbacks.rb +234 -0
- data/lib/mongo_mapper/plugins/clone.rb +13 -0
- data/lib/mongo_mapper/plugins/descendants.rb +16 -0
- data/lib/mongo_mapper/plugins/dirty.rb +119 -0
- data/lib/mongo_mapper/plugins/equality.rb +23 -0
- data/lib/mongo_mapper/plugins/identity_map.rb +122 -0
- data/lib/mongo_mapper/plugins/inspect.rb +14 -0
- data/lib/mongo_mapper/plugins/keys.rb +336 -0
- data/lib/mongo_mapper/plugins/logger.rb +17 -0
- data/lib/mongo_mapper/plugins/modifiers.rb +87 -0
- data/lib/mongo_mapper/plugins/pagination.rb +24 -0
- data/lib/mongo_mapper/plugins/pagination/proxy.rb +72 -0
- data/lib/mongo_mapper/plugins/protected.rb +45 -0
- data/lib/mongo_mapper/plugins/rails.rb +53 -0
- data/lib/mongo_mapper/plugins/serialization.rb +75 -0
- data/lib/mongo_mapper/plugins/timestamps.rb +21 -0
- data/lib/mongo_mapper/plugins/userstamps.rb +14 -0
- data/lib/mongo_mapper/plugins/validations.rb +46 -0
- data/lib/mongo_mapper/query.rb +130 -0
- data/lib/mongo_mapper/support.rb +216 -0
- data/lib/mongo_mapper/support/descendant_appends.rb +46 -0
- data/lib/mongo_mapper/support/find.rb +77 -0
- data/lib/mongo_mapper/version.rb +3 -0
- data/numon.gemspec +207 -0
- data/performance/read_write.rb +52 -0
- data/specs.watchr +51 -0
- data/test/NOTE_ON_TESTING +1 -0
- data/test/active_model_lint_test.rb +11 -0
- data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +63 -0
- data/test/functional/associations/test_belongs_to_proxy.rb +101 -0
- data/test/functional/associations/test_in_array_proxy.rb +325 -0
- data/test/functional/associations/test_many_documents_as_proxy.rb +229 -0
- data/test/functional/associations/test_many_documents_proxy.rb +453 -0
- data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +176 -0
- data/test/functional/associations/test_many_embedded_proxy.rb +256 -0
- data/test/functional/associations/test_many_polymorphic_proxy.rb +302 -0
- data/test/functional/associations/test_one_proxy.rb +161 -0
- data/test/functional/test_associations.rb +44 -0
- data/test/functional/test_binary.rb +27 -0
- data/test/functional/test_callbacks.rb +151 -0
- data/test/functional/test_dirty.rb +163 -0
- data/test/functional/test_document.rb +1165 -0
- data/test/functional/test_embedded_document.rb +130 -0
- data/test/functional/test_identity_map.rb +508 -0
- data/test/functional/test_indexing.rb +44 -0
- data/test/functional/test_logger.rb +20 -0
- data/test/functional/test_modifiers.rb +322 -0
- data/test/functional/test_pagination.rb +93 -0
- data/test/functional/test_protected.rb +161 -0
- data/test/functional/test_string_id_compatibility.rb +67 -0
- data/test/functional/test_timestamps.rb +64 -0
- data/test/functional/test_userstamps.rb +28 -0
- data/test/functional/test_validations.rb +329 -0
- data/test/models.rb +232 -0
- data/test/support/custom_matchers.rb +55 -0
- data/test/support/timing.rb +16 -0
- data/test/test_helper.rb +61 -0
- data/test/unit/associations/test_base.rb +207 -0
- data/test/unit/associations/test_proxy.rb +105 -0
- data/test/unit/serializers/test_json_serializer.rb +202 -0
- data/test/unit/test_descendant_appends.rb +71 -0
- data/test/unit/test_document.rb +231 -0
- data/test/unit/test_dynamic_finder.rb +123 -0
- data/test/unit/test_embedded_document.rb +663 -0
- data/test/unit/test_keys.rb +173 -0
- data/test/unit/test_mongo_mapper.rb +155 -0
- data/test/unit/test_pagination.rb +160 -0
- data/test/unit/test_plugins.rb +50 -0
- data/test/unit/test_query.rb +340 -0
- data/test/unit/test_rails.rb +123 -0
- data/test/unit/test_rails_compatibility.rb +52 -0
- data/test/unit/test_serialization.rb +51 -0
- data/test/unit/test_support.rb +366 -0
- data/test/unit/test_time_zones.rb +39 -0
- data/test/unit/test_validations.rb +544 -0
- metadata +305 -0
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
# Almost all of this callback stuff is pulled directly from ActiveSupport
|
|
2
|
+
# in the interest of support rails 2 and 3 at the same time and is the
|
|
3
|
+
# same copyright as rails.
|
|
4
|
+
module MongoMapper
|
|
5
|
+
module Plugins
|
|
6
|
+
module Callbacks
|
|
7
|
+
def self.configure(model)
|
|
8
|
+
model.class_eval do
|
|
9
|
+
define_callbacks(
|
|
10
|
+
:before_save, :after_save,
|
|
11
|
+
:before_create, :after_create,
|
|
12
|
+
:before_update, :after_update,
|
|
13
|
+
:before_validation, :after_validation,
|
|
14
|
+
:before_validation_on_create, :after_validation_on_create,
|
|
15
|
+
:before_validation_on_update, :after_validation_on_update,
|
|
16
|
+
:before_destroy, :after_destroy,
|
|
17
|
+
:validate_on_create, :validate_on_update,
|
|
18
|
+
:validate
|
|
19
|
+
)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
module ClassMethods
|
|
24
|
+
def define_callbacks(*callbacks)
|
|
25
|
+
callbacks.each do |callback|
|
|
26
|
+
class_eval <<-"end_eval"
|
|
27
|
+
def self.#{callback}(*methods, &block)
|
|
28
|
+
callbacks = CallbackChain.build(:#{callback}, *methods, &block)
|
|
29
|
+
@#{callback}_callbacks ||= CallbackChain.new
|
|
30
|
+
@#{callback}_callbacks.concat callbacks
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def self.#{callback}_callback_chain
|
|
34
|
+
@#{callback}_callbacks ||= CallbackChain.new
|
|
35
|
+
|
|
36
|
+
if superclass.respond_to?(:#{callback}_callback_chain)
|
|
37
|
+
CallbackChain.new(
|
|
38
|
+
superclass.#{callback}_callback_chain +
|
|
39
|
+
@#{callback}_callbacks
|
|
40
|
+
)
|
|
41
|
+
else
|
|
42
|
+
@#{callback}_callbacks
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end_eval
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
module InstanceMethods
|
|
51
|
+
def valid?
|
|
52
|
+
action = new? ? 'create' : 'update'
|
|
53
|
+
run_callbacks(:before_validation)
|
|
54
|
+
run_callbacks("before_validation_on_#{action}".to_sym)
|
|
55
|
+
result = super
|
|
56
|
+
run_callbacks("after_validation_on_#{action}".to_sym)
|
|
57
|
+
run_callbacks(:after_validation)
|
|
58
|
+
result
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Overriding validatable's valid_for_group? to integrate validation callbacks
|
|
62
|
+
def valid_for_group?(group) #:nodoc:
|
|
63
|
+
errors.clear
|
|
64
|
+
run_before_validations
|
|
65
|
+
run_callbacks(:validate)
|
|
66
|
+
new? ? run_callbacks(:validate_on_create) : run_callbacks(:validate_on_update)
|
|
67
|
+
self.class.validate_children(self, group)
|
|
68
|
+
self.validate_group(group)
|
|
69
|
+
errors.empty?
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def destroy
|
|
73
|
+
run_callbacks(:before_destroy)
|
|
74
|
+
result = super
|
|
75
|
+
run_callbacks(:after_destroy)
|
|
76
|
+
result
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def run_callbacks(kind, options = {}, &block)
|
|
80
|
+
callback_chain_method = "#{kind}_callback_chain"
|
|
81
|
+
return unless self.class.respond_to?(callback_chain_method)
|
|
82
|
+
self.class.send(callback_chain_method).run(self, options, &block)
|
|
83
|
+
self.embedded_associations.each do |association|
|
|
84
|
+
self.send(association.name).each do |document|
|
|
85
|
+
document.run_callbacks(kind, options, &block)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
private
|
|
91
|
+
def create_or_update(*args)
|
|
92
|
+
run_callbacks(:before_save)
|
|
93
|
+
if result = super
|
|
94
|
+
run_callbacks(:after_save)
|
|
95
|
+
end
|
|
96
|
+
result
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def create(*args)
|
|
100
|
+
run_callbacks(:before_create)
|
|
101
|
+
result = super
|
|
102
|
+
run_callbacks(:after_create)
|
|
103
|
+
result
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def update(*args)
|
|
107
|
+
run_callbacks(:before_update)
|
|
108
|
+
result = super
|
|
109
|
+
run_callbacks(:after_update)
|
|
110
|
+
result
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
class CallbackChain < Array
|
|
115
|
+
def self.build(kind, *methods, &block)
|
|
116
|
+
methods, options = extract_options(*methods, &block)
|
|
117
|
+
methods.map! { |method| Callback.new(kind, method, options) }
|
|
118
|
+
new(methods)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def run(object, options = {}, &terminator)
|
|
122
|
+
enumerator = options[:enumerator] || :each
|
|
123
|
+
unless block_given?
|
|
124
|
+
send(enumerator) { |callback| callback.call(object) }
|
|
125
|
+
else
|
|
126
|
+
send(enumerator) do |callback|
|
|
127
|
+
result = callback.call(object)
|
|
128
|
+
break result if terminator.call(result, object)
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
# TODO: Decompose into more Array like behavior
|
|
133
|
+
def replace_or_append!(chain)
|
|
134
|
+
if index = index(chain)
|
|
135
|
+
self[index] = chain
|
|
136
|
+
else
|
|
137
|
+
self << chain
|
|
138
|
+
end
|
|
139
|
+
self
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def find(callback, &block)
|
|
143
|
+
select { |c| c == callback && (!block_given? || yield(c)) }.first
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def delete(callback)
|
|
147
|
+
super(callback.is_a?(Callback) ? callback : find(callback))
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
private
|
|
151
|
+
def self.extract_options(*methods, &block)
|
|
152
|
+
methods.flatten!
|
|
153
|
+
options = methods.extract_options!
|
|
154
|
+
methods << block if block_given?
|
|
155
|
+
return methods, options
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def extract_options(*methods, &block)
|
|
159
|
+
self.class.extract_options(*methods, &block)
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
class Callback
|
|
164
|
+
attr_reader :kind, :method, :identifier, :options
|
|
165
|
+
|
|
166
|
+
def initialize(kind, method, options = {})
|
|
167
|
+
@kind = kind
|
|
168
|
+
@method = method
|
|
169
|
+
@identifier = options[:identifier]
|
|
170
|
+
@options = options
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def ==(other)
|
|
174
|
+
case other
|
|
175
|
+
when Callback
|
|
176
|
+
(self.identifier && self.identifier == other.identifier) || self.method == other.method
|
|
177
|
+
else
|
|
178
|
+
(self.identifier && self.identifier == other) || self.method == other
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def eql?(other)
|
|
183
|
+
self == other
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def dup
|
|
187
|
+
self.class.new(@kind, @method, @options.dup)
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def hash
|
|
191
|
+
if @identifier
|
|
192
|
+
@identifier.hash
|
|
193
|
+
else
|
|
194
|
+
@method.hash
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
def call(*args, &block)
|
|
199
|
+
evaluate_method(method, *args, &block) if should_run_callback?(*args)
|
|
200
|
+
rescue LocalJumpError
|
|
201
|
+
raise ArgumentError,
|
|
202
|
+
"Cannot yield from a Proc type filter. The Proc must take two " +
|
|
203
|
+
"arguments and execute #call on the second argument."
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
private
|
|
207
|
+
def evaluate_method(method, *args, &block)
|
|
208
|
+
case method
|
|
209
|
+
when Symbol
|
|
210
|
+
object = args.shift
|
|
211
|
+
object.send(method, *args, &block)
|
|
212
|
+
when String
|
|
213
|
+
eval(method, args.first.instance_eval { binding })
|
|
214
|
+
when Proc, Method
|
|
215
|
+
method.call(*args, &block)
|
|
216
|
+
else
|
|
217
|
+
if method.respond_to?(kind)
|
|
218
|
+
method.send(kind, *args, &block)
|
|
219
|
+
else
|
|
220
|
+
raise ArgumentError,
|
|
221
|
+
"Callbacks must be a symbol denoting the method to call, a string to be evaluated, " +
|
|
222
|
+
"a block to be invoked, or an object responding to the callback method."
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
def should_run_callback?(*args)
|
|
228
|
+
[options[:if]].flatten.compact.all? { |a| evaluate_method(a, *args) } &&
|
|
229
|
+
![options[:unless]].flatten.compact.any? { |a| evaluate_method(a, *args) }
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
end
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
module MongoMapper
|
|
2
|
+
module Plugins
|
|
3
|
+
module Dirty
|
|
4
|
+
module InstanceMethods
|
|
5
|
+
def method_missing(method, *args, &block)
|
|
6
|
+
if method.to_s =~ /(_changed\?|_change|_will_change!|_was)$/
|
|
7
|
+
method_suffix = $1
|
|
8
|
+
key = method.to_s.gsub(method_suffix, '')
|
|
9
|
+
|
|
10
|
+
if key_names.include?(key)
|
|
11
|
+
case method_suffix
|
|
12
|
+
when '_changed?'
|
|
13
|
+
key_changed?(key)
|
|
14
|
+
when '_change'
|
|
15
|
+
key_change(key)
|
|
16
|
+
when '_will_change!'
|
|
17
|
+
key_will_change!(key)
|
|
18
|
+
when '_was'
|
|
19
|
+
key_was(key)
|
|
20
|
+
end
|
|
21
|
+
else
|
|
22
|
+
super
|
|
23
|
+
end
|
|
24
|
+
else
|
|
25
|
+
super
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def changed?
|
|
30
|
+
!changed_keys.empty?
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def changed
|
|
34
|
+
changed_keys.keys
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def changes
|
|
38
|
+
changed.inject({}) { |h, key| h[key] = key_change(key); h }
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def initialize(*args)
|
|
42
|
+
super
|
|
43
|
+
changed_keys.clear if args.first.blank? || !new?
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def save(*args)
|
|
47
|
+
if status = super
|
|
48
|
+
changed_keys.clear
|
|
49
|
+
end
|
|
50
|
+
status
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def save!(*args)
|
|
54
|
+
status = super
|
|
55
|
+
changed_keys.clear
|
|
56
|
+
status
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def reload(*args)
|
|
60
|
+
document = super
|
|
61
|
+
changed_keys.clear
|
|
62
|
+
document
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
private
|
|
66
|
+
def clone_key_value(key)
|
|
67
|
+
value = read_key(key)
|
|
68
|
+
value.duplicable? ? value.clone : value
|
|
69
|
+
rescue TypeError, NoMethodError
|
|
70
|
+
value
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def changed_keys
|
|
74
|
+
@changed_keys ||= {}
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def key_changed?(key)
|
|
78
|
+
changed_keys.include?(key)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def key_change(key)
|
|
82
|
+
[changed_keys[key], __send__(key)] if key_changed?(key)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def key_was(key)
|
|
86
|
+
key_changed?(key) ? changed_keys[key] : __send__(key)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def key_will_change!(key)
|
|
90
|
+
changed_keys[key] = clone_key_value(key)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def write_key(key, value)
|
|
94
|
+
key = key.to_s
|
|
95
|
+
|
|
96
|
+
if changed_keys.include?(key)
|
|
97
|
+
old = changed_keys[key]
|
|
98
|
+
changed_keys.delete(key) unless value_changed?(key, old, value)
|
|
99
|
+
else
|
|
100
|
+
old = clone_key_value(key)
|
|
101
|
+
changed_keys[key] = old if value_changed?(key, old, value)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
super(key, value)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def value_changed?(key_name, old, value)
|
|
108
|
+
key = keys[key_name]
|
|
109
|
+
|
|
110
|
+
if key.number? && value.blank?
|
|
111
|
+
value = nil
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
old != value
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module MongoMapper
|
|
2
|
+
module Plugins
|
|
3
|
+
module Equality
|
|
4
|
+
module InstanceMethods
|
|
5
|
+
def ==(other)
|
|
6
|
+
other.is_a?(self.class) && _id == other._id
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def eql?(other)
|
|
10
|
+
self == other
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def equal?(other)
|
|
14
|
+
object_id === other.object_id
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def hash
|
|
18
|
+
_id.hash
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
module MongoMapper
|
|
2
|
+
module Plugins
|
|
3
|
+
module IdentityMap
|
|
4
|
+
def self.models
|
|
5
|
+
@models ||= Set.new
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def self.clear
|
|
9
|
+
models.each { |m| m.identity_map.clear }
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.configure(model)
|
|
13
|
+
IdentityMap.models << model
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
module ClassMethods
|
|
17
|
+
def inherited(descendant)
|
|
18
|
+
descendant.identity_map = identity_map
|
|
19
|
+
super
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def identity_map
|
|
23
|
+
@identity_map ||= {}
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def identity_map=(v)
|
|
27
|
+
@identity_map = v
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def find_one(options={})
|
|
31
|
+
criteria, query_options = to_query(options)
|
|
32
|
+
|
|
33
|
+
if simple_find?(criteria) && identity_map.key?(criteria[:_id])
|
|
34
|
+
identity_map[criteria[:_id]]
|
|
35
|
+
else
|
|
36
|
+
super.tap do |document|
|
|
37
|
+
remove_documents_from_map(document) if selecting_fields?(query_options)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def find_many(options)
|
|
43
|
+
criteria, query_options = to_query(options)
|
|
44
|
+
super.tap do |documents|
|
|
45
|
+
remove_documents_from_map(documents) if selecting_fields?(query_options)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def load(attrs)
|
|
50
|
+
document = identity_map[attrs['_id']]
|
|
51
|
+
|
|
52
|
+
if document.nil? || identity_map_off?
|
|
53
|
+
document = super
|
|
54
|
+
identity_map[document._id] = document if identity_map_on?
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
document
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def identity_map_status
|
|
61
|
+
defined?(@identity_map_status) ? @identity_map_status : true
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def identity_map_on
|
|
65
|
+
@identity_map_status = true
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def identity_map_off
|
|
69
|
+
@identity_map_status = false
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def identity_map_on?
|
|
73
|
+
identity_map_status
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def identity_map_off?
|
|
77
|
+
!identity_map_on?
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def without_identity_map(&block)
|
|
81
|
+
identity_map_off
|
|
82
|
+
yield
|
|
83
|
+
ensure
|
|
84
|
+
identity_map_on
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
private
|
|
88
|
+
def remove_documents_from_map(*documents)
|
|
89
|
+
documents.flatten.compact.each do |document|
|
|
90
|
+
identity_map.delete(document._id)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def simple_find?(criteria)
|
|
95
|
+
criteria.keys == [:_id] || criteria.keys.to_set == [:_id, :_type].to_set
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def selecting_fields?(options)
|
|
99
|
+
!options[:fields].nil?
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
module InstanceMethods
|
|
104
|
+
def identity_map
|
|
105
|
+
self.class.identity_map
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def save(*args)
|
|
109
|
+
if result = super
|
|
110
|
+
identity_map[_id] = self if self.class.identity_map_on?
|
|
111
|
+
end
|
|
112
|
+
result
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def delete
|
|
116
|
+
identity_map.delete(_id) if self.class.identity_map_on?
|
|
117
|
+
super
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|