mongodb 0.0.13 → 2.0.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/Rakefile CHANGED
@@ -1,11 +1,10 @@
1
1
  require 'rake_ext'
2
2
 
3
- project(
3
+ project \
4
4
  name: "mongodb",
5
- # version: '0.1.0',
5
+ version: '2.0.0',
6
6
  gem: true,
7
7
  summary: "Persistence for any Ruby Object & Driver enhancements for MongoDB.",
8
8
 
9
9
  author: "Alexey Petrushin",
10
- homepage: "http://alexeypetrushin.github.com/mongodb"
11
- )
10
+ homepage: "http://alexeypetrushin.github.com/mongodb"
@@ -12,7 +12,6 @@ class Mongo::NotFound < Mongo::Error; end
12
12
  dynamic_finders
13
13
  ).each{|f| require "mongo/driver/#{f}"}
14
14
 
15
- # defaults
16
15
  Mongo.class_eval do
17
16
  class << self
18
17
  def defaults; @defaults ||= {} end
@@ -29,7 +28,6 @@ Mongo.class_eval do
29
28
  end
30
29
  end
31
30
  end
32
- Mongo.defaults[:convert_id_to_string] = true
33
31
 
34
32
  Mongo::Connection.send :include, Mongo::ConnectionExt
35
33
 
@@ -42,4 +40,6 @@ Mongo::Collection.class_eval do
42
40
  alias_method "#{method}_without_ext", method
43
41
  alias_method method, "#{method}_with_ext"
44
42
  end
45
- end
43
+ end
44
+
45
+ Mongo.defaults[:convert_id_to_string] = true
@@ -2,9 +2,8 @@ require 'set'
2
2
  require 'date'
3
3
 
4
4
  module Mongo::CollectionExt
5
- #
6
- # CRUD
7
- #
5
+ # CRUD.
6
+
8
7
  def save_with_ext doc, options = {}
9
8
  save_without_ext doc, reverse_merge_defaults(options, :safe)
10
9
  end
@@ -12,7 +11,7 @@ module Mongo::CollectionExt
12
11
  def insert_with_ext args, options = {}
13
12
  result = insert_without_ext args, reverse_merge_defaults(options, :safe)
14
13
 
15
- # for some strange reason MongoDB Ruby driver
14
+ # For some strange reason MongoDB Ruby driver
16
15
  # uses Strings for all keys but _id.
17
16
  # It's inconvinient, fixing it.
18
17
  if Mongo.defaults[:convert_id_to_string]
@@ -20,7 +19,7 @@ module Mongo::CollectionExt
20
19
  list.each{|h| h['_id'] = h.delete :_id}
21
20
  end
22
21
 
23
- # fix for mongodriver, it will return single result if we supply [doc] as args
22
+ # Fix for mongodriver, it will return single result if we supply [doc] as args.
24
23
  (args.is_a?(Array) and !result.is_a?(Array)) ? [result] : result
25
24
  end
26
25
 
@@ -43,7 +42,7 @@ module Mongo::CollectionExt
43
42
  remove_without_ext selector, reverse_merge_defaults(options, :safe, :multi)
44
43
  end
45
44
 
46
- def destroy *args
45
+ def delete *args
47
46
  remove *args
48
47
  end
49
48
 
@@ -51,9 +50,8 @@ module Mongo::CollectionExt
51
50
  insert *args
52
51
  end
53
52
 
54
- #
55
- # Querying
56
- #
53
+ # Querying.
54
+
57
55
  def first selector = {}, options = {}
58
56
  selector = convert_underscore_to_dollar_in_selector selector if selector.is_a? Hash
59
57
  find_one selector, options
@@ -114,17 +112,7 @@ module Mongo::CollectionExt
114
112
  h
115
113
  end
116
114
 
117
- # # symbolizing hashes
118
- # def symbolize_doc doc
119
- # return doc unless Mongo.defaults[:symbolize]
120
- #
121
- # Mongo::CollectionExt.convert_doc doc do |k, v, result|
122
- # k = k.to_sym if k.is_a? String
123
- # result[k] = v
124
- # end
125
- # end
126
-
127
- # replaces :_lt to :$lt in query
115
+ # Replaces :_lt to :$lt in query.
128
116
  def convert_underscore_to_dollar_in_selector selector
129
117
  return selector unless Mongo.defaults[:convert_underscore_to_dollar]
130
118
 
@@ -134,7 +122,7 @@ module Mongo::CollectionExt
134
122
  end
135
123
  end
136
124
 
137
- # replaces :_set to :$set in query
125
+ # Replaces :_set to :$set in query.
138
126
  def convert_underscore_to_dollar_in_update update
139
127
  return update unless Mongo.defaults[:convert_underscore_to_dollar]
140
128
 
@@ -144,7 +132,7 @@ module Mongo::CollectionExt
144
132
  end
145
133
  end
146
134
 
147
- # walks on hash and creates another (also works with nested & arrays)
135
+ # Walks on hash and creates another (also works with nested & arrays).
148
136
  def self.convert_doc doc, &block
149
137
  if doc.is_a? Hash
150
138
  result = {}
@@ -1,8 +1,6 @@
1
1
  module Mongo::DynamicFinders
2
2
  protected
3
- #
4
- # first_by_field, all_by_field, each_by_field, first_by_field
5
- #
3
+ # Dynamic finders, like `first_by_field`, `all_by_field`, `each_by_field`, `first_by_field`.
6
4
  def method_missing clause, *args, &block
7
5
  if clause =~ /^([a-z]_by_[a-z_])|(by_[a-z_])/
8
6
  clause = clause.to_s
@@ -1,19 +1,5 @@
1
1
  require 'mongo/driver'
2
2
 
3
- %w(
4
- support
5
- object
6
- object_helper
7
- ).each{|f| require "mongo/object/#{f}"}
8
-
9
- Mongo.defaults[:callbacks] = true
10
-
11
- # collection
12
- Mongo::Collection.class_eval do
13
- include Mongo::ObjectHelper
14
-
15
- %w(create update save destroy).each do |method|
16
- alias_method "#{method}_without_object", method
17
- alias_method method, "#{method}_with_object"
18
- end
3
+ Mongo.class_eval do
4
+ autoload :Object, 'mongo/object/load'
19
5
  end
@@ -1,7 +1,6 @@
1
- module Mongo::ObjectHelper
2
- #
3
- # CRUD
4
- #
1
+ module Mongo::CollectionHelper
2
+ # CRUD.
3
+
5
4
  def create_with_object doc, options = {}
6
5
  if doc.is_a? ::Mongo::Object
7
6
  doc.create_object self, options
@@ -28,36 +27,34 @@ module Mongo::ObjectHelper
28
27
  end
29
28
  end
30
29
 
31
- def destroy_with_object *args
30
+ def delete_with_object *args
32
31
  if args.first.is_a? ::Mongo::Object
33
32
  doc, options = args
34
33
  options ||= {}
35
- doc.destroy_object self, options
34
+ doc.delete_object self, options
36
35
  else
37
- destroy_without_object *args
36
+ delete_without_object *args
38
37
  end
39
38
  end
40
39
 
41
40
  def create! *args
42
- create(*args) || raise(Mongo::Error, "can't create #{doc.inspect}!")
41
+ create(*args) || raise(Mongo::Error, "can't create #{args.inspect}!")
43
42
  end
44
43
 
45
44
  def update! *args
46
- update(*args) || raise(Mongo::Error, "can't update #{doc.inspect}!")
45
+ update(*args) || raise(Mongo::Error, "can't update #{args.inspect}!")
47
46
  end
48
47
 
49
48
  def save! *args
50
- save(*args) || raise(Mongo::Error, "can't save #{doc.inspect}!")
49
+ save(*args) || raise(Mongo::Error, "can't save #{args.inspect}!")
51
50
  end
52
51
 
53
- def destroy! *args
54
- destroy(*args) || raise(Mongo::Error, "can't destroy #{doc.inspect}!")
52
+ def delete! *args
53
+ delete(*args) || raise(Mongo::Error, "can't delete #{args.inspect}!")
55
54
  end
56
55
 
56
+ # Querying.
57
57
 
58
- #
59
- # Querying
60
- #
61
58
  def first selector = {}, options = {}, &block
62
59
  options = options.clone
63
60
  if options.delete(:object) == false
@@ -0,0 +1,22 @@
1
+ require 'mongo/object/support'
2
+ require 'mongo/object/object'
3
+ require 'mongo/object/collection_helper'
4
+
5
+ Mongo::Collection.class_eval do
6
+ include Mongo::CollectionHelper
7
+
8
+ %w(create update save delete).each do |method|
9
+ alias_method "#{method}_without_object", method
10
+ alias_method method, "#{method}_with_object"
11
+ end
12
+ end
13
+
14
+ # By default MongoDB automatically generates BSON::ObjectId,
15
+ # it has smaller size than string, but usually strings are more convinient to use.
16
+ # This options changes this behaviour and allows to define `generate_id` method
17
+ # on model and use it to generate ids.
18
+ Mongo.defaults[:generate_id] = false
19
+
20
+ # Size of autogenerated random string id in default `generate_id` method,
21
+ # (used only if :generate_id option if enabled).
22
+ Mongo.defaults[:random_string_id_size] = 6
@@ -1,56 +1,30 @@
1
1
  module Mongo::Object
2
2
  attr_accessor :_id, :_parent
3
3
 
4
- def valid? options = {}
5
- errors.clear
6
- run_validations options
7
- end
8
-
9
- def run_validations options = {}
10
- options = ::Mongo::Object.parse_options options
11
- begin
12
- return false if options[:callbacks] and !::Mongo::Object.run_before_callbacks(self, :validate)
13
-
14
- child_options = options.merge internal: true
15
- result = [
16
- (respond_to?(:run_model_validations) ? run_model_validations : true),
17
- child_objects.all?{|group| group.all?{|obj| obj.valid?(child_options)}},
18
- errors.empty?
19
- ].all?
4
+ def _id?; !!_id end
5
+ def new?; !_id end
6
+ alias_method :new_record?, :new?
20
7
 
21
- ::Mongo::Object.run_after_callbacks(self, :validate) if options[:callbacks]
22
-
23
- result
24
- ensure
25
- clear_child_objects_cache unless options[:internal]
26
- end
27
- end
8
+ def create_object collection, options
9
+ doc = to_mongo
28
10
 
29
- def errors
30
- @_errors ||= Hash.new([])
31
- end
11
+ # Generating custom id if option enabled.
12
+ doc['_id'] = generate_id if Mongo.defaults[:generate_id]
32
13
 
33
- def create_object collection, options
34
- with_object_callbacks :create, options do |options|
35
- doc = ::Mongo::Object.to_mongo self
36
- collection.create(doc, options)
37
- self._id = doc['_id']
38
- end
14
+ id = collection.create doc, options
15
+ self._id = id
16
+ id
39
17
  end
40
18
 
41
19
  def update_object collection, options
42
- with_object_callbacks :update, options do |options|
43
- id = _id || "can't update object without _id (#{self})!"
44
- doc = ::Mongo::Object.to_mongo self
45
- collection.update({_id: id}, doc, options)
46
- end
20
+ id = _id || "can't update object without _id (#{self})!"
21
+ doc = to_mongo
22
+ collection.update({_id: id}, doc, options)
47
23
  end
48
24
 
49
- def destroy_object collection, options
50
- with_object_callbacks :destroy, options do |options|
51
- id = _id || "can't destroy object without _id (#{self})!"
52
- collection.destroy({_id: id}, options)
53
- end
25
+ def delete_object collection, options
26
+ id = _id || "can't delete object without _id (#{self})!"
27
+ collection.delete({_id: id}, options)
54
28
  end
55
29
 
56
30
  def save_object collection, options
@@ -61,124 +35,53 @@ module Mongo::Object
61
35
  end
62
36
  end
63
37
 
64
- # need this to allow change it in specs
65
- # RSpec adds @mock_proxy, and we need to skip it
66
- SKIP_IV_REGEXP = /^@_/
67
-
68
- class << self
69
- def parse_options options
70
- options = options.clone
71
- options[:validate] = true unless options.include?(:validate)
72
- options[:callbacks] = Mongo.defaults[:callbacks] unless options.include?(:callbacks)
73
- return options
74
- end
75
-
76
- def parse_mongo_options options
77
- options = options.clone
78
- options.delete :validate
79
- options.delete :callbacks
80
- options
81
- end
38
+ # Skipping variables starting with @_, usually they
39
+ # have specific meaning and used for things like cache.
40
+ def persistent_instance_variable_names *args
41
+ instance_variables(*args).select{|n| n !~ /^@_/}
42
+ end
82
43
 
83
- def each_instance_variable obj, &block
84
- instance_variables(obj).each do |iv_name|
85
- block.call iv_name, obj.instance_variable_get(iv_name)
44
+ # Convert object to document (with nested documents & arrays).
45
+ def to_mongo
46
+ {}.tap do |h|
47
+ # Copy instance variables.
48
+ persistent_instance_variable_names.each do |iv_name|
49
+ k = iv_name.to_s[1..-1]
50
+ v = instance_variable_get iv_name
51
+ h[k] = v.to_mongo
86
52
  end
87
- end
88
53
 
89
- def instance_variables obj
90
- # skipping variables starting with @_, usually they
91
- # have specific meaning and used for example for cache
92
- obj.instance_variables.select{|n| n !~ SKIP_IV_REGEXP}
54
+ # Adding _id & _class.
55
+ h['_id'] = _id if _id
56
+ h['_class'] = self.class.name || \
57
+ raise("unknow class name for model #{h.inspect}!")
93
58
  end
59
+ end
60
+ alias_method :to_hash, :to_mongo
94
61
 
95
- # converts object to document (also works with nested & arrays)
96
- def to_mongo obj
97
- return obj.to_mongo if obj.respond_to? :to_mongo
98
-
99
- if obj.is_a? Hash
100
- doc = {}
101
- obj.each do |k, v|
102
- doc[k] = to_mongo v
103
- end
104
- doc
105
- elsif obj.is_a? Array
106
- obj.collect{|v| to_mongo v}
107
- elsif obj.is_a? Mongo::Object
108
- doc = {}
109
-
110
- # copying instance variables
111
- each_instance_variable obj do |iv_name, v|
112
- k = iv_name.to_s[1..-1]
113
- doc[k] = to_mongo v
114
- end
115
-
116
- # adding _id & _class
117
- id = instance_variable_get('@_id')
118
- doc['_id'] = id if id
119
- doc['_class'] = obj.class.name
120
-
121
- doc
122
- else # simple type
123
- obj
124
- end
125
- end
62
+ # Override it to generate Your custom ids.
63
+ def generate_id
64
+ generate_random_string_id
65
+ end
126
66
 
127
- def convert obj, method, options = {}
128
- if obj.is_a? Hash
129
- r = {}
130
- obj.each do |k, v|
131
- r[k] = convert v, method, options
132
- end
133
- r
134
- elsif obj.is_a? Array
135
- obj.collect{|v| convert v, method, options}
136
- elsif obj.is_a? Mongo::Object
137
- obj.send method, options
138
- else # simple type
139
- obj
140
- end
141
- end
67
+ def inspect
68
+ h = to_hash
69
+ h.delete '_class'
70
+ "#<#{self.class}:#{h.inspect}>"
71
+ end
72
+ alias_method :to_s, :inspect
142
73
 
143
- def each_object obj, &block
144
- if obj.is_a? Hash
145
- block.call obj if obj.is_a? ::Mongo::Object
146
- obj.each{|k, v| each_object v, &block}
147
- elsif obj.is_a? Array
148
- block.call obj if obj.is_a? ::Mongo::Object
149
- obj.each{|v| each_object v, &block}
150
- elsif obj.is_a? ::Mongo::Object
151
- block.call obj
152
- each_instance_variable obj do |iv_name, v|
153
- each_object v, &block
154
- end
155
- end
156
- nil
74
+ protected
75
+ ID_SYMBOLS = ('a'..'z').to_a + ('A'..'Z').to_a + ('0'..'9').to_a
76
+ def generate_random_string_id
77
+ id, size = "", Mongo.defaults[:random_string_id_size]
78
+ size.times{id << ID_SYMBOLS[rand(ID_SYMBOLS.size)]}
79
+ id
157
80
  end
158
81
 
82
+ class << self
159
83
  def build doc
160
- return unless doc
161
- obj = _build doc, nil
162
- obj.send :update_original_children! if obj.is_a? ::Mongo::Object
163
- obj
164
- end
165
-
166
- def run_before_callbacks obj, method
167
- if obj.respond_to?(:run_before_callbacks)
168
- obj.run_before_callbacks(:save, method: :save) if method == :update or method == :create
169
- obj.run_before_callbacks(method, method: method)
170
- else
171
- true
172
- end
173
- end
174
-
175
- def run_after_callbacks obj, method
176
- if obj.respond_to?(:run_after_callbacks)
177
- obj.run_after_callbacks(method, method: method)
178
- obj.run_after_callbacks(:save, method: :save) if method == :update or method == :create
179
- else
180
- true
181
- end
84
+ doc && _build(doc, nil)
182
85
  end
183
86
 
184
87
  protected
@@ -187,30 +90,31 @@ module Mongo::Object
187
90
  if class_name = doc[:_class] || doc['_class']
188
91
  klass = constantize class_name
189
92
 
93
+ # Unmarshalling object.
190
94
  if klass.respond_to? :from_mongo
191
95
  obj = klass.from_mongo doc
192
96
  else
193
97
  obj = klass.new
194
98
  parent ||= obj
195
99
  doc.each do |k, v|
196
- next if k.to_sym == :_class
197
-
198
100
  v = _build v, parent
199
101
  obj.instance_variable_set "@#{k}", v
200
102
  end
201
103
  obj
202
104
  end
203
105
  obj._parent = parent if parent
204
- run_after_callbacks obj, :build
106
+
107
+ # Firing special after build callback if defined.
108
+ obj.run_after_callbacks :build, :build if obj.respond_to? :run_after_callbacks
109
+
205
110
  obj
206
111
  else
207
- hash = {}
208
- doc.each{|k, v| hash[k] = _build v, parent}
209
- hash
112
+ {}.tap{|h| doc.each{|k, v| h[k] = _build v, parent}}
210
113
  end
211
114
  elsif doc.is_a? Array
212
115
  doc.collect{|v| _build v, parent}
213
116
  else
117
+ # Simple type.
214
118
  doc
215
119
  end
216
120
  end
@@ -224,102 +128,4 @@ module Mongo::Object
224
128
  klass
225
129
  end
226
130
  end
227
-
228
- protected
229
- def original_children; @_original_children ||= [] end
230
-
231
- def update_original_children!
232
- return unless ::Mongo.defaults[:callbacks]
233
-
234
- original_children.clear
235
- ::Mongo::Object.each_object self do |obj|
236
- original_children << obj unless obj.equal?(self)
237
- end
238
- end
239
-
240
- def clear_child_objects_cache
241
- if instance_variable_get(:@_child_objects_cache)
242
- child_objects.each do |group|
243
- group.each{|obj| obj.clear_child_objects_cache}
244
- end
245
- remove_instance_variable :@_child_objects_cache
246
- end
247
- end
248
-
249
- def child_objects
250
- unless @_child_objects_cache
251
- created_children, updated_children, destroyed_children = [], [], []
252
-
253
- original_children_ids = Set.new; original_children.each{|obj| original_children_ids << obj.object_id}
254
- ::Mongo::Object.each_object self do |obj|
255
- (original_children_ids.include?(obj.object_id) ? updated_children : created_children) << obj unless obj.equal?(self)
256
- end
257
-
258
- children_ids = Set.new; ::Mongo::Object.each_object self do |obj|
259
- children_ids << obj.object_id unless obj.equal?(self)
260
- end
261
- destroyed_children = original_children.select{|obj| !children_ids.include?(obj.object_id)}
262
-
263
- @_child_objects_cache = [created_children, updated_children, destroyed_children]
264
- end
265
- @_child_objects_cache
266
- end
267
-
268
- def with_object_callbacks method, options, &block
269
- options = ::Mongo::Object.parse_options options
270
-
271
- # validation
272
- return false if options[:validate] and !valid?(options.merge(internal: true))
273
-
274
- # before callbacks
275
- return false if options[:callbacks] and !run_all_callbacks(:before, method)
276
-
277
- # saving
278
- block.call ::Mongo::Object.parse_mongo_options(options)
279
- update_original_children!
280
-
281
- # after callbacks
282
- run_all_callbacks :after, method if options[:callbacks]
283
-
284
- true
285
- ensure
286
- clear_child_objects_cache
287
- end
288
-
289
- def run_all_callbacks type, method
290
- result = if type == :before
291
- ::Mongo::Object.run_before_callbacks self, method
292
- else
293
- true
294
- end
295
-
296
- result &= if method == :create
297
- child_objects.all? do |group|
298
- group.all? do |obj|
299
- obj.run_all_callbacks type, method
300
- end
301
- end
302
- elsif method == :update
303
- created_children, updated_children, destroyed_children = child_objects
304
- created_children.all?{|obj| obj.run_all_callbacks type, :create} and
305
- updated_children.all?{|obj| obj.run_all_callbacks type, :update} and
306
- destroyed_children.all?{|obj| obj.run_all_callbacks type, :destroy}
307
- elsif method == :destroy
308
- child_objects.all? do |group|
309
- group.all? do |obj|
310
- obj.run_all_callbacks type, method
311
- end
312
- end
313
- else
314
- raise_error "unknown callback method (#{method})!"
315
- end
316
-
317
- if type == :after
318
- ::Mongo::Object.run_after_callbacks self, method
319
- else
320
- true
321
- end
322
-
323
- result
324
- end
325
131
  end