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.
- 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
|