mongo_mapper 0.7.0 → 0.7.1
Sign up to get free protection for your applications and to get access to all the features.
- 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