epugh-sequel 0.0.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 (134) hide show
  1. data/README.rdoc +652 -0
  2. data/VERSION.yml +4 -0
  3. data/bin/sequel +104 -0
  4. data/lib/sequel.rb +1 -0
  5. data/lib/sequel/adapters/ado.rb +85 -0
  6. data/lib/sequel/adapters/db2.rb +132 -0
  7. data/lib/sequel/adapters/dbi.rb +101 -0
  8. data/lib/sequel/adapters/do.rb +197 -0
  9. data/lib/sequel/adapters/do/mysql.rb +38 -0
  10. data/lib/sequel/adapters/do/postgres.rb +92 -0
  11. data/lib/sequel/adapters/do/sqlite.rb +31 -0
  12. data/lib/sequel/adapters/firebird.rb +307 -0
  13. data/lib/sequel/adapters/informix.rb +75 -0
  14. data/lib/sequel/adapters/jdbc.rb +485 -0
  15. data/lib/sequel/adapters/jdbc/h2.rb +62 -0
  16. data/lib/sequel/adapters/jdbc/mysql.rb +56 -0
  17. data/lib/sequel/adapters/jdbc/oracle.rb +23 -0
  18. data/lib/sequel/adapters/jdbc/postgresql.rb +101 -0
  19. data/lib/sequel/adapters/jdbc/sqlite.rb +43 -0
  20. data/lib/sequel/adapters/mysql.rb +370 -0
  21. data/lib/sequel/adapters/odbc.rb +184 -0
  22. data/lib/sequel/adapters/openbase.rb +57 -0
  23. data/lib/sequel/adapters/oracle.rb +140 -0
  24. data/lib/sequel/adapters/postgres.rb +453 -0
  25. data/lib/sequel/adapters/shared/mssql.rb +93 -0
  26. data/lib/sequel/adapters/shared/mysql.rb +341 -0
  27. data/lib/sequel/adapters/shared/oracle.rb +62 -0
  28. data/lib/sequel/adapters/shared/postgres.rb +743 -0
  29. data/lib/sequel/adapters/shared/progress.rb +34 -0
  30. data/lib/sequel/adapters/shared/sqlite.rb +263 -0
  31. data/lib/sequel/adapters/sqlite.rb +243 -0
  32. data/lib/sequel/adapters/utils/date_format.rb +21 -0
  33. data/lib/sequel/adapters/utils/stored_procedures.rb +75 -0
  34. data/lib/sequel/adapters/utils/unsupported.rb +62 -0
  35. data/lib/sequel/connection_pool.rb +258 -0
  36. data/lib/sequel/core.rb +204 -0
  37. data/lib/sequel/core_sql.rb +185 -0
  38. data/lib/sequel/database.rb +687 -0
  39. data/lib/sequel/database/schema_generator.rb +324 -0
  40. data/lib/sequel/database/schema_methods.rb +164 -0
  41. data/lib/sequel/database/schema_sql.rb +324 -0
  42. data/lib/sequel/dataset.rb +422 -0
  43. data/lib/sequel/dataset/convenience.rb +237 -0
  44. data/lib/sequel/dataset/prepared_statements.rb +220 -0
  45. data/lib/sequel/dataset/sql.rb +1105 -0
  46. data/lib/sequel/deprecated.rb +529 -0
  47. data/lib/sequel/exceptions.rb +44 -0
  48. data/lib/sequel/extensions/blank.rb +42 -0
  49. data/lib/sequel/extensions/inflector.rb +288 -0
  50. data/lib/sequel/extensions/pagination.rb +96 -0
  51. data/lib/sequel/extensions/pretty_table.rb +78 -0
  52. data/lib/sequel/extensions/query.rb +48 -0
  53. data/lib/sequel/extensions/string_date_time.rb +47 -0
  54. data/lib/sequel/metaprogramming.rb +44 -0
  55. data/lib/sequel/migration.rb +212 -0
  56. data/lib/sequel/model.rb +142 -0
  57. data/lib/sequel/model/association_reflection.rb +263 -0
  58. data/lib/sequel/model/associations.rb +1024 -0
  59. data/lib/sequel/model/base.rb +911 -0
  60. data/lib/sequel/model/deprecated.rb +188 -0
  61. data/lib/sequel/model/deprecated_hooks.rb +103 -0
  62. data/lib/sequel/model/deprecated_inflector.rb +335 -0
  63. data/lib/sequel/model/deprecated_validations.rb +384 -0
  64. data/lib/sequel/model/errors.rb +37 -0
  65. data/lib/sequel/model/exceptions.rb +7 -0
  66. data/lib/sequel/model/inflections.rb +230 -0
  67. data/lib/sequel/model/plugins.rb +74 -0
  68. data/lib/sequel/object_graph.rb +230 -0
  69. data/lib/sequel/plugins/caching.rb +122 -0
  70. data/lib/sequel/plugins/hook_class_methods.rb +122 -0
  71. data/lib/sequel/plugins/schema.rb +53 -0
  72. data/lib/sequel/plugins/single_table_inheritance.rb +63 -0
  73. data/lib/sequel/plugins/validation_class_methods.rb +373 -0
  74. data/lib/sequel/sql.rb +854 -0
  75. data/lib/sequel/version.rb +11 -0
  76. data/lib/sequel_core.rb +1 -0
  77. data/lib/sequel_model.rb +1 -0
  78. data/spec/adapters/ado_spec.rb +46 -0
  79. data/spec/adapters/firebird_spec.rb +376 -0
  80. data/spec/adapters/informix_spec.rb +96 -0
  81. data/spec/adapters/mysql_spec.rb +875 -0
  82. data/spec/adapters/oracle_spec.rb +272 -0
  83. data/spec/adapters/postgres_spec.rb +692 -0
  84. data/spec/adapters/spec_helper.rb +10 -0
  85. data/spec/adapters/sqlite_spec.rb +550 -0
  86. data/spec/core/connection_pool_spec.rb +526 -0
  87. data/spec/core/core_ext_spec.rb +156 -0
  88. data/spec/core/core_sql_spec.rb +528 -0
  89. data/spec/core/database_spec.rb +1214 -0
  90. data/spec/core/dataset_spec.rb +3513 -0
  91. data/spec/core/expression_filters_spec.rb +363 -0
  92. data/spec/core/migration_spec.rb +261 -0
  93. data/spec/core/object_graph_spec.rb +280 -0
  94. data/spec/core/pretty_table_spec.rb +58 -0
  95. data/spec/core/schema_generator_spec.rb +167 -0
  96. data/spec/core/schema_spec.rb +778 -0
  97. data/spec/core/spec_helper.rb +82 -0
  98. data/spec/core/version_spec.rb +7 -0
  99. data/spec/extensions/blank_spec.rb +67 -0
  100. data/spec/extensions/caching_spec.rb +201 -0
  101. data/spec/extensions/hook_class_methods_spec.rb +470 -0
  102. data/spec/extensions/inflector_spec.rb +122 -0
  103. data/spec/extensions/pagination_spec.rb +99 -0
  104. data/spec/extensions/pretty_table_spec.rb +91 -0
  105. data/spec/extensions/query_spec.rb +85 -0
  106. data/spec/extensions/schema_spec.rb +111 -0
  107. data/spec/extensions/single_table_inheritance_spec.rb +53 -0
  108. data/spec/extensions/spec_helper.rb +90 -0
  109. data/spec/extensions/string_date_time_spec.rb +93 -0
  110. data/spec/extensions/validation_class_methods_spec.rb +1054 -0
  111. data/spec/integration/dataset_test.rb +160 -0
  112. data/spec/integration/eager_loader_test.rb +683 -0
  113. data/spec/integration/prepared_statement_test.rb +130 -0
  114. data/spec/integration/schema_test.rb +183 -0
  115. data/spec/integration/spec_helper.rb +75 -0
  116. data/spec/integration/type_test.rb +96 -0
  117. data/spec/model/association_reflection_spec.rb +93 -0
  118. data/spec/model/associations_spec.rb +1780 -0
  119. data/spec/model/base_spec.rb +494 -0
  120. data/spec/model/caching_spec.rb +217 -0
  121. data/spec/model/dataset_methods_spec.rb +78 -0
  122. data/spec/model/eager_loading_spec.rb +1165 -0
  123. data/spec/model/hooks_spec.rb +472 -0
  124. data/spec/model/inflector_spec.rb +126 -0
  125. data/spec/model/model_spec.rb +588 -0
  126. data/spec/model/plugins_spec.rb +142 -0
  127. data/spec/model/record_spec.rb +1243 -0
  128. data/spec/model/schema_spec.rb +92 -0
  129. data/spec/model/spec_helper.rb +124 -0
  130. data/spec/model/validations_spec.rb +1080 -0
  131. data/spec/rcov.opts +6 -0
  132. data/spec/spec.opts +0 -0
  133. data/spec/spec_config.rb.example +10 -0
  134. metadata +202 -0
@@ -0,0 +1,1214 @@
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
+ deprec_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
+ deprec_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.identifier_output_method is not called" 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
+ p.should_receive(:disconnect).once.and_return(2)
224
+ d.disconnect.should == 2
225
+ end
226
+ end
227
+
228
+ context "Database#connect" do
229
+ specify "should raise Sequel::Error::NotImplemented" do
230
+ proc {Sequel::Database.new.connect}.should raise_error(NotImplementedError)
231
+ end
232
+ end
233
+
234
+ context "Database#uri" do
235
+ setup do
236
+ @c = Class.new(Sequel::Database) do
237
+ set_adapter_scheme :mau
238
+ end
239
+
240
+ @db = Sequel.connect('mau://user:pass@localhost:9876/maumau')
241
+ end
242
+
243
+ specify "should return the connection URI for the database" do
244
+ @db.uri.should == 'mau://user:pass@localhost:9876/maumau'
245
+ end
246
+
247
+ specify "should be aliased as #url" do
248
+ @db.url.should == 'mau://user:pass@localhost:9876/maumau'
249
+ end
250
+ end
251
+
252
+ context "Database.adapter_scheme" do
253
+ specify "should return the database schema" do
254
+ Sequel::Database.adapter_scheme.should be_nil
255
+
256
+ @c = Class.new(Sequel::Database) do
257
+ set_adapter_scheme :mau
258
+ end
259
+
260
+ @c.adapter_scheme.should == :mau
261
+ end
262
+ end
263
+
264
+ context "Database#dataset" do
265
+ setup do
266
+ @db = Sequel::Database.new
267
+ @ds = @db.dataset
268
+ end
269
+
270
+ specify "should provide a blank dataset through #dataset" do
271
+ @ds.should be_a_kind_of(Sequel::Dataset)
272
+ @ds.opts.should == {}
273
+ @ds.db.should be(@db)
274
+ end
275
+
276
+ specify "should provide a #from dataset" do
277
+ d = @db.from(:mau)
278
+ d.should be_a_kind_of(Sequel::Dataset)
279
+ d.sql.should == 'SELECT * FROM mau'
280
+
281
+ e = @db[:miu]
282
+ e.should be_a_kind_of(Sequel::Dataset)
283
+ e.sql.should == 'SELECT * FROM miu'
284
+ end
285
+
286
+ specify "should provide a filtered #from dataset if a block is given" do
287
+ d = @db.from(:mau) {:x.sql_number > 100}
288
+ d.should be_a_kind_of(Sequel::Dataset)
289
+ d.sql.should == 'SELECT * FROM mau WHERE (x > 100)'
290
+ end
291
+
292
+ specify "should provide a #select dataset" do
293
+ d = @db.select(:a, :b, :c).from(:mau)
294
+ d.should be_a_kind_of(Sequel::Dataset)
295
+ d.sql.should == 'SELECT a, b, c FROM mau'
296
+ end
297
+
298
+ specify "should allow #select to take a block" do
299
+ d = @db.select(:a, :b){c}.from(:mau)
300
+ d.should be_a_kind_of(Sequel::Dataset)
301
+ d.sql.should == 'SELECT a, b, c FROM mau'
302
+ end
303
+ end
304
+
305
+ context "Database#execute" do
306
+ specify "should raise Sequel::Error::NotImplemented" do
307
+ proc {Sequel::Database.new.execute('blah blah')}.should raise_error(NotImplementedError)
308
+ proc {Sequel::Database.new << 'blah blah'}.should raise_error(NotImplementedError)
309
+ end
310
+ end
311
+
312
+ context "Database#<<" do
313
+ setup do
314
+ @c = Class.new(Sequel::Database) do
315
+ define_method(:execute) {|sql, opts| sql}
316
+ end
317
+ @db = @c.new({})
318
+ end
319
+
320
+ specify "should pass the supplied sql to #execute" do
321
+ (@db << "DELETE FROM items").should == "DELETE FROM items"
322
+ end
323
+
324
+ deprec_specify "should accept an array and convert it to SQL" do
325
+ a = %[
326
+ --
327
+ CREATE TABLE items (a integer, /*b integer*/
328
+ b text, c integer);
329
+ DROP TABLE old_items;
330
+ ].split($/)
331
+ (@db << a).should ==
332
+ "CREATE TABLE items (a integer, b text, c integer); DROP TABLE old_items;"
333
+ end
334
+
335
+ deprec_specify "should remove comments and whitespace from arrays" do
336
+ s = %[
337
+ --
338
+ CREATE TABLE items (a integer, /*b integer*/
339
+ b text, c integer); \r\n
340
+ DROP TABLE old_items;
341
+ ].split($/)
342
+ (@db << s).should ==
343
+ "CREATE TABLE items (a integer, b text, c integer); DROP TABLE old_items;"
344
+ end
345
+
346
+ specify "should not remove comments and whitespace from strings" do
347
+ s = "INSERT INTO items VALUES ('---abc')"
348
+ (@db << s).should == s
349
+ end
350
+ end
351
+
352
+ context "Database#synchronize" do
353
+ setup do
354
+ @db = Sequel::Database.new(:max_connections => 1)
355
+ @db.pool.connection_proc = proc {12345}
356
+ end
357
+
358
+ specify "should wrap the supplied block in pool.hold" do
359
+ stop = false
360
+ c1, c2 = nil
361
+ t1 = Thread.new {@db.synchronize {|c| c1 = c; while !stop;sleep 0.1;end}}
362
+ while !c1;end
363
+ c1.should == 12345
364
+ t2 = Thread.new {@db.synchronize {|c| c2 = c}}
365
+ sleep 0.2
366
+ @db.pool.available_connections.should be_empty
367
+ c2.should be_nil
368
+ stop = true
369
+ t1.join
370
+ sleep 0.1
371
+ c2.should == 12345
372
+ t2.join
373
+ end
374
+ end
375
+
376
+ context "Database#test_connection" do
377
+ setup do
378
+ @db = Sequel::Database.new
379
+ @test = nil
380
+ @db.pool.connection_proc = proc {@test = rand(100)}
381
+ end
382
+
383
+ specify "should call pool#hold" do
384
+ @db.test_connection
385
+ @test.should_not be_nil
386
+ end
387
+
388
+ specify "should return true if successful" do
389
+ @db.test_connection.should be_true
390
+ end
391
+ end
392
+
393
+ class DummyDataset < Sequel::Dataset
394
+ def first
395
+ raise if @opts[:from] == [:a]
396
+ true
397
+ end
398
+ end
399
+
400
+ class DummyDatabase < Sequel::Database
401
+ attr_reader :sqls
402
+
403
+ def execute(sql, opts={})
404
+ @sqls ||= []
405
+ @sqls << sql
406
+ end
407
+
408
+ def transaction; yield; end
409
+
410
+ def dataset
411
+ DummyDataset.new(self)
412
+ end
413
+ end
414
+
415
+ context "Database#create_table" do
416
+ setup do
417
+ @db = DummyDatabase.new
418
+ end
419
+
420
+ specify "should construct proper SQL" do
421
+ @db.create_table :test do
422
+ primary_key :id, :integer, :null => false
423
+ column :name, :text
424
+ index :name, :unique => true
425
+ end
426
+ @db.sqls.should == [
427
+ 'CREATE TABLE test (id integer NOT NULL PRIMARY KEY AUTOINCREMENT, name text)',
428
+ 'CREATE UNIQUE INDEX test_name_index ON test (name)'
429
+ ]
430
+ end
431
+ end
432
+
433
+ context "Database#alter_table" do
434
+ setup do
435
+ @db = DummyDatabase.new
436
+ end
437
+
438
+ specify "should construct proper SQL" do
439
+ @db.alter_table :xyz do
440
+ add_column :aaa, :text, :null => false, :unique => true
441
+ drop_column :bbb
442
+ rename_column :ccc, :ddd
443
+ set_column_type :eee, :integer
444
+ set_column_default :hhh, 'abcd'
445
+
446
+ add_index :fff, :unique => true
447
+ drop_index :ggg
448
+ end
449
+
450
+ @db.sqls.should == [
451
+ 'ALTER TABLE xyz ADD COLUMN aaa text UNIQUE NOT NULL',
452
+ 'ALTER TABLE xyz DROP COLUMN bbb',
453
+ 'ALTER TABLE xyz RENAME COLUMN ccc TO ddd',
454
+ 'ALTER TABLE xyz ALTER COLUMN eee TYPE integer',
455
+ "ALTER TABLE xyz ALTER COLUMN hhh SET DEFAULT 'abcd'",
456
+
457
+ 'CREATE UNIQUE INDEX xyz_fff_index ON xyz (fff)',
458
+ 'DROP INDEX xyz_ggg_index'
459
+ ]
460
+ end
461
+ end
462
+
463
+ context "Database#add_column" do
464
+ setup do
465
+ @db = DummyDatabase.new
466
+ end
467
+
468
+ specify "should construct proper SQL" do
469
+ @db.add_column :test, :name, :text, :unique => true
470
+ @db.sqls.should == [
471
+ 'ALTER TABLE test ADD COLUMN name text UNIQUE'
472
+ ]
473
+ end
474
+ end
475
+
476
+ context "Database#drop_column" do
477
+ setup do
478
+ @db = DummyDatabase.new
479
+ end
480
+
481
+ specify "should construct proper SQL" do
482
+ @db.drop_column :test, :name
483
+ @db.sqls.should == [
484
+ 'ALTER TABLE test DROP COLUMN name'
485
+ ]
486
+ end
487
+ end
488
+
489
+ context "Database#rename_column" do
490
+ setup do
491
+ @db = DummyDatabase.new
492
+ end
493
+
494
+ specify "should construct proper SQL" do
495
+ @db.rename_column :test, :abc, :def
496
+ @db.sqls.should == [
497
+ 'ALTER TABLE test RENAME COLUMN abc TO def'
498
+ ]
499
+ end
500
+ end
501
+
502
+ context "Database#set_column_type" do
503
+ setup do
504
+ @db = DummyDatabase.new
505
+ end
506
+
507
+ specify "should construct proper SQL" do
508
+ @db.set_column_type :test, :name, :integer
509
+ @db.sqls.should == [
510
+ 'ALTER TABLE test ALTER COLUMN name TYPE integer'
511
+ ]
512
+ end
513
+ end
514
+
515
+ context "Database#set_column_default" do
516
+ setup do
517
+ @db = DummyDatabase.new
518
+ end
519
+
520
+ specify "should construct proper SQL" do
521
+ @db.set_column_default :test, :name, 'zyx'
522
+ @db.sqls.should == [
523
+ "ALTER TABLE test ALTER COLUMN name SET DEFAULT 'zyx'"
524
+ ]
525
+ end
526
+ end
527
+
528
+ context "Database#add_index" do
529
+ setup do
530
+ @db = DummyDatabase.new
531
+ end
532
+
533
+ specify "should construct proper SQL" do
534
+ @db.add_index :test, :name, :unique => true
535
+ @db.sqls.should == [
536
+ 'CREATE UNIQUE INDEX test_name_index ON test (name)'
537
+ ]
538
+ end
539
+
540
+ specify "should accept multiple columns" do
541
+ @db.add_index :test, [:one, :two]
542
+ @db.sqls.should == [
543
+ 'CREATE INDEX test_one_two_index ON test (one, two)'
544
+ ]
545
+ end
546
+ end
547
+
548
+ context "Database#drop_index" do
549
+ setup do
550
+ @db = DummyDatabase.new
551
+ end
552
+
553
+ specify "should construct proper SQL" do
554
+ @db.drop_index :test, :name
555
+ @db.sqls.should == [
556
+ 'DROP INDEX test_name_index'
557
+ ]
558
+ end
559
+
560
+ end
561
+
562
+ class Dummy2Database < Sequel::Database
563
+ attr_reader :sql
564
+ def execute(sql); @sql = sql; end
565
+ def transaction; yield; end
566
+ end
567
+
568
+ context "Database#drop_table" do
569
+ setup do
570
+ @db = DummyDatabase.new
571
+ end
572
+
573
+ specify "should construct proper SQL" do
574
+ @db.drop_table :test
575
+ @db.sqls.should == ['DROP TABLE test']
576
+ end
577
+
578
+ specify "should accept multiple table names" do
579
+ @db.drop_table :a, :bb, :ccc
580
+ @db.sqls.should == [
581
+ 'DROP TABLE a',
582
+ 'DROP TABLE bb',
583
+ 'DROP TABLE ccc'
584
+ ]
585
+ end
586
+ end
587
+
588
+ context "Database#rename_table" do
589
+ setup do
590
+ @db = DummyDatabase.new
591
+ end
592
+
593
+ specify "should construct proper SQL" do
594
+ @db.rename_table :abc, :xyz
595
+ @db.sqls.should == ['ALTER TABLE abc RENAME TO xyz']
596
+ end
597
+ end
598
+
599
+ context "Database#table_exists?" do
600
+ setup do
601
+ @db = DummyDatabase.new
602
+ @db.instance_variable_set(:@schemas, {:a=>[]})
603
+ @db2 = DummyDatabase.new
604
+ end
605
+
606
+ specify "should use schema information if available" do
607
+ @db.table_exists?(:a).should be_true
608
+ end
609
+
610
+ specify "should otherwise try to select the first record from the table's dataset" do
611
+ @db2.table_exists?(:a).should be_false
612
+ @db2.table_exists?(:b).should be_true
613
+ end
614
+ end
615
+
616
+ class Dummy3Database < Sequel::Database
617
+ attr_reader :sql, :transactions
618
+ def execute(sql, opts={}); @sql ||= []; @sql << sql; end
619
+
620
+ class DummyConnection
621
+ def initialize(db); @db = db; end
622
+ def execute(sql); @db.execute(sql); end
623
+ end
624
+ end
625
+
626
+ context "Database#transaction" do
627
+ setup do
628
+ @db = Dummy3Database.new
629
+ @db.pool.connection_proc = proc {Dummy3Database::DummyConnection.new(@db)}
630
+ end
631
+
632
+ specify "should wrap the supplied block with BEGIN + COMMIT statements" do
633
+ @db.transaction {@db.execute 'DROP TABLE test;'}
634
+ @db.sql.should == ['BEGIN', 'DROP TABLE test;', 'COMMIT']
635
+ end
636
+
637
+ specify "should handle returning inside of the block by committing" do
638
+ def @db.ret_commit
639
+ transaction do
640
+ execute 'DROP TABLE test;'
641
+ return
642
+ execute 'DROP TABLE test2;';
643
+ end
644
+ end
645
+ @db.ret_commit
646
+ @db.sql.should == ['BEGIN', 'DROP TABLE test;', 'COMMIT']
647
+ end
648
+
649
+ specify "should issue ROLLBACK if an exception is raised, and re-raise" do
650
+ @db.transaction {@db.execute 'DROP TABLE test'; raise RuntimeError} rescue nil
651
+ @db.sql.should == ['BEGIN', 'DROP TABLE test', 'ROLLBACK']
652
+
653
+ proc {@db.transaction {raise RuntimeError}}.should raise_error(RuntimeError)
654
+ end
655
+
656
+ specify "should issue ROLLBACK if Sequel::Error::Rollback is called in the transaction" do
657
+ @db.transaction do
658
+ @db.drop_table(:a)
659
+ raise Sequel::Error::Rollback
660
+ @db.drop_table(:b)
661
+ end
662
+
663
+ @db.sql.should == ['BEGIN', 'DROP TABLE a', 'ROLLBACK']
664
+ end
665
+
666
+ specify "should be re-entrant" do
667
+ stop = false
668
+ cc = nil
669
+ t = Thread.new do
670
+ @db.transaction {@db.transaction {@db.transaction {|c|
671
+ cc = c
672
+ while !stop; sleep 0.1; end
673
+ }}}
674
+ end
675
+ while cc.nil?; sleep 0.1; end
676
+ cc.should be_a_kind_of(Dummy3Database::DummyConnection)
677
+ @db.transactions.should == [t]
678
+ stop = true
679
+ t.join
680
+ @db.transactions.should be_empty
681
+ end
682
+ end
683
+
684
+ class Sequel::Database
685
+ def self.get_adapters; @@adapters; end
686
+ end
687
+
688
+ context "A Database adapter with a scheme" do
689
+ setup do
690
+ class CCC < Sequel::Database
691
+ if defined?(DISCONNECTS)
692
+ DISCONNECTS.clear
693
+ else
694
+ DISCONNECTS = []
695
+ end
696
+ set_adapter_scheme :ccc
697
+ def disconnect
698
+ DISCONNECTS << self
699
+ end
700
+ end
701
+ end
702
+
703
+ specify "should be registered in adapters" do
704
+ Sequel::Database.get_adapters[:ccc].should == CCC
705
+ end
706
+
707
+ specify "should be instantiated when its scheme is specified" do
708
+ c = Sequel::Database.connect('ccc://localhost/db')
709
+ c.should be_a_kind_of(CCC)
710
+ c.opts[:host].should == 'localhost'
711
+ c.opts[:database].should == 'db'
712
+ end
713
+
714
+ specify "should be accessible through Sequel.connect" do
715
+ c = Sequel.connect 'ccc://localhost/db'
716
+ c.should be_a_kind_of(CCC)
717
+ c.opts[:host].should == 'localhost'
718
+ c.opts[:database].should == 'db'
719
+ end
720
+
721
+ specify "should be accessible through Sequel.connect via a block" do
722
+ x = nil
723
+ y = nil
724
+ z = nil
725
+
726
+ p = proc do |c|
727
+ c.should be_a_kind_of(CCC)
728
+ c.opts[:host].should == 'localhost'
729
+ c.opts[:database].should == 'db'
730
+ z = y
731
+ y = x
732
+ x = c
733
+ end
734
+ Sequel::Database.connect('ccc://localhost/db', &p).should == nil
735
+ CCC::DISCONNECTS.should == [x]
736
+
737
+ Sequel.connect('ccc://localhost/db', &p).should == nil
738
+ CCC::DISCONNECTS.should == [y, x]
739
+
740
+ Sequel.send(:def_adapter_method, :ccc)
741
+ Sequel.ccc('db', :host=>'localhost', &p).should == nil
742
+ CCC::DISCONNECTS.should == [z, y, x]
743
+ end
744
+
745
+ deprec_specify "should be accessible through Sequel.open" do
746
+ c = Sequel.open 'ccc://localhost/db'
747
+ c.should be_a_kind_of(CCC)
748
+ c.opts[:host].should == 'localhost'
749
+ c.opts[:database].should == 'db'
750
+ end
751
+
752
+ specify "should be accessible through Sequel.<adapter>" do
753
+ Sequel.send(:def_adapter_method, :ccc)
754
+
755
+ # invalid parameters
756
+ proc {Sequel.ccc('abc', 'def')}.should raise_error(Sequel::Error)
757
+
758
+ c = Sequel.ccc('mydb')
759
+ c.should be_a_kind_of(CCC)
760
+ c.opts.should == {:adapter=>:ccc, :database => 'mydb'}
761
+
762
+ c = Sequel.ccc('mydb', :host => 'localhost')
763
+ c.should be_a_kind_of(CCC)
764
+ c.opts.should == {:adapter=>:ccc, :database => 'mydb', :host => 'localhost'}
765
+
766
+ c = Sequel.ccc
767
+ c.should be_a_kind_of(CCC)
768
+ c.opts.should == {:adapter=>:ccc}
769
+
770
+ c = Sequel.ccc(:database => 'mydb', :host => 'localhost')
771
+ c.should be_a_kind_of(CCC)
772
+ c.opts.should == {:adapter=>:ccc, :database => 'mydb', :host => 'localhost'}
773
+ end
774
+
775
+ specify "should be accessible through Sequel.connect with options" do
776
+ c = Sequel.connect(:adapter => :ccc, :database => 'mydb')
777
+ c.should be_a_kind_of(CCC)
778
+ c.opts.should == {:adapter => :ccc, :database => 'mydb'}
779
+ end
780
+
781
+ specify "should be accessible through Sequel.connect with URL parameters" do
782
+ c = Sequel.connect 'ccc://localhost/db?host=/tmp&user=test'
783
+ c.should be_a_kind_of(CCC)
784
+ c.opts[:host].should == '/tmp'
785
+ c.opts[:database].should == 'db'
786
+ c.opts[:user].should == 'test'
787
+ end
788
+
789
+ end
790
+
791
+ context "An unknown database scheme" do
792
+ specify "should raise an error in Sequel::Database.connect" do
793
+ proc {Sequel::Database.connect('ddd://localhost/db')}.should raise_error(Sequel::Error::AdapterNotFound)
794
+ end
795
+
796
+ specify "should raise an error in Sequel.connect" do
797
+ proc {Sequel.connect('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/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
+ deprec_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
+ @db.sqls.clear
1017
+ @db.create_view :test.identifier, "SELECT * FROM xyz"
1018
+ @db.sqls.should == ['CREATE VIEW test AS SELECT * FROM xyz']
1019
+ end
1020
+
1021
+ specify "should construct proper SQL with dataset" do
1022
+ @db.create_view :test, @db[:items].select(:a, :b).order(:c)
1023
+ @db.sqls.should == ['CREATE VIEW test AS SELECT a, b FROM items ORDER BY c']
1024
+ @db.sqls.clear
1025
+ @db.create_view :test.qualify(:sch), @db[:items].select(:a, :b).order(:c)
1026
+ @db.sqls.should == ['CREATE VIEW sch.test AS SELECT a, b FROM items ORDER BY c']
1027
+ end
1028
+ end
1029
+
1030
+ context "Database#create_or_replace_view" do
1031
+ setup do
1032
+ @db = DummyDatabase.new
1033
+ end
1034
+
1035
+ specify "should construct proper SQL with raw SQL" do
1036
+ @db.create_or_replace_view :test, "SELECT * FROM xyz"
1037
+ @db.sqls.should == ['CREATE OR REPLACE VIEW test AS SELECT * FROM xyz']
1038
+ @db.sqls.clear
1039
+ @db.create_or_replace_view :sch__test, "SELECT * FROM xyz"
1040
+ @db.sqls.should == ['CREATE OR REPLACE VIEW sch.test AS SELECT * FROM xyz']
1041
+ end
1042
+
1043
+ specify "should construct proper SQL with dataset" do
1044
+ @db.create_or_replace_view :test, @db[:items].select(:a, :b).order(:c)
1045
+ @db.sqls.should == ['CREATE OR REPLACE VIEW test AS SELECT a, b FROM items ORDER BY c']
1046
+ @db.sqls.clear
1047
+ @db.create_or_replace_view :test.identifier, @db[:items].select(:a, :b).order(:c)
1048
+ @db.sqls.should == ['CREATE OR REPLACE VIEW test AS SELECT a, b FROM items ORDER BY c']
1049
+ end
1050
+ end
1051
+
1052
+ context "Database#drop_view" do
1053
+ setup do
1054
+ @db = DummyDatabase.new
1055
+ end
1056
+
1057
+ specify "should construct proper SQL" do
1058
+ @db.drop_view :test
1059
+ @db.drop_view :test.identifier
1060
+ @db.drop_view :sch__test
1061
+ @db.drop_view :test.qualify(:sch)
1062
+ @db.sqls.should == ['DROP VIEW test', 'DROP VIEW test', 'DROP VIEW sch.test', 'DROP VIEW sch.test']
1063
+ end
1064
+ end
1065
+
1066
+ # TODO: beaf this up with specs for all supported ops
1067
+ context "Database#alter_table_sql" do
1068
+ setup do
1069
+ @db = DummyDatabase.new
1070
+ end
1071
+
1072
+ specify "should raise error for an invalid op" do
1073
+ proc {@db.alter_table_sql(:mau, :op => :blah)}.should raise_error(Sequel::Error)
1074
+ end
1075
+ end
1076
+
1077
+ context "Database.connect" do
1078
+ 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"
1079
+
1080
+ setup do
1081
+ class EEE < Sequel::Database
1082
+ set_adapter_scheme :eee
1083
+ end
1084
+
1085
+ @fn = File.join(File.dirname(__FILE__), 'eee.yaml')
1086
+ File.open(@fn, 'wb') {|f| f << EEE_YAML}
1087
+ end
1088
+
1089
+ teardown do
1090
+ File.delete(@fn)
1091
+ end
1092
+
1093
+ specify "should accept hashes loaded from YAML files" do
1094
+ db = Sequel.connect(YAML.load_file(@fn)['development'])
1095
+ db.class.should == EEE
1096
+ db.opts[:database].should == 'mydb'
1097
+ db.opts[:user].should == 'mau'
1098
+ db.opts[:password].should == 'tau'
1099
+ db.opts[:host].should == 'alfonso'
1100
+ end
1101
+ end
1102
+
1103
+ context "Database#inspect" do
1104
+ setup do
1105
+ @db = DummyDatabase.new
1106
+
1107
+ @db.meta_def(:uri) {'blah://blahblah/blah'}
1108
+ end
1109
+
1110
+ specify "should include the class name and the connection url" do
1111
+ @db.inspect.should == '#<DummyDatabase: "blah://blahblah/blah">'
1112
+ end
1113
+ end
1114
+
1115
+ context "Database#get" do
1116
+ setup do
1117
+ @c = Class.new(DummyDatabase) do
1118
+ def dataset
1119
+ ds = super
1120
+ def ds.get(*args, &block)
1121
+ @db.execute select(*args, &block).sql
1122
+ args
1123
+ end
1124
+ ds
1125
+ end
1126
+ end
1127
+
1128
+ @db = @c.new
1129
+ end
1130
+
1131
+ specify "should use Dataset#get to get a single value" do
1132
+ @db.get(1).should == [1]
1133
+ @db.sqls.last.should == 'SELECT 1'
1134
+
1135
+ @db.get(:version.sql_function)
1136
+ @db.sqls.last.should == 'SELECT version()'
1137
+ end
1138
+
1139
+ specify "should accept a block" do
1140
+ @db.get{1}
1141
+ @db.sqls.last.should == 'SELECT 1'
1142
+
1143
+ @db.get{version(1)}
1144
+ @db.sqls.last.should == 'SELECT version(1)'
1145
+ end
1146
+ end
1147
+
1148
+ context "Database#call" do
1149
+ specify "should call the prepared statement with the given name" do
1150
+ db = MockDatabase.new
1151
+ db[:items].prepare(:select, :select_all)
1152
+ db.call(:select_all).should == [{:id => 1, :x => 1}]
1153
+ db[:items].filter(:n=>:$n).prepare(:select, :select_n)
1154
+ db.call(:select_n, :n=>1).should == [{:id => 1, :x => 1}]
1155
+ db.sqls.should == ['SELECT * FROM items', 'SELECT * FROM items WHERE (n = 1)']
1156
+ end
1157
+ end
1158
+
1159
+ context "Database#server_opts" do
1160
+ specify "should return the general opts if no :servers option is used" do
1161
+ opts = {:host=>1, :database=>2}
1162
+ MockDatabase.new(opts).send(:server_opts, :server1).should == {:host=>1, :database=>2}
1163
+ end
1164
+
1165
+ specify "should return the general opts if entry for the server is present in the :servers option" do
1166
+ opts = {:host=>1, :database=>2, :servers=>{}}
1167
+ MockDatabase.new(opts).send(:server_opts, :server1).should == {:host=>1, :database=>2}
1168
+ end
1169
+
1170
+ specify "should return the general opts merged with the specific opts if given as a hash" do
1171
+ opts = {:host=>1, :database=>2, :servers=>{:server1=>{:host=>3}}}
1172
+ MockDatabase.new(opts).send(:server_opts, :server1).should == {:host=>3, :database=>2}
1173
+ end
1174
+
1175
+ specify "should return the sgeneral opts merged with the specific opts if given as a proc" do
1176
+ opts = {:host=>1, :database=>2, :servers=>{:server1=>proc{|db| {:host=>4}}}}
1177
+ MockDatabase.new(opts).send(:server_opts, :server1).should == {:host=>4, :database=>2}
1178
+ end
1179
+
1180
+ specify "should raise an error if the specific opts is not a proc or hash" do
1181
+ opts = {:host=>1, :database=>2, :servers=>{:server1=>2}}
1182
+ proc{MockDatabase.new(opts).send(:server_opts, :server1)}.should raise_error(Sequel::Error)
1183
+ end
1184
+ end
1185
+
1186
+ context "Database#raise_error" do
1187
+ specify "should reraise if the exception class is not in opts[:classes]" do
1188
+ e = Class.new(StandardError)
1189
+ proc{MockDatabase.new.send(:raise_error, e.new(''), :classes=>[])}.should raise_error(e)
1190
+ end
1191
+
1192
+ specify "should convert the exception to a DatabaseError if the exception class is not in opts[:classes]" do
1193
+ proc{MockDatabase.new.send(:raise_error, Interrupt.new(''), :classes=>[Interrupt])}.should raise_error(Sequel::DatabaseError)
1194
+ end
1195
+
1196
+ specify "should convert the exception to a DatabaseError if opts[:classes] if not present" do
1197
+ proc{MockDatabase.new.send(:raise_error, Interrupt.new(''))}.should raise_error(Sequel::DatabaseError)
1198
+ end
1199
+ end
1200
+
1201
+ context "Database#typecast_value" do
1202
+ setup do
1203
+ @db = Sequel::Database.new
1204
+ end
1205
+ specify "should raise an Error::InvalidValue when given an invalid value" do
1206
+ proc{@db.typecast_value(:integer, "13a")}.should raise_error(Sequel::Error::InvalidValue)
1207
+ proc{@db.typecast_value(:float, "4.e2")}.should raise_error(Sequel::Error::InvalidValue)
1208
+ proc{@db.typecast_value(:decimal, :invalid_value)}.should raise_error(Sequel::Error::InvalidValue)
1209
+ proc{@db.typecast_value(:date, Object.new)}.should raise_error(Sequel::Error::InvalidValue)
1210
+ proc{@db.typecast_value(:date, 'a')}.should raise_error(Sequel::Error::InvalidValue)
1211
+ proc{@db.typecast_value(:time, Date.new)}.should raise_error(Sequel::Error::InvalidValue)
1212
+ proc{@db.typecast_value(:datetime, 4)}.should raise_error(Sequel::Error::InvalidValue)
1213
+ end
1214
+ end