sequel 3.21.0 → 3.32.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (234) hide show
  1. data/CHANGELOG +539 -3
  2. data/MIT-LICENSE +1 -1
  3. data/README.rdoc +20 -6
  4. data/Rakefile +37 -19
  5. data/bin/sequel +1 -5
  6. data/doc/advanced_associations.rdoc +17 -0
  7. data/doc/association_basics.rdoc +293 -43
  8. data/doc/dataset_basics.rdoc +4 -4
  9. data/doc/dataset_filtering.rdoc +8 -0
  10. data/doc/mass_assignment.rdoc +54 -0
  11. data/doc/migration.rdoc +15 -538
  12. data/doc/model_hooks.rdoc +72 -27
  13. data/doc/opening_databases.rdoc +89 -50
  14. data/doc/prepared_statements.rdoc +40 -13
  15. data/doc/reflection.rdoc +8 -2
  16. data/doc/release_notes/3.22.0.txt +39 -0
  17. data/doc/release_notes/3.23.0.txt +172 -0
  18. data/doc/release_notes/3.24.0.txt +420 -0
  19. data/doc/release_notes/3.25.0.txt +88 -0
  20. data/doc/release_notes/3.26.0.txt +88 -0
  21. data/doc/release_notes/3.27.0.txt +82 -0
  22. data/doc/release_notes/3.28.0.txt +304 -0
  23. data/doc/release_notes/3.29.0.txt +459 -0
  24. data/doc/release_notes/3.30.0.txt +135 -0
  25. data/doc/release_notes/3.31.0.txt +146 -0
  26. data/doc/release_notes/3.32.0.txt +202 -0
  27. data/doc/schema_modification.rdoc +547 -0
  28. data/doc/sharding.rdoc +7 -1
  29. data/doc/testing.rdoc +129 -0
  30. data/doc/transactions.rdoc +137 -0
  31. data/doc/virtual_rows.rdoc +2 -2
  32. data/lib/sequel/adapters/ado/mssql.rb +18 -6
  33. data/lib/sequel/adapters/ado.rb +40 -18
  34. data/lib/sequel/adapters/amalgalite.rb +17 -9
  35. data/lib/sequel/adapters/db2.rb +175 -86
  36. data/lib/sequel/adapters/dbi.rb +15 -15
  37. data/lib/sequel/adapters/do/mysql.rb +5 -7
  38. data/lib/sequel/adapters/do/postgres.rb +0 -5
  39. data/lib/sequel/adapters/do/sqlite.rb +0 -5
  40. data/lib/sequel/adapters/do.rb +17 -36
  41. data/lib/sequel/adapters/firebird.rb +27 -208
  42. data/lib/sequel/adapters/ibmdb.rb +448 -0
  43. data/lib/sequel/adapters/informix.rb +6 -23
  44. data/lib/sequel/adapters/jdbc/as400.rb +16 -34
  45. data/lib/sequel/adapters/jdbc/db2.rb +52 -0
  46. data/lib/sequel/adapters/jdbc/derby.rb +260 -0
  47. data/lib/sequel/adapters/jdbc/firebird.rb +29 -0
  48. data/lib/sequel/adapters/jdbc/h2.rb +66 -30
  49. data/lib/sequel/adapters/jdbc/hsqldb.rb +177 -0
  50. data/lib/sequel/adapters/jdbc/informix.rb +26 -0
  51. data/lib/sequel/adapters/jdbc/jtds.rb +34 -0
  52. data/lib/sequel/adapters/jdbc/mssql.rb +3 -33
  53. data/lib/sequel/adapters/jdbc/mysql.rb +11 -11
  54. data/lib/sequel/adapters/jdbc/oracle.rb +88 -25
  55. data/lib/sequel/adapters/jdbc/postgresql.rb +9 -13
  56. data/lib/sequel/adapters/jdbc/sqlite.rb +2 -6
  57. data/lib/sequel/adapters/jdbc/sqlserver.rb +71 -0
  58. data/lib/sequel/adapters/jdbc/transactions.rb +83 -0
  59. data/lib/sequel/adapters/jdbc.rb +231 -78
  60. data/lib/sequel/adapters/mock.rb +339 -0
  61. data/lib/sequel/adapters/mysql.rb +85 -184
  62. data/lib/sequel/adapters/mysql2.rb +26 -25
  63. data/lib/sequel/adapters/odbc/db2.rb +17 -0
  64. data/lib/sequel/adapters/odbc/mssql.rb +1 -6
  65. data/lib/sequel/adapters/odbc.rb +28 -9
  66. data/lib/sequel/adapters/openbase.rb +3 -5
  67. data/lib/sequel/adapters/oracle.rb +355 -53
  68. data/lib/sequel/adapters/postgres.rb +194 -33
  69. data/lib/sequel/adapters/shared/access.rb +32 -9
  70. data/lib/sequel/adapters/shared/db2.rb +328 -0
  71. data/lib/sequel/adapters/shared/firebird.rb +221 -0
  72. data/lib/sequel/adapters/shared/informix.rb +53 -0
  73. data/lib/sequel/adapters/shared/mssql.rb +278 -107
  74. data/lib/sequel/adapters/shared/mysql.rb +203 -65
  75. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +149 -0
  76. data/lib/sequel/adapters/shared/oracle.rb +237 -46
  77. data/lib/sequel/adapters/shared/postgres.rb +214 -82
  78. data/lib/sequel/adapters/shared/progress.rb +5 -8
  79. data/lib/sequel/adapters/shared/sqlite.rb +200 -50
  80. data/lib/sequel/adapters/sqlite.rb +29 -21
  81. data/lib/sequel/adapters/swift/mysql.rb +12 -7
  82. data/lib/sequel/adapters/swift/postgres.rb +0 -5
  83. data/lib/sequel/adapters/swift/sqlite.rb +8 -6
  84. data/lib/sequel/adapters/swift.rb +5 -5
  85. data/lib/sequel/adapters/tinytds.rb +160 -19
  86. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +66 -0
  87. data/lib/sequel/adapters/utils/stored_procedures.rb +1 -11
  88. data/lib/sequel/ast_transformer.rb +190 -0
  89. data/lib/sequel/connection_pool/threaded.rb +3 -2
  90. data/lib/sequel/connection_pool.rb +1 -1
  91. data/lib/sequel/core.rb +68 -5
  92. data/lib/sequel/database/connecting.rb +5 -6
  93. data/lib/sequel/database/dataset.rb +4 -4
  94. data/lib/sequel/database/dataset_defaults.rb +59 -1
  95. data/lib/sequel/database/logging.rb +1 -1
  96. data/lib/sequel/database/misc.rb +104 -19
  97. data/lib/sequel/database/query.rb +163 -59
  98. data/lib/sequel/database/schema_generator.rb +17 -7
  99. data/lib/sequel/database/schema_methods.rb +59 -29
  100. data/lib/sequel/dataset/actions.rb +240 -76
  101. data/lib/sequel/dataset/features.rb +91 -8
  102. data/lib/sequel/dataset/graph.rb +38 -11
  103. data/lib/sequel/dataset/misc.rb +50 -23
  104. data/lib/sequel/dataset/mutation.rb +12 -7
  105. data/lib/sequel/dataset/prepared_statements.rb +59 -27
  106. data/lib/sequel/dataset/query.rb +236 -43
  107. data/lib/sequel/dataset/sql.rb +676 -267
  108. data/lib/sequel/dataset.rb +8 -0
  109. data/lib/sequel/exceptions.rb +4 -0
  110. data/lib/sequel/extensions/columns_introspection.rb +61 -0
  111. data/lib/sequel/extensions/migration.rb +6 -4
  112. data/lib/sequel/extensions/named_timezones.rb +5 -0
  113. data/lib/sequel/extensions/query.rb +1 -1
  114. data/lib/sequel/extensions/thread_local_timezones.rb +1 -1
  115. data/lib/sequel/extensions/to_dot.rb +95 -83
  116. data/lib/sequel/model/associations.rb +1081 -344
  117. data/lib/sequel/model/base.rb +420 -133
  118. data/lib/sequel/model/errors.rb +1 -1
  119. data/lib/sequel/model/exceptions.rb +5 -1
  120. data/lib/sequel/model.rb +20 -10
  121. data/lib/sequel/plugins/active_model.rb +13 -1
  122. data/lib/sequel/plugins/association_pks.rb +22 -4
  123. data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
  124. data/lib/sequel/plugins/composition.rb +43 -10
  125. data/lib/sequel/plugins/dataset_associations.rb +100 -0
  126. data/lib/sequel/plugins/defaults_setter.rb +58 -0
  127. data/lib/sequel/plugins/force_encoding.rb +6 -6
  128. data/lib/sequel/plugins/identity_map.rb +114 -7
  129. data/lib/sequel/plugins/many_through_many.rb +68 -7
  130. data/lib/sequel/plugins/nested_attributes.rb +65 -10
  131. data/lib/sequel/plugins/prepared_statements.rb +151 -0
  132. data/lib/sequel/plugins/prepared_statements_associations.rb +84 -0
  133. data/lib/sequel/plugins/prepared_statements_safe.rb +82 -0
  134. data/lib/sequel/plugins/prepared_statements_with_pk.rb +59 -0
  135. data/lib/sequel/plugins/rcte_tree.rb +29 -15
  136. data/lib/sequel/plugins/serialization.rb +98 -49
  137. data/lib/sequel/plugins/serialization_modification_detection.rb +63 -0
  138. data/lib/sequel/plugins/sharding.rb +21 -54
  139. data/lib/sequel/plugins/single_table_inheritance.rb +3 -1
  140. data/lib/sequel/plugins/typecast_on_load.rb +9 -12
  141. data/lib/sequel/plugins/update_primary_key.rb +2 -2
  142. data/lib/sequel/plugins/xml_serializer.rb +3 -3
  143. data/lib/sequel/sql.rb +109 -52
  144. data/lib/sequel/timezones.rb +57 -38
  145. data/lib/sequel/version.rb +1 -1
  146. data/spec/adapters/db2_spec.rb +146 -0
  147. data/spec/adapters/mssql_spec.rb +135 -30
  148. data/spec/adapters/mysql_spec.rb +244 -212
  149. data/spec/adapters/oracle_spec.rb +67 -77
  150. data/spec/adapters/postgres_spec.rb +267 -78
  151. data/spec/adapters/spec_helper.rb +6 -5
  152. data/spec/adapters/sqlite_spec.rb +35 -21
  153. data/spec/core/connection_pool_spec.rb +71 -92
  154. data/spec/core/core_sql_spec.rb +21 -30
  155. data/spec/core/database_spec.rb +789 -512
  156. data/spec/core/dataset_spec.rb +1176 -1061
  157. data/spec/core/expression_filters_spec.rb +159 -42
  158. data/spec/core/mock_adapter_spec.rb +419 -0
  159. data/spec/core/object_graph_spec.rb +86 -114
  160. data/spec/core/schema_generator_spec.rb +3 -3
  161. data/spec/core/schema_spec.rb +298 -38
  162. data/spec/core/spec_helper.rb +6 -48
  163. data/spec/extensions/active_model_spec.rb +13 -0
  164. data/spec/extensions/association_autoreloading_spec.rb +1 -10
  165. data/spec/extensions/association_dependencies_spec.rb +2 -12
  166. data/spec/extensions/association_pks_spec.rb +66 -32
  167. data/spec/extensions/caching_spec.rb +23 -50
  168. data/spec/extensions/class_table_inheritance_spec.rb +31 -83
  169. data/spec/extensions/columns_introspection_spec.rb +91 -0
  170. data/spec/extensions/composition_spec.rb +18 -13
  171. data/spec/extensions/dataset_associations_spec.rb +199 -0
  172. data/spec/extensions/defaults_setter_spec.rb +64 -0
  173. data/spec/extensions/hook_class_methods_spec.rb +65 -91
  174. data/spec/extensions/identity_map_spec.rb +114 -22
  175. data/spec/extensions/instance_filters_spec.rb +11 -21
  176. data/spec/extensions/instance_hooks_spec.rb +53 -0
  177. data/spec/extensions/json_serializer_spec.rb +4 -5
  178. data/spec/extensions/lazy_attributes_spec.rb +16 -20
  179. data/spec/extensions/list_spec.rb +17 -39
  180. data/spec/extensions/many_through_many_spec.rb +283 -250
  181. data/spec/extensions/migration_spec.rb +35 -32
  182. data/spec/extensions/named_timezones_spec.rb +23 -3
  183. data/spec/extensions/nested_attributes_spec.rb +97 -88
  184. data/spec/extensions/optimistic_locking_spec.rb +9 -20
  185. data/spec/extensions/prepared_statements_associations_spec.rb +111 -0
  186. data/spec/extensions/prepared_statements_safe_spec.rb +61 -0
  187. data/spec/extensions/prepared_statements_spec.rb +53 -0
  188. data/spec/extensions/prepared_statements_with_pk_spec.rb +31 -0
  189. data/spec/extensions/pretty_table_spec.rb +1 -6
  190. data/spec/extensions/query_spec.rb +6 -0
  191. data/spec/extensions/rcte_tree_spec.rb +41 -43
  192. data/spec/extensions/schema_dumper_spec.rb +5 -8
  193. data/spec/extensions/schema_spec.rb +13 -21
  194. data/spec/extensions/serialization_modification_detection_spec.rb +72 -0
  195. data/spec/extensions/serialization_spec.rb +81 -43
  196. data/spec/extensions/sharding_spec.rb +66 -140
  197. data/spec/extensions/single_table_inheritance_spec.rb +18 -29
  198. data/spec/extensions/spec_helper.rb +13 -61
  199. data/spec/extensions/sql_expr_spec.rb +20 -60
  200. data/spec/extensions/tactical_eager_loading_spec.rb +9 -19
  201. data/spec/extensions/thread_local_timezones_spec.rb +22 -2
  202. data/spec/extensions/timestamps_spec.rb +6 -6
  203. data/spec/extensions/to_dot_spec.rb +4 -7
  204. data/spec/extensions/touch_spec.rb +13 -14
  205. data/spec/extensions/tree_spec.rb +11 -26
  206. data/spec/extensions/typecast_on_load_spec.rb +1 -6
  207. data/spec/extensions/update_primary_key_spec.rb +30 -24
  208. data/spec/extensions/validation_class_methods_spec.rb +30 -51
  209. data/spec/extensions/validation_helpers_spec.rb +16 -35
  210. data/spec/extensions/xml_serializer_spec.rb +16 -4
  211. data/spec/integration/associations_test.rb +661 -21
  212. data/spec/integration/database_test.rb +4 -2
  213. data/spec/integration/dataset_test.rb +500 -67
  214. data/spec/integration/eager_loader_test.rb +19 -21
  215. data/spec/integration/model_test.rb +80 -1
  216. data/spec/integration/plugin_test.rb +367 -119
  217. data/spec/integration/prepared_statement_test.rb +222 -125
  218. data/spec/integration/schema_test.rb +217 -39
  219. data/spec/integration/spec_helper.rb +39 -30
  220. data/spec/integration/timezone_test.rb +38 -12
  221. data/spec/integration/transaction_test.rb +182 -5
  222. data/spec/integration/type_test.rb +17 -3
  223. data/spec/model/association_reflection_spec.rb +201 -7
  224. data/spec/model/associations_spec.rb +955 -662
  225. data/spec/model/base_spec.rb +275 -95
  226. data/spec/model/dataset_methods_spec.rb +7 -27
  227. data/spec/model/eager_loading_spec.rb +677 -676
  228. data/spec/model/hooks_spec.rb +349 -67
  229. data/spec/model/model_spec.rb +222 -168
  230. data/spec/model/plugins_spec.rb +24 -13
  231. data/spec/model/record_spec.rb +381 -218
  232. data/spec/model/spec_helper.rb +13 -71
  233. data/spec/model/validations_spec.rb +11 -0
  234. metadata +117 -73
@@ -2,16 +2,16 @@ require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper.rb')
2
2
 
3
3
  describe "Simple Dataset operations" do
4
4
  before do
5
- INTEGRATION_DB.create_table!(:items) do
5
+ @db = INTEGRATION_DB
6
+ @db.create_table!(:items) do
6
7
  primary_key :id
7
8
  Integer :number
8
9
  end
9
- @ds = INTEGRATION_DB[:items]
10
+ @ds = @db[:items]
10
11
  @ds.insert(:number=>10)
11
- clear_sqls
12
12
  end
13
13
  after do
14
- INTEGRATION_DB.drop_table(:items)
14
+ @db.drop_table(:items)
15
15
  end
16
16
 
17
17
  specify "should support sequential primary keys" do
@@ -23,7 +23,7 @@ describe "Simple Dataset operations" do
23
23
  {:id => 3, :number=>30} ]
24
24
  end
25
25
 
26
- cspecify "should insert with a primary key specified", :mssql do
26
+ cspecify "should insert with a primary key specified", :db2, :mssql do
27
27
  @ds.insert(:id=>100, :number=>20)
28
28
  @ds.count.should == 2
29
29
  @ds.order(:id).all.should == [{:id=>1, :number=>10}, {:id=>100, :number=>20}]
@@ -34,6 +34,43 @@ describe "Simple Dataset operations" do
34
34
  @ds.filter(:id=>2).first[:number].should == 20
35
35
  end
36
36
 
37
+ specify "should have insert work correctly with static SQL" do
38
+ @db["INSERT INTO #{@ds.literal(:items)} (#{@ds.literal(:number)}) VALUES (20)"].insert
39
+ @ds.filter(:id=>2).first[:number].should == 20
40
+ end
41
+
42
+ specify "should have insert_multiple return primary key values" do
43
+ @ds.insert_multiple([{:number=>20}, {:number=>30}]).should == [2, 3]
44
+ @ds.filter(:id=>2).get(:number).should == 20
45
+ @ds.filter(:id=>3).get(:number).should == 30
46
+ end
47
+
48
+ specify "should join correctly" do
49
+ @ds.join(:items___b, :id=>:id).select_all(:items).all.should == [{:id=>1, :number=>10}]
50
+ end
51
+
52
+ specify "should correctly deal with qualified columns and subselects" do
53
+ @ds.from_self(:alias=>:a).select(:a__id, :number.qualify(:a)).all.should == [{:id=>1, :number=>10}]
54
+ @ds.join(@ds.as(:a), :id=>:id).select(:a__id, :number.qualify(:a)).all.should == [{:id=>1, :number=>10}]
55
+ end
56
+
57
+ specify "should graph correctly" do
58
+ @ds.graph(:items, {:id=>:id}, :table_alias=>:b).all.should == [{:items=>{:id=>1, :number=>10}, :b=>{:id=>1, :number=>10}}]
59
+ end
60
+
61
+ specify "should graph correctly with a subselect" do
62
+ @ds.from_self(:alias=>:items).graph(@ds.from_self, {:id=>:id}, :table_alias=>:b).all.should == [{:items=>{:id=>1, :number=>10}, :b=>{:id=>1, :number=>10}}]
63
+ end
64
+
65
+ cspecify "should have insert work correctly when inserting a row with all NULL values", :hsqldb do
66
+ @db.create_table!(:items) do
67
+ String :name
68
+ Integer :number
69
+ end
70
+ proc{@ds.insert}.should_not raise_error
71
+ @ds.all.should == [{:name=>nil, :number=>nil}]
72
+ end
73
+
37
74
  specify "should delete correctly" do
38
75
  @ds.filter(1=>1).delete.should == 1
39
76
  @ds.count.should == 0
@@ -79,13 +116,60 @@ describe "Simple Dataset operations" do
79
116
  @ds.order(:id).limit(2, 1).all.should == [{:id=>2, :number=>20}]
80
117
  end
81
118
 
82
- cspecify "should fetch correctly with a limit and offset without an order", :mssql do
119
+ specify "should provide correct columns when using a limit and offset" do
120
+ ds = @ds.order(:id).limit(1, 1)
121
+ ds.all
122
+ ds.columns.should == [:id, :number]
123
+ @ds.order(:id).limit(1, 1).columns.should == [:id, :number]
124
+ end
125
+
126
+ specify "should fetch correctly with a limit and offset for different combinations of from and join tables" do
127
+ @db.create_table!(:items2){primary_key :id2; Integer :number2}
128
+ @db[:items2].insert(:number2=>10)
129
+ @ds.from(:items, :items2).order(:id).limit(2, 0).all.should == [{:id=>1, :number=>10, :id2=>1, :number2=>10}]
130
+ @ds.from(:items___i, :items2___i2).order(:id).limit(2, 0).all.should == [{:id=>1, :number=>10, :id2=>1, :number2=>10}]
131
+ @ds.cross_join(:items2).order(:id).limit(2, 0).all.should ==[{:id=>1, :number=>10, :id2=>1, :number2=>10}]
132
+ @ds.from(:items___i).cross_join(:items2___i2).order(:id).limit(2, 0).all.should == [{:id=>1, :number=>10, :id2=>1, :number2=>10}]
133
+ @ds.cross_join(:items2___i).cross_join(@db[:items2].select(:id2___id3, :number2___number3)).order(:id).limit(2, 0).all.should == [{:id=>1, :number=>10, :id2=>1, :number2=>10, :id3=>1, :number3=>10}]
134
+
135
+ @ds.from(:items, :items2).order(:id).limit(2, 1).all.should == []
136
+ @ds.from(:items___i, :items2___i2).order(:id).limit(2, 1).all.should == []
137
+ @ds.cross_join(:items2).order(:id).limit(2, 1).all.should == []
138
+ @ds.from(:items___i).cross_join(:items2___i2).order(:id).limit(2, 1).all.should == []
139
+ @ds.cross_join(:items2___i).cross_join(@db[:items2].select(:id2___id3, :number2___number3)).order(:id).limit(2, 1).all.should == []
140
+ @db.drop_table(:items2)
141
+ end
142
+
143
+ cspecify "should fetch correctly with a limit and offset without an order", :db2, :mssql, :oracle do
83
144
  @ds.limit(2, 1).all.should == []
84
145
  end
85
146
 
147
+ specify "should fetch correctly with a limit in an IN subselect" do
148
+ @ds.where(:id=>@ds.select(:id).order(:id).limit(2)).all.should == [{:id=>1, :number=>10}]
149
+ @ds.insert(:number=>20)
150
+ @ds.where(:id=>@ds.select(:id).order(:id).limit(1)).all.should == [{:id=>1, :number=>10}]
151
+ @ds.where(:id=>@ds.select(:id).order(:id).limit(2)).order(:id).all.should == [{:id=>1, :number=>10}, {:id=>2, :number=>20}]
152
+ end
153
+
154
+ specify "should fetch correctly with a limit and offset in an IN subselect" do
155
+ @ds.where(:id=>@ds.select(:id).order(:id).limit(2, 0)).all.should == [{:id=>1, :number=>10}]
156
+ @ds.where(:id=>@ds.select(:id).order(:id).limit(2, 1)).all.should == []
157
+ @ds.insert(:number=>20)
158
+ @ds.where(:id=>@ds.select(:id).order(:id).limit(1, 1)).all.should == [{:id=>2, :number=>20}]
159
+ @ds.where(:id=>@ds.select(:id).order(:id).limit(2, 0)).order(:id).all.should == [{:id=>1, :number=>10}, {:id=>2, :number=>20}]
160
+ @ds.where(:id=>@ds.select(:id).order(:id).limit(2, 1)).all.should == [{:id=>2, :number=>20}]
161
+ end
162
+
86
163
  specify "should alias columns correctly" do
87
164
  @ds.select(:id___x, :number___n).first.should == {:x=>1, :n=>10}
88
165
  end
166
+
167
+ specify "should handle true/false properly" do
168
+ @ds.filter(Sequel::TRUE).select_map(:number).should == [10]
169
+ @ds.filter(Sequel::FALSE).select_map(:number).should == []
170
+ @ds.filter(true).select_map(:number).should == [10]
171
+ @ds.filter(false).select_map(:number).should == []
172
+ end
89
173
  end
90
174
 
91
175
  describe Sequel::Dataset do
@@ -95,7 +179,6 @@ describe Sequel::Dataset do
95
179
  Integer :value
96
180
  end
97
181
  @d = INTEGRATION_DB[:test]
98
- clear_sqls
99
182
  end
100
183
  after do
101
184
  INTEGRATION_DB.drop_table(:test)
@@ -187,7 +270,11 @@ describe Sequel::Database do
187
270
  INTEGRATION_DB.drop_table(t) rescue nil
188
271
  INTEGRATION_DB.table_exists?(t).should == false
189
272
  INTEGRATION_DB.create_table(t){Integer :a}
190
- INTEGRATION_DB.table_exists?(t).should == true
273
+ begin
274
+ INTEGRATION_DB.table_exists?(t).should == true
275
+ ensure
276
+ INTEGRATION_DB.drop_table(t)
277
+ end
191
278
  end
192
279
  end
193
280
 
@@ -251,18 +338,17 @@ end
251
338
 
252
339
  describe "Simple Dataset operations in transactions" do
253
340
  before do
254
- INTEGRATION_DB.create_table!(:items_insert_in_transaction) do
341
+ INTEGRATION_DB.create_table!(:items) do
255
342
  primary_key :id
256
343
  integer :number
257
344
  end
258
- @ds = INTEGRATION_DB[:items_insert_in_transaction]
259
- clear_sqls
345
+ @ds = INTEGRATION_DB[:items]
260
346
  end
261
347
  after do
262
- INTEGRATION_DB.drop_table(:items_insert_in_transaction)
348
+ INTEGRATION_DB.drop_table(:items)
263
349
  end
264
350
 
265
- cspecify "should insert correctly with a primary key specified inside a transaction", :mssql do
351
+ cspecify "should insert correctly with a primary key specified inside a transaction", :db2, :mssql do
266
352
  INTEGRATION_DB.transaction do
267
353
  @ds.insert(:id=>100, :number=>20)
268
354
  @ds.count.should == 1
@@ -293,7 +379,6 @@ describe "Dataset UNION, EXCEPT, and INTERSECT" do
293
379
  @ds2 = INTEGRATION_DB[:i2]
294
380
  @ds2.insert(:number=>10)
295
381
  @ds2.insert(:number=>30)
296
- clear_sqls
297
382
  end
298
383
 
299
384
  specify "should give the correct results for simple UNION, EXCEPT, and INTERSECT" do
@@ -359,7 +444,7 @@ end
359
444
 
360
445
  if INTEGRATION_DB.dataset.supports_cte?
361
446
  describe "Common Table Expressions" do
362
- before do
447
+ before(:all) do
363
448
  @db = INTEGRATION_DB
364
449
  @db.create_table!(:i1){Integer :id; Integer :parent_id}
365
450
  @ds = @db[:i1]
@@ -370,7 +455,7 @@ if INTEGRATION_DB.dataset.supports_cte?
370
455
  @ds.insert(:id=>5, :parent_id=>3)
371
456
  @ds.insert(:id=>6, :parent_id=>5)
372
457
  end
373
- after do
458
+ after(:all) do
374
459
  @db.drop_table(:i1)
375
460
  end
376
461
 
@@ -378,7 +463,7 @@ if INTEGRATION_DB.dataset.supports_cte?
378
463
  @db[:t].with(:t, @ds.filter(:parent_id=>nil).select(:id)).order(:id).map(:id).should == [1, 2]
379
464
  end
380
465
 
381
- specify "should give correct results for recursive WITH" do
466
+ cspecify "should give correct results for recursive WITH", :db2 do
382
467
  ds = @db[:t].select(:i___id, :pi___parent_id).with_recursive(:t, @ds.filter(:parent_id=>nil), @ds.join(:t, :i=>:parent_id).select(:i1__id, :i1__parent_id), :args=>[:i, :pi])
383
468
  ds.all.should == [{:parent_id=>nil, :id=>1}, {:parent_id=>nil, :id=>2}, {:parent_id=>1, :id=>3}, {:parent_id=>1, :id=>4}, {:parent_id=>3, :id=>5}, {:parent_id=>5, :id=>6}]
384
469
  ps = @db[:t].select(:i___id, :pi___parent_id).with_recursive(:t, @ds.filter(:parent_id=>:$n), @ds.join(:t, :i=>:parent_id).filter(:t__i=>:parent_id).select(:i1__id, :i1__parent_id), :args=>[:i, :pi]).prepare(:select, :cte_sel)
@@ -391,12 +476,116 @@ if INTEGRATION_DB.dataset.supports_cte?
391
476
  @ds.inner_join(@db[:t].with(:t, @ds.filter(:parent_id=>nil)), :id => :id).select(:i1__id).order(:i1__id).map(:id).should == [1,2]
392
477
  @db[:t].with(:t, @ds).inner_join(@db[:s].with(:s, @ds.filter(:parent_id=>nil)), :id => :id).select(:t__id).order(:t__id).map(:id).should == [1,2]
393
478
  end
479
+
480
+ specify "should support a subselect in the FROM clause with a CTE" do
481
+ @ds.from(@db[:t].with(:t, @ds)).select_order_map(:id).should == [1,2,3,4,5,6]
482
+ @db[:t].with(:t, @ds).from_self.select_order_map(:id).should == [1,2,3,4,5,6]
483
+ end
484
+
485
+ specify "should support using a CTE inside a CTE" do
486
+ @db[:s].with(:s, @db[:t].with(:t, @ds)).select_order_map(:id).should == [1,2,3,4,5,6]
487
+ @db[:s].with_recursive(:s, @db[:t].with(:t, @ds), @db[:t2].with(:t2, @ds)).select_order_map(:id).should == [1,1,2,2,3,3,4,4,5,5,6,6]
488
+ end
489
+
490
+ specify "should support using a CTE inside UNION/EXCEPT/INTERSECT" do
491
+ @ds.union(@db[:t].with(:t, @ds)).select_order_map(:id).should == [1,2,3,4,5,6]
492
+ if @ds.supports_intersect_except?
493
+ @ds.intersect(@db[:t].with(:t, @ds)).select_order_map(:id).should == [1,2,3,4,5,6]
494
+ @ds.except(@db[:t].with(:t, @ds)).select_order_map(:id).should == []
495
+ end
496
+ end
497
+ end
498
+ end
499
+
500
+ if INTEGRATION_DB.dataset.supports_cte?(:update) # Assume INSERT and DELETE support as well
501
+ describe "Common Table Expressions in INSERT/UPDATE/DELETE" do
502
+ before do
503
+ @db = INTEGRATION_DB
504
+ @db.create_table!(:i1){Integer :id}
505
+ @ds = @db[:i1]
506
+ @ds2 = @ds.with(:t, @ds)
507
+ @ds.insert(:id=>1)
508
+ @ds.insert(:id=>2)
509
+ end
510
+ after do
511
+ @db.drop_table(:i1)
512
+ end
513
+
514
+ specify "should give correct results for WITH" do
515
+ @ds2.insert(@db[:t])
516
+ @ds.select_order_map(:id).should == [1, 1, 2, 2]
517
+ @ds2.filter(:id=>@db[:t].select{max(id)}).update(:id=>:id+1)
518
+ @ds.select_order_map(:id).should == [1, 1, 3, 3]
519
+ @ds2.filter(:id=>@db[:t].select{max(id)}).delete
520
+ @ds.select_order_map(:id).should == [1, 1]
521
+ end
522
+ end
523
+ end
524
+
525
+ if INTEGRATION_DB.dataset.supports_returning?(:insert)
526
+ describe "RETURNING clauses in INSERT" do
527
+ before do
528
+ @db = INTEGRATION_DB
529
+ @db.create_table!(:i1){Integer :id; Integer :foo}
530
+ @ds = @db[:i1]
531
+ end
532
+ after do
533
+ @db.drop_table(:i1)
534
+ end
535
+
536
+ specify "should give correct results" do
537
+ h = {}
538
+ @ds.returning(:foo).insert(1, 2){|r| h = r}
539
+ h.should == {:foo=>2}
540
+ @ds.returning(:id).insert(3, 4){|r| h = r}
541
+ h.should == {:id=>3}
542
+ @ds.returning.insert(5, 6){|r| h = r}
543
+ h.should == {:id=>5, :foo=>6}
544
+ @ds.returning(:id___foo, :foo___id).insert(7, 8){|r| h = r}
545
+ h.should == {:id=>8, :foo=>7}
546
+ end
547
+ end
548
+ end
549
+
550
+ if INTEGRATION_DB.dataset.supports_returning?(:update) # Assume DELETE support as well
551
+ describe "RETURNING clauses in UPDATE/DELETE" do
552
+ before do
553
+ @db = INTEGRATION_DB
554
+ @db.create_table!(:i1){Integer :id; Integer :foo}
555
+ @ds = @db[:i1]
556
+ @ds.insert(1, 2)
557
+ end
558
+ after do
559
+ @db.drop_table(:i1)
560
+ end
561
+
562
+ specify "should give correct results" do
563
+ h = []
564
+ @ds.returning(:foo).update(:id=>:id+1, :foo=>:foo*2){|r| h << r}
565
+ h.should == [{:foo=>4}]
566
+ h.clear
567
+ @ds.returning(:id).update(:id=>:id+1, :foo=>:foo*2){|r| h << r}
568
+ h.should == [{:id=>3}]
569
+ h.clear
570
+ @ds.returning.update(:id=>:id+1, :foo=>:foo*2){|r| h << r}
571
+ h.should == [{:id=>4, :foo=>16}]
572
+ h.clear
573
+ @ds.returning(:id___foo, :foo___id).update(:id=>:id+1, :foo=>:foo*2){|r| h << r}
574
+ h.should == [{:id=>32, :foo=>5}]
575
+ h.clear
576
+
577
+ @ds.returning.delete{|r| h << r}
578
+ h.should == [{:id=>5, :foo=>32}]
579
+ h.clear
580
+ @ds.returning.delete{|r| h << r}
581
+ h.should == []
582
+ end
394
583
  end
395
584
  end
396
585
 
397
586
  if INTEGRATION_DB.dataset.supports_window_functions?
398
587
  describe "Window Functions" do
399
- before do
588
+ before(:all) do
400
589
  @db = INTEGRATION_DB
401
590
  @db.create_table!(:i1){Integer :id; Integer :group_id; Integer :amount}
402
591
  @ds = @db[:i1].order(:id)
@@ -407,7 +596,7 @@ if INTEGRATION_DB.dataset.supports_window_functions?
407
596
  @ds.insert(:id=>5, :group_id=>2, :amount=>10000)
408
597
  @ds.insert(:id=>6, :group_id=>2, :amount=>100000)
409
598
  end
410
- after do
599
+ after(:all) do
411
600
  @db.drop_table(:i1)
412
601
  end
413
602
 
@@ -435,21 +624,13 @@ if INTEGRATION_DB.dataset.supports_window_functions?
435
624
  cspecify "should give correct results for aggregate window functions with frames", :mssql do
436
625
  @ds.select(:id){sum(:over, :args=>amount, :partition=>group_id, :order=>id, :frame=>:all){}.as(:sum)}.all.should ==
437
626
  [{:sum=>111, :id=>1}, {:sum=>111, :id=>2}, {:sum=>111, :id=>3}, {:sum=>111000, :id=>4}, {:sum=>111000, :id=>5}, {:sum=>111000, :id=>6}]
438
- @ds.select(:id){sum(:over, :args=>amount, :partition=>group_id, :frame=>:all){}.as(:sum)}.all.should ==
439
- [{:sum=>111, :id=>1}, {:sum=>111, :id=>2}, {:sum=>111, :id=>3}, {:sum=>111000, :id=>4}, {:sum=>111000, :id=>5}, {:sum=>111000, :id=>6}]
440
627
  @ds.select(:id){sum(:over, :args=>amount, :order=>id, :frame=>:all){}.as(:sum)}.all.should ==
441
628
  [{:sum=>111111, :id=>1}, {:sum=>111111, :id=>2}, {:sum=>111111, :id=>3}, {:sum=>111111, :id=>4}, {:sum=>111111, :id=>5}, {:sum=>111111, :id=>6}]
442
- @ds.select(:id){sum(:over, :args=>amount, :frame=>:all){}.as(:sum)}.all.should ==
443
- [{:sum=>111111, :id=>1}, {:sum=>111111, :id=>2}, {:sum=>111111, :id=>3}, {:sum=>111111, :id=>4}, {:sum=>111111, :id=>5}, {:sum=>111111, :id=>6}]
444
629
 
445
630
  @ds.select(:id){sum(:over, :args=>amount, :partition=>group_id, :order=>id, :frame=>:rows){}.as(:sum)}.all.should ==
446
631
  [{:sum=>1, :id=>1}, {:sum=>11, :id=>2}, {:sum=>111, :id=>3}, {:sum=>1000, :id=>4}, {:sum=>11000, :id=>5}, {:sum=>111000, :id=>6}]
447
- @ds.select(:id){sum(:over, :args=>amount, :partition=>group_id, :frame=>:rows){}.as(:sum)}.all.should ==
448
- [{:sum=>1, :id=>1}, {:sum=>11, :id=>2}, {:sum=>111, :id=>3}, {:sum=>1000, :id=>4}, {:sum=>11000, :id=>5}, {:sum=>111000, :id=>6}]
449
632
  @ds.select(:id){sum(:over, :args=>amount, :order=>id, :frame=>:rows){}.as(:sum)}.all.should ==
450
633
  [{:sum=>1, :id=>1}, {:sum=>11, :id=>2}, {:sum=>111, :id=>3}, {:sum=>1111, :id=>4}, {:sum=>11111, :id=>5}, {:sum=>111111, :id=>6}]
451
- @ds.select(:id){sum(:over, :args=>amount, :frame=>:rows){}.as(:sum)}.all.should ==
452
- [{:sum=>1, :id=>1}, {:sum=>11, :id=>2}, {:sum=>111, :id=>3}, {:sum=>1111, :id=>4}, {:sum=>11111, :id=>5}, {:sum=>111111, :id=>6}]
453
634
  end
454
635
  end
455
636
  end
@@ -471,10 +652,10 @@ describe Sequel::SQL::Constants do
471
652
  @c2 = proc{|v| v.is_a?(Date) ? v : Date.parse(v) }
472
653
  end
473
654
  after do
474
- @db.drop_table(:constants)
655
+ @db.drop_table(:constants) if @db.table_exists?(:constants)
475
656
  end
476
657
 
477
- cspecify "should have working CURRENT_DATE", [:odbc, :mssql], [:jdbc, :sqlite] do
658
+ cspecify "should have working CURRENT_DATE", [:odbc, :mssql], [:jdbc, :sqlite], :oracle do
478
659
  @db.create_table!(:constants){Date :d}
479
660
  @ds.insert(:d=>Sequel::CURRENT_DATE)
480
661
  d = @c2[@ds.get(:d)]
@@ -485,26 +666,33 @@ describe Sequel::SQL::Constants do
485
666
  cspecify "should have working CURRENT_TIME", [:do, :mysql], [:jdbc, :sqlite], [:mysql2] do
486
667
  @db.create_table!(:constants){Time :t, :only_time=>true}
487
668
  @ds.insert(:t=>Sequel::CURRENT_TIME)
488
- (Time.now - @c[@ds.get(:t)]).should be_within(1).of(0)
669
+ (Time.now - @c[@ds.get(:t)]).should be_within(2).of(0)
489
670
  end
490
671
 
491
672
  cspecify "should have working CURRENT_TIMESTAMP", [:jdbc, :sqlite] do
492
673
  @db.create_table!(:constants){DateTime :ts}
493
674
  @ds.insert(:ts=>Sequel::CURRENT_TIMESTAMP)
494
- (Time.now - @c[@ds.get(:ts)]).should be_within(1).of(0)
675
+ (Time.now - @c[@ds.get(:ts)]).should be_within(2).of(0)
676
+ end
677
+
678
+ cspecify "should have working CURRENT_TIMESTAMP when used as a column default", [:jdbc, :sqlite] do
679
+ @db.create_table!(:constants){DateTime :ts, :default=>Sequel::CURRENT_TIMESTAMP}
680
+ @ds.insert
681
+ (Time.now - @c[@ds.get(:ts)]).should be_within(2).of(0)
495
682
  end
496
683
  end
497
684
 
498
685
  describe "Sequel::Dataset#import and #multi_insert" do
499
- before do
686
+ before(:all) do
500
687
  @db = INTEGRATION_DB
501
688
  @db.create_table!(:imp){Integer :i}
502
- @db.create_table!(:exp2){Integer :i}
503
689
  @ids = @db[:imp].order(:i)
504
- @eds = @db[:exp2]
505
690
  end
506
- after do
507
- @db.drop_table(:imp, :exp2)
691
+ before do
692
+ @ids.delete
693
+ end
694
+ after(:all) do
695
+ @db.drop_table(:imp)
508
696
  end
509
697
 
510
698
  it "should import with multi_insert and an array of hashes" do
@@ -518,9 +706,11 @@ describe "Sequel::Dataset#import and #multi_insert" do
518
706
  end
519
707
 
520
708
  it "should import with a dataset" do
521
- @eds.import([:i], [[10], [20]])
522
- @ids.import([:i], @eds)
709
+ @db.create_table!(:exp2){Integer :i}
710
+ @db[:exp2].import([:i], [[10], [20]])
711
+ @ids.import([:i], @db[:exp2])
523
712
  @ids.all.should == [{:i=>10}, {:i=>20}]
713
+ @db.drop_table(:exp2)
524
714
  end
525
715
 
526
716
  it "should have import work with the :slice_size option" do
@@ -535,13 +725,65 @@ describe "Sequel::Dataset#import and #multi_insert" do
535
725
  end
536
726
  end
537
727
 
538
- describe "Sequel::Dataset convenience methods" do
728
+ describe "Sequel::Dataset#import and #multi_insert :return=>:primary_key " do
539
729
  before do
730
+ @db = INTEGRATION_DB
731
+ @db.create_table!(:imp){primary_key :id; Integer :i}
732
+ @ds = @db[:imp]
733
+ end
734
+ after do
735
+ @db.drop_table(:imp)
736
+ end
737
+
738
+ specify "should return primary key values " do
739
+ @ds.multi_insert([{:i=>10}, {:i=>20}, {:i=>30}], :return=>:primary_key).should == [1, 2, 3]
740
+ @ds.import([:i], [[40], [50], [60]], :return=>:primary_key).should == [4, 5, 6]
741
+ @ds.order(:id).map([:id, :i]).should == [[1, 10], [2, 20], [3, 30], [4, 40], [5, 50], [6, 60]]
742
+ end
743
+
744
+ specify "should return primary key values when :slice is used" do
745
+ @ds.multi_insert([{:i=>10}, {:i=>20}, {:i=>30}], :return=>:primary_key, :slice=>2).should == [1, 2, 3]
746
+ @ds.import([:i], [[40], [50], [60]], :return=>:primary_key, :slice=>2).should == [4, 5, 6]
747
+ @ds.order(:id).map([:id, :i]).should == [[1, 10], [2, 20], [3, 30], [4, 40], [5, 50], [6, 60]]
748
+ end
749
+ end
750
+
751
+ describe "Sequel::Dataset convenience methods" do
752
+ before(:all) do
753
+ @db = INTEGRATION_DB
754
+ @db.create_table!(:a){Integer :a; Integer :b; Integer :c}
755
+ @ds = @db[:a]
756
+ @ds.insert(1, 3, 5)
757
+ @ds.insert(1, 3, 6)
758
+ @ds.insert(1, 4, 5)
759
+ @ds.insert(2, 3, 5)
760
+ @ds.insert(2, 4, 6)
761
+ end
762
+ after(:all) do
763
+ @db.drop_table(:a)
764
+ end
765
+
766
+ it "#group_rollup should include hierarchy of groupings" do
767
+ @ds.group_by(:a).group_rollup.select_map([:a, :sum.sql_function(:b).cast(Integer).as(:b), :sum.sql_function(:c).cast(Integer).as(:c)]).sort_by{|x| x.inspect}.should == [[1, 10, 16], [2, 7, 11], [nil, 17, 27]]
768
+ @ds.group_by(:a, :b).group_rollup.select_map([:a, :b, :sum.sql_function(:c).cast(Integer).as(:c)]).sort_by{|x| x.inspect}.should == [[1, 3, 11], [1, 4, 5], [1, nil, 16], [2, 3, 5], [2, 4, 6], [2, nil, 11], [nil, nil, 27]]
769
+ end if INTEGRATION_DB.dataset.supports_group_rollup?
770
+
771
+ it "#group_cube should include all combinations of groupings" do
772
+ @ds.group_by(:a).group_cube.select_map([:a, :sum.sql_function(:b).cast(Integer).as(:b), :sum.sql_function(:c).cast(Integer).as(:c)]).sort_by{|x| x.inspect}.should == [[1, 10, 16], [2, 7, 11], [nil, 17, 27]]
773
+ @ds.group_by(:a, :b).group_cube.select_map([:a, :b, :sum.sql_function(:c).cast(Integer).as(:c)]).sort_by{|x| x.inspect}.should == [[1, 3, 11], [1, 4, 5], [1, nil, 16], [2, 3, 5], [2, 4, 6], [2, nil, 11], [nil, 3, 16], [nil, 4, 11], [nil, nil, 27]]
774
+ end if INTEGRATION_DB.dataset.supports_group_cube?
775
+ end
776
+
777
+ describe "Sequel::Dataset convenience methods" do
778
+ before(:all) do
540
779
  @db = INTEGRATION_DB
541
780
  @db.create_table!(:a){Integer :a; Integer :b}
542
781
  @ds = @db[:a].order(:a)
543
782
  end
544
- after do
783
+ before do
784
+ @ds.delete
785
+ end
786
+ after(:all) do
545
787
  @db.drop_table(:a)
546
788
  end
547
789
 
@@ -557,6 +799,22 @@ describe "Sequel::Dataset convenience methods" do
557
799
  @ds.empty?.should == false
558
800
  end
559
801
 
802
+ it "#empty? should work correctly for datasets with limits" do
803
+ ds = @ds.limit(1)
804
+ ds.empty?.should == true
805
+ ds.insert(20, 10)
806
+ ds.empty?.should == false
807
+ end
808
+
809
+ it "#empty? should work correctly for datasets with limits and offsets" do
810
+ ds = @ds.limit(1, 1)
811
+ ds.empty?.should == true
812
+ ds.insert(20, 10)
813
+ ds.empty?.should == true
814
+ ds.insert(20, 10)
815
+ ds.empty?.should == false
816
+ end
817
+
560
818
  it "#group_and_count should return a grouping by count" do
561
819
  @ds.group_and_count(:a).order(:count).all.should == []
562
820
  @ds.insert(20, 10)
@@ -577,7 +835,7 @@ describe "Sequel::Dataset convenience methods" do
577
835
  @ds.group_and_count(:a___c).order(:count).all.each{|h| h[:count] = h[:count].to_i}.should == [{:c=>30, :count=>1}, {:c=>20, :count=>2}]
578
836
  end
579
837
 
580
- cspecify "#range should return the range between the maximum and minimum values", :sqlite do
838
+ specify "#range should return the range between the maximum and minimum values" do
581
839
  @ds = @ds.unordered
582
840
  @ds.insert(20, 10)
583
841
  @ds.insert(30, 10)
@@ -595,12 +853,15 @@ describe "Sequel::Dataset convenience methods" do
595
853
  end
596
854
 
597
855
  describe "Sequel::Dataset main SQL methods" do
598
- before do
856
+ before(:all) do
599
857
  @db = INTEGRATION_DB
600
858
  @db.create_table!(:a){Integer :a; Integer :b}
601
859
  @ds = @db[:a].order(:a)
602
860
  end
603
- after do
861
+ before do
862
+ @ds.delete
863
+ end
864
+ after(:all) do
604
865
  @db.drop_table(:a)
605
866
  end
606
867
 
@@ -625,6 +886,23 @@ describe "Sequel::Dataset main SQL methods" do
625
886
  @ds.filter(:a=>20).or(:b=>15).all.should == [{:a=>20, :b=>30}]
626
887
  @ds.filter(:a=>10).or(:b=>15).all.should == []
627
888
  end
889
+
890
+ it "#select_group should work correctly" do
891
+ @ds.unordered!
892
+ @ds.select_group(:a).all.should == []
893
+ @ds.insert(20, 30)
894
+ @ds.select_group(:a).all.should == [{:a=>20}]
895
+ @ds.select_group(:b).all.should == [{:b=>30}]
896
+ @ds.insert(20, 40)
897
+ @ds.select_group(:a).all.should == [{:a=>20}]
898
+ @ds.order(:b).select_group(:b).all.should == [{:b=>30}, {:b=>40}]
899
+ end
900
+
901
+ it "#select_group should work correctly when aliasing" do
902
+ @ds.unordered!
903
+ @ds.insert(20, 30)
904
+ @ds.select_group(:b___c).all.should == [{:c=>30}]
905
+ end
628
906
 
629
907
  it "#having should work correctly" do
630
908
  @ds.unordered!
@@ -645,13 +923,92 @@ describe "Sequel::Dataset main SQL methods" do
645
923
  end
646
924
  end
647
925
 
648
- describe "Sequel::Dataset DSL support" do
926
+ describe "Sequel::Dataset convenience methods" do
927
+ before(:all) do
928
+ @db = INTEGRATION_DB
929
+ @db.create_table!(:a){Integer :a; Integer :b; Integer :c; Integer :d}
930
+ @ds = @db[:a].order(:a)
931
+ end
649
932
  before do
933
+ @ds.delete
934
+ @ds.insert(1, 2, 3, 4)
935
+ @ds.insert(5, 6, 7, 8)
936
+ end
937
+ after(:all) do
938
+ @db.drop_table(:a)
939
+ end
940
+
941
+ specify "should have working #map" do
942
+ @ds.map(:a).should == [1, 5]
943
+ @ds.map(:b).should == [2, 6]
944
+ @ds.map([:a, :b]).should == [[1, 2], [5, 6]]
945
+ end
946
+
947
+ specify "should have working #to_hash" do
948
+ @ds.to_hash(:a).should == {1=>{:a=>1, :b=>2, :c=>3, :d=>4}, 5=>{:a=>5, :b=>6, :c=>7, :d=>8}}
949
+ @ds.to_hash(:b).should == {2=>{:a=>1, :b=>2, :c=>3, :d=>4}, 6=>{:a=>5, :b=>6, :c=>7, :d=>8}}
950
+ @ds.to_hash([:a, :b]).should == {[1, 2]=>{:a=>1, :b=>2, :c=>3, :d=>4}, [5, 6]=>{:a=>5, :b=>6, :c=>7, :d=>8}}
951
+
952
+ @ds.to_hash(:a, :b).should == {1=>2, 5=>6}
953
+ @ds.to_hash([:a, :c], :b).should == {[1, 3]=>2, [5, 7]=>6}
954
+ @ds.to_hash(:a, [:b, :c]).should == {1=>[2, 3], 5=>[6, 7]}
955
+ @ds.to_hash([:a, :c], [:b, :d]).should == {[1, 3]=>[2, 4], [5, 7]=>[6, 8]}
956
+ end
957
+
958
+ specify "should have working #select_map" do
959
+ @ds.select_map(:a).should == [1, 5]
960
+ @ds.select_map(:b).should == [2, 6]
961
+ @ds.select_map([:a]).should == [[1], [5]]
962
+ @ds.select_map([:a, :b]).should == [[1, 2], [5, 6]]
963
+
964
+ @ds.select_map(:a___e).should == [1, 5]
965
+ @ds.select_map(:b___e).should == [2, 6]
966
+ @ds.select_map([:a___e, :b___f]).should == [[1, 2], [5, 6]]
967
+ @ds.select_map([:a__a___e, :a__b___f]).should == [[1, 2], [5, 6]]
968
+ @ds.select_map([:a__a.as(:e), :a__b.as(:f)]).should == [[1, 2], [5, 6]]
969
+ @ds.select_map([:a.qualify(:a).as(:e), :b.qualify(:a).as(:f)]).should == [[1, 2], [5, 6]]
970
+ @ds.select_map([:a.identifier.qualify(:a).as(:e), :b.qualify(:a).as(:f)]).should == [[1, 2], [5, 6]]
971
+ end
972
+
973
+ specify "should have working #select_order_map" do
974
+ @ds.select_order_map(:a).should == [1, 5]
975
+ @ds.select_order_map(:a__b.desc).should == [6, 2]
976
+ @ds.select_order_map(:a__b___e.desc).should == [6, 2]
977
+ @ds.select_order_map(:b.qualify(:a).as(:e)).should == [2, 6]
978
+ @ds.select_order_map([:a]).should == [[1], [5]]
979
+ @ds.select_order_map([:a.desc, :b]).should == [[5, 6], [1, 2]]
980
+
981
+ @ds.select_order_map(:a___e).should == [1, 5]
982
+ @ds.select_order_map(:b___e).should == [2, 6]
983
+ @ds.select_order_map([:a___e.desc, :b___f]).should == [[5, 6], [1, 2]]
984
+ @ds.select_order_map([:a__a___e.desc, :a__b___f]).should == [[5, 6], [1, 2]]
985
+ @ds.select_order_map([:a__a.desc, :a__b.as(:f)]).should == [[5, 6], [1, 2]]
986
+ @ds.select_order_map([:a.qualify(:a).desc, :b.qualify(:a).as(:f)]).should == [[5, 6], [1, 2]]
987
+ @ds.select_order_map([:a.identifier.qualify(:a).desc, :b.qualify(:a).as(:f)]).should == [[5, 6], [1, 2]]
988
+ end
989
+
990
+ specify "should have working #select_hash" do
991
+ @ds.select_hash(:a, :b).should == {1=>2, 5=>6}
992
+ @ds.select_hash(:a__a___e, :b).should == {1=>2, 5=>6}
993
+ @ds.select_hash(:a__a.as(:e), :b).should == {1=>2, 5=>6}
994
+ @ds.select_hash(:a.qualify(:a).as(:e), :b).should == {1=>2, 5=>6}
995
+ @ds.select_hash(:a.identifier.qualify(:a).as(:e), :b).should == {1=>2, 5=>6}
996
+ @ds.select_hash([:a, :c], :b).should == {[1, 3]=>2, [5, 7]=>6}
997
+ @ds.select_hash(:a, [:b, :c]).should == {1=>[2, 3], 5=>[6, 7]}
998
+ @ds.select_hash([:a, :c], [:b, :d]).should == {[1, 3]=>[2, 4], [5, 7]=>[6, 8]}
999
+ end
1000
+ end
1001
+
1002
+ describe "Sequel::Dataset DSL support" do
1003
+ before(:all) do
650
1004
  @db = INTEGRATION_DB
651
1005
  @db.create_table!(:a){Integer :a; Integer :b}
652
1006
  @ds = @db[:a].order(:a)
653
1007
  end
654
- after do
1008
+ before do
1009
+ @ds.delete
1010
+ end
1011
+ after(:all) do
655
1012
  @db.drop_table(:a)
656
1013
  end
657
1014
 
@@ -663,31 +1020,36 @@ describe "Sequel::Dataset DSL support" do
663
1020
  @ds.get{a / b}.to_i.should == 2
664
1021
  end
665
1022
 
666
- specify "should work with bitwise shift operators" do
1023
+ cspecify "should work with bitwise shift operators", :derby do
667
1024
  @ds.insert(3, 2)
668
1025
  @ds.get{a.sql_number << b}.to_i.should == 12
669
1026
  @ds.get{a.sql_number >> b}.to_i.should == 0
1027
+ @ds.get{a.sql_number << b << 1}.to_i.should == 24
670
1028
  @ds.delete
671
1029
  @ds.insert(3, 1)
672
1030
  @ds.get{a.sql_number << b}.to_i.should == 6
673
1031
  @ds.get{a.sql_number >> b}.to_i.should == 1
1032
+ @ds.get{a.sql_number >> b >> 1}.to_i.should == 0
674
1033
  end
675
1034
 
676
- specify "should work with bitwise AND and OR operators" do
1035
+ cspecify "should work with bitwise AND and OR operators", :derby do
677
1036
  @ds.insert(3, 5)
678
1037
  @ds.get{a.sql_number | b}.to_i.should == 7
679
1038
  @ds.get{a.sql_number & b}.to_i.should == 1
1039
+ @ds.get{a.sql_number | b | 8}.to_i.should == 15
1040
+ @ds.get{a.sql_number & b & 8}.to_i.should == 0
680
1041
  end
681
1042
 
682
- cspecify "should work with the bitwise compliment operator", :h2 do
1043
+ specify "should work with the bitwise compliment operator" do
683
1044
  @ds.insert(-3, 3)
684
1045
  @ds.get{~a.sql_number}.to_i.should == 2
685
1046
  @ds.get{~b.sql_number}.to_i.should == -4
686
1047
  end
687
1048
 
688
- cspecify "should work with the bitwise xor operator", :sqlite do
1049
+ cspecify "should work with the bitwise xor operator", :derby do
689
1050
  @ds.insert(3, 5)
690
1051
  @ds.get{a.sql_number ^ b}.to_i.should == 6
1052
+ @ds.get{a.sql_number ^ b ^ 1}.to_i.should == 7
691
1053
  end
692
1054
 
693
1055
  specify "should work with inequality operators" do
@@ -778,7 +1140,7 @@ describe "Sequel::Dataset DSL support" do
778
1140
  @ds.filter({15=>20}.case(0, :a) > 0).all.should == []
779
1141
  end
780
1142
 
781
- it "should work with multiple value arrays" do
1143
+ specify "should work with multiple value arrays" do
782
1144
  @ds.insert(20, 10)
783
1145
  @ds.quote_identifiers = false
784
1146
  @ds.filter([:a, :b]=>[[20, 10]].sql_array).all.should == [{:a=>20, :b=>10}]
@@ -822,11 +1184,42 @@ describe "Sequel::Dataset DSL support" do
822
1184
  specify "should work empty arrays with nulls" do
823
1185
  @ds.insert(nil, nil)
824
1186
  @ds.filter(:a=>[]).all.should == []
825
- @ds.exclude(:a=>[]).all.should == [{:a=>nil, :b=>nil}]
1187
+ @ds.exclude(:a=>[]).all.should == []
826
1188
  @ds.filter([:a, :b]=>[]).all.should == []
827
- @ds.exclude([:a, :b]=>[]).all.should == [{:a=>nil, :b=>nil}]
1189
+ @ds.exclude([:a, :b]=>[]).all.should == []
1190
+
1191
+ unless Sequel.guarded?(:mssql, :oracle, :db2)
1192
+ # MSSQL doesn't like boolean results in the select list
1193
+ pr = proc{|r| r.is_a?(Integer) ? (r != 0) : r}
1194
+ pr[@ds.get({:a=>[]}.sql_expr)].should == nil
1195
+ pr[@ds.get(~({:a=>[]}).sql_expr)].should == nil
1196
+ pr[@ds.get({[:a, :b]=>[]}.sql_expr)].should == nil
1197
+ pr[@ds.get(~({[:a, :b]=>[]}).sql_expr)].should == nil
1198
+ end
828
1199
  end
829
1200
 
1201
+ specify "should work empty arrays with nulls and Sequel.empty_array_null_handling = true" do
1202
+ begin
1203
+ Sequel.empty_array_handle_nulls = false
1204
+ @ds.insert(nil, nil)
1205
+ @ds.filter(:a=>[]).all.should == []
1206
+ @ds.exclude(:a=>[]).all.should == [{:a=>nil, :b=>nil}]
1207
+ @ds.filter([:a, :b]=>[]).all.should == []
1208
+ @ds.exclude([:a, :b]=>[]).all.should == [{:a=>nil, :b=>nil}]
1209
+
1210
+ unless Sequel.guarded?(:mssql, :oracle, :db2)
1211
+ # MSSQL doesn't like boolean results in the select list
1212
+ pr = proc{|r| r.is_a?(Integer) ? (r != 0) : r}
1213
+ pr[@ds.get({:a=>[]}.sql_expr)].should == false
1214
+ pr[@ds.get(~({:a=>[]}).sql_expr)].should == true
1215
+ pr[@ds.get({[:a, :b]=>[]}.sql_expr)].should == false
1216
+ pr[@ds.get(~({[:a, :b]=>[]}).sql_expr)].should == true
1217
+ end
1218
+ ensure
1219
+ Sequel.empty_array_handle_nulls = true
1220
+ end
1221
+ end
1222
+
830
1223
  it "should work multiple conditions" do
831
1224
  @ds.insert(20, 10)
832
1225
  @ds.filter(:a=>20, :b=>10).all.should == [{:a=>20, :b=>10}]
@@ -847,22 +1240,36 @@ describe "SQL Extract Function" do
847
1240
  @db.drop_table(:a)
848
1241
  end
849
1242
 
850
- cspecify "should return the part of the datetime asked for", :sqlite, :mssql do
1243
+ specify "should return the part of the datetime asked for" do
851
1244
  t = Time.now
1245
+ def @ds.supports_timestamp_timezones?() false end
852
1246
  @ds.insert(t)
853
1247
  @ds.get{a.extract(:year)}.should == t.year
854
1248
  @ds.get{a.extract(:month)}.should == t.month
855
1249
  @ds.get{a.extract(:day)}.should == t.day
1250
+ @ds.get{a.extract(:hour)}.should == t.hour
1251
+ @ds.get{a.extract(:minute)}.should == t.min
1252
+ @ds.get{a.extract(:second)}.to_i.should == t.sec
856
1253
  end
857
1254
  end
858
1255
 
859
1256
  describe "Dataset string methods" do
860
- before do
1257
+ before(:all) do
861
1258
  @db = INTEGRATION_DB
862
- @db.create_table!(:a){String :a; String :b}
1259
+ csc = {}
1260
+ cic = {}
1261
+ csc[:collate] = @db.dataset_class::CASE_SENSITIVE_COLLATION if defined? @db.dataset_class::CASE_SENSITIVE_COLLATION
1262
+ cic[:collate] = @db.dataset_class::CASE_INSENSITIVE_COLLATION if defined? @db.dataset_class::CASE_INSENSITIVE_COLLATION
1263
+ @db.create_table!(:a) do
1264
+ String :a, csc
1265
+ String :b, cic
1266
+ end
863
1267
  @ds = @db[:a].order(:a)
864
1268
  end
865
- after do
1269
+ before do
1270
+ @ds.delete
1271
+ end
1272
+ after(:all) do
866
1273
  @db.drop_table(:a)
867
1274
  end
868
1275
 
@@ -877,15 +1284,15 @@ describe "Dataset string methods" do
877
1284
  end
878
1285
 
879
1286
  it "#grep should work with :all_patterns and :all_columns options" do
880
- @ds.insert('foo bar', '')
1287
+ @ds.insert('foo bar', ' ')
881
1288
  @ds.insert('foo d', 'bar')
882
- @ds.insert('foo e', '')
883
- @ds.insert('', 'bar')
1289
+ @ds.insert('foo e', ' ')
1290
+ @ds.insert(' ', 'bar')
884
1291
  @ds.insert('foo f', 'baz')
885
1292
  @ds.insert('foo baz', 'bar baz')
886
1293
  @ds.insert('foo boo', 'boo foo')
887
1294
 
888
- @ds.grep([:a, :b], %w'%foo% %bar%', :all_patterns=>true).all.should == [{:a=>'foo bar', :b=>''}, {:a=>'foo baz', :b=>'bar baz'}, {:a=>'foo d', :b=>'bar'}]
1295
+ @ds.grep([:a, :b], %w'%foo% %bar%', :all_patterns=>true).all.should == [{:a=>'foo bar', :b=>' '}, {:a=>'foo baz', :b=>'bar baz'}, {:a=>'foo d', :b=>'bar'}]
889
1296
  @ds.grep([:a, :b], %w'%foo% %bar% %blob%', :all_patterns=>true).all.should == []
890
1297
 
891
1298
  @ds.grep([:a, :b], %w'%bar% %foo%', :all_columns=>true).all.should == [{:a=>"foo baz", :b=>"bar baz"}, {:a=>"foo boo", :b=>"boo foo"}, {:a=>"foo d", :b=>"bar"}]
@@ -900,6 +1307,19 @@ describe "Dataset string methods" do
900
1307
  @ds.filter(:a.like('foo')).all.should == [{:a=>'foo', :b=>'bar'}]
901
1308
  @ds.filter(:a.like('bar')).all.should == []
902
1309
  @ds.filter(:a.like('foo', 'bar')).all.should == [{:a=>'foo', :b=>'bar'}]
1310
+ @ds.exclude(:a.like('foo')).all.should == []
1311
+ @ds.exclude(:a.like('bar')).all.should == [{:a=>'foo', :b=>'bar'}]
1312
+ @ds.exclude(:a.like('foo', 'bar')).all.should == []
1313
+ end
1314
+
1315
+ it "#like should be case sensitive" do
1316
+ @ds.insert('foo', 'bar')
1317
+ @ds.filter(:a.like('Foo')).all.should == []
1318
+ @ds.filter(:b.like('baR')).all.should == []
1319
+ @ds.filter(:a.like('FOO', 'BAR')).all.should == []
1320
+ @ds.exclude(:a.like('Foo')).all.should == [{:a=>'foo', :b=>'bar'}]
1321
+ @ds.exclude(:a.like('baR')).all.should == [{:a=>'foo', :b=>'bar'}]
1322
+ @ds.exclude(:a.like('FOO', 'BAR')).all.should == [{:a=>'foo', :b=>'bar'}]
903
1323
  end
904
1324
 
905
1325
  it "#ilike should return matching rows, in a case insensitive manner" do
@@ -907,17 +1327,20 @@ describe "Dataset string methods" do
907
1327
  @ds.filter(:a.ilike('Foo')).all.should == [{:a=>'foo', :b=>'bar'}]
908
1328
  @ds.filter(:a.ilike('baR')).all.should == []
909
1329
  @ds.filter(:a.ilike('FOO', 'BAR')).all.should == [{:a=>'foo', :b=>'bar'}]
1330
+ @ds.exclude(:a.ilike('Foo')).all.should == []
1331
+ @ds.exclude(:a.ilike('baR')).all.should == [{:a=>'foo', :b=>'bar'}]
1332
+ @ds.exclude(:a.ilike('FOO', 'BAR')).all.should == []
910
1333
  end
911
1334
 
912
1335
  it "should work with strings created with sql_string_join" do
913
1336
  @ds.insert('foo', 'bar')
914
- @ds.get([:a, :b].sql_string_join).should == 'foobar'
915
- @ds.get([:a, :b].sql_string_join(' ')).should == 'foo bar'
1337
+ @ds.get([:a, "bar"].sql_string_join).should == 'foobar'
1338
+ @ds.get(["foo", :b].sql_string_join(' ')).should == 'foo bar'
916
1339
  end
917
1340
  end
918
1341
 
919
1342
  describe "Dataset identifier methods" do
920
- before do
1343
+ before(:all) do
921
1344
  class ::String
922
1345
  def uprev
923
1346
  upcase.reverse
@@ -925,10 +1348,12 @@ describe "Dataset identifier methods" do
925
1348
  end
926
1349
  @db = INTEGRATION_DB
927
1350
  @db.create_table!(:a){Integer :ab}
1351
+ @db[:a].insert(1)
1352
+ end
1353
+ before do
928
1354
  @ds = @db[:a].order(:ab)
929
- @ds.insert(1)
930
1355
  end
931
- after do
1356
+ after(:all) do
932
1357
  @db.drop_table(:a)
933
1358
  end
934
1359
 
@@ -939,6 +1364,11 @@ describe "Dataset identifier methods" do
939
1364
  @ds.first.should == {:BA=>1}
940
1365
  end
941
1366
 
1367
+ it "should work with a nil identifier_output_method" do
1368
+ @ds.identifier_output_method = nil
1369
+ [{:ab=>1}, {:AB=>1}].should include(@ds.first)
1370
+ end
1371
+
942
1372
  it "should work when not quoting identifiers" do
943
1373
  @ds.quote_identifiers = false
944
1374
  @ds.first.should == {:ab=>1}
@@ -946,12 +1376,15 @@ describe "Dataset identifier methods" do
946
1376
  end
947
1377
 
948
1378
  describe "Dataset defaults and overrides" do
949
- before do
1379
+ before(:all) do
950
1380
  @db = INTEGRATION_DB
951
1381
  @db.create_table!(:a){Integer :a}
952
1382
  @ds = @db[:a].order(:a)
953
1383
  end
954
- after do
1384
+ before do
1385
+ @ds.delete
1386
+ end
1387
+ after(:all) do
955
1388
  @db.drop_table(:a)
956
1389
  end
957
1390