mongo_mapper 0.7.0 → 0.7.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/README.rdoc +3 -1
- data/Rakefile +9 -12
- data/lib/mongo_mapper.rb +30 -10
- data/lib/mongo_mapper/document.rb +16 -74
- data/lib/mongo_mapper/embedded_document.rb +7 -1
- data/lib/mongo_mapper/plugins.rb +3 -0
- data/lib/mongo_mapper/plugins/associations/embedded_collection.rb +1 -12
- data/lib/mongo_mapper/plugins/associations/in_array_proxy.rb +6 -1
- data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +4 -1
- data/lib/mongo_mapper/plugins/callbacks.rb +183 -12
- data/lib/mongo_mapper/plugins/keys.rb +17 -5
- data/lib/mongo_mapper/plugins/modifiers.rb +87 -0
- data/lib/mongo_mapper/plugins/pagination/proxy.rb +7 -3
- data/lib/mongo_mapper/plugins/protected.rb +1 -1
- data/lib/mongo_mapper/plugins/rails.rb +16 -8
- data/lib/mongo_mapper/plugins/serialization.rb +51 -81
- data/lib/mongo_mapper/plugins/timestamps.rb +21 -0
- data/lib/mongo_mapper/plugins/userstamps.rb +14 -0
- data/lib/mongo_mapper/query.rb +1 -1
- data/lib/mongo_mapper/version.rb +3 -0
- data/mongo_mapper.gemspec +22 -11
- data/test/active_model_lint_test.rb +11 -0
- data/test/functional/associations/test_in_array_proxy.rb +16 -0
- data/test/functional/associations/test_many_documents_proxy.rb +22 -0
- data/test/functional/test_callbacks.rb +104 -34
- data/test/functional/test_document.rb +70 -149
- data/test/functional/test_embedded_document.rb +39 -34
- data/test/functional/test_indexing.rb +44 -0
- data/test/functional/test_modifiers.rb +297 -227
- data/test/functional/test_protected.rb +11 -5
- data/test/functional/test_timestamps.rb +64 -0
- data/test/functional/test_userstamps.rb +28 -0
- data/test/support/timing.rb +1 -1
- data/test/unit/serializers/test_json_serializer.rb +30 -17
- data/test/unit/test_embedded_document.rb +15 -15
- data/test/unit/test_keys.rb +15 -11
- data/test/unit/test_mongo_mapper.rb +31 -1
- data/test/unit/test_pagination.rb +33 -0
- data/test/unit/test_query.rb +6 -0
- data/test/unit/test_serialization.rb +3 -3
- data/test/unit/test_support.rb +9 -5
- metadata +17 -6
- data/VERSION +0 -1
@@ -170,11 +170,14 @@ module MongoMapper
|
|
170
170
|
|
171
171
|
def attributes=(attrs)
|
172
172
|
return if attrs.blank?
|
173
|
-
|
173
|
+
|
174
174
|
attrs.each_pair do |name, value|
|
175
175
|
writer_method = "#{name}="
|
176
176
|
|
177
177
|
if respond_to?(writer_method)
|
178
|
+
if writer_method == '_root_document='
|
179
|
+
puts "_root_document= #{value.inspect}"
|
180
|
+
end
|
178
181
|
self.send(writer_method, value)
|
179
182
|
else
|
180
183
|
self[name.to_s] = value
|
@@ -217,7 +220,7 @@ module MongoMapper
|
|
217
220
|
def id
|
218
221
|
_id
|
219
222
|
end
|
220
|
-
|
223
|
+
|
221
224
|
def id=(value)
|
222
225
|
if self.class.using_object_id?
|
223
226
|
value = MongoMapper.normalize_object_id(value)
|
@@ -259,7 +262,7 @@ module MongoMapper
|
|
259
262
|
def assign_type_if_present
|
260
263
|
self._type = self.class.name if respond_to?(:_type=)
|
261
264
|
end
|
262
|
-
|
265
|
+
|
263
266
|
def ensure_key_exists(name)
|
264
267
|
self.class.key(name) unless respond_to?("#{name}=")
|
265
268
|
end
|
@@ -280,11 +283,16 @@ module MongoMapper
|
|
280
283
|
|
281
284
|
def write_key(name, value)
|
282
285
|
key = keys[name]
|
286
|
+
|
287
|
+
if key.embeddable? && value.is_a?(key.type)
|
288
|
+
value._parent_document = self
|
289
|
+
end
|
290
|
+
|
283
291
|
instance_variable_set "@#{name}_before_typecast", value
|
284
292
|
instance_variable_set "@#{name}", key.set(value)
|
285
293
|
end
|
286
294
|
end
|
287
|
-
|
295
|
+
|
288
296
|
class Key
|
289
297
|
attr_accessor :name, :type, :options, :default_value
|
290
298
|
|
@@ -309,7 +317,11 @@ module MongoMapper
|
|
309
317
|
|
310
318
|
def get(value)
|
311
319
|
if value.nil? && !default_value.nil?
|
312
|
-
|
320
|
+
if default_value.respond_to?(:call)
|
321
|
+
return default_value.call
|
322
|
+
else
|
323
|
+
return default_value
|
324
|
+
end
|
313
325
|
end
|
314
326
|
|
315
327
|
type.from_mongo(value)
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module MongoMapper
|
2
|
+
module Plugins
|
3
|
+
module Modifiers
|
4
|
+
module ClassMethods
|
5
|
+
def increment(*args)
|
6
|
+
modifier_update('$inc', args)
|
7
|
+
end
|
8
|
+
|
9
|
+
def decrement(*args)
|
10
|
+
criteria, keys = criteria_and_keys_from_args(args)
|
11
|
+
values, to_decrement = keys.values, {}
|
12
|
+
keys.keys.each_with_index { |k, i| to_decrement[k] = -values[i].abs }
|
13
|
+
collection.update(criteria, {'$inc' => to_decrement}, :multi => true)
|
14
|
+
end
|
15
|
+
|
16
|
+
def set(*args)
|
17
|
+
modifier_update('$set', args)
|
18
|
+
end
|
19
|
+
|
20
|
+
def push(*args)
|
21
|
+
modifier_update('$push', args)
|
22
|
+
end
|
23
|
+
|
24
|
+
def push_all(*args)
|
25
|
+
modifier_update('$pushAll', args)
|
26
|
+
end
|
27
|
+
|
28
|
+
def push_uniq(*args)
|
29
|
+
criteria, keys = criteria_and_keys_from_args(args)
|
30
|
+
keys.each { |key, value | criteria[key] = {'$ne' => value} }
|
31
|
+
collection.update(criteria, {'$push' => keys}, :multi => true)
|
32
|
+
end
|
33
|
+
|
34
|
+
def pull(*args)
|
35
|
+
modifier_update('$pull', args)
|
36
|
+
end
|
37
|
+
|
38
|
+
def pull_all(*args)
|
39
|
+
modifier_update('$pullAll', args)
|
40
|
+
end
|
41
|
+
|
42
|
+
def pop(*args)
|
43
|
+
modifier_update('$pop', args)
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
def modifier_update(modifier, args)
|
48
|
+
criteria, keys = criteria_and_keys_from_args(args)
|
49
|
+
modifiers = {modifier => keys}
|
50
|
+
collection.update(criteria, modifiers, :multi => true)
|
51
|
+
end
|
52
|
+
|
53
|
+
def criteria_and_keys_from_args(args)
|
54
|
+
keys = args.pop
|
55
|
+
criteria = args[0].is_a?(Hash) ? args[0] : {:id => args}
|
56
|
+
[to_criteria(criteria), keys]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
module InstanceMethods
|
61
|
+
def increment(hash)
|
62
|
+
self.class.increment({:_id => id}, hash)
|
63
|
+
end
|
64
|
+
|
65
|
+
def decrement(hash)
|
66
|
+
self.class.decrement({:_id => id}, hash)
|
67
|
+
end
|
68
|
+
|
69
|
+
def set(hash)
|
70
|
+
self.class.set({:_id => id}, hash)
|
71
|
+
end
|
72
|
+
|
73
|
+
def push(hash)
|
74
|
+
self.class.push({:_id => id}, hash)
|
75
|
+
end
|
76
|
+
|
77
|
+
def pull(hash)
|
78
|
+
self.class.pull({:_id => id}, hash)
|
79
|
+
end
|
80
|
+
|
81
|
+
def push_uniq(hash)
|
82
|
+
self.class.push_uniq({:_id => id}, hash)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -2,8 +2,8 @@ module MongoMapper
|
|
2
2
|
module Plugins
|
3
3
|
module Pagination
|
4
4
|
class Proxy
|
5
|
-
instance_methods.each { |m| undef_method m unless m =~ /(^__|^nil\?$|^send$|proxy_|^object_id$)/ }
|
6
|
-
|
5
|
+
instance_methods.each { |m| undef_method m unless m =~ /(^__|^nil\?$|^send$|respond_to\?|proxy_|^object_id$)/ }
|
6
|
+
|
7
7
|
attr_accessor :subject
|
8
8
|
attr_reader :total_entries, :per_page, :current_page
|
9
9
|
alias limit per_page
|
@@ -50,7 +50,11 @@ module MongoMapper
|
|
50
50
|
def method_missing(name, *args, &block)
|
51
51
|
@subject.send(name, *args, &block)
|
52
52
|
end
|
53
|
-
|
53
|
+
|
54
|
+
def respond_to?(name, *args, &block)
|
55
|
+
super || @subject.respond_to?(name, *args, &block)
|
56
|
+
end
|
57
|
+
|
54
58
|
private
|
55
59
|
def per_page=(value)
|
56
60
|
value = 25 if value.blank?
|
@@ -37,7 +37,7 @@ module MongoMapper
|
|
37
37
|
protected
|
38
38
|
def filter_protected_attrs(attrs)
|
39
39
|
return attrs if protected_attributes.blank?
|
40
|
-
attrs.dup.delete_if { |key, val| protected_attributes.include?(key) }
|
40
|
+
attrs.dup.delete_if { |key, val| protected_attributes.include?(key.to_sym) }
|
41
41
|
end
|
42
42
|
end
|
43
43
|
end
|
@@ -1,41 +1,49 @@
|
|
1
1
|
module MongoMapper
|
2
2
|
module Plugins
|
3
3
|
module Rails
|
4
|
+
def self.configure(model)
|
5
|
+
model.extend ActiveModel::Naming if defined?(ActiveModel)
|
6
|
+
end
|
7
|
+
|
4
8
|
module InstanceMethods
|
5
9
|
def to_param
|
6
10
|
id.to_s
|
7
11
|
end
|
8
|
-
|
12
|
+
|
13
|
+
def to_model
|
14
|
+
self
|
15
|
+
end
|
16
|
+
|
9
17
|
def new_record?
|
10
18
|
new?
|
11
19
|
end
|
12
|
-
|
20
|
+
|
13
21
|
def read_attribute(name)
|
14
22
|
self[name]
|
15
23
|
end
|
16
|
-
|
24
|
+
|
17
25
|
def read_attribute_before_typecast(name)
|
18
26
|
read_key_before_typecast(name)
|
19
27
|
end
|
20
|
-
|
28
|
+
|
21
29
|
def write_attribute(name, value)
|
22
30
|
self[name] = value
|
23
31
|
end
|
24
32
|
end
|
25
|
-
|
33
|
+
|
26
34
|
module ClassMethods
|
27
35
|
def has_one(*args)
|
28
36
|
one(*args)
|
29
37
|
end
|
30
|
-
|
38
|
+
|
31
39
|
def has_many(*args)
|
32
40
|
many(*args)
|
33
41
|
end
|
34
|
-
|
42
|
+
|
35
43
|
def column_names
|
36
44
|
keys.keys
|
37
45
|
end
|
38
|
-
|
46
|
+
|
39
47
|
def human_name
|
40
48
|
self.name.demodulize.titleize
|
41
49
|
end
|
@@ -4,102 +4,72 @@ module MongoMapper
|
|
4
4
|
module Plugins
|
5
5
|
module Serialization
|
6
6
|
def self.configure(model)
|
7
|
-
model.class_eval {
|
7
|
+
model.class_eval { cattr_accessor :include_root_in_json, :instance_writer => true }
|
8
8
|
end
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
def serializable_key_names
|
18
|
-
key_names = @record.attributes.keys
|
19
|
-
|
20
|
-
if options[:only]
|
21
|
-
options.delete(:except)
|
22
|
-
key_names = key_names & Array(options[:only]).collect { |n| n.to_s }
|
23
|
-
else
|
24
|
-
options[:except] = Array(options[:except])
|
25
|
-
key_names = key_names - options[:except].collect { |n| n.to_s }
|
26
|
-
end
|
27
|
-
|
28
|
-
key_names
|
29
|
-
end
|
30
|
-
|
31
|
-
def serializable_method_names
|
32
|
-
Array(options[:methods]).inject([]) do |method_attributes, name|
|
33
|
-
method_attributes << name if @record.respond_to?(name.to_s)
|
34
|
-
method_attributes
|
10
|
+
module InstanceMethods
|
11
|
+
def as_json options={}
|
12
|
+
options ||= {}
|
13
|
+
unless options[:only]
|
14
|
+
methods = [options.delete(:methods)].flatten.compact
|
15
|
+
methods << :id
|
16
|
+
options[:methods] = methods.uniq
|
35
17
|
end
|
36
|
-
end
|
37
18
|
|
38
|
-
|
39
|
-
|
40
|
-
|
19
|
+
except = [options.delete(:except)].flatten.compact
|
20
|
+
except << :_id
|
21
|
+
options[:except] = except
|
41
22
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
end
|
23
|
+
# Direct rip from Rails 3 ActiveModel Serialization (#serializable_hash)
|
24
|
+
hash = begin
|
25
|
+
options[:only] = Array.wrap(options[:only]).map { |n| n.to_s }
|
26
|
+
options[:except] = Array.wrap(options[:except]).map { |n| n.to_s }
|
47
27
|
|
48
|
-
|
49
|
-
|
50
|
-
|
28
|
+
attribute_names = attributes.keys.sort
|
29
|
+
if options[:only].any?
|
30
|
+
attribute_names &= options[:only]
|
31
|
+
elsif options[:except].any?
|
32
|
+
attribute_names -= options[:except]
|
33
|
+
end
|
51
34
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
module Json
|
58
|
-
def self.included(base)
|
59
|
-
base.cattr_accessor :include_root_in_json, :instance_writer => false
|
60
|
-
base.extend ClassMethods
|
61
|
-
end
|
35
|
+
method_names = Array.wrap(options[:methods]).inject([]) do |methods, name|
|
36
|
+
methods << name if respond_to?(name.to_s)
|
37
|
+
methods
|
38
|
+
end
|
62
39
|
|
63
|
-
|
64
|
-
|
65
|
-
|
40
|
+
(attribute_names + method_names).inject({}) { |hash, name|
|
41
|
+
hash[name] = send(name)
|
42
|
+
hash
|
43
|
+
}
|
66
44
|
end
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
45
|
+
# End rip
|
46
|
+
|
47
|
+
options.delete(:only) if options[:only].nil? or options[:only].empty?
|
48
|
+
|
49
|
+
hash.each do |key, value|
|
50
|
+
if value.is_a?(Array)
|
51
|
+
hash[key] = value.map do |item|
|
52
|
+
item.respond_to?(:as_json) ? item.as_json(options) : item
|
53
|
+
end
|
54
|
+
elsif value.is_a? Mongo::ObjectID
|
55
|
+
hash[key] = value.to_s
|
56
|
+
elsif value.respond_to?(:as_json)
|
57
|
+
hash[key] = value.as_json(options)
|
58
|
+
end
|
76
59
|
end
|
60
|
+
|
61
|
+
# Replicate Rails 3 naming - and also bin anytihng after : for use in our dynamic classes from unit tests
|
62
|
+
hash = { ActiveSupport::Inflector.underscore(ActiveSupport::Inflector.demodulize(self)).gsub(/:.*/,'') => hash } if include_root_in_json
|
63
|
+
hash
|
77
64
|
end
|
65
|
+
end
|
78
66
|
|
67
|
+
module ClassMethods
|
79
68
|
def from_json(json)
|
80
|
-
self.
|
81
|
-
self
|
69
|
+
self.new(ActiveSupport::JSON.decode(json))
|
82
70
|
end
|
83
|
-
|
84
|
-
class JsonSerializer < Serializer
|
85
|
-
def serialize
|
86
|
-
serializable_record.to_json
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
private
|
91
|
-
def apply_to_json_defaults(options)
|
92
|
-
unless options[:only]
|
93
|
-
methods = [options.delete(:methods)].flatten.compact
|
94
|
-
methods << :id
|
95
|
-
options[:methods] = methods.uniq
|
96
|
-
end
|
97
|
-
|
98
|
-
except = [options.delete(:except)].flatten.compact
|
99
|
-
except << :_id
|
100
|
-
options[:except] = except
|
101
|
-
end
|
102
71
|
end
|
72
|
+
|
103
73
|
end
|
104
74
|
end
|
105
75
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module MongoMapper
|
2
|
+
module Plugins
|
3
|
+
module Timestamps
|
4
|
+
module ClassMethods
|
5
|
+
def timestamps!
|
6
|
+
key :created_at, Time
|
7
|
+
key :updated_at, Time
|
8
|
+
class_eval { before_save :update_timestamps }
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
module InstanceMethods
|
13
|
+
def update_timestamps
|
14
|
+
now = Time.now.utc
|
15
|
+
self[:created_at] = now if new? && !created_at?
|
16
|
+
self[:updated_at] = now
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module MongoMapper
|
2
|
+
module Plugins
|
3
|
+
module Userstamps
|
4
|
+
module ClassMethods
|
5
|
+
def userstamps!
|
6
|
+
key :creator_id, ObjectId
|
7
|
+
key :updater_id, ObjectId
|
8
|
+
belongs_to :creator, :class_name => 'User'
|
9
|
+
belongs_to :updater, :class_name => 'User'
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
data/lib/mongo_mapper/query.rb
CHANGED