dm-mongo-adapter 0.2.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
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,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,3 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
2
+ $db = DataMapper::Mongo::Spec.database(:default)
3
+ include DataMapper::Mongo
@@ -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