colincasey-sequel 2.10.0 → 2.10.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (137) hide show
  1. data/CHANGELOG +7 -1
  2. data/doc/advanced_associations.rdoc +614 -0
  3. data/doc/cheat_sheet.rdoc +223 -0
  4. data/doc/dataset_filtering.rdoc +158 -0
  5. data/doc/prepared_statements.rdoc +104 -0
  6. data/doc/release_notes/1.0.txt +38 -0
  7. data/doc/release_notes/1.1.txt +143 -0
  8. data/doc/release_notes/1.3.txt +101 -0
  9. data/doc/release_notes/1.4.0.txt +53 -0
  10. data/doc/release_notes/1.5.0.txt +155 -0
  11. data/doc/release_notes/2.0.0.txt +298 -0
  12. data/doc/release_notes/2.1.0.txt +271 -0
  13. data/doc/release_notes/2.10.0.txt +328 -0
  14. data/doc/release_notes/2.2.0.txt +253 -0
  15. data/doc/release_notes/2.3.0.txt +88 -0
  16. data/doc/release_notes/2.4.0.txt +106 -0
  17. data/doc/release_notes/2.5.0.txt +137 -0
  18. data/doc/release_notes/2.6.0.txt +157 -0
  19. data/doc/release_notes/2.7.0.txt +166 -0
  20. data/doc/release_notes/2.8.0.txt +171 -0
  21. data/doc/release_notes/2.9.0.txt +97 -0
  22. data/doc/schema.rdoc +29 -0
  23. data/doc/sharding.rdoc +113 -0
  24. data/lib/sequel.rb +1 -0
  25. data/lib/sequel_core/adapters/ado.rb +89 -0
  26. data/lib/sequel_core/adapters/db2.rb +143 -0
  27. data/lib/sequel_core/adapters/dbi.rb +112 -0
  28. data/lib/sequel_core/adapters/do/mysql.rb +38 -0
  29. data/lib/sequel_core/adapters/do/postgres.rb +92 -0
  30. data/lib/sequel_core/adapters/do/sqlite.rb +31 -0
  31. data/lib/sequel_core/adapters/do.rb +205 -0
  32. data/lib/sequel_core/adapters/firebird.rb +298 -0
  33. data/lib/sequel_core/adapters/informix.rb +85 -0
  34. data/lib/sequel_core/adapters/jdbc/h2.rb +69 -0
  35. data/lib/sequel_core/adapters/jdbc/mysql.rb +66 -0
  36. data/lib/sequel_core/adapters/jdbc/oracle.rb +23 -0
  37. data/lib/sequel_core/adapters/jdbc/postgresql.rb +113 -0
  38. data/lib/sequel_core/adapters/jdbc/sqlite.rb +43 -0
  39. data/lib/sequel_core/adapters/jdbc.rb +491 -0
  40. data/lib/sequel_core/adapters/mysql.rb +369 -0
  41. data/lib/sequel_core/adapters/odbc.rb +174 -0
  42. data/lib/sequel_core/adapters/openbase.rb +68 -0
  43. data/lib/sequel_core/adapters/oracle.rb +107 -0
  44. data/lib/sequel_core/adapters/postgres.rb +456 -0
  45. data/lib/sequel_core/adapters/shared/ms_access.rb +110 -0
  46. data/lib/sequel_core/adapters/shared/mssql.rb +102 -0
  47. data/lib/sequel_core/adapters/shared/mysql.rb +325 -0
  48. data/lib/sequel_core/adapters/shared/oracle.rb +61 -0
  49. data/lib/sequel_core/adapters/shared/postgres.rb +715 -0
  50. data/lib/sequel_core/adapters/shared/progress.rb +31 -0
  51. data/lib/sequel_core/adapters/shared/sqlite.rb +265 -0
  52. data/lib/sequel_core/adapters/sqlite.rb +248 -0
  53. data/lib/sequel_core/connection_pool.rb +258 -0
  54. data/lib/sequel_core/core_ext.rb +217 -0
  55. data/lib/sequel_core/core_sql.rb +202 -0
  56. data/lib/sequel_core/database/schema.rb +164 -0
  57. data/lib/sequel_core/database.rb +691 -0
  58. data/lib/sequel_core/dataset/callback.rb +13 -0
  59. data/lib/sequel_core/dataset/convenience.rb +237 -0
  60. data/lib/sequel_core/dataset/pagination.rb +96 -0
  61. data/lib/sequel_core/dataset/prepared_statements.rb +220 -0
  62. data/lib/sequel_core/dataset/query.rb +41 -0
  63. data/lib/sequel_core/dataset/schema.rb +15 -0
  64. data/lib/sequel_core/dataset/sql.rb +1010 -0
  65. data/lib/sequel_core/dataset/stored_procedures.rb +75 -0
  66. data/lib/sequel_core/dataset/unsupported.rb +43 -0
  67. data/lib/sequel_core/dataset.rb +511 -0
  68. data/lib/sequel_core/deprecated.rb +26 -0
  69. data/lib/sequel_core/exceptions.rb +44 -0
  70. data/lib/sequel_core/migration.rb +212 -0
  71. data/lib/sequel_core/object_graph.rb +230 -0
  72. data/lib/sequel_core/pretty_table.rb +71 -0
  73. data/lib/sequel_core/schema/generator.rb +320 -0
  74. data/lib/sequel_core/schema/sql.rb +325 -0
  75. data/lib/sequel_core/schema.rb +2 -0
  76. data/lib/sequel_core/sql.rb +887 -0
  77. data/lib/sequel_core/version.rb +11 -0
  78. data/lib/sequel_core.rb +172 -0
  79. data/lib/sequel_model/association_reflection.rb +267 -0
  80. data/lib/sequel_model/associations.rb +499 -0
  81. data/lib/sequel_model/base.rb +523 -0
  82. data/lib/sequel_model/caching.rb +82 -0
  83. data/lib/sequel_model/dataset_methods.rb +26 -0
  84. data/lib/sequel_model/eager_loading.rb +370 -0
  85. data/lib/sequel_model/exceptions.rb +7 -0
  86. data/lib/sequel_model/hooks.rb +101 -0
  87. data/lib/sequel_model/inflector.rb +281 -0
  88. data/lib/sequel_model/plugins.rb +62 -0
  89. data/lib/sequel_model/record.rb +568 -0
  90. data/lib/sequel_model/schema.rb +49 -0
  91. data/lib/sequel_model/validations.rb +429 -0
  92. data/lib/sequel_model.rb +91 -0
  93. data/spec/adapters/ado_spec.rb +46 -0
  94. data/spec/adapters/firebird_spec.rb +376 -0
  95. data/spec/adapters/informix_spec.rb +96 -0
  96. data/spec/adapters/mysql_spec.rb +881 -0
  97. data/spec/adapters/oracle_spec.rb +244 -0
  98. data/spec/adapters/postgres_spec.rb +687 -0
  99. data/spec/adapters/spec_helper.rb +10 -0
  100. data/spec/adapters/sqlite_spec.rb +555 -0
  101. data/spec/integration/dataset_test.rb +134 -0
  102. data/spec/integration/eager_loader_test.rb +696 -0
  103. data/spec/integration/prepared_statement_test.rb +130 -0
  104. data/spec/integration/schema_test.rb +180 -0
  105. data/spec/integration/spec_helper.rb +58 -0
  106. data/spec/integration/type_test.rb +96 -0
  107. data/spec/rcov.opts +6 -0
  108. data/spec/sequel_core/connection_pool_spec.rb +526 -0
  109. data/spec/sequel_core/core_ext_spec.rb +156 -0
  110. data/spec/sequel_core/core_sql_spec.rb +522 -0
  111. data/spec/sequel_core/database_spec.rb +1188 -0
  112. data/spec/sequel_core/dataset_spec.rb +3481 -0
  113. data/spec/sequel_core/expression_filters_spec.rb +363 -0
  114. data/spec/sequel_core/migration_spec.rb +261 -0
  115. data/spec/sequel_core/object_graph_spec.rb +272 -0
  116. data/spec/sequel_core/pretty_table_spec.rb +58 -0
  117. data/spec/sequel_core/schema_generator_spec.rb +167 -0
  118. data/spec/sequel_core/schema_spec.rb +780 -0
  119. data/spec/sequel_core/spec_helper.rb +55 -0
  120. data/spec/sequel_core/version_spec.rb +7 -0
  121. data/spec/sequel_model/association_reflection_spec.rb +93 -0
  122. data/spec/sequel_model/associations_spec.rb +1767 -0
  123. data/spec/sequel_model/base_spec.rb +419 -0
  124. data/spec/sequel_model/caching_spec.rb +215 -0
  125. data/spec/sequel_model/dataset_methods_spec.rb +78 -0
  126. data/spec/sequel_model/eager_loading_spec.rb +1165 -0
  127. data/spec/sequel_model/hooks_spec.rb +485 -0
  128. data/spec/sequel_model/inflector_spec.rb +119 -0
  129. data/spec/sequel_model/model_spec.rb +588 -0
  130. data/spec/sequel_model/plugins_spec.rb +80 -0
  131. data/spec/sequel_model/record_spec.rb +1184 -0
  132. data/spec/sequel_model/schema_spec.rb +90 -0
  133. data/spec/sequel_model/spec_helper.rb +78 -0
  134. data/spec/sequel_model/validations_spec.rb +1067 -0
  135. data/spec/spec.opts +0 -0
  136. data/spec/spec_config.rb.example +10 -0
  137. metadata +177 -3
@@ -0,0 +1,1188 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ context "A new Database" do
4
+ setup do
5
+ @db = Sequel::Database.new(1 => 2, :logger => 3)
6
+ end
7
+ teardown do
8
+ Sequel.quote_identifiers = false
9
+ Sequel.identifier_input_method = nil
10
+ Sequel.identifier_output_method = nil
11
+ end
12
+
13
+ specify "should receive options" do
14
+ @db.opts.should == {1 => 2, :logger => 3}
15
+ end
16
+
17
+ specify "should set the logger from opts[:logger] and opts[:loggers]" do
18
+ @db.logger.should == 3
19
+ @db.loggers.should == [3]
20
+ Sequel::Database.new(1 => 2, :loggers => 3).logger.should == 3
21
+ Sequel::Database.new(1 => 2, :loggers => 3).loggers.should == [3]
22
+ Sequel::Database.new(1 => 2, :loggers => [3]).logger.should == 3
23
+ Sequel::Database.new(1 => 2, :loggers => [3]).loggers.should == [3]
24
+ Sequel::Database.new(1 => 2, :logger => 4, :loggers => 3).logger.should == 4
25
+ Sequel::Database.new(1 => 2, :logger => 4, :loggers => 3).loggers.should == [4,3]
26
+ Sequel::Database.new(1 => 2, :logger => [4], :loggers => [3]).logger.should == 4
27
+ Sequel::Database.new(1 => 2, :logger => [4], :loggers => [3]).loggers.should == [4,3]
28
+ end
29
+
30
+ specify "should create a connection pool" do
31
+ @db.pool.should be_a_kind_of(Sequel::ConnectionPool)
32
+ @db.pool.max_size.should == 4
33
+
34
+ Sequel::Database.new(:max_connections => 10).pool.max_size.should == 10
35
+ end
36
+
37
+ specify "should pass the supplied block to the connection pool" do
38
+ cc = nil
39
+ d = Sequel::Database.new {1234}
40
+ d.synchronize {|c| cc = c}
41
+ cc.should == 1234
42
+ end
43
+
44
+ specify "should respect the :single_threaded option" do
45
+ db = Sequel::Database.new(:single_threaded=>true)
46
+ db.pool.should be_a_kind_of(Sequel::SingleThreadedPool)
47
+ db = Sequel::Database.new(:single_threaded=>false)
48
+ db.pool.should be_a_kind_of(Sequel::ConnectionPool)
49
+ end
50
+
51
+ specify "should respect the :quote_identifiers option" do
52
+ db = Sequel::Database.new(:quote_identifiers=>false)
53
+ db.quote_identifiers?.should == false
54
+ db = Sequel::Database.new(:quote_identifiers=>true)
55
+ db.quote_identifiers?.should == true
56
+ end
57
+
58
+ specify "should upcase on input and downcase on output by default" do
59
+ db = Sequel::Database.new
60
+ db.send(:identifier_input_method_default).should == :upcase
61
+ db.send(:identifier_output_method_default).should == :downcase
62
+ end
63
+
64
+ specify "should respect the :upcase_identifiers option" do
65
+ Sequel.upcase_identifiers = false
66
+ db = Sequel::Database.new(:upcase_identifiers=>false)
67
+ db.upcase_identifiers?.should == false
68
+ db.upcase_identifiers = true
69
+ db.upcase_identifiers?.should == true
70
+ db = Sequel::Database.new(:upcase_identifiers=>true)
71
+ db.upcase_identifiers?.should == true
72
+ db.upcase_identifiers = false
73
+ db.upcase_identifiers?.should == false
74
+ Sequel.upcase_identifiers = true
75
+ db = Sequel::Database.new(:upcase_identifiers=>false)
76
+ db.upcase_identifiers?.should == false
77
+ db.upcase_identifiers = true
78
+ db.upcase_identifiers?.should == true
79
+ db = Sequel::Database.new(:upcase_identifiers=>true)
80
+ db.upcase_identifiers?.should == true
81
+ db.upcase_identifiers = false
82
+ db.upcase_identifiers?.should == false
83
+ end
84
+
85
+ specify "should respect the :identifier_input_method option" do
86
+ Sequel.identifier_input_method = nil
87
+ Sequel::Database.identifier_input_method.should == ""
88
+ db = Sequel::Database.new(:identifier_input_method=>nil)
89
+ db.identifier_input_method.should == nil
90
+ db.identifier_input_method = :downcase
91
+ db.identifier_input_method.should == :downcase
92
+ db = Sequel::Database.new(:identifier_input_method=>:upcase)
93
+ db.identifier_input_method.should == :upcase
94
+ db.identifier_input_method = nil
95
+ db.identifier_input_method.should == nil
96
+ Sequel.identifier_input_method = :downcase
97
+ Sequel::Database.identifier_input_method.should == :downcase
98
+ db = Sequel::Database.new(:identifier_input_method=>nil)
99
+ db.identifier_input_method.should == nil
100
+ db.identifier_input_method = :upcase
101
+ db.identifier_input_method.should == :upcase
102
+ db = Sequel::Database.new(:identifier_input_method=>:upcase)
103
+ db.identifier_input_method.should == :upcase
104
+ db.identifier_input_method = nil
105
+ db.identifier_input_method.should == nil
106
+ end
107
+
108
+ specify "should respect the :identifier_output_method option" do
109
+ Sequel.identifier_output_method = nil
110
+ Sequel::Database.identifier_output_method.should == ""
111
+ db = Sequel::Database.new(:identifier_output_method=>nil)
112
+ db.identifier_output_method.should == nil
113
+ db.identifier_output_method = :downcase
114
+ db.identifier_output_method.should == :downcase
115
+ db = Sequel::Database.new(:identifier_output_method=>:upcase)
116
+ db.identifier_output_method.should == :upcase
117
+ db.identifier_output_method = nil
118
+ db.identifier_output_method.should == nil
119
+ Sequel.identifier_output_method = :downcase
120
+ Sequel::Database.identifier_output_method.should == :downcase
121
+ db = Sequel::Database.new(:identifier_output_method=>nil)
122
+ db.identifier_output_method.should == nil
123
+ db.identifier_output_method = :upcase
124
+ db.identifier_output_method.should == :upcase
125
+ db = Sequel::Database.new(:identifier_output_method=>:upcase)
126
+ db.identifier_output_method.should == :upcase
127
+ db.identifier_output_method = nil
128
+ db.identifier_output_method.should == nil
129
+ end
130
+
131
+ specify "should use the default Sequel.quote_identifiers value" do
132
+ Sequel.quote_identifiers = true
133
+ Sequel::Database.new({}).quote_identifiers?.should == true
134
+ Sequel.quote_identifiers = false
135
+ Sequel::Database.new({}).quote_identifiers?.should == false
136
+ Sequel::Database.quote_identifiers = true
137
+ Sequel::Database.new({}).quote_identifiers?.should == true
138
+ Sequel::Database.quote_identifiers = false
139
+ Sequel::Database.new({}).quote_identifiers?.should == false
140
+ end
141
+
142
+ specify "should use the default Sequel.upcase_identifiers value" do
143
+ Sequel.upcase_identifiers = true
144
+ Sequel::Database.new({}).upcase_identifiers?.should == true
145
+ Sequel.upcase_identifiers = false
146
+ Sequel::Database.new({}).upcase_identifiers?.should == false
147
+ Sequel::Database.upcase_identifiers = true
148
+ Sequel::Database.new({}).upcase_identifiers?.should == true
149
+ Sequel::Database.upcase_identifiers = false
150
+ Sequel::Database.new({}).upcase_identifiers?.should == false
151
+ end
152
+
153
+ specify "should use the default Sequel.identifier_input_method value" do
154
+ Sequel.identifier_input_method = :downcase
155
+ Sequel::Database.new({}).identifier_input_method.should == :downcase
156
+ Sequel.identifier_input_method = :upcase
157
+ Sequel::Database.new({}).identifier_input_method.should == :upcase
158
+ Sequel::Database.identifier_input_method = :downcase
159
+ Sequel::Database.new({}).identifier_input_method.should == :downcase
160
+ Sequel::Database.identifier_input_method = :upcase
161
+ Sequel::Database.new({}).identifier_input_method.should == :upcase
162
+ end
163
+
164
+ specify "should use the default Sequel.identifier_output_method value" do
165
+ Sequel.identifier_output_method = :downcase
166
+ Sequel::Database.new({}).identifier_output_method.should == :downcase
167
+ Sequel.identifier_output_method = :upcase
168
+ Sequel::Database.new({}).identifier_output_method.should == :upcase
169
+ Sequel::Database.identifier_output_method = :downcase
170
+ Sequel::Database.new({}).identifier_output_method.should == :downcase
171
+ Sequel::Database.identifier_output_method = :upcase
172
+ Sequel::Database.new({}).identifier_output_method.should == :upcase
173
+ end
174
+
175
+ specify "should respect the quote_indentifiers_default method if Sequel.quote_identifiers = nil" do
176
+ Sequel.quote_identifiers = nil
177
+ Sequel::Database.new({}).quote_identifiers?.should == true
178
+ x = Class.new(Sequel::Database){def quote_identifiers_default; false end}
179
+ x.new({}).quote_identifiers?.should == false
180
+ y = Class.new(Sequel::Database){def quote_identifiers_default; true end}
181
+ y.new({}).quote_identifiers?.should == true
182
+ end
183
+
184
+ specify "should respect the identifier_input_method_default method" do
185
+ class Sequel::Database
186
+ @@identifier_input_method = nil
187
+ end
188
+ x = Class.new(Sequel::Database){def identifier_input_method_default; :downcase end}
189
+ x.new({}).identifier_input_method.should == :downcase
190
+ y = Class.new(Sequel::Database){def identifier_input_method_default; :camelize end}
191
+ y.new({}).identifier_input_method.should == :camelize
192
+ end
193
+
194
+ specify "should respect the identifier_output_method_default method if Sequel.upcase_identifiers = nil" do
195
+ class Sequel::Database
196
+ @@identifier_output_method = nil
197
+ end
198
+ x = Class.new(Sequel::Database){def identifier_output_method_default; :upcase end}
199
+ x.new({}).identifier_output_method.should == :upcase
200
+ y = Class.new(Sequel::Database){def identifier_output_method_default; :underscore end}
201
+ y.new({}).identifier_output_method.should == :underscore
202
+ end
203
+
204
+ specify "should just use a :uri option for jdbc with the full connection string" do
205
+ Sequel::Database.should_receive(:adapter_class).once.with(:jdbc).and_return(Sequel::Database)
206
+ db = Sequel.connect('jdbc:test://host/db_name')
207
+ db.should be_a_kind_of(Sequel::Database)
208
+ db.opts[:uri].should == 'jdbc:test://host/db_name'
209
+ end
210
+
211
+ specify "should just use a :uri option for do with the full connection string" do
212
+ Sequel::Database.should_receive(:adapter_class).once.with(:do).and_return(Sequel::Database)
213
+ db = Sequel.connect('do:test://host/db_name')
214
+ db.should be_a_kind_of(Sequel::Database)
215
+ db.opts[:uri].should == 'do:test://host/db_name'
216
+ end
217
+ end
218
+
219
+ context "Database#disconnect" do
220
+ specify "should call pool.disconnect" do
221
+ d = Sequel::Database.new
222
+ p = d.pool
223
+ a = 1
224
+ p.meta_def(:disconnect){a += 1}
225
+ d.disconnect.should == 2
226
+ a.should == 2
227
+ end
228
+ end
229
+
230
+ context "Database#connect" do
231
+ specify "should raise Sequel::Error::NotImplemented" do
232
+ proc {Sequel::Database.new.connect}.should raise_error(NotImplementedError)
233
+ end
234
+ end
235
+
236
+ context "Database#uri" do
237
+ setup do
238
+ @c = Class.new(Sequel::Database) do
239
+ set_adapter_scheme :mau
240
+ end
241
+
242
+ @db = Sequel.connect('mau://user:pass@localhost:9876/maumau')
243
+ end
244
+
245
+ specify "should return the connection URI for the database" do
246
+ @db.uri.should == 'mau://user:pass@localhost:9876/maumau'
247
+ end
248
+
249
+ specify "should be aliased as #url" do
250
+ @db.url.should == 'mau://user:pass@localhost:9876/maumau'
251
+ end
252
+ end
253
+
254
+ context "Database.adapter_scheme" do
255
+ specify "should return the database schema" do
256
+ Sequel::Database.adapter_scheme.should be_nil
257
+
258
+ @c = Class.new(Sequel::Database) do
259
+ set_adapter_scheme :mau
260
+ end
261
+
262
+ @c.adapter_scheme.should == :mau
263
+ end
264
+ end
265
+
266
+ context "Database#dataset" do
267
+ setup do
268
+ @db = Sequel::Database.new
269
+ @ds = @db.dataset
270
+ end
271
+
272
+ specify "should provide a blank dataset through #dataset" do
273
+ @ds.should be_a_kind_of(Sequel::Dataset)
274
+ @ds.opts.should == {}
275
+ @ds.db.should be(@db)
276
+ end
277
+
278
+ specify "should provide a #from dataset" do
279
+ d = @db.from(:mau)
280
+ d.should be_a_kind_of(Sequel::Dataset)
281
+ d.sql.should == 'SELECT * FROM mau'
282
+
283
+ e = @db[:miu]
284
+ e.should be_a_kind_of(Sequel::Dataset)
285
+ e.sql.should == 'SELECT * FROM miu'
286
+ end
287
+
288
+ specify "should provide a filtered #from dataset if a block is given" do
289
+ d = @db.from(:mau) {:x.sql_number > 100}
290
+ d.should be_a_kind_of(Sequel::Dataset)
291
+ d.sql.should == 'SELECT * FROM mau WHERE (x > 100)'
292
+ end
293
+
294
+ specify "should provide a #select dataset" do
295
+ d = @db.select(:a, :b, :c).from(:mau)
296
+ d.should be_a_kind_of(Sequel::Dataset)
297
+ d.sql.should == 'SELECT a, b, c FROM mau'
298
+ end
299
+ end
300
+
301
+ context "Database#execute" do
302
+ specify "should raise Sequel::Error::NotImplemented" do
303
+ proc {Sequel::Database.new.execute('blah blah')}.should raise_error(NotImplementedError)
304
+ proc {Sequel::Database.new << 'blah blah'}.should raise_error(NotImplementedError)
305
+ end
306
+ end
307
+
308
+ context "Database#<<" do
309
+ setup do
310
+ @c = Class.new(Sequel::Database) do
311
+ define_method(:execute) {|sql, opts| sql}
312
+ end
313
+ @db = @c.new({})
314
+ end
315
+
316
+ specify "should pass the supplied sql to #execute" do
317
+ (@db << "DELETE FROM items").should == "DELETE FROM items"
318
+ end
319
+
320
+ specify "should accept an array and convert it to SQL" do
321
+ a = %[
322
+ --
323
+ CREATE TABLE items (a integer, /*b integer*/
324
+ b text, c integer);
325
+ DROP TABLE old_items;
326
+ ].split($/)
327
+ (@db << a).should ==
328
+ "CREATE TABLE items (a integer, b text, c integer); DROP TABLE old_items;"
329
+ end
330
+
331
+ specify "should remove comments and whitespace from arrays" do
332
+ s = %[
333
+ --
334
+ CREATE TABLE items (a integer, /*b integer*/
335
+ b text, c integer); \r\n
336
+ DROP TABLE old_items;
337
+ ].split($/)
338
+ (@db << s).should ==
339
+ "CREATE TABLE items (a integer, b text, c integer); DROP TABLE old_items;"
340
+ end
341
+
342
+ specify "should not remove comments and whitespace from strings" do
343
+ s = "INSERT INTO items VALUES ('---abc')"
344
+ (@db << s).should == s
345
+ end
346
+ end
347
+
348
+ context "Database#synchronize" do
349
+ setup do
350
+ @db = Sequel::Database.new(:max_connections => 1)
351
+ @db.pool.connection_proc = proc {12345}
352
+ end
353
+
354
+ specify "should wrap the supplied block in pool.hold" do
355
+ stop = false
356
+ c1, c2 = nil
357
+ t1 = Thread.new {@db.synchronize {|c| c1 = c; while !stop;sleep 0.1;end}}
358
+ while !c1;end
359
+ c1.should == 12345
360
+ t2 = Thread.new {@db.synchronize {|c| c2 = c}}
361
+ sleep 0.2
362
+ @db.pool.available_connections.should be_empty
363
+ c2.should be_nil
364
+ stop = true
365
+ t1.join
366
+ sleep 0.1
367
+ c2.should == 12345
368
+ t2.join
369
+ end
370
+ end
371
+
372
+ context "Database#test_connection" do
373
+ setup do
374
+ @db = Sequel::Database.new
375
+ @test = nil
376
+ @db.pool.connection_proc = proc {@test = rand(100)}
377
+ end
378
+
379
+ specify "should call pool#hold" do
380
+ @db.test_connection
381
+ @test.should_not be_nil
382
+ end
383
+
384
+ specify "should return true if successful" do
385
+ @db.test_connection.should be_true
386
+ end
387
+ end
388
+
389
+ class DummyDataset < Sequel::Dataset
390
+ def first
391
+ raise if @opts[:from] == [:a]
392
+ true
393
+ end
394
+ end
395
+
396
+ class DummyDatabase < Sequel::Database
397
+ attr_reader :sqls
398
+
399
+ def execute(sql, opts={})
400
+ @sqls ||= []
401
+ @sqls << sql
402
+ end
403
+
404
+ def transaction; yield; end
405
+
406
+ def dataset
407
+ DummyDataset.new(self)
408
+ end
409
+ end
410
+
411
+ context "Database#create_table" do
412
+ setup do
413
+ @db = DummyDatabase.new
414
+ end
415
+
416
+ specify "should construct proper SQL" do
417
+ @db.create_table :test do
418
+ primary_key :id, :integer, :null => false
419
+ column :name, :text
420
+ index :name, :unique => true
421
+ end
422
+ @db.sqls.should == [
423
+ 'CREATE TABLE test (id integer NOT NULL PRIMARY KEY AUTOINCREMENT, name text)',
424
+ 'CREATE UNIQUE INDEX test_name_index ON test (name)'
425
+ ]
426
+ end
427
+ end
428
+
429
+ context "Database#alter_table" do
430
+ setup do
431
+ @db = DummyDatabase.new
432
+ end
433
+
434
+ specify "should construct proper SQL" do
435
+ @db.alter_table :xyz do
436
+ add_column :aaa, :text, :null => false, :unique => true
437
+ drop_column :bbb
438
+ rename_column :ccc, :ddd
439
+ set_column_type :eee, :integer
440
+ set_column_default :hhh, 'abcd'
441
+
442
+ add_index :fff, :unique => true
443
+ drop_index :ggg
444
+ end
445
+
446
+ @db.sqls.should == [
447
+ 'ALTER TABLE xyz ADD COLUMN aaa text UNIQUE NOT NULL',
448
+ 'ALTER TABLE xyz DROP COLUMN bbb',
449
+ 'ALTER TABLE xyz RENAME COLUMN ccc TO ddd',
450
+ 'ALTER TABLE xyz ALTER COLUMN eee TYPE integer',
451
+ "ALTER TABLE xyz ALTER COLUMN hhh SET DEFAULT 'abcd'",
452
+
453
+ 'CREATE UNIQUE INDEX xyz_fff_index ON xyz (fff)',
454
+ 'DROP INDEX xyz_ggg_index'
455
+ ]
456
+ end
457
+ end
458
+
459
+ context "Database#add_column" do
460
+ setup do
461
+ @db = DummyDatabase.new
462
+ end
463
+
464
+ specify "should construct proper SQL" do
465
+ @db.add_column :test, :name, :text, :unique => true
466
+ @db.sqls.should == [
467
+ 'ALTER TABLE test ADD COLUMN name text UNIQUE'
468
+ ]
469
+ end
470
+ end
471
+
472
+ context "Database#drop_column" do
473
+ setup do
474
+ @db = DummyDatabase.new
475
+ end
476
+
477
+ specify "should construct proper SQL" do
478
+ @db.drop_column :test, :name
479
+ @db.sqls.should == [
480
+ 'ALTER TABLE test DROP COLUMN name'
481
+ ]
482
+ end
483
+ end
484
+
485
+ context "Database#rename_column" do
486
+ setup do
487
+ @db = DummyDatabase.new
488
+ end
489
+
490
+ specify "should construct proper SQL" do
491
+ @db.rename_column :test, :abc, :def
492
+ @db.sqls.should == [
493
+ 'ALTER TABLE test RENAME COLUMN abc TO def'
494
+ ]
495
+ end
496
+ end
497
+
498
+ context "Database#set_column_type" do
499
+ setup do
500
+ @db = DummyDatabase.new
501
+ end
502
+
503
+ specify "should construct proper SQL" do
504
+ @db.set_column_type :test, :name, :integer
505
+ @db.sqls.should == [
506
+ 'ALTER TABLE test ALTER COLUMN name TYPE integer'
507
+ ]
508
+ end
509
+ end
510
+
511
+ context "Database#set_column_default" do
512
+ setup do
513
+ @db = DummyDatabase.new
514
+ end
515
+
516
+ specify "should construct proper SQL" do
517
+ @db.set_column_default :test, :name, 'zyx'
518
+ @db.sqls.should == [
519
+ "ALTER TABLE test ALTER COLUMN name SET DEFAULT 'zyx'"
520
+ ]
521
+ end
522
+ end
523
+
524
+ context "Database#add_index" do
525
+ setup do
526
+ @db = DummyDatabase.new
527
+ end
528
+
529
+ specify "should construct proper SQL" do
530
+ @db.add_index :test, :name, :unique => true
531
+ @db.sqls.should == [
532
+ 'CREATE UNIQUE INDEX test_name_index ON test (name)'
533
+ ]
534
+ end
535
+
536
+ specify "should accept multiple columns" do
537
+ @db.add_index :test, [:one, :two]
538
+ @db.sqls.should == [
539
+ 'CREATE INDEX test_one_two_index ON test (one, two)'
540
+ ]
541
+ end
542
+ end
543
+
544
+ context "Database#drop_index" do
545
+ setup do
546
+ @db = DummyDatabase.new
547
+ end
548
+
549
+ specify "should construct proper SQL" do
550
+ @db.drop_index :test, :name
551
+ @db.sqls.should == [
552
+ 'DROP INDEX test_name_index'
553
+ ]
554
+ end
555
+
556
+ end
557
+
558
+ class Dummy2Database < Sequel::Database
559
+ attr_reader :sql
560
+ def execute(sql); @sql = sql; end
561
+ def transaction; yield; end
562
+ end
563
+
564
+ context "Database#drop_table" do
565
+ setup do
566
+ @db = DummyDatabase.new
567
+ end
568
+
569
+ specify "should construct proper SQL" do
570
+ @db.drop_table :test
571
+ @db.sqls.should == ['DROP TABLE test']
572
+ end
573
+
574
+ specify "should accept multiple table names" do
575
+ @db.drop_table :a, :bb, :ccc
576
+ @db.sqls.should == [
577
+ 'DROP TABLE a',
578
+ 'DROP TABLE bb',
579
+ 'DROP TABLE ccc'
580
+ ]
581
+ end
582
+ end
583
+
584
+ context "Database#rename_table" do
585
+ setup do
586
+ @db = DummyDatabase.new
587
+ end
588
+
589
+ specify "should construct proper SQL" do
590
+ @db.rename_table :abc, :xyz
591
+ @db.sqls.should == ['ALTER TABLE abc RENAME TO xyz']
592
+ end
593
+ end
594
+
595
+ context "Database#table_exists?" do
596
+ setup do
597
+ @db = DummyDatabase.new
598
+ @db.instance_variable_set(:@schemas, {:a=>[]})
599
+ @db2 = DummyDatabase.new
600
+ end
601
+
602
+ specify "should use schema information if available" do
603
+ @db.table_exists?(:a).should be_true
604
+ end
605
+
606
+ specify "should otherwise try to select the first record from the table's dataset" do
607
+ @db2.table_exists?(:a).should be_false
608
+ @db2.table_exists?(:b).should be_true
609
+ end
610
+ end
611
+
612
+ class Dummy3Database < Sequel::Database
613
+ attr_reader :sql, :transactions
614
+ def execute(sql, opts={}); @sql ||= []; @sql << sql; end
615
+
616
+ class DummyConnection
617
+ def initialize(db); @db = db; end
618
+ def execute(sql); @db.execute(sql); end
619
+ end
620
+ end
621
+
622
+ context "Database#transaction" do
623
+ setup do
624
+ @db = Dummy3Database.new
625
+ @db.pool.connection_proc = proc {Dummy3Database::DummyConnection.new(@db)}
626
+ end
627
+
628
+ specify "should wrap the supplied block with BEGIN + COMMIT statements" do
629
+ @db.transaction {@db.execute 'DROP TABLE test;'}
630
+ @db.sql.should == ['BEGIN', 'DROP TABLE test;', 'COMMIT']
631
+ end
632
+
633
+ specify "should handle returning inside of the block by committing" do
634
+ def @db.ret_commit
635
+ transaction do
636
+ execute 'DROP TABLE test;'
637
+ return
638
+ execute 'DROP TABLE test2;';
639
+ end
640
+ end
641
+ @db.ret_commit
642
+ @db.sql.should == ['BEGIN', 'DROP TABLE test;', 'COMMIT']
643
+ end
644
+
645
+ specify "should issue ROLLBACK if an exception is raised, and re-raise" do
646
+ @db.transaction {@db.execute 'DROP TABLE test'; raise RuntimeError} rescue nil
647
+ @db.sql.should == ['BEGIN', 'DROP TABLE test', 'ROLLBACK']
648
+
649
+ proc {@db.transaction {raise RuntimeError}}.should raise_error(RuntimeError)
650
+ end
651
+
652
+ specify "should issue ROLLBACK if Sequel::Error::Rollback is called in the transaction" do
653
+ @db.transaction do
654
+ @db.drop_table(:a)
655
+ raise Sequel::Error::Rollback
656
+ @db.drop_table(:b)
657
+ end
658
+
659
+ @db.sql.should == ['BEGIN', 'DROP TABLE a', 'ROLLBACK']
660
+ end
661
+
662
+ specify "should be re-entrant" do
663
+ stop = false
664
+ cc = nil
665
+ t = Thread.new do
666
+ @db.transaction {@db.transaction {@db.transaction {|c|
667
+ cc = c
668
+ while !stop; sleep 0.1; end
669
+ }}}
670
+ end
671
+ while cc.nil?; sleep 0.1; end
672
+ cc.should be_a_kind_of(Dummy3Database::DummyConnection)
673
+ @db.transactions.should == [t]
674
+ stop = true
675
+ t.join
676
+ @db.transactions.should be_empty
677
+ end
678
+ end
679
+
680
+ class Sequel::Database
681
+ def self.get_adapters; @@adapters; end
682
+ end
683
+
684
+ context "A Database adapter with a scheme" do
685
+ setup do
686
+ class CCC < Sequel::Database
687
+ if defined?(DISCONNECTS)
688
+ DISCONNECTS.clear
689
+ else
690
+ DISCONNECTS = []
691
+ end
692
+ set_adapter_scheme :ccc
693
+ def disconnect
694
+ DISCONNECTS << self
695
+ end
696
+ end
697
+ end
698
+
699
+ specify "should be registered in adapters" do
700
+ Sequel::Database.get_adapters[:ccc].should == CCC
701
+ end
702
+
703
+ specify "should be instantiated when its scheme is specified" do
704
+ c = Sequel::Database.connect('ccc://localhost/db')
705
+ c.should be_a_kind_of(CCC)
706
+ c.opts[:host].should == 'localhost'
707
+ c.opts[:database].should == 'db'
708
+ end
709
+
710
+ specify "should be accessible through Sequel.connect" do
711
+ c = Sequel.connect 'ccc://localhost/db'
712
+ c.should be_a_kind_of(CCC)
713
+ c.opts[:host].should == 'localhost'
714
+ c.opts[:database].should == 'db'
715
+ end
716
+
717
+ specify "should be accessible through Sequel.connect via a block" do
718
+ x = nil
719
+ y = nil
720
+ z = nil
721
+
722
+ p = proc do |c|
723
+ c.should be_a_kind_of(CCC)
724
+ c.opts[:host].should == 'localhost'
725
+ c.opts[:database].should == 'db'
726
+ z = y
727
+ y = x
728
+ x = c
729
+ end
730
+ Sequel::Database.connect('ccc://localhost/db', &p).should == nil
731
+ CCC::DISCONNECTS.should == [x]
732
+
733
+ Sequel.connect('ccc://localhost/db', &p).should == nil
734
+ CCC::DISCONNECTS.should == [y, x]
735
+
736
+ Sequel.send(:def_adapter_method, :ccc)
737
+ Sequel.ccc('db', :host=>'localhost', &p).should == nil
738
+ CCC::DISCONNECTS.should == [z, y, x]
739
+ end
740
+
741
+ specify "should be accessible through Sequel.open" do
742
+ c = Sequel.open 'ccc://localhost/db'
743
+ c.should be_a_kind_of(CCC)
744
+ c.opts[:host].should == 'localhost'
745
+ c.opts[:database].should == 'db'
746
+ end
747
+
748
+ specify "should be accessible through Sequel.<adapter>" do
749
+ Sequel.send(:def_adapter_method, :ccc)
750
+
751
+ # invalid parameters
752
+ proc {Sequel.ccc('abc', 'def')}.should raise_error(Sequel::Error)
753
+
754
+ c = Sequel.ccc('mydb')
755
+ c.should be_a_kind_of(CCC)
756
+ c.opts.should == {:adapter=>:ccc, :database => 'mydb'}
757
+
758
+ c = Sequel.ccc('mydb', :host => 'localhost')
759
+ c.should be_a_kind_of(CCC)
760
+ c.opts.should == {:adapter=>:ccc, :database => 'mydb', :host => 'localhost'}
761
+
762
+ c = Sequel.ccc
763
+ c.should be_a_kind_of(CCC)
764
+ c.opts.should == {:adapter=>:ccc}
765
+
766
+ c = Sequel.ccc(:database => 'mydb', :host => 'localhost')
767
+ c.should be_a_kind_of(CCC)
768
+ c.opts.should == {:adapter=>:ccc, :database => 'mydb', :host => 'localhost'}
769
+ end
770
+
771
+ specify "should be accessible through Sequel.connect with options" do
772
+ c = Sequel.connect(:adapter => :ccc, :database => 'mydb')
773
+ c.should be_a_kind_of(CCC)
774
+ c.opts.should == {:adapter => :ccc, :database => 'mydb'}
775
+ end
776
+
777
+ specify "should be accessible through Sequel.connect with URL parameters" do
778
+ c = Sequel.connect 'ccc://localhost/db?host=/tmp&user=test'
779
+ c.should be_a_kind_of(CCC)
780
+ c.opts[:host].should == '/tmp'
781
+ c.opts[:database].should == 'db'
782
+ c.opts[:user].should == 'test'
783
+ end
784
+
785
+ end
786
+
787
+ context "An unknown database scheme" do
788
+ specify "should raise an error in Sequel::Database.connect" do
789
+ proc {Sequel::Database.connect('ddd://localhost/db')}.should raise_error(Sequel::Error::AdapterNotFound)
790
+ end
791
+
792
+ specify "should raise an error in Sequel.connect" do
793
+ proc {Sequel.connect('ddd://localhost/db')}.should raise_error(Sequel::Error::AdapterNotFound)
794
+ end
795
+
796
+ specify "should raise an error in Sequel.open" do
797
+ proc {Sequel.open('ddd://localhost/db')}.should raise_error(Sequel::Error::AdapterNotFound)
798
+ end
799
+ end
800
+
801
+ context "A broken adapter (lib is there but the class is not)" do
802
+ setup do
803
+ @fn = File.join(File.dirname(__FILE__), '../../lib/sequel_core/adapters/blah.rb')
804
+ File.open(@fn,'a'){}
805
+ end
806
+
807
+ teardown do
808
+ File.delete(@fn)
809
+ end
810
+
811
+ specify "should raise an error" do
812
+ proc {Sequel.connect('blah://blow')}.should raise_error(Sequel::Error::AdapterNotFound)
813
+ end
814
+ end
815
+
816
+ context "A single threaded database" do
817
+ teardown do
818
+ Sequel::Database.single_threaded = false
819
+ end
820
+
821
+ specify "should use a SingleThreadedPool instead of a ConnectionPool" do
822
+ db = Sequel::Database.new(:single_threaded => true)
823
+ db.pool.should be_a_kind_of(Sequel::SingleThreadedPool)
824
+ end
825
+
826
+ specify "should be constructable using :single_threaded => true option" do
827
+ db = Sequel::Database.new(:single_threaded => true)
828
+ db.pool.should be_a_kind_of(Sequel::SingleThreadedPool)
829
+ end
830
+
831
+ specify "should be constructable using Database.single_threaded = true" do
832
+ Sequel::Database.single_threaded = true
833
+ db = Sequel::Database.new
834
+ db.pool.should be_a_kind_of(Sequel::SingleThreadedPool)
835
+ end
836
+
837
+ specify "should be constructable using Sequel.single_threaded = true" do
838
+ Sequel.single_threaded = true
839
+ db = Sequel::Database.new
840
+ db.pool.should be_a_kind_of(Sequel::SingleThreadedPool)
841
+ end
842
+ end
843
+
844
+ context "A single threaded database" do
845
+ setup do
846
+ conn = 1234567
847
+ @db = Sequel::Database.new(:single_threaded => true) do
848
+ conn += 1
849
+ end
850
+ end
851
+
852
+ specify "should invoke connection_proc only once" do
853
+ @db.pool.hold {|c| c.should == 1234568}
854
+ @db.pool.hold {|c| c.should == 1234568}
855
+ end
856
+
857
+ specify "should convert an Exception into a RuntimeError" do
858
+ db = Sequel::Database.new(:single_threaded => true) do
859
+ raise Exception
860
+ end
861
+
862
+ proc {db.pool.hold {|c|}}.should raise_error(RuntimeError)
863
+ end
864
+ end
865
+
866
+ context "A database" do
867
+ setup do
868
+ Sequel::Database.single_threaded = false
869
+ end
870
+
871
+ teardown do
872
+ Sequel::Database.single_threaded = false
873
+ end
874
+
875
+ specify "should be either single_threaded? or multi_threaded?" do
876
+ db = Sequel::Database.new(:single_threaded => true)
877
+ db.should be_single_threaded
878
+ db.should_not be_multi_threaded
879
+
880
+ db = Sequel::Database.new(:max_options => 1)
881
+ db.should_not be_single_threaded
882
+ db.should be_multi_threaded
883
+
884
+ db = Sequel::Database.new
885
+ db.should_not be_single_threaded
886
+ db.should be_multi_threaded
887
+
888
+ Sequel::Database.single_threaded = true
889
+
890
+ db = Sequel::Database.new
891
+ db.should be_single_threaded
892
+ db.should_not be_multi_threaded
893
+
894
+ db = Sequel::Database.new(:max_options => 4)
895
+ db.should be_single_threaded
896
+ db.should_not be_multi_threaded
897
+ end
898
+
899
+ specify "should accept a logger object" do
900
+ db = Sequel::Database.new
901
+ s = "I'm a logger"
902
+ db.logger = s
903
+ db.logger.should == s
904
+ db.loggers.should == [s]
905
+ db.logger = nil
906
+ db.logger.should == nil
907
+ db.loggers.should == []
908
+
909
+ db.loggers = [s]
910
+ db.logger.should == s
911
+ db.loggers.should == [s]
912
+ db.loggers = []
913
+ db.logger.should == nil
914
+ db.loggers.should == []
915
+
916
+ t = "I'm also a logger"
917
+ db.loggers = [s, t]
918
+ db.logger.should == s
919
+ db.loggers.should == [s,t]
920
+ db.loggers = []
921
+ db.logger.should == nil
922
+ db.loggers.should == []
923
+ end
924
+ end
925
+
926
+ context "Database#dataset" do
927
+ setup do
928
+ @db = Sequel::Database.new
929
+ end
930
+
931
+ specify "should delegate to Dataset#query if block is provided" do
932
+ @d = @db.query {select :x; from :y}
933
+ @d.should be_a_kind_of(Sequel::Dataset)
934
+ @d.sql.should == "SELECT x FROM y"
935
+ end
936
+ end
937
+
938
+ context "Database#fetch" do
939
+ setup do
940
+ @db = Sequel::Database.new
941
+ c = Class.new(Sequel::Dataset) do
942
+ def fetch_rows(sql); yield({:sql => sql}); end
943
+ end
944
+ @db.meta_def(:dataset) {c.new(self)}
945
+ end
946
+
947
+ specify "should create a dataset and invoke its fetch_rows method with the given sql" do
948
+ sql = nil
949
+ @db.fetch('select * from xyz') {|r| sql = r[:sql]}
950
+ sql.should == 'select * from xyz'
951
+ end
952
+
953
+ specify "should format the given sql with any additional arguments" do
954
+ sql = nil
955
+ @db.fetch('select * from xyz where x = ? and y = ?', 15, 'abc') {|r| sql = r[:sql]}
956
+ sql.should == "select * from xyz where x = 15 and y = 'abc'"
957
+
958
+ # and Aman Gupta's example
959
+ @db.fetch('select name from table where name = ? or id in ?',
960
+ 'aman', [3,4,7]) {|r| sql = r[:sql]}
961
+ sql.should == "select name from table where name = 'aman' or id in (3, 4, 7)"
962
+ end
963
+
964
+ specify "should return the dataset if no block is given" do
965
+ @db.fetch('select * from xyz').should be_a_kind_of(Sequel::Dataset)
966
+
967
+ @db.fetch('select a from b').map {|r| r[:sql]}.should == ['select a from b']
968
+
969
+ @db.fetch('select c from d').inject([]) {|m, r| m << r; m}.should == \
970
+ [{:sql => 'select c from d'}]
971
+ end
972
+
973
+ specify "should return a dataset that always uses the given sql for SELECTs" do
974
+ ds = @db.fetch('select * from xyz')
975
+ ds.select_sql.should == 'select * from xyz'
976
+ ds.sql.should == 'select * from xyz'
977
+
978
+ ds.filter!(:price.sql_number < 100)
979
+ ds.select_sql.should == 'select * from xyz'
980
+ ds.sql.should == 'select * from xyz'
981
+ end
982
+ end
983
+
984
+
985
+ context "Database#[]" do
986
+ setup do
987
+ @db = Sequel::Database.new
988
+ end
989
+
990
+ specify "should return a dataset when symbols are given" do
991
+ ds = @db[:items]
992
+ ds.class.should == Sequel::Dataset
993
+ ds.opts[:from].should == [:items]
994
+ end
995
+
996
+ specify "should return an enumerator when a string is given" do
997
+ c = Class.new(Sequel::Dataset) do
998
+ def fetch_rows(sql); yield({:sql => sql}); end
999
+ end
1000
+ @db.meta_def(:dataset) {c.new(self)}
1001
+
1002
+ sql = nil
1003
+ @db['select * from xyz where x = ? and y = ?', 15, 'abc'].each {|r| sql = r[:sql]}
1004
+ sql.should == "select * from xyz where x = 15 and y = 'abc'"
1005
+ end
1006
+ end
1007
+
1008
+ context "Database#create_view" do
1009
+ setup do
1010
+ @db = DummyDatabase.new
1011
+ end
1012
+
1013
+ specify "should construct proper SQL with raw SQL" do
1014
+ @db.create_view :test, "SELECT * FROM xyz"
1015
+ @db.sqls.should == ['CREATE VIEW test AS SELECT * FROM xyz']
1016
+ end
1017
+
1018
+ specify "should construct proper SQL with dataset" do
1019
+ @db.create_view :test, @db[:items].select(:a, :b).order(:c)
1020
+ @db.sqls.should == ['CREATE VIEW test AS SELECT a, b FROM items ORDER BY c']
1021
+ end
1022
+ end
1023
+
1024
+ context "Database#create_or_replace_view" do
1025
+ setup do
1026
+ @db = DummyDatabase.new
1027
+ end
1028
+
1029
+ specify "should construct proper SQL with raw SQL" do
1030
+ @db.create_or_replace_view :test, "SELECT * FROM xyz"
1031
+ @db.sqls.should == ['CREATE OR REPLACE VIEW test AS SELECT * FROM xyz']
1032
+ end
1033
+
1034
+ specify "should construct proper SQL with dataset" do
1035
+ @db.create_or_replace_view :test, @db[:items].select(:a, :b).order(:c)
1036
+ @db.sqls.should == ['CREATE OR REPLACE VIEW test AS SELECT a, b FROM items ORDER BY c']
1037
+ end
1038
+ end
1039
+
1040
+ context "Database#drop_view" do
1041
+ setup do
1042
+ @db = DummyDatabase.new
1043
+ end
1044
+
1045
+ specify "should construct proper SQL" do
1046
+ @db.drop_view :test
1047
+ @db.sqls.should == ['DROP VIEW test']
1048
+ end
1049
+ end
1050
+
1051
+ # TODO: beaf this up with specs for all supported ops
1052
+ context "Database#alter_table_sql" do
1053
+ setup do
1054
+ @db = DummyDatabase.new
1055
+ end
1056
+
1057
+ specify "should raise error for an invalid op" do
1058
+ proc {@db.alter_table_sql(:mau, :op => :blah)}.should raise_error(Sequel::Error)
1059
+ end
1060
+ end
1061
+
1062
+ context "Database.connect" do
1063
+ EEE_YAML = "development:\r\n adapter: eee\r\n username: mau\r\n password: tau\r\n host: alfonso\r\n database: mydb\r\n"
1064
+
1065
+ setup do
1066
+ class EEE < Sequel::Database
1067
+ set_adapter_scheme :eee
1068
+ end
1069
+
1070
+ @fn = File.join(File.dirname(__FILE__), 'eee.yaml')
1071
+ File.open(@fn, 'wb') {|f| f << EEE_YAML}
1072
+ end
1073
+
1074
+ teardown do
1075
+ File.delete(@fn)
1076
+ end
1077
+
1078
+ specify "should accept hashes loaded from YAML files" do
1079
+ db = Sequel.connect(YAML.load_file(@fn)['development'])
1080
+ db.class.should == EEE
1081
+ db.opts[:database].should == 'mydb'
1082
+ db.opts[:user].should == 'mau'
1083
+ db.opts[:password].should == 'tau'
1084
+ db.opts[:host].should == 'alfonso'
1085
+ end
1086
+ end
1087
+
1088
+ context "Database#inspect" do
1089
+ setup do
1090
+ @db = DummyDatabase.new
1091
+
1092
+ @db.meta_def(:uri) {'blah://blahblah/blah'}
1093
+ end
1094
+
1095
+ specify "should include the class name and the connection url" do
1096
+ @db.inspect.should == '#<DummyDatabase: "blah://blahblah/blah">'
1097
+ end
1098
+ end
1099
+
1100
+ context "Database#get" do
1101
+ setup do
1102
+ @c = Class.new(DummyDatabase) do
1103
+ def dataset
1104
+ ds = super
1105
+ ds.meta_def(:get) {|c| @db.execute select(c).sql; c}
1106
+ ds
1107
+ end
1108
+ end
1109
+
1110
+ @db = @c.new
1111
+ end
1112
+
1113
+ specify "should use Dataset#get to get a single value" do
1114
+ @db.get(1).should == 1
1115
+ @db.sqls.last.should == 'SELECT 1'
1116
+
1117
+ @db.get(:version.sql_function)
1118
+ @db.sqls.last.should == 'SELECT version()'
1119
+ end
1120
+ end
1121
+
1122
+ context "Database#call" do
1123
+ specify "should call the prepared statement with the given name" do
1124
+ db = MockDatabase.new
1125
+ db[:items].prepare(:select, :select_all)
1126
+ db.call(:select_all).should == [{:id => 1, :x => 1}]
1127
+ db[:items].filter(:n=>:$n).prepare(:select, :select_n)
1128
+ db.call(:select_n, :n=>1).should == [{:id => 1, :x => 1}]
1129
+ db.sqls.should == ['SELECT * FROM items', 'SELECT * FROM items WHERE (n = 1)']
1130
+ end
1131
+ end
1132
+
1133
+ context "Database#server_opts" do
1134
+ specify "should return the general opts if no :servers option is used" do
1135
+ opts = {:host=>1, :database=>2}
1136
+ MockDatabase.new(opts).send(:server_opts, :server1).should == {:host=>1, :database=>2}
1137
+ end
1138
+
1139
+ specify "should return the general opts if entry for the server is present in the :servers option" do
1140
+ opts = {:host=>1, :database=>2, :servers=>{}}
1141
+ MockDatabase.new(opts).send(:server_opts, :server1).should == {:host=>1, :database=>2}
1142
+ end
1143
+
1144
+ specify "should return the general opts merged with the specific opts if given as a hash" do
1145
+ opts = {:host=>1, :database=>2, :servers=>{:server1=>{:host=>3}}}
1146
+ MockDatabase.new(opts).send(:server_opts, :server1).should == {:host=>3, :database=>2}
1147
+ end
1148
+
1149
+ specify "should return the sgeneral opts merged with the specific opts if given as a proc" do
1150
+ opts = {:host=>1, :database=>2, :servers=>{:server1=>proc{|db| {:host=>4}}}}
1151
+ MockDatabase.new(opts).send(:server_opts, :server1).should == {:host=>4, :database=>2}
1152
+ end
1153
+
1154
+ specify "should raise an error if the specific opts is not a proc or hash" do
1155
+ opts = {:host=>1, :database=>2, :servers=>{:server1=>2}}
1156
+ proc{MockDatabase.new(opts).send(:server_opts, :server1)}.should raise_error(Sequel::Error)
1157
+ end
1158
+ end
1159
+
1160
+ context "Database#raise_error" do
1161
+ specify "should reraise if the exception class is not in opts[:classes]" do
1162
+ e = Class.new(StandardError)
1163
+ proc{MockDatabase.new.send(:raise_error, e.new(''), :classes=>[])}.should raise_error(e)
1164
+ end
1165
+
1166
+ specify "should convert the exception to a DatabaseError if the exception class is not in opts[:classes]" do
1167
+ proc{MockDatabase.new.send(:raise_error, Interrupt.new(''), :classes=>[Interrupt])}.should raise_error(Sequel::DatabaseError)
1168
+ end
1169
+
1170
+ specify "should convert the exception to a DatabaseError if opts[:classes] if not present" do
1171
+ proc{MockDatabase.new.send(:raise_error, Interrupt.new(''))}.should raise_error(Sequel::DatabaseError)
1172
+ end
1173
+ end
1174
+
1175
+ context "Database#typecast_value" do
1176
+ setup do
1177
+ @db = Sequel::Database.new
1178
+ end
1179
+ specify "should raise an Error::InvalidValue when given an invalid value" do
1180
+ proc{@db.typecast_value(:integer, "13a")}.should raise_error(Sequel::Error::InvalidValue)
1181
+ proc{@db.typecast_value(:float, "4.e2")}.should raise_error(Sequel::Error::InvalidValue)
1182
+ proc{@db.typecast_value(:decimal, :invalid_value)}.should raise_error(Sequel::Error::InvalidValue)
1183
+ proc{@db.typecast_value(:date, Object.new)}.should raise_error(Sequel::Error::InvalidValue)
1184
+ proc{@db.typecast_value(:date, 'a')}.should raise_error(Sequel::Error::InvalidValue)
1185
+ proc{@db.typecast_value(:time, Date.new)}.should raise_error(Sequel::Error::InvalidValue)
1186
+ proc{@db.typecast_value(:datetime, 4)}.should raise_error(Sequel::Error::InvalidValue)
1187
+ end
1188
+ end