ardm-do-adapter 1.2.0

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