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