sequel 3.21.0 → 3.31.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 (225) hide show
  1. data/CHANGELOG +485 -3
  2. data/README.rdoc +20 -6
  3. data/Rakefile +37 -19
  4. data/bin/sequel +1 -5
  5. data/doc/association_basics.rdoc +249 -43
  6. data/doc/dataset_basics.rdoc +4 -4
  7. data/doc/dataset_filtering.rdoc +8 -0
  8. data/doc/mass_assignment.rdoc +54 -0
  9. data/doc/migration.rdoc +15 -538
  10. data/doc/model_hooks.rdoc +72 -27
  11. data/doc/opening_databases.rdoc +89 -50
  12. data/doc/prepared_statements.rdoc +40 -13
  13. data/doc/reflection.rdoc +8 -2
  14. data/doc/release_notes/3.22.0.txt +39 -0
  15. data/doc/release_notes/3.23.0.txt +172 -0
  16. data/doc/release_notes/3.24.0.txt +420 -0
  17. data/doc/release_notes/3.25.0.txt +88 -0
  18. data/doc/release_notes/3.26.0.txt +88 -0
  19. data/doc/release_notes/3.27.0.txt +82 -0
  20. data/doc/release_notes/3.28.0.txt +304 -0
  21. data/doc/release_notes/3.29.0.txt +459 -0
  22. data/doc/release_notes/3.30.0.txt +135 -0
  23. data/doc/release_notes/3.31.0.txt +146 -0
  24. data/doc/schema_modification.rdoc +547 -0
  25. data/doc/sharding.rdoc +7 -1
  26. data/doc/testing.rdoc +129 -0
  27. data/doc/transactions.rdoc +137 -0
  28. data/doc/virtual_rows.rdoc +2 -2
  29. data/lib/sequel/adapters/ado/mssql.rb +18 -6
  30. data/lib/sequel/adapters/ado.rb +40 -18
  31. data/lib/sequel/adapters/amalgalite.rb +17 -9
  32. data/lib/sequel/adapters/db2.rb +175 -86
  33. data/lib/sequel/adapters/dbi.rb +15 -15
  34. data/lib/sequel/adapters/do/mysql.rb +5 -7
  35. data/lib/sequel/adapters/do/postgres.rb +0 -5
  36. data/lib/sequel/adapters/do/sqlite.rb +0 -5
  37. data/lib/sequel/adapters/do.rb +17 -36
  38. data/lib/sequel/adapters/firebird.rb +27 -208
  39. data/lib/sequel/adapters/ibmdb.rb +448 -0
  40. data/lib/sequel/adapters/informix.rb +6 -23
  41. data/lib/sequel/adapters/jdbc/as400.rb +16 -34
  42. data/lib/sequel/adapters/jdbc/db2.rb +45 -0
  43. data/lib/sequel/adapters/jdbc/derby.rb +247 -0
  44. data/lib/sequel/adapters/jdbc/firebird.rb +29 -0
  45. data/lib/sequel/adapters/jdbc/h2.rb +56 -29
  46. data/lib/sequel/adapters/jdbc/hsqldb.rb +170 -0
  47. data/lib/sequel/adapters/jdbc/informix.rb +26 -0
  48. data/lib/sequel/adapters/jdbc/jtds.rb +34 -0
  49. data/lib/sequel/adapters/jdbc/mssql.rb +3 -33
  50. data/lib/sequel/adapters/jdbc/mysql.rb +11 -11
  51. data/lib/sequel/adapters/jdbc/oracle.rb +81 -25
  52. data/lib/sequel/adapters/jdbc/postgresql.rb +9 -13
  53. data/lib/sequel/adapters/jdbc/sqlite.rb +2 -6
  54. data/lib/sequel/adapters/jdbc/sqlserver.rb +71 -0
  55. data/lib/sequel/adapters/jdbc/transactions.rb +83 -0
  56. data/lib/sequel/adapters/jdbc.rb +231 -78
  57. data/lib/sequel/adapters/mock.rb +335 -0
  58. data/lib/sequel/adapters/mysql.rb +82 -184
  59. data/lib/sequel/adapters/mysql2.rb +26 -25
  60. data/lib/sequel/adapters/odbc/db2.rb +17 -0
  61. data/lib/sequel/adapters/odbc/mssql.rb +1 -6
  62. data/lib/sequel/adapters/odbc.rb +28 -9
  63. data/lib/sequel/adapters/openbase.rb +3 -5
  64. data/lib/sequel/adapters/oracle.rb +351 -53
  65. data/lib/sequel/adapters/postgres.rb +194 -33
  66. data/lib/sequel/adapters/shared/access.rb +32 -9
  67. data/lib/sequel/adapters/shared/db2.rb +321 -0
  68. data/lib/sequel/adapters/shared/firebird.rb +221 -0
  69. data/lib/sequel/adapters/shared/informix.rb +53 -0
  70. data/lib/sequel/adapters/shared/mssql.rb +231 -106
  71. data/lib/sequel/adapters/shared/mysql.rb +181 -63
  72. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +149 -0
  73. data/lib/sequel/adapters/shared/oracle.rb +231 -41
  74. data/lib/sequel/adapters/shared/postgres.rb +214 -82
  75. data/lib/sequel/adapters/shared/progress.rb +4 -7
  76. data/lib/sequel/adapters/shared/sqlite.rb +201 -57
  77. data/lib/sequel/adapters/sqlite.rb +29 -21
  78. data/lib/sequel/adapters/swift/mysql.rb +12 -7
  79. data/lib/sequel/adapters/swift/postgres.rb +0 -5
  80. data/lib/sequel/adapters/swift/sqlite.rb +8 -6
  81. data/lib/sequel/adapters/swift.rb +5 -5
  82. data/lib/sequel/adapters/tinytds.rb +160 -19
  83. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +66 -0
  84. data/lib/sequel/adapters/utils/stored_procedures.rb +1 -11
  85. data/lib/sequel/ast_transformer.rb +190 -0
  86. data/lib/sequel/connection_pool/threaded.rb +3 -2
  87. data/lib/sequel/connection_pool.rb +1 -1
  88. data/lib/sequel/core.rb +46 -5
  89. data/lib/sequel/database/connecting.rb +5 -6
  90. data/lib/sequel/database/dataset.rb +4 -4
  91. data/lib/sequel/database/dataset_defaults.rb +59 -1
  92. data/lib/sequel/database/logging.rb +1 -1
  93. data/lib/sequel/database/misc.rb +104 -19
  94. data/lib/sequel/database/query.rb +153 -58
  95. data/lib/sequel/database/schema_generator.rb +17 -7
  96. data/lib/sequel/database/schema_methods.rb +59 -29
  97. data/lib/sequel/dataset/actions.rb +231 -76
  98. data/lib/sequel/dataset/features.rb +91 -8
  99. data/lib/sequel/dataset/graph.rb +38 -11
  100. data/lib/sequel/dataset/misc.rb +50 -23
  101. data/lib/sequel/dataset/mutation.rb +5 -6
  102. data/lib/sequel/dataset/prepared_statements.rb +48 -27
  103. data/lib/sequel/dataset/query.rb +236 -43
  104. data/lib/sequel/dataset/sql.rb +665 -253
  105. data/lib/sequel/dataset.rb +8 -0
  106. data/lib/sequel/exceptions.rb +4 -0
  107. data/lib/sequel/extensions/columns_introspection.rb +61 -0
  108. data/lib/sequel/extensions/migration.rb +6 -4
  109. data/lib/sequel/extensions/named_timezones.rb +5 -0
  110. data/lib/sequel/extensions/thread_local_timezones.rb +1 -1
  111. data/lib/sequel/extensions/to_dot.rb +95 -83
  112. data/lib/sequel/model/associations.rb +1020 -337
  113. data/lib/sequel/model/base.rb +414 -132
  114. data/lib/sequel/model/errors.rb +1 -1
  115. data/lib/sequel/model/exceptions.rb +5 -1
  116. data/lib/sequel/model.rb +15 -8
  117. data/lib/sequel/plugins/association_pks.rb +22 -4
  118. data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
  119. data/lib/sequel/plugins/dataset_associations.rb +100 -0
  120. data/lib/sequel/plugins/defaults_setter.rb +58 -0
  121. data/lib/sequel/plugins/force_encoding.rb +6 -6
  122. data/lib/sequel/plugins/identity_map.rb +114 -7
  123. data/lib/sequel/plugins/many_through_many.rb +65 -7
  124. data/lib/sequel/plugins/prepared_statements.rb +151 -0
  125. data/lib/sequel/plugins/prepared_statements_associations.rb +84 -0
  126. data/lib/sequel/plugins/prepared_statements_safe.rb +82 -0
  127. data/lib/sequel/plugins/prepared_statements_with_pk.rb +59 -0
  128. data/lib/sequel/plugins/rcte_tree.rb +29 -15
  129. data/lib/sequel/plugins/serialization.rb +88 -44
  130. data/lib/sequel/plugins/serialization_modification_detection.rb +51 -0
  131. data/lib/sequel/plugins/sharding.rb +21 -54
  132. data/lib/sequel/plugins/single_table_inheritance.rb +3 -1
  133. data/lib/sequel/plugins/typecast_on_load.rb +9 -12
  134. data/lib/sequel/plugins/update_primary_key.rb +2 -2
  135. data/lib/sequel/plugins/xml_serializer.rb +3 -3
  136. data/lib/sequel/sql.rb +109 -52
  137. data/lib/sequel/timezones.rb +57 -38
  138. data/lib/sequel/version.rb +1 -1
  139. data/spec/adapters/db2_spec.rb +146 -0
  140. data/spec/adapters/mssql_spec.rb +111 -29
  141. data/spec/adapters/mysql_spec.rb +135 -123
  142. data/spec/adapters/oracle_spec.rb +49 -77
  143. data/spec/adapters/postgres_spec.rb +267 -78
  144. data/spec/adapters/spec_helper.rb +6 -5
  145. data/spec/adapters/sqlite_spec.rb +35 -21
  146. data/spec/core/connection_pool_spec.rb +71 -92
  147. data/spec/core/core_sql_spec.rb +21 -30
  148. data/spec/core/database_spec.rb +788 -512
  149. data/spec/core/dataset_spec.rb +1073 -1053
  150. data/spec/core/expression_filters_spec.rb +159 -42
  151. data/spec/core/mock_adapter_spec.rb +419 -0
  152. data/spec/core/object_graph_spec.rb +86 -114
  153. data/spec/core/schema_generator_spec.rb +3 -3
  154. data/spec/core/schema_spec.rb +298 -38
  155. data/spec/core/spec_helper.rb +6 -48
  156. data/spec/extensions/association_autoreloading_spec.rb +1 -10
  157. data/spec/extensions/association_dependencies_spec.rb +2 -12
  158. data/spec/extensions/association_pks_spec.rb +66 -32
  159. data/spec/extensions/caching_spec.rb +23 -50
  160. data/spec/extensions/class_table_inheritance_spec.rb +31 -83
  161. data/spec/extensions/columns_introspection_spec.rb +91 -0
  162. data/spec/extensions/composition_spec.rb +18 -13
  163. data/spec/extensions/dataset_associations_spec.rb +199 -0
  164. data/spec/extensions/defaults_setter_spec.rb +64 -0
  165. data/spec/extensions/hook_class_methods_spec.rb +65 -91
  166. data/spec/extensions/identity_map_spec.rb +114 -22
  167. data/spec/extensions/instance_filters_spec.rb +11 -21
  168. data/spec/extensions/instance_hooks_spec.rb +53 -0
  169. data/spec/extensions/json_serializer_spec.rb +4 -5
  170. data/spec/extensions/lazy_attributes_spec.rb +16 -20
  171. data/spec/extensions/list_spec.rb +17 -39
  172. data/spec/extensions/many_through_many_spec.rb +283 -250
  173. data/spec/extensions/migration_spec.rb +35 -32
  174. data/spec/extensions/named_timezones_spec.rb +23 -3
  175. data/spec/extensions/nested_attributes_spec.rb +97 -88
  176. data/spec/extensions/optimistic_locking_spec.rb +9 -20
  177. data/spec/extensions/prepared_statements_associations_spec.rb +111 -0
  178. data/spec/extensions/prepared_statements_safe_spec.rb +61 -0
  179. data/spec/extensions/prepared_statements_spec.rb +53 -0
  180. data/spec/extensions/prepared_statements_with_pk_spec.rb +31 -0
  181. data/spec/extensions/pretty_table_spec.rb +1 -6
  182. data/spec/extensions/rcte_tree_spec.rb +41 -43
  183. data/spec/extensions/schema_dumper_spec.rb +5 -8
  184. data/spec/extensions/schema_spec.rb +13 -21
  185. data/spec/extensions/serialization_modification_detection_spec.rb +37 -0
  186. data/spec/extensions/serialization_spec.rb +72 -43
  187. data/spec/extensions/sharding_spec.rb +66 -140
  188. data/spec/extensions/single_table_inheritance_spec.rb +18 -29
  189. data/spec/extensions/spec_helper.rb +13 -61
  190. data/spec/extensions/sql_expr_spec.rb +20 -60
  191. data/spec/extensions/tactical_eager_loading_spec.rb +9 -19
  192. data/spec/extensions/thread_local_timezones_spec.rb +22 -2
  193. data/spec/extensions/timestamps_spec.rb +6 -6
  194. data/spec/extensions/to_dot_spec.rb +4 -7
  195. data/spec/extensions/touch_spec.rb +13 -14
  196. data/spec/extensions/tree_spec.rb +11 -26
  197. data/spec/extensions/typecast_on_load_spec.rb +1 -6
  198. data/spec/extensions/update_primary_key_spec.rb +30 -24
  199. data/spec/extensions/validation_class_methods_spec.rb +30 -51
  200. data/spec/extensions/validation_helpers_spec.rb +16 -35
  201. data/spec/extensions/xml_serializer_spec.rb +16 -4
  202. data/spec/integration/associations_test.rb +537 -21
  203. data/spec/integration/database_test.rb +4 -2
  204. data/spec/integration/dataset_test.rb +461 -65
  205. data/spec/integration/eager_loader_test.rb +19 -21
  206. data/spec/integration/model_test.rb +80 -1
  207. data/spec/integration/plugin_test.rb +304 -116
  208. data/spec/integration/prepared_statement_test.rb +212 -122
  209. data/spec/integration/schema_test.rb +161 -30
  210. data/spec/integration/spec_helper.rb +39 -30
  211. data/spec/integration/timezone_test.rb +38 -12
  212. data/spec/integration/transaction_test.rb +172 -5
  213. data/spec/integration/type_test.rb +17 -3
  214. data/spec/model/association_reflection_spec.rb +201 -7
  215. data/spec/model/associations_spec.rb +865 -662
  216. data/spec/model/base_spec.rb +275 -95
  217. data/spec/model/dataset_methods_spec.rb +7 -27
  218. data/spec/model/eager_loading_spec.rb +677 -676
  219. data/spec/model/hooks_spec.rb +309 -67
  220. data/spec/model/model_spec.rb +222 -168
  221. data/spec/model/plugins_spec.rb +24 -13
  222. data/spec/model/record_spec.rb +381 -218
  223. data/spec/model/spec_helper.rb +13 -71
  224. data/spec/model/validations_spec.rb +11 -0
  225. metadata +115 -73
@@ -0,0 +1,419 @@
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
+
3
+ describe "Sequel Mock Adapter" do
4
+ specify "should have an adapter method" do
5
+ db = Sequel.mock
6
+ db.should be_a_kind_of(Sequel::Mock::Database)
7
+ db.adapter_scheme.should == :mock
8
+ end
9
+
10
+ specify "should have constructor accept no arguments" do
11
+ Sequel::Mock::Database.new.should be_a_kind_of(Sequel::Mock::Database)
12
+ end
13
+
14
+ specify "should each not return any rows by default" do
15
+ called = false
16
+ Sequel.mock[:t].each{|r| called = true}
17
+ called.should be_false
18
+ end
19
+
20
+ specify "should return 0 for update and delete by default" do
21
+ Sequel.mock[:t].update(:a=>1).should == 0
22
+ Sequel.mock[:t].delete.should == 0
23
+ end
24
+
25
+ specify "should return nil for insert by default" do
26
+ Sequel.mock[:t].insert(:a=>1).should be_nil
27
+ end
28
+
29
+ specify "should be able to set the rows returned by each using :fetch option with a single hash" do
30
+ rs = []
31
+ db = Sequel.mock(:fetch=>{:a=>1})
32
+ db[:t].each{|r| rs << r}
33
+ rs.should == [{:a=>1}]
34
+ db[:t].each{|r| rs << r}
35
+ rs.should == [{:a=>1}, {:a=>1}]
36
+ db[:t].each{|r| r[:a] = 2; rs << r}
37
+ rs.should == [{:a=>1}, {:a=>1}, {:a=>2}]
38
+ db[:t].each{|r| rs << r}
39
+ rs.should == [{:a=>1}, {:a=>1}, {:a=>2}, {:a=>1}]
40
+ end
41
+
42
+ specify "should be able to set the rows returned by each using :fetch option with an array of hashes" do
43
+ rs = []
44
+ db = Sequel.mock(:fetch=>[{:a=>1}, {:a=>2}])
45
+ db[:t].each{|r| rs << r}
46
+ rs.should == [{:a=>1}, {:a=>2}]
47
+ db[:t].each{|r| rs << r}
48
+ rs.should == [{:a=>1}, {:a=>2}, {:a=>1}, {:a=>2}]
49
+ db[:t].each{|r| r[:a] += 2; rs << r}
50
+ rs.should == [{:a=>1}, {:a=>2}, {:a=>1}, {:a=>2}, {:a=>3}, {:a=>4}]
51
+ db[:t].each{|r| rs << r}
52
+ rs.should == [{:a=>1}, {:a=>2}, {:a=>1}, {:a=>2}, {:a=>3}, {:a=>4}, {:a=>1}, {:a=>2}]
53
+ end
54
+
55
+ specify "should be able to set the rows returned by each using :fetch option with an array or arrays of hashes" do
56
+ rs = []
57
+ db = Sequel.mock(:fetch=>[[{:a=>1}, {:a=>2}], [{:a=>3}, {:a=>4}]])
58
+ db[:t].each{|r| rs << r}
59
+ rs.should == [{:a=>1}, {:a=>2}]
60
+ db[:t].each{|r| rs << r}
61
+ rs.should == [{:a=>1}, {:a=>2}, {:a=>3}, {:a=>4}]
62
+ db[:t].each{|r| rs << r}
63
+ rs.should == [{:a=>1}, {:a=>2}, {:a=>3}, {:a=>4}]
64
+ end
65
+
66
+ specify "should be able to set the rows returned by each using :fetch option with a proc that takes sql" do
67
+ rs = []
68
+ db = Sequel.mock(:fetch=>proc{|sql| sql =~ /FROM t/ ? {:b=>1} : [{:a=>1}, {:a=>2}]})
69
+ db[:t].each{|r| rs << r}
70
+ rs.should == [{:b=>1}]
71
+ db[:b].each{|r| rs << r}
72
+ rs.should == [{:b=>1}, {:a=>1}, {:a=>2}]
73
+ db[:t].each{|r| r[:b] += 1; rs << r}
74
+ db[:b].each{|r| r[:a] += 2; rs << r}
75
+ rs.should == [{:b=>1}, {:a=>1}, {:a=>2}, {:b=>2}, {:a=>3}, {:a=>4}]
76
+ db[:t].each{|r| rs << r}
77
+ db[:b].each{|r| rs << r}
78
+ rs.should == [{:b=>1}, {:a=>1}, {:a=>2}, {:b=>2}, {:a=>3}, {:a=>4}, {:b=>1}, {:a=>1}, {:a=>2}]
79
+ end
80
+
81
+ specify "should have a fetch= method for setting rows returned by each after the fact" do
82
+ rs = []
83
+ db = Sequel.mock
84
+ db.fetch = {:a=>1}
85
+ db[:t].each{|r| rs << r}
86
+ rs.should == [{:a=>1}]
87
+ db[:t].each{|r| rs << r}
88
+ rs.should == [{:a=>1}] * 2
89
+ end
90
+
91
+ specify "should be able to set an exception to raise by setting the :fetch option to an exception class " do
92
+ db = Sequel.mock(:fetch=>ArgumentError)
93
+ proc{db[:t].all}.should raise_error(Sequel::DatabaseError)
94
+ begin
95
+ db[:t].all
96
+ rescue => e
97
+ end
98
+ e.should be_a_kind_of(Sequel::DatabaseError)
99
+ e.wrapped_exception.should be_a_kind_of(ArgumentError)
100
+ end
101
+
102
+ specify "should be able to set separate kinds of results for fetch using an array" do
103
+ rs = []
104
+ db = Sequel.mock(:fetch=>[{:a=>1}, [{:a=>2}, {:a=>3}], proc{|s| {:a=>4}}, proc{|s| }, nil, ArgumentError])
105
+ db[:t].each{|r| rs << r}
106
+ rs.should == [{:a=>1}]
107
+ db[:t].each{|r| rs << r}
108
+ rs.should == [{:a=>1}, {:a=>2}, {:a=>3}]
109
+ db[:t].each{|r| rs << r}
110
+ rs.should == [{:a=>1}, {:a=>2}, {:a=>3}, {:a=>4}]
111
+ db[:t].each{|r| rs << r}
112
+ rs.should == [{:a=>1}, {:a=>2}, {:a=>3}, {:a=>4}]
113
+ db[:t].each{|r| rs << r}
114
+ rs.should == [{:a=>1}, {:a=>2}, {:a=>3}, {:a=>4}]
115
+ proc{db[:t].all}.should raise_error(Sequel::DatabaseError)
116
+ end
117
+
118
+ specify "should be able to set the rows returned by each on a per dataset basis using _fetch" do
119
+ rs = []
120
+ db = Sequel.mock(:fetch=>{:a=>1})
121
+ ds = db[:t]
122
+ ds.each{|r| rs << r}
123
+ rs.should == [{:a=>1}]
124
+ ds._fetch = {:b=>2}
125
+ ds.each{|r| rs << r}
126
+ rs.should == [{:a=>1}, {:b=>2}]
127
+ end
128
+
129
+ specify "should raise Error if given an invalid object to fetch" do
130
+ proc{Sequel.mock(:fetch=>Class.new).get(1)}.should raise_error(Sequel::Error)
131
+ proc{Sequel.mock(:fetch=>Object.new).get(1)}.should raise_error(Sequel::Error)
132
+ end
133
+
134
+ specify "should be able to set the number of rows modified by update and delete using :numrows option as an integer" do
135
+ db = Sequel.mock(:numrows=>2)
136
+ db[:t].update(:a=>1).should == 2
137
+ db[:t].delete.should == 2
138
+ db[:t].update(:a=>1).should == 2
139
+ db[:t].delete.should == 2
140
+ end
141
+
142
+ specify "should be able to set the number of rows modified by update and delete using :numrows option as an array of integers" do
143
+ db = Sequel.mock(:numrows=>[2, 1])
144
+ db[:t].update(:a=>1).should == 2
145
+ db[:t].delete.should == 1
146
+ db[:t].update(:a=>1).should == 0
147
+ db[:t].delete.should == 0
148
+ end
149
+
150
+ specify "should be able to set the number of rows modified by update and delete using :numrows option as a proc" do
151
+ db = Sequel.mock(:numrows=>proc{|sql| sql =~ / t/ ? 2 : 1})
152
+ db[:t].update(:a=>1).should == 2
153
+ db[:t].delete.should == 2
154
+ db[:b].update(:a=>1).should == 1
155
+ db[:b].delete.should == 1
156
+ end
157
+
158
+ specify "should be able to set an exception to raise by setting the :numrows option to an exception class " do
159
+ db = Sequel.mock(:numrows=>ArgumentError)
160
+ proc{db[:t].update(:a=>1)}.should raise_error(Sequel::DatabaseError)
161
+ begin
162
+ db[:t].delete
163
+ rescue => e
164
+ end
165
+ e.should be_a_kind_of(Sequel::DatabaseError)
166
+ e.wrapped_exception.should be_a_kind_of(ArgumentError)
167
+ end
168
+
169
+ specify "should be able to set separate kinds of results for numrows using an array" do
170
+ db = Sequel.mock(:numrows=>[1, proc{|s| 2}, nil, ArgumentError])
171
+ db[:t].delete.should == 1
172
+ db[:t].update(:a=>1).should == 2
173
+ db[:t].delete.should == 0
174
+ proc{db[:t].delete}.should raise_error(Sequel::DatabaseError)
175
+ end
176
+
177
+ specify "should have a numrows= method to set the number of rows modified by update and delete after the fact" do
178
+ db = Sequel.mock
179
+ db.numrows = 2
180
+ db[:t].update(:a=>1).should == 2
181
+ db[:t].delete.should == 2
182
+ db[:t].update(:a=>1).should == 2
183
+ db[:t].delete.should == 2
184
+ end
185
+
186
+ specify "should be able to set the number of rows modified by update and delete on a per dataset basis" do
187
+ db = Sequel.mock(:numrows=>2)
188
+ ds = db[:t]
189
+ ds.update(:a=>1).should == 2
190
+ ds.delete.should == 2
191
+ ds.numrows = 3
192
+ ds.update(:a=>1).should == 3
193
+ ds.delete.should == 3
194
+ end
195
+
196
+ specify "should raise Error if given an invalid object for numrows or autoid" do
197
+ proc{Sequel.mock(:numrows=>Class.new)[:a].delete}.should raise_error(Sequel::Error)
198
+ proc{Sequel.mock(:numrows=>Object.new)[:a].delete}.should raise_error(Sequel::Error)
199
+ proc{Sequel.mock(:autoid=>Class.new)[:a].insert}.should raise_error(Sequel::Error)
200
+ proc{Sequel.mock(:autoid=>Object.new)[:a].insert}.should raise_error(Sequel::Error)
201
+ end
202
+
203
+ specify "should be able to set the autogenerated primary key returned by insert using :autoid option as an integer" do
204
+ db = Sequel.mock(:autoid=>1)
205
+ db[:t].insert(:a=>1).should == 1
206
+ db[:t].insert(:a=>1).should == 2
207
+ db[:t].insert(:a=>1).should == 3
208
+ end
209
+
210
+ specify "should be able to set the autogenerated primary key returned by insert using :autoid option as an array of integers" do
211
+ db = Sequel.mock(:autoid=>[1, 3, 5])
212
+ db[:t].insert(:a=>1).should == 1
213
+ db[:t].insert(:a=>1).should == 3
214
+ db[:t].insert(:a=>1).should == 5
215
+ db[:t].insert(:a=>1).should be_nil
216
+ end
217
+
218
+ specify "should be able to set the autogenerated primary key returned by insert using :autoid option as a proc" do
219
+ db = Sequel.mock(:autoid=>proc{|sql| sql =~ /INTO t / ? 2 : 1})
220
+ db[:t].insert(:a=>1).should == 2
221
+ db[:t].insert(:a=>1).should == 2
222
+ db[:b].insert(:a=>1).should == 1
223
+ db[:b].insert(:a=>1).should == 1
224
+ end
225
+
226
+ specify "should be able to set an exception to raise by setting the :autoid option to an exception class " do
227
+ db = Sequel.mock(:autoid=>ArgumentError)
228
+ proc{db[:t].insert(:a=>1)}.should raise_error(Sequel::DatabaseError)
229
+ begin
230
+ db[:t].insert
231
+ rescue => e
232
+ end
233
+ e.should be_a_kind_of(Sequel::DatabaseError)
234
+ e.wrapped_exception.should be_a_kind_of(ArgumentError)
235
+ end
236
+
237
+ specify "should be able to set separate kinds of results for autoid using an array" do
238
+ db = Sequel.mock(:autoid=>[1, proc{|s| 2}, nil, ArgumentError])
239
+ db[:t].insert.should == 1
240
+ db[:t].insert.should == 2
241
+ db[:t].insert.should == nil
242
+ proc{db[:t].insert}.should raise_error(Sequel::DatabaseError)
243
+ end
244
+
245
+ specify "should have an autoid= method to set the autogenerated primary key returned by insert after the fact" do
246
+ db = Sequel.mock
247
+ db.autoid = 1
248
+ db[:t].insert(:a=>1).should == 1
249
+ db[:t].insert(:a=>1).should == 2
250
+ db[:t].insert(:a=>1).should == 3
251
+ end
252
+
253
+ specify "should be able to set the autogenerated primary key returned by insert on a per dataset basis" do
254
+ db = Sequel.mock(:autoid=>1)
255
+ ds = db[:t]
256
+ ds.insert(:a=>1).should == 1
257
+ ds.autoid = 5
258
+ ds.insert(:a=>1).should == 5
259
+ ds.insert(:a=>1).should == 6
260
+ db[:t].insert(:a=>1).should == 2
261
+ end
262
+
263
+ specify "should be able to set the columns to set in the dataset as an array of symbols" do
264
+ db = Sequel.mock(:columns=>[:a, :b])
265
+ db[:t].columns.should == [:a, :b]
266
+ db.sqls.should == ["SELECT * FROM t LIMIT 1"]
267
+ ds = db[:t]
268
+ ds.all
269
+ db.sqls.should == ["SELECT * FROM t"]
270
+ ds.columns.should == [:a, :b]
271
+ db.sqls.should == []
272
+ db[:t].columns.should == [:a, :b]
273
+ end
274
+
275
+ specify "should be able to set the columns to set in the dataset as an array of arrays of symbols" do
276
+ db = Sequel.mock(:columns=>[[:a, :b], [:c, :d]])
277
+ db[:t].columns.should == [:a, :b]
278
+ db[:t].columns.should == [:c, :d]
279
+ end
280
+
281
+ specify "should be able to set the columns to set in the dataset as a proc" do
282
+ db = Sequel.mock(:columns=>proc{|sql| (sql =~ / t/) ? [:a, :b] : [:c, :d]})
283
+ db[:b].columns.should == [:c, :d]
284
+ db[:t].columns.should == [:a, :b]
285
+ end
286
+
287
+ specify "should have a columns= method to set the columns to set after the fact" do
288
+ db = Sequel.mock
289
+ db.columns = [[:a, :b], [:c, :d]]
290
+ db[:t].columns.should == [:a, :b]
291
+ db[:t].columns.should == [:c, :d]
292
+ end
293
+
294
+ specify "should raise Error if given an invalid columns" do
295
+ proc{Sequel.mock(:columns=>Object.new)[:a].columns}.should raise_error(Sequel::Error)
296
+ end
297
+
298
+ specify "should not quote identifiers by default" do
299
+ Sequel.mock.send(:quote_identifiers_default).should be_false
300
+ end
301
+
302
+ specify "should not have identifier input/output methods by default" do
303
+ Sequel.mock.send(:identifier_input_method_default).should be_nil
304
+ Sequel.mock.send(:identifier_output_method_default).should be_nil
305
+ end
306
+
307
+ specify "should keep a record of all executed SQL in #sqls" do
308
+ db = Sequel.mock
309
+ db[:t].all
310
+ db[:b].delete
311
+ db[:c].insert(:a=>1)
312
+ db[:d].update(:a=>1)
313
+ db.sqls.should == ['SELECT * FROM t', 'DELETE FROM b', 'INSERT INTO c (a) VALUES (1)', 'UPDATE d SET a = 1']
314
+ end
315
+
316
+ specify "should clear sqls on retrieval" do
317
+ db = Sequel.mock
318
+ db[:t].all
319
+ db.sqls.should == ['SELECT * FROM t']
320
+ db.sqls.should == []
321
+ end
322
+
323
+ specify "should also log SQL executed to the given loggers" do
324
+ a = []
325
+ def a.method_missing(m, *x) push(*x) end
326
+ db = Sequel.mock(:loggers=>[a])
327
+ db[:t].all
328
+ db[:b].delete
329
+ db[:c].insert(:a=>1)
330
+ db[:d].update(:a=>1)
331
+ a.should == ['SELECT * FROM t', 'DELETE FROM b', 'INSERT INTO c (a) VALUES (1)', 'UPDATE d SET a = 1']
332
+ end
333
+
334
+ specify "should correctly handle transactions" do
335
+ db = Sequel.mock
336
+ db.transaction{db[:a].all}
337
+ db.sqls.should == ['BEGIN', 'SELECT * FROM a', 'COMMIT']
338
+ db.transaction{db[:a].all; raise Sequel::Rollback}
339
+ db.sqls.should == ['BEGIN', 'SELECT * FROM a', 'ROLLBACK']
340
+ proc{db.transaction{db[:a].all; raise ArgumentError}}.should raise_error(ArgumentError)
341
+ db.sqls.should == ['BEGIN', 'SELECT * FROM a', 'ROLLBACK']
342
+ proc{db.transaction(:rollback=>:reraise){db[:a].all; raise Sequel::Rollback}}.should raise_error(Sequel::Rollback)
343
+ db.sqls.should == ['BEGIN', 'SELECT * FROM a', 'ROLLBACK']
344
+ db.transaction(:rollback=>:always){db[:a].all}
345
+ db.sqls.should == ['BEGIN', 'SELECT * FROM a', 'ROLLBACK']
346
+ db.transaction{db.transaction{db[:a].all; raise Sequel::Rollback}}
347
+ db.sqls.should == ['BEGIN', 'SELECT * FROM a', 'ROLLBACK']
348
+ db.transaction{db.transaction(:savepoint=>true){db[:a].all; raise Sequel::Rollback}}
349
+ db.sqls.should == ['BEGIN', 'SAVEPOINT autopoint_1', 'SELECT * FROM a', 'ROLLBACK TO SAVEPOINT autopoint_1', 'COMMIT']
350
+ db.transaction{db.transaction(:savepoint=>true){db[:a].all}; raise Sequel::Rollback}
351
+ db.sqls.should == ['BEGIN', 'SAVEPOINT autopoint_1', 'SELECT * FROM a', 'RELEASE SAVEPOINT autopoint_1', 'ROLLBACK']
352
+ end
353
+
354
+ specify "should correctly handle transactions when sharding" do
355
+ db = Sequel.mock(:servers=>{:test=>{}})
356
+ db.transaction{db.transaction(:server=>:test){db[:a].all; db[:t].server(:test).all}}
357
+ db.sqls.should == ['BEGIN', 'BEGIN -- test', 'SELECT * FROM a', 'SELECT * FROM t -- test', 'COMMIT -- test', 'COMMIT']
358
+ end
359
+
360
+ specify "should yield a mock connection object from synchronize" do
361
+ c = Sequel.mock.synchronize{|conn| conn}
362
+ c.should be_a_kind_of(Sequel::Mock::Connection)
363
+ end
364
+
365
+ specify "should deal correctly with sharding" do
366
+ db = Sequel.mock(:servers=>{:test=>{}})
367
+ c1 = db.synchronize{|conn| conn}
368
+ c2 = db.synchronize(:test){|conn| conn}
369
+ c1.server.should == :default
370
+ c2.server.should == :test
371
+ end
372
+
373
+ specify "should disconnect correctly" do
374
+ db = Sequel.mock
375
+ db.test_connection
376
+ proc{db.disconnect}.should_not raise_error
377
+ end
378
+
379
+ specify "should accept :extend option for extending the object with a module" do
380
+ Sequel.mock(:extend=>Module.new{def foo(v) v * 2 end}).foo(3).should == 6
381
+ end
382
+
383
+ specify "should accept :sqls option for where to store the SQL queries" do
384
+ a = []
385
+ Sequel.mock(:sqls=>a)[:t].all
386
+ a.should == ['SELECT * FROM t']
387
+ end
388
+
389
+ specify "should include :append option in SQL if it is given" do
390
+ db = Sequel.mock(:append=>'a')
391
+ db[:t].all
392
+ db.sqls.should == ['SELECT * FROM t -- a']
393
+ end
394
+
395
+ specify "should append :arguments option to execute to the SQL if present" do
396
+ db = Sequel.mock
397
+ db.execute('SELECT * FROM t', :arguments=>[1, 2])
398
+ db.sqls.should == ['SELECT * FROM t -- args: [1, 2]']
399
+ end
400
+
401
+ specify "should have Dataset#columns take columns to set and return self" do
402
+ db = Sequel.mock
403
+ ds = db[:t].columns(:id, :a, :b)
404
+ ds.should be_a_kind_of(Sequel::Mock::Dataset)
405
+ ds.columns.should == [:id, :a, :b]
406
+ end
407
+
408
+ specify "should be able to load dialects based on the database name" do
409
+ Sequel.mock(:host=>'access').select(Date.new(2011, 12, 13)).sql.should == 'SELECT #2011-12-13#'
410
+ Sequel.mock(:host=>'db2').select(1).sql.should == 'SELECT 1 FROM "SYSIBM"."SYSDUMMY1"'
411
+ Sequel.mock(:host=>'firebird')[:a].distinct.limit(1, 2).sql.should == 'SELECT DISTINCT FIRST 1 SKIP 2 * FROM a'
412
+ Sequel.mock(:host=>'informix')[:a].distinct.limit(1, 2).sql.should == 'SELECT SKIP 2 FIRST 1 DISTINCT * FROM a'
413
+ Sequel.mock(:host=>'mssql', :quote_identifiers=>true, :identifier_input_method=>:upcase)[:a].full_text_search(:b, 'c').sql.should == "SELECT * FROM [A] WHERE (CONTAINS ([B], 'c'))"
414
+ Sequel.mock(:host=>'mysql', :quote_identifiers=>true)[:a].full_text_search(:b, 'c').sql.should == "SELECT * FROM `a` WHERE (MATCH (`b`) AGAINST ('c'))"
415
+ Sequel.mock(:host=>'oracle', :quote_identifiers=>true)[:a].limit(1).sql.should == 'SELECT * FROM (SELECT * FROM "a") "t1" WHERE (ROWNUM <= 1)'
416
+ Sequel.mock(:host=>'postgres', :quote_identifiers=>true)[:a].full_text_search(:b, 'c').sql.should == "SELECT * FROM \"a\" WHERE (to_tsvector('simple', (COALESCE(\"b\", ''))) @@ to_tsquery('simple', 'c'))"
417
+ Sequel.mock(:host=>'sqlite', :quote_identifiers=>true)[:a___b].sql.should == "SELECT * FROM `a` AS 'b'"
418
+ end
419
+ end