mongodb 0.0.13 → 2.0.0

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