sequel 3.28.0 → 3.29.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (148) hide show
  1. data/CHANGELOG +119 -3
  2. data/Rakefile +5 -3
  3. data/bin/sequel +1 -5
  4. data/doc/model_hooks.rdoc +9 -1
  5. data/doc/opening_databases.rdoc +49 -40
  6. data/doc/prepared_statements.rdoc +27 -6
  7. data/doc/release_notes/3.28.0.txt +2 -2
  8. data/doc/release_notes/3.29.0.txt +459 -0
  9. data/doc/sharding.rdoc +7 -1
  10. data/doc/testing.rdoc +18 -9
  11. data/doc/transactions.rdoc +41 -1
  12. data/lib/sequel/adapters/ado.rb +28 -17
  13. data/lib/sequel/adapters/ado/mssql.rb +18 -6
  14. data/lib/sequel/adapters/amalgalite.rb +11 -7
  15. data/lib/sequel/adapters/db2.rb +122 -70
  16. data/lib/sequel/adapters/dbi.rb +15 -15
  17. data/lib/sequel/adapters/do.rb +5 -36
  18. data/lib/sequel/adapters/do/mysql.rb +0 -5
  19. data/lib/sequel/adapters/do/postgres.rb +0 -5
  20. data/lib/sequel/adapters/do/sqlite.rb +0 -5
  21. data/lib/sequel/adapters/firebird.rb +3 -6
  22. data/lib/sequel/adapters/ibmdb.rb +24 -16
  23. data/lib/sequel/adapters/informix.rb +2 -4
  24. data/lib/sequel/adapters/jdbc.rb +47 -11
  25. data/lib/sequel/adapters/jdbc/as400.rb +5 -24
  26. data/lib/sequel/adapters/jdbc/db2.rb +0 -5
  27. data/lib/sequel/adapters/jdbc/derby.rb +217 -0
  28. data/lib/sequel/adapters/jdbc/firebird.rb +0 -5
  29. data/lib/sequel/adapters/jdbc/h2.rb +10 -12
  30. data/lib/sequel/adapters/jdbc/hsqldb.rb +166 -0
  31. data/lib/sequel/adapters/jdbc/informix.rb +0 -5
  32. data/lib/sequel/adapters/jdbc/jtds.rb +0 -5
  33. data/lib/sequel/adapters/jdbc/mysql.rb +0 -10
  34. data/lib/sequel/adapters/jdbc/oracle.rb +70 -3
  35. data/lib/sequel/adapters/jdbc/postgresql.rb +0 -11
  36. data/lib/sequel/adapters/jdbc/sqlite.rb +0 -5
  37. data/lib/sequel/adapters/jdbc/sqlserver.rb +0 -5
  38. data/lib/sequel/adapters/jdbc/transactions.rb +56 -7
  39. data/lib/sequel/adapters/mock.rb +315 -0
  40. data/lib/sequel/adapters/mysql.rb +64 -51
  41. data/lib/sequel/adapters/mysql2.rb +15 -9
  42. data/lib/sequel/adapters/odbc.rb +13 -6
  43. data/lib/sequel/adapters/odbc/db2.rb +0 -4
  44. data/lib/sequel/adapters/odbc/mssql.rb +0 -5
  45. data/lib/sequel/adapters/openbase.rb +2 -4
  46. data/lib/sequel/adapters/oracle.rb +333 -51
  47. data/lib/sequel/adapters/postgres.rb +80 -27
  48. data/lib/sequel/adapters/shared/access.rb +0 -6
  49. data/lib/sequel/adapters/shared/db2.rb +13 -15
  50. data/lib/sequel/adapters/shared/firebird.rb +6 -6
  51. data/lib/sequel/adapters/shared/mssql.rb +23 -18
  52. data/lib/sequel/adapters/shared/mysql.rb +6 -6
  53. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +6 -0
  54. data/lib/sequel/adapters/shared/oracle.rb +185 -30
  55. data/lib/sequel/adapters/shared/postgres.rb +35 -18
  56. data/lib/sequel/adapters/shared/progress.rb +0 -6
  57. data/lib/sequel/adapters/shared/sqlite.rb +116 -37
  58. data/lib/sequel/adapters/sqlite.rb +16 -8
  59. data/lib/sequel/adapters/swift.rb +5 -5
  60. data/lib/sequel/adapters/swift/mysql.rb +0 -5
  61. data/lib/sequel/adapters/swift/postgres.rb +0 -5
  62. data/lib/sequel/adapters/swift/sqlite.rb +6 -4
  63. data/lib/sequel/adapters/tinytds.rb +13 -10
  64. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +8 -0
  65. data/lib/sequel/core.rb +40 -0
  66. data/lib/sequel/database/connecting.rb +1 -2
  67. data/lib/sequel/database/dataset.rb +3 -3
  68. data/lib/sequel/database/dataset_defaults.rb +58 -0
  69. data/lib/sequel/database/misc.rb +62 -2
  70. data/lib/sequel/database/query.rb +113 -49
  71. data/lib/sequel/database/schema_methods.rb +7 -2
  72. data/lib/sequel/dataset/actions.rb +37 -19
  73. data/lib/sequel/dataset/features.rb +24 -0
  74. data/lib/sequel/dataset/graph.rb +7 -6
  75. data/lib/sequel/dataset/misc.rb +11 -3
  76. data/lib/sequel/dataset/mutation.rb +2 -3
  77. data/lib/sequel/dataset/prepared_statements.rb +6 -4
  78. data/lib/sequel/dataset/query.rb +46 -15
  79. data/lib/sequel/dataset/sql.rb +28 -4
  80. data/lib/sequel/extensions/named_timezones.rb +5 -0
  81. data/lib/sequel/extensions/thread_local_timezones.rb +1 -1
  82. data/lib/sequel/model.rb +2 -1
  83. data/lib/sequel/model/associations.rb +115 -33
  84. data/lib/sequel/model/base.rb +91 -31
  85. data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
  86. data/lib/sequel/plugins/dataset_associations.rb +100 -0
  87. data/lib/sequel/plugins/force_encoding.rb +6 -6
  88. data/lib/sequel/plugins/identity_map.rb +1 -1
  89. data/lib/sequel/plugins/many_through_many.rb +6 -10
  90. data/lib/sequel/plugins/prepared_statements.rb +12 -1
  91. data/lib/sequel/plugins/prepared_statements_associations.rb +1 -1
  92. data/lib/sequel/plugins/rcte_tree.rb +29 -15
  93. data/lib/sequel/plugins/serialization.rb +6 -1
  94. data/lib/sequel/plugins/sharding.rb +0 -5
  95. data/lib/sequel/plugins/single_table_inheritance.rb +1 -1
  96. data/lib/sequel/plugins/typecast_on_load.rb +9 -12
  97. data/lib/sequel/plugins/update_primary_key.rb +1 -1
  98. data/lib/sequel/timezones.rb +42 -42
  99. data/lib/sequel/version.rb +1 -1
  100. data/spec/adapters/mssql_spec.rb +29 -29
  101. data/spec/adapters/mysql_spec.rb +86 -104
  102. data/spec/adapters/oracle_spec.rb +48 -76
  103. data/spec/adapters/postgres_spec.rb +98 -33
  104. data/spec/adapters/spec_helper.rb +0 -5
  105. data/spec/adapters/sqlite_spec.rb +24 -21
  106. data/spec/core/connection_pool_spec.rb +9 -15
  107. data/spec/core/core_sql_spec.rb +20 -31
  108. data/spec/core/database_spec.rb +491 -227
  109. data/spec/core/dataset_spec.rb +638 -1051
  110. data/spec/core/expression_filters_spec.rb +0 -1
  111. data/spec/core/mock_adapter_spec.rb +378 -0
  112. data/spec/core/object_graph_spec.rb +48 -114
  113. data/spec/core/schema_generator_spec.rb +3 -3
  114. data/spec/core/schema_spec.rb +51 -114
  115. data/spec/core/spec_helper.rb +3 -90
  116. data/spec/extensions/class_table_inheritance_spec.rb +1 -1
  117. data/spec/extensions/dataset_associations_spec.rb +199 -0
  118. data/spec/extensions/instance_hooks_spec.rb +71 -0
  119. data/spec/extensions/named_timezones_spec.rb +22 -2
  120. data/spec/extensions/nested_attributes_spec.rb +3 -0
  121. data/spec/extensions/schema_spec.rb +1 -1
  122. data/spec/extensions/serialization_modification_detection_spec.rb +1 -0
  123. data/spec/extensions/serialization_spec.rb +5 -8
  124. data/spec/extensions/spec_helper.rb +4 -0
  125. data/spec/extensions/thread_local_timezones_spec.rb +22 -2
  126. data/spec/extensions/typecast_on_load_spec.rb +1 -6
  127. data/spec/integration/associations_test.rb +123 -12
  128. data/spec/integration/dataset_test.rb +140 -47
  129. data/spec/integration/eager_loader_test.rb +19 -21
  130. data/spec/integration/model_test.rb +80 -1
  131. data/spec/integration/plugin_test.rb +179 -128
  132. data/spec/integration/prepared_statement_test.rb +92 -91
  133. data/spec/integration/schema_test.rb +42 -23
  134. data/spec/integration/spec_helper.rb +25 -31
  135. data/spec/integration/timezone_test.rb +38 -12
  136. data/spec/integration/transaction_test.rb +161 -34
  137. data/spec/integration/type_test.rb +3 -3
  138. data/spec/model/association_reflection_spec.rb +83 -7
  139. data/spec/model/associations_spec.rb +393 -676
  140. data/spec/model/base_spec.rb +186 -116
  141. data/spec/model/dataset_methods_spec.rb +7 -27
  142. data/spec/model/eager_loading_spec.rb +343 -867
  143. data/spec/model/hooks_spec.rb +160 -79
  144. data/spec/model/model_spec.rb +118 -165
  145. data/spec/model/plugins_spec.rb +7 -13
  146. data/spec/model/record_spec.rb +138 -207
  147. data/spec/model/spec_helper.rb +10 -73
  148. metadata +14 -8
@@ -60,12 +60,6 @@ describe "Dataset" do
60
60
  db = Sequel::Database.new(:identifier_output_method=>:downcase)
61
61
  db[:a].identifier_output_method.should == :downcase
62
62
  end
63
- end
64
-
65
- describe "Dataset" do
66
- before do
67
- @dataset = Sequel::Dataset.new("db")
68
- end
69
63
 
70
64
  specify "should have quote_identifiers= method which changes literalization of identifiers" do
71
65
  @dataset.quote_identifiers = true
@@ -111,27 +105,25 @@ describe "Dataset#clone" do
111
105
 
112
106
  specify "should create an exact copy of the dataset" do
113
107
  @dataset.row_proc = Proc.new{|r| r}
114
- @clone = @dataset.clone
108
+ clone = @dataset.clone
115
109
 
116
- @clone.object_id.should_not === @dataset.object_id
117
- @clone.class.should == @dataset.class
118
- @clone.opts.should == @dataset.opts
119
- @clone.row_proc.should == @dataset.row_proc
110
+ clone.object_id.should_not === @dataset.object_id
111
+ clone.class.should == @dataset.class
112
+ clone.db.should == @dataset.db
113
+ clone.opts.should == @dataset.opts
114
+ clone.row_proc.should == @dataset.row_proc
120
115
  end
121
116
 
122
117
  specify "should deep-copy the dataset opts" do
123
- @clone = @dataset.clone
118
+ clone = @dataset.clone
124
119
 
125
- @clone.opts.should_not equal(@dataset.opts)
120
+ clone.opts.should_not equal(@dataset.opts)
126
121
  @dataset.filter!(:a => 'b')
127
- @clone.opts[:filter].should be_nil
128
- end
129
-
130
- specify "should return a clone self" do
131
- clone = @dataset.clone({})
132
- clone.class.should == @dataset.class
133
- clone.db.should == @dataset.db
134
- clone.opts.should == @dataset.opts
122
+ clone.opts[:filter].should be_nil
123
+
124
+ clone = @dataset.clone(:from => [:other])
125
+ @dataset.opts[:from].should == [:items]
126
+ clone.opts[:from].should == [:other]
135
127
  end
136
128
 
137
129
  specify "should merge the specified options" do
@@ -144,12 +136,6 @@ describe "Dataset#clone" do
144
136
  clone.opts.should == {:from => [:other]}
145
137
  end
146
138
 
147
- specify "should create a clone with a deep copy of options" do
148
- clone = @dataset.clone(:from => [:other])
149
- @dataset.opts[:from].should == [:items]
150
- clone.opts[:from].should == [:other]
151
- end
152
-
153
139
  specify "should return an object with the same modules included" do
154
140
  m = Module.new do
155
141
  def __xyz__; "xyz"; end
@@ -161,7 +147,7 @@ end
161
147
 
162
148
  describe "Dataset#==" do
163
149
  before do
164
- @db = MockDatabase.new
150
+ @db = Sequel.mock
165
151
  @h = {}
166
152
  end
167
153
 
@@ -170,7 +156,7 @@ describe "Dataset#==" do
170
156
  end
171
157
 
172
158
  specify "should be different for datasets with different dbs" do
173
- @db[:t].should_not == MockDatabase.new[:t]
159
+ @db[:t].should_not == Sequel.mock[:t]
174
160
  end
175
161
 
176
162
  specify "should be different for datasets with different opts" do
@@ -186,7 +172,7 @@ end
186
172
 
187
173
  describe "Dataset#hash" do
188
174
  before do
189
- @db = MockDatabase.new
175
+ @db = Sequel.mock
190
176
  @h = {}
191
177
  end
192
178
 
@@ -197,7 +183,7 @@ describe "Dataset#hash" do
197
183
  end
198
184
 
199
185
  specify "should be different for datasets with different dbs" do
200
- @db[:t].hash.should_not == MockDatabase.new[:t].hash
186
+ @db[:t].hash.should_not == Sequel.mock[:t].hash
201
187
  end
202
188
 
203
189
  specify "should be different for datasets with different opts" do
@@ -232,6 +218,12 @@ describe "A simple dataset" do
232
218
  @dataset.insert_sql.should == 'INSERT INTO test DEFAULT VALUES'
233
219
  end
234
220
 
221
+ specify "should use a single column with a default value when the dataset doesn't support using insert statement with default values" do
222
+ @dataset.meta_def(:insert_supports_empty_values?){false}
223
+ @dataset.meta_def(:columns){[:a, :b]}
224
+ @dataset.insert_sql.should == 'INSERT INTO test (b) VALUES (DEFAULT)'
225
+ end
226
+
235
227
  specify "should format an insert statement with hash" do
236
228
  @dataset.insert_sql(:name => 'wxyz', :price => 342).
237
229
  should match(/INSERT INTO test \(name, price\) VALUES \('wxyz', 342\)|INSERT INTO test \(price, name\) VALUES \(342, 'wxyz'\)/)
@@ -245,8 +237,6 @@ describe "A simple dataset" do
245
237
  end
246
238
 
247
239
  specify "should format an insert statement with an object that respond_to? :values" do
248
- dbb = Sequel::Database.new
249
-
250
240
  v = Object.new
251
241
  def v.values; {:a => 1}; end
252
242
 
@@ -261,29 +251,24 @@ describe "A simple dataset" do
261
251
  end
262
252
 
263
253
  specify "should format an insert statement with sub-query" do
264
- @sub = Sequel::Dataset.new(nil).from(:something).filter(:x => 2)
265
- @dataset.insert_sql(@sub).should == \
266
- "INSERT INTO test SELECT * FROM something WHERE (x = 2)"
254
+ @dataset.insert_sql(@dataset.from(:something).filter(:x => 2)).should == "INSERT INTO test SELECT * FROM something WHERE (x = 2)"
267
255
  end
268
256
 
269
257
  specify "should format an insert statement with array" do
270
- @dataset.insert_sql('a', 2, 6.5).should ==
271
- "INSERT INTO test VALUES ('a', 2, 6.5)"
258
+ @dataset.insert_sql('a', 2, 6.5).should == "INSERT INTO test VALUES ('a', 2, 6.5)"
272
259
  end
273
260
 
274
261
  specify "should format an update statement" do
275
- @dataset.update_sql(:name => 'abc').should ==
276
- "UPDATE test SET name = 'abc'"
262
+ @dataset.update_sql(:name => 'abc').should == "UPDATE test SET name = 'abc'"
277
263
  end
278
264
 
279
265
  specify "should be able to return rows for arbitrary SQL" do
280
- @dataset.clone(:sql => 'xxx yyy zzz').select_sql.should ==
281
- "xxx yyy zzz"
266
+ @dataset.clone(:sql => 'xxx yyy zzz').select_sql.should == "xxx yyy zzz"
282
267
  end
283
268
 
284
269
  specify "should use the :sql option for all sql methods" do
285
270
  sql = "X"
286
- ds = Sequel::Dataset.new(nil, :sql=>sql)
271
+ ds = @dataset.clone(:sql=>sql)
287
272
  ds.sql.should == sql
288
273
  ds.select_sql.should == sql
289
274
  ds.insert_sql.should == sql
@@ -418,7 +403,7 @@ describe "Dataset#where" do
418
403
  b.should == a
419
404
  end
420
405
 
421
- specify "should not replace named placeholders that don't existin in the hash" do
406
+ specify "should not replace named placeholders that don't exist in the hash" do
422
407
  @dataset.where('price < :price AND id in :ids', :price=>100).select_sql.should ==
423
408
  "SELECT * FROM test WHERE (price < 100 AND id in :ids)"
424
409
  end
@@ -538,53 +523,31 @@ describe "Dataset#where" do
538
523
 
539
524
  specify "should handle IN/NOT IN queries with multiple columns and a dataset where the database doesn't support it" do
540
525
  @dataset.meta_def(:supports_multiple_column_in?){false}
541
- db = MockDatabase.new()
542
- d1 = db[:test].select(:id1, :id2).filter(:region=>'Asia')
543
- d1.instance_variable_set(:@columns, [:id1, :id2])
544
- def d1.fetch_rows(sql)
545
- db << sql
546
- @columns = [:id1, :id2]
547
- yield(:id1=>1, :id2=>2)
548
- yield(:id1=>3, :id2=>4)
549
- end
526
+ db = Sequel.mock(:fetch=>[{:id1=>1, :id2=>2}, {:id1=>3, :id2=>4}])
527
+ d1 = db[:test].select(:id1, :id2).filter(:region=>'Asia').columns(:id1, :id2)
550
528
  @dataset.filter([:id1, :id2] => d1).sql.should == "SELECT * FROM test WHERE (((id1 = 1) AND (id2 = 2)) OR ((id1 = 3) AND (id2 = 4)))"
551
529
  db.sqls.should == ["SELECT id1, id2 FROM test WHERE (region = 'Asia')"]
552
- db.sqls.clear
553
530
  @dataset.exclude([:id1, :id2] => d1).sql.should == "SELECT * FROM test WHERE (((id1 != 1) OR (id2 != 2)) AND ((id1 != 3) OR (id2 != 4)))"
554
531
  db.sqls.should == ["SELECT id1, id2 FROM test WHERE (region = 'Asia')"]
555
532
  end
556
533
 
557
534
  specify "should handle IN/NOT IN queries with multiple columns and an empty dataset where the database doesn't support it" do
558
535
  @dataset.meta_def(:supports_multiple_column_in?){false}
559
- db = MockDatabase.new()
560
- d1 = db[:test].select(:id1, :id2).filter(:region=>'Asia')
561
- d1.instance_variable_set(:@columns, [:id1, :id2])
562
- def d1.fetch_rows(sql)
563
- db << sql
564
- @columns = [:id1, :id2]
565
- end
536
+ db = Sequel.mock
537
+ d1 = db[:test].select(:id1, :id2).filter(:region=>'Asia').columns(:id1, :id2)
566
538
  @dataset.filter([:id1, :id2] => d1).sql.should == "SELECT * FROM test WHERE ((id1 != id1) AND (id2 != id2))"
567
539
  db.sqls.should == ["SELECT id1, id2 FROM test WHERE (region = 'Asia')"]
568
- db.sqls.clear
569
540
  @dataset.exclude([:id1, :id2] => d1).sql.should == "SELECT * FROM test WHERE (1 = 1)"
570
541
  db.sqls.should == ["SELECT id1, id2 FROM test WHERE (region = 'Asia')"]
571
542
  end
572
543
 
573
544
  specify "should handle IN/NOT IN queries for datasets with row_procs" do
574
545
  @dataset.meta_def(:supports_multiple_column_in?){false}
575
- db = MockDatabase.new()
576
- d1 = db[:test].select(:id1, :id2).filter(:region=>'Asia')
546
+ db = Sequel.mock(:fetch=>[{:id1=>1, :id2=>2}, {:id1=>3, :id2=>4}])
547
+ d1 = db[:test].select(:id1, :id2).filter(:region=>'Asia').columns(:id1, :id2)
577
548
  d1.row_proc = proc{|h| Object.new}
578
- d1.instance_variable_set(:@columns, [:id1, :id2])
579
- def d1.fetch_rows(sql)
580
- db << sql
581
- @columns = [:id1, :id2]
582
- yield(:id1=>1, :id2=>2)
583
- yield(:id1=>3, :id2=>4)
584
- end
585
549
  @dataset.filter([:id1, :id2] => d1).sql.should == "SELECT * FROM test WHERE (((id1 = 1) AND (id2 = 2)) OR ((id1 = 3) AND (id2 = 4)))"
586
550
  db.sqls.should == ["SELECT id1, id2 FROM test WHERE (region = 'Asia')"]
587
- db.sqls.clear
588
551
  @dataset.exclude([:id1, :id2] => d1).sql.should == "SELECT * FROM test WHERE (((id1 != 1) OR (id2 != 2)) AND ((id1 != 3) OR (id2 != 4)))"
589
552
  db.sqls.should == ["SELECT id1, id2 FROM test WHERE (region = 'Asia')"]
590
553
  end
@@ -687,33 +650,25 @@ describe "Dataset#or" do
687
650
  end
688
651
 
689
652
  specify "should add an alternative expression to the where clause" do
690
- @d1.or(:y => 2).sql.should ==
691
- 'SELECT * FROM test WHERE ((x = 1) OR (y = 2))'
653
+ @d1.or(:y => 2).sql.should == 'SELECT * FROM test WHERE ((x = 1) OR (y = 2))'
692
654
  end
693
655
 
694
656
  specify "should accept all forms of filters" do
695
- @d1.or('y > ?', 2).sql.should ==
696
- 'SELECT * FROM test WHERE ((x = 1) OR (y > 2))'
697
- @d1.or(:yy.sql_number > 3).sql.should ==
698
- 'SELECT * FROM test WHERE ((x = 1) OR (yy > 3))'
657
+ @d1.or('y > ?', 2).sql.should == 'SELECT * FROM test WHERE ((x = 1) OR (y > 2))'
658
+ @d1.or(:yy.sql_number > 3).sql.should == 'SELECT * FROM test WHERE ((x = 1) OR (yy > 3))'
699
659
  end
700
660
 
701
661
  specify "should accept blocks passed to filter" do
702
- @d1.or{:yy.sql_number > 3}.sql.should ==
703
- 'SELECT * FROM test WHERE ((x = 1) OR (yy > 3))'
662
+ @d1.or{:yy.sql_number > 3}.sql.should == 'SELECT * FROM test WHERE ((x = 1) OR (yy > 3))'
704
663
  end
705
664
 
706
665
  specify "should correctly add parens to give predictable results" do
707
- @d1.filter(:y => 2).or(:z => 3).sql.should ==
708
- 'SELECT * FROM test WHERE (((x = 1) AND (y = 2)) OR (z = 3))'
709
-
710
- @d1.or(:y => 2).filter(:z => 3).sql.should ==
711
- 'SELECT * FROM test WHERE (((x = 1) OR (y = 2)) AND (z = 3))'
666
+ @d1.filter(:y => 2).or(:z => 3).sql.should == 'SELECT * FROM test WHERE (((x = 1) AND (y = 2)) OR (z = 3))'
667
+ @d1.or(:y => 2).filter(:z => 3).sql.should == 'SELECT * FROM test WHERE (((x = 1) OR (y = 2)) AND (z = 3))'
712
668
  end
713
669
 
714
670
  specify "should allow the use of blocks and arguments simultaneously" do
715
- @d1.or(:zz.sql_number < 3){:yy.sql_number > 3}.sql.should ==
716
- 'SELECT * FROM test WHERE ((x = 1) OR ((zz < 3) AND (yy > 3)))'
671
+ @d1.or(:zz.sql_number < 3){:yy.sql_number > 3}.sql.should == 'SELECT * FROM test WHERE ((x = 1) OR ((zz < 3) AND (yy > 3)))'
717
672
  end
718
673
  end
719
674
 
@@ -726,34 +681,25 @@ describe "Dataset#and" do
726
681
  specify "should raise if no filter exists" do
727
682
  proc {@dataset.and(:a => 1)}.should raise_error(Sequel::Error)
728
683
  proc {@dataset.where(:a => 1).group(:t).and(:b => 2)}.should_not raise_error(Sequel::Error)
729
- @dataset.where(:a => 1).group(:t).and(:b => 2).sql ==
730
- "SELECT * FROM test WHERE (a = 1) AND (b = 2) GROUP BY t"
684
+ @dataset.where(:a => 1).group(:t).and(:b => 2).sql == "SELECT * FROM test WHERE (a = 1) AND (b = 2) GROUP BY t"
731
685
  end
732
686
 
733
687
  specify "should add an alternative expression to the where clause" do
734
- @d1.and(:y => 2).sql.should ==
735
- 'SELECT * FROM test WHERE ((x = 1) AND (y = 2))'
688
+ @d1.and(:y => 2).sql.should == 'SELECT * FROM test WHERE ((x = 1) AND (y = 2))'
736
689
  end
737
690
 
738
- specify "should accept all forms of filters" do
739
- # probably not exhaustive, but good enough
740
- @d1.and('y > ?', 2).sql.should ==
741
- 'SELECT * FROM test WHERE ((x = 1) AND (y > 2))'
742
- @d1.and(:yy.sql_number > 3).sql.should ==
743
- 'SELECT * FROM test WHERE ((x = 1) AND (yy > 3))'
691
+ specify "should accept different types of filters" do
692
+ @d1.and('y > ?', 2).sql.should == 'SELECT * FROM test WHERE ((x = 1) AND (y > 2))'
693
+ @d1.and(:yy.sql_number > 3).sql.should == 'SELECT * FROM test WHERE ((x = 1) AND (yy > 3))'
744
694
  end
745
695
 
746
696
  specify "should accept blocks passed to filter" do
747
- @d1.and {:yy.sql_number > 3}.sql.should ==
748
- 'SELECT * FROM test WHERE ((x = 1) AND (yy > 3))'
697
+ @d1.and {:yy.sql_number > 3}.sql.should == 'SELECT * FROM test WHERE ((x = 1) AND (yy > 3))'
749
698
  end
750
699
 
751
700
  specify "should correctly add parens to give predictable results" do
752
- @d1.or(:y => 2).and(:z => 3).sql.should ==
753
- 'SELECT * FROM test WHERE (((x = 1) OR (y = 2)) AND (z = 3))'
754
-
755
- @d1.and(:y => 2).or(:z => 3).sql.should ==
756
- 'SELECT * FROM test WHERE (((x = 1) AND (y = 2)) OR (z = 3))'
701
+ @d1.or(:y => 2).and(:z => 3).sql.should == 'SELECT * FROM test WHERE (((x = 1) OR (y = 2)) AND (z = 3))'
702
+ @d1.and(:y => 2).or(:z => 3).sql.should == 'SELECT * FROM test WHERE (((x = 1) AND (y = 2)) OR (z = 3))'
757
703
  end
758
704
  end
759
705
 
@@ -763,13 +709,11 @@ describe "Dataset#exclude" do
763
709
  end
764
710
 
765
711
  specify "should correctly negate the expression when one condition is given" do
766
- @dataset.exclude(:region=>'Asia').select_sql.should ==
767
- "SELECT * FROM test WHERE (region != 'Asia')"
712
+ @dataset.exclude(:region=>'Asia').select_sql.should == "SELECT * FROM test WHERE (region != 'Asia')"
768
713
  end
769
714
 
770
715
  specify "should affect the having clause if having clause is already used" do
771
- @dataset.group_and_count(:name).having{count > 2}.exclude{count > 5}.sql.should ==
772
- "SELECT name, count(*) AS count FROM test GROUP BY name HAVING ((count > 2) AND (count <= 5))"
716
+ @dataset.group_and_count(:name).having{count > 2}.exclude{count > 5}.sql.should == "SELECT name, count(*) AS count FROM test GROUP BY name HAVING ((count > 2) AND (count <= 5))"
773
717
  end
774
718
 
775
719
  specify "should take multiple conditions as a hash and express the logic correctly in SQL" do
@@ -779,30 +723,24 @@ describe "Dataset#exclude" do
779
723
  end
780
724
 
781
725
  specify "should parenthesize a single string condition correctly" do
782
- @dataset.exclude("region = 'Asia' AND name = 'Japan'").select_sql.should ==
783
- "SELECT * FROM test WHERE NOT (region = 'Asia' AND name = 'Japan')"
726
+ @dataset.exclude("region = 'Asia' AND name = 'Japan'").select_sql.should == "SELECT * FROM test WHERE NOT (region = 'Asia' AND name = 'Japan')"
784
727
  end
785
728
 
786
729
  specify "should parenthesize an array condition correctly" do
787
- @dataset.exclude('region = ? AND name = ?', 'Asia', 'Japan').select_sql.should ==
788
- "SELECT * FROM test WHERE NOT (region = 'Asia' AND name = 'Japan')"
730
+ @dataset.exclude('region = ? AND name = ?', 'Asia', 'Japan').select_sql.should == "SELECT * FROM test WHERE NOT (region = 'Asia' AND name = 'Japan')"
789
731
  end
790
732
 
791
733
  specify "should correctly parenthesize when it is used twice" do
792
- @dataset.exclude(:region => 'Asia').exclude(:name => 'Japan').select_sql.should ==
793
- "SELECT * FROM test WHERE ((region != 'Asia') AND (name != 'Japan'))"
734
+ @dataset.exclude(:region => 'Asia').exclude(:name => 'Japan').select_sql.should == "SELECT * FROM test WHERE ((region != 'Asia') AND (name != 'Japan'))"
794
735
  end
795
736
 
796
737
  specify "should support proc expressions" do
797
- @dataset.exclude{:id.sql_number < 6}.sql.should ==
798
- 'SELECT * FROM test WHERE (id >= 6)'
738
+ @dataset.exclude{:id.sql_number < 6}.sql.should == 'SELECT * FROM test WHERE (id >= 6)'
799
739
  end
800
740
 
801
741
  specify "should allow the use of blocks and arguments simultaneously" do
802
- @dataset.exclude(:id => (7..11)){:id.sql_number < 6}.sql.should ==
803
- 'SELECT * FROM test WHERE ((id < 7) OR (id > 11) OR (id >= 6))'
804
- @dataset.exclude([:id, 1], [:x, 3]){:id.sql_number < 6}.sql.should ==
805
- 'SELECT * FROM test WHERE ((id != 1) OR (x != 3) OR (id >= 6))'
742
+ @dataset.exclude(:id => (7..11)){:id.sql_number < 6}.sql.should == 'SELECT * FROM test WHERE ((id < 7) OR (id > 11) OR (id >= 6))'
743
+ @dataset.exclude([:id, 1], [:x, 3]){:id.sql_number < 6}.sql.should == 'SELECT * FROM test WHERE ((id != 1) OR (x != 3) OR (id >= 6))'
806
744
  end
807
745
  end
808
746
 
@@ -850,9 +788,6 @@ describe "Dataset#having" do
850
788
  before do
851
789
  @dataset = Sequel::Dataset.new(nil).from(:test)
852
790
  @grouped = @dataset.group(:region).select(:region, :sum.sql_function(:population), :avg.sql_function(:gdp))
853
- @d1 = @grouped.having('sum(population) > 10')
854
- @d2 = @grouped.having(:region => 'Asia')
855
- @columns = "region, sum(population), avg(gdp)"
856
791
  end
857
792
 
858
793
  specify "should just clone if given an empty argument" do
@@ -862,18 +797,15 @@ describe "Dataset#having" do
862
797
  end
863
798
 
864
799
  specify "should affect select statements" do
865
- @d1.select_sql.should ==
866
- "SELECT #{@columns} FROM test GROUP BY region HAVING (sum(population) > 10)"
800
+ @grouped.having('sum(population) > 10').select_sql.should == "SELECT region, sum(population), avg(gdp) FROM test GROUP BY region HAVING (sum(population) > 10)"
867
801
  end
868
802
 
869
803
  specify "should support proc expressions" do
870
- @grouped.having {:sum.sql_function(:population) > 10}.sql.should ==
871
- "SELECT #{@columns} FROM test GROUP BY region HAVING (sum(population) > 10)"
804
+ @grouped.having {:sum.sql_function(:population) > 10}.sql.should == "SELECT region, sum(population), avg(gdp) FROM test GROUP BY region HAVING (sum(population) > 10)"
872
805
  end
873
806
 
874
807
  specify "should work with and on the having clause" do
875
- @grouped.having( :a.sql_number > 1 ).and( :b.sql_number < 2 ).sql.should ==
876
- "SELECT #{@columns} FROM test GROUP BY region HAVING ((a > 1) AND (b < 2))"
808
+ @grouped.having( :a.sql_number > 1 ).and( :b.sql_number < 2 ).sql.should == "SELECT region, sum(population), avg(gdp) FROM test GROUP BY region HAVING ((a > 1) AND (b < 2))"
877
809
  end
878
810
  end
879
811
 
@@ -904,7 +836,7 @@ describe "a grouped dataset" do
904
836
  end
905
837
 
906
838
  specify "should format the right statement for counting (as a subquery)" do
907
- db = MockDatabase.new
839
+ db = Sequel.mock
908
840
  db[:test].select(:name).group(:name).count
909
841
  db.sqls.should == ["SELECT COUNT(*) AS count FROM (SELECT name FROM test GROUP BY name) AS t1 LIMIT 1"]
910
842
  end
@@ -924,31 +856,23 @@ describe "Dataset#group_by" do
924
856
  end
925
857
 
926
858
  specify "should specify the grouping in generated select statement" do
927
- @dataset.select_sql.should ==
928
- "SELECT * FROM test GROUP BY type_id"
929
- @dataset.group_by(:a, :b).select_sql.should ==
930
- "SELECT * FROM test GROUP BY a, b"
931
- @dataset.group_by(:type_id=>nil).select_sql.should ==
932
- "SELECT * FROM test GROUP BY (type_id IS NULL)"
859
+ @dataset.select_sql.should == "SELECT * FROM test GROUP BY type_id"
860
+ @dataset.group_by(:a, :b).select_sql.should == "SELECT * FROM test GROUP BY a, b"
861
+ @dataset.group_by(:type_id=>nil).select_sql.should == "SELECT * FROM test GROUP BY (type_id IS NULL)"
933
862
  end
934
863
 
935
864
  specify "should ungroup when passed nil or no arguments" do
936
- @dataset.group_by.select_sql.should ==
937
- "SELECT * FROM test"
938
- @dataset.group_by(nil).select_sql.should ==
939
- "SELECT * FROM test"
865
+ @dataset.group_by.select_sql.should == "SELECT * FROM test"
866
+ @dataset.group_by(nil).select_sql.should == "SELECT * FROM test"
940
867
  end
941
868
 
942
869
  specify "should undo previous grouping" do
943
- @dataset.group_by(:a).group_by(:b).select_sql.should ==
944
- "SELECT * FROM test GROUP BY b"
945
- @dataset.group_by(:a, :b).group_by.select_sql.should ==
946
- "SELECT * FROM test"
870
+ @dataset.group_by(:a).group_by(:b).select_sql.should == "SELECT * FROM test GROUP BY b"
871
+ @dataset.group_by(:a, :b).group_by.select_sql.should == "SELECT * FROM test"
947
872
  end
948
873
 
949
874
  specify "should be aliased as #group" do
950
- @dataset.group(:type_id=>nil).select_sql.should ==
951
- "SELECT * FROM test GROUP BY (type_id IS NULL)"
875
+ @dataset.group(:type_id=>nil).select_sql.should == "SELECT * FROM test GROUP BY (type_id IS NULL)"
952
876
  end
953
877
 
954
878
  specify "should take a virtual row block" do
@@ -962,14 +886,13 @@ end
962
886
  describe "Dataset#as" do
963
887
  specify "should set up an alias" do
964
888
  dataset = Sequel::Dataset.new(nil).from(:test)
965
- dataset.select(dataset.limit(1).select(:name).as(:n)).sql.should == \
966
- 'SELECT (SELECT name FROM test LIMIT 1) AS n FROM test'
889
+ dataset.select(dataset.limit(1).select(:name).as(:n)).sql.should == 'SELECT (SELECT name FROM test LIMIT 1) AS n FROM test'
967
890
  end
968
891
  end
969
892
 
970
893
  describe "Dataset#literal" do
971
894
  before do
972
- @dataset = Sequel::Dataset.new(nil).from(:test)
895
+ @dataset = Sequel::Database.new.from(:test)
973
896
  end
974
897
 
975
898
  specify "should escape strings properly" do
@@ -1138,35 +1061,25 @@ describe "Dataset#from" do
1138
1061
  end
1139
1062
 
1140
1063
  specify "should format a Dataset as a subquery if it has had options set" do
1141
- @dataset.from(@dataset.from(:a).where(:a=>1)).select_sql.should ==
1142
- "SELECT * FROM (SELECT * FROM a WHERE (a = 1)) AS t1"
1064
+ @dataset.from(@dataset.from(:a).where(:a=>1)).select_sql.should == "SELECT * FROM (SELECT * FROM a WHERE (a = 1)) AS t1"
1143
1065
  end
1144
1066
 
1145
1067
  specify "should automatically alias sub-queries" do
1146
- @dataset.from(@dataset.from(:a).group(:b)).select_sql.should ==
1147
- "SELECT * FROM (SELECT * FROM a GROUP BY b) AS t1"
1068
+ @dataset.from(@dataset.from(:a).group(:b)).select_sql.should == "SELECT * FROM (SELECT * FROM a GROUP BY b) AS t1"
1148
1069
 
1149
1070
  d1 = @dataset.from(:a).group(:b)
1150
1071
  d2 = @dataset.from(:c).group(:d)
1151
-
1152
- @dataset.from(d1, d2).sql.should ==
1153
- "SELECT * FROM (SELECT * FROM a GROUP BY b) AS t1, (SELECT * FROM c GROUP BY d) AS t2"
1072
+ @dataset.from(d1, d2).sql.should == "SELECT * FROM (SELECT * FROM a GROUP BY b) AS t1, (SELECT * FROM c GROUP BY d) AS t2"
1154
1073
  end
1155
1074
 
1156
1075
  specify "should accept a hash for aliasing" do
1157
- @dataset.from(:a => :b).sql.should ==
1158
- "SELECT * FROM a AS b"
1159
-
1160
- @dataset.from(:a => 'b').sql.should ==
1161
- "SELECT * FROM a AS b"
1162
-
1163
- @dataset.from(@dataset.from(:a).group(:b) => :c).sql.should ==
1164
- "SELECT * FROM (SELECT * FROM a GROUP BY b) AS c"
1076
+ @dataset.from(:a => :b).sql.should == "SELECT * FROM a AS b"
1077
+ @dataset.from(:a => 'b').sql.should == "SELECT * FROM a AS b"
1078
+ @dataset.from(@dataset.from(:a).group(:b) => :c).sql.should == "SELECT * FROM (SELECT * FROM a GROUP BY b) AS c"
1165
1079
  end
1166
1080
 
1167
1081
  specify "should always use a subquery if given a dataset" do
1168
- @dataset.from(@dataset.from(:a)).select_sql.should ==
1169
- "SELECT * FROM (SELECT * FROM a) AS t1"
1082
+ @dataset.from(@dataset.from(:a)).select_sql.should == "SELECT * FROM (SELECT * FROM a) AS t1"
1170
1083
  end
1171
1084
 
1172
1085
  specify "should remove all FROM tables if called with no arguments" do
@@ -1174,32 +1087,27 @@ describe "Dataset#from" do
1174
1087
  end
1175
1088
 
1176
1089
  specify "should accept sql functions" do
1177
- @dataset.from(:abc.sql_function(:def)).select_sql.should ==
1178
- "SELECT * FROM abc(def)"
1179
-
1180
- @dataset.from(:a.sql_function(:i)).select_sql.should ==
1181
- "SELECT * FROM a(i)"
1090
+ @dataset.from(:abc.sql_function(:def)).select_sql.should == "SELECT * FROM abc(def)"
1091
+ @dataset.from(:a.sql_function(:i)).select_sql.should == "SELECT * FROM a(i)"
1182
1092
  end
1183
1093
 
1184
1094
  specify "should accept :schema__table___alias symbol format" do
1185
- @dataset.from(:abc__def).select_sql.should ==
1186
- "SELECT * FROM abc.def"
1187
- @dataset.from(:a_b__c).select_sql.should ==
1188
- "SELECT * FROM a_b.c"
1189
- @dataset.from(:'#__#').select_sql.should ==
1190
- 'SELECT * FROM #.#'
1191
- @dataset.from(:abc__def___d).select_sql.should ==
1192
- "SELECT * FROM abc.def AS d"
1193
- @dataset.from(:a_b__d_e___f_g).select_sql.should ==
1194
- "SELECT * FROM a_b.d_e AS f_g"
1195
- @dataset.from(:'#__#___#').select_sql.should ==
1196
- 'SELECT * FROM #.# AS #'
1197
- @dataset.from(:abc___def).select_sql.should ==
1198
- "SELECT * FROM abc AS def"
1199
- @dataset.from(:a_b___c_d).select_sql.should ==
1200
- "SELECT * FROM a_b AS c_d"
1201
- @dataset.from(:'#___#').select_sql.should ==
1202
- 'SELECT * FROM # AS #'
1095
+ @dataset.from(:abc__def).select_sql.should == "SELECT * FROM abc.def"
1096
+ @dataset.from(:a_b__c).select_sql.should == "SELECT * FROM a_b.c"
1097
+ @dataset.from(:'#__#').select_sql.should == 'SELECT * FROM #.#'
1098
+ @dataset.from(:abc__def___d).select_sql.should == "SELECT * FROM abc.def AS d"
1099
+ @dataset.from(:a_b__d_e___f_g).select_sql.should == "SELECT * FROM a_b.d_e AS f_g"
1100
+ @dataset.from(:'#__#___#').select_sql.should == 'SELECT * FROM #.# AS #'
1101
+ @dataset.from(:abc___def).select_sql.should == "SELECT * FROM abc AS def"
1102
+ @dataset.from(:a_b___c_d).select_sql.should == "SELECT * FROM a_b AS c_d"
1103
+ @dataset.from(:'#___#').select_sql.should == 'SELECT * FROM # AS #'
1104
+ end
1105
+
1106
+ specify "should hoist WITH clauses from subqueries if the dataset doesn't support CTEs in subselects" do
1107
+ @dataset.meta_def(:supports_cte?){true}
1108
+ @dataset.meta_def(:supports_cte_in_subselect?){false}
1109
+ @dataset.from(@dataset.from(:a).with(:a, @dataset.from(:b))).sql.should == 'WITH a AS (SELECT * FROM b) SELECT * FROM (SELECT * FROM a) AS t1'
1110
+ @dataset.from(@dataset.from(:a).with(:a, @dataset.from(:b)), @dataset.from(:c).with(:c, @dataset.from(:d))).sql.should == 'WITH a AS (SELECT * FROM b), c AS (SELECT * FROM d) SELECT * FROM (SELECT * FROM a) AS t1, (SELECT * FROM c) AS t2'
1203
1111
  end
1204
1112
  end
1205
1113
 
@@ -1216,18 +1124,17 @@ describe "Dataset#select" do
1216
1124
  specify "should accept symbols and literal strings" do
1217
1125
  @d.select('aaa'.lit).sql.should == 'SELECT aaa FROM test'
1218
1126
  @d.select(:a, 'b'.lit).sql.should == 'SELECT a, b FROM test'
1219
- @d.select(:test__cc, 'test.d AS e'.lit).sql.should ==
1220
- 'SELECT test.cc, test.d AS e FROM test'
1221
- @d.select('test.d AS e'.lit, :test__cc).sql.should ==
1222
- 'SELECT test.d AS e, test.cc FROM test'
1223
-
1224
- # symbol helpers
1225
- @d.select(:test.*).sql.should ==
1226
- 'SELECT test.* FROM test'
1227
- @d.select(:test__name.as(:n)).sql.should ==
1228
- 'SELECT test.name AS n FROM test'
1229
- @d.select(:test__name___n).sql.should ==
1230
- 'SELECT test.name AS n FROM test'
1127
+ @d.select(:test__cc, 'test.d AS e'.lit).sql.should == 'SELECT test.cc, test.d AS e FROM test'
1128
+ @d.select('test.d AS e'.lit, :test__cc).sql.should == 'SELECT test.d AS e, test.cc FROM test'
1129
+ @d.select(:test__name___n).sql.should == 'SELECT test.name AS n FROM test'
1130
+ end
1131
+
1132
+ specify "should accept ColumnAlls" do
1133
+ @d.select(:test.*).sql.should == 'SELECT test.* FROM test'
1134
+ end
1135
+
1136
+ specify "should accept QualifiedIdentifiers" do
1137
+ @d.select(:test__name.as(:n)).sql.should == 'SELECT test.name AS n FROM test'
1231
1138
  end
1232
1139
 
1233
1140
  specify "should use the wildcard if no arguments are given" do
@@ -1235,20 +1142,17 @@ describe "Dataset#select" do
1235
1142
  end
1236
1143
 
1237
1144
  specify "should accept a hash for AS values" do
1238
- @d.select(:name => 'n', :__ggh => 'age').sql.should =~
1239
- /SELECT ((name AS n, __ggh AS age)|(__ggh AS age, name AS n)) FROM test/
1145
+ @d.select(:name => 'n', :__ggh => 'age').sql.should =~ /SELECT ((name AS n, __ggh AS age)|(__ggh AS age, name AS n)) FROM test/
1240
1146
  end
1241
1147
 
1242
- specify "should overrun the previous select option" do
1148
+ specify "should override the previous select option" do
1243
1149
  @d.select!(:a, :b, :c).select.sql.should == 'SELECT * FROM test'
1244
1150
  @d.select!(:price).select(:name).sql.should == 'SELECT name FROM test'
1245
1151
  end
1246
1152
 
1247
1153
  specify "should accept arbitrary objects and literalize them correctly" do
1248
1154
  @d.select(1, :a, 't').sql.should == "SELECT 1, a, 't' FROM test"
1249
-
1250
1155
  @d.select(nil, :sum.sql_function(:t), :x___y).sql.should == "SELECT NULL, sum(t), x AS y FROM test"
1251
-
1252
1156
  @d.select(nil, 1, :x => :y).sql.should == "SELECT NULL, 1, x AS y FROM test"
1253
1157
  end
1254
1158
 
@@ -1297,7 +1201,7 @@ describe "Dataset#select_all" do
1297
1201
  @d.select_all.sql.should == 'SELECT * FROM test'
1298
1202
  end
1299
1203
 
1300
- specify "should overrun the previous select option" do
1204
+ specify "should override the previous select option" do
1301
1205
  @d.select!(:a, :b, :c).select_all.sql.should == 'SELECT * FROM test'
1302
1206
  end
1303
1207
 
@@ -1394,38 +1298,31 @@ describe "Dataset#order" do
1394
1298
  end
1395
1299
 
1396
1300
  specify "should include an ORDER BY clause in the select statement" do
1397
- @dataset.order(:name).sql.should ==
1398
- 'SELECT * FROM test ORDER BY name'
1301
+ @dataset.order(:name).sql.should == 'SELECT * FROM test ORDER BY name'
1399
1302
  end
1400
1303
 
1401
1304
  specify "should accept multiple arguments" do
1402
- @dataset.order(:name, :price.desc).sql.should ==
1403
- 'SELECT * FROM test ORDER BY name, price DESC'
1305
+ @dataset.order(:name, :price.desc).sql.should == 'SELECT * FROM test ORDER BY name, price DESC'
1404
1306
  end
1405
1307
 
1406
1308
  specify "should accept :nulls options for asc and desc" do
1407
- @dataset.order(:name.asc(:nulls=>:last), :price.desc(:nulls=>:first)).sql.should ==
1408
- 'SELECT * FROM test ORDER BY name ASC NULLS LAST, price DESC NULLS FIRST'
1309
+ @dataset.order(:name.asc(:nulls=>:last), :price.desc(:nulls=>:first)).sql.should == 'SELECT * FROM test ORDER BY name ASC NULLS LAST, price DESC NULLS FIRST'
1409
1310
  end
1410
1311
 
1411
- specify "should overrun a previous ordering" do
1412
- @dataset.order(:name).order(:stamp).sql.should ==
1413
- 'SELECT * FROM test ORDER BY stamp'
1312
+ specify "should override a previous ordering" do
1313
+ @dataset.order(:name).order(:stamp).sql.should == 'SELECT * FROM test ORDER BY stamp'
1414
1314
  end
1415
1315
 
1416
1316
  specify "should accept a literal string" do
1417
- @dataset.order('dada ASC'.lit).sql.should ==
1418
- 'SELECT * FROM test ORDER BY dada ASC'
1317
+ @dataset.order('dada ASC'.lit).sql.should == 'SELECT * FROM test ORDER BY dada ASC'
1419
1318
  end
1420
1319
 
1421
1320
  specify "should accept a hash as an expression" do
1422
- @dataset.order(:name=>nil).sql.should ==
1423
- 'SELECT * FROM test ORDER BY (name IS NULL)'
1321
+ @dataset.order(:name=>nil).sql.should == 'SELECT * FROM test ORDER BY (name IS NULL)'
1424
1322
  end
1425
1323
 
1426
1324
  specify "should accept a nil to remove ordering" do
1427
- @dataset.order(:bah).order(nil).sql.should ==
1428
- 'SELECT * FROM test'
1325
+ @dataset.order(:bah).order(nil).sql.should == 'SELECT * FROM test'
1429
1326
  end
1430
1327
 
1431
1328
  specify "should accept a block that yields a virtual row" do
@@ -1502,28 +1399,23 @@ describe "Dataset#order_by" do
1502
1399
  end
1503
1400
 
1504
1401
  specify "should include an ORDER BY clause in the select statement" do
1505
- @dataset.order_by(:name).sql.should ==
1506
- 'SELECT * FROM test ORDER BY name'
1402
+ @dataset.order_by(:name).sql.should == 'SELECT * FROM test ORDER BY name'
1507
1403
  end
1508
1404
 
1509
1405
  specify "should accept multiple arguments" do
1510
- @dataset.order_by(:name, :price.desc).sql.should ==
1511
- 'SELECT * FROM test ORDER BY name, price DESC'
1406
+ @dataset.order_by(:name, :price.desc).sql.should == 'SELECT * FROM test ORDER BY name, price DESC'
1512
1407
  end
1513
1408
 
1514
- specify "should overrun a previous ordering" do
1515
- @dataset.order_by(:name).order(:stamp).sql.should ==
1516
- 'SELECT * FROM test ORDER BY stamp'
1409
+ specify "should override a previous ordering" do
1410
+ @dataset.order_by(:name).order(:stamp).sql.should == 'SELECT * FROM test ORDER BY stamp'
1517
1411
  end
1518
1412
 
1519
1413
  specify "should accept a string" do
1520
- @dataset.order_by('dada ASC'.lit).sql.should ==
1521
- 'SELECT * FROM test ORDER BY dada ASC'
1414
+ @dataset.order_by('dada ASC'.lit).sql.should == 'SELECT * FROM test ORDER BY dada ASC'
1522
1415
  end
1523
1416
 
1524
1417
  specify "should accept a nil to remove ordering" do
1525
- @dataset.order_by(:bah).order_by(nil).sql.should ==
1526
- 'SELECT * FROM test'
1418
+ @dataset.order_by(:bah).order_by(nil).sql.should == 'SELECT * FROM test'
1527
1419
  end
1528
1420
  end
1529
1421
 
@@ -1556,13 +1448,11 @@ describe "Dataset#order_prepend" do
1556
1448
  end
1557
1449
 
1558
1450
  specify "should include an ORDER BY clause in the select statement" do
1559
- @dataset.order_prepend(:name).sql.should ==
1560
- 'SELECT * FROM test ORDER BY name'
1451
+ @dataset.order_prepend(:name).sql.should == 'SELECT * FROM test ORDER BY name'
1561
1452
  end
1562
1453
 
1563
1454
  specify "should add to the beginning of a previous ordering" do
1564
- @dataset.order(:name).order_prepend(:stamp.desc).sql.should ==
1565
- 'SELECT * FROM test ORDER BY stamp DESC, name'
1455
+ @dataset.order(:name).order_prepend(:stamp.desc).sql.should == 'SELECT * FROM test ORDER BY stamp DESC, name'
1566
1456
  end
1567
1457
 
1568
1458
  specify "should accept a block that yields a virtual row" do
@@ -1577,45 +1467,36 @@ describe "Dataset#reverse_order" do
1577
1467
  end
1578
1468
 
1579
1469
  specify "should use DESC as default order" do
1580
- @dataset.reverse_order(:name).sql.should ==
1581
- 'SELECT * FROM test ORDER BY name DESC'
1470
+ @dataset.reverse_order(:name).sql.should == 'SELECT * FROM test ORDER BY name DESC'
1582
1471
  end
1583
1472
 
1584
1473
  specify "should invert the order given" do
1585
- @dataset.reverse_order(:name.desc).sql.should ==
1586
- 'SELECT * FROM test ORDER BY name ASC'
1474
+ @dataset.reverse_order(:name.desc).sql.should == 'SELECT * FROM test ORDER BY name ASC'
1587
1475
  end
1588
1476
 
1589
1477
  specify "should invert the order for ASC expressions" do
1590
- @dataset.reverse_order(:name.asc).sql.should ==
1591
- 'SELECT * FROM test ORDER BY name DESC'
1478
+ @dataset.reverse_order(:name.asc).sql.should == 'SELECT * FROM test ORDER BY name DESC'
1592
1479
  end
1593
1480
 
1594
1481
  specify "should accept multiple arguments" do
1595
- @dataset.reverse_order(:name, :price.desc).sql.should ==
1596
- 'SELECT * FROM test ORDER BY name DESC, price ASC'
1482
+ @dataset.reverse_order(:name, :price.desc).sql.should == 'SELECT * FROM test ORDER BY name DESC, price ASC'
1597
1483
  end
1598
1484
 
1599
1485
  specify "should handles NULLS ordering correctly when reversing" do
1600
- @dataset.reverse_order(:name.asc(:nulls=>:first), :price.desc(:nulls=>:last)).sql.should ==
1601
- 'SELECT * FROM test ORDER BY name DESC NULLS LAST, price ASC NULLS FIRST'
1486
+ @dataset.reverse_order(:name.asc(:nulls=>:first), :price.desc(:nulls=>:last)).sql.should == 'SELECT * FROM test ORDER BY name DESC NULLS LAST, price ASC NULLS FIRST'
1602
1487
  end
1603
1488
 
1604
1489
  specify "should reverse a previous ordering if no arguments are given" do
1605
- @dataset.order(:name).reverse_order.sql.should ==
1606
- 'SELECT * FROM test ORDER BY name DESC'
1607
- @dataset.order(:clumsy.desc, :fool).reverse_order.sql.should ==
1608
- 'SELECT * FROM test ORDER BY clumsy ASC, fool DESC'
1490
+ @dataset.order(:name).reverse_order.sql.should == 'SELECT * FROM test ORDER BY name DESC'
1491
+ @dataset.order(:clumsy.desc, :fool).reverse_order.sql.should == 'SELECT * FROM test ORDER BY clumsy ASC, fool DESC'
1609
1492
  end
1610
1493
 
1611
1494
  specify "should return an unordered dataset for a dataset with no order" do
1612
- @dataset.unordered.reverse_order.sql.should ==
1613
- 'SELECT * FROM test'
1495
+ @dataset.unordered.reverse_order.sql.should == 'SELECT * FROM test'
1614
1496
  end
1615
1497
 
1616
1498
  specify "should have #reverse alias" do
1617
- @dataset.order(:name).reverse.sql.should ==
1618
- 'SELECT * FROM test ORDER BY name DESC'
1499
+ @dataset.order(:name).reverse.sql.should == 'SELECT * FROM test ORDER BY name DESC'
1619
1500
  end
1620
1501
  end
1621
1502
 
@@ -1625,42 +1506,33 @@ describe "Dataset#limit" do
1625
1506
  end
1626
1507
 
1627
1508
  specify "should include a LIMIT clause in the select statement" do
1628
- @dataset.limit(10).sql.should ==
1629
- 'SELECT * FROM test LIMIT 10'
1509
+ @dataset.limit(10).sql.should == 'SELECT * FROM test LIMIT 10'
1630
1510
  end
1631
1511
 
1632
1512
  specify "should accept ranges" do
1633
- @dataset.limit(3..7).sql.should ==
1634
- 'SELECT * FROM test LIMIT 5 OFFSET 3'
1635
-
1636
- @dataset.limit(3...7).sql.should ==
1637
- 'SELECT * FROM test LIMIT 4 OFFSET 3'
1513
+ @dataset.limit(3..7).sql.should == 'SELECT * FROM test LIMIT 5 OFFSET 3'
1514
+ @dataset.limit(3...7).sql.should == 'SELECT * FROM test LIMIT 4 OFFSET 3'
1638
1515
  end
1639
1516
 
1640
1517
  specify "should include an offset if a second argument is given" do
1641
- @dataset.limit(6, 10).sql.should ==
1642
- 'SELECT * FROM test LIMIT 6 OFFSET 10'
1643
- end
1518
+ @dataset.limit(6, 10).sql.should == 'SELECT * FROM test LIMIT 6 OFFSET 10'
1519
+ end
1644
1520
 
1645
1521
  specify "should convert regular strings to integers" do
1646
- @dataset.limit('6', 'a() - 1').sql.should ==
1647
- 'SELECT * FROM test LIMIT 6 OFFSET 0'
1522
+ @dataset.limit('6', 'a() - 1').sql.should == 'SELECT * FROM test LIMIT 6 OFFSET 0'
1648
1523
  end
1649
1524
 
1650
1525
  specify "should not convert literal strings to integers" do
1651
- @dataset.limit('6'.lit, 'a() - 1'.lit).sql.should ==
1652
- 'SELECT * FROM test LIMIT 6 OFFSET a() - 1'
1526
+ @dataset.limit('6'.lit, 'a() - 1'.lit).sql.should == 'SELECT * FROM test LIMIT 6 OFFSET a() - 1'
1653
1527
  end
1654
1528
 
1655
1529
  specify "should not convert other objects" do
1656
- @dataset.limit(6, :a.sql_function - 1).sql.should ==
1657
- 'SELECT * FROM test LIMIT 6 OFFSET (a() - 1)'
1530
+ @dataset.limit(6, :a.sql_function - 1).sql.should == 'SELECT * FROM test LIMIT 6 OFFSET (a() - 1)'
1658
1531
  end
1659
1532
 
1660
1533
  specify "should work with fixed sql datasets" do
1661
1534
  @dataset.opts[:sql] = 'select * from cccc'
1662
- @dataset.limit(6, 10).sql.should ==
1663
- 'SELECT * FROM (select * from cccc) AS t1 LIMIT 6 OFFSET 10'
1535
+ @dataset.limit(6, 10).sql.should == 'SELECT * FROM (select * from cccc) AS t1 LIMIT 6 OFFSET 10'
1664
1536
  end
1665
1537
 
1666
1538
  specify "should raise an error if an invalid limit or offset is used" do
@@ -1674,15 +1546,10 @@ describe "Dataset#limit" do
1674
1546
  end
1675
1547
 
1676
1548
  describe "Dataset#naked" do
1677
- before do
1678
- @d1 = Sequel::Dataset.new(nil, {1 => 2, 3 => 4})
1679
- @d2 = @d1.clone
1680
- @d2.row_proc = Proc.new{|r| r}
1681
- end
1682
-
1683
1549
  specify "should remove any existing row_proc" do
1684
- naked = @d2.naked
1685
- naked.row_proc.should be_nil
1550
+ d = Sequel::Dataset.new(nil)
1551
+ d.row_proc = Proc.new{|r| r}
1552
+ d.naked.row_proc.should be_nil
1686
1553
  end
1687
1554
  end
1688
1555
 
@@ -1712,11 +1579,11 @@ end
1712
1579
 
1713
1580
  describe "Dataset#map" do
1714
1581
  before do
1715
- @d = DummyDataset.new(nil).from(:items)
1582
+ @d = Sequel.mock(:fetch=>[{:a => 1, :b => 2}, {:a => 3, :b => 4}, {:a => 5, :b => 6}])[:items]
1716
1583
  end
1717
1584
 
1718
1585
  specify "should provide the usual functionality if no argument is given" do
1719
- @d.map {|n| n[:a] + n[:b]}.should == [3, 7, 11]
1586
+ @d.map{|n| n[:a] + n[:b]}.should == [3, 7, 11]
1720
1587
  end
1721
1588
 
1722
1589
  specify "should map using #[column name] if column name is given" do
@@ -1727,14 +1594,25 @@ describe "Dataset#map" do
1727
1594
  @d.map([:a, :b]).should == [[1, 2], [3, 4], [5, 6]]
1728
1595
  end
1729
1596
 
1597
+ specify "should not call the row_proc if an argument is given" do
1598
+ @d.row_proc = proc{|r| h = {}; r.keys.each{|k| h[k] = r[k] * 2}; h}
1599
+ @d.map(:a).should == [1, 3, 5]
1600
+ @d.map([:a, :b]).should == [[1, 2], [3, 4], [5, 6]]
1601
+ end
1602
+
1603
+ specify "should call the row_proc if no argument is given" do
1604
+ @d.row_proc = proc{|r| h = {}; r.keys.each{|k| h[k] = r[k] * 2}; h}
1605
+ @d.map{|n| n[:a] + n[:b]}.should == [6, 14, 22]
1606
+ end
1607
+
1730
1608
  specify "should return the complete dataset values if nothing is given" do
1731
- @d.map.to_a.should == DummyDataset::VALUES
1609
+ @d.map.to_a.should == [{:a => 1, :b => 2}, {:a => 3, :b => 4}, {:a => 5, :b => 6}]
1732
1610
  end
1733
1611
  end
1734
1612
 
1735
1613
  describe "Dataset#to_hash" do
1736
1614
  before do
1737
- @d = DummyDataset.new(nil).from(:items)
1615
+ @d = Sequel.mock(:fetch=>[{:a => 1, :b => 2}, {:a => 3, :b => 4}, {:a => 5, :b => 6}])[:items]
1738
1616
  end
1739
1617
 
1740
1618
  specify "should provide a hash with the first column as key and the second as value" do
@@ -1753,11 +1631,28 @@ describe "Dataset#to_hash" do
1753
1631
  @d.to_hash([:b, :a], [:a, :b]).should == {[2, 1] => [1, 2], [4, 3] => [3, 4], [6, 5] => [5, 6]}
1754
1632
  @d.to_hash([:a, :b]).should == {[1, 2] => {:a => 1, :b => 2}, [3, 4] => {:a => 3, :b => 4}, [5, 6] => {:a => 5, :b => 6}}
1755
1633
  end
1634
+
1635
+ specify "should not call the row_proc if two arguments are given" do
1636
+ @d.row_proc = proc{|r| h = {}; r.keys.each{|k| h[k] = r[k] * 2}; h}
1637
+ @d.to_hash(:a, :b).should == {1 => 2, 3 => 4, 5 => 6}
1638
+ @d.to_hash(:b, :a).should == {2 => 1, 4 => 3, 6 => 5}
1639
+ @d.to_hash([:a, :b], :b).should == {[1, 2] => 2, [3, 4] => 4, [5, 6] => 6}
1640
+ @d.to_hash(:b, [:a, :b]).should == {2 => [1, 2], 4 => [3, 4], 6 => [5, 6]}
1641
+ @d.to_hash([:b, :a], [:a, :b]).should == {[2, 1] => [1, 2], [4, 3] => [3, 4], [6, 5] => [5, 6]}
1642
+ end
1643
+
1644
+ specify "should call the row_proc if only a single argument is given" do
1645
+ @d.row_proc = proc{|r| h = {}; r.keys.each{|k| h[k] = r[k] * 2}; h}
1646
+ @d.to_hash(:a).should == {2 => {:a => 2, :b => 4}, 6 => {:a => 6, :b => 8}, 10 => {:a => 10, :b => 12}}
1647
+ @d.to_hash(:b).should == {4 => {:a => 2, :b => 4}, 8 => {:a => 6, :b => 8}, 12 => {:a => 10, :b => 12}}
1648
+ @d.to_hash([:a, :b]).should == {[2, 4] => {:a => 2, :b => 4}, [6, 8] => {:a => 6, :b => 8}, [10, 12] => {:a => 10, :b => 12}}
1649
+ end
1650
+
1756
1651
  end
1757
1652
 
1758
1653
  describe "Dataset#distinct" do
1759
1654
  before do
1760
- @db = MockDatabase.new
1655
+ @db = Sequel.mock
1761
1656
  @dataset = @db[:test].select(:name)
1762
1657
  end
1763
1658
 
@@ -1784,113 +1679,84 @@ end
1784
1679
 
1785
1680
  describe "Dataset#count" do
1786
1681
  before do
1787
- @c = Class.new(Sequel::Dataset) do
1788
- def self.sql
1789
- @@sql
1790
- end
1791
-
1792
- def fetch_rows(sql)
1793
- @columns = [sql =~ /SELECT COUNT/i ? :count : :a]
1794
- @@sql = sql
1795
- yield({@columns.first=>1})
1796
- end
1797
- end
1798
- @dataset = @c.new(nil).from(:test)
1682
+ @db = Sequel.mock(:fetch=>{:count=>1})
1683
+ @dataset = @db.from(:test).columns(:count)
1799
1684
  end
1800
1685
 
1801
1686
  specify "should format SQL properly" do
1802
1687
  @dataset.count.should == 1
1803
- @c.sql.should == 'SELECT COUNT(*) AS count FROM test LIMIT 1'
1688
+ @db.sqls.should == ['SELECT COUNT(*) AS count FROM test LIMIT 1']
1804
1689
  end
1805
1690
 
1806
1691
  specify "should include the where clause if it's there" do
1807
1692
  @dataset.filter(:abc.sql_number < 30).count.should == 1
1808
- @c.sql.should == 'SELECT COUNT(*) AS count FROM test WHERE (abc < 30) LIMIT 1'
1693
+ @db.sqls.should == ['SELECT COUNT(*) AS count FROM test WHERE (abc < 30) LIMIT 1']
1809
1694
  end
1810
1695
 
1811
1696
  specify "should count properly for datasets with fixed sql" do
1812
1697
  @dataset.opts[:sql] = "select abc from xyz"
1813
1698
  @dataset.count.should == 1
1814
- @c.sql.should == "SELECT COUNT(*) AS count FROM (select abc from xyz) AS t1 LIMIT 1"
1699
+ @db.sqls.should == ["SELECT COUNT(*) AS count FROM (select abc from xyz) AS t1 LIMIT 1"]
1815
1700
  end
1816
1701
 
1817
1702
  specify "should count properly when using UNION, INTERSECT, or EXCEPT" do
1818
1703
  @dataset.union(@dataset).count.should == 1
1819
- @c.sql.should == "SELECT COUNT(*) AS count FROM (SELECT * FROM test UNION SELECT * FROM test) AS t1 LIMIT 1"
1704
+ @db.sqls.should == ["SELECT COUNT(*) AS count FROM (SELECT * FROM test UNION SELECT * FROM test) AS t1 LIMIT 1"]
1820
1705
  @dataset.intersect(@dataset).count.should == 1
1821
- @c.sql.should == "SELECT COUNT(*) AS count FROM (SELECT * FROM test INTERSECT SELECT * FROM test) AS t1 LIMIT 1"
1706
+ @db.sqls.should == ["SELECT COUNT(*) AS count FROM (SELECT * FROM test INTERSECT SELECT * FROM test) AS t1 LIMIT 1"]
1822
1707
  @dataset.except(@dataset).count.should == 1
1823
- @c.sql.should == "SELECT COUNT(*) AS count FROM (SELECT * FROM test EXCEPT SELECT * FROM test) AS t1 LIMIT 1"
1708
+ @db.sqls.should == ["SELECT COUNT(*) AS count FROM (SELECT * FROM test EXCEPT SELECT * FROM test) AS t1 LIMIT 1"]
1824
1709
  end
1825
1710
 
1826
1711
  specify "should return limit if count is greater than it" do
1827
1712
  @dataset.limit(5).count.should == 1
1828
- @c.sql.should == "SELECT COUNT(*) AS count FROM (SELECT * FROM test LIMIT 5) AS t1 LIMIT 1"
1713
+ @db.sqls.should == ["SELECT COUNT(*) AS count FROM (SELECT * FROM test LIMIT 5) AS t1 LIMIT 1"]
1829
1714
  end
1830
1715
 
1831
1716
  it "should work on a graphed_dataset" do
1832
1717
  @dataset.should_receive(:columns).twice.and_return([:a])
1833
1718
  @dataset.graph(@dataset, [:a], :table_alias=>:test2).count.should == 1
1834
- @c.sql.should == 'SELECT COUNT(*) AS count FROM test LEFT OUTER JOIN test AS test2 USING (a) LIMIT 1'
1719
+ @db.sqls.should == ['SELECT COUNT(*) AS count FROM test LEFT OUTER JOIN test AS test2 USING (a) LIMIT 1']
1835
1720
  end
1836
1721
 
1837
1722
  specify "should not cache the columns value" do
1838
- ds = @dataset.from(:blah)
1723
+ ds = @dataset.from(:blah).columns(:a)
1839
1724
  ds.columns.should == [:a]
1840
1725
  ds.count.should == 1
1841
- @c.sql.should == 'SELECT COUNT(*) AS count FROM blah LIMIT 1'
1726
+ @db.sqls.should == ['SELECT COUNT(*) AS count FROM blah LIMIT 1']
1842
1727
  ds.columns.should == [:a]
1843
1728
  end
1844
1729
  end
1845
1730
 
1846
-
1847
1731
  describe "Dataset#group_and_count" do
1848
1732
  before do
1849
- @c = Class.new(Sequel::Dataset) do
1850
- def self.sql
1851
- @@sql
1852
- end
1853
-
1854
- def fetch_rows(sql)
1855
- @@sql = sql
1856
- yield({1 => 1})
1857
- end
1858
- end
1859
- @ds = @c.new(nil).from(:test)
1733
+ @ds = Sequel::Dataset.new(nil).from(:test)
1860
1734
  end
1861
1735
 
1862
1736
  specify "should format SQL properly" do
1863
- @ds.group_and_count(:name).sql.should ==
1864
- "SELECT name, count(*) AS count FROM test GROUP BY name"
1737
+ @ds.group_and_count(:name).sql.should == "SELECT name, count(*) AS count FROM test GROUP BY name"
1865
1738
  end
1866
1739
 
1867
1740
  specify "should accept multiple columns for grouping" do
1868
- @ds.group_and_count(:a, :b).sql.should ==
1869
- "SELECT a, b, count(*) AS count FROM test GROUP BY a, b"
1741
+ @ds.group_and_count(:a, :b).sql.should == "SELECT a, b, count(*) AS count FROM test GROUP BY a, b"
1870
1742
  end
1871
1743
 
1872
1744
  specify "should format column aliases in the select clause but not in the group clause" do
1873
- @ds.group_and_count(:name___n).sql.should ==
1874
- "SELECT name AS n, count(*) AS count FROM test GROUP BY name"
1875
- @ds.group_and_count(:name__n).sql.should ==
1876
- "SELECT name.n, count(*) AS count FROM test GROUP BY name.n"
1745
+ @ds.group_and_count(:name___n).sql.should == "SELECT name AS n, count(*) AS count FROM test GROUP BY name"
1746
+ @ds.group_and_count(:name__n).sql.should == "SELECT name.n, count(*) AS count FROM test GROUP BY name.n"
1877
1747
  end
1878
1748
 
1879
1749
  specify "should handle identifiers" do
1880
- @ds.group_and_count(:name___n.identifier).sql.should ==
1881
- "SELECT name___n, count(*) AS count FROM test GROUP BY name___n"
1750
+ @ds.group_and_count(:name___n.identifier).sql.should == "SELECT name___n, count(*) AS count FROM test GROUP BY name___n"
1882
1751
  end
1883
1752
 
1884
1753
  specify "should handle literal strings" do
1885
- @ds.group_and_count("name".lit).sql.should ==
1886
- "SELECT name, count(*) AS count FROM test GROUP BY name"
1754
+ @ds.group_and_count("name".lit).sql.should == "SELECT name, count(*) AS count FROM test GROUP BY name"
1887
1755
  end
1888
1756
 
1889
1757
  specify "should handle aliased expressions" do
1890
- @ds.group_and_count(:name.as(:n)).sql.should ==
1891
- "SELECT name AS n, count(*) AS count FROM test GROUP BY name"
1892
- @ds.group_and_count(:name.identifier.as(:n)).sql.should ==
1893
- "SELECT name AS n, count(*) AS count FROM test GROUP BY name"
1758
+ @ds.group_and_count(:name.as(:n)).sql.should == "SELECT name AS n, count(*) AS count FROM test GROUP BY name"
1759
+ @ds.group_and_count(:name.identifier.as(:n)).sql.should == "SELECT name AS n, count(*) AS count FROM test GROUP BY name"
1894
1760
  end
1895
1761
 
1896
1762
  specify "should take a virtual row block" do
@@ -1902,20 +1768,11 @@ end
1902
1768
 
1903
1769
  describe "Dataset#empty?" do
1904
1770
  specify "should return true if records exist in the dataset" do
1905
- @c = Class.new(Sequel::Dataset) do
1906
- def self.sql
1907
- @@sql
1908
- end
1909
-
1910
- def fetch_rows(sql)
1911
- @@sql = sql
1912
- yield({1 => 1}) unless sql =~ /WHERE 'f'/
1913
- end
1914
- end
1915
- @c.new(nil).from(:test).should_not be_empty
1916
- @c.sql.should == 'SELECT 1 FROM test LIMIT 1'
1917
- @c.new(nil).from(:test).filter(false).should be_empty
1918
- @c.sql.should == "SELECT 1 FROM test WHERE 'f' LIMIT 1"
1771
+ db = Sequel.mock(:fetch=>proc{|sql| {1=>1} unless sql =~ /WHERE 'f'/})
1772
+ db.from(:test).should_not be_empty
1773
+ db.sqls.should == ['SELECT 1 FROM test LIMIT 1']
1774
+ db.from(:test).filter(false).should be_empty
1775
+ db.sqls.should == ["SELECT 1 FROM test WHERE 'f' LIMIT 1"]
1919
1776
  end
1920
1777
  end
1921
1778
 
@@ -1994,25 +1851,31 @@ describe "Dataset#from_self" do
1994
1851
  'SELECT * FROM (SELECT name FROM test LIMIT 1) AS some_name INNER JOIN posts ON (posts.alias = some_name.name)'
1995
1852
  end
1996
1853
 
1997
- specify "should not options such as server" do
1854
+ specify "should not remove non-SQL options such as :server" do
1998
1855
  @ds.server(:blah).from_self(:alias=>:some_name).opts[:server].should == :blah
1999
1856
  end
2000
1857
 
1858
+ specify "should hoist WITH clauses in current dataset if dataset doesn't support WITH in subselect" do
1859
+ ds = Sequel::Dataset.new(nil)
1860
+ ds.meta_def(:supports_cte?){true}
1861
+ ds.meta_def(:supports_cte_in_subselect?){false}
1862
+ ds.from(:a).with(:a, ds.from(:b)).from_self.sql.should == 'WITH a AS (SELECT * FROM b) SELECT * FROM (SELECT * FROM a) AS t1'
1863
+ ds.from(:a, :c).with(:a, ds.from(:b)).with(:c, ds.from(:d)).from_self.sql.should == 'WITH a AS (SELECT * FROM b), c AS (SELECT * FROM d) SELECT * FROM (SELECT * FROM a, c) AS t1'
1864
+ end
2001
1865
  end
2002
1866
 
2003
1867
  describe "Dataset#join_table" do
2004
1868
  before do
2005
- @d = MockDataset.new(nil).from(:items)
1869
+ @d = Sequel::Dataset.new(nil).from(:items)
2006
1870
  @d.quote_identifiers = true
2007
1871
  end
2008
1872
 
2009
1873
  specify "should format the JOIN clause properly" do
2010
- @d.join_table(:left_outer, :categories, :category_id => :id).sql.should ==
2011
- 'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
1874
+ @d.join_table(:left_outer, :categories, :category_id => :id).sql.should == 'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
2012
1875
  end
2013
1876
 
2014
1877
  specify "should handle multiple conditions on the same join table column" do
2015
- @d.join_table(:left_outer, :categories, [[:category_id, :id], [:category_id, 0..100]]).sql.should ==
1878
+ @d.join_table(:left_outer, :categories, [[:category_id, :id], [:category_id, 0..100]]).sql.should ==
2016
1879
  'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON (("categories"."category_id" = "items"."id") AND ("categories"."category_id" >= 0) AND ("categories"."category_id" <= 100))'
2017
1880
  end
2018
1881
 
@@ -2022,45 +1885,30 @@ describe "Dataset#join_table" do
2022
1885
  end
2023
1886
 
2024
1887
  specify "should include ORDER BY clause if applicable" do
2025
- @d.order(:stamp).join_table(:full_outer, :categories, :category_id => :id).sql.should ==
2026
- 'SELECT * FROM "items" FULL OUTER JOIN "categories" ON ("categories"."category_id" = "items"."id") ORDER BY "stamp"'
1888
+ @d.order(:stamp).join_table(:full_outer, :categories, :category_id => :id).sql.should == 'SELECT * FROM "items" FULL OUTER JOIN "categories" ON ("categories"."category_id" = "items"."id") ORDER BY "stamp"'
2027
1889
  end
2028
1890
 
2029
1891
  specify "should support multiple joins" do
2030
- @d.join_table(:inner, :b, :items_id=>:id).join_table(:left_outer, :c, :b_id => :b__id).sql.should ==
2031
- 'SELECT * FROM "items" INNER JOIN "b" ON ("b"."items_id" = "items"."id") LEFT OUTER JOIN "c" ON ("c"."b_id" = "b"."id")'
1892
+ @d.join_table(:inner, :b, :items_id=>:id).join_table(:left_outer, :c, :b_id => :b__id).sql.should == 'SELECT * FROM "items" INNER JOIN "b" ON ("b"."items_id" = "items"."id") LEFT OUTER JOIN "c" ON ("c"."b_id" = "b"."id")'
2032
1893
  end
2033
1894
 
2034
1895
  specify "should support arbitrary join types" do
2035
- @d.join_table(:magic, :categories, :category_id=>:id).sql.should ==
2036
- 'SELECT * FROM "items" MAGIC JOIN "categories" ON ("categories"."category_id" = "items"."id")'
1896
+ @d.join_table(:magic, :categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" MAGIC JOIN "categories" ON ("categories"."category_id" = "items"."id")'
2037
1897
  end
2038
1898
 
2039
1899
  specify "should support many join methods" do
2040
- @d.left_outer_join(:categories, :category_id=>:id).sql.should ==
2041
- 'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
2042
- @d.right_outer_join(:categories, :category_id=>:id).sql.should ==
2043
- 'SELECT * FROM "items" RIGHT OUTER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
2044
- @d.full_outer_join(:categories, :category_id=>:id).sql.should ==
2045
- 'SELECT * FROM "items" FULL OUTER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
2046
- @d.inner_join(:categories, :category_id=>:id).sql.should ==
2047
- 'SELECT * FROM "items" INNER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
2048
- @d.left_join(:categories, :category_id=>:id).sql.should ==
2049
- 'SELECT * FROM "items" LEFT JOIN "categories" ON ("categories"."category_id" = "items"."id")'
2050
- @d.right_join(:categories, :category_id=>:id).sql.should ==
2051
- 'SELECT * FROM "items" RIGHT JOIN "categories" ON ("categories"."category_id" = "items"."id")'
2052
- @d.full_join(:categories, :category_id=>:id).sql.should ==
2053
- 'SELECT * FROM "items" FULL JOIN "categories" ON ("categories"."category_id" = "items"."id")'
2054
- @d.natural_join(:categories).sql.should ==
2055
- 'SELECT * FROM "items" NATURAL JOIN "categories"'
2056
- @d.natural_left_join(:categories).sql.should ==
2057
- 'SELECT * FROM "items" NATURAL LEFT JOIN "categories"'
2058
- @d.natural_right_join(:categories).sql.should ==
2059
- 'SELECT * FROM "items" NATURAL RIGHT JOIN "categories"'
2060
- @d.natural_full_join(:categories).sql.should ==
2061
- 'SELECT * FROM "items" NATURAL FULL JOIN "categories"'
2062
- @d.cross_join(:categories).sql.should ==
2063
- 'SELECT * FROM "items" CROSS JOIN "categories"'
1900
+ @d.left_outer_join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
1901
+ @d.right_outer_join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" RIGHT OUTER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
1902
+ @d.full_outer_join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" FULL OUTER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
1903
+ @d.inner_join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
1904
+ @d.left_join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" LEFT JOIN "categories" ON ("categories"."category_id" = "items"."id")'
1905
+ @d.right_join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" RIGHT JOIN "categories" ON ("categories"."category_id" = "items"."id")'
1906
+ @d.full_join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" FULL JOIN "categories" ON ("categories"."category_id" = "items"."id")'
1907
+ @d.natural_join(:categories).sql.should == 'SELECT * FROM "items" NATURAL JOIN "categories"'
1908
+ @d.natural_left_join(:categories).sql.should == 'SELECT * FROM "items" NATURAL LEFT JOIN "categories"'
1909
+ @d.natural_right_join(:categories).sql.should == 'SELECT * FROM "items" NATURAL RIGHT JOIN "categories"'
1910
+ @d.natural_full_join(:categories).sql.should == 'SELECT * FROM "items" NATURAL FULL JOIN "categories"'
1911
+ @d.cross_join(:categories).sql.should == 'SELECT * FROM "items" CROSS JOIN "categories"'
2064
1912
  end
2065
1913
 
2066
1914
  specify "should raise an error if additional arguments are provided to join methods that don't take conditions" do
@@ -2080,95 +1928,68 @@ describe "Dataset#join_table" do
2080
1928
  end
2081
1929
 
2082
1930
  specify "should default to a plain join if nil is used for the type" do
2083
- @d.join_table(nil, :categories, :category_id=>:id).sql.should ==
2084
- 'SELECT * FROM "items" JOIN "categories" ON ("categories"."category_id" = "items"."id")'
1931
+ @d.join_table(nil, :categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" JOIN "categories" ON ("categories"."category_id" = "items"."id")'
2085
1932
  end
2086
1933
 
2087
1934
  specify "should use an inner join for Dataset#join" do
2088
- @d.join(:categories, :category_id=>:id).sql.should ==
2089
- 'SELECT * FROM "items" INNER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
1935
+ @d.join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
2090
1936
  end
2091
1937
 
2092
1938
  specify "should support aliased tables using the deprecated argument" do
2093
- @d.from('stats').join('players', {:id => :player_id}, 'p').sql.should ==
2094
- 'SELECT * FROM "stats" INNER JOIN "players" AS "p" ON ("p"."id" = "stats"."player_id")'
1939
+ @d.from('stats').join('players', {:id => :player_id}, 'p').sql.should == 'SELECT * FROM "stats" INNER JOIN "players" AS "p" ON ("p"."id" = "stats"."player_id")'
2095
1940
  end
2096
1941
 
2097
1942
  specify "should support aliased tables using the :table_alias option" do
2098
- @d.from('stats').join('players', {:id => :player_id}, :table_alias=>:p).sql.should ==
2099
- 'SELECT * FROM "stats" INNER JOIN "players" AS "p" ON ("p"."id" = "stats"."player_id")'
1943
+ @d.from('stats').join('players', {:id => :player_id}, :table_alias=>:p).sql.should == 'SELECT * FROM "stats" INNER JOIN "players" AS "p" ON ("p"."id" = "stats"."player_id")'
2100
1944
  end
2101
1945
 
2102
1946
  specify "should support aliased tables using an implicit alias" do
2103
- @d.from('stats').join(:players.as(:p), {:id => :player_id}).sql.should ==
2104
- 'SELECT * FROM "stats" INNER JOIN "players" AS "p" ON ("p"."id" = "stats"."player_id")'
1947
+ @d.from('stats').join(:players.as(:p), {:id => :player_id}).sql.should == 'SELECT * FROM "stats" INNER JOIN "players" AS "p" ON ("p"."id" = "stats"."player_id")'
2105
1948
  end
2106
1949
 
2107
1950
  specify "should support using an alias for the FROM when doing the first join with unqualified condition columns" do
2108
- ds = MockDataset.new(nil).from(:foo => :f)
2109
- ds.quote_identifiers = true
2110
- ds.join_table(:inner, :bar, :id => :bar_id).sql.should ==
2111
- 'SELECT * FROM "foo" AS "f" INNER JOIN "bar" ON ("bar"."id" = "f"."bar_id")'
1951
+ @d.from(:foo=>:f).join_table(:inner, :bar, :id => :bar_id).sql.should == 'SELECT * FROM "foo" AS "f" INNER JOIN "bar" ON ("bar"."id" = "f"."bar_id")'
2112
1952
  end
2113
1953
 
2114
1954
  specify "should support implicit schemas in from table symbols" do
2115
- @d.from(:s__t).join(:u__v, {:id => :player_id}).sql.should ==
2116
- 'SELECT * FROM "s"."t" INNER JOIN "u"."v" ON ("u"."v"."id" = "s"."t"."player_id")'
1955
+ @d.from(:s__t).join(:u__v, {:id => :player_id}).sql.should == 'SELECT * FROM "s"."t" INNER JOIN "u"."v" ON ("u"."v"."id" = "s"."t"."player_id")'
2117
1956
  end
2118
1957
 
2119
1958
  specify "should support implicit aliases in from table symbols" do
2120
- @d.from(:t___z).join(:v___y, {:id => :player_id}).sql.should ==
2121
- 'SELECT * FROM "t" AS "z" INNER JOIN "v" AS "y" ON ("y"."id" = "z"."player_id")'
2122
- @d.from(:s__t___z).join(:u__v___y, {:id => :player_id}).sql.should ==
2123
- 'SELECT * FROM "s"."t" AS "z" INNER JOIN "u"."v" AS "y" ON ("y"."id" = "z"."player_id")'
1959
+ @d.from(:t___z).join(:v___y, {:id => :player_id}).sql.should == 'SELECT * FROM "t" AS "z" INNER JOIN "v" AS "y" ON ("y"."id" = "z"."player_id")'
1960
+ @d.from(:s__t___z).join(:u__v___y, {:id => :player_id}).sql.should == 'SELECT * FROM "s"."t" AS "z" INNER JOIN "u"."v" AS "y" ON ("y"."id" = "z"."player_id")'
2124
1961
  end
2125
1962
 
2126
1963
  specify "should support AliasedExpressions" do
2127
- @d.from(:s.as(:t)).join(:u.as(:v), {:id => :player_id}).sql.should ==
2128
- 'SELECT * FROM "s" AS "t" INNER JOIN "u" AS "v" ON ("v"."id" = "t"."player_id")'
1964
+ @d.from(:s.as(:t)).join(:u.as(:v), {:id => :player_id}).sql.should == 'SELECT * FROM "s" AS "t" INNER JOIN "u" AS "v" ON ("v"."id" = "t"."player_id")'
2129
1965
  end
2130
1966
 
2131
1967
  specify "should support the :implicit_qualifier option" do
2132
- @d.from('stats').join('players', {:id => :player_id}, :implicit_qualifier=>:p).sql.should ==
2133
- 'SELECT * FROM "stats" INNER JOIN "players" ON ("players"."id" = "p"."player_id")'
1968
+ @d.from('stats').join('players', {:id => :player_id}, :implicit_qualifier=>:p).sql.should == 'SELECT * FROM "stats" INNER JOIN "players" ON ("players"."id" = "p"."player_id")'
2134
1969
  end
2135
1970
 
2136
1971
  specify "should allow for arbitrary conditions in the JOIN clause" do
2137
- @d.join_table(:left_outer, :categories, :status => 0).sql.should ==
2138
- 'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."status" = 0)'
2139
- @d.join_table(:left_outer, :categories, :categorizable_type => "Post").sql.should ==
2140
- 'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."categorizable_type" = \'Post\')'
2141
- @d.join_table(:left_outer, :categories, :timestamp => "CURRENT_TIMESTAMP".lit).sql.should ==
2142
- 'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."timestamp" = CURRENT_TIMESTAMP)'
2143
- @d.join_table(:left_outer, :categories, :status => [1, 2, 3]).sql.should ==
2144
- 'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."status" IN (1, 2, 3))'
1972
+ @d.join_table(:left_outer, :categories, :status => 0).sql.should == 'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."status" = 0)'
1973
+ @d.join_table(:left_outer, :categories, :categorizable_type => "Post").sql.should == 'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."categorizable_type" = \'Post\')'
1974
+ @d.join_table(:left_outer, :categories, :timestamp => "CURRENT_TIMESTAMP".lit).sql.should == 'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."timestamp" = CURRENT_TIMESTAMP)'
1975
+ @d.join_table(:left_outer, :categories, :status => [1, 2, 3]).sql.should == 'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."status" IN (1, 2, 3))'
2145
1976
  end
2146
1977
 
2147
1978
  specify "should raise error for a table without a source" do
2148
- proc {Sequel::Dataset.new(nil).join('players', :id => :player_id)}. \
2149
- should raise_error(Sequel::Error)
1979
+ proc {Sequel::Dataset.new(nil).join('players', :id => :player_id)}.should raise_error(Sequel::Error)
2150
1980
  end
2151
1981
 
2152
1982
  specify "should support joining datasets" do
2153
1983
  ds = Sequel::Dataset.new(nil).from(:categories)
2154
-
2155
- @d.join_table(:left_outer, ds, :item_id => :id).sql.should ==
2156
- 'SELECT * FROM "items" LEFT OUTER JOIN (SELECT * FROM categories) AS "t1" ON ("t1"."item_id" = "items"."id")'
2157
-
1984
+ @d.join_table(:left_outer, ds, :item_id => :id).sql.should == 'SELECT * FROM "items" LEFT OUTER JOIN (SELECT * FROM categories) AS "t1" ON ("t1"."item_id" = "items"."id")'
2158
1985
  ds.filter!(:active => true)
2159
-
2160
- @d.join_table(:left_outer, ds, :item_id => :id).sql.should ==
2161
- 'SELECT * FROM "items" LEFT OUTER JOIN (SELECT * FROM categories WHERE (active IS TRUE)) AS "t1" ON ("t1"."item_id" = "items"."id")'
2162
-
2163
- @d.from_self.join_table(:left_outer, ds, :item_id => :id).sql.should ==
2164
- 'SELECT * FROM (SELECT * FROM "items") AS "t1" LEFT OUTER JOIN (SELECT * FROM categories WHERE (active IS TRUE)) AS "t2" ON ("t2"."item_id" = "t1"."id")'
1986
+ @d.join_table(:left_outer, ds, :item_id => :id).sql.should == 'SELECT * FROM "items" LEFT OUTER JOIN (SELECT * FROM categories WHERE (active IS TRUE)) AS "t1" ON ("t1"."item_id" = "items"."id")'
1987
+ @d.from_self.join_table(:left_outer, ds, :item_id => :id).sql.should == 'SELECT * FROM (SELECT * FROM "items") AS "t1" LEFT OUTER JOIN (SELECT * FROM categories WHERE (active IS TRUE)) AS "t2" ON ("t2"."item_id" = "t1"."id")'
2165
1988
  end
2166
1989
 
2167
1990
  specify "should support joining datasets and aliasing the join" do
2168
1991
  ds = Sequel::Dataset.new(nil).from(:categories)
2169
-
2170
- @d.join_table(:left_outer, ds, {:ds__item_id => :id}, :ds).sql.should ==
2171
- 'SELECT * FROM "items" LEFT OUTER JOIN (SELECT * FROM categories) AS "ds" ON ("ds"."item_id" = "items"."id")'
1992
+ @d.join_table(:left_outer, ds, {:ds__item_id => :id}, :ds).sql.should == 'SELECT * FROM "items" LEFT OUTER JOIN (SELECT * FROM categories) AS "ds" ON ("ds"."item_id" = "items"."id")'
2172
1993
  end
2173
1994
 
2174
1995
  specify "should support joining multiple datasets" do
@@ -2185,40 +2006,30 @@ describe "Dataset#join_table" do
2185
2006
  specify "should support joining objects that respond to :table_name" do
2186
2007
  ds = Object.new
2187
2008
  def ds.table_name; :categories end
2188
-
2189
- @d.join(ds, :item_id => :id).sql.should ==
2190
- 'SELECT * FROM "items" INNER JOIN "categories" ON ("categories"."item_id" = "items"."id")'
2009
+ @d.join(ds, :item_id => :id).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" ON ("categories"."item_id" = "items"."id")'
2191
2010
  end
2192
2011
 
2193
- specify "should support using a SQL String as the join condition" do
2194
- @d.join(:categories, %{c.item_id = items.id}, :c).sql.should ==
2195
- 'SELECT * FROM "items" INNER JOIN "categories" AS "c" ON (c.item_id = items.id)'
2012
+ specify "should support using an SQL String as the join condition" do
2013
+ @d.join(:categories, "c.item_id = items.id", :c).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" AS "c" ON (c.item_id = items.id)'
2196
2014
  end
2197
2015
 
2198
2016
  specify "should support using a boolean column as the join condition" do
2199
- @d.join(:categories, :active).sql.should ==
2200
- 'SELECT * FROM "items" INNER JOIN "categories" ON "active"'
2017
+ @d.join(:categories, :active).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" ON "active"'
2201
2018
  end
2202
2019
 
2203
2020
  specify "should support using an expression as the join condition" do
2204
- @d.join(:categories, :number.sql_number > 10).sql.should ==
2205
- 'SELECT * FROM "items" INNER JOIN "categories" ON ("number" > 10)'
2021
+ @d.join(:categories, :number.sql_number > 10).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" ON ("number" > 10)'
2206
2022
  end
2207
2023
 
2208
- specify "should support natural and cross joins using nil" do
2209
- @d.join_table(:natural, :categories).sql.should ==
2210
- 'SELECT * FROM "items" NATURAL JOIN "categories"'
2211
- @d.join_table(:cross, :categories, nil).sql.should ==
2212
- 'SELECT * FROM "items" CROSS JOIN "categories"'
2213
- @d.join_table(:natural, :categories, nil, :c).sql.should ==
2214
- 'SELECT * FROM "items" NATURAL JOIN "categories" AS "c"'
2024
+ specify "should support natural and cross joins" do
2025
+ @d.join_table(:natural, :categories).sql.should == 'SELECT * FROM "items" NATURAL JOIN "categories"'
2026
+ @d.join_table(:cross, :categories, nil).sql.should == 'SELECT * FROM "items" CROSS JOIN "categories"'
2027
+ @d.join_table(:natural, :categories, nil, :c).sql.should == 'SELECT * FROM "items" NATURAL JOIN "categories" AS "c"'
2215
2028
  end
2216
2029
 
2217
2030
  specify "should support joins with a USING clause if an array of symbols is used" do
2218
- @d.join(:categories, [:id]).sql.should ==
2219
- 'SELECT * FROM "items" INNER JOIN "categories" USING ("id")'
2220
- @d.join(:categories, [:id1, :id2]).sql.should ==
2221
- 'SELECT * FROM "items" INNER JOIN "categories" USING ("id1", "id2")'
2031
+ @d.join(:categories, [:id]).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" USING ("id")'
2032
+ @d.join(:categories, [:id1, :id2]).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" USING ("id1", "id2")'
2222
2033
  end
2223
2034
 
2224
2035
  specify "should emulate JOIN USING (poorly) if the dataset doesn't support it" do
@@ -2286,22 +2097,17 @@ describe "Dataset#join_table" do
2286
2097
  end
2287
2098
 
2288
2099
  specify "should use the block result as the only condition if no condition is given" do
2289
- @d.join(:categories){|j,lj,js| {:b.qualify(j)=>:c.qualify(lj)}}.sql.should ==
2290
- 'SELECT * FROM "items" INNER JOIN "categories" ON ("categories"."b" = "items"."c")'
2291
- @d.join(:categories){|j,lj,js| :b.qualify(j) > :c.qualify(lj)}.sql.should ==
2292
- 'SELECT * FROM "items" INNER JOIN "categories" ON ("categories"."b" > "items"."c")'
2100
+ @d.join(:categories){|j,lj,js| {:b.qualify(j)=>:c.qualify(lj)}}.sql.should == 'SELECT * FROM "items" INNER JOIN "categories" ON ("categories"."b" = "items"."c")'
2101
+ @d.join(:categories){|j,lj,js| :b.qualify(j) > :c.qualify(lj)}.sql.should == 'SELECT * FROM "items" INNER JOIN "categories" ON ("categories"."b" > "items"."c")'
2293
2102
  end
2294
2103
 
2295
2104
  specify "should combine the block conditions and argument conditions if both given" do
2296
- @d.join(:categories, :a=>:d){|j,lj,js| {:b.qualify(j)=>:c.qualify(lj)}}.sql.should ==
2297
- 'SELECT * FROM "items" INNER JOIN "categories" ON (("categories"."a" = "items"."d") AND ("categories"."b" = "items"."c"))'
2298
- @d.join(:categories, :a=>:d){|j,lj,js| :b.qualify(j) > :c.qualify(lj)}.sql.should ==
2299
- 'SELECT * FROM "items" INNER JOIN "categories" ON (("categories"."a" = "items"."d") AND ("categories"."b" > "items"."c"))'
2105
+ @d.join(:categories, :a=>:d){|j,lj,js| {:b.qualify(j)=>:c.qualify(lj)}}.sql.should == 'SELECT * FROM "items" INNER JOIN "categories" ON (("categories"."a" = "items"."d") AND ("categories"."b" = "items"."c"))'
2106
+ @d.join(:categories, :a=>:d){|j,lj,js| :b.qualify(j) > :c.qualify(lj)}.sql.should == 'SELECT * FROM "items" INNER JOIN "categories" ON (("categories"."a" = "items"."d") AND ("categories"."b" > "items"."c"))'
2300
2107
  end
2301
2108
 
2302
2109
  specify "should prefer explicit aliases over implicit" do
2303
- @d.from(:items___i).join(:categories___c, {:category_id => :id}, {:table_alias=>:c2, :implicit_qualifier=>:i2}).sql.should ==
2304
- 'SELECT * FROM "items" AS "i" INNER JOIN "categories" AS "c2" ON ("c2"."category_id" = "i2"."id")'
2110
+ @d.from(:items___i).join(:categories___c, {:category_id => :id}, {:table_alias=>:c2, :implicit_qualifier=>:i2}).sql.should == 'SELECT * FROM "items" AS "i" INNER JOIN "categories" AS "c2" ON ("c2"."category_id" = "i2"."id")'
2305
2111
  @d.from(:items.as(:i)).join(:categories.as(:c), {:category_id => :id}, {:table_alias=>:c2, :implicit_qualifier=>:i2}).sql.should ==
2306
2112
  'SELECT * FROM "items" AS "i" INNER JOIN "categories" AS "c2" ON ("c2"."category_id" = "i2"."id")'
2307
2113
  end
@@ -2320,81 +2126,48 @@ describe "Dataset#join_table" do
2320
2126
  end
2321
2127
 
2322
2128
  describe "Dataset#[]=" do
2323
- before do
2324
- c = Class.new(Sequel::Dataset) do
2325
- def last_sql
2326
- @@last_sql
2327
- end
2328
-
2329
- def update(*args)
2330
- @@last_sql = update_sql(*args)
2331
- end
2332
- end
2333
-
2334
- @d = c.new(nil).from(:items)
2335
- end
2336
-
2337
2129
  specify "should perform an update on the specified filter" do
2338
- @d[:a => 1] = {:x => 3}
2339
- @d.last_sql.should == 'UPDATE items SET x = 3 WHERE (a = 1)'
2130
+ db = Sequel.mock
2131
+ ds = db[:items]
2132
+ ds[:a => 1] = {:x => 3}
2133
+ db.sqls.should == ['UPDATE items SET x = 3 WHERE (a = 1)']
2340
2134
  end
2341
2135
  end
2342
2136
 
2343
2137
  describe "Dataset#set" do
2344
- before do
2345
- c = Class.new(Sequel::Dataset) do
2346
- def last_sql
2347
- @@last_sql
2348
- end
2349
-
2350
- def update(*args, &block)
2351
- @@last_sql = update_sql(*args, &block)
2352
- end
2353
- end
2354
-
2355
- @d = c.new(nil).from(:items)
2356
- end
2357
-
2358
2138
  specify "should act as alias to #update" do
2359
- @d.set({:x => 3})
2360
- @d.last_sql.should == 'UPDATE items SET x = 3'
2139
+ db = Sequel.mock
2140
+ ds = db[:items]
2141
+ ds.set({:x => 3})
2142
+ db.sqls.should == ['UPDATE items SET x = 3']
2361
2143
  end
2362
2144
  end
2363
2145
 
2364
-
2365
2146
  describe "Dataset#insert_multiple" do
2366
2147
  before do
2367
- c = Class.new(Sequel::Dataset) do
2368
- attr_reader :inserts
2369
- def insert(arg)
2370
- @inserts ||= []
2371
- @inserts << arg
2372
- end
2373
- end
2374
-
2375
- @d = c.new(nil)
2148
+ @db = Sequel.mock
2149
+ @ds = @db[:items]
2376
2150
  end
2377
2151
 
2378
2152
  specify "should insert all items in the supplied array" do
2379
- @d.insert_multiple [:aa, 5, 3, {1 => 2}]
2380
- @d.inserts.should == [:aa, 5, 3, {1 => 2}]
2153
+ @ds.insert_multiple(['aa', 5, 3, {:a => 2}])
2154
+ @db.sqls.should == ["INSERT INTO items VALUES ('aa')",
2155
+ "INSERT INTO items VALUES (5)",
2156
+ "INSERT INTO items VALUES (3)",
2157
+ "INSERT INTO items (a) VALUES (2)"]
2381
2158
  end
2382
2159
 
2383
2160
  specify "should pass array items through the supplied block if given" do
2384
- a = ["inevitable", "hello", "the ticking clock"]
2385
- @d.insert_multiple(a) {|i| i.gsub('l', 'r')}
2386
- @d.inserts.should == ["inevitabre", "herro", "the ticking crock"]
2161
+ @ds.insert_multiple(["inevitable", "hello", "the ticking clock"]){|i| i.gsub('l', 'r')}
2162
+ @db.sqls.should == ["INSERT INTO items VALUES ('inevitabre')",
2163
+ "INSERT INTO items VALUES ('herro')",
2164
+ "INSERT INTO items VALUES ('the ticking crock')"]
2387
2165
  end
2388
2166
  end
2389
2167
 
2390
2168
  describe "Dataset aggregate methods" do
2391
2169
  before do
2392
- c = Class.new(Sequel::Dataset) do
2393
- def fetch_rows(sql)
2394
- yield({1 => sql})
2395
- end
2396
- end
2397
- @d = c.new(nil).from(:test)
2170
+ @d = Sequel.mock(:fetch=>proc{|s| {1=>s}})[:test]
2398
2171
  end
2399
2172
 
2400
2173
  specify "should include min" do
@@ -2428,116 +2201,88 @@ end
2428
2201
 
2429
2202
  describe "Dataset#range" do
2430
2203
  before do
2431
- c = Class.new(Sequel::Dataset) do
2432
- class_variable_set(:@@sql, nil)
2433
-
2434
- def last_sql; self.class.send(:class_variable_get, :@@sql); end
2435
-
2436
- def fetch_rows(sql)
2437
- self.class.send(:class_variable_set, :@@sql, sql)
2438
- yield(:v1 => 1, :v2 => 10)
2439
- end
2440
- end
2441
- @d = c.new(nil).from(:test)
2204
+ @db = Sequel.mock(:fetch=>{:v1 => 1, :v2 => 10})
2205
+ @ds = @db[:test]
2442
2206
  end
2443
2207
 
2444
2208
  specify "should generate a correct SQL statement" do
2445
- @d.range(:stamp)
2446
- @d.last_sql.should == "SELECT min(stamp) AS v1, max(stamp) AS v2 FROM test LIMIT 1"
2209
+ @ds.range(:stamp)
2210
+ @db.sqls.should == ["SELECT min(stamp) AS v1, max(stamp) AS v2 FROM test LIMIT 1"]
2447
2211
 
2448
- @d.filter(:price.sql_number > 100).range(:stamp)
2449
- @d.last_sql.should == "SELECT min(stamp) AS v1, max(stamp) AS v2 FROM test WHERE (price > 100) LIMIT 1"
2212
+ @ds.filter(:price.sql_number > 100).range(:stamp)
2213
+ @db.sqls.should == ["SELECT min(stamp) AS v1, max(stamp) AS v2 FROM test WHERE (price > 100) LIMIT 1"]
2450
2214
  end
2451
2215
 
2452
2216
  specify "should return a range object" do
2453
- @d.range(:tryme).should == (1..10)
2217
+ @ds.range(:tryme).should == (1..10)
2454
2218
  end
2455
2219
 
2456
2220
  specify "should use a subselect for the same conditions as count" do
2457
- @d.order(:stamp).limit(5).range(:stamp).should == (1..10)
2458
- @d.last_sql.should == 'SELECT min(stamp) AS v1, max(stamp) AS v2 FROM (SELECT * FROM test ORDER BY stamp LIMIT 5) AS t1 LIMIT 1'
2221
+ @ds.order(:stamp).limit(5).range(:stamp).should == (1..10)
2222
+ @db.sqls.should == ['SELECT min(stamp) AS v1, max(stamp) AS v2 FROM (SELECT * FROM test ORDER BY stamp LIMIT 5) AS t1 LIMIT 1']
2459
2223
  end
2460
2224
  end
2461
2225
 
2462
2226
  describe "Dataset#interval" do
2463
2227
  before do
2464
- c = Class.new(Sequel::Dataset) do
2465
- class_variable_set(:@@sql, nil)
2466
-
2467
- def last_sql; self.class.send(:class_variable_get, :@@sql); end
2468
-
2469
- def fetch_rows(sql)
2470
- self.class.send(:class_variable_set, :@@sql, sql)
2471
- yield(:v => 1234)
2472
- end
2473
- end
2474
- @d = c.new(nil).from(:test)
2228
+ @db = Sequel.mock(:fetch=>{:v => 1234})
2229
+ @ds = @db[:test]
2475
2230
  end
2476
2231
 
2477
- specify "should generate a correct SQL statement" do
2478
- @d.interval(:stamp)
2479
- @d.last_sql.should == "SELECT (max(stamp) - min(stamp)) FROM test LIMIT 1"
2232
+ specify "should generate the correct SQL statement" do
2233
+ @ds.interval(:stamp)
2234
+ @db.sqls.should == ["SELECT (max(stamp) - min(stamp)) FROM test LIMIT 1"]
2480
2235
 
2481
- @d.filter(:price.sql_number > 100).interval(:stamp)
2482
- @d.last_sql.should == "SELECT (max(stamp) - min(stamp)) FROM test WHERE (price > 100) LIMIT 1"
2483
- end
2484
-
2485
- specify "should return an integer" do
2486
- @d.interval(:tryme).should == 1234
2236
+ @ds.filter(:price.sql_number > 100).interval(:stamp)
2237
+ @db.sqls.should == ["SELECT (max(stamp) - min(stamp)) FROM test WHERE (price > 100) LIMIT 1"]
2487
2238
  end
2488
2239
 
2489
2240
  specify "should use a subselect for the same conditions as count" do
2490
- @d.order(:stamp).limit(5).interval(:stamp).should == 1234
2491
- @d.last_sql.should == 'SELECT (max(stamp) - min(stamp)) FROM (SELECT * FROM test ORDER BY stamp LIMIT 5) AS t1 LIMIT 1'
2241
+ @ds.order(:stamp).limit(5).interval(:stamp).should == 1234
2242
+ @db.sqls.should == ['SELECT (max(stamp) - min(stamp)) FROM (SELECT * FROM test ORDER BY stamp LIMIT 5) AS t1 LIMIT 1']
2492
2243
  end
2493
2244
  end
2494
2245
 
2495
2246
  describe "Dataset #first and #last" do
2496
2247
  before do
2497
- @c = Class.new(Sequel::Dataset) do
2498
- def each(&block)
2499
- s = select_sql
2500
- x = [:a,1,:b,2,s]
2501
- i = /LIMIT (\d+)/.match(s)[1].to_i.times{yield x}
2502
- end
2503
- end
2504
- @d = @c.new(nil).from(:test)
2248
+ @db = Sequel.mock(:fetch=>proc{|s| {:s=>s}})
2249
+ @d = @db[:test]
2505
2250
  end
2506
2251
 
2507
2252
  specify "should return a single record if no argument is given" do
2508
- @d.order(:a).first.should == [:a,1,:b,2, 'SELECT * FROM test ORDER BY a LIMIT 1']
2509
- @d.order(:a).last.should == [:a,1,:b,2, 'SELECT * FROM test ORDER BY a DESC LIMIT 1']
2253
+ @d.order(:a).first.should == {:s=>'SELECT * FROM test ORDER BY a LIMIT 1'}
2254
+ @d.order(:a).last.should == {:s=>'SELECT * FROM test ORDER BY a DESC LIMIT 1'}
2510
2255
  end
2511
2256
 
2512
2257
  specify "should return the first/last matching record if argument is not an Integer" do
2513
- @d.order(:a).first(:z => 26).should == [:a,1,:b,2, 'SELECT * FROM test WHERE (z = 26) ORDER BY a LIMIT 1']
2514
- @d.order(:a).first('z = ?', 15).should == [:a,1,:b,2, 'SELECT * FROM test WHERE (z = 15) ORDER BY a LIMIT 1']
2515
- @d.order(:a).last(:z => 26).should == [:a,1,:b,2, 'SELECT * FROM test WHERE (z = 26) ORDER BY a DESC LIMIT 1']
2516
- @d.order(:a).last('z = ?', 15).should == [:a,1,:b,2, 'SELECT * FROM test WHERE (z = 15) ORDER BY a DESC LIMIT 1']
2258
+ @d.order(:a).first(:z => 26).should == {:s=>'SELECT * FROM test WHERE (z = 26) ORDER BY a LIMIT 1'}
2259
+ @d.order(:a).first('z = ?', 15).should == {:s=>'SELECT * FROM test WHERE (z = 15) ORDER BY a LIMIT 1'}
2260
+ @d.order(:a).last(:z => 26).should == {:s=>'SELECT * FROM test WHERE (z = 26) ORDER BY a DESC LIMIT 1'}
2261
+ @d.order(:a).last('z = ?', 15).should == {:s=>'SELECT * FROM test WHERE (z = 15) ORDER BY a DESC LIMIT 1'}
2517
2262
  end
2518
2263
 
2519
2264
  specify "should set the limit and return an array of records if the given number is > 1" do
2520
2265
  i = rand(10) + 10
2521
- r = @d.order(:a).first(i).should == [[:a,1,:b,2, "SELECT * FROM test ORDER BY a LIMIT #{i}"]] * i
2266
+ r = @d.order(:a).first(i).should == [{:s=>"SELECT * FROM test ORDER BY a LIMIT #{i}"}]
2522
2267
  i = rand(10) + 10
2523
- r = @d.order(:a).last(i).should == [[:a,1,:b,2, "SELECT * FROM test ORDER BY a DESC LIMIT #{i}"]] * i
2268
+ r = @d.order(:a).last(i).should == [{:s=>"SELECT * FROM test ORDER BY a DESC LIMIT #{i}"}]
2524
2269
  end
2525
2270
 
2526
2271
  specify "should return the first matching record if a block is given without an argument" do
2527
- @d.first{:z.sql_number > 26}.should == [:a,1,:b,2, 'SELECT * FROM test WHERE (z > 26) LIMIT 1']
2528
- @d.order(:name).last{:z.sql_number > 26}.should == [:a,1,:b,2, 'SELECT * FROM test WHERE (z > 26) ORDER BY name DESC LIMIT 1']
2272
+ @d.first{:z.sql_number > 26}.should == {:s=>'SELECT * FROM test WHERE (z > 26) LIMIT 1'}
2273
+ @d.order(:name).last{:z.sql_number > 26}.should == {:s=>'SELECT * FROM test WHERE (z > 26) ORDER BY name DESC LIMIT 1'}
2529
2274
  end
2530
2275
 
2531
2276
  specify "should combine block and standard argument filters if argument is not an Integer" do
2532
- @d.first(:y=>25){:z.sql_number > 26}.should == [:a,1,:b,2, 'SELECT * FROM test WHERE ((z > 26) AND (y = 25)) LIMIT 1']
2533
- @d.order(:name).last('y = ?', 16){:z.sql_number > 26}.should == [:a,1,:b,2, 'SELECT * FROM test WHERE ((z > 26) AND (y = 16)) ORDER BY name DESC LIMIT 1']
2277
+ @d.first(:y=>25){:z.sql_number > 26}.should == {:s=>'SELECT * FROM test WHERE ((z > 26) AND (y = 25)) LIMIT 1'}
2278
+ @d.order(:name).last('y = ?', 16){:z.sql_number > 26}.should == {:s=>'SELECT * FROM test WHERE ((z > 26) AND (y = 16)) ORDER BY name DESC LIMIT 1'}
2534
2279
  end
2535
2280
 
2536
2281
  specify "should filter and return an array of records if an Integer argument is provided and a block is given" do
2537
2282
  i = rand(10) + 10
2538
- r = @d.order(:a).first(i){:z.sql_number > 26}.should == [[:a,1,:b,2, "SELECT * FROM test WHERE (z > 26) ORDER BY a LIMIT #{i}"]] * i
2283
+ r = @d.order(:a).first(i){:z.sql_number > 26}.should == [{:s=>"SELECT * FROM test WHERE (z > 26) ORDER BY a LIMIT #{i}"}]
2539
2284
  i = rand(10) + 10
2540
- r = @d.order(:a).last(i){:z.sql_number > 26}.should == [[:a,1,:b,2, "SELECT * FROM test WHERE (z > 26) ORDER BY a DESC LIMIT #{i}"]] * i
2285
+ r = @d.order(:a).last(i){:z.sql_number > 26}.should == [{:s=>"SELECT * FROM test WHERE (z > 26) ORDER BY a DESC LIMIT #{i}"}]
2541
2286
  end
2542
2287
 
2543
2288
  specify "#last should raise if no order is given" do
@@ -2548,10 +2293,10 @@ describe "Dataset #first and #last" do
2548
2293
  end
2549
2294
 
2550
2295
  specify "#last should invert the order" do
2551
- @d.order(:a).last.pop.should == 'SELECT * FROM test ORDER BY a DESC LIMIT 1'
2552
- @d.order(:b.desc).last.pop.should == 'SELECT * FROM test ORDER BY b ASC LIMIT 1'
2553
- @d.order(:c, :d).last.pop.should == 'SELECT * FROM test ORDER BY c DESC, d DESC LIMIT 1'
2554
- @d.order(:e.desc, :f).last.pop.should == 'SELECT * FROM test ORDER BY e ASC, f DESC LIMIT 1'
2296
+ @d.order(:a).last.should == {:s=>'SELECT * FROM test ORDER BY a DESC LIMIT 1'}
2297
+ @d.order(:b.desc).last.should == {:s=>'SELECT * FROM test ORDER BY b ASC LIMIT 1'}
2298
+ @d.order(:c, :d).last.should == {:s=>'SELECT * FROM test ORDER BY c DESC, d DESC LIMIT 1'}
2299
+ @d.order(:e.desc, :f).last.should == {:s=>'SELECT * FROM test ORDER BY e ASC, f DESC LIMIT 1'}
2555
2300
  end
2556
2301
  end
2557
2302
 
@@ -2562,55 +2307,37 @@ describe "Dataset compound operations" do
2562
2307
  end
2563
2308
 
2564
2309
  specify "should support UNION and UNION ALL" do
2565
- @a.union(@b).sql.should == \
2566
- "SELECT * FROM (SELECT * FROM a WHERE (z = 1) UNION SELECT * FROM b WHERE (z = 2)) AS t1"
2567
- @b.union(@a, true).sql.should == \
2568
- "SELECT * FROM (SELECT * FROM b WHERE (z = 2) UNION ALL SELECT * FROM a WHERE (z = 1)) AS t1"
2569
- @b.union(@a, :all=>true).sql.should == \
2570
- "SELECT * FROM (SELECT * FROM b WHERE (z = 2) UNION ALL SELECT * FROM a WHERE (z = 1)) AS t1"
2310
+ @a.union(@b).sql.should == "SELECT * FROM (SELECT * FROM a WHERE (z = 1) UNION SELECT * FROM b WHERE (z = 2)) AS t1"
2311
+ @b.union(@a, true).sql.should == "SELECT * FROM (SELECT * FROM b WHERE (z = 2) UNION ALL SELECT * FROM a WHERE (z = 1)) AS t1"
2312
+ @b.union(@a, :all=>true).sql.should == "SELECT * FROM (SELECT * FROM b WHERE (z = 2) UNION ALL SELECT * FROM a WHERE (z = 1)) AS t1"
2571
2313
  end
2572
2314
 
2573
2315
  specify "should support INTERSECT and INTERSECT ALL" do
2574
- @a.intersect(@b).sql.should == \
2575
- "SELECT * FROM (SELECT * FROM a WHERE (z = 1) INTERSECT SELECT * FROM b WHERE (z = 2)) AS t1"
2576
- @b.intersect(@a, true).sql.should == \
2577
- "SELECT * FROM (SELECT * FROM b WHERE (z = 2) INTERSECT ALL SELECT * FROM a WHERE (z = 1)) AS t1"
2578
- @b.intersect(@a, :all=>true).sql.should == \
2579
- "SELECT * FROM (SELECT * FROM b WHERE (z = 2) INTERSECT ALL SELECT * FROM a WHERE (z = 1)) AS t1"
2316
+ @a.intersect(@b).sql.should == "SELECT * FROM (SELECT * FROM a WHERE (z = 1) INTERSECT SELECT * FROM b WHERE (z = 2)) AS t1"
2317
+ @b.intersect(@a, true).sql.should == "SELECT * FROM (SELECT * FROM b WHERE (z = 2) INTERSECT ALL SELECT * FROM a WHERE (z = 1)) AS t1"
2318
+ @b.intersect(@a, :all=>true).sql.should == "SELECT * FROM (SELECT * FROM b WHERE (z = 2) INTERSECT ALL SELECT * FROM a WHERE (z = 1)) AS t1"
2580
2319
  end
2581
2320
 
2582
2321
  specify "should support EXCEPT and EXCEPT ALL" do
2583
- @a.except(@b).sql.should == \
2584
- "SELECT * FROM (SELECT * FROM a WHERE (z = 1) EXCEPT SELECT * FROM b WHERE (z = 2)) AS t1"
2585
- @b.except(@a, true).sql.should == \
2586
- "SELECT * FROM (SELECT * FROM b WHERE (z = 2) EXCEPT ALL SELECT * FROM a WHERE (z = 1)) AS t1"
2587
- @b.except(@a, :all=>true).sql.should == \
2588
- "SELECT * FROM (SELECT * FROM b WHERE (z = 2) EXCEPT ALL SELECT * FROM a WHERE (z = 1)) AS t1"
2322
+ @a.except(@b).sql.should == "SELECT * FROM (SELECT * FROM a WHERE (z = 1) EXCEPT SELECT * FROM b WHERE (z = 2)) AS t1"
2323
+ @b.except(@a, true).sql.should == "SELECT * FROM (SELECT * FROM b WHERE (z = 2) EXCEPT ALL SELECT * FROM a WHERE (z = 1)) AS t1"
2324
+ @b.except(@a, :all=>true).sql.should == "SELECT * FROM (SELECT * FROM b WHERE (z = 2) EXCEPT ALL SELECT * FROM a WHERE (z = 1)) AS t1"
2589
2325
  end
2590
2326
 
2591
2327
  specify "should support :alias option for specifying identifier" do
2592
- @a.union(@b, :alias=>:xx).sql.should == \
2593
- "SELECT * FROM (SELECT * FROM a WHERE (z = 1) UNION SELECT * FROM b WHERE (z = 2)) AS xx"
2594
- @a.intersect(@b, :alias=>:xx).sql.should == \
2595
- "SELECT * FROM (SELECT * FROM a WHERE (z = 1) INTERSECT SELECT * FROM b WHERE (z = 2)) AS xx"
2596
- @a.except(@b, :alias=>:xx).sql.should == \
2597
- "SELECT * FROM (SELECT * FROM a WHERE (z = 1) EXCEPT SELECT * FROM b WHERE (z = 2)) AS xx"
2328
+ @a.union(@b, :alias=>:xx).sql.should == "SELECT * FROM (SELECT * FROM a WHERE (z = 1) UNION SELECT * FROM b WHERE (z = 2)) AS xx"
2329
+ @a.intersect(@b, :alias=>:xx).sql.should == "SELECT * FROM (SELECT * FROM a WHERE (z = 1) INTERSECT SELECT * FROM b WHERE (z = 2)) AS xx"
2330
+ @a.except(@b, :alias=>:xx).sql.should == "SELECT * FROM (SELECT * FROM a WHERE (z = 1) EXCEPT SELECT * FROM b WHERE (z = 2)) AS xx"
2598
2331
  end
2599
2332
 
2600
2333
  specify "should support :from_self=>false option to not wrap the compound in a SELECT * FROM (...)" do
2601
- @b.union(@a, :from_self=>false).sql.should == \
2602
- "SELECT * FROM b WHERE (z = 2) UNION SELECT * FROM a WHERE (z = 1)"
2603
- @b.intersect(@a, :from_self=>false).sql.should == \
2604
- "SELECT * FROM b WHERE (z = 2) INTERSECT SELECT * FROM a WHERE (z = 1)"
2605
- @b.except(@a, :from_self=>false).sql.should == \
2606
- "SELECT * FROM b WHERE (z = 2) EXCEPT SELECT * FROM a WHERE (z = 1)"
2334
+ @b.union(@a, :from_self=>false).sql.should == "SELECT * FROM b WHERE (z = 2) UNION SELECT * FROM a WHERE (z = 1)"
2335
+ @b.intersect(@a, :from_self=>false).sql.should == "SELECT * FROM b WHERE (z = 2) INTERSECT SELECT * FROM a WHERE (z = 1)"
2336
+ @b.except(@a, :from_self=>false).sql.should == "SELECT * FROM b WHERE (z = 2) EXCEPT SELECT * FROM a WHERE (z = 1)"
2607
2337
 
2608
- @b.union(@a, :from_self=>false, :all=>true).sql.should == \
2609
- "SELECT * FROM b WHERE (z = 2) UNION ALL SELECT * FROM a WHERE (z = 1)"
2610
- @b.intersect(@a, :from_self=>false, :all=>true).sql.should == \
2611
- "SELECT * FROM b WHERE (z = 2) INTERSECT ALL SELECT * FROM a WHERE (z = 1)"
2612
- @b.except(@a, :from_self=>false, :all=>true).sql.should == \
2613
- "SELECT * FROM b WHERE (z = 2) EXCEPT ALL SELECT * FROM a WHERE (z = 1)"
2338
+ @b.union(@a, :from_self=>false, :all=>true).sql.should == "SELECT * FROM b WHERE (z = 2) UNION ALL SELECT * FROM a WHERE (z = 1)"
2339
+ @b.intersect(@a, :from_self=>false, :all=>true).sql.should == "SELECT * FROM b WHERE (z = 2) INTERSECT ALL SELECT * FROM a WHERE (z = 1)"
2340
+ @b.except(@a, :from_self=>false, :all=>true).sql.should == "SELECT * FROM b WHERE (z = 2) EXCEPT ALL SELECT * FROM a WHERE (z = 1)"
2614
2341
  end
2615
2342
 
2616
2343
  specify "should raise an InvalidOperation if INTERSECT or EXCEPT is used and they are not supported" do
@@ -2630,141 +2357,105 @@ describe "Dataset compound operations" do
2630
2357
  end
2631
2358
 
2632
2359
  specify "should handle chained compound operations" do
2633
- @a.union(@b).union(@a, true).sql.should == \
2634
- "SELECT * FROM (SELECT * FROM (SELECT * FROM a WHERE (z = 1) UNION SELECT * FROM b WHERE (z = 2)) AS t1 UNION ALL SELECT * FROM a WHERE (z = 1)) AS t1"
2635
- @a.intersect(@b, true).intersect(@a).sql.should == \
2636
- "SELECT * FROM (SELECT * FROM (SELECT * FROM a WHERE (z = 1) INTERSECT ALL SELECT * FROM b WHERE (z = 2)) AS t1 INTERSECT SELECT * FROM a WHERE (z = 1)) AS t1"
2637
- @a.except(@b).except(@a, true).sql.should == \
2638
- "SELECT * FROM (SELECT * FROM (SELECT * FROM a WHERE (z = 1) EXCEPT SELECT * FROM b WHERE (z = 2)) AS t1 EXCEPT ALL SELECT * FROM a WHERE (z = 1)) AS t1"
2360
+ @a.union(@b).union(@a, true).sql.should == "SELECT * FROM (SELECT * FROM (SELECT * FROM a WHERE (z = 1) UNION SELECT * FROM b WHERE (z = 2)) AS t1 UNION ALL SELECT * FROM a WHERE (z = 1)) AS t1"
2361
+ @a.intersect(@b, true).intersect(@a).sql.should == "SELECT * FROM (SELECT * FROM (SELECT * FROM a WHERE (z = 1) INTERSECT ALL SELECT * FROM b WHERE (z = 2)) AS t1 INTERSECT SELECT * FROM a WHERE (z = 1)) AS t1"
2362
+ @a.except(@b).except(@a, true).sql.should == "SELECT * FROM (SELECT * FROM (SELECT * FROM a WHERE (z = 1) EXCEPT SELECT * FROM b WHERE (z = 2)) AS t1 EXCEPT ALL SELECT * FROM a WHERE (z = 1)) AS t1"
2639
2363
  end
2640
2364
 
2641
2365
  specify "should use a subselect when using a compound operation with a dataset that already has a compound operation" do
2642
- @a.union(@b.union(@a, true)).sql.should == \
2643
- "SELECT * FROM (SELECT * FROM a WHERE (z = 1) UNION SELECT * FROM (SELECT * FROM b WHERE (z = 2) UNION ALL SELECT * FROM a WHERE (z = 1)) AS t1) AS t1"
2644
- @a.intersect(@b.intersect(@a), true).sql.should == \
2645
- "SELECT * FROM (SELECT * FROM a WHERE (z = 1) INTERSECT ALL SELECT * FROM (SELECT * FROM b WHERE (z = 2) INTERSECT SELECT * FROM a WHERE (z = 1)) AS t1) AS t1"
2646
- @a.except(@b.except(@a, true)).sql.should == \
2647
- "SELECT * FROM (SELECT * FROM a WHERE (z = 1) EXCEPT SELECT * FROM (SELECT * FROM b WHERE (z = 2) EXCEPT ALL SELECT * FROM a WHERE (z = 1)) AS t1) AS t1"
2366
+ @a.union(@b.union(@a, true)).sql.should == "SELECT * FROM (SELECT * FROM a WHERE (z = 1) UNION SELECT * FROM (SELECT * FROM b WHERE (z = 2) UNION ALL SELECT * FROM a WHERE (z = 1)) AS t1) AS t1"
2367
+ @a.intersect(@b.intersect(@a), true).sql.should == "SELECT * FROM (SELECT * FROM a WHERE (z = 1) INTERSECT ALL SELECT * FROM (SELECT * FROM b WHERE (z = 2) INTERSECT SELECT * FROM a WHERE (z = 1)) AS t1) AS t1"
2368
+ @a.except(@b.except(@a, true)).sql.should == "SELECT * FROM (SELECT * FROM a WHERE (z = 1) EXCEPT SELECT * FROM (SELECT * FROM b WHERE (z = 2) EXCEPT ALL SELECT * FROM a WHERE (z = 1)) AS t1) AS t1"
2648
2369
  end
2649
2370
 
2650
2371
  specify "should order and limit properly when using UNION, INTERSECT, or EXCEPT" do
2651
2372
  @dataset = Sequel::Dataset.new(nil).from(:test)
2652
- @dataset.union(@dataset).limit(2).sql.should ==
2653
- "SELECT * FROM (SELECT * FROM test UNION SELECT * FROM test) AS t1 LIMIT 2"
2654
- @dataset.limit(2).intersect(@dataset).sql.should ==
2655
- "SELECT * FROM (SELECT * FROM (SELECT * FROM test LIMIT 2) AS t1 INTERSECT SELECT * FROM test) AS t1"
2656
- @dataset.except(@dataset.limit(2)).sql.should ==
2657
- "SELECT * FROM (SELECT * FROM test EXCEPT SELECT * FROM (SELECT * FROM test LIMIT 2) AS t1) AS t1"
2658
-
2659
- @dataset.union(@dataset).order(:num).sql.should ==
2660
- "SELECT * FROM (SELECT * FROM test UNION SELECT * FROM test) AS t1 ORDER BY num"
2661
- @dataset.order(:num).intersect(@dataset).sql.should ==
2662
- "SELECT * FROM (SELECT * FROM (SELECT * FROM test ORDER BY num) AS t1 INTERSECT SELECT * FROM test) AS t1"
2663
- @dataset.except(@dataset.order(:num)).sql.should ==
2664
- "SELECT * FROM (SELECT * FROM test EXCEPT SELECT * FROM (SELECT * FROM test ORDER BY num) AS t1) AS t1"
2373
+ @dataset.union(@dataset).limit(2).sql.should == "SELECT * FROM (SELECT * FROM test UNION SELECT * FROM test) AS t1 LIMIT 2"
2374
+ @dataset.limit(2).intersect(@dataset).sql.should == "SELECT * FROM (SELECT * FROM (SELECT * FROM test LIMIT 2) AS t1 INTERSECT SELECT * FROM test) AS t1"
2375
+ @dataset.except(@dataset.limit(2)).sql.should == "SELECT * FROM (SELECT * FROM test EXCEPT SELECT * FROM (SELECT * FROM test LIMIT 2) AS t1) AS t1"
2376
+
2377
+ @dataset.union(@dataset).order(:num).sql.should == "SELECT * FROM (SELECT * FROM test UNION SELECT * FROM test) AS t1 ORDER BY num"
2378
+ @dataset.order(:num).intersect(@dataset).sql.should == "SELECT * FROM (SELECT * FROM (SELECT * FROM test ORDER BY num) AS t1 INTERSECT SELECT * FROM test) AS t1"
2379
+ @dataset.except(@dataset.order(:num)).sql.should == "SELECT * FROM (SELECT * FROM test EXCEPT SELECT * FROM (SELECT * FROM test ORDER BY num) AS t1) AS t1"
2665
2380
 
2666
2381
  @dataset.limit(2).order(:a).union(@dataset.limit(3).order(:b)).order(:c).limit(4).sql.should ==
2667
2382
  "SELECT * FROM (SELECT * FROM (SELECT * FROM test ORDER BY a LIMIT 2) AS t1 UNION SELECT * FROM (SELECT * FROM test ORDER BY b LIMIT 3) AS t1) AS t1 ORDER BY c LIMIT 4"
2668
2383
  end
2669
2384
 
2385
+ specify "should hoist WITH clauses in given dataset if dataset doesn't support WITH in subselect" do
2386
+ ds = Sequel::Dataset.new(nil)
2387
+ ds.meta_def(:supports_cte?){true}
2388
+ ds.meta_def(:supports_cte_in_subselect?){false}
2389
+ ds.from(:a).union(ds.from(:c).with(:c, ds.from(:d)), :from_self=>false).sql.should == 'WITH c AS (SELECT * FROM d) SELECT * FROM a UNION SELECT * FROM c'
2390
+ ds.from(:a).except(ds.from(:c).with(:c, ds.from(:d))).sql.should == 'WITH c AS (SELECT * FROM d) SELECT * FROM (SELECT * FROM a EXCEPT SELECT * FROM c) AS t1'
2391
+ ds.from(:a).with(:a, ds.from(:b)).intersect(ds.from(:c).with(:c, ds.from(:d)), :from_self=>false).sql.should == 'WITH a AS (SELECT * FROM b), c AS (SELECT * FROM d) SELECT * FROM a INTERSECT SELECT * FROM c'
2392
+ end
2670
2393
  end
2671
2394
 
2672
2395
  describe "Dataset#[]" do
2673
2396
  before do
2674
- @c = Class.new(Sequel::Dataset) do
2675
- class_variable_set(:@@last_dataset, nil)
2676
-
2677
- def self.last_dataset
2678
- class_variable_get(:@@last_dataset)
2679
- end
2680
-
2681
- def single_record
2682
- self.class.send(:class_variable_set, :@@last_dataset, opts ? clone(opts) : self)
2683
- {1 => 2, 3 => 4}
2684
- end
2685
- end
2686
- @d = @c.new(nil).from(:test)
2397
+ @db = Sequel.mock(:fetch=>{1 => 2, 3 => 4})
2398
+ @d = @db[:items]
2687
2399
  end
2688
2400
 
2689
2401
  specify "should return a single record filtered according to the given conditions" do
2690
2402
  @d[:name => 'didi'].should == {1 => 2, 3 => 4}
2691
- @c.last_dataset.literal(@c.last_dataset.opts[:where]).should == "(name = 'didi')"
2403
+ @db.sqls.should == ["SELECT * FROM items WHERE (name = 'didi') LIMIT 1"]
2692
2404
 
2693
2405
  @d[:id => 5..45].should == {1 => 2, 3 => 4}
2694
- @c.last_dataset.literal(@c.last_dataset.opts[:where]).should == "((id >= 5) AND (id <= 45))"
2406
+ @db.sqls.should == ["SELECT * FROM items WHERE ((id >= 5) AND (id <= 45)) LIMIT 1"]
2695
2407
  end
2696
2408
  end
2697
2409
 
2698
2410
  describe "Dataset#single_record" do
2699
2411
  before do
2700
- @c = Class.new(Sequel::Dataset) do
2701
- def fetch_rows(sql)
2702
- yield sql
2703
- end
2704
- end
2705
- @cc = Class.new(@c) do
2706
- def fetch_rows(sql); end
2707
- end
2708
-
2709
- @d = @c.new(nil).from(:test)
2710
- @e = @cc.new(nil).from(:test)
2412
+ @db = Sequel.mock
2711
2413
  end
2712
2414
 
2713
2415
  specify "should call each with a limit of 1 and return the record" do
2714
- @d.single_record.should == 'SELECT * FROM test LIMIT 1'
2416
+ @db.fetch = {:a=>1}
2417
+ @db[:test].single_record.should == {:a=>1}
2418
+ @db.sqls.should == ['SELECT * FROM test LIMIT 1']
2715
2419
  end
2716
2420
 
2717
2421
  specify "should return nil if no record is present" do
2718
- @e.single_record.should be_nil
2422
+ @db[:test].single_record.should be_nil
2423
+ @db.sqls.should == ['SELECT * FROM test LIMIT 1']
2719
2424
  end
2720
2425
  end
2721
2426
 
2722
2427
  describe "Dataset#single_value" do
2723
2428
  before do
2724
- @c = Class.new(Sequel::Dataset) do
2725
- def fetch_rows(sql)
2726
- yield({1 => sql})
2727
- end
2728
- end
2729
- @cc = Class.new(@c) do
2730
- def fetch_rows(sql); end
2731
- end
2732
-
2733
- @d = @c.new(nil).from(:test)
2734
- @e = @cc.new(nil).from(:test)
2429
+ @db = Sequel.mock
2735
2430
  end
2736
2431
 
2737
2432
  specify "should call each and return the first value of the first record" do
2738
- @d.single_value.should == 'SELECT * FROM test LIMIT 1'
2433
+ @db.fetch = {:a=>1}
2434
+ @db[:test].single_value.should == 1
2435
+ @db.sqls.should == ['SELECT * FROM test LIMIT 1']
2739
2436
  end
2740
2437
 
2741
2438
  specify "should return nil if no records" do
2742
- @e.single_value.should be_nil
2439
+ @db[:test].single_value.should be_nil
2440
+ @db.sqls.should == ['SELECT * FROM test LIMIT 1']
2743
2441
  end
2744
2442
 
2745
2443
  it "should work on a graphed_dataset" do
2746
- @d.should_receive(:columns).twice.and_return([:a])
2747
- @d.graph(@d, [:a], :table_alias=>:test2).single_value.should == 'SELECT test.a, test2.a AS test2_a FROM test LEFT OUTER JOIN test AS test2 USING (a) LIMIT 1'
2444
+ @db.fetch = {:a=>1}
2445
+ ds = @db[:test].columns(:a)
2446
+ ds.graph(ds, [:a], :table_alias=>:test2).single_value.should == 1
2447
+ @db.sqls.should == ['SELECT test.a, test2.a AS test2_a FROM test LEFT OUTER JOIN test AS test2 USING (a) LIMIT 1']
2748
2448
  end
2749
2449
  end
2750
2450
 
2751
2451
  describe "Dataset#get" do
2752
2452
  before do
2753
- @c = Class.new(Sequel::Dataset) do
2754
- attr_reader :last_sql
2755
-
2756
- def fetch_rows(sql)
2757
- @last_sql = sql
2758
- yield(:name => sql)
2759
- end
2760
- end
2761
-
2762
- @d = @c.new(nil).from(:test)
2453
+ @d = Sequel.mock(:fetch=>proc{|s| {:name=>s}})[:test]
2763
2454
  end
2764
2455
 
2765
2456
  specify "should select the specified column and fetch its value" do
2766
2457
  @d.get(:name).should == "SELECT name FROM test LIMIT 1"
2767
- @d.get(:abc).should == "SELECT abc FROM test LIMIT 1" # the first available value is returned always
2458
+ @d.get(:abc).should == "SELECT abc FROM test LIMIT 1"
2768
2459
  end
2769
2460
 
2770
2461
  specify "should work with filters" do
@@ -2787,239 +2478,206 @@ end
2787
2478
 
2788
2479
  describe "Dataset#set_row_proc" do
2789
2480
  before do
2790
- @c = Class.new(Sequel::Dataset) do
2791
- def fetch_rows(sql, &block)
2792
- # yield a hash with kind as the 1 bit of a number
2793
- (1..10).each {|i| block.call({:kind => i[0]})}
2794
- end
2795
- end
2796
- @dataset = @c.new(nil).from(:items)
2481
+ @db = Sequel.mock(:fetch=>[{:a=>1}, {:a=>2}])
2482
+ @dataset = @db[:items]
2483
+ @dataset.row_proc = proc{|h| h[:der] = h[:a] + 2; h}
2797
2484
  end
2798
2485
 
2799
2486
  specify "should cause dataset to pass all rows through the filter" do
2800
- @dataset.row_proc = proc{|h| h[:der] = h[:kind] + 2; h}
2801
-
2802
2487
  rows = @dataset.all
2803
- rows.size.should == 10
2804
-
2805
- rows.each {|r| r[:der].should == (r[:kind] + 2)}
2488
+ rows.map{|h| h[:der]}.should == [3, 4]
2489
+ @db.sqls.should == ['SELECT * FROM items']
2806
2490
  end
2807
2491
 
2808
2492
  specify "should be copied over when dataset is cloned" do
2809
- @dataset.row_proc = proc{|h| h[:der] = h[:kind] + 2; h}
2810
-
2811
- @dataset.filter(:a => 1).first.should == {:kind => 1, :der => 3}
2493
+ @dataset.filter(:a => 1).all.should == [{:a=>1, :der=>3}, {:a=>2, :der=>4}]
2812
2494
  end
2813
2495
  end
2814
2496
 
2815
2497
  describe "Dataset#<<" do
2816
2498
  before do
2817
- @d = Sequel::Dataset.new(nil)
2818
- @d.meta_def(:insert) do |*args|
2819
- 1234567890
2820
- end
2499
+ @db = Sequel.mock
2821
2500
  end
2822
-
2501
+
2823
2502
  specify "should call #insert" do
2824
- (@d << {:name => 1}).should == 1234567890
2503
+ @db[:items] << {:name => 1}
2504
+ @db.sqls.should == ['INSERT INTO items (name) VALUES (1)']
2505
+ end
2506
+
2507
+ specify "should be chainable" do
2508
+ @db[:items] << {:name => 1} << @db[:old_items].select(:name)
2509
+ @db.sqls.should == ['INSERT INTO items (name) VALUES (1)', 'INSERT INTO items SELECT name FROM old_items']
2825
2510
  end
2826
2511
  end
2827
2512
 
2828
2513
  describe "Dataset#columns" do
2829
2514
  before do
2830
- @dataset = DummyDataset.new(nil).from(:items)
2831
- @dataset.meta_def(:columns=) {|c| @columns = c}
2832
- i = 'a'
2833
- @dataset.meta_def(:each){@columns = select_sql + i; i = i.next}
2515
+ @dataset = Sequel.mock[:items]
2834
2516
  end
2835
2517
 
2836
2518
  specify "should return the value of @columns if @columns is not nil" do
2837
- @dataset.columns = [:a, :b, :c]
2838
- @dataset.columns.should == [:a, :b, :c]
2519
+ @dataset.columns(:a, :b, :c).columns.should == [:a, :b, :c]
2520
+ @dataset.db.sqls.should == []
2839
2521
  end
2840
2522
 
2841
2523
  specify "should attempt to get a single record and return @columns if @columns is nil" do
2842
- @dataset.columns = nil
2843
- @dataset.columns.should == 'SELECT * FROM items LIMIT 1a'
2844
- @dataset.opts[:from] = [:nana]
2845
- @dataset.columns.should == 'SELECT * FROM items LIMIT 1a'
2524
+ @dataset.db.columns = [:a]
2525
+ @dataset.columns.should == [:a]
2526
+ @dataset.db.sqls.should == ['SELECT * FROM items LIMIT 1']
2527
+ end
2528
+
2529
+ specify "should be cleared if you change the selected columns" do
2530
+ @dataset.db.columns = [[:a], [:b]]
2531
+ @dataset.columns.should == [:a]
2532
+ @dataset.db.sqls.should == ['SELECT * FROM items LIMIT 1']
2533
+ @dataset.columns.should == [:a]
2534
+ @dataset.db.sqls.should == []
2535
+ ds = @dataset.select{foo{}}
2536
+ ds.columns.should == [:b]
2537
+ @dataset.db.sqls.should == ['SELECT foo() FROM items LIMIT 1']
2538
+ end
2539
+
2540
+ specify "should be cleared if you change the FROM table" do
2541
+ @dataset.db.columns = [[:a], [:b]]
2542
+ @dataset.columns.should == [:a]
2543
+ @dataset.db.sqls.should == ['SELECT * FROM items LIMIT 1']
2544
+ ds = @dataset.from(:foo)
2545
+ ds.columns.should == [:b]
2546
+ @dataset.db.sqls.should == ['SELECT * FROM foo LIMIT 1']
2547
+ end
2548
+
2549
+ specify "should be cleared if you join a table to the dataset" do
2550
+ @dataset.db.columns = [[:a], [:a, :b]]
2551
+ @dataset.columns.should == [:a]
2552
+ @dataset.db.sqls.should == ['SELECT * FROM items LIMIT 1']
2553
+ ds = @dataset.cross_join(:foo)
2554
+ ds.columns.should == [:a, :b]
2555
+ @dataset.db.sqls.should == ['SELECT * FROM items CROSS JOIN foo LIMIT 1']
2556
+ end
2557
+
2558
+ specify "should be cleared if you set custom SQL for the dataset" do
2559
+ @dataset.db.columns = [[:a], [:b]]
2560
+ @dataset.columns.should == [:a]
2561
+ @dataset.db.sqls.should == ['SELECT * FROM items LIMIT 1']
2562
+ ds = @dataset.with_sql('SELECT b FROM foo')
2563
+ ds.columns.should == [:b]
2564
+ @dataset.db.sqls.should == ['SELECT b FROM foo']
2846
2565
  end
2847
2566
 
2848
2567
  specify "should ignore any filters, orders, or DISTINCT clauses" do
2568
+ @dataset.db.columns = [:a]
2849
2569
  @dataset.filter!(:b=>100).order!(:b).distinct!
2850
- @dataset.columns = nil
2851
- @dataset.columns.should == 'SELECT * FROM items LIMIT 1a'
2570
+ @dataset.columns.should == [:a]
2571
+ @dataset.db.sqls.should == ['SELECT * FROM items LIMIT 1']
2852
2572
  end
2853
2573
  end
2854
2574
 
2855
2575
  describe "Dataset#columns!" do
2856
- before do
2857
- @dataset = DummyDataset.new(nil).from(:items)
2858
- i = 'a'
2859
- @dataset.meta_def(:each){@columns = select_sql + i; i = i.next}
2860
- end
2861
-
2862
2576
  specify "should always attempt to get a record and return @columns" do
2863
- @dataset.columns!.should == 'SELECT * FROM items LIMIT 1a'
2864
- @dataset.columns!.should == 'SELECT * FROM items LIMIT 1b'
2865
- @dataset.opts[:from] = [:nana]
2866
- @dataset.columns!.should == 'SELECT * FROM nana LIMIT 1c'
2577
+ ds = Sequel.mock(:columns=>[[:a, :b, :c], [:d, :e, :f]])[:items]
2578
+ ds.columns!.should == [:a, :b, :c]
2579
+ ds.db.sqls.should == ['SELECT * FROM items LIMIT 1']
2580
+ ds.columns!.should == [:d, :e, :f]
2581
+ ds.db.sqls.should == ['SELECT * FROM items LIMIT 1']
2867
2582
  end
2868
2583
  end
2869
2584
 
2870
2585
  describe "Dataset#import" do
2871
2586
  before do
2872
- @dbc = Class.new(Sequel::Database) do
2873
- attr_reader :sqls
2874
-
2875
- def execute(sql, opts={})
2876
- @sqls ||= []
2877
- @sqls << sql
2878
- end
2879
- alias execute_dui execute
2880
-
2881
- def transaction(opts={})
2882
- @sqls ||= []
2883
- @sqls << 'BEGIN'
2884
- yield
2885
- @sqls << 'COMMIT'
2886
- end
2887
- end
2888
- @db = @dbc.new
2889
-
2890
- @ds = Sequel::Dataset.new(@db).from(:items)
2891
-
2892
- @list = [{:name => 'abc'}, {:name => 'def'}, {:name => 'ghi'}]
2587
+ @db = Sequel.mock
2588
+ @ds = @db[:items]
2893
2589
  end
2894
2590
 
2895
2591
  specify "should accept string keys as column names" do
2896
2592
  @ds.import(['x', 'y'], [[1, 2], [3, 4]])
2897
- @db.sqls.should == [
2898
- 'BEGIN',
2593
+ @db.sqls.should == ['BEGIN',
2899
2594
  "INSERT INTO items (x, y) VALUES (1, 2)",
2900
2595
  "INSERT INTO items (x, y) VALUES (3, 4)",
2901
- 'COMMIT'
2902
- ]
2596
+ 'COMMIT']
2903
2597
  end
2904
2598
 
2905
2599
  specify "should accept a columns array and a values array" do
2906
2600
  @ds.import([:x, :y], [[1, 2], [3, 4]])
2907
- @db.sqls.should == [
2908
- 'BEGIN',
2601
+ @db.sqls.should == ['BEGIN',
2909
2602
  "INSERT INTO items (x, y) VALUES (1, 2)",
2910
2603
  "INSERT INTO items (x, y) VALUES (3, 4)",
2911
- 'COMMIT'
2912
- ]
2604
+ 'COMMIT']
2913
2605
  end
2914
2606
 
2915
2607
  specify "should accept a columns array and a dataset" do
2916
- @ds2 = Sequel::Dataset.new(@db).from(:cats).filter(:purr => true).select(:a, :b)
2608
+ @ds2 = @ds.from(:cats).filter(:purr => true).select(:a, :b)
2917
2609
 
2918
2610
  @ds.import([:x, :y], @ds2)
2919
- @db.sqls.should == [
2920
- 'BEGIN',
2611
+ @db.sqls.should == ['BEGIN',
2921
2612
  "INSERT INTO items (x, y) SELECT a, b FROM cats WHERE (purr IS TRUE)",
2922
- 'COMMIT'
2923
- ]
2613
+ 'COMMIT']
2924
2614
  end
2925
2615
 
2926
2616
  specify "should accept a columns array and a values array with :commit_every option" do
2927
2617
  @ds.import([:x, :y], [[1, 2], [3, 4], [5, 6]], :commit_every => 3)
2928
- @db.sqls.should == [
2929
- 'BEGIN',
2618
+ @db.sqls.should == ['BEGIN',
2930
2619
  "INSERT INTO items (x, y) VALUES (1, 2)",
2931
2620
  "INSERT INTO items (x, y) VALUES (3, 4)",
2932
2621
  "INSERT INTO items (x, y) VALUES (5, 6)",
2933
- 'COMMIT',
2934
- ]
2622
+ 'COMMIT']
2935
2623
  end
2936
- specify "should accept a columns array and a values array with slice option" do
2624
+ specify "should accept a columns array and a values array with :slice option" do
2937
2625
  @ds.import([:x, :y], [[1, 2], [3, 4], [5, 6]], :slice => 2)
2938
- @db.sqls.should == [
2939
- 'BEGIN',
2626
+ @db.sqls.should == ['BEGIN',
2940
2627
  "INSERT INTO items (x, y) VALUES (1, 2)",
2941
2628
  "INSERT INTO items (x, y) VALUES (3, 4)",
2942
2629
  'COMMIT',
2943
2630
  'BEGIN',
2944
2631
  "INSERT INTO items (x, y) VALUES (5, 6)",
2945
- 'COMMIT'
2946
- ]
2632
+ 'COMMIT']
2947
2633
  end
2948
2634
  end
2949
2635
 
2950
2636
  describe "Dataset#multi_insert" do
2951
2637
  before do
2952
- @dbc = Class.new do
2953
- attr_reader :sqls
2954
-
2955
- def execute(sql, opts={})
2956
- @sqls ||= []
2957
- @sqls << sql
2958
- end
2959
- alias execute_dui execute
2960
-
2961
- def transaction(opts={})
2962
- @sqls ||= []
2963
- @sqls << 'BEGIN'
2964
- yield
2965
- @sqls << 'COMMIT'
2966
- end
2967
- end
2968
- @db = @dbc.new
2969
-
2970
- @ds = Sequel::Dataset.new(@db).from(:items)
2971
-
2638
+ @db = Sequel.mock
2639
+ @ds = @db[:items]
2972
2640
  @list = [{:name => 'abc'}, {:name => 'def'}, {:name => 'ghi'}]
2973
2641
  end
2974
2642
 
2975
2643
  specify "should issue multiple insert statements inside a transaction" do
2976
2644
  @ds.multi_insert(@list)
2977
- @db.sqls.should == [
2978
- 'BEGIN',
2645
+ @db.sqls.should == ['BEGIN',
2979
2646
  "INSERT INTO items (name) VALUES ('abc')",
2980
2647
  "INSERT INTO items (name) VALUES ('def')",
2981
2648
  "INSERT INTO items (name) VALUES ('ghi')",
2982
- 'COMMIT'
2983
- ]
2649
+ 'COMMIT']
2984
2650
  end
2985
2651
 
2986
2652
  specify "should handle different formats for tables" do
2987
2653
  @ds = @ds.from(:sch__tab)
2988
2654
  @ds.multi_insert(@list)
2989
- @db.sqls.should == [
2990
- 'BEGIN',
2655
+ @db.sqls.should == ['BEGIN',
2991
2656
  "INSERT INTO sch.tab (name) VALUES ('abc')",
2992
2657
  "INSERT INTO sch.tab (name) VALUES ('def')",
2993
2658
  "INSERT INTO sch.tab (name) VALUES ('ghi')",
2994
- 'COMMIT'
2995
- ]
2996
- @db.sqls.clear
2659
+ 'COMMIT']
2997
2660
 
2998
2661
  @ds = @ds.from(:tab.qualify(:sch))
2999
2662
  @ds.multi_insert(@list)
3000
- @db.sqls.should == [
3001
- 'BEGIN',
2663
+ @db.sqls.should == ['BEGIN',
3002
2664
  "INSERT INTO sch.tab (name) VALUES ('abc')",
3003
2665
  "INSERT INTO sch.tab (name) VALUES ('def')",
3004
2666
  "INSERT INTO sch.tab (name) VALUES ('ghi')",
3005
- 'COMMIT'
3006
- ]
3007
- @db.sqls.clear
2667
+ 'COMMIT']
2668
+
3008
2669
  @ds = @ds.from(:sch__tab.identifier)
3009
2670
  @ds.multi_insert(@list)
3010
- @db.sqls.should == [
3011
- 'BEGIN',
2671
+ @db.sqls.should == ['BEGIN',
3012
2672
  "INSERT INTO sch__tab (name) VALUES ('abc')",
3013
2673
  "INSERT INTO sch__tab (name) VALUES ('def')",
3014
2674
  "INSERT INTO sch__tab (name) VALUES ('ghi')",
3015
- 'COMMIT'
3016
- ]
2675
+ 'COMMIT']
3017
2676
  end
3018
2677
 
3019
2678
  specify "should accept the :commit_every option for committing every x records" do
3020
2679
  @ds.multi_insert(@list, :commit_every => 1)
3021
- @db.sqls.should == [
3022
- 'BEGIN',
2680
+ @db.sqls.should == ['BEGIN',
3023
2681
  "INSERT INTO items (name) VALUES ('abc')",
3024
2682
  'COMMIT',
3025
2683
  'BEGIN',
@@ -3027,36 +2685,31 @@ describe "Dataset#multi_insert" do
3027
2685
  'COMMIT',
3028
2686
  'BEGIN',
3029
2687
  "INSERT INTO items (name) VALUES ('ghi')",
3030
- 'COMMIT'
3031
- ]
2688
+ 'COMMIT']
3032
2689
  end
3033
2690
 
3034
2691
  specify "should accept the :slice option for committing every x records" do
3035
2692
  @ds.multi_insert(@list, :slice => 2)
3036
- @db.sqls.should == [
3037
- 'BEGIN',
2693
+ @db.sqls.should == ['BEGIN',
3038
2694
  "INSERT INTO items (name) VALUES ('abc')",
3039
2695
  "INSERT INTO items (name) VALUES ('def')",
3040
2696
  'COMMIT',
3041
2697
  'BEGIN',
3042
2698
  "INSERT INTO items (name) VALUES ('ghi')",
3043
- 'COMMIT'
3044
- ]
2699
+ 'COMMIT']
3045
2700
  end
3046
2701
 
3047
2702
  specify "should accept string keys as column names" do
3048
2703
  @ds.multi_insert([{'x'=>1, 'y'=>2}, {'x'=>3, 'y'=>4}])
3049
- @db.sqls.should == [
3050
- 'BEGIN',
2704
+ @db.sqls.should == ['BEGIN',
3051
2705
  "INSERT INTO items (x, y) VALUES (1, 2)",
3052
2706
  "INSERT INTO items (x, y) VALUES (3, 4)",
3053
- 'COMMIT'
3054
- ]
2707
+ 'COMMIT']
3055
2708
  end
3056
2709
 
3057
2710
  specify "should not do anything if no hashes are provided" do
3058
2711
  @ds.multi_insert([])
3059
- @db.sqls.should be_nil
2712
+ @db.sqls.should == []
3060
2713
  end
3061
2714
  end
3062
2715
 
@@ -3101,41 +2754,21 @@ describe "Dataset" do
3101
2754
  end
3102
2755
 
3103
2756
  specify "should support chaining of bang methods" do
3104
- @d.order!(:y)
3105
- @d.filter!(:y => 1)
3106
- @d.sql.should == "SELECT * FROM x WHERE (y = 1) ORDER BY y"
2757
+ @d.order!(:y).filter!(:y => 1).sql.should == "SELECT * FROM x WHERE (y = 1) ORDER BY y"
3107
2758
  end
3108
2759
  end
3109
2760
 
3110
2761
  describe "Dataset#to_csv" do
3111
2762
  before do
3112
- @c = Class.new(Sequel::Dataset) do
3113
- attr_accessor :data
3114
- attr_accessor :columns
3115
-
3116
- def fetch_rows(sql, &block)
3117
- @data.each(&block)
3118
- end
3119
-
3120
- # naked should return self here because to_csv wants a naked result set.
3121
- def naked
3122
- self
3123
- end
3124
- end
3125
-
3126
- @ds = @c.new(nil).from(:items)
3127
- @ds.columns = [:a, :b, :c]
3128
- @ds.data = [ {:a=>1, :b=>2, :c=>3}, {:a=>4, :b=>5, :c=>6}, {:a=>7, :b=>8, :c=>9} ]
2763
+ @ds = Sequel.mock(:fetch=>[{:a=>1, :b=>2, :c=>3}, {:a=>4, :b=>5, :c=>6}, {:a=>7, :b=>8, :c=>9}])[:items].columns(:a, :b, :c)
3129
2764
  end
3130
2765
 
3131
2766
  specify "should format a CSV representation of the records" do
3132
- @ds.to_csv.should ==
3133
- "a, b, c\r\n1, 2, 3\r\n4, 5, 6\r\n7, 8, 9\r\n"
2767
+ @ds.to_csv.should == "a, b, c\r\n1, 2, 3\r\n4, 5, 6\r\n7, 8, 9\r\n"
3134
2768
  end
3135
2769
 
3136
2770
  specify "should exclude column titles if so specified" do
3137
- @ds.to_csv(false).should ==
3138
- "1, 2, 3\r\n4, 5, 6\r\n7, 8, 9\r\n"
2771
+ @ds.to_csv(false).should == "1, 2, 3\r\n4, 5, 6\r\n7, 8, 9\r\n"
3139
2772
  end
3140
2773
  end
3141
2774
 
@@ -3233,66 +2866,40 @@ describe "Dataset#insert_sql" do
3233
2866
  end
3234
2867
  end
3235
2868
 
3236
- class DummyMummyDataset < Sequel::Dataset
3237
- def first
3238
- raise if @opts[:from] == [:a]
3239
- true
2869
+ describe "Dataset#inspect" do
2870
+ before do
2871
+ class ::InspectDataset < Sequel::Dataset; end
3240
2872
  end
3241
- end
3242
-
3243
- class DummyMummyDatabase < Sequel::Database
3244
- attr_reader :sqls
3245
-
3246
- def execute(sql)
3247
- @sqls ||= []
3248
- @sqls << sql
2873
+ after do
2874
+ Object.send(:remove_const, :InspectDataset) if defined?(::InspectDataset)
3249
2875
  end
3250
-
3251
- def transaction; yield; end
3252
2876
 
3253
- def dataset
3254
- DummyMummyDataset.new(self)
2877
+ specify "should include the class name and the corresponding SQL statement" do
2878
+ Sequel::Dataset.new(nil).from(:blah).inspect.should == '#<Sequel::Dataset: "SELECT * FROM blah">'
2879
+ InspectDataset.new(nil).from(:blah).inspect.should == '#<InspectDataset: "SELECT * FROM blah">'
3255
2880
  end
3256
- end
3257
2881
 
3258
- describe "Dataset#inspect" do
3259
- before do
3260
- @ds = Sequel::Dataset.new(nil).from(:blah)
3261
- end
3262
-
3263
- specify "should include the class name and the corresponding SQL statement" do
3264
- @ds.inspect.should == '#<%s: %s>' % [@ds.class.to_s, @ds.sql.inspect]
2882
+ specify "should skip anonymous classes" do
2883
+ Class.new(Class.new(Sequel::Dataset)).new(nil).from(:blah).inspect.should == '#<Sequel::Dataset: "SELECT * FROM blah">'
2884
+ Class.new(InspectDataset).new(nil).from(:blah).inspect.should == '#<InspectDataset: "SELECT * FROM blah">'
3265
2885
  end
3266
2886
  end
3267
2887
 
3268
2888
  describe "Dataset#all" do
3269
2889
  before do
3270
- @c = Class.new(Sequel::Dataset) do
3271
- def fetch_rows(sql, &block)
3272
- block.call({:x => 1, :y => 2})
3273
- block.call({:x => 3, :y => 4})
3274
- block.call(sql)
3275
- end
3276
- end
3277
- @dataset = @c.new(nil).from(:items)
2890
+ @dataset = Sequel.mock(:fetch=>[{:x => 1, :y => 2}, {:x => 3, :y => 4}])[:items]
3278
2891
  end
3279
2892
 
3280
2893
  specify "should return an array with all records" do
3281
- @dataset.all.should == [
3282
- {:x => 1, :y => 2},
3283
- {:x => 3, :y => 4},
3284
- "SELECT * FROM items"
3285
- ]
2894
+ @dataset.all.should == [{:x => 1, :y => 2}, {:x => 3, :y => 4}]
2895
+ @dataset.db.sqls.should == ["SELECT * FROM items"]
3286
2896
  end
3287
2897
 
3288
2898
  specify "should iterate over the array if a block is given" do
3289
2899
  a = []
3290
-
3291
- @dataset.all do |r|
3292
- a << (r.is_a?(Hash) ? r[:x] : r)
3293
- end
3294
-
3295
- a.should == [1, 3, "SELECT * FROM items"]
2900
+ @dataset.all{|r| a << r.values_at(:x, :y)}.should == [{:x => 1, :y => 2}, {:x => 3, :y => 4}]
2901
+ a.should == [[1, 2], [3, 4]]
2902
+ @dataset.db.sqls.should == ["SELECT * FROM items"]
3296
2903
  end
3297
2904
  end
3298
2905
 
@@ -3302,71 +2909,56 @@ describe "Dataset#grep" do
3302
2909
  end
3303
2910
 
3304
2911
  specify "should format a SQL filter correctly" do
3305
- @ds.grep(:title, 'ruby').sql.should ==
3306
- "SELECT * FROM posts WHERE ((title LIKE 'ruby'))"
2912
+ @ds.grep(:title, 'ruby').sql.should == "SELECT * FROM posts WHERE ((title LIKE 'ruby'))"
3307
2913
  end
3308
2914
 
3309
2915
  specify "should support multiple columns" do
3310
- @ds.grep([:title, :body], 'ruby').sql.should ==
3311
- "SELECT * FROM posts WHERE ((title LIKE 'ruby') OR (body LIKE 'ruby'))"
2916
+ @ds.grep([:title, :body], 'ruby').sql.should == "SELECT * FROM posts WHERE ((title LIKE 'ruby') OR (body LIKE 'ruby'))"
3312
2917
  end
3313
2918
 
3314
2919
  specify "should support multiple search terms" do
3315
- @ds.grep(:title, ['abc', 'def']).sql.should ==
3316
- "SELECT * FROM posts WHERE ((title LIKE 'abc') OR (title LIKE 'def'))"
2920
+ @ds.grep(:title, ['abc', 'def']).sql.should == "SELECT * FROM posts WHERE ((title LIKE 'abc') OR (title LIKE 'def'))"
3317
2921
  end
3318
2922
 
3319
2923
  specify "should support multiple columns and search terms" do
3320
- @ds.grep([:title, :body], ['abc', 'def']).sql.should ==
3321
- "SELECT * FROM posts WHERE ((title LIKE 'abc') OR (title LIKE 'def') OR (body LIKE 'abc') OR (body LIKE 'def'))"
2924
+ @ds.grep([:title, :body], ['abc', 'def']).sql.should == "SELECT * FROM posts WHERE ((title LIKE 'abc') OR (title LIKE 'def') OR (body LIKE 'abc') OR (body LIKE 'def'))"
3322
2925
  end
3323
2926
 
3324
2927
  specify "should support the :all_patterns option" do
3325
- @ds.grep([:title, :body], ['abc', 'def'], :all_patterns=>true).sql.should ==
3326
- "SELECT * FROM posts WHERE (((title LIKE 'abc') OR (body LIKE 'abc')) AND ((title LIKE 'def') OR (body LIKE 'def')))"
2928
+ @ds.grep([:title, :body], ['abc', 'def'], :all_patterns=>true).sql.should == "SELECT * FROM posts WHERE (((title LIKE 'abc') OR (body LIKE 'abc')) AND ((title LIKE 'def') OR (body LIKE 'def')))"
3327
2929
  end
3328
2930
 
3329
2931
  specify "should support the :all_columns option" do
3330
- @ds.grep([:title, :body], ['abc', 'def'], :all_columns=>true).sql.should ==
3331
- "SELECT * FROM posts WHERE (((title LIKE 'abc') OR (title LIKE 'def')) AND ((body LIKE 'abc') OR (body LIKE 'def')))"
2932
+ @ds.grep([:title, :body], ['abc', 'def'], :all_columns=>true).sql.should == "SELECT * FROM posts WHERE (((title LIKE 'abc') OR (title LIKE 'def')) AND ((body LIKE 'abc') OR (body LIKE 'def')))"
3332
2933
  end
3333
2934
 
3334
2935
  specify "should support the :case_insensitive option" do
3335
- @ds.grep([:title, :body], ['abc', 'def'], :case_insensitive=>true).sql.should ==
3336
- "SELECT * FROM posts WHERE ((title ILIKE 'abc') OR (title ILIKE 'def') OR (body ILIKE 'abc') OR (body ILIKE 'def'))"
2936
+ @ds.grep([:title, :body], ['abc', 'def'], :case_insensitive=>true).sql.should == "SELECT * FROM posts WHERE ((title ILIKE 'abc') OR (title ILIKE 'def') OR (body ILIKE 'abc') OR (body ILIKE 'def'))"
3337
2937
  end
3338
2938
 
3339
2939
  specify "should support the :all_patterns and :all_columns options together" do
3340
- @ds.grep([:title, :body], ['abc', 'def'], :all_patterns=>true, :all_columns=>true).sql.should ==
3341
- "SELECT * FROM posts WHERE ((title LIKE 'abc') AND (body LIKE 'abc') AND (title LIKE 'def') AND (body LIKE 'def'))"
2940
+ @ds.grep([:title, :body], ['abc', 'def'], :all_patterns=>true, :all_columns=>true).sql.should == "SELECT * FROM posts WHERE ((title LIKE 'abc') AND (body LIKE 'abc') AND (title LIKE 'def') AND (body LIKE 'def'))"
3342
2941
  end
3343
2942
 
3344
2943
  specify "should support the :all_patterns and :case_insensitive options together" do
3345
- @ds.grep([:title, :body], ['abc', 'def'], :all_patterns=>true, :case_insensitive=>true).sql.should ==
3346
- "SELECT * FROM posts WHERE (((title ILIKE 'abc') OR (body ILIKE 'abc')) AND ((title ILIKE 'def') OR (body ILIKE 'def')))"
2944
+ @ds.grep([:title, :body], ['abc', 'def'], :all_patterns=>true, :case_insensitive=>true).sql.should == "SELECT * FROM posts WHERE (((title ILIKE 'abc') OR (body ILIKE 'abc')) AND ((title ILIKE 'def') OR (body ILIKE 'def')))"
3347
2945
  end
3348
2946
 
3349
2947
  specify "should support the :all_columns and :case_insensitive options together" do
3350
- @ds.grep([:title, :body], ['abc', 'def'], :all_columns=>true, :case_insensitive=>true).sql.should ==
3351
- "SELECT * FROM posts WHERE (((title ILIKE 'abc') OR (title ILIKE 'def')) AND ((body ILIKE 'abc') OR (body ILIKE 'def')))"
2948
+ @ds.grep([:title, :body], ['abc', 'def'], :all_columns=>true, :case_insensitive=>true).sql.should == "SELECT * FROM posts WHERE (((title ILIKE 'abc') OR (title ILIKE 'def')) AND ((body ILIKE 'abc') OR (body ILIKE 'def')))"
3352
2949
  end
3353
2950
 
3354
2951
  specify "should support the :all_patterns, :all_columns, and :case_insensitive options together" do
3355
- @ds.grep([:title, :body], ['abc', 'def'], :all_patterns=>true, :all_columns=>true, :case_insensitive=>true).sql.should ==
3356
- "SELECT * FROM posts WHERE ((title ILIKE 'abc') AND (body ILIKE 'abc') AND (title ILIKE 'def') AND (body ILIKE 'def'))"
2952
+ @ds.grep([:title, :body], ['abc', 'def'], :all_patterns=>true, :all_columns=>true, :case_insensitive=>true).sql.should == "SELECT * FROM posts WHERE ((title ILIKE 'abc') AND (body ILIKE 'abc') AND (title ILIKE 'def') AND (body ILIKE 'def'))"
3357
2953
  end
3358
2954
 
3359
2955
  specify "should support regexps though the database may not support it" do
3360
- @ds.grep(:title, /ruby/).sql.should ==
3361
- "SELECT * FROM posts WHERE ((title ~ 'ruby'))"
3362
-
3363
- @ds.grep(:title, [/^ruby/, 'ruby']).sql.should ==
3364
- "SELECT * FROM posts WHERE ((title ~ '^ruby') OR (title LIKE 'ruby'))"
2956
+ @ds.grep(:title, /ruby/).sql.should == "SELECT * FROM posts WHERE ((title ~ 'ruby'))"
2957
+ @ds.grep(:title, [/^ruby/, 'ruby']).sql.should == "SELECT * FROM posts WHERE ((title ~ '^ruby') OR (title LIKE 'ruby'))"
3365
2958
  end
3366
2959
 
3367
2960
  specify "should support searching against other columns" do
3368
- @ds.grep(:title, :body).sql.should ==
3369
- "SELECT * FROM posts WHERE ((title LIKE body))"
2961
+ @ds.grep(:title, :body).sql.should == "SELECT * FROM posts WHERE ((title LIKE body))"
3370
2962
  end
3371
2963
  end
3372
2964
 
@@ -3420,18 +3012,7 @@ end
3420
3012
 
3421
3013
  describe "Dataset prepared statements and bound variables " do
3422
3014
  before do
3423
- @db = Sequel::Database.new
3424
- @db.meta_def(:sqls){@sqls||=[]}
3425
- def @db.execute(sql, opts={})
3426
- sqls << sql
3427
- end
3428
- def @db.dataset
3429
- ds = super()
3430
- def ds.fetch_rows(sql, &block)
3431
- execute(sql)
3432
- end
3433
- ds
3434
- end
3015
+ @db = Sequel.mock
3435
3016
  @ds = @db[:items]
3436
3017
  @ds.meta_def(:insert_sql){|*v| "#{super(*v)}#{' RETURNING *' if opts.has_key?(:returning)}" }
3437
3018
  end
@@ -3477,7 +3058,7 @@ describe "Dataset prepared statements and bound variables " do
3477
3058
 
3478
3059
  specify "#inspect should indicate it is a prepared statement with the prepared SQL" do
3479
3060
  @ds.filter(:num=>:$n).prepare(:select, :sn).inspect.should == \
3480
- '<Sequel::Dataset/PreparedStatement "SELECT * FROM items WHERE (num = $n)">'
3061
+ '<Sequel::Mock::Dataset/PreparedStatement "SELECT * FROM items WHERE (num = $n)">'
3481
3062
  end
3482
3063
 
3483
3064
  specify "should handle literal strings" do
@@ -3513,23 +3094,16 @@ end
3513
3094
 
3514
3095
  describe Sequel::Dataset::UnnumberedArgumentMapper do
3515
3096
  before do
3516
- @db = Sequel::Database.new
3517
- @db.meta_def(:sqls){@sqls||=[]}
3518
- def @db.execute(sql, opts={})
3519
- sqls << [sql, *opts[:arguments]]
3520
- end
3097
+ @db = Sequel.mock
3521
3098
  @ds = @db[:items].filter(:num=>:$n)
3522
- def @ds.fetch_rows(sql, &block)
3523
- execute(sql)
3524
- end
3525
3099
  def @ds.execute(sql, opts={}, &block)
3526
- @db.execute(sql, {:arguments=>bind_arguments}.merge(opts))
3100
+ super(sql, opts.merge({:arguments=>bind_arguments}), &block)
3527
3101
  end
3528
- def @ds.execute_dui(*args, &block)
3529
- execute(*args, &block)
3102
+ def @ds.execute_dui(sql, opts={}, &block)
3103
+ super(sql, opts.merge({:arguments=>bind_arguments}), &block)
3530
3104
  end
3531
- def @ds.execute_insert(*args, &block)
3532
- execute(*args, &block)
3105
+ def @ds.execute_insert(sql, opts={}, &block)
3106
+ super(sql, opts.merge({:arguments=>bind_arguments}), &block)
3533
3107
  end
3534
3108
  @ps = []
3535
3109
  @ps << @ds.prepare(:select, :s)
@@ -3542,64 +3116,43 @@ describe Sequel::Dataset::UnnumberedArgumentMapper do
3542
3116
  end
3543
3117
 
3544
3118
  specify "#inspect should show the actual SQL submitted to the database" do
3545
- @ps.first.inspect.should == '<Sequel::Dataset/PreparedStatement "SELECT * FROM items WHERE (num = ?)">'
3119
+ @ps.first.inspect.should == '<Sequel::Mock::Dataset/PreparedStatement "SELECT * FROM items WHERE (num = ?)">'
3546
3120
  end
3547
3121
 
3548
3122
  specify "should submitted the SQL to the database with placeholders and bind variables" do
3549
3123
  @ps.each{|p| p.prepared_sql; p.call(:n=>1)}
3550
- @db.sqls.should == [["SELECT * FROM items WHERE (num = ?)", 1],
3551
- ["SELECT * FROM items WHERE (num = ?)", 1],
3552
- ["SELECT * FROM items WHERE (num = ?) LIMIT 1", 1],
3553
- ["DELETE FROM items WHERE (num = ?)", 1],
3554
- ["INSERT INTO items (num) VALUES (?)", 1],
3555
- ["UPDATE items SET num = ? WHERE (num = ?)", 1, 1],
3556
- ]
3124
+ @db.sqls.should == ["SELECT * FROM items WHERE (num = ?) -- args: [1]",
3125
+ "SELECT * FROM items WHERE (num = ?) -- args: [1]",
3126
+ "SELECT * FROM items WHERE (num = ?) LIMIT 1 -- args: [1]",
3127
+ "DELETE FROM items WHERE (num = ?) -- args: [1]",
3128
+ "INSERT INTO items (num) VALUES (?) -- args: [1]",
3129
+ "UPDATE items SET num = ? WHERE (num = ?) -- args: [1, 1]"]
3557
3130
  end
3558
3131
  end
3559
3132
 
3560
3133
  describe "Sequel::Dataset#server" do
3561
3134
  specify "should set the server to use for the dataset" do
3562
- @db = Sequel::Database.new
3135
+ @db = Sequel.mock(:servers=>{:s=>{}, :i=>{}, :d=>{}, :u=>{}})
3563
3136
  @ds = @db[:items].server(:s)
3564
- sqls = []
3565
- @db.meta_def(:execute) do |sql, opts|
3566
- sqls << [sql, opts[:server]]
3567
- end
3568
- def @ds.fetch_rows(sql, &block)
3569
- execute(sql)
3570
- end
3571
3137
  @ds.all
3572
3138
  @ds.server(:i).insert(:a=>1)
3573
3139
  @ds.server(:d).delete
3574
3140
  @ds.server(:u).update(:a=>:a+1)
3575
- sqls.should == [['SELECT * FROM items', :s],
3576
- ['INSERT INTO items (a) VALUES (1)', :i],
3577
- ['DELETE FROM items', :d],
3578
- ['UPDATE items SET a = (a + 1)', :u]]
3141
+ @db.sqls.should == ['SELECT * FROM items -- s', 'INSERT INTO items (a) VALUES (1) -- i', 'DELETE FROM items -- d', 'UPDATE items SET a = (a + 1) -- u']
3579
3142
  end
3580
3143
  end
3581
3144
 
3582
3145
  describe "Sequel::Dataset#each_server" do
3583
- before do
3584
- @db = Sequel::Database.new(:servers=>{:s=>{}, :i=>{}})
3585
- @ds = @db[:items]
3586
- sqls = @sqls = []
3587
- @db.meta_def(:execute) do |sql, opts|
3588
- sqls << [sql, opts[:server]]
3589
- end
3590
- def @ds.fetch_rows(sql, &block)
3591
- execute(sql)
3592
- end
3593
- end
3594
-
3595
3146
  specify "should yield a dataset for each server" do
3147
+ @db = Sequel.mock(:servers=>{:s=>{}, :i=>{}})
3148
+ @ds = @db[:items]
3596
3149
  @ds.each_server do |ds|
3597
3150
  ds.should be_a_kind_of(Sequel::Dataset)
3598
3151
  ds.should_not == @ds
3599
3152
  ds.sql.should == @ds.sql
3600
3153
  ds.all
3601
3154
  end
3602
- @sqls.sort_by{|sql, s| s.to_s}.should == [['SELECT * FROM items', :default], ['SELECT * FROM items', :i], ['SELECT * FROM items', :s]]
3155
+ @db.sqls.sort.should == ['SELECT * FROM items', 'SELECT * FROM items -- i', 'SELECT * FROM items -- s']
3603
3156
  end
3604
3157
  end
3605
3158
 
@@ -3649,23 +3202,23 @@ end
3649
3202
 
3650
3203
  describe "Sequel::Dataset#qualify" do
3651
3204
  specify "should qualify to the given table" do
3652
- MockDatabase.new[:t].filter{a<b}.qualify(:e).sql.should == 'SELECT e.* FROM t WHERE (e.a < e.b)'
3205
+ Sequel::Dataset.new(nil).from(:t).filter{a<b}.qualify(:e).sql.should == 'SELECT e.* FROM t WHERE (e.a < e.b)'
3653
3206
  end
3654
3207
 
3655
3208
  specify "should qualify to the first source if no table if given" do
3656
- MockDatabase.new[:t].filter{a<b}.qualify.sql.should == 'SELECT t.* FROM t WHERE (t.a < t.b)'
3209
+ Sequel::Dataset.new(nil).from(:t).filter{a<b}.qualify.sql.should == 'SELECT t.* FROM t WHERE (t.a < t.b)'
3657
3210
  end
3658
3211
  end
3659
3212
 
3660
3213
  describe "Sequel::Dataset#qualify_to" do
3661
3214
  specify "should qualify to the given table" do
3662
- MockDatabase.new[:t].filter{a<b}.qualify_to(:e).sql.should == 'SELECT e.* FROM t WHERE (e.a < e.b)'
3215
+ Sequel::Dataset.new(nil).from(:t).filter{a<b}.qualify_to(:e).sql.should == 'SELECT e.* FROM t WHERE (e.a < e.b)'
3663
3216
  end
3664
3217
  end
3665
3218
 
3666
3219
  describe "Sequel::Dataset#qualify_to_first_source" do
3667
3220
  before do
3668
- @ds = MockDatabase.new[:t]
3221
+ @ds = Sequel::Database.new[:t]
3669
3222
  end
3670
3223
 
3671
3224
  specify "should qualify_to the first source" do
@@ -3675,13 +3228,11 @@ describe "Sequel::Dataset#qualify_to_first_source" do
3675
3228
  end
3676
3229
 
3677
3230
  specify "should handle the select, order, where, having, and group options/clauses" do
3678
- @ds.select(:a).filter(:a=>1).order(:a).group(:a).having(:a).qualify_to_first_source.sql.should == \
3679
- 'SELECT t.a FROM t WHERE (t.a = 1) GROUP BY t.a HAVING t.a ORDER BY t.a'
3231
+ @ds.select(:a).filter(:a=>1).order(:a).group(:a).having(:a).qualify_to_first_source.sql.should == 'SELECT t.a FROM t WHERE (t.a = 1) GROUP BY t.a HAVING t.a ORDER BY t.a'
3680
3232
  end
3681
3233
 
3682
3234
  specify "should handle the select using a table.* if all columns are currently selected" do
3683
- @ds.filter(:a=>1).order(:a).group(:a).having(:a).qualify_to_first_source.sql.should == \
3684
- 'SELECT t.* FROM t WHERE (t.a = 1) GROUP BY t.a HAVING t.a ORDER BY t.a'
3235
+ @ds.filter(:a=>1).order(:a).group(:a).having(:a).qualify_to_first_source.sql.should == 'SELECT t.* FROM t WHERE (t.a = 1) GROUP BY t.a HAVING t.a ORDER BY t.a'
3685
3236
  end
3686
3237
 
3687
3238
  specify "should handle hashes in select option" do
@@ -3750,14 +3301,13 @@ describe "Sequel::Dataset#qualify_to_first_source" do
3750
3301
  end
3751
3302
 
3752
3303
  specify "should handle all other objects by returning them unchanged" do
3753
- @ds.select("a").filter{a(3)}.filter('blah').order('true'.lit).group('a > ?'.lit(1)).having(false).qualify_to_first_source.sql.should == \
3754
- "SELECT 'a' FROM t WHERE (a(3) AND (blah)) GROUP BY a > 1 HAVING 'f' ORDER BY true"
3304
+ @ds.select("a").filter{a(3)}.filter('blah').order('true'.lit).group('a > ?'.lit(1)).having(false).qualify_to_first_source.sql.should == "SELECT 'a' FROM t WHERE (a(3) AND (blah)) GROUP BY a > 1 HAVING 'f' ORDER BY true"
3755
3305
  end
3756
3306
  end
3757
3307
 
3758
3308
  describe "Sequel::Dataset#unbind" do
3759
3309
  before do
3760
- @ds = MockDatabase.new[:t]
3310
+ @ds = Sequel::Database.new[:t]
3761
3311
  @u = proc{|ds| ds, bv = ds.unbind; [ds.sql, bv]}
3762
3312
  end
3763
3313
 
@@ -3827,7 +3377,7 @@ end
3827
3377
 
3828
3378
  describe "Sequel::Dataset #with and #with_recursive" do
3829
3379
  before do
3830
- @db = MockDatabase.new
3380
+ @db = Sequel::Database.new
3831
3381
  @ds = @db[:t]
3832
3382
  end
3833
3383
 
@@ -3868,11 +3418,18 @@ describe "Sequel::Dataset #with and #with_recursive" do
3868
3418
  @ds.with(:t, @db[:x]).update_sql(:foo=>1).should == 'WITH t AS (SELECT * FROM x) UPDATE t SET foo = 1'
3869
3419
  @ds.with(:t, @db[:x]).delete_sql.should == 'WITH t AS (SELECT * FROM x) DELETE FROM t'
3870
3420
  end
3421
+
3422
+ specify "should hoist WITH clauses in given dataset(s) if dataset doesn't support WITH in subselect" do
3423
+ @ds.meta_def(:supports_cte?){true}
3424
+ @ds.meta_def(:supports_cte_in_subselect?){false}
3425
+ @ds.with(:t, @ds.from(:s).with(:s, @ds.from(:r))).sql.should == 'WITH s AS (SELECT * FROM r), t AS (SELECT * FROM s) SELECT * FROM t'
3426
+ @ds.with_recursive(:t, @ds.from(:s).with(:s, @ds.from(:r)), @ds.from(:q).with(:q, @ds.from(:p))).sql.should == 'WITH s AS (SELECT * FROM r), q AS (SELECT * FROM p), t AS (SELECT * FROM s UNION ALL SELECT * FROM q) SELECT * FROM t'
3427
+ end
3871
3428
  end
3872
3429
 
3873
3430
  describe Sequel::SQL::Constants do
3874
3431
  before do
3875
- @db = MockDatabase.new
3432
+ @db = Sequel::Database.new
3876
3433
  end
3877
3434
 
3878
3435
  it "should have CURRENT_DATE" do
@@ -3917,7 +3474,7 @@ end
3917
3474
 
3918
3475
  describe "Sequel timezone support" do
3919
3476
  before do
3920
- @db = MockDatabase.new
3477
+ @db = Sequel::Database.new
3921
3478
  @dataset = @db.dataset
3922
3479
  @dataset.meta_def(:supports_timestamp_timezones?){true}
3923
3480
  @dataset.meta_def(:supports_timestamp_usecs?){false}
@@ -3952,6 +3509,30 @@ describe "Sequel timezone support" do
3952
3509
  @dataset.literal(t).should == "#{s}#{@offset}'"
3953
3510
  end
3954
3511
 
3512
+ specify "should have Database#timezone override Sequel.database_timezone" do
3513
+ Sequel.database_timezone = :local
3514
+ @db.timezone = :utc
3515
+
3516
+ t = Time.now
3517
+ s = t.getutc.strftime("'%Y-%m-%d %H:%M:%S")
3518
+ @dataset.literal(t).should == "#{s}+0000'"
3519
+
3520
+ t = DateTime.now
3521
+ s = t.new_offset(0).strftime("'%Y-%m-%d %H:%M:%S")
3522
+ @dataset.literal(t).should == "#{s}+0000'"
3523
+
3524
+ Sequel.database_timezone = :utc
3525
+ @db.timezone = :local
3526
+
3527
+ t = Time.now.utc
3528
+ s = t.getlocal.strftime("'%Y-%m-%d %H:%M:%S")
3529
+ @dataset.literal(t).should == "#{s}#{@offset}'"
3530
+
3531
+ t = DateTime.now.new_offset(0)
3532
+ s = t.new_offset(DateTime.now.offset).strftime("'%Y-%m-%d %H:%M:%S")
3533
+ @dataset.literal(t).should == "#{s}#{@offset}'"
3534
+ end
3535
+
3955
3536
  specify "should handle converting database timestamps into application timestamps" do
3956
3537
  Sequel.database_timezone = :utc
3957
3538
  Sequel.application_timezone = :local
@@ -4062,13 +3643,7 @@ end
4062
3643
 
4063
3644
  describe "Sequel::Dataset#select_map" do
4064
3645
  before do
4065
- @ds = MockDatabase.new[:t]
4066
- def @ds.fetch_rows(sql)
4067
- db << sql
4068
- yield({:c=>1})
4069
- yield({:c=>2})
4070
- end
4071
- @ds.db.reset
3646
+ @ds = Sequel.mock(:fetch=>[{:c=>1}, {:c=>2}])[:t]
4072
3647
  end
4073
3648
 
4074
3649
  specify "should do select and map in one step" do
@@ -4099,21 +3674,19 @@ describe "Sequel::Dataset#select_map" do
4099
3674
  specify "should handle an array of columns" do
4100
3675
  @ds.select_map([:c, :c]).should == [[1, 1], [2, 2]]
4101
3676
  @ds.db.sqls.should == ['SELECT c, c FROM t']
4102
- @ds.db.reset
4103
- @ds.select_order_map([:d.as(:c), :c.qualify(:b), :c.identifier, :c.identifier.qualify(:b), :a__c, :a__d___c]).should == [[1, 1, 1, 1, 1, 1], [2, 2, 2, 2, 2, 2]]
4104
- @ds.db.sqls.should == ['SELECT d AS c, b.c, c, b.c, a.c, a.d AS c FROM t ORDER BY d, b.c, c, b.c, a.c, a.d']
3677
+ @ds.select_map([:d.as(:c), :c.qualify(:b), :c.identifier, :c.identifier.qualify(:b), :a__c, :a__d___c]).should == [[1, 1, 1, 1, 1, 1], [2, 2, 2, 2, 2, 2]]
3678
+ @ds.db.sqls.should == ['SELECT d AS c, b.c, c, b.c, a.c, a.d AS c FROM t']
3679
+ end
3680
+
3681
+ specify "should handle an array with a single element" do
3682
+ @ds.select_map([:c]).should == [[1], [2]]
3683
+ @ds.db.sqls.should == ['SELECT c FROM t']
4105
3684
  end
4106
3685
  end
4107
3686
 
4108
3687
  describe "Sequel::Dataset#select_order_map" do
4109
3688
  before do
4110
- @ds = MockDatabase.new[:t]
4111
- def @ds.fetch_rows(sql)
4112
- db << sql
4113
- yield({:c=>1})
4114
- yield({:c=>2})
4115
- end
4116
- @ds.db.reset
3689
+ @ds = Sequel.mock(:fetch=>[{:c=>1}, {:c=>2}])[:t]
4117
3690
  end
4118
3691
 
4119
3692
  specify "should do select and map in one step" do
@@ -4154,73 +3727,65 @@ describe "Sequel::Dataset#select_order_map" do
4154
3727
  specify "should handle an array of columns" do
4155
3728
  @ds.select_order_map([:c, :c]).should == [[1, 1], [2, 2]]
4156
3729
  @ds.db.sqls.should == ['SELECT c, c FROM t ORDER BY c, c']
4157
- @ds.db.reset
4158
3730
  @ds.select_order_map([:d.as(:c), :c.qualify(:b), :c.identifier, :c.identifier.qualify(:b), :c.identifier.qualify(:b).desc, :a__c, :a__d___c.desc]).should == [[1, 1, 1, 1, 1, 1, 1], [2, 2, 2, 2, 2, 2, 2]]
4159
3731
  @ds.db.sqls.should == ['SELECT d AS c, b.c, c, b.c, b.c, a.c, a.d AS c FROM t ORDER BY d, b.c, c, b.c, b.c DESC, a.c, a.d DESC']
4160
3732
  end
3733
+
3734
+ specify "should handle an array with a single element" do
3735
+ @ds.select_order_map([:c]).should == [[1], [2]]
3736
+ @ds.db.sqls.should == ['SELECT c FROM t ORDER BY c']
3737
+ end
4161
3738
  end
4162
3739
 
4163
3740
  describe "Sequel::Dataset#select_hash" do
4164
3741
  before do
4165
- @ds = MockDatabase.new[:t]
4166
- def @ds.set_fr_yield(hs)
4167
- @hs = hs
4168
- end
4169
- def @ds.fetch_rows(sql)
4170
- db << sql
4171
- @hs.each{|h| yield h}
4172
- end
4173
- @ds.db.reset
3742
+ @db = Sequel.mock(:fetch=>[{:a=>1, :b=>2}, {:a=>3, :b=>4}])
3743
+ @ds = @db[:t]
4174
3744
  end
4175
3745
 
4176
3746
  specify "should do select and to_hash in one step" do
4177
- @ds.set_fr_yield([{:a=>1, :b=>2}, {:a=>3, :b=>4}])
4178
3747
  @ds.select_hash(:a, :b).should == {1=>2, 3=>4}
4179
3748
  @ds.db.sqls.should == ['SELECT a, b FROM t']
4180
3749
  end
4181
3750
 
4182
3751
  specify "should handle implicit qualifiers in arguments" do
4183
- @ds.set_fr_yield([{:a=>1, :b=>2}, {:a=>3, :b=>4}])
4184
3752
  @ds.select_hash(:t__a, :t__b).should == {1=>2, 3=>4}
4185
3753
  @ds.db.sqls.should == ['SELECT t.a, t.b FROM t']
4186
3754
  end
4187
3755
 
4188
3756
  specify "should handle implicit aliases in arguments" do
4189
- @ds.set_fr_yield([{:a=>1, :b=>2}, {:a=>3, :b=>4}])
4190
3757
  @ds.select_hash(:c___a, :d___b).should == {1=>2, 3=>4}
4191
3758
  @ds.db.sqls.should == ['SELECT c AS a, d AS b FROM t']
4192
3759
  end
4193
3760
 
4194
3761
  specify "should handle implicit qualifiers and aliases in arguments" do
4195
- @ds.set_fr_yield([{:a=>1, :b=>2}, {:a=>3, :b=>4}])
4196
3762
  @ds.select_hash(:t__c___a, :t__d___b).should == {1=>2, 3=>4}
4197
3763
  @ds.db.sqls.should == ['SELECT t.c AS a, t.d AS b FROM t']
4198
3764
  end
4199
3765
 
4200
3766
  specify "should handle SQL::Identifiers in arguments" do
4201
- @ds.set_fr_yield([{:a=>1, :b=>2}, {:a=>3, :b=>4}])
4202
3767
  @ds.select_hash(:a.identifier, :b.identifier).should == {1=>2, 3=>4}
4203
3768
  @ds.db.sqls.should == ['SELECT a, b FROM t']
4204
3769
  end
4205
3770
 
4206
3771
  specify "should handle SQL::QualifiedIdentifiers in arguments" do
4207
- @ds.set_fr_yield([{:a=>1, :b=>2}, {:a=>3, :b=>4}])
4208
3772
  @ds.select_hash(:a.qualify(:t), :b.identifier.qualify(:t)).should == {1=>2, 3=>4}
4209
3773
  @ds.db.sqls.should == ['SELECT t.a, t.b FROM t']
4210
3774
  end
4211
3775
 
4212
3776
  specify "should handle SQL::AliasedExpressions in arguments" do
4213
- @ds.set_fr_yield([{:a=>1, :b=>2}, {:a=>3, :b=>4}])
4214
3777
  @ds.select_hash(:c.as(:a), :t.as(:b)).should == {1=>2, 3=>4}
4215
3778
  @ds.db.sqls.should == ['SELECT c AS a, t AS b FROM t']
4216
3779
  end
4217
3780
 
4218
3781
  specify "should work with arrays of columns" do
4219
- @ds.set_fr_yield([{:a=>1, :b=>2, :c=>3}, {:a=>4, :b=>5, :c=>6}])
3782
+ @db.fetch = [{:a=>1, :b=>2, :c=>3}, {:a=>4, :b=>5, :c=>6}]
4220
3783
  @ds.select_hash([:a, :c], :b).should == {[1, 3]=>2, [4, 6]=>5}
4221
3784
  @ds.db.sqls.should == ['SELECT a, c, b FROM t']
4222
3785
  @ds.select_hash(:a, [:b, :c]).should == {1=>[2, 3], 4=>[5, 6]}
3786
+ @ds.db.sqls.should == ['SELECT a, b, c FROM t']
4223
3787
  @ds.select_hash([:a, :b], [:b, :c]).should == {[1, 2]=>[2, 3], [4, 5]=>[5, 6]}
3788
+ @ds.db.sqls.should == ['SELECT a, b, b, c FROM t']
4224
3789
  end
4225
3790
 
4226
3791
  specify "should raise an error if the resulting symbol cannot be determined" do
@@ -4230,9 +3795,8 @@ end
4230
3795
 
4231
3796
  describe "Modifying joined datasets" do
4232
3797
  before do
4233
- @ds = MockDatabase.new.from(:b, :c).join(:d, [:id]).where(:id => 2)
3798
+ @ds = Sequel.mock.from(:b, :c).join(:d, [:id]).where(:id => 2)
4234
3799
  @ds.meta_def(:supports_modifying_joins?){true}
4235
- @ds.db.reset
4236
3800
  end
4237
3801
 
4238
3802
  specify "should allow deleting from joined datasets" do
@@ -4248,7 +3812,7 @@ end
4248
3812
 
4249
3813
  describe "Dataset#lock_style and for_update" do
4250
3814
  before do
4251
- @ds = MockDatabase.new[:t]
3815
+ @ds = Sequel::Dataset.new(nil).from(:t)
4252
3816
  end
4253
3817
 
4254
3818
  specify "#for_update should use FOR UPDATE" do
@@ -4271,16 +3835,15 @@ describe "Custom ASTTransformer" do
4271
3835
  (s.is_a?(Symbol) || s.is_a?(String)) ? :"#{s}#{s}" : super
4272
3836
  end
4273
3837
  end.new
4274
- ds = MockDatabase.new[:t].cross_join(:a___g).join(:b___h, [:c]).join(:d___i, :e=>:f)
3838
+ ds = Sequel::Dataset.new(nil).from(:t).cross_join(:a___g).join(:b___h, [:c]).join(:d___i, :e=>:f)
4275
3839
  ds.sql.should == 'SELECT * FROM t CROSS JOIN a AS g INNER JOIN b AS h USING (c) INNER JOIN d AS i ON (i.e = h.f)'
4276
- ds.clone(:from=>c.transform(ds.opts[:from]), :join=>c.transform(ds.opts[:join])).sql.should ==
4277
- 'SELECT * FROM tt CROSS JOIN aa AS gg INNER JOIN bb AS hh USING (cc) INNER JOIN dd AS ii ON (ii.ee = hh.ff)'
3840
+ ds.clone(:from=>c.transform(ds.opts[:from]), :join=>c.transform(ds.opts[:join])).sql.should == 'SELECT * FROM tt CROSS JOIN aa AS gg INNER JOIN bb AS hh USING (cc) INNER JOIN dd AS ii ON (ii.ee = hh.ff)'
4278
3841
  end
4279
3842
  end
4280
3843
 
4281
3844
  describe "Dataset#returning" do
4282
3845
  before do
4283
- @ds = Sequel::Database.new[:t].returning(:foo)
3846
+ @ds = Sequel.mock(:fetch=>proc{|s| {:foo=>s}})[:t].returning(:foo)
4284
3847
  @pr = proc do
4285
3848
  [:insert, :update, :delete].each do |m|
4286
3849
  @ds.meta_def(:"#{m}_clause_methods"){super() + [:"#{m}_returning_sql"]}
@@ -4303,9 +3866,6 @@ describe "Dataset#returning" do
4303
3866
 
4304
3867
  specify "should have insert, update, and delete yield to blocks if RETURNING is used" do
4305
3868
  @pr.call
4306
- def @ds.fetch_rows(sql)
4307
- yield(:foo=>sql)
4308
- end
4309
3869
  h = {}
4310
3870
  @ds.delete{|r| h = r}
4311
3871
  h.should == {:foo=>"DELETE FROM t RETURNING foo"}
@@ -4317,12 +3877,39 @@ describe "Dataset#returning" do
4317
3877
 
4318
3878
  specify "should have insert, update, and delete return arrays of hashes if RETURNING is used and a block is not given" do
4319
3879
  @pr.call
4320
- def @ds.fetch_rows(sql)
4321
- yield(:foo=>sql)
4322
- end
4323
3880
  h = {}
4324
3881
  @ds.delete.should == [{:foo=>"DELETE FROM t RETURNING foo"}]
4325
3882
  @ds.insert(1).should == [{:foo=>"INSERT INTO t VALUES (1) RETURNING foo"}]
4326
3883
  @ds.update(:foo=>1).should == [{:foo=>"UPDATE t SET foo = 1 RETURNING foo"}]
4327
3884
  end
4328
3885
  end
3886
+
3887
+ describe "Dataset emulating bitwise operator support" do
3888
+ before do
3889
+ @ds = Sequel::Database.new.dataset
3890
+ @ds.quote_identifiers = true
3891
+ def @ds.complex_expression_sql(op, args)
3892
+ complex_expression_arg_pairs(args){|a, b| "bitand(#{literal(a)}, #{literal(b)})"}
3893
+ end
3894
+ end
3895
+
3896
+ it "should work with any numbers of arguments for operators" do
3897
+ @ds.select(Sequel::SQL::ComplexExpression.new(:&, :x)).sql.should == 'SELECT "x"'
3898
+ @ds.select(:x & 1).sql.should == 'SELECT bitand("x", 1)'
3899
+ @ds.select(:x & 1 & 2).sql.should == 'SELECT bitand(bitand("x", 1), 2)'
3900
+ end
3901
+ end
3902
+
3903
+ describe "Dataset feature defaults" do
3904
+ it "should not require aliases for recursive CTEs by default" do
3905
+ Sequel::Database.new.dataset.recursive_cte_requires_column_aliases?.should be_false
3906
+ end
3907
+
3908
+ it "should not require placeholder type specifiers by default" do
3909
+ Sequel::Database.new.dataset.requires_placeholder_type_specifiers?.should be_false
3910
+ end
3911
+
3912
+ it "offset use should be returning a separate row number column by default" do
3913
+ Sequel::Database.new.dataset.send(:offset_returns_row_number_column?).should be_false
3914
+ end
3915
+ end