mongo_persist 0.0.2 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -11,8 +11,10 @@ begin
11
11
  gem.homepage = "http://github.com/mharris717/mongo_persist"
12
12
  gem.authors = ["Mike Harris"]
13
13
  gem.add_development_dependency "rspec"
14
+ gem.add_development_dependency 'rr'
14
15
  gem.add_dependency 'fattr'
15
16
  gem.add_dependency 'activesupport'
17
+ gem.add_dependency 'mharris_ext'
16
18
  # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
17
19
  end
18
20
  Jeweler::GemcutterTasks.new
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.2
1
+ 0.1.0
data/examples/only.rb ADDED
@@ -0,0 +1,57 @@
1
+ require 'rubygems'
2
+ require 'mongo'
3
+ require 'mongo_persist'
4
+
5
+ def db
6
+ Mongo::Connection.new.db('test-db')
7
+ end
8
+
9
+ class Order
10
+ include MongoPersist
11
+ attr_accessor :po_number
12
+ fattr(:order_products) { [] }
13
+ def products
14
+ order_products.map { |x| x.product }
15
+ end
16
+ end
17
+
18
+ class OrderProduct
19
+ include MongoPersist
20
+ attr_accessor :unit_price, :quantity, :product
21
+
22
+ # Store a reference to objects for this attribute, not the entire object.
23
+ mongo_reference_attributes ['product']
24
+ end
25
+
26
+ class Product
27
+ include MongoPersist
28
+ attr_accessor :name
29
+ end
30
+
31
+ products = [Product.new(:name => 'Leather Couch'),Product.new(:name => 'Maroon Chair')].each { |x| x.mongo.save! }
32
+
33
+ orders = []
34
+ orders << Order.new(:po_number => 1234,
35
+ :order_products => [OrderProduct.new(:unit_price => 1000, :quantity => 1, :product => products[0])]).mongo.save!
36
+ orders << Order.new(:po_number => 1235,
37
+ :order_products => [OrderProduct.new(:unit_price => 200, :quantity => 2, :product => products[1])]).mongo.save!
38
+
39
+ # objects are saved to MongoDB as JSON objects
40
+
41
+ # get all order objects back from Mongo
42
+ # you get back the ruby objects you put in, not raw JSON objects
43
+ Order.collection.find_objects
44
+
45
+ # Since on OrderProduct, the product attribute was marked as a reference attribute,
46
+ # the product is stored in MongoDB only as a reference to the product obj
47
+ #
48
+ # When you read the Order/OrderProduct back out, MongoPersist takes care of
49
+ # fetching the Product object again. You don't have to do anything.
50
+ Order.collection.find_one_object.products.first # An object of class Product
51
+ Order.collection.find_one_object.products.first.name # Leather Couch
52
+
53
+ # Because the product is stored as a reference, if you update that product
54
+ # elsewhere and save to Mongo, later reads of Orders with that product will be correctly updated
55
+ products[0].name = 'White Leather Couch'
56
+ products[0].mongo.save!
57
+ Order.collection.find_one_object.products.first.name # White Leather Couch
data/lib/mongo_persist.rb CHANGED
@@ -1,137 +1,8 @@
1
1
  require 'rubygems'
2
2
  require 'mongo'
3
- require 'activesupport'
3
+ require 'active_support'
4
4
  require 'fattr'
5
- require File.dirname(__FILE__) + "/mongo_persist/util"
5
+ %w(util core_ext array_ext hash_ext base mongo_ext).each { |x| require File.dirname(__FILE__) + "/mongo_persist/#{x}" }
6
6
  require 'andand'
7
7
 
8
- class Object
9
- def safe_to_mongo_hash
10
- sos(:to_mongo_hash)
11
- end
12
- def safe_to_mongo_object
13
- sos(:to_mongo_object)
14
- end
15
- end
16
8
 
17
- class Array
18
- def to_mongo_hash
19
- map { |x| x.safe_to_mongo_hash }
20
- end
21
- def to_mongo_object
22
- map { |x| x.safe_to_mongo_object }
23
- end
24
- def to_mongo_ref_hash
25
- map { |x| x.to_mongo_ref_hash }
26
- end
27
- end
28
-
29
- class Hash
30
- def get_mongo_id
31
- ['_id','mongo_id'].each { |x| return self[x] if self[x] }
32
- nil
33
- end
34
- def naked_reference?
35
- (keys - ['_id','_mongo_class','mongo_id']).empty? && !!get_mongo_id
36
- end
37
- def mongo_class
38
- self['_mongo_class'] ? eval(self['_mongo_class']) : nil
39
- end
40
- def to_mongo_hash_for_obj
41
- h = reject { |k,v| k == '_mongo_class' }
42
- h['mongo_id'] = h['_id'] if h['_id']
43
- h.reject { |k,v| k == '_id' }
44
- end
45
- def to_mongo_object
46
- return map_value { |v| v.safe_to_mongo_object } unless mongo_class
47
- if naked_reference?
48
- mongo_class.collection.find_one_object('_id' => get_mongo_id)
49
- else
50
- mongo_class.from_mongo_hash(to_mongo_hash_for_obj)
51
- end
52
- end
53
- def to_mongo_hash
54
- res = {}
55
- each { |k,v| res[k.safe_to_mongo_hash] = v.safe_to_mongo_hash }
56
- res
57
- end
58
- end
59
-
60
- class MongoWrapper
61
- attr_accessor :obj
62
- include FromHash
63
- def save!
64
- if obj.mongo_id
65
- obj.klass.collection.update({'_id' => obj.mongo_id},obj.to_mongo_hash)
66
- else
67
- obj.mongo_id = obj.class.collection.save(obj.to_mongo_hash)
68
- end
69
- obj
70
- end
71
- end
72
-
73
- module MongoPersist
74
- attr_accessor :mongo_id
75
- #can be overriden by class. If not, assumes that all instance variables should be saved.
76
- def mongo_attributes
77
- instance_variables.map { |x| x[1..-1] } - ['mongo']
78
- end
79
- def mongo_child_attributes
80
- mongo_attributes - self.class.mongo_reference_attributes
81
- end
82
- def to_mongo_ref_hash
83
- {'_mongo_class' => klass.to_s, '_id' => mongo_id}
84
- end
85
- def to_mongo_hash
86
- res = mongo_child_attributes.inject({}) { |h,attr| h.merge(attr => send(attr).safe_to_mongo_hash) }.merge("_mongo_class" => self.class.to_s)
87
- klass.mongo_reference_attributes.each do |attr|
88
- val = send(attr)
89
- res[attr] = val.to_mongo_ref_hash if val
90
- end
91
- res
92
- end
93
- def from_mongo_hash(h)
94
- h = h.map_value { |v| v.safe_to_mongo_object }
95
- from_hash(h)
96
- end
97
- fattr(:mongo) { MongoWrapper.new(:obj => self) }
98
-
99
- module ClassMethods
100
- dsl_method(:mongo_reference_attributes) { [] }
101
- def default_collection_name
102
- to_s.downcase.pluralize
103
- end
104
- fattr(:collection) { db.collection(default_collection_name) }
105
- def from_mongo_hash(h)
106
- new.tap { |x| x.from_mongo_hash(h) }
107
- end
108
- def mongo_connection(ops)
109
- ops.each { |k,v| send("#{k}=",v) }
110
- end
111
- end
112
- def self.included(mod)
113
- super(mod)
114
- mod.send(:include,FromHash)
115
- mod.send(:extend,ClassMethods)
116
- end
117
- end
118
-
119
- class ObjCursor
120
- attr_accessor :cursor
121
- include FromHash
122
- def each
123
- cursor.each { |x| yield(x.to_mongo_object) }
124
- end
125
- def count
126
- cursor.count
127
- end
128
- end
129
-
130
- class Mongo::Collection
131
- def find_objects(*args)
132
- ObjCursor.new(:cursor => find(*args))
133
- end
134
- def find_one_object(*args)
135
- find_one(*args).to_mongo_object
136
- end
137
- end
@@ -0,0 +1,14 @@
1
+ class Array
2
+ def to_mongo_hash
3
+ map { |x| x.safe_to_mongo_hash }
4
+ end
5
+ def to_mongo_object
6
+ map { |x| x.safe_to_mongo_object }
7
+ end
8
+ def to_mongo_ref_hash
9
+ map { |x| x.to_mongo_ref_hash }
10
+ end
11
+ def can_mongo_convert?
12
+ all? { |x| x.can_mongo_convert? && x }
13
+ end
14
+ end
@@ -0,0 +1,83 @@
1
+ class MongoWrapper
2
+ attr_accessor :obj
3
+ include FromHash
4
+ def save!
5
+ if obj.mongo_id
6
+ obj.klass.collection.update({'_id' => obj.mongo_id},obj.to_mongo_hash)
7
+ else
8
+ obj.mongo_id = obj.class.collection.save(obj.to_mongo_hash)
9
+ end
10
+ obj
11
+ rescue => exp
12
+ require 'pp'
13
+ pp obj.to_mongo_hash
14
+ raise exp
15
+ end
16
+ end
17
+
18
+ module MongoPersist
19
+ NIL_OBJ = 99999
20
+ attr_accessor :mongo_id
21
+ #can be overriden by class. If not, assumes that all instance variables should be saved.
22
+ def mongo_attributes
23
+ (instance_variables.map { |x| x[1..-1] } - ['mongo','mongo_id']).select { |x| respond_to?(x) }
24
+ end
25
+ def mongo_addl_attributes
26
+ []
27
+ end
28
+ def mongo_child_attributes
29
+ (mongo_attributes - self.class.mongo_reference_attributes + mongo_addl_attributes).uniq
30
+ end
31
+ def to_mongo_ref_hash
32
+ {'_mongo_class' => klass.to_s, '_id' => mongo_id}
33
+ end
34
+ def new_hashx(attr,h,obj)
35
+ if obj.can_mongo_convert?
36
+ h.merge(attr => obj.to_mongo_hash)
37
+ else
38
+ h
39
+ end
40
+ rescue
41
+ return h
42
+ end
43
+ def to_mongo_hash
44
+ res = mongo_child_attributes.inject({}) do |h,attr|
45
+ obj = send(attr)
46
+ raise "#{attr} is nil" unless obj
47
+ new_hashx(attr,h,obj)
48
+ end.merge("_mongo_class" => self.class.to_s)
49
+ klass.mongo_reference_attributes.each do |attr|
50
+ val = send(attr)
51
+ res[attr] = val.to_mongo_ref_hash if val
52
+ end
53
+ res
54
+ end
55
+ def from_mongo_hash(h)
56
+ h = h.map_value { |v| v.safe_to_mongo_object }
57
+ from_hash(h)
58
+ end
59
+ fattr(:mongo) { MongoWrapper.new(:obj => self) }
60
+
61
+ module ClassMethods
62
+ dsl_method(:mongo_reference_attributes) { [] }
63
+ def default_collection_name
64
+ to_s.downcase.pluralize
65
+ end
66
+ fattr(:collection) { db.collection(default_collection_name) }
67
+ def new_with_nil_args
68
+ args = (1..(instance_method(:initialize).arity)).map { |x| nil }
69
+ new(*args)
70
+ end
71
+ def from_mongo_hash(h)
72
+ new_with_nil_args.tap { |x| x.from_mongo_hash(h) }
73
+ end
74
+ def mongo_connection(ops)
75
+ ops.each { |k,v| send("#{k}=",v) }
76
+ end
77
+ end
78
+ def self.included(mod)
79
+ super(mod)
80
+ mod.send(:include,FromHash)
81
+ mod.send(:extend,ClassMethods)
82
+ end
83
+ end
@@ -0,0 +1,57 @@
1
+ class Object
2
+ def safe_to_mongo_hash
3
+ respond_to?(:to_mongo_hash) ? to_mongo_hash : nil
4
+ end
5
+ def safe_to_mongo_object
6
+ to_mongo_object
7
+ end
8
+ def ngil_obj?
9
+ self == MongoPersist::NIL_OBJ
10
+ end
11
+ def can_mongo_convert?
12
+ false
13
+ end
14
+ end
15
+
16
+ module BaseObjects
17
+ def to_mongo_hash
18
+ self
19
+ end
20
+ def to_mongo_object
21
+ self
22
+ end
23
+ def can_mongo_convert?
24
+ true
25
+ end
26
+ end
27
+
28
+ [Numeric,Symbol,String,Mongo::ObjectID,TrueClass,FalseClass].each do |cls|
29
+ cls.send(:include,BaseObjects)
30
+ end
31
+
32
+ class NilClass
33
+ def to_mongo_object
34
+ self
35
+ end
36
+ end
37
+
38
+ class Object
39
+ def to_mongo_key
40
+ self
41
+ end
42
+ def from_mongo_key
43
+ self
44
+ end
45
+ end
46
+
47
+ class Fixnum
48
+ def to_mongo_key
49
+ "#{self}-NUM"
50
+ end
51
+ end
52
+
53
+ class String
54
+ def from_mongo_key
55
+ (self =~ /^(.*)-NUM$/) ? $1.to_i : self
56
+ end
57
+ end
@@ -0,0 +1,34 @@
1
+ module MongoHash
2
+ def get_mongo_id
3
+ ['_id','mongo_id'].each { |x| return self[x] if self[x] }
4
+ nil
5
+ end
6
+ def naked_reference?
7
+ (keys - ['_id','_mongo_class','mongo_id']).empty? && !!get_mongo_id
8
+ end
9
+ def mongo_class
10
+ self['_mongo_class'] ? eval(self['_mongo_class']) : nil
11
+ end
12
+ def to_mongo_hash_for_obj
13
+ h = reject { |k,v| k == '_mongo_class' }
14
+ h['mongo_id'] = h['_id'] if h['_id']
15
+ h.reject { |k,v| k == '_id' }
16
+ end
17
+ def to_mongo_object
18
+ return map_value { |v| v.safe_to_mongo_object }.map_key { |k| k.from_mongo_key } unless mongo_class
19
+ if naked_reference?
20
+ mongo_class.collection.find_one_object('_id' => get_mongo_id)
21
+ else
22
+ mongo_class.from_mongo_hash(to_mongo_hash_for_obj)
23
+ end
24
+ end
25
+ def to_mongo_hash
26
+ res = {}
27
+ each { |k,v| res[k.safe_to_mongo_hash.to_mongo_key] = v.safe_to_mongo_hash }
28
+ res
29
+ end
30
+ end
31
+
32
+ class Hash
33
+ include MongoHash
34
+ end
@@ -0,0 +1,23 @@
1
+ class ObjCursor
2
+ attr_accessor :cursor
3
+ include FromHash
4
+ def each
5
+ cursor.each { |x| yield(x.to_mongo_object) }
6
+ end
7
+ def count
8
+ cursor.count
9
+ end
10
+ end
11
+
12
+ module MongoPersistCollection
13
+ def find_objects(*args)
14
+ ObjCursor.new(:cursor => find(*args))
15
+ end
16
+ def find_one_object(*args)
17
+ find_one(*args).to_mongo_object
18
+ end
19
+ end
20
+
21
+ class Mongo::Collection
22
+ include MongoPersistCollection
23
+ end
@@ -44,6 +44,9 @@ module FromHash
44
44
  end
45
45
  def initialize(ops={})
46
46
  from_hash(ops)
47
+ after_initialize
48
+ end
49
+ def after_initialize
47
50
  end
48
51
  end
49
52
 
@@ -53,4 +56,9 @@ class Hash
53
56
  each { |k,v| res[k] = yield(v) }
54
57
  res
55
58
  end
59
+ def map_key
60
+ res = {}
61
+ each { |k,v| res[yield(k)] = v }
62
+ res
63
+ end
56
64
  end
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{mongo_persist}
8
- s.version = "0.0.2"
8
+ s.version = "0.1.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Mike Harris"]
12
- s.date = %q{2009-11-19}
12
+ s.date = %q{2009-12-17}
13
13
  s.description = %q{Library to add MongoDB Persistance to normal Ruby objects}
14
14
  s.email = %q{mharris717@gmail.com}
15
15
  s.extra_rdoc_files = [
@@ -24,9 +24,15 @@ Gem::Specification.new do |s|
24
24
  "Rakefile",
25
25
  "VERSION",
26
26
  "lib/mongo_persist.rb",
27
+ "lib/mongo_persist/array_ext.rb",
28
+ "lib/mongo_persist/base.rb",
29
+ "lib/mongo_persist/core_ext.rb",
30
+ "lib/mongo_persist/hash_ext.rb",
31
+ "lib/mongo_persist/mongo_ext.rb",
27
32
  "lib/mongo_persist/sandbox.rb",
28
33
  "lib/mongo_persist/util.rb",
29
34
  "mongo_persist.gemspec",
35
+ "spec/mocks.rb",
30
36
  "spec/mongo_persist_spec.rb",
31
37
  "spec/spec_helper.rb"
32
38
  ]
@@ -36,8 +42,10 @@ Gem::Specification.new do |s|
36
42
  s.rubygems_version = %q{1.3.5}
37
43
  s.summary = %q{Library to add MongoDB Persistance to normal Ruby objects}
38
44
  s.test_files = [
39
- "spec/mongo_persist_spec.rb",
40
- "spec/spec_helper.rb"
45
+ "spec/mocks.rb",
46
+ "spec/mongo_persist_spec.rb",
47
+ "spec/spec_helper.rb",
48
+ "examples/only.rb"
41
49
  ]
42
50
 
43
51
  if s.respond_to? :specification_version then
@@ -46,16 +54,22 @@ Gem::Specification.new do |s|
46
54
 
47
55
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
48
56
  s.add_development_dependency(%q<rspec>, [">= 0"])
57
+ s.add_development_dependency(%q<rr>, [">= 0"])
49
58
  s.add_runtime_dependency(%q<fattr>, [">= 0"])
50
59
  s.add_runtime_dependency(%q<activesupport>, [">= 0"])
60
+ s.add_runtime_dependency(%q<mharris_ext>, [">= 0"])
51
61
  else
52
62
  s.add_dependency(%q<rspec>, [">= 0"])
63
+ s.add_dependency(%q<rr>, [">= 0"])
53
64
  s.add_dependency(%q<fattr>, [">= 0"])
54
65
  s.add_dependency(%q<activesupport>, [">= 0"])
66
+ s.add_dependency(%q<mharris_ext>, [">= 0"])
55
67
  end
56
68
  else
57
69
  s.add_dependency(%q<rspec>, [">= 0"])
70
+ s.add_dependency(%q<rr>, [">= 0"])
58
71
  s.add_dependency(%q<fattr>, [">= 0"])
59
72
  s.add_dependency(%q<activesupport>, [">= 0"])
73
+ s.add_dependency(%q<mharris_ext>, [">= 0"])
60
74
  end
61
75
  end
data/spec/mocks.rb ADDED
@@ -0,0 +1,48 @@
1
+ class MockDB
2
+ def collection(name)
3
+ MockCollection.new(:name => name)
4
+ end
5
+ end
6
+
7
+ class MockCursor
8
+ include Enumerable
9
+ attr_accessor :objs
10
+ include FromHash
11
+ def each(&b)
12
+ objs.each(&b)
13
+ end
14
+ def count
15
+ objs.size
16
+ end
17
+ end
18
+
19
+ class MockCollection
20
+ include MongoPersistCollection
21
+ attr_accessor :name
22
+ include FromHash
23
+ fattr(:objs) { {} }
24
+ def remove
25
+ objs!
26
+ end
27
+ def save(doc)
28
+ doc['_id'] = rand(10000000000)
29
+ objs[doc['_id']] = doc
30
+ doc['_id']
31
+ end
32
+ def update(ops,new_doc)
33
+ find_raw(ops).each do |doc|
34
+ objs[doc['_id']] = new_doc.merge('_id' => doc['_id'])
35
+ end
36
+ end
37
+ def find_raw(ops={})
38
+ objs.values.select do |h|
39
+ ops.all? { |k,v| v === h[k.to_s] }
40
+ end
41
+ end
42
+ def find(ops={})
43
+ MockCursor.new(:objs => find_raw(ops))
44
+ end
45
+ def find_one(ops={})
46
+ find_raw(ops).first
47
+ end
48
+ end
@@ -1,7 +1,20 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
 
3
+ require_lib "/code/mongo_scope/lib/mongo_scope"
4
+ require 'mharris_ext'
5
+
6
+ def on_rcr?
7
+ dir = File.expand_path(File.dirname(__FILE__))
8
+ !!(dir =~ /\/mnt\/repos/)#.tap { |x| puts "Dir #{dir} rcr? #{x}" }
9
+ end
10
+
3
11
  def db
4
- Mongo::Connection.new.db('test-db')
12
+ if on_rcr?
13
+ require File.dirname(__FILE__) + "/mocks"
14
+ MockDB.new
15
+ else
16
+ Mongo::Connection.new('98.129.37.34',27017).db('test-db')
17
+ end
5
18
  end
6
19
 
7
20
  class Order
@@ -36,6 +49,17 @@ class Customer
36
49
  attr_accessor :email
37
50
  end
38
51
 
52
+ class Foo
53
+ include MongoPersist
54
+ attr_accessor :bar
55
+ def initialize(b)
56
+ @bar = b
57
+ end
58
+ def self.fgrom_mongo_hash(ops)
59
+ new(nil).from_hash(ops)
60
+ end
61
+ end
62
+ if true
39
63
  # too many assertions per test, too many "this is how things should be before i check the point of this test" assertions
40
64
  describe MongoPersist do
41
65
  before do
@@ -84,6 +108,81 @@ describe MongoPersist do
84
108
  o = Order.new(:po_number => 1, :some_hash => {'1' => Product.new(:name => 'Chair')})
85
109
  o.mongo.save!
86
110
  Order.collection.find_one_object(:po_number => 1).some_hash['1'].name.should == 'Chair'
87
- Order.collection.find_one_object.subtotal.should == 1000
111
+ Order.collection.find_one_object(:po_number => 1234).subtotal.should == 1000
112
+ end
113
+ it 'saving reference hashes' do
114
+ p = Product.new(:name => 'Chair')
115
+ p.mongo.save!
116
+ o = Order.new(:po_number => 1, :some_hash => {'1' => p})
117
+ o.mongo.save!
118
+ Order.collection.find_one_object(:po_number => 1).some_hash['1'].name.should == 'Chair'
119
+ Order.collection.find_one_object(:po_number => 1234).subtotal.should == 1000
120
+ end
121
+ it 'obj with own constructor' do
122
+ Foo.collection.remove
123
+ Foo.new(14).mongo.save!
124
+ Foo.collection.find_one_object.bar.should == 14
125
+ end
126
+ it 'hash with number key' do
127
+ Foo.collection.remove
128
+ f = Foo.new(14)
129
+ f.bar = {1 => 2}
130
+ f.mongo.save!
131
+ Foo.collection.find_one_object.bar.keys.should == [1]
132
+ end
133
+ it 'grouping' do
134
+ if false; coll = db.collection('abc')
135
+ coll.remove
136
+ coll.save('a' => 'a', 'b' => 1)
137
+ coll.save("a" => 'a', 'b' => 3)
138
+ coll.save('a' => 'b', 'b' => 2)
139
+
140
+ # reduce_function = "function (obj, prev) { prev.count += obj.b; }"
141
+ # code = Mongo::Code.new(reduce_function)
142
+ # res = coll.group(['a'], {}, {"count" => 0},code)
143
+
144
+ res = coll.sum_by_raw(:key => 'a', :sum_field => 'b')
145
+
146
+ res.find { |x| x['a'] == 'a'}['count'].should == 4
147
+ res.find { |x| x['a'] == 'b'}['count'].should == 2
148
+
149
+ res = coll.sum_by(:key => 'a', :sum_field => 'b').should == {'a' => 4, 'b' => 2}; end
150
+ end
151
+ end
152
+ end
153
+ describe "n+1" do
154
+ before do
155
+ $proxy = true
156
+ [Order,Product].each { |x| x.collection.remove }
157
+ @products = [Product.new(:name => 'Leather Couch'),Product.new(:name => 'Maroon Chair')].each { |x| x.mongo.save! }
158
+ #@products = (1..5000).map { |x| Product.new(:name => x.to_s) }
159
+ @products.each { |x| x.mongo.save! }
160
+ @order_products = @products.map { |x| OrderProduct.new(:product => x) }
161
+ @order = Order.new(:order_products => @order_products).mongo.save!
162
+ end
163
+ it 'loading products should only do 1 lookup' do
164
+ mock.proxy(Product.collection).find()
165
+ Order.collection.find_one_object.products.map { |x| x.name }.should == @products.map { |x| x.name }
166
+ end
167
+ it 'speed test' do
168
+ tm('with proxy') do
169
+ Order.collection.find_one_object.products.each { |x| x.name }
170
+ end
171
+ tm('without proxy') do
172
+ $proxy = false
173
+ Order.collection.find_one_object.products.each { |x| x.name }
174
+ end
88
175
  end
89
176
  end
177
+
178
+ class Mongo::Collection
179
+ def sum_by_raw(ops)
180
+ reduce_function = "function (obj, prev) { prev.count += (obj.#{ops[:sum_field]} ? obj.#{ops[:sum_field]} : 0); }"
181
+ code = Mongo::Code.new(reduce_function)
182
+ group([ops[:key]].flatten, {'a' => 'a'}, {"count" => 0},code)
183
+ end
184
+ def sum_by(ops)
185
+ sum_by_raw(ops).inject({}) { |h,a| k = ops[:key]; h.merge(a[k] => a['count'])}
186
+ end
187
+ end
188
+
data/spec/spec_helper.rb CHANGED
@@ -5,5 +5,15 @@ require 'spec'
5
5
  require 'spec/autorun'
6
6
 
7
7
  Spec::Runner.configure do |config|
8
-
8
+ config.mock_with :rr
9
9
  end
10
+
11
+ def require_lib(path,name=nil)
12
+ name ||= path.split("/")[-1]
13
+ file = "#{path}.rb"
14
+ if FileTest.exists?(file)
15
+ require path
16
+ else
17
+ require name
18
+ end
19
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongo_persist
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Harris
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-11-19 00:00:00 -05:00
12
+ date: 2009-12-17 00:00:00 -05:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -22,6 +22,16 @@ dependencies:
22
22
  - !ruby/object:Gem::Version
23
23
  version: "0"
24
24
  version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: rr
27
+ type: :development
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: "0"
34
+ version:
25
35
  - !ruby/object:Gem::Dependency
26
36
  name: fattr
27
37
  type: :runtime
@@ -42,6 +52,16 @@ dependencies:
42
52
  - !ruby/object:Gem::Version
43
53
  version: "0"
44
54
  version:
55
+ - !ruby/object:Gem::Dependency
56
+ name: mharris_ext
57
+ type: :runtime
58
+ version_requirement:
59
+ version_requirements: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: "0"
64
+ version:
45
65
  description: Library to add MongoDB Persistance to normal Ruby objects
46
66
  email: mharris717@gmail.com
47
67
  executables: []
@@ -59,9 +79,15 @@ files:
59
79
  - Rakefile
60
80
  - VERSION
61
81
  - lib/mongo_persist.rb
82
+ - lib/mongo_persist/array_ext.rb
83
+ - lib/mongo_persist/base.rb
84
+ - lib/mongo_persist/core_ext.rb
85
+ - lib/mongo_persist/hash_ext.rb
86
+ - lib/mongo_persist/mongo_ext.rb
62
87
  - lib/mongo_persist/sandbox.rb
63
88
  - lib/mongo_persist/util.rb
64
89
  - mongo_persist.gemspec
90
+ - spec/mocks.rb
65
91
  - spec/mongo_persist_spec.rb
66
92
  - spec/spec_helper.rb
67
93
  has_rdoc: true
@@ -93,5 +119,7 @@ signing_key:
93
119
  specification_version: 3
94
120
  summary: Library to add MongoDB Persistance to normal Ruby objects
95
121
  test_files:
122
+ - spec/mocks.rb
96
123
  - spec/mongo_persist_spec.rb
97
124
  - spec/spec_helper.rb
125
+ - examples/only.rb