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,177 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
|
2
|
+
|
3
|
+
describe DataMapper::Mongo::Model::Embedment do
|
4
|
+
before :all do
|
5
|
+
# let's start with an empty collection
|
6
|
+
$db.drop_collection('users')
|
7
|
+
|
8
|
+
class ::User
|
9
|
+
include Resource
|
10
|
+
|
11
|
+
property :id, ObjectID
|
12
|
+
property :name, String
|
13
|
+
property :age, Integer
|
14
|
+
end
|
15
|
+
|
16
|
+
class ::Address
|
17
|
+
include EmbeddedResource
|
18
|
+
|
19
|
+
property :street, String
|
20
|
+
property :post_code, String
|
21
|
+
property :phone, String
|
22
|
+
end
|
23
|
+
|
24
|
+
class ::Car
|
25
|
+
include EmbeddedResource
|
26
|
+
|
27
|
+
property :name, String
|
28
|
+
end
|
29
|
+
|
30
|
+
@user_attributes = {:name => 'piotr', :age => 26, :address => {:street => '1st ave', :post_code => '123-45'}}
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "Resource" do
|
34
|
+
# @done
|
35
|
+
it "should respond to #embeds" do
|
36
|
+
User.should respond_to(:embeds)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should respond to #embedded_in" do
|
40
|
+
User.should respond_to(:embedded_in)
|
41
|
+
end
|
42
|
+
|
43
|
+
# @done
|
44
|
+
it "should respond to #embedments" do
|
45
|
+
User.should respond_to(:embedments)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "#embeds" do
|
50
|
+
describe "One-To-One Relationship" do
|
51
|
+
before :all do
|
52
|
+
User.embeds(1, :address, :model => Address)
|
53
|
+
end
|
54
|
+
|
55
|
+
describe "#dirty?" do
|
56
|
+
# @done
|
57
|
+
it "should return false without dirty attributes and without an embedded resource" do
|
58
|
+
u = User.new
|
59
|
+
u.dirty?.should be_false
|
60
|
+
end
|
61
|
+
|
62
|
+
# @done
|
63
|
+
it "should return true with a dirty attributes and with an embedded resource" do
|
64
|
+
u = User.new(@user_attributes.except(:address))
|
65
|
+
u.dirty?.should be_true
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# @done
|
70
|
+
it "should create a new embedment" do
|
71
|
+
User.embedments[:address].class.should be(Embedments::OneToOne::Relationship)
|
72
|
+
end
|
73
|
+
|
74
|
+
# @done
|
75
|
+
it "should create readers and writers for the embedded resource" do
|
76
|
+
user = User.new
|
77
|
+
|
78
|
+
user.should respond_to("address")
|
79
|
+
user.should respond_to("address=")
|
80
|
+
end
|
81
|
+
|
82
|
+
# @done
|
83
|
+
it "should not require embedded resource to save the parent" do
|
84
|
+
user = User.new(@user_attributes.except(:address))
|
85
|
+
user.save.should be_true
|
86
|
+
end
|
87
|
+
|
88
|
+
# @done
|
89
|
+
it "should set the embedded resource" do
|
90
|
+
user = User.new
|
91
|
+
address = Address.new
|
92
|
+
|
93
|
+
user.address = address
|
94
|
+
user.address.should be(address)
|
95
|
+
|
96
|
+
address.parent.should be(user)
|
97
|
+
end
|
98
|
+
|
99
|
+
# @done
|
100
|
+
it "should save the embedded resource" do
|
101
|
+
user = User.new(@user_attributes)
|
102
|
+
user.save.should be(true)
|
103
|
+
user.address.new?.should be(false)
|
104
|
+
end
|
105
|
+
|
106
|
+
# @done
|
107
|
+
it "should load parent and the embedded resource" do
|
108
|
+
_id = $db.collection('users').insert(@user_attributes)
|
109
|
+
|
110
|
+
user = User.get(_id)
|
111
|
+
|
112
|
+
user.address.should_not be_nil
|
113
|
+
end
|
114
|
+
|
115
|
+
# @done
|
116
|
+
#
|
117
|
+
# Spec now fails since a OneToOne relationship which hasn't been set
|
118
|
+
# should return nil.
|
119
|
+
#
|
120
|
+
# it "should load parent if the embedded resource is nil" do
|
121
|
+
# _id = $db.collection('users').insert(:name => 'john')
|
122
|
+
#
|
123
|
+
# user = User.get(_id)
|
124
|
+
# user.address.should_not be_nil
|
125
|
+
# end
|
126
|
+
end
|
127
|
+
|
128
|
+
describe "One-to-Many Relationship" do
|
129
|
+
before :all do
|
130
|
+
User.embeds User.n, :cars
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should create a new embedment" do
|
134
|
+
User.embedments[:cars].class.should be(Embedments::OneToMany::Relationship)
|
135
|
+
end
|
136
|
+
|
137
|
+
it "should create readers and writers for the embedded resource" do
|
138
|
+
user = User.new
|
139
|
+
|
140
|
+
user.should respond_to("cars")
|
141
|
+
user.should respond_to("cars=")
|
142
|
+
end
|
143
|
+
|
144
|
+
it "should set the embedded collection" do
|
145
|
+
user = User.new
|
146
|
+
|
147
|
+
3.times { user.cars << Car.new }
|
148
|
+
|
149
|
+
user.cars.size.should eql(3)
|
150
|
+
user.cars.all?{ |c| c.parent == user }.should be(true)
|
151
|
+
end
|
152
|
+
|
153
|
+
it "should save the embedded resources" do
|
154
|
+
user = User.new @user_attributes.except(:address)
|
155
|
+
|
156
|
+
['ford', 'honda', 'volvo'].each { |name| user.cars << Car.new(:name => name) }
|
157
|
+
|
158
|
+
user.save.should be(true)
|
159
|
+
user.cars.all? { |car| car.saved? }.should be(true)
|
160
|
+
end
|
161
|
+
|
162
|
+
it "should load parent with its embedded collection" do
|
163
|
+
_id = $db.collection('users').insert(
|
164
|
+
"name"=>"piotr", "cars"=>[{"name"=>"ford"}, {"name"=>"honda"}, {"name"=>"volvo"}], "age"=>26)
|
165
|
+
|
166
|
+
user = User.get(_id)
|
167
|
+
|
168
|
+
user.cars.should_not be_nil
|
169
|
+
user.cars.size.should eql(3)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
describe "Many-To-One Relationship" do
|
174
|
+
it "should be implemented"
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
|
2
|
+
|
3
|
+
# @done
|
4
|
+
describe "updates with mongodb modifiers" do
|
5
|
+
# @done
|
6
|
+
before :all do
|
7
|
+
$db.drop_collection("posts")
|
8
|
+
class ::Post
|
9
|
+
include DataMapper::Mongo::Resource
|
10
|
+
property :id, ObjectID
|
11
|
+
property :comment_count, Integer
|
12
|
+
property :body, Text
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# @done
|
17
|
+
it "should increment" do
|
18
|
+
post = Post.create(:comment_count => 1)
|
19
|
+
post.increment(:comment_count, 1)
|
20
|
+
post.comment_count.should == 2
|
21
|
+
Post.get(post.id).comment_count.should == 2
|
22
|
+
end
|
23
|
+
|
24
|
+
# @done
|
25
|
+
it "should decrement" do
|
26
|
+
post = Post.create(:comment_count => 10)
|
27
|
+
post.decrement(:comment_count, 5)
|
28
|
+
post.comment_count.should == 5
|
29
|
+
Post.get(post.id).comment_count.should == 5
|
30
|
+
end
|
31
|
+
|
32
|
+
# @done
|
33
|
+
it "should set" do
|
34
|
+
# post = Post.create(:body => "This needs to be edited", :comment_count => 2)
|
35
|
+
# post.set(:body => "This was edited", :comment_count => 3)
|
36
|
+
# post.body.should == "This was edited"
|
37
|
+
# post.comment_count.should == 3
|
38
|
+
# fresh_post = Post.get(post.id)
|
39
|
+
# fresh_post.body.should == "This was edited"
|
40
|
+
# fresh_post.comment_count.should == 3
|
41
|
+
pending
|
42
|
+
end
|
43
|
+
|
44
|
+
# @done
|
45
|
+
it "should unset" do
|
46
|
+
#post = Post.create(:body => "This needs to be removed", :comment_count => 2)
|
47
|
+
#post.unset(:body, :comment_count)
|
48
|
+
#post.body.should be_nil
|
49
|
+
#post.comment_count.should be_nil
|
50
|
+
#fresh_post = Post.get(post.id)
|
51
|
+
#fresh_post.body.should be_nil
|
52
|
+
#fresh_post.comment_count.should be_nil
|
53
|
+
pending
|
54
|
+
end
|
55
|
+
|
56
|
+
# @done
|
57
|
+
it "should push" do
|
58
|
+
pending
|
59
|
+
end
|
60
|
+
|
61
|
+
# @done
|
62
|
+
it "should push_all" do
|
63
|
+
pending
|
64
|
+
end
|
65
|
+
|
66
|
+
# @done
|
67
|
+
it "should pop" do
|
68
|
+
pending
|
69
|
+
end
|
70
|
+
|
71
|
+
# @done
|
72
|
+
it "should pull" do
|
73
|
+
pending
|
74
|
+
end
|
75
|
+
|
76
|
+
# @done
|
77
|
+
it "should pull_all" do
|
78
|
+
pending
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
|
2
|
+
|
3
|
+
describe "Property" do
|
4
|
+
before :all do
|
5
|
+
ENV['TZ'] = 'UTC'
|
6
|
+
|
7
|
+
class ::User
|
8
|
+
include DataMapper::Mongo::Resource
|
9
|
+
|
10
|
+
property :id, ObjectID
|
11
|
+
property :date_time_field, DateTime
|
12
|
+
property :date_field, Date
|
13
|
+
property :type, Discriminator
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "Class" do
|
18
|
+
it "should be typecasted to a string" do
|
19
|
+
lambda{
|
20
|
+
user = User.create!(:type => User)
|
21
|
+
}.should_not raise_error
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "DateTime" do
|
26
|
+
it "should be typecasted from a Time object" do
|
27
|
+
dt_now = DateTime.now
|
28
|
+
t_now = Time.now
|
29
|
+
|
30
|
+
_id = $db.collection('users').insert(:type => 'User', :date_time_field => t_now)
|
31
|
+
|
32
|
+
user = User.get(_id)
|
33
|
+
|
34
|
+
user.date_time_field.class.should be(DateTime)
|
35
|
+
user.date_time_field.to_time.to_i.should == dt_now.to_time.to_i
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "Date" do
|
40
|
+
it "should be typecasted from a Time object" do
|
41
|
+
today = Date.today
|
42
|
+
|
43
|
+
_id = $db.collection('users').insert(:type => 'User', :date_field => Time.parse(today.to_s))
|
44
|
+
|
45
|
+
user = User.get(_id)
|
46
|
+
|
47
|
+
user.date_field.class.should be(Date)
|
48
|
+
Time.parse(user.date_field.to_s).should == Time.parse(today.to_s)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
|
2
|
+
|
3
|
+
# @done (in public/types/discriminator_spec.rb which is a modified copy from dm-core specs)
|
4
|
+
describe "Single Table Inheritance" do
|
5
|
+
before(:all) do
|
6
|
+
class ::Person
|
7
|
+
include DataMapper::Mongo::Resource
|
8
|
+
|
9
|
+
property :id, ObjectID
|
10
|
+
property :name, String
|
11
|
+
property :job, String
|
12
|
+
property :type, Discriminator
|
13
|
+
end
|
14
|
+
|
15
|
+
class ::Male < Person; end
|
16
|
+
class ::Father < Male; end
|
17
|
+
class ::Son < Male; end
|
18
|
+
end
|
19
|
+
|
20
|
+
before(:each) do
|
21
|
+
$db.drop_collection('people')
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should have a type property that reflects the class" do
|
25
|
+
[Person, Male, Father, Son].each_with_index do |model, i|
|
26
|
+
object = model.create!(:name => "#{model} #{i}")
|
27
|
+
object.reload
|
28
|
+
object.type.should == model
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should parent should return an instance of the child when type is explicitly specified" do
|
33
|
+
[Person, Male, Father, Son].each_with_index do |model, i|
|
34
|
+
object = model.create!(:name => "#{model} #{i}")
|
35
|
+
object.reload
|
36
|
+
object.should be_instance_of(model)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should discriminate types during reads" do
|
41
|
+
father1 = Father.create!(:name => '1')
|
42
|
+
father2 = Father.create!(:name => '2')
|
43
|
+
|
44
|
+
fathers = Father.all
|
45
|
+
|
46
|
+
fathers.should == [father1, father2]
|
47
|
+
|
48
|
+
fathers.each do |father|
|
49
|
+
father.type.should be(Father)
|
50
|
+
father.should be_instance_of(Father)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module DataMapper::Mongo::Spec
|
2
|
+
module CleanupModels
|
3
|
+
|
4
|
+
# Cleans up models after a spec by dropping the Mongo collection,
|
5
|
+
# removing the model classes from the descendants list, and then
|
6
|
+
# undefining the constants.
|
7
|
+
#
|
8
|
+
# @todo Only used once; try to remove.
|
9
|
+
#
|
10
|
+
def cleanup_models(*models)
|
11
|
+
unless models.empty?
|
12
|
+
model = models.pop
|
13
|
+
sym = model.to_s.to_sym
|
14
|
+
|
15
|
+
if Object.const_defined?(sym)
|
16
|
+
if model.respond_to?(:storage_name)
|
17
|
+
db = DataMapper::Mongo::Spec.database(model.repository.name)
|
18
|
+
db.drop_collection(model.storage_name)
|
19
|
+
end
|
20
|
+
|
21
|
+
DataMapper::Model.descendants.delete(model)
|
22
|
+
DataMapper::Mongo::EmbeddedModel.descendants.delete(model)
|
23
|
+
|
24
|
+
Object.send(:remove_const, sym)
|
25
|
+
end
|
26
|
+
|
27
|
+
cleanup_models(*models)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end # CleanupModels
|
32
|
+
end # DataMaper::Mongo::Spec
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module DataMapper::Mongo::Spec
|
2
|
+
module RawConnections
|
3
|
+
# Returns a Mongo::Database instance which can be used for manually
|
4
|
+
# adjusting the database used by repository +repo+.
|
5
|
+
def database(repo = :default)
|
6
|
+
DataMapper.repository(repo).adapter.send(:database)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
extend RawConnections
|
11
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
|
2
|
+
|
3
|
+
describe DataMapper::Mongo::EmbeddedResource do
|
4
|
+
before :all do
|
5
|
+
class ::Student
|
6
|
+
include DataMapper::Mongo::Resource
|
7
|
+
property :id, ObjectID
|
8
|
+
property :name, String
|
9
|
+
|
10
|
+
embeds n, :scores
|
11
|
+
end
|
12
|
+
|
13
|
+
class ::Score
|
14
|
+
include DataMapper::Mongo::EmbeddedResource
|
15
|
+
property :value, Float
|
16
|
+
property :course, String
|
17
|
+
end
|
18
|
+
|
19
|
+
Student.all.destroy!
|
20
|
+
|
21
|
+
@student = Student.new
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "#new" do
|
25
|
+
it "should create a new instance and add it to the collection" do
|
26
|
+
score = @student.scores.new
|
27
|
+
score.should be_kind_of(Score)
|
28
|
+
score.parent.should be(@student)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should set a new instance with attributes" do
|
32
|
+
attrs = { :value => 5.0, :course => 'MongoDB' }
|
33
|
+
score = @student.scores.new(attrs)
|
34
|
+
score.attributes.should == attrs
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "#dirty?" do
|
39
|
+
it "should return true when includes dirty resources" do
|
40
|
+
@student.scores << Score.new(:value => 6.0)
|
41
|
+
@student.scores.dirty?.should be(true)
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should return false when it doesn't include dirty resources" do
|
45
|
+
@student.scores << Score.new
|
46
|
+
@student.scores.dirty?.should be(true)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "#save" do
|
51
|
+
it "should call save on parent" do
|
52
|
+
expected = Score.new(:value => 7.0)
|
53
|
+
|
54
|
+
@student.scores << expected
|
55
|
+
@student.scores.save.should be(true)
|
56
|
+
@student.clean?.should be(true)
|
57
|
+
|
58
|
+
@student.reload.scores.should == [expected]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|