dm-mongo-adapter 0.2.0.pre1

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.
Files changed (65) hide show
  1. data/.gitignore +9 -0
  2. data/LICENSE +20 -0
  3. data/README.rdoc +130 -0
  4. data/Rakefile +36 -0
  5. data/TODO +33 -0
  6. data/VERSION.yml +5 -0
  7. data/bin/console +31 -0
  8. data/dm-mongo-adapter.gemspec +154 -0
  9. data/lib/mongo_adapter.rb +71 -0
  10. data/lib/mongo_adapter/adapter.rb +255 -0
  11. data/lib/mongo_adapter/aggregates.rb +21 -0
  12. data/lib/mongo_adapter/conditions.rb +100 -0
  13. data/lib/mongo_adapter/embedded_model.rb +187 -0
  14. data/lib/mongo_adapter/embedded_resource.rb +134 -0
  15. data/lib/mongo_adapter/embedments/one_to_many.rb +139 -0
  16. data/lib/mongo_adapter/embedments/one_to_one.rb +53 -0
  17. data/lib/mongo_adapter/embedments/relationship.rb +258 -0
  18. data/lib/mongo_adapter/migrations.rb +45 -0
  19. data/lib/mongo_adapter/model.rb +89 -0
  20. data/lib/mongo_adapter/model/embedment.rb +215 -0
  21. data/lib/mongo_adapter/modifier.rb +85 -0
  22. data/lib/mongo_adapter/query.rb +252 -0
  23. data/lib/mongo_adapter/query/java_script.rb +145 -0
  24. data/lib/mongo_adapter/resource.rb +147 -0
  25. data/lib/mongo_adapter/types/date.rb +28 -0
  26. data/lib/mongo_adapter/types/date_time.rb +28 -0
  27. data/lib/mongo_adapter/types/db_ref.rb +65 -0
  28. data/lib/mongo_adapter/types/discriminator.rb +32 -0
  29. data/lib/mongo_adapter/types/object_id.rb +72 -0
  30. data/lib/mongo_adapter/types/objects.rb +31 -0
  31. data/script/performance.rb +260 -0
  32. data/spec/legacy/README +6 -0
  33. data/spec/legacy/adapter_shared_spec.rb +299 -0
  34. data/spec/legacy/adapter_spec.rb +174 -0
  35. data/spec/legacy/associations_spec.rb +140 -0
  36. data/spec/legacy/embedded_resource_spec.rb +157 -0
  37. data/spec/legacy/embedments_spec.rb +177 -0
  38. data/spec/legacy/modifier_spec.rb +81 -0
  39. data/spec/legacy/property_spec.rb +51 -0
  40. data/spec/legacy/spec_helper.rb +3 -0
  41. data/spec/legacy/sti_spec.rb +53 -0
  42. data/spec/lib/cleanup_models.rb +32 -0
  43. data/spec/lib/raw_connections.rb +11 -0
  44. data/spec/public/embedded_collection_spec.rb +61 -0
  45. data/spec/public/embedded_resource_spec.rb +220 -0
  46. data/spec/public/model/embedment_spec.rb +186 -0
  47. data/spec/public/model_spec.rb +37 -0
  48. data/spec/public/resource_spec.rb +564 -0
  49. data/spec/public/shared/model_embedments_spec.rb +338 -0
  50. data/spec/public/shared/object_id_shared_spec.rb +56 -0
  51. data/spec/public/types/df_ref_spec.rb +6 -0
  52. data/spec/public/types/discriminator_spec.rb +118 -0
  53. data/spec/public/types/embedded_array_spec.rb +55 -0
  54. data/spec/public/types/embedded_hash_spec.rb +83 -0
  55. data/spec/public/types/object_id_spec.rb +6 -0
  56. data/spec/rcov.opts +6 -0
  57. data/spec/semipublic/embedded_model_spec.rb +43 -0
  58. data/spec/semipublic/model/embedment_spec.rb +42 -0
  59. data/spec/semipublic/resource_spec.rb +70 -0
  60. data/spec/spec.opts +4 -0
  61. data/spec/spec_helper.rb +45 -0
  62. data/tasks/spec.rake +37 -0
  63. data/tasks/yard.rake +9 -0
  64. data/tasks/yardstick.rake +21 -0
  65. metadata +215 -0
@@ -0,0 +1,174 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
2
+ require File.expand_path(File.join(File.dirname(__FILE__), 'adapter_shared_spec'))
3
+
4
+ describe DataMapper::Adapters::MongoAdapter do
5
+ before :all do
6
+ # let's start with an empty collection
7
+ $db.drop_collection('heffalumps')
8
+
9
+ class ::Heffalump
10
+ include DataMapper::Mongo::Resource
11
+
12
+ property :id, ObjectID
13
+ property :color, String
14
+ property :num_spots, Integer
15
+ property :striped, Boolean
16
+ end
17
+ end
18
+
19
+ it_should_behave_like "An Adapter"
20
+
21
+ describe "authentication" do
22
+ before(:all) do
23
+ # Create a user if needed.
24
+ @details = { :username => 'dm-mongo-auth',
25
+ :password => 'dm-mongo-password' }
26
+
27
+ connection = Mongo::Connection.new
28
+
29
+ begin
30
+ users = connection.db('dm-mongo-test-auth').collection('system.users')
31
+
32
+ # Remove the existing user if one is present.
33
+ users.remove(:user => @details[:username])
34
+ users.remove(:username => @details[:username])
35
+
36
+ # Create a new user.
37
+ users.save(
38
+ :user => @details[:username],
39
+ :pwd => Digest::MD5.hexdigest(
40
+ "#{@details[:username]}:mongo:#{@details[:password]}")
41
+ )
42
+ ensure
43
+ connection.close
44
+ end
45
+ end
46
+
47
+ it 'should raise no error when connecting with valid credentials' do
48
+ DataMapper.setup(:dm_mongo_auth,
49
+ :adapter => 'mongo',
50
+ :hostname => 'localhost',
51
+ :database => 'dm-mongo-test-auth',
52
+ :username => @details[:username],
53
+ :password => @details[:password]
54
+ )
55
+
56
+ lambda do
57
+ repository(:dm_mongo_auth) do
58
+ Heffalump.create(:color => 'red', :num_spots => 2)
59
+ end
60
+ end.should_not raise_error(DataMapper::Mongo::Adapter::ConnectionError)
61
+ end
62
+
63
+ it 'should raise an error when connecting with an invalid username' do
64
+ DataMapper.setup(:dm_mongo_auth,
65
+ :adapter => 'mongo',
66
+ :hostname => 'localhost',
67
+ :database => 'dm-mongo-test',
68
+ :username => @details[:username],
69
+ :password => '__invalid__'
70
+ )
71
+
72
+ lambda do
73
+ repository(:dm_mongo_auth) do
74
+ Heffalump.create(:color => 'red', :num_spots => 2)
75
+ end
76
+ end.should raise_error(DataMapper::Mongo::Adapter::ConnectionError)
77
+ end
78
+
79
+ it 'should raise an error when connecting with an invalid password' do
80
+ DataMapper.setup(:dm_mongo_auth,
81
+ :adapter => 'mongo',
82
+ :hostname => 'localhost',
83
+ :database => 'dm-mongo-test',
84
+ :username => '__invalid__',
85
+ :password => @details[:password]
86
+ )
87
+
88
+ lambda do
89
+ repository(:dm_mongo_auth) do
90
+ Heffalump.create(:color => 'red', :num_spots => 2)
91
+ end
92
+ end.should raise_error(DataMapper::Mongo::Adapter::ConnectionError)
93
+ end
94
+ end
95
+
96
+ describe "queries" do
97
+ before :all do
98
+ @red = Heffalump.create(:color => 'red', :num_spots => 2)
99
+ @green = Heffalump.create(:color => 'green', :num_spots => 3)
100
+ @blue = Heffalump.create(:color => 'blue', :num_spots => 5)
101
+ end
102
+
103
+ it "should be able to search for objects matching conditions for the same property" do
104
+ col = Heffalump.all(:num_spots.gt => 2, :num_spots.not => 3)
105
+
106
+ col.size.should == 1
107
+ col.first.should eql(@blue)
108
+ end
109
+ end
110
+
111
+ describe "embedded objects as properties" do
112
+ before :all do
113
+ class ::Zoo
114
+ include DataMapper::Mongo::Resource
115
+
116
+ property :id, ObjectID
117
+ property :animals, EmbeddedArray
118
+ property :address, EmbeddedHash
119
+ end
120
+ end
121
+
122
+ describe "using arrays" do
123
+ it "should save a resource" do
124
+ zoo = Zoo.new
125
+ zoo.animals = [:marty, :alex, :gloria]
126
+
127
+ lambda {
128
+ zoo.save
129
+ }.should_not raise_error
130
+ end
131
+
132
+ it "should be able to search with 'equal to' criterium" do
133
+ penguins = [:skipper, :kowalski, :private, :rico]
134
+ Zoo.create(:animals => penguins)
135
+
136
+ zoo = Zoo.first(:animals => penguins)
137
+ zoo.should_not be_nil
138
+ zoo.animals.should eql(penguins)
139
+ end
140
+ end
141
+
142
+ describe "using hashes" do
143
+ it "should save a resource" do
144
+ zoo = Zoo.new
145
+ zoo.address = {:street => 'Street 1', :telephone => '123-45-67'}
146
+
147
+ lambda {
148
+ zoo.save
149
+ zoo.address.class.should be(Hash)
150
+ }.should_not raise_error
151
+ end
152
+
153
+ it "should set the property value as hash" do
154
+ _id = $db.collection('zoos').insert(:address => { :street => 'Street 2' })
155
+
156
+ zoo = Zoo.get(_id)
157
+
158
+ zoo.address.should be_kind_of(Hash)
159
+ zoo.address[:street].should eql('Street 2')
160
+ end
161
+
162
+ it "should be able to search with 'equal to' criterium" do
163
+ address = {:street => 'Street 3'}
164
+
165
+ Zoo.create(:address => address)
166
+
167
+ zoo = Zoo.first(:address => address)
168
+
169
+ zoo.should_not be_nil
170
+ zoo.address.should == address
171
+ end
172
+ end
173
+ end
174
+ end
@@ -0,0 +1,140 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
2
+
3
+ describe "associations" do
4
+ before :all do
5
+ cleanup_models :User, :Group
6
+
7
+ class ::User
8
+ include DataMapper::Mongo::Resource
9
+
10
+ property :id, ObjectID
11
+ property :group_id, DBRef
12
+ property :name, String
13
+ property :age, Integer
14
+ end
15
+
16
+ class ::Group
17
+ include DataMapper::Mongo::Resource
18
+
19
+ property :id, ObjectID
20
+ property :name, String
21
+ end
22
+
23
+ class ::Friend
24
+ include DataMapper::Mongo::Resource
25
+
26
+ property :id, ObjectID
27
+ property :name, String
28
+ end
29
+
30
+ User.belongs_to :group
31
+ Group.has Group.n, :users
32
+ User.has User.n, :friends
33
+ end
34
+
35
+ before :each do
36
+ $db.drop_collection('users')
37
+ $db.drop_collection('groups')
38
+ end
39
+
40
+ describe "belongs_to" do
41
+ before do
42
+ @john = User.create(:name => 'john', :age => 101)
43
+ @jane = User.create(:name => 'jane', :age => 102)
44
+
45
+ @group = Group.create(:name => 'dm hackers')
46
+ end
47
+
48
+ it "should set parent object _id in the db ref" do
49
+ lambda {
50
+ @john.group = @group
51
+ @john.save
52
+ }.should_not raise_error
53
+
54
+ @john.group_id.should eql(@group.id)
55
+ end
56
+
57
+ it "should fetch parent object" do
58
+ user = User.create(:name => 'jane')
59
+ user.group_id = @group.id
60
+ user.group.should eql(@group)
61
+ end
62
+
63
+ it "should work with SEL" do
64
+ users = User.all(:name => /john|jane/)
65
+
66
+ users.each { |u| u.update(:group_id => @group.id) }
67
+
68
+ users.each do |user|
69
+ user.group.should_not be_nil
70
+ end
71
+ end
72
+ end
73
+
74
+ describe "has many" do
75
+ before :each do
76
+ @john = User.create(:name => 'john', :age => 101)
77
+ @jane = User.create(:name => 'jane', :age => 102)
78
+
79
+ @group = Group.create(:name => 'dm hackers')
80
+
81
+ [@john, @jane].each { |user| user.update(:group_id => @group.id) }
82
+ end
83
+
84
+ # @done
85
+ it "should get children" do
86
+ @group.users.size.should eql(2)
87
+ end
88
+
89
+ it "should add new children with <<" do
90
+ user = User.new(:name => 'kyle')
91
+ @group.users << user
92
+ user.group_id.should eql(@group.id)
93
+ @group.users.size.should eql(3)
94
+ end
95
+
96
+ # @done
97
+ it "should replace children" do
98
+ user = User.create(:name => 'stan')
99
+ @group.users = [user]
100
+ @group.users.size.should eql(1)
101
+ @group.users.first.should eql(user)
102
+ end
103
+
104
+ it "should fetch children matching conditions" do
105
+ users = @group.users.all(:name => 'john')
106
+ users.size.should eql(1)
107
+ end
108
+ end
109
+
110
+ describe "nested saves" do
111
+ before :each do
112
+ #@friend1 = Friend.new
113
+ #@friend2 = Friend.new
114
+ @user1 = User.new
115
+ @user2 = User.new
116
+ @group = Group.new(:users =>
117
+ [
118
+ {:friends =>
119
+ [{:name => "blah"}, {:name => "blah2"}]
120
+ },
121
+ {:friends =>
122
+ [{:name => "blah3"},{:name => "blah4"}]
123
+ }])
124
+ end
125
+
126
+ # @done
127
+ it "should save nested objects" do
128
+
129
+ #@group.users << @user1
130
+ #@group.users << @user2
131
+ @group.save
132
+ Group.get(@group.id).users.all.each do |u|
133
+ u.group_id.should == @group.id
134
+ u.friends.each do |f|
135
+ f.user_id.should == u.id
136
+ end
137
+ end
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,157 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
2
+
3
+ describe DataMapper::Mongo::EmbeddedModel do
4
+
5
+ before(:all) do
6
+ class ::User
7
+ include Resource
8
+
9
+ property :id, ObjectID
10
+ property :name, String
11
+ property :age, Integer
12
+ end
13
+
14
+ class ::Address
15
+ include EmbeddedResource
16
+
17
+ property :street, String
18
+ property :post_code, String
19
+ property :phone, String
20
+ end
21
+
22
+ class ::Car
23
+ include EmbeddedResource
24
+
25
+ property :name, String
26
+ end
27
+
28
+ User.embeds 1, :address, :model => Address
29
+ User.has User.n, :cars
30
+ end
31
+
32
+ describe "#new" do
33
+ it "should not need a key" do
34
+ lambda {
35
+ class ::Thing
36
+ include DataMapper::Mongo::EmbeddedResource
37
+ property :name, String
38
+ end
39
+
40
+ Thing.new
41
+ }.should_not raise_error
42
+ end
43
+ end
44
+
45
+ # @done
46
+ describe "creating new resources" do
47
+ # @done
48
+ it "should save via parent" do
49
+ user = User.new :address => Address.new(:street => 'Blank 0')
50
+ user.save.should be(true)
51
+ user.new?.should be(false)
52
+ end
53
+
54
+ # @done
55
+ it "should create via parent" do
56
+ user = User.create(:address => Address.new(:street => 'Blank 0'))
57
+ user.new?.should be(false)
58
+ end
59
+
60
+ # @done
61
+ it "should save an embedded resource" do
62
+ user = User.new :address => Address.new(:street => 'Blank 0')
63
+ user.address.save.should be(true)
64
+ user.new?.should be(false)
65
+ user.address.new?.should be(false)
66
+ end
67
+
68
+ # @done
69
+ it "should not allow to create an embedded resource without a parent" do
70
+ address = Address.new(:street => 'Blank 0')
71
+ lambda { address.save }.should raise_error(EmbeddedResource::MissingParentError)
72
+ end
73
+ end
74
+
75
+ # @done
76
+ describe "updating resources" do
77
+ before :all do
78
+ @user = User.create(:name => 'john', :address => Address.new)
79
+ end
80
+
81
+ # @done
82
+ it "should update embedded resource" do
83
+ @user.update(:address => { :street => 'Something 1' }).should be(true)
84
+
85
+ @user.reload
86
+
87
+ @user.address.street.should_not be_nil
88
+ @user.address.street.should eql('Something 1')
89
+ end
90
+ end
91
+
92
+ describe "#dirty?" do
93
+ before :all do
94
+ @user = User.new
95
+ end
96
+
97
+ # @done
98
+ it "should return false when new" do
99
+ address = Address.new
100
+ address.dirty?.should be(false)
101
+ end
102
+
103
+ # @done
104
+ it "should return true if changed" do
105
+ address = Address.new(:street => "Some Street 1234")
106
+ address.dirty?.should be(true)
107
+ end
108
+
109
+ # @done
110
+ it "should return false for a clean parent" do
111
+ @user.dirty?.should be(false)
112
+ end
113
+
114
+ # @done
115
+ it "should return true with one-to-one" do
116
+ @user.address = Address.new(:street => 'Some Street 1234')
117
+ @user.dirty?.should be(true)
118
+ @user.address.dirty?.should be(true)
119
+ end
120
+
121
+ it "should include embedded resource attributes in the dirty attributes list" do
122
+ @user.address = Address.new
123
+ @user.address.street = 'Some Street 1234'
124
+
125
+ dirty_attributes = @user.dirty_attributes
126
+
127
+ dirty_attributes.should_not be_nil
128
+
129
+ address_dirty_attrs = dirty_attributes[@user.model.embedments[:address]]
130
+
131
+ address_dirty_attrs.should_not be_nil
132
+ address_dirty_attrs.keys.size.should eql(1)
133
+ address_dirty_attrs.values.include?('Some Street 1234').should be(true)
134
+ end
135
+
136
+ describe "with saved resource" do
137
+ before :all do
138
+ @user.name = 'john'
139
+ @user.address = Address.new(:street => 'A Street 101')
140
+ @user.save
141
+ end
142
+
143
+ # @done
144
+ it "should return true with one-to-many" do
145
+ @user.cars << Car.new
146
+ @user.dirty?.should be(true)
147
+ end
148
+
149
+ # @done
150
+ it "should return false with a loaded resource" do
151
+ user = User.get(@user.id)
152
+ user.dirty_embedments?.should be(false)
153
+ user.dirty?.should be(false)
154
+ end
155
+ end
156
+ end
157
+ end