mongo_mapper_ign 0.7.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (105) hide show
  1. data/.gitignore +10 -0
  2. data/LICENSE +20 -0
  3. data/README.rdoc +35 -0
  4. data/Rakefile +37 -0
  5. data/bin/mmconsole +60 -0
  6. data/lib/mongo_mapper.rb +116 -0
  7. data/lib/mongo_mapper/document.rb +313 -0
  8. data/lib/mongo_mapper/embedded_document.rb +70 -0
  9. data/lib/mongo_mapper/plugins.rb +35 -0
  10. data/lib/mongo_mapper/plugins/associations.rb +114 -0
  11. data/lib/mongo_mapper/plugins/associations/base.rb +123 -0
  12. data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +30 -0
  13. data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +25 -0
  14. data/lib/mongo_mapper/plugins/associations/collection.rb +21 -0
  15. data/lib/mongo_mapper/plugins/associations/embedded_collection.rb +39 -0
  16. data/lib/mongo_mapper/plugins/associations/in_array_proxy.rb +144 -0
  17. data/lib/mongo_mapper/plugins/associations/many_documents_as_proxy.rb +28 -0
  18. data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +129 -0
  19. data/lib/mongo_mapper/plugins/associations/many_embedded_polymorphic_proxy.rb +31 -0
  20. data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +23 -0
  21. data/lib/mongo_mapper/plugins/associations/many_polymorphic_proxy.rb +13 -0
  22. data/lib/mongo_mapper/plugins/associations/one_embedded_proxy.rb +41 -0
  23. data/lib/mongo_mapper/plugins/associations/one_proxy.rb +69 -0
  24. data/lib/mongo_mapper/plugins/associations/proxy.rb +124 -0
  25. data/lib/mongo_mapper/plugins/callbacks.rb +240 -0
  26. data/lib/mongo_mapper/plugins/clone.rb +13 -0
  27. data/lib/mongo_mapper/plugins/descendants.rb +16 -0
  28. data/lib/mongo_mapper/plugins/dirty.rb +119 -0
  29. data/lib/mongo_mapper/plugins/equality.rb +23 -0
  30. data/lib/mongo_mapper/plugins/identity_map.rb +122 -0
  31. data/lib/mongo_mapper/plugins/inspect.rb +14 -0
  32. data/lib/mongo_mapper/plugins/keys.rb +345 -0
  33. data/lib/mongo_mapper/plugins/logger.rb +17 -0
  34. data/lib/mongo_mapper/plugins/modifiers.rb +107 -0
  35. data/lib/mongo_mapper/plugins/pagination.rb +24 -0
  36. data/lib/mongo_mapper/plugins/pagination/proxy.rb +72 -0
  37. data/lib/mongo_mapper/plugins/persistence.rb +68 -0
  38. data/lib/mongo_mapper/plugins/protected.rb +45 -0
  39. data/lib/mongo_mapper/plugins/rails.rb +57 -0
  40. data/lib/mongo_mapper/plugins/serialization.rb +91 -0
  41. data/lib/mongo_mapper/plugins/serialization/array.rb +56 -0
  42. data/lib/mongo_mapper/plugins/serialization/xml_serializer.rb +240 -0
  43. data/lib/mongo_mapper/plugins/timestamps.rb +21 -0
  44. data/lib/mongo_mapper/plugins/userstamps.rb +14 -0
  45. data/lib/mongo_mapper/plugins/validations.rb +46 -0
  46. data/lib/mongo_mapper/query.rb +143 -0
  47. data/lib/mongo_mapper/support.rb +218 -0
  48. data/lib/mongo_mapper/support/descendant_appends.rb +46 -0
  49. data/lib/mongo_mapper/support/find.rb +77 -0
  50. data/lib/mongo_mapper/version.rb +3 -0
  51. data/mongo_mapper.gemspec +214 -0
  52. data/mongo_mapper_ign.gemspec +217 -0
  53. data/performance/read_write.rb +52 -0
  54. data/specs.watchr +51 -0
  55. data/test/NOTE_ON_TESTING +1 -0
  56. data/test/active_model_lint_test.rb +13 -0
  57. data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +63 -0
  58. data/test/functional/associations/test_belongs_to_proxy.rb +101 -0
  59. data/test/functional/associations/test_in_array_proxy.rb +325 -0
  60. data/test/functional/associations/test_many_documents_as_proxy.rb +229 -0
  61. data/test/functional/associations/test_many_documents_proxy.rb +536 -0
  62. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +176 -0
  63. data/test/functional/associations/test_many_embedded_proxy.rb +256 -0
  64. data/test/functional/associations/test_many_polymorphic_proxy.rb +302 -0
  65. data/test/functional/associations/test_one_embedded_proxy.rb +68 -0
  66. data/test/functional/associations/test_one_proxy.rb +196 -0
  67. data/test/functional/test_associations.rb +44 -0
  68. data/test/functional/test_binary.rb +27 -0
  69. data/test/functional/test_callbacks.rb +151 -0
  70. data/test/functional/test_dirty.rb +163 -0
  71. data/test/functional/test_document.rb +1219 -0
  72. data/test/functional/test_embedded_document.rb +210 -0
  73. data/test/functional/test_identity_map.rb +507 -0
  74. data/test/functional/test_indexing.rb +44 -0
  75. data/test/functional/test_logger.rb +20 -0
  76. data/test/functional/test_modifiers.rb +394 -0
  77. data/test/functional/test_pagination.rb +93 -0
  78. data/test/functional/test_protected.rb +163 -0
  79. data/test/functional/test_string_id_compatibility.rb +67 -0
  80. data/test/functional/test_timestamps.rb +64 -0
  81. data/test/functional/test_userstamps.rb +28 -0
  82. data/test/functional/test_validations.rb +342 -0
  83. data/test/models.rb +227 -0
  84. data/test/support/custom_matchers.rb +37 -0
  85. data/test/support/timing.rb +16 -0
  86. data/test/test_helper.rb +64 -0
  87. data/test/unit/associations/test_base.rb +212 -0
  88. data/test/unit/associations/test_proxy.rb +105 -0
  89. data/test/unit/serializers/test_json_serializer.rb +202 -0
  90. data/test/unit/test_descendant_appends.rb +71 -0
  91. data/test/unit/test_document.rb +225 -0
  92. data/test/unit/test_dynamic_finder.rb +123 -0
  93. data/test/unit/test_embedded_document.rb +657 -0
  94. data/test/unit/test_keys.rb +185 -0
  95. data/test/unit/test_mongo_mapper.rb +118 -0
  96. data/test/unit/test_pagination.rb +160 -0
  97. data/test/unit/test_plugins.rb +50 -0
  98. data/test/unit/test_query.rb +374 -0
  99. data/test/unit/test_rails.rb +181 -0
  100. data/test/unit/test_rails_compatibility.rb +52 -0
  101. data/test/unit/test_serialization.rb +51 -0
  102. data/test/unit/test_support.rb +382 -0
  103. data/test/unit/test_time_zones.rb +39 -0
  104. data/test/unit/test_validations.rb +544 -0
  105. metadata +327 -0
@@ -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
@@ -0,0 +1,14 @@
1
+ module MongoMapper
2
+ module Plugins
3
+ module Inspect
4
+ module InstanceMethods
5
+ def inspect
6
+ attributes_as_nice_string = key_names.collect do |name|
7
+ "#{name}: #{self[name].inspect}"
8
+ end.join(", ")
9
+ "#<#{self.class} #{attributes_as_nice_string}>"
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,345 @@
1
+ module MongoMapper
2
+ module Plugins
3
+ module Keys
4
+ def self.configure(model)
5
+ model.key :_id, ObjectId
6
+ end
7
+
8
+ module ClassMethods
9
+ def inherited(descendant)
10
+ key :_type, String unless keys.keys.include?(:_type)
11
+ descendant.instance_variable_set(:@keys, keys.dup)
12
+ super
13
+ end
14
+
15
+ def keys
16
+ @keys ||= HashWithIndifferentAccess.new
17
+ end
18
+
19
+ def key(*args)
20
+ key = Key.new(*args)
21
+ keys[key.name] = key
22
+
23
+ create_accessors_for(key)
24
+ create_key_in_descendants(*args)
25
+ create_indexes_for(key)
26
+ create_validations_for(key)
27
+
28
+ key
29
+ end
30
+
31
+ def key?(key)
32
+ keys.keys.include?(key.to_s)
33
+ end
34
+
35
+ def using_object_id?
36
+ object_id_key?(:_id)
37
+ end
38
+
39
+ def object_id_key?(name)
40
+ key = keys[name.to_s]
41
+ key && key.type == ObjectId
42
+ end
43
+
44
+ def to_mongo(instance)
45
+ return nil if instance.nil?
46
+ instance.to_mongo
47
+ end
48
+
49
+ def from_mongo(value)
50
+ return nil if value.nil?
51
+ value.is_a?(self) ? value : load(value)
52
+ end
53
+
54
+ # load is overridden in identity map to ensure same objects are loaded
55
+ def load(attrs)
56
+ begin
57
+ klass = attrs['_type'].present? ? attrs['_type'].constantize : self
58
+ klass.new(attrs, true)
59
+ rescue NameError
60
+ new(attrs, true)
61
+ end
62
+ end
63
+
64
+ private
65
+ def accessors_module
66
+ module_defined = if method(:const_defined?).arity == 1 # Ruby 1.9 compat check
67
+ const_defined?('MongoMapperKeys')
68
+ else
69
+ const_defined?('MongoMapperKeys', false)
70
+ end
71
+
72
+ if module_defined
73
+ const_get 'MongoMapperKeys'
74
+ else
75
+ const_set 'MongoMapperKeys', Module.new
76
+ end
77
+ end
78
+
79
+ def create_accessors_for(key)
80
+ accessors_module.module_eval <<-end_eval
81
+ def #{key.name}
82
+ read_key(:#{key.name})
83
+ end
84
+
85
+ def #{key.name}_before_typecast
86
+ read_key_before_typecast(:#{key.name})
87
+ end
88
+
89
+ def #{key.name}=(value)
90
+ write_key(:#{key.name}, value)
91
+ end
92
+
93
+ def #{key.name}?
94
+ read_key(:#{key.name}).present?
95
+ end
96
+ end_eval
97
+
98
+ include accessors_module
99
+ end
100
+
101
+ def create_key_in_descendants(*args)
102
+ descendants.each { |descendant| descendant.key(*args) }
103
+ end
104
+
105
+ def create_indexes_for(key)
106
+ ensure_index key.name if key.options[:index] && !key.embeddable?
107
+ end
108
+
109
+ def create_validations_for(key)
110
+ attribute = key.name.to_sym
111
+
112
+ if key.options[:required]
113
+ validates_presence_of(attribute)
114
+ end
115
+
116
+ if key.options[:unique]
117
+ validates_uniqueness_of(attribute)
118
+ end
119
+
120
+ if key.options[:numeric]
121
+ number_options = key.type == Integer ? {:only_integer => true} : {}
122
+ validates_numericality_of(attribute, number_options)
123
+ end
124
+
125
+ if key.options[:format]
126
+ validates_format_of(attribute, :with => key.options[:format])
127
+ end
128
+
129
+ if key.options[:in]
130
+ validates_inclusion_of(attribute, :within => key.options[:in])
131
+ end
132
+
133
+ if key.options[:not_in]
134
+ validates_exclusion_of(attribute, :within => key.options[:not_in])
135
+ end
136
+
137
+ if key.options[:length]
138
+ length_options = case key.options[:length]
139
+ when Integer
140
+ {:minimum => 0, :maximum => key.options[:length]}
141
+ when Range
142
+ {:within => key.options[:length]}
143
+ when Hash
144
+ key.options[:length]
145
+ end
146
+ validates_length_of(attribute, length_options)
147
+ end
148
+ end
149
+ end
150
+
151
+ module InstanceMethods
152
+ def initialize(attrs={}, from_database=false)
153
+ default_id_value(attrs)
154
+
155
+ if from_database
156
+ @new = false
157
+ self.attributes = attrs
158
+ else
159
+ @new = true
160
+ assign(attrs)
161
+ end
162
+
163
+ assign_type
164
+ end
165
+
166
+ def persisted?
167
+ !new? && !destroyed?
168
+ end
169
+
170
+ def attributes=(attrs)
171
+ return if attrs.blank?
172
+
173
+ attrs.each_pair do |name, value|
174
+ writer_method = "#{name}="
175
+
176
+ if respond_to?(writer_method)
177
+ self.send(writer_method, value)
178
+ else
179
+ self[name.to_s] = value
180
+ end
181
+ end
182
+ end
183
+
184
+ def attributes
185
+ attrs = HashWithIndifferentAccess.new
186
+
187
+ keys.each_pair do |name, key|
188
+ value = key.set(self[key.name])
189
+ attrs[name] = value
190
+ end
191
+
192
+ embedded_associations.each do |association|
193
+ if documents = instance_variable_get(association.ivar)
194
+ if association.one?
195
+ attrs[association.name] = documents.to_mongo
196
+ else
197
+ attrs[association.name] = documents.map { |document| document.to_mongo }
198
+ end
199
+ end
200
+ end
201
+
202
+ attrs
203
+ end
204
+ alias :to_mongo :attributes
205
+
206
+ def assign(attrs={})
207
+ self.attributes = attrs
208
+ end
209
+
210
+ def update_attributes(attrs={})
211
+ assign(attrs)
212
+ save
213
+ end
214
+
215
+ def update_attributes!(attrs={})
216
+ assign(attrs)
217
+ save!
218
+ end
219
+
220
+ def id
221
+ _id
222
+ end
223
+
224
+ def id=(value)
225
+ if self.class.using_object_id?
226
+ value = ObjectId.to_mongo(value)
227
+ end
228
+
229
+ self[:_id] = value
230
+ end
231
+
232
+ def [](name)
233
+ read_key(name)
234
+ end
235
+
236
+ def []=(name, value)
237
+ ensure_key_exists(name)
238
+ write_key(name, value)
239
+ end
240
+
241
+ def keys
242
+ self.class.keys
243
+ end
244
+
245
+ def key_names
246
+ keys.keys
247
+ end
248
+
249
+ def non_embedded_keys
250
+ keys.values.select { |key| !key.embeddable? }
251
+ end
252
+
253
+ def embedded_keys
254
+ keys.values.select { |key| key.embeddable? }
255
+ end
256
+
257
+ private
258
+ def default_id_value(attrs)
259
+ unless attrs.nil?
260
+ provided_keys = attrs.keys.map { |k| k.to_s }
261
+ unless provided_keys.include?('_id') || provided_keys.include?('id')
262
+ write_key :_id, BSON::ObjectID.new
263
+ end
264
+ end
265
+ end
266
+
267
+ def assign_type
268
+ self._type = self.class.name if respond_to?(:_type=)
269
+ end
270
+
271
+ def ensure_key_exists(name)
272
+ self.class.key(name) unless respond_to?("#{name}=")
273
+ end
274
+
275
+ def set_parent_document(key, value)
276
+ if key.embeddable? && value.is_a?(key.type)
277
+ value._parent_document = self
278
+ end
279
+ end
280
+
281
+ def read_key(name)
282
+ if key = keys[name]
283
+ var_name = "@#{name}"
284
+ value = key.get(instance_variable_get(var_name))
285
+ set_parent_document(key, value)
286
+ instance_variable_set(var_name, value)
287
+ else
288
+ raise KeyNotFound, "Could not find key: #{name.inspect}"
289
+ end
290
+ end
291
+
292
+ def read_key_before_typecast(name)
293
+ instance_variable_get("@#{name}_before_typecast")
294
+ end
295
+
296
+ def write_key(name, value)
297
+ key = keys[name]
298
+
299
+ set_parent_document(key, value)
300
+ instance_variable_set "@#{name}_before_typecast", value
301
+ instance_variable_set "@#{name}", key.set(value)
302
+ end
303
+ end
304
+
305
+ class Key
306
+ attr_accessor :name, :type, :options, :default_value
307
+
308
+ def initialize(*args)
309
+ options = args.extract_options!
310
+ @name, @type = args.shift.to_s, args.shift
311
+ self.options = (options || {}).symbolize_keys
312
+ self.default_value = self.options.delete(:default)
313
+ end
314
+
315
+ def ==(other)
316
+ @name == other.name && @type == other.type
317
+ end
318
+
319
+ def embeddable?
320
+ type.respond_to?(:embeddable?) && type.embeddable? ? true : false
321
+ end
322
+
323
+ def number?
324
+ [Integer, Float].include?(type)
325
+ end
326
+
327
+ def get(value)
328
+ if value.nil? && !default_value.nil?
329
+ if default_value.respond_to?(:call)
330
+ return default_value.call
331
+ else
332
+ return default_value
333
+ end
334
+ end
335
+
336
+ type.from_mongo(value)
337
+ end
338
+
339
+ def set(value)
340
+ type.to_mongo(value)
341
+ end
342
+ end
343
+ end
344
+ end
345
+ end