ardm-do-adapter 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,415 @@
1
+ share_examples_for 'A DataObjects Adapter' do
2
+ before :all do
3
+ raise '+@adapter+ should be defined in before block' unless instance_variable_get('@adapter')
4
+
5
+ @log = StringIO.new
6
+
7
+ @original_logger = DataMapper.logger
8
+ DataMapper.logger = DataMapper::Logger.new(@log, :debug)
9
+
10
+ # set up the adapter after switching the logger so queries can be captured
11
+ @adapter = DataMapper.setup(@adapter.name, @adapter.options)
12
+
13
+ @jruby = !!(RUBY_PLATFORM =~ /java/)
14
+
15
+ @postgres = defined?(DataMapper::Adapters::PostgresAdapter) && @adapter.kind_of?(DataMapper::Adapters::PostgresAdapter)
16
+ @mysql = defined?(DataMapper::Adapters::MysqlAdapter) && @adapter.kind_of?(DataMapper::Adapters::MysqlAdapter)
17
+ @sql_server = defined?(DataMapper::Adapters::SqlserverAdapter) && @adapter.kind_of?(DataMapper::Adapters::SqlserverAdapter)
18
+ @oracle = defined?(DataMapper::Adapters::OracleAdapter) && @adapter.kind_of?(DataMapper::Adapters::OracleAdapter)
19
+ end
20
+
21
+ after :all do
22
+ DataMapper.logger = @original_logger
23
+ end
24
+
25
+ def reset_log
26
+ @log.truncate(0)
27
+ @log.rewind
28
+ end
29
+
30
+ def log_output
31
+ @log.rewind
32
+ output = @log.read
33
+ output.chomp!
34
+ output.gsub!(/\A\s+~ \(\d+[\.,]?\d*\)\s+/, '')
35
+ output.gsub!(/\Acom\.\w+\.jdbc\.JDBC4PreparedStatement@[^:]+:\s+/, '') if @jruby
36
+ output.split($/)
37
+ end
38
+
39
+ def supports_default_values?
40
+ @adapter.send(:supports_default_values?)
41
+ end
42
+
43
+ def supports_returning?
44
+ @adapter.send(:supports_returning?)
45
+ end
46
+
47
+ describe '#create' do
48
+ describe 'serial properties' do
49
+ before :all do
50
+ class ::Article
51
+ include DataMapper::Resource
52
+
53
+ property :id, Serial
54
+
55
+ auto_migrate!
56
+ end
57
+
58
+ reset_log
59
+
60
+ Article.create
61
+ end
62
+
63
+ it 'should not send NULL values' do
64
+ statement = if @mysql
65
+ /\AINSERT INTO `articles` \(\) VALUES \(\)\z/
66
+ elsif @oracle
67
+ /\AINSERT INTO "ARTICLES" \("ID"\) VALUES \(DEFAULT\) RETURNING "ID"/
68
+ elsif supports_default_values? && supports_returning?
69
+ /\AINSERT INTO "articles" DEFAULT VALUES RETURNING \"id\"\z/
70
+ elsif supports_default_values?
71
+ /\AINSERT INTO "articles" DEFAULT VALUES\z/
72
+ else
73
+ /\AINSERT INTO "articles" \(\) VALUES \(\)\z/
74
+ end
75
+
76
+ log_output.first.should =~ statement
77
+ end
78
+ end
79
+
80
+ describe 'properties without a default' do
81
+ before :all do
82
+ class ::Article
83
+ include DataMapper::Resource
84
+
85
+ property :id, Serial
86
+ property :title, String
87
+
88
+ auto_migrate!
89
+ end
90
+
91
+ reset_log
92
+
93
+ Article.create(:id => 1)
94
+ end
95
+
96
+ it 'should not send NULL values' do
97
+ regexp = if @mysql
98
+ /^INSERT INTO `articles` \(`id`\) VALUES \(.{1,2}\)$/i
99
+ elsif @sql_server
100
+ /^SET IDENTITY_INSERT \"articles\" ON INSERT INTO "articles" \("id"\) VALUES \(.{1,2}\) SET IDENTITY_INSERT \"articles\" OFF $/i
101
+ else
102
+ /^INSERT INTO "articles" \("id"\) VALUES \(('.{1,2}'|.{1,2})\)$/i
103
+ end
104
+
105
+ log_output.first.should =~ regexp
106
+ end
107
+ end
108
+ end
109
+
110
+ describe '#select' do
111
+ before :all do
112
+ class ::Article
113
+ include DataMapper::Resource
114
+
115
+ property :name, String, :key => true
116
+ property :author, String, :required => true
117
+
118
+ auto_migrate!
119
+ end
120
+
121
+ @article_model = Article
122
+
123
+ @article_model.create(:name => 'Learning DataMapper', :author => 'Dan Kubb')
124
+ end
125
+
126
+ describe 'when one field specified in SELECT statement' do
127
+ before :all do
128
+ @return = @adapter.select('SELECT name FROM articles')
129
+ end
130
+
131
+ it 'should return an Array' do
132
+ @return.should be_kind_of(Array)
133
+ end
134
+
135
+ it 'should have a single result' do
136
+ @return.size.should == 1
137
+ end
138
+
139
+ it 'should return an Array of values' do
140
+ @return.should == [ 'Learning DataMapper' ]
141
+ end
142
+ end
143
+
144
+ describe 'when more than one field specified in SELECT statement' do
145
+ before :all do
146
+ @return = @adapter.select('SELECT name, author FROM articles')
147
+ end
148
+
149
+ it 'should return an Array' do
150
+ @return.should be_kind_of(Array)
151
+ end
152
+
153
+ it 'should have a single result' do
154
+ @return.size.should == 1
155
+ end
156
+
157
+ it 'should return an Array of Struct objects' do
158
+ @return.first.should be_kind_of(Struct)
159
+ end
160
+
161
+ it 'should return expected values' do
162
+ @return.first.values.should == [ 'Learning DataMapper', 'Dan Kubb' ]
163
+ end
164
+ end
165
+ end
166
+
167
+ describe '#execute' do
168
+ before :all do
169
+ class ::Article
170
+ include DataMapper::Resource
171
+
172
+ property :name, String, :key => true
173
+ property :author, String, :required => true
174
+
175
+ auto_migrate!
176
+ end
177
+
178
+ @article_model = Article
179
+ end
180
+
181
+ before :all do
182
+ @result = @adapter.execute('INSERT INTO articles (name, author) VALUES(?, ?)', 'Learning DataMapper', 'Dan Kubb')
183
+ end
184
+
185
+ it 'should return a DataObjects::Result' do
186
+ @result.should be_kind_of(DataObjects::Result)
187
+ end
188
+
189
+ it 'should affect 1 row' do
190
+ @result.affected_rows.should == 1
191
+ end
192
+
193
+ it 'should not have an insert_id' do
194
+ pending_if 'Inconsistent insert_id results', !(@postgres || @mysql || @oracle) do
195
+ @result.insert_id.should be_nil
196
+ end
197
+ end
198
+ end
199
+
200
+ describe '#read' do
201
+ before :all do
202
+ class ::Article
203
+ include DataMapper::Resource
204
+
205
+ property :name, String, :key => true
206
+ property :description, String, :required => false
207
+
208
+ belongs_to :parent, self, :required => false
209
+ has n, :children, self, :inverse => :parent
210
+
211
+ auto_migrate!
212
+ end
213
+
214
+ class ::Publisher
215
+ include DataMapper::Resource
216
+
217
+ property :name, String, :key => true
218
+
219
+ auto_migrate!
220
+ end
221
+
222
+ class ::Author
223
+ include DataMapper::Resource
224
+
225
+ property :name, String, :key => true
226
+
227
+ belongs_to :article
228
+ belongs_to :publisher
229
+
230
+ auto_migrate!
231
+ end
232
+
233
+ @article_model = Article
234
+ @publisher_model = Publisher
235
+ @author_model = Author
236
+ end
237
+
238
+ describe 'with a raw query' do
239
+ before :all do
240
+ @article_model.create(:name => 'Test', :description => 'Description').should be_saved
241
+ @article_model.create(:name => 'NoDescription').should be_saved
242
+
243
+ @query = DataMapper::Query.new(@repository, @article_model, :conditions => [ 'description IS NOT NULL' ])
244
+
245
+ @return = @adapter.read(@query)
246
+ end
247
+
248
+ it 'should return an Array of Hashes' do
249
+ @return.should be_kind_of(Array)
250
+ @return.all? { |entry| entry.should be_kind_of(Hash) }
251
+ end
252
+
253
+ it 'should return expected values' do
254
+ @return.should == [ { @article_model.properties[:name] => 'Test',
255
+ @article_model.properties[:description] => 'Description',
256
+ @article_model.properties[:parent_name] => nil } ]
257
+ end
258
+ end
259
+
260
+ describe 'with a raw query with a bind value mismatch' do
261
+ before :all do
262
+ @article_model.create(:name => 'Test').should be_saved
263
+
264
+ @query = DataMapper::Query.new(@repository, @article_model, :conditions => [ 'name IS NOT NULL', nil ])
265
+ end
266
+
267
+ it 'should raise an error' do
268
+ lambda {
269
+ @adapter.read(@query)
270
+ }.should raise_error(ArgumentError, 'Binding mismatch: 1 for 0')
271
+ end
272
+ end
273
+
274
+ describe 'with a Collection bind value' do
275
+ describe 'with an inclusion comparison' do
276
+ before :all do
277
+ 5.times do |index|
278
+ @article_model.create(:name => "Test #{index}", :parent => @article_model.last).should be_saved
279
+ end
280
+
281
+ @parents = @article_model.all
282
+ @query = DataMapper::Query.new(@repository, @article_model, :parent => @parents)
283
+
284
+ @expected = @article_model.all[1, 4].map { |article| article.attributes(:property) }
285
+ end
286
+
287
+ describe 'that is not loaded' do
288
+ before :all do
289
+ reset_log
290
+ @return = @adapter.read(@query)
291
+ end
292
+
293
+ it 'should return an Array of Hashes' do
294
+ @return.should be_kind_of(Array)
295
+ @return.all? { |entry| entry.should be_kind_of(Hash) }
296
+ end
297
+
298
+ it 'should return expected values' do
299
+ @return.should == @expected
300
+ end
301
+
302
+ it 'should execute one subquery' do
303
+ pending_if @mysql do
304
+ log_output.size.should == 1
305
+ end
306
+ end
307
+ end
308
+
309
+ describe 'that is loaded' do
310
+ before :all do
311
+ @parents.to_a # lazy load the collection
312
+ end
313
+
314
+ before :all do
315
+ reset_log
316
+ @return = @adapter.read(@query)
317
+ end
318
+
319
+ it 'should return an Array of Hashes' do
320
+ @return.should be_kind_of(Array)
321
+ @return.all? { |entry| entry.should be_kind_of(Hash) }
322
+ end
323
+
324
+ it 'should return expected values' do
325
+ @return.should == @expected
326
+ end
327
+
328
+ it 'should execute one query' do
329
+ log_output.size.should == 1
330
+ end
331
+ end
332
+ end
333
+
334
+ describe 'with an negated inclusion comparison' do
335
+ before :all do
336
+ 5.times do |index|
337
+ @article_model.create(:name => "Test #{index}", :parent => @article_model.last).should be_saved
338
+ end
339
+
340
+ @parents = @article_model.all
341
+ @query = DataMapper::Query.new(@repository, @article_model, :parent.not => @parents)
342
+
343
+ @expected = []
344
+ end
345
+
346
+ describe 'that is not loaded' do
347
+ before :all do
348
+ reset_log
349
+ @return = @adapter.read(@query)
350
+ end
351
+
352
+ it 'should return an Array of Hashes' do
353
+ @return.should be_kind_of(Array)
354
+ @return.all? { |entry| entry.should be_kind_of(Hash) }
355
+ end
356
+
357
+ it 'should return expected values' do
358
+ @return.should == @expected
359
+ end
360
+
361
+ it 'should execute one subquery' do
362
+ pending_if @mysql do
363
+ log_output.size.should == 1
364
+ end
365
+ end
366
+ end
367
+
368
+ describe 'that is loaded' do
369
+ before :all do
370
+ @parents.to_a # lazy load the collection
371
+ end
372
+
373
+ before :all do
374
+ reset_log
375
+ @return = @adapter.read(@query)
376
+ end
377
+
378
+ it 'should return an Array of Hashes' do
379
+ @return.should be_kind_of(Array)
380
+ @return.all? { |entry| entry.should be_kind_of(Hash) }
381
+ end
382
+
383
+ it 'should return expected values' do
384
+ @return.should == @expected
385
+ end
386
+
387
+ it 'should execute one query' do
388
+ log_output.size.should == 1
389
+ end
390
+ end
391
+ end
392
+
393
+ end
394
+
395
+ describe 'with a Query Path' do
396
+ subject { @author_model.all(query).to_a }
397
+
398
+ let(:article_name) { 'DataMapper Rocks!' }
399
+ let(:publisher_name) { 'Unbiased Press' }
400
+ let(:query) { { 'article.name' => article_name, 'publisher.name' => publisher_name } }
401
+
402
+ before do
403
+ @author = @author_model.first_or_create(
404
+ :name => 'Dan Kubb',
405
+ :article => { :name => article_name },
406
+ :publisher => { :name => publisher_name }
407
+ )
408
+ end
409
+
410
+ specify { expect { subject }.to_not raise_error }
411
+
412
+ it { should == [ @author ] }
413
+ end
414
+ end
415
+ end
@@ -0,0 +1,5 @@
1
+ module DataMapper
2
+ module DoAdapter
3
+ VERSION = '1.2.0'
4
+ end
5
+ end
data/tasks/yard.rake ADDED
@@ -0,0 +1,9 @@
1
+ begin
2
+ require 'yard'
3
+
4
+ YARD::Rake::YardocTask.new
5
+ rescue LoadError
6
+ task :yard do
7
+ abort 'YARD is not available. In order to run yard, you must: gem install yard'
8
+ end
9
+ end
@@ -0,0 +1,19 @@
1
+ begin
2
+ require 'pathname'
3
+ require 'yardstick/rake/measurement'
4
+ require 'yardstick/rake/verify'
5
+
6
+ # yardstick_measure task
7
+ Yardstick::Rake::Measurement.new
8
+
9
+ # verify_measurements task
10
+ Yardstick::Rake::Verify.new do |verify|
11
+ verify.threshold = 100
12
+ end
13
+ rescue LoadError
14
+ %w[ yardstick_measure verify_measurements ].each do |name|
15
+ task name.to_s do
16
+ abort "Yardstick is not available. In order to run #{name}, you must: gem install yardstick"
17
+ end
18
+ end
19
+ end