dm-do-adapter 1.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,370 @@
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
+ @log.read.chomp.gsub(/^\s+~ \(\d+\.?\d*\)\s+/, '').split("\n")
33
+ end
34
+
35
+ def supports_default_values?
36
+ @adapter.send(:supports_default_values?)
37
+ end
38
+
39
+ def supports_returning?
40
+ @adapter.send(:supports_returning?)
41
+ end
42
+
43
+ describe '#create' do
44
+ describe 'serial properties' do
45
+ before :all do
46
+ class ::Article
47
+ include DataMapper::Resource
48
+
49
+ property :id, Serial
50
+
51
+ auto_migrate!
52
+ end
53
+
54
+ reset_log
55
+
56
+ Article.create
57
+ end
58
+
59
+ it 'should not send NULL values' do
60
+ statement = if @mysql
61
+ /\AINSERT INTO `articles` \(\) VALUES \(\)\z/
62
+ elsif @oracle
63
+ /\AINSERT INTO "ARTICLES" \("ID"\) VALUES \(DEFAULT\) RETURNING "ID"/
64
+ elsif supports_default_values? && supports_returning?
65
+ /\AINSERT INTO "articles" DEFAULT VALUES RETURNING \"id\"\z/
66
+ elsif supports_default_values?
67
+ /\AINSERT INTO "articles" DEFAULT VALUES\z/
68
+ else
69
+ /\AINSERT INTO "articles" \(\) VALUES \(\)\z/
70
+ end
71
+
72
+ log_output.first.should =~ statement
73
+ end
74
+ end
75
+
76
+ describe 'properties without a default' do
77
+ before :all do
78
+ class ::Article
79
+ include DataMapper::Resource
80
+
81
+ property :id, Serial
82
+ property :title, String
83
+
84
+ auto_migrate!
85
+ end
86
+
87
+ reset_log
88
+
89
+ Article.create(:id => 1)
90
+ end
91
+
92
+ it 'should not send NULL values' do
93
+ regexp = if @mysql
94
+ /^INSERT INTO `articles` \(`id`\) VALUES \(.{1,2}\)$/i
95
+ elsif @sql_server
96
+ /^SET IDENTITY_INSERT \"articles\" ON INSERT INTO "articles" \("id"\) VALUES \(.{1,2}\) SET IDENTITY_INSERT \"articles\" OFF $/i
97
+ else
98
+ /^INSERT INTO "articles" \("id"\) VALUES \(.{1,2}\)$/i
99
+ end
100
+
101
+ log_output.first.should =~ regexp
102
+ end
103
+ end
104
+ end
105
+
106
+ describe '#select' do
107
+ before :all do
108
+ class ::Article
109
+ include DataMapper::Resource
110
+
111
+ property :name, String, :key => true
112
+ property :author, String, :required => true
113
+
114
+ auto_migrate!
115
+ end
116
+
117
+ @article_model = Article
118
+
119
+ @article_model.create(:name => 'Learning DataMapper', :author => 'Dan Kubb')
120
+ end
121
+
122
+ describe 'when one field specified in SELECT statement' do
123
+ before :all do
124
+ @return = @adapter.select('SELECT name FROM articles')
125
+ end
126
+
127
+ it 'should return an Array' do
128
+ @return.should be_kind_of(Array)
129
+ end
130
+
131
+ it 'should have a single result' do
132
+ @return.size.should == 1
133
+ end
134
+
135
+ it 'should return an Array of values' do
136
+ @return.should == [ 'Learning DataMapper' ]
137
+ end
138
+ end
139
+
140
+ describe 'when more than one field specified in SELECT statement' do
141
+ before :all do
142
+ @return = @adapter.select('SELECT name, author FROM articles')
143
+ end
144
+
145
+ it 'should return an Array' do
146
+ @return.should be_kind_of(Array)
147
+ end
148
+
149
+ it 'should have a single result' do
150
+ @return.size.should == 1
151
+ end
152
+
153
+ it 'should return an Array of Struct objects' do
154
+ @return.first.should be_kind_of(Struct)
155
+ end
156
+
157
+ it 'should return expected values' do
158
+ @return.first.values.should == [ 'Learning DataMapper', 'Dan Kubb' ]
159
+ end
160
+ end
161
+ end
162
+
163
+ describe '#execute' do
164
+ before :all do
165
+ class ::Article
166
+ include DataMapper::Resource
167
+
168
+ property :name, String, :key => true
169
+ property :author, String, :required => true
170
+
171
+ auto_migrate!
172
+ end
173
+
174
+ @article_model = Article
175
+ end
176
+
177
+ before :all do
178
+ @result = @adapter.execute('INSERT INTO articles (name, author) VALUES(?, ?)', 'Learning DataMapper', 'Dan Kubb')
179
+ end
180
+
181
+ it 'should return a DataObjects::Result' do
182
+ @result.should be_kind_of(DataObjects::Result)
183
+ end
184
+
185
+ it 'should affect 1 row' do
186
+ @result.affected_rows.should == 1
187
+ end
188
+
189
+ it 'should not have an insert_id' do
190
+ pending_if 'Inconsistent insert_id results', !(@postgres || @mysql || @oracle) do
191
+ @result.insert_id.should be_nil
192
+ end
193
+ end
194
+ end
195
+
196
+ describe '#read' do
197
+ before :all do
198
+ class ::Article
199
+ include DataMapper::Resource
200
+
201
+ property :name, String, :key => true
202
+ property :description, String, :required => false
203
+
204
+ belongs_to :parent, self, :required => false
205
+ has n, :children, self, :inverse => :parent
206
+
207
+ auto_migrate!
208
+ end
209
+
210
+ @article_model = Article
211
+ end
212
+
213
+ describe 'with a raw query' do
214
+ before :all do
215
+ @article_model.create(:name => 'Test', :description => 'Description').should be_saved
216
+ @article_model.create(:name => 'NoDescription').should be_saved
217
+
218
+ @query = DataMapper::Query.new(@repository, @article_model, :conditions => [ 'description IS NOT NULL' ])
219
+
220
+ @return = @adapter.read(@query)
221
+ end
222
+
223
+ it 'should return an Array of Hashes' do
224
+ @return.should be_kind_of(Array)
225
+ @return.all? { |entry| entry.should be_kind_of(Hash) }
226
+ end
227
+
228
+ it 'should return expected values' do
229
+ @return.should == [ { @article_model.properties[:name] => 'Test',
230
+ @article_model.properties[:description] => 'Description',
231
+ @article_model.properties[:parent_name] => nil } ]
232
+ end
233
+ end
234
+
235
+ describe 'with a raw query with a bind value mismatch' do
236
+ before :all do
237
+ @article_model.create(:name => 'Test').should be_saved
238
+
239
+ @query = DataMapper::Query.new(@repository, @article_model, :conditions => [ 'name IS NOT NULL', nil ])
240
+ end
241
+
242
+ it 'should raise an error' do
243
+ lambda {
244
+ @adapter.read(@query)
245
+ }.should raise_error(ArgumentError, 'Binding mismatch: 1 for 0')
246
+ end
247
+ end
248
+
249
+ describe 'with a Collection bind value' do
250
+ describe 'with an inclusion comparison' do
251
+ before :all do
252
+ 5.times do |index|
253
+ @article_model.create(:name => "Test #{index}", :parent => @article_model.last).should be_saved
254
+ end
255
+
256
+ @parents = @article_model.all
257
+ @query = DataMapper::Query.new(@repository, @article_model, :parent => @parents)
258
+
259
+ @expected = @article_model.all[1, 4].map { |article| article.attributes(:property) }
260
+ end
261
+
262
+ describe 'that is not loaded' do
263
+ before :all do
264
+ reset_log
265
+ @return = @adapter.read(@query)
266
+ end
267
+
268
+ it 'should return an Array of Hashes' do
269
+ @return.should be_kind_of(Array)
270
+ @return.all? { |entry| entry.should be_kind_of(Hash) }
271
+ end
272
+
273
+ it 'should return expected values' do
274
+ @return.should == @expected
275
+ end
276
+
277
+ it 'should execute one subquery' do
278
+ pending_if @mysql do
279
+ log_output.size.should == 1
280
+ end
281
+ end
282
+ end
283
+
284
+ describe 'that is loaded' do
285
+ before :all do
286
+ @parents.to_a # lazy load the collection
287
+ end
288
+
289
+ before :all do
290
+ reset_log
291
+ @return = @adapter.read(@query)
292
+ end
293
+
294
+ it 'should return an Array of Hashes' do
295
+ @return.should be_kind_of(Array)
296
+ @return.all? { |entry| entry.should be_kind_of(Hash) }
297
+ end
298
+
299
+ it 'should return expected values' do
300
+ @return.should == @expected
301
+ end
302
+
303
+ it 'should execute one query' do
304
+ log_output.size.should == 1
305
+ end
306
+ end
307
+ end
308
+
309
+ describe 'with an negated inclusion comparison' do
310
+ before :all do
311
+ 5.times do |index|
312
+ @article_model.create(:name => "Test #{index}", :parent => @article_model.last).should be_saved
313
+ end
314
+
315
+ @parents = @article_model.all
316
+ @query = DataMapper::Query.new(@repository, @article_model, :parent.not => @parents)
317
+
318
+ @expected = []
319
+ end
320
+
321
+ describe 'that is not loaded' do
322
+ before :all do
323
+ reset_log
324
+ @return = @adapter.read(@query)
325
+ end
326
+
327
+ it 'should return an Array of Hashes' do
328
+ @return.should be_kind_of(Array)
329
+ @return.all? { |entry| entry.should be_kind_of(Hash) }
330
+ end
331
+
332
+ it 'should return expected values' do
333
+ @return.should == @expected
334
+ end
335
+
336
+ it 'should execute one subquery' do
337
+ pending_if @mysql do
338
+ log_output.size.should == 1
339
+ end
340
+ end
341
+ end
342
+
343
+ describe 'that is loaded' do
344
+ before :all do
345
+ @parents.to_a # lazy load the collection
346
+ end
347
+
348
+ before :all do
349
+ reset_log
350
+ @return = @adapter.read(@query)
351
+ end
352
+
353
+ it 'should return an Array of Hashes' do
354
+ @return.should be_kind_of(Array)
355
+ @return.all? { |entry| entry.should be_kind_of(Hash) }
356
+ end
357
+
358
+ it 'should return expected values' do
359
+ @return.should == @expected
360
+ end
361
+
362
+ it 'should execute one query' do
363
+ log_output.size.should == 1
364
+ end
365
+ end
366
+ end
367
+
368
+ end
369
+ end
370
+ end
@@ -0,0 +1 @@
1
+ require 'dm-do-adapter/adapter'
@@ -0,0 +1,18 @@
1
+ desc "Support bundling from local source code (allows BUNDLE_GEMFILE=Gemfile.local bundle foo)"
2
+ task :local_gemfile do |t|
3
+
4
+ root = Pathname(__FILE__).dirname.parent
5
+ datamapper = root.parent
6
+
7
+ source_regex = /DATAMAPPER = 'git:\/\/github.com\/datamapper'/
8
+ gem_source_regex = /:git => \"#\{DATAMAPPER\}\/(.+?)(?:\.git)?\"/
9
+
10
+ root.join('Gemfile.local').open('w') do |f|
11
+ root.join('Gemfile').open.each do |line|
12
+ line.sub!(source_regex, "DATAMAPPER = '#{datamapper}'")
13
+ line.sub!(gem_source_regex, ':path => "#{DATAMAPPER}/\1"')
14
+ f.puts line
15
+ end
16
+ end
17
+
18
+ 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
metadata ADDED
@@ -0,0 +1,119 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dm-do-adapter
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: true
5
+ segments:
6
+ - 1
7
+ - 0
8
+ - 0
9
+ - rc1
10
+ version: 1.0.0.rc1
11
+ platform: ruby
12
+ authors:
13
+ - Dan Kubb
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-05-19 00:00:00 -07:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: data_objects
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - ~>
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 0
30
+ - 10
31
+ - 1
32
+ version: 0.10.1
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: dm-core
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ~>
41
+ - !ruby/object:Gem::Version
42
+ segments:
43
+ - 1
44
+ - 0
45
+ - 0
46
+ - rc1
47
+ version: 1.0.0.rc1
48
+ type: :runtime
49
+ version_requirements: *id002
50
+ - !ruby/object:Gem::Dependency
51
+ name: rspec
52
+ prerelease: false
53
+ requirement: &id003 !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ~>
56
+ - !ruby/object:Gem::Version
57
+ segments:
58
+ - 1
59
+ - 3
60
+ version: "1.3"
61
+ type: :development
62
+ version_requirements: *id003
63
+ description: DataObjects Adapter for DataMapper
64
+ email: dan.kubb@gmail.com
65
+ executables: []
66
+
67
+ extensions: []
68
+
69
+ extra_rdoc_files:
70
+ - LICENSE
71
+ - README.rdoc
72
+ files:
73
+ - .gitignore
74
+ - Gemfile
75
+ - LICENSE
76
+ - README.rdoc
77
+ - Rakefile
78
+ - VERSION
79
+ - dm-do-adapter.gemspec
80
+ - lib/dm-do-adapter.rb
81
+ - lib/dm-do-adapter/adapter.rb
82
+ - lib/dm-do-adapter/spec/shared_spec.rb
83
+ - tasks/local_gemfile.rake
84
+ - tasks/yard.rake
85
+ - tasks/yardstick.rake
86
+ has_rdoc: true
87
+ homepage: http://github.com/datamapper/dm-do-adapter
88
+ licenses: []
89
+
90
+ post_install_message:
91
+ rdoc_options:
92
+ - --charset=UTF-8
93
+ require_paths:
94
+ - lib
95
+ required_ruby_version: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ segments:
100
+ - 0
101
+ version: "0"
102
+ required_rubygems_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ">"
105
+ - !ruby/object:Gem::Version
106
+ segments:
107
+ - 1
108
+ - 3
109
+ - 1
110
+ version: 1.3.1
111
+ requirements: []
112
+
113
+ rubyforge_project:
114
+ rubygems_version: 1.3.6
115
+ signing_key:
116
+ specification_version: 3
117
+ summary: DataObjects Adapter for DataMapper
118
+ test_files: []
119
+