sequel 2.2.0 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. data/CHANGELOG +1551 -4
  2. data/README +306 -19
  3. data/Rakefile +84 -56
  4. data/bin/sequel +106 -0
  5. data/doc/cheat_sheet.rdoc +225 -0
  6. data/doc/dataset_filtering.rdoc +182 -0
  7. data/lib/sequel_core.rb +136 -0
  8. data/lib/sequel_core/adapters/adapter_skeleton.rb +54 -0
  9. data/lib/sequel_core/adapters/ado.rb +80 -0
  10. data/lib/sequel_core/adapters/db2.rb +148 -0
  11. data/lib/sequel_core/adapters/dbi.rb +117 -0
  12. data/lib/sequel_core/adapters/informix.rb +78 -0
  13. data/lib/sequel_core/adapters/jdbc.rb +186 -0
  14. data/lib/sequel_core/adapters/jdbc/mysql.rb +55 -0
  15. data/lib/sequel_core/adapters/jdbc/postgresql.rb +66 -0
  16. data/lib/sequel_core/adapters/jdbc/sqlite.rb +47 -0
  17. data/lib/sequel_core/adapters/mysql.rb +231 -0
  18. data/lib/sequel_core/adapters/odbc.rb +155 -0
  19. data/lib/sequel_core/adapters/odbc_mssql.rb +106 -0
  20. data/lib/sequel_core/adapters/openbase.rb +64 -0
  21. data/lib/sequel_core/adapters/oracle.rb +170 -0
  22. data/lib/sequel_core/adapters/postgres.rb +199 -0
  23. data/lib/sequel_core/adapters/shared/mysql.rb +275 -0
  24. data/lib/sequel_core/adapters/shared/postgres.rb +351 -0
  25. data/lib/sequel_core/adapters/shared/sqlite.rb +146 -0
  26. data/lib/sequel_core/adapters/sqlite.rb +138 -0
  27. data/lib/sequel_core/connection_pool.rb +194 -0
  28. data/lib/sequel_core/core_ext.rb +203 -0
  29. data/lib/sequel_core/core_sql.rb +184 -0
  30. data/lib/sequel_core/database.rb +471 -0
  31. data/lib/sequel_core/database/schema.rb +156 -0
  32. data/lib/sequel_core/dataset.rb +457 -0
  33. data/lib/sequel_core/dataset/callback.rb +13 -0
  34. data/lib/sequel_core/dataset/convenience.rb +245 -0
  35. data/lib/sequel_core/dataset/pagination.rb +96 -0
  36. data/lib/sequel_core/dataset/query.rb +41 -0
  37. data/lib/sequel_core/dataset/schema.rb +15 -0
  38. data/lib/sequel_core/dataset/sql.rb +889 -0
  39. data/lib/sequel_core/deprecated.rb +26 -0
  40. data/lib/sequel_core/exceptions.rb +42 -0
  41. data/lib/sequel_core/migration.rb +187 -0
  42. data/lib/sequel_core/object_graph.rb +216 -0
  43. data/lib/sequel_core/pretty_table.rb +71 -0
  44. data/lib/sequel_core/schema.rb +2 -0
  45. data/lib/sequel_core/schema/generator.rb +239 -0
  46. data/lib/sequel_core/schema/sql.rb +325 -0
  47. data/lib/sequel_core/sql.rb +812 -0
  48. data/lib/sequel_model.rb +5 -1
  49. data/lib/sequel_model/association_reflection.rb +3 -8
  50. data/lib/sequel_model/base.rb +15 -10
  51. data/lib/sequel_model/inflector.rb +3 -5
  52. data/lib/sequel_model/plugins.rb +1 -1
  53. data/lib/sequel_model/record.rb +11 -3
  54. data/lib/sequel_model/schema.rb +4 -4
  55. data/lib/sequel_model/validations.rb +6 -1
  56. data/spec/adapters/ado_spec.rb +17 -0
  57. data/spec/adapters/informix_spec.rb +96 -0
  58. data/spec/adapters/mysql_spec.rb +764 -0
  59. data/spec/adapters/oracle_spec.rb +222 -0
  60. data/spec/adapters/postgres_spec.rb +441 -0
  61. data/spec/adapters/spec_helper.rb +7 -0
  62. data/spec/adapters/sqlite_spec.rb +400 -0
  63. data/spec/integration/dataset_test.rb +51 -0
  64. data/spec/integration/eager_loader_test.rb +702 -0
  65. data/spec/integration/schema_test.rb +102 -0
  66. data/spec/integration/spec_helper.rb +44 -0
  67. data/spec/integration/type_test.rb +43 -0
  68. data/spec/rcov.opts +2 -0
  69. data/spec/sequel_core/connection_pool_spec.rb +363 -0
  70. data/spec/sequel_core/core_ext_spec.rb +156 -0
  71. data/spec/sequel_core/core_sql_spec.rb +427 -0
  72. data/spec/sequel_core/database_spec.rb +964 -0
  73. data/spec/sequel_core/dataset_spec.rb +2977 -0
  74. data/spec/sequel_core/expression_filters_spec.rb +346 -0
  75. data/spec/sequel_core/migration_spec.rb +261 -0
  76. data/spec/sequel_core/object_graph_spec.rb +234 -0
  77. data/spec/sequel_core/pretty_table_spec.rb +58 -0
  78. data/spec/sequel_core/schema_generator_spec.rb +122 -0
  79. data/spec/sequel_core/schema_spec.rb +497 -0
  80. data/spec/sequel_core/spec_helper.rb +51 -0
  81. data/spec/{association_reflection_spec.rb → sequel_model/association_reflection_spec.rb} +6 -6
  82. data/spec/{associations_spec.rb → sequel_model/associations_spec.rb} +47 -18
  83. data/spec/{base_spec.rb → sequel_model/base_spec.rb} +2 -1
  84. data/spec/{caching_spec.rb → sequel_model/caching_spec.rb} +0 -0
  85. data/spec/{dataset_methods_spec.rb → sequel_model/dataset_methods_spec.rb} +13 -1
  86. data/spec/{eager_loading_spec.rb → sequel_model/eager_loading_spec.rb} +75 -14
  87. data/spec/{hooks_spec.rb → sequel_model/hooks_spec.rb} +4 -4
  88. data/spec/sequel_model/inflector_spec.rb +119 -0
  89. data/spec/{model_spec.rb → sequel_model/model_spec.rb} +30 -11
  90. data/spec/{plugins_spec.rb → sequel_model/plugins_spec.rb} +0 -0
  91. data/spec/{record_spec.rb → sequel_model/record_spec.rb} +47 -6
  92. data/spec/{schema_spec.rb → sequel_model/schema_spec.rb} +18 -4
  93. data/spec/{spec_helper.rb → sequel_model/spec_helper.rb} +3 -2
  94. data/spec/{validations_spec.rb → sequel_model/validations_spec.rb} +37 -17
  95. data/spec/spec_config.rb +9 -0
  96. data/spec/spec_config.rb.example +10 -0
  97. metadata +110 -37
  98. data/spec/inflector_spec.rb +0 -34
@@ -0,0 +1,7 @@
1
+ require 'rubygems'
2
+ unless Object.const_defined?('Sequel')
3
+ $:.unshift(File.join(File.dirname(__FILE__), "../../lib/"))
4
+ require 'sequel_core'
5
+ Sequel.quote_identifiers = false
6
+ end
7
+ require File.join(File.dirname(__FILE__), '../spec_config.rb')
@@ -0,0 +1,400 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper.rb')
2
+
3
+ unless defined?(SQLITE_DB)
4
+ SQLITE_URL = 'sqlite:/' unless defined? SQLITE_URL
5
+ SQLITE_DB = Sequel.connect(ENV['SEQUEL_SQLITE_SPEC_DB']||SQLITE_URL)
6
+ end
7
+
8
+ context "An SQLite database" do
9
+ before do
10
+ @db = SQLITE_DB
11
+ end
12
+
13
+ if SQLITE_DB.auto_vacuum == :none
14
+ specify "should support getting pragma values" do
15
+ @db.pragma_get(:auto_vacuum).to_s.should == '0'
16
+ end
17
+
18
+ specify "should support setting pragma values" do
19
+ @db.pragma_set(:auto_vacuum, '1')
20
+ @db.pragma_get(:auto_vacuum).to_s.should == '1'
21
+ @db.pragma_set(:auto_vacuum, '2')
22
+ @db.pragma_get(:auto_vacuum).to_s.should == '2'
23
+ end
24
+
25
+ specify "should support getting and setting the auto_vacuum pragma" do
26
+ @db.auto_vacuum = :full
27
+ @db.auto_vacuum.should == :full
28
+ @db.auto_vacuum = :incremental
29
+ @db.auto_vacuum.should == :incremental
30
+
31
+ proc {@db.auto_vacuum = :invalid}.should raise_error(Sequel::Error)
32
+ end
33
+ end
34
+
35
+ specify "should provide a list of existing tables" do
36
+ @db.drop_table(:testing) rescue nil
37
+ @db.tables.should be_a_kind_of(Array)
38
+ @db.tables.should_not include(:testing)
39
+ @db.create_table! :testing do
40
+ text :name
41
+ end
42
+ @db.tables.should include(:testing)
43
+ end
44
+
45
+ specify "should support getting and setting the synchronous pragma" do
46
+ @db.synchronous = :off
47
+ @db.synchronous.should == :off
48
+ @db.synchronous = :normal
49
+ @db.synchronous.should == :normal
50
+ @db.synchronous = :full
51
+ @db.synchronous.should == :full
52
+
53
+ proc {@db.synchronous = :invalid}.should raise_error(Sequel::Error)
54
+ end
55
+
56
+ specify "should support getting and setting the temp_store pragma" do
57
+ @db.temp_store = :default
58
+ @db.temp_store.should == :default
59
+ @db.temp_store = :file
60
+ @db.temp_store.should == :file
61
+ @db.temp_store = :memory
62
+ @db.temp_store.should == :memory
63
+
64
+ proc {@db.temp_store = :invalid}.should raise_error(Sequel::Error)
65
+ end
66
+
67
+ specify "should be able to execute transactions" do
68
+ @db.transaction do
69
+ @db.create_table!(:t) {text :name}
70
+ end
71
+
72
+ @db.tables.should include(:t)
73
+
74
+ proc {@db.transaction do
75
+ @db.create_table!(:u) {text :name}
76
+ raise ArgumentError
77
+ end}.should raise_error(ArgumentError)
78
+ # no commit
79
+ @db.tables.should_not include(:u)
80
+
81
+ proc {@db.transaction do
82
+ @db.create_table!(:v) {text :name}
83
+ raise Sequel::Error::Rollback
84
+ end}.should_not raise_error
85
+ # no commit
86
+ @db.tables.should_not include(:r)
87
+ end
88
+
89
+ specify "should support nested transactions" do
90
+ @db.transaction do
91
+ @db.transaction do
92
+ @db.create_table!(:t) {text :name}
93
+ end
94
+ end
95
+
96
+ @db.tables.should include(:t)
97
+
98
+ proc {@db.transaction do
99
+ @db.create_table!(:v) {text :name}
100
+ @db.transaction do
101
+ raise Sequel::Error::Rollback # should roll back the top-level transaction
102
+ end
103
+ end}.should_not raise_error
104
+ # no commit
105
+ @db.tables.should_not include(:v)
106
+ end
107
+
108
+ specify "should handle returning inside of transaction by committing" do
109
+ @db.create_table!(:items2){text :name}
110
+ def @db.ret_commit
111
+ transaction do
112
+ self[:items2] << {:name => 'abc'}
113
+ return
114
+ self[:items2] << {:name => 'd'}
115
+ end
116
+ end
117
+ @db[:items2].count.should == 0
118
+ @db.ret_commit
119
+ @db[:items2].count.should == 1
120
+ @db.ret_commit
121
+ @db[:items2].count.should == 2
122
+ proc do
123
+ @db.transaction do
124
+ raise Interrupt, 'asdf'
125
+ end
126
+ end.should raise_error(Interrupt)
127
+
128
+ @db[:items2].count.should == 2
129
+ end
130
+
131
+ specify "should support timestamps" do
132
+ t1 = Time.at(Time.now.to_i) #normalize time
133
+ @db.create_table!(:time) {timestamp :t}
134
+ @db[:time] << {:t => t1}
135
+ x = @db[:time].first[:t]
136
+ [t1.iso8601, t1.to_s].should include(x.respond_to?(:iso8601) ? x.iso8601 : x.to_s)
137
+ end
138
+
139
+ specify "should support sequential primary keys" do
140
+ @db.create_table!(:with_pk) {primary_key :id; text :name}
141
+ @db[:with_pk] << {:name => 'abc'}
142
+ @db[:with_pk] << {:name => 'def'}
143
+ @db[:with_pk] << {:name => 'ghi'}
144
+ @db[:with_pk].order(:name).all.should == [
145
+ {:id => 1, :name => 'abc'},
146
+ {:id => 2, :name => 'def'},
147
+ {:id => 3, :name => 'ghi'}
148
+ ]
149
+ end
150
+
151
+ specify "should catch invalid SQL errors and raise them as Error" do
152
+ proc {@db.execute 'blah blah'}.should raise_error(Sequel::Error)
153
+ proc {@db.execute_insert 'blah blah'}.should raise_error(Sequel::Error)
154
+ end
155
+
156
+ specify "should not swallow non-SQLite based exceptions" do
157
+ proc {@db.pool.hold{raise Interrupt, "test"}}.should raise_error(Interrupt)
158
+ end
159
+
160
+ specify "should correctly parse the schema" do
161
+ @db.create_table!(:time2) {timestamp :t}
162
+ @db.schema(:time2, :reload=>true).should == [[:t, {:type=>:datetime, :allow_null=>true, :max_chars=>nil, :default=>nil, :db_type=>"timestamp", :numeric_precision=>nil, :primary_key=>false}]]
163
+ end
164
+
165
+ specify "should get the schema all database tables if no table name is used" do
166
+ @db.create_table!(:time2) {timestamp :t}
167
+ @db.schema(:time2, :reload=>true).should == @db.schema(nil, :reload=>true)[:time]
168
+ end
169
+ end
170
+
171
+ context "An SQLite dataset" do
172
+ setup do
173
+ SQLITE_DB.create_table! :items do
174
+ integer :id, :primary_key => true, :auto_increment => true
175
+ text :name
176
+ float :value
177
+ end
178
+ @d = SQLITE_DB[:items]
179
+ @d.delete # remove all records
180
+ end
181
+
182
+ specify "should return the correct records" do
183
+ @d.to_a.should == []
184
+ @d << {:name => 'abc', :value => 1.23}
185
+ @d << {:name => 'abc', :value => 4.56}
186
+ @d << {:name => 'def', :value => 7.89}
187
+ @d.select(:name, :value).to_a.sort_by {|h| h[:value]}.should == [
188
+ {:name => 'abc', :value => 1.23},
189
+ {:name => 'abc', :value => 4.56},
190
+ {:name => 'def', :value => 7.89}
191
+ ]
192
+ end
193
+
194
+ specify "should return the correct record count" do
195
+ @d.count.should == 0
196
+ @d << {:name => 'abc', :value => 1.23}
197
+ @d << {:name => 'abc', :value => 4.56}
198
+ @d << {:name => 'def', :value => 7.89}
199
+ @d.count.should == 3
200
+ end
201
+
202
+ specify "should return the last inserted id when inserting records" do
203
+ id = @d << {:name => 'abc', :value => 1.23}
204
+ id.should == @d.first[:id]
205
+ end
206
+
207
+ specify "should update records correctly" do
208
+ @d << {:name => 'abc', :value => 1.23}
209
+ @d << {:name => 'abc', :value => 4.56}
210
+ @d << {:name => 'def', :value => 7.89}
211
+ @d.filter(:name => 'abc').update(:value => 5.3)
212
+
213
+ # the third record should stay the same
214
+ @d[:name => 'def'][:value].should == 7.89
215
+ @d.filter(:value => 5.3).count.should == 2
216
+ end
217
+
218
+ specify "should delete records correctly" do
219
+ @d << {:name => 'abc', :value => 1.23}
220
+ @d << {:name => 'abc', :value => 4.56}
221
+ @d << {:name => 'def', :value => 7.89}
222
+ @d.filter(:name => 'abc').delete
223
+
224
+ @d.count.should == 1
225
+ @d.first[:name].should == 'def'
226
+ end
227
+
228
+ specify "should handle string pattern matches correctly" do
229
+ @d.literal(:x.like('a')).should == "(x LIKE 'a')"
230
+ @d.literal(~:x.like('a')).should == "NOT (x LIKE 'a')"
231
+ @d.literal(:x.ilike('a')).should == "(x LIKE 'a')"
232
+ @d.literal(~:x.ilike('a')).should == "NOT (x LIKE 'a')"
233
+ end
234
+
235
+ specify "should raise errors if given a regexp pattern match" do
236
+ proc{@d.literal(:x.like(/a/))}.should raise_error(Sequel::Error)
237
+ proc{@d.literal(~:x.like(/a/))}.should raise_error(Sequel::Error)
238
+ proc{@d.literal(:x.like(/a/i))}.should raise_error(Sequel::Error)
239
+ proc{@d.literal(~:x.like(/a/i))}.should raise_error(Sequel::Error)
240
+ end
241
+ end
242
+
243
+ context "An SQLite dataset" do
244
+ setup do
245
+ SQLITE_DB.create_table! :items do
246
+ integer :id, :primary_key => true, :auto_increment => true
247
+ text :name
248
+ float :value
249
+ end
250
+ @d = SQLITE_DB[:items]
251
+ @d.delete # remove all records
252
+ @d << {:name => 'abc', :value => 1.23}
253
+ @d << {:name => 'def', :value => 4.56}
254
+ @d << {:name => 'ghi', :value => 7.89}
255
+ end
256
+
257
+ specify "should correctly return avg" do
258
+ @d.avg(:value).to_s.should == ((1.23 + 4.56 + 7.89) / 3).to_s
259
+ end
260
+
261
+ specify "should correctly return sum" do
262
+ @d.sum(:value).to_s.should == (1.23 + 4.56 + 7.89).to_s
263
+ end
264
+
265
+ specify "should correctly return max" do
266
+ @d.max(:value).to_s.should == 7.89.to_s
267
+ end
268
+
269
+ specify "should correctly return min" do
270
+ @d.min(:value).to_s.should == 1.23.to_s
271
+ end
272
+ end
273
+
274
+ context "SQLite::Dataset#delete" do
275
+ setup do
276
+ SQLITE_DB.create_table! :items do
277
+ integer :id, :primary_key => true, :auto_increment => true
278
+ text :name
279
+ float :value
280
+ end
281
+ @d = SQLITE_DB[:items]
282
+ @d.delete # remove all records
283
+ @d << {:name => 'abc', :value => 1.23}
284
+ @d << {:name => 'def', :value => 4.56}
285
+ @d << {:name => 'ghi', :value => 7.89}
286
+ end
287
+
288
+ specify "should return the number of records affected when filtered" do
289
+ @d.count.should == 3
290
+ @d.filter {:value < 3}.delete.should == 1
291
+ @d.count.should == 2
292
+
293
+ @d.filter {:value < 3}.delete.should == 0
294
+ @d.count.should == 2
295
+ end
296
+
297
+ specify "should return the number of records affected when unfiltered" do
298
+ @d.count.should == 3
299
+ @d.delete.should == 3
300
+ @d.count.should == 0
301
+
302
+ @d.delete.should == 0
303
+ end
304
+ end
305
+
306
+ context "SQLite::Dataset#update" do
307
+ setup do
308
+ SQLITE_DB.create_table! :items do
309
+ integer :id, :primary_key => true, :auto_increment => true
310
+ text :name
311
+ float :value
312
+ end
313
+ @d = SQLITE_DB[:items]
314
+ @d.delete # remove all records
315
+ @d << {:name => 'abc', :value => 1.23}
316
+ @d << {:name => 'def', :value => 4.56}
317
+ @d << {:name => 'ghi', :value => 7.89}
318
+ end
319
+
320
+ specify "should return the number of records affected" do
321
+ @d.filter(:name => 'abc').update(:value => 2).should == 1
322
+
323
+ @d.update(:value => 10).should == 3
324
+
325
+ @d.filter(:name => 'xxx').update(:value => 23).should == 0
326
+ end
327
+ end
328
+
329
+ context "SQLite dataset" do
330
+ setup do
331
+ SQLITE_DB.create_table! :test do
332
+ integer :id, :primary_key => true, :auto_increment => true
333
+ text :name
334
+ float :value
335
+ end
336
+ SQLITE_DB.create_table! :items do
337
+ integer :id, :primary_key => true, :auto_increment => true
338
+ text :name
339
+ float :value
340
+ end
341
+ @d = SQLITE_DB[:items]
342
+ @d.delete # remove all records
343
+ @d << {:name => 'abc', :value => 1.23}
344
+ @d << {:name => 'def', :value => 4.56}
345
+ @d << {:name => 'ghi', :value => 7.89}
346
+ end
347
+
348
+ teardown do
349
+ SQLITE_DB.drop_table :test
350
+ end
351
+
352
+ specify "should be able to insert from a subquery" do
353
+ SQLITE_DB[:test] << @d
354
+ SQLITE_DB[:test].count.should == 3
355
+ SQLITE_DB[:test].select(:name, :value).order(:value).to_a.should == \
356
+ @d.select(:name, :value).order(:value).to_a
357
+ end
358
+ end
359
+
360
+ context "A SQLite database" do
361
+ setup do
362
+ @db = SQLITE_DB
363
+ @db.create_table! :test2 do
364
+ text :name
365
+ integer :value
366
+ end
367
+ end
368
+
369
+ specify "should support add_column operations" do
370
+ @db.add_column :test2, :xyz, :text
371
+
372
+ @db[:test2].columns.should == [:name, :value, :xyz]
373
+ @db[:test2] << {:name => 'mmm', :value => 111, :xyz=>'000'}
374
+ @db[:test2].first.should == {:name => 'mmm', :value => 111, :xyz=>'000'}
375
+ end
376
+
377
+ specify "should support drop_column operations" do
378
+ @db.drop_column :test2, :value
379
+ @db[:test2].columns.should == [:name]
380
+ @db[:test2] << {:name => 'mmm'}
381
+ @db[:test2].first.should == {:name => 'mmm'}
382
+ end
383
+
384
+ specify "should not support rename_column operations" do
385
+ proc {@db.rename_column :test2, :value, :zyx}.should raise_error(Sequel::Error)
386
+ end
387
+
388
+ specify "should not support set_column_type operations" do
389
+ proc {@db.set_column_type :test2, :value, :integer}.should raise_error(Sequel::Error)
390
+ end
391
+
392
+ specify "should support add_index" do
393
+ @db.add_index :test2, :value, :unique => true
394
+ @db.add_index :test2, [:name, :value]
395
+ end
396
+
397
+ specify "should not support drop_index" do
398
+ proc {@db.drop_index :test2, :value}.should raise_error(Sequel::Error)
399
+ end
400
+ end
@@ -0,0 +1,51 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper.rb')
2
+
3
+ describe "Simple Dataset operations" do
4
+ before do
5
+ INTEGRATION_DB.create_table!(:items) do
6
+ primary_key :id
7
+ integer :number
8
+ end
9
+ @ds = INTEGRATION_DB[:items]
10
+ @ds.insert(:number=>10)
11
+ clear_sqls
12
+ end
13
+ after do
14
+ INTEGRATION_DB.drop_table(:items)
15
+ end
16
+
17
+ specify "should insert with a primary key specified" do
18
+ @ds.insert(:id=>100, :number=>20)
19
+ sqls_should_be(/INSERT INTO items \((number, id|id, number)\) VALUES \((100, 20|20, 100)\)/)
20
+ @ds.count.should == 2
21
+ @ds.order(:id).all.should == [{:id=>1, :number=>10}, {:id=>100, :number=>20}]
22
+ end
23
+
24
+ specify "should have insert return primary key value" do
25
+ @ds.insert(:number=>20).should == 2
26
+ sqls_should_be('INSERT INTO items (number) VALUES (20)')
27
+ @ds.filter(:id=>2).first[:number].should == 20
28
+ end
29
+
30
+ specify "should delete correctly" do
31
+ @ds.filter(1=>1).delete.should == 1
32
+ sqls_should_be('DELETE FROM items WHERE (1 = 1)')
33
+ @ds.count.should == 0
34
+ end
35
+
36
+ specify "should update correctly" do
37
+ @ds.update(:number=>:number+1).should == 1
38
+ sqls_should_be('UPDATE items SET number = (number + 1)')
39
+ @ds.all.should == [{:id=>1, :number=>11}]
40
+ end
41
+
42
+ specify "should fetch all results correctly" do
43
+ @ds.all.should == [{:id=>1, :number=>10}]
44
+ sqls_should_be('SELECT * FROM items')
45
+ end
46
+
47
+ specify "should fetch a single row correctly" do
48
+ @ds.first.should == {:id=>1, :number=>10}
49
+ sqls_should_be('SELECT * FROM items LIMIT 1')
50
+ end
51
+ end