dm-mongo-adapter 0.2.0.pre1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +9 -0
- data/LICENSE +20 -0
- data/README.rdoc +130 -0
- data/Rakefile +36 -0
- data/TODO +33 -0
- data/VERSION.yml +5 -0
- data/bin/console +31 -0
- data/dm-mongo-adapter.gemspec +154 -0
- data/lib/mongo_adapter.rb +71 -0
- data/lib/mongo_adapter/adapter.rb +255 -0
- data/lib/mongo_adapter/aggregates.rb +21 -0
- data/lib/mongo_adapter/conditions.rb +100 -0
- data/lib/mongo_adapter/embedded_model.rb +187 -0
- data/lib/mongo_adapter/embedded_resource.rb +134 -0
- data/lib/mongo_adapter/embedments/one_to_many.rb +139 -0
- data/lib/mongo_adapter/embedments/one_to_one.rb +53 -0
- data/lib/mongo_adapter/embedments/relationship.rb +258 -0
- data/lib/mongo_adapter/migrations.rb +45 -0
- data/lib/mongo_adapter/model.rb +89 -0
- data/lib/mongo_adapter/model/embedment.rb +215 -0
- data/lib/mongo_adapter/modifier.rb +85 -0
- data/lib/mongo_adapter/query.rb +252 -0
- data/lib/mongo_adapter/query/java_script.rb +145 -0
- data/lib/mongo_adapter/resource.rb +147 -0
- data/lib/mongo_adapter/types/date.rb +28 -0
- data/lib/mongo_adapter/types/date_time.rb +28 -0
- data/lib/mongo_adapter/types/db_ref.rb +65 -0
- data/lib/mongo_adapter/types/discriminator.rb +32 -0
- data/lib/mongo_adapter/types/object_id.rb +72 -0
- data/lib/mongo_adapter/types/objects.rb +31 -0
- data/script/performance.rb +260 -0
- data/spec/legacy/README +6 -0
- data/spec/legacy/adapter_shared_spec.rb +299 -0
- data/spec/legacy/adapter_spec.rb +174 -0
- data/spec/legacy/associations_spec.rb +140 -0
- data/spec/legacy/embedded_resource_spec.rb +157 -0
- data/spec/legacy/embedments_spec.rb +177 -0
- data/spec/legacy/modifier_spec.rb +81 -0
- data/spec/legacy/property_spec.rb +51 -0
- data/spec/legacy/spec_helper.rb +3 -0
- data/spec/legacy/sti_spec.rb +53 -0
- data/spec/lib/cleanup_models.rb +32 -0
- data/spec/lib/raw_connections.rb +11 -0
- data/spec/public/embedded_collection_spec.rb +61 -0
- data/spec/public/embedded_resource_spec.rb +220 -0
- data/spec/public/model/embedment_spec.rb +186 -0
- data/spec/public/model_spec.rb +37 -0
- data/spec/public/resource_spec.rb +564 -0
- data/spec/public/shared/model_embedments_spec.rb +338 -0
- data/spec/public/shared/object_id_shared_spec.rb +56 -0
- data/spec/public/types/df_ref_spec.rb +6 -0
- data/spec/public/types/discriminator_spec.rb +118 -0
- data/spec/public/types/embedded_array_spec.rb +55 -0
- data/spec/public/types/embedded_hash_spec.rb +83 -0
- data/spec/public/types/object_id_spec.rb +6 -0
- data/spec/rcov.opts +6 -0
- data/spec/semipublic/embedded_model_spec.rb +43 -0
- data/spec/semipublic/model/embedment_spec.rb +42 -0
- data/spec/semipublic/resource_spec.rb +70 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +45 -0
- data/tasks/spec.rake +37 -0
- data/tasks/yard.rake +9 -0
- data/tasks/yardstick.rake +21 -0
- 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
|