mordor 0.3.0-java

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.
@@ -0,0 +1,3 @@
1
+ module Mordor
2
+ VERSION = "0.3.0"
3
+ end
@@ -0,0 +1,38 @@
1
+ require './lib/mordor/version'
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = 'mordor'
5
+
6
+ # Do not set the version and date field manually, this is done by the release script
7
+ s.version = Mordor::VERSION
8
+ s.date = "2015-05-15"
9
+
10
+ s.summary = 'mordor'
11
+ s.description = <<-eos
12
+ Small gem to add MongoDB Resources, resources have attributes that translate into document fields. When an attribute is declared, finders for the attribute are added to the Resource automatically
13
+ eos
14
+
15
+ s.authors = ['Jan-Willem Koelewijn', 'Dirkjan Bussink']
16
+ s.email = ['janwillem.koelewijn@nedap.com', 'dirkjan.bussink@nedap.com']
17
+ s.homepage = 'http://www.nedap.com'
18
+
19
+ s.add_runtime_dependency 'extlib'
20
+ s.add_runtime_dependency 'json'
21
+ s.add_runtime_dependency 'mongo', '< 2.0'
22
+
23
+ s.add_development_dependency 'rack-test'
24
+ s.add_development_dependency 'rake'
25
+ s.add_development_dependency 'rspec', '~> 2.0', '< 2.99'
26
+
27
+ s.extensions << 'ext/mkrf_conf.rb'
28
+
29
+ if defined? JRUBY_VERSION
30
+ s.platform = 'java'
31
+ else
32
+ s.add_runtime_dependency('bson_ext')
33
+ end
34
+
35
+ # The files and test_files directives are set automatically by the release script.
36
+ # Do not change them by hand, but make sure to add the files to the git repository.
37
+ s.files = %w(.gitignore .travis.yml CHANGES.md Gemfile Guardfile LICENSE README.md Rakefile ext/mkrf_conf.rb lib/mordor.rb lib/mordor/collection.rb lib/mordor/config.rb lib/mordor/resource.rb lib/mordor/version.rb mordor.gemspec spec/mordor/collection_spec.rb spec/mordor/connection_spec.rb spec/mordor/resource_spec.rb spec/spec.opts spec/spec_helper.rb tasks/github-gem.rake)
38
+ end
@@ -0,0 +1,159 @@
1
+ require File.join(File.dirname(__FILE__), '..', '/spec_helper.rb')
2
+
3
+ describe "with respect to collections" do
4
+ before :each do
5
+ class TestResource
6
+ include Mordor::Resource
7
+
8
+ attribute :first, :index => true
9
+ attribute :second, :index => true, :index_type => Mongo::ASCENDING
10
+ attribute :third, :finder_method => :find_by_third_attribute
11
+ end
12
+ end
13
+
14
+ after :each do
15
+ drop_db_collections
16
+ end
17
+
18
+ describe "serialization" do
19
+ before :each do
20
+ 5.times do |index|
21
+ res = TestResource.new(:first => "#{index}_first", :second => "#{index}_second", :third => "#{index}_third")
22
+ res.save.should be true
23
+ end
24
+ end
25
+
26
+ it "should correctly serialize a collection" do
27
+ collection = TestResource.all
28
+ collection.size.should == 5
29
+
30
+ json_collection = collection.to_json
31
+ json_collection.should_not be_nil
32
+
33
+ json_collection = JSON.parse(json_collection)
34
+
35
+ json_collection.size.should == 5
36
+ end
37
+ end
38
+
39
+ describe "converting to array" do
40
+ before :each do
41
+ 5.times do |index|
42
+ res = TestResource.new(:first => "#{index}_first", :second => "#{index}_second", :third => "#{index}_third")
43
+ res.save.should be true
44
+ end
45
+ end
46
+
47
+ it "should be possible to convert a collection to an array" do
48
+ collection = TestResource.find_by_first("1_first")
49
+ collection.to_a.should be_a Array
50
+ end
51
+
52
+ it "should be possible to convert multiple times after iterating using each" do
53
+ collection = TestResource.find_by_first("1_first")
54
+ collection.each do |resource|
55
+ resource.first
56
+ end
57
+ array1 = collection.to_a
58
+ array2 = collection.to_a
59
+ array1.size.should == array2.size
60
+ end
61
+
62
+ it "should be possible to convert a collection to an array multiple times" do
63
+ collection = TestResource.find_by_first("1_first")
64
+ array1 = collection.to_a
65
+ array2 = collection.to_a
66
+ array1.size.should == array2.size
67
+ end
68
+
69
+ it "should convert the collection to an array with the same size" do
70
+ collection = TestResource.find_by_first("1_first")
71
+ collection_size = collection.size
72
+ collection.to_a.size.should == collection_size
73
+ end
74
+ end
75
+
76
+ describe "counting" do
77
+
78
+ before :each do
79
+ 5.times do |index|
80
+ res = TestResource.new(:first => "#{index}_first", :second => "#{index}_second", :third => "#{index}_third")
81
+ res.save.should be true
82
+ end
83
+ end
84
+
85
+ it "should default to taking in account limits" do
86
+ TestResource.find({}, {:limit => 3}).count.should == 3
87
+ end
88
+
89
+ it "should not take in account limits when requested" do
90
+ TestResource.find({}, {:limit => 3}).count(false).should == 5
91
+ end
92
+
93
+ it "should not take in account skips when requested" do
94
+ TestResource.find({}, {:skip => 2}).count(false).should == 5
95
+ end
96
+
97
+ it "should not take in account skips and limits when requested" do
98
+ TestResource.find({}, {:skip => 1, :limit => 3}).count(false).should == 5
99
+ end
100
+
101
+ it "should take in account skips by defaults" do
102
+ TestResource.find({}, {:skip => 2}).count.should == 3
103
+ end
104
+
105
+ it "should take in account skips and limits by default" do
106
+ TestResource.find({}, {:skip => 1, :limit => 3}).count.should == 3
107
+ end
108
+ end
109
+
110
+ describe "merging array based collection" do
111
+ before :each do
112
+ @first_collection = Mordor::Collection.new(TestResource, [TestResource.new(:first => "first", :second => "second", :third => "third")])
113
+ @second_collection = Mordor::Collection.new(TestResource, [TestResource.new(:first => "1st", :second => "2nd", :third => "3rd")])
114
+ end
115
+
116
+ it "should not change original collections when no bang is used" do
117
+ first_size = @first_collection.size
118
+ second_size = @second_collection.size
119
+
120
+ new_collection = @first_collection.merge(@second_collection)
121
+ @first_collection.size.should == first_size
122
+ @second_collection.size.should == second_size
123
+ end
124
+
125
+ it "should create collection with all elements from original collections" do
126
+ new_collection = @first_collection.merge(@second_collection)
127
+ new_collection.size.should == (@first_collection.size + @second_collection.size)
128
+
129
+ [@first_collection, @second_collection].each do |collection|
130
+ collection.each do |element|
131
+ new_collection.should include element
132
+ end
133
+ end
134
+ end
135
+
136
+ it "should be possible to use the + as an alias" do
137
+ new_collection = @first_collection + @second_collection
138
+ new_collection.size.should == (@first_collection.size + @second_collection.size)
139
+
140
+ [@first_collection, @second_collection].each do |collection|
141
+ collection.each do |element|
142
+ new_collection.should include element
143
+ end
144
+ end
145
+ end
146
+
147
+ it "should change the receiver of the merge! to have all elements" do
148
+ first_size = @first_collection.size
149
+ second_size = @second_collection.size
150
+
151
+ @first_collection.merge!(@second_collection)
152
+ @first_collection.size.should == (first_size + second_size)
153
+
154
+ @second_collection.each do |element|
155
+ @first_collection.should include element
156
+ end
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,143 @@
1
+ require File.join(File.dirname(__FILE__), '..', '/spec_helper.rb')
2
+
3
+ describe "connecting to mongo" do
4
+ before :each do
5
+ class TestResource
6
+ include Mordor::Resource
7
+ end
8
+ end
9
+
10
+ describe 'database connection' do
11
+ it "should have a mongo database " do
12
+ TestResource.database.should be_instance_of(Mongo::DB)
13
+ end
14
+
15
+ it "should select the correct database" do
16
+ database_name = "any_database_name"
17
+ Mordor::Config.use { |config| config[:database] = database_name }
18
+
19
+ TestResource.database.name.should == database_name
20
+ end
21
+ end
22
+
23
+ describe "when credentials are provided" do
24
+ let(:credentials) { {:username => "A username", :password => "A password"} }
25
+
26
+ before :each do
27
+ Mordor::Config.use do |config|
28
+ config[:username] = credentials[:username]
29
+ config[:password] = credentials[:password]
30
+ end
31
+
32
+ @mock_db = double("db")
33
+ Mongo::Connection.stub(:new).and_return(double("connection", :db => @mock_db))
34
+ end
35
+
36
+ it "should authenticate with username and password" do
37
+ @mock_db.should_receive(:authenticate).with(credentials[:username], credentials[:password])
38
+ TestResource.database
39
+ end
40
+ end
41
+
42
+ describe "the Mongo database connection" do
43
+ before :each do
44
+ @mock_connection = double("connection", :db => double("db"))
45
+ end
46
+
47
+ after :each do
48
+ TestResource.database
49
+ end
50
+
51
+ it "should connect with specified host" do
52
+ host = "any host IP or reachable hostname"
53
+ Mordor::Config.use { |config| config[:hostname] = host }
54
+ Mongo::Connection.should_receive(:new).with(host, anything).and_return(@mock_connection)
55
+ end
56
+
57
+ it "should connect on specified port" do
58
+ port = rand(10000)
59
+ Mordor::Config.use { |config| config[:port] = port }
60
+ Mongo::Connection.should_receive(:new).with(anything, port).and_return(@mock_connection)
61
+ end
62
+
63
+ describe 'setting connection pool options' do
64
+ it 'supports setting pool size' do
65
+ Mordor::Config.use { |config| config[:pool_size] = 7 }
66
+ Mongo::Connection.should_receive(:new).with('localhost', 27017, pool_size: 7).and_return(@mock_connection)
67
+ end
68
+
69
+ it 'supports setting pool timeout' do
70
+ Mordor::Config.use { |config| config[:pool_timeout] = 8 }
71
+ Mongo::Connection.should_receive(:new).with('localhost', 27017, pool_timeout: 8).and_return(@mock_connection)
72
+ end
73
+
74
+ it 'supports setting both' do
75
+ Mordor::Config.use { |config|
76
+ config[:pool_size] = 9
77
+ config[:pool_timeout] = 10
78
+ }
79
+ Mongo::Connection.should_receive(:new).with('localhost', 27017, pool_size: 9, pool_timeout: 10).and_return(@mock_connection)
80
+ end
81
+ end
82
+ end
83
+
84
+ describe "replica sets" do
85
+ before :each do
86
+ @mock_connection = double("connection", :db => double("db"))
87
+ Mordor::Config.use { |config| config[:hostname] = host_string }
88
+ end
89
+
90
+ after :each do
91
+ TestResource.database
92
+ end
93
+
94
+ let(:host_string){ 'localhost:27017, localhost:27018 ' }
95
+ let(:hosts_array){ host_string.split(',').map(&:strip) }
96
+ let(:replica_set_string){ 'sample replica set' }
97
+
98
+ it "creates a mongo replica set client when multiple hosts are provided" do
99
+ Mongo::MongoReplicaSetClient.should_receive(:new).with(hosts_array, anything).and_return(@mock_connection)
100
+ end
101
+
102
+ it "creates a mongo replica set client with the correct replica set name if given" do
103
+ Mordor::Config.use do |config|
104
+ config[:replica_set] = replica_set_string
105
+ end
106
+ options = {:rs_name => replica_set_string, :refresh_mode => :sync}
107
+
108
+ Mongo::MongoReplicaSetClient.should_receive(:new).with(anything, options).and_return(@mock_connection)
109
+ end
110
+
111
+ describe 'setting connection pool options' do
112
+ it 'supports setting pool size' do
113
+ Mordor::Config.use do |config|
114
+ config[:pool_size] = 1
115
+ end
116
+ options = {:pool_size => 1, :refresh_mode => :sync}
117
+
118
+ Mongo::MongoReplicaSetClient.should_receive(:new).with(anything, options).and_return(@mock_connection)
119
+ end
120
+
121
+ it 'supports setting pool timeout' do
122
+ Mordor::Config.use do |config|
123
+ config[:pool_timeout] = 1
124
+ end
125
+
126
+ options = {:pool_timeout => 1, :refresh_mode => :sync}
127
+ Mongo::MongoReplicaSetClient.should_receive(:new).with(anything, options).and_return(@mock_connection)
128
+ end
129
+
130
+ it 'supports setting both' do
131
+ Mordor::Config.use do |config|
132
+ config[:pool_size] = 5
133
+ config[:pool_timeout] = 1
134
+ config[:replica_set] = replica_set_string
135
+ end
136
+ options = {:pool_size => 5, :pool_timeout => 1, :refresh_mode => :sync, :rs_name => replica_set_string}
137
+
138
+ Mongo::MongoReplicaSetClient.should_receive(:new).with(anything, options).and_return(@mock_connection)
139
+ end
140
+ end
141
+
142
+ end
143
+ end
@@ -0,0 +1,519 @@
1
+ require File.join(File.dirname(__FILE__), '..', '/spec_helper.rb')
2
+
3
+ describe "with respect to resources" do
4
+ before :each do
5
+ class TestResource
6
+ include Mordor::Resource
7
+
8
+ attribute :first, :index => true
9
+ attribute :second, :index => true, :index_type => Mongo::ASCENDING
10
+ attribute :third, :finder_method => :find_by_third_attribute
11
+ attribute :at
12
+ attribute :created_at, :timestamp => true
13
+
14
+ # Put this in here again to ensure the original method is still here
15
+ class_eval do
16
+ def self.ensure_indices
17
+ collection.ensure_index( indices.map{|index| [index.to_s, Mongo::DESCENDING]} ) if indices.any?
18
+ end
19
+ end
20
+ end
21
+ end
22
+
23
+ after :each do
24
+ drop_db_collections
25
+ end
26
+
27
+ it "should create accessor methods for all attributes" do
28
+ ["first", "first=", "second", "second="].each{ |v| TestResource.public_instance_methods.map{|m| m.to_s}.should include(v) }
29
+ end
30
+
31
+ it "should create class level finder methods for all attributes" do
32
+ ["find_by_first", "find_by_second"].each do |finder_method|
33
+ TestResource.methods.map{|m| m.to_s}.should include(finder_method)
34
+ end
35
+ end
36
+
37
+ it "should create finder methods with the supplied finder method name" do
38
+ TestResource.methods.map{|m| m.to_s}.should include "find_by_third_attribute"
39
+ end
40
+
41
+ it "should ensure indices when the option :index => true is given" do
42
+ TestResource.send(:indices).should include :first
43
+ end
44
+
45
+ it "should default to descending indices" do
46
+ TestResource.send(:index_types).keys.should include :first
47
+ TestResource.send(:index_types)[:first].should == Mongo::DESCENDING
48
+ end
49
+
50
+ it "should be possible to set index type using the 'index_type' option" do
51
+ TestResource.send(:index_types).keys.should include :second
52
+ TestResource.send(:index_types)[:second].should == Mongo::ASCENDING
53
+ end
54
+
55
+ it "should be possible to designate an attribute as a timestamp" do
56
+ TestResource.timestamped_attribute.should_not be_nil
57
+ TestResource.timestamped_attribute.should == :created_at
58
+ end
59
+
60
+ it "should only be possible to have one attribute as a timestamp" do
61
+ lambda {
62
+ TestResource2.class_eval do
63
+ attribute :some_timestamp, :timestamp => true
64
+ attribute :another_timestamp, :timestamp => true
65
+ end
66
+ }.should raise_error
67
+ end
68
+
69
+ it "should provide timestamped attribute as first attribute when creating a Resource" do
70
+ tr = TestResource.create({:first => 'first'})
71
+ tr.reload
72
+ tr.at.should_not be_nil
73
+ TestResource.get(tr._id).at.should_not == BSON::Timestamp.new(0,0)
74
+ end
75
+
76
+ context "with respect to replacing params" do
77
+ it "should correctly substitute non-alphanumeric characters in keys with underscores" do
78
+ options = {
79
+ "o*p#t>i_o@n)s" => "test"
80
+ }
81
+ result = TestResource.new.replace_params(options)
82
+ result.keys.first.should eql "o_p_t_i_o_n_s"
83
+ end
84
+
85
+ it "should correctly replace Date and DateTimes" do
86
+ options = {
87
+ "option" => Date.today,
88
+ "another" => DateTime.now
89
+ }
90
+ result = TestResource.new.replace_params(options)
91
+ result.each do |k, v|
92
+ v.should be_a Time
93
+ end
94
+ end
95
+
96
+ it "should correctly replace BigDecimals" do
97
+ options = {
98
+ "option" => BigDecimal.new("1.00")
99
+ }
100
+ result = TestResource.new.replace_params(options)
101
+ result.each do |k,v|
102
+ v.should be_a Float
103
+ end
104
+ end
105
+
106
+ it "should correctly replace BSON::Timestamps" do
107
+ options = {
108
+ "option" => BSON::Timestamp.new(324244, 12)
109
+ }
110
+ result = TestResource.new.replace_params(options)
111
+ result.each do |k, v|
112
+ v["seconds"].should == 324244
113
+ v["increment"].should == 12
114
+ end
115
+ end
116
+
117
+ it "should correctly respond to to_hash" do
118
+ resource = TestResource.new({:first => "first", :second => "second", :third => "third"})
119
+ hash = resource.to_hash
120
+ hash.size.should == 5
121
+ hash[:first].should == "first"
122
+ hash[:second].should == "second"
123
+ hash[:third].should == "third"
124
+ hash[:at].should == ""
125
+ end
126
+ end
127
+
128
+ context "with respect to times and ranges" do
129
+ context "when DateTime days are given" do
130
+ it "should return a correct range" do
131
+ day = DateTime.civil(2012, 1, 19, 10, 0)
132
+ range = TestResource.send(:day_to_range, day)
133
+ range.first.should == DateTime.civil(2012, 1, 19).to_time.gmtime
134
+ range.last.should == DateTime.civil(2012, 1, 20).to_time.gmtime
135
+ end
136
+
137
+ it "should return an Array of 2 Time objects" do
138
+ day = DateTime.civil(2012, 1, 19, 10, 0)
139
+ range = TestResource.send(:day_to_range, day)
140
+ range.first.should be_a Time
141
+ range.last.should be_a Time
142
+ end
143
+ end
144
+
145
+ context "when Date days are given" do
146
+ it "should return a correct range" do
147
+ day = Date.parse("2012-1-19")
148
+ range = TestResource.send(:day_to_range, day)
149
+ range.first.should == Date.parse("2012-1-19").to_time.gmtime
150
+ range.last.should == Date.parse("2012-1-20").to_time.gmtime
151
+ end
152
+
153
+ it "should return an Array of 2 Time objects" do
154
+ day = Date.parse("2012-1-19")
155
+ range = TestResource.send(:day_to_range, day)
156
+ range.first.should be_a Time
157
+ range.last.should be_a Time
158
+ end
159
+ end
160
+
161
+ context "when Time days are given" do
162
+ it "should return a correct range" do
163
+ day = DateTime.civil(2012, 1, 19, 10, 0).to_time
164
+ range = TestResource.send(:day_to_range, day)
165
+ range.first.should == DateTime.civil(2012, 1, 19).to_time.gmtime
166
+ range.last.should == DateTime.civil(2012, 1, 20).to_time.gmtime
167
+ end
168
+
169
+ it "should return an Array of 2 Time objects" do
170
+ day = DateTime.civil(2012, 1, 19, 10, 0).to_time
171
+ range = TestResource.send(:day_to_range, day)
172
+ range.first.should be_a Time
173
+ range.last.should be_a Time
174
+ end
175
+ end
176
+
177
+ context "when ranges are changed to queries" do
178
+ before :each do
179
+ @range = TestResource.send(:day_to_range, DateTime.civil(2012, 1, 19))
180
+ @query = TestResource.send(:date_range_to_query, @range)
181
+ end
182
+
183
+ it "should scope the query to the 'at' attribute" do
184
+ @query.size.should == 1
185
+ @query[:at].should be_a Hash
186
+ end
187
+
188
+ it "should use the first of the range for the greater equal part" do
189
+ @query[:at][:$gte].should == @range.first
190
+ end
191
+
192
+ it "should use the last of the range for the smaller than part" do
193
+ @query[:at][:$lt].should == @range.last
194
+ end
195
+ end
196
+ end
197
+
198
+ context "with respect to indices" do
199
+ before :each do
200
+ class TestResource2
201
+ include Mordor::Resource
202
+ end
203
+
204
+ [TestResource, TestResource2].each do |klass|
205
+ klass.class_eval do
206
+ def self.reset_ensure_count
207
+ @count = 0
208
+ end
209
+
210
+ def self.ensure_count
211
+ @count ||= 0
212
+ end
213
+
214
+ def self.ensure_count=(val)
215
+ @count = val
216
+ end
217
+
218
+ private
219
+
220
+ def self.do_ensure_index(attribute)
221
+ collection.ensure_index( [ [attribute.to_s, index_types[attribute]] ] )
222
+ end
223
+
224
+ def self.ensure_indices
225
+ indices.each do |index|
226
+ ensure_index(index)
227
+ end
228
+ end
229
+
230
+ def self.ensure_index(attribute)
231
+ self.ensure_count += 1
232
+ self.do_ensure_index(attribute)
233
+ end
234
+ end
235
+ end
236
+ end
237
+
238
+ it "should call ensure_index on the collection for each index when a query is performed" do
239
+ TestResource.create({:first => 'first', :second => 'second', :third => 'third'})
240
+ TestResource.reset_ensure_count
241
+ TestResource.all()
242
+ TestResource.ensure_count.should == 2 # For each index
243
+ end
244
+
245
+ it "should call ensure_index on the collection whenever a resource is destroyed" do
246
+ resource = TestResource.create({:first => 'first', :second => 'second', :third => 'third'})
247
+ TestResource.reset_ensure_count
248
+ resource.destroy
249
+ TestResource.ensure_count.should == 2 # For each index
250
+ end
251
+
252
+ it "should call ensure index for each index attribute on creation" do
253
+ TestResource2.class_eval do
254
+ attribute :test_attribute, :index => true
255
+ end
256
+
257
+ TestResource2.ensure_count.should == 1
258
+ end
259
+ end
260
+
261
+ context "with respect to creating" do
262
+ before :each do
263
+ @resource = TestResource.create({:first => "first", :second => "second", :third => "third"})
264
+ end
265
+
266
+ it "should be possible to create a resource" do
267
+ @resource.should be_saved
268
+ end
269
+
270
+ it "should be possible to retrieve created resources" do
271
+ res = TestResource.get(@resource._id)
272
+ res.should_not be_nil
273
+ res.first.should eql @resource.first
274
+ res.second.should eql @resource.second
275
+ res.third.should eql @resource.third
276
+ res._id.should eql @resource._id
277
+ end
278
+ end
279
+
280
+ context "with respect to destroying" do
281
+ before :each do
282
+ @resource = TestResource.create({:first => "first", :second => "second", :third => "third"})
283
+ end
284
+
285
+ it "should not create destroyed resources" do
286
+ @resource.should_not be_destroyed
287
+ end
288
+
289
+ it "should be possible to destroy a resource" do
290
+ @resource.should_not be_destroyed
291
+ @resource.destroy
292
+ @resource.should be_destroyed
293
+ end
294
+
295
+ it "should not be possible to retrieve a resource after it has been destroyed" do
296
+ @resource.destroy
297
+ res = TestResource.get(@resource._id)
298
+ res.should be_nil
299
+ end
300
+
301
+ it "should only destroy the current resource" do
302
+ resource2 = TestResource.create({:first => "first2", :second => "second2", :third => "third2"})
303
+ @resource.destroy
304
+ TestResource.get(resource2._id).should_not be_nil
305
+ end
306
+ end
307
+
308
+ context "with respect to saving and retrieving" do
309
+ it "should correctly save resources" do
310
+ resource = TestResource.new({:first => "first", :second => "second"})
311
+ resource.save.should be_true
312
+ resource._id.should_not be_nil
313
+ resource.collection.count.should == 1
314
+ resource.collection.find_one['_id'].should == resource._id
315
+ end
316
+
317
+ it "should correctly update resources" do
318
+ resource = TestResource.new({:first => "first", :second => "second"})
319
+ resource.save.should be_true
320
+ resource._id.should_not be_nil
321
+
322
+ original_id = resource._id
323
+
324
+ resource.collection.count.should == 1
325
+ resource.collection.find_one['_id'].should == resource._id
326
+
327
+ resource.first = "third"
328
+ resource.save.should be_true
329
+ resource._id.should == original_id
330
+ resource.collection.find_one['first'].should == resource.first
331
+ end
332
+
333
+ it "should be able to find resources by their ids" do
334
+ resource = TestResource.new({:first => "first", :second => "second"})
335
+ resource.save.should be_true
336
+ res = TestResource.find_by_id(resource._id)
337
+ res._id.should == resource._id
338
+ res.first.should == resource.first
339
+ res.second.should == resource.second
340
+ end
341
+
342
+ it "should be able to find resources by their ids as strings" do
343
+ resource = TestResource.new({:first => "first", :second => "second"})
344
+ resource.save.should be_true
345
+ res = TestResource.find_by_id(resource._id.to_s)
346
+ res._id.should == resource._id
347
+ res.first.should == resource.first
348
+ res.second.should == resource.second
349
+ end
350
+
351
+ it "should be possible to find resources using queries" do
352
+ resource = TestResource.new({:first => "first", :second => "second"})
353
+ resource.save.should be_true
354
+
355
+ resource2 = TestResource.new({:first => "first", :second => "2nd"})
356
+ resource2.save.should be_true
357
+
358
+ collection = TestResource.find({:first => "first"})
359
+ collection.should_not be_nil
360
+ collection.size.should == 2
361
+
362
+ collection = TestResource.find({:second => "2nd"})
363
+ collection.should_not be_nil
364
+ collection.size.should == 1
365
+ end
366
+
367
+ it "should be possible to query with a limit" do
368
+ resource = TestResource.new({:first => "first", :second => "second"})
369
+ resource.save.should be_true
370
+
371
+ resource2 = TestResource.new({:first => "first", :second => "2nd"})
372
+ resource2.save.should be_true
373
+
374
+ collection = TestResource.find({:first => "first"}, :limit => 1)
375
+ collection.should_not be_nil
376
+ collection.size.should == 1
377
+ end
378
+
379
+ it "should be possible to retrieve all resources" do
380
+ TestResource.all.should_not be_nil
381
+ TestResource.all.size.should == 0
382
+
383
+ resource = TestResource.new({:first => "first", :second => "second"})
384
+ resource.save.should be_true
385
+
386
+ resource2 = TestResource.new({:first => "first", :second => "second"})
387
+ resource2.save.should be_true
388
+
389
+ collection = TestResource.all
390
+ collection.should_not be_nil
391
+ collection.size.should == 2
392
+ end
393
+
394
+ it "should be possible to limit the number of returned resources" do
395
+ TestResource.all.should_not be_nil
396
+ TestResource.all.size.should == 0
397
+
398
+ resource = TestResource.new({:first => "first", :second => "second"})
399
+ resource.save.should be_true
400
+
401
+ resource2 = TestResource.new({:first => "first", :second => "second"})
402
+ resource2.save.should be_true
403
+
404
+ collection = TestResource.all(:limit => 1)
405
+ collection.should_not be_nil
406
+ collection.size.should == 1
407
+ end
408
+
409
+ describe "with respect to passing extra query parameters to finder methods" do
410
+ before :each do
411
+ 5.times do |i|
412
+ TestResource.create({:first => "first", :second => "second-#{i}", :third => "third-#{i}", :at => (Date.today).to_time})
413
+ end
414
+ end
415
+
416
+ it "should raise an argument exception if the :value option is omitted from a complex finder query" do
417
+ collection = TestResource.find_by_first("first")
418
+ collection.size.should == 5
419
+
420
+ lambda{ TestResource.find_by_first({:second => "second-2"})}.should raise_error
421
+ end
422
+
423
+ it "should be possible to add extra query clauses to the find_by_day method" do
424
+ collection = TestResource.find_by_day(Date.today)
425
+ collection.size.should == 5
426
+
427
+ collection = TestResource.find_by_day({:value => Date.today, :second => "second-1"})
428
+ collection.size.should == 1
429
+ resource = collection.first
430
+ resource.first.should == "first"
431
+ resource.at.should == Date.today.to_time
432
+ end
433
+
434
+ it "should be possible to add more complex query clauses to the find_by_day method" do
435
+ collection = TestResource.find_by_day(Date.today)
436
+ collection.size.should == 5
437
+
438
+ collection = TestResource.find_by_day({:value => Date.today, :second => {:$in => ["second-1", "second-2"]}})
439
+ collection.size.should == 2
440
+ collection.each do |res|
441
+ res.at.should == Date.today.to_time
442
+ ["second-1", "second-2"].should include res.second
443
+ end
444
+
445
+ end
446
+
447
+ it "should be possible to add extra query clauses to a finder method" do
448
+ collection = TestResource.find_by_first("first")
449
+ collection.size.should == 5
450
+
451
+ collection = TestResource.find_by_first({:value => "first", :second => "second-2"})
452
+ collection.size.should == 1
453
+ resource = collection.first
454
+ resource.first.should == "first"
455
+ resource.second.should == "second-2"
456
+ end
457
+
458
+ it "should be possible to add more complex query clauses to a finder method" do
459
+ collection = TestResource.find_by_first("first")
460
+ collection.size.should == 5
461
+
462
+ collection = TestResource.find_by_first({:value => "first", :second => {:$in => ["second-1", "second-2"]}})
463
+ collection.size.should == 2
464
+ collection.each do |res|
465
+ res.first.should == "first"
466
+ ["second-1", "second-2"].should include res.second
467
+ end
468
+ end
469
+ end
470
+ end
471
+
472
+ context "with respect to retrieving by day" do
473
+ before :each do
474
+ class TestTimedResource
475
+ include Mordor::Resource
476
+
477
+ attribute :first
478
+ attribute :at
479
+ end
480
+ end
481
+
482
+ it "should be possible to retrieve a Resource by day" do
483
+ TestTimedResource.create({:first => "hallo", :at => DateTime.civil(2011, 11, 11, 11, 11)})
484
+
485
+ col = TestTimedResource.find_by_day(DateTime.civil(2011,11,11))
486
+ col.size.should == 1
487
+ col.first.first.should eql "hallo"
488
+ end
489
+
490
+ it "should not retrieve resources from other days" do
491
+ TestTimedResource.create({:first => "hallo", :at => DateTime.civil(2011, 11, 11, 11, 11)})
492
+
493
+ col = TestTimedResource.find_by_day(DateTime.civil(2011,11,10))
494
+ col.size.should == 0
495
+ end
496
+ end
497
+
498
+ context "with respect to collections" do
499
+ it "should correctly return a collection name" do
500
+ TestResource.collection_name.should == "testresources"
501
+ end
502
+
503
+ it "should be connected to a database" do
504
+ TestResource.database.should_not be_nil
505
+ end
506
+ end
507
+
508
+ context "with respect to not finding something" do
509
+ it "should just return an empty collection when a collection query doesn't return results" do
510
+ col = TestResource.find_by_day(DateTime.civil(2011, 11, 8))
511
+ col.size.should == 0
512
+ end
513
+
514
+ it "should return nil when an non existing id is queried" do
515
+ resource = TestResource.find_by_id('4eb8f3570e02e10cce000002')
516
+ resource.should be_nil
517
+ end
518
+ end
519
+ end