sequel 3.28.0 → 3.29.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +119 -3
- data/Rakefile +5 -3
- data/bin/sequel +1 -5
- data/doc/model_hooks.rdoc +9 -1
- data/doc/opening_databases.rdoc +49 -40
- data/doc/prepared_statements.rdoc +27 -6
- data/doc/release_notes/3.28.0.txt +2 -2
- data/doc/release_notes/3.29.0.txt +459 -0
- data/doc/sharding.rdoc +7 -1
- data/doc/testing.rdoc +18 -9
- data/doc/transactions.rdoc +41 -1
- data/lib/sequel/adapters/ado.rb +28 -17
- data/lib/sequel/adapters/ado/mssql.rb +18 -6
- data/lib/sequel/adapters/amalgalite.rb +11 -7
- data/lib/sequel/adapters/db2.rb +122 -70
- data/lib/sequel/adapters/dbi.rb +15 -15
- data/lib/sequel/adapters/do.rb +5 -36
- data/lib/sequel/adapters/do/mysql.rb +0 -5
- data/lib/sequel/adapters/do/postgres.rb +0 -5
- data/lib/sequel/adapters/do/sqlite.rb +0 -5
- data/lib/sequel/adapters/firebird.rb +3 -6
- data/lib/sequel/adapters/ibmdb.rb +24 -16
- data/lib/sequel/adapters/informix.rb +2 -4
- data/lib/sequel/adapters/jdbc.rb +47 -11
- data/lib/sequel/adapters/jdbc/as400.rb +5 -24
- data/lib/sequel/adapters/jdbc/db2.rb +0 -5
- data/lib/sequel/adapters/jdbc/derby.rb +217 -0
- data/lib/sequel/adapters/jdbc/firebird.rb +0 -5
- data/lib/sequel/adapters/jdbc/h2.rb +10 -12
- data/lib/sequel/adapters/jdbc/hsqldb.rb +166 -0
- data/lib/sequel/adapters/jdbc/informix.rb +0 -5
- data/lib/sequel/adapters/jdbc/jtds.rb +0 -5
- data/lib/sequel/adapters/jdbc/mysql.rb +0 -10
- data/lib/sequel/adapters/jdbc/oracle.rb +70 -3
- data/lib/sequel/adapters/jdbc/postgresql.rb +0 -11
- data/lib/sequel/adapters/jdbc/sqlite.rb +0 -5
- data/lib/sequel/adapters/jdbc/sqlserver.rb +0 -5
- data/lib/sequel/adapters/jdbc/transactions.rb +56 -7
- data/lib/sequel/adapters/mock.rb +315 -0
- data/lib/sequel/adapters/mysql.rb +64 -51
- data/lib/sequel/adapters/mysql2.rb +15 -9
- data/lib/sequel/adapters/odbc.rb +13 -6
- data/lib/sequel/adapters/odbc/db2.rb +0 -4
- data/lib/sequel/adapters/odbc/mssql.rb +0 -5
- data/lib/sequel/adapters/openbase.rb +2 -4
- data/lib/sequel/adapters/oracle.rb +333 -51
- data/lib/sequel/adapters/postgres.rb +80 -27
- data/lib/sequel/adapters/shared/access.rb +0 -6
- data/lib/sequel/adapters/shared/db2.rb +13 -15
- data/lib/sequel/adapters/shared/firebird.rb +6 -6
- data/lib/sequel/adapters/shared/mssql.rb +23 -18
- data/lib/sequel/adapters/shared/mysql.rb +6 -6
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +6 -0
- data/lib/sequel/adapters/shared/oracle.rb +185 -30
- data/lib/sequel/adapters/shared/postgres.rb +35 -18
- data/lib/sequel/adapters/shared/progress.rb +0 -6
- data/lib/sequel/adapters/shared/sqlite.rb +116 -37
- data/lib/sequel/adapters/sqlite.rb +16 -8
- data/lib/sequel/adapters/swift.rb +5 -5
- data/lib/sequel/adapters/swift/mysql.rb +0 -5
- data/lib/sequel/adapters/swift/postgres.rb +0 -5
- data/lib/sequel/adapters/swift/sqlite.rb +6 -4
- data/lib/sequel/adapters/tinytds.rb +13 -10
- data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +8 -0
- data/lib/sequel/core.rb +40 -0
- data/lib/sequel/database/connecting.rb +1 -2
- data/lib/sequel/database/dataset.rb +3 -3
- data/lib/sequel/database/dataset_defaults.rb +58 -0
- data/lib/sequel/database/misc.rb +62 -2
- data/lib/sequel/database/query.rb +113 -49
- data/lib/sequel/database/schema_methods.rb +7 -2
- data/lib/sequel/dataset/actions.rb +37 -19
- data/lib/sequel/dataset/features.rb +24 -0
- data/lib/sequel/dataset/graph.rb +7 -6
- data/lib/sequel/dataset/misc.rb +11 -3
- data/lib/sequel/dataset/mutation.rb +2 -3
- data/lib/sequel/dataset/prepared_statements.rb +6 -4
- data/lib/sequel/dataset/query.rb +46 -15
- data/lib/sequel/dataset/sql.rb +28 -4
- data/lib/sequel/extensions/named_timezones.rb +5 -0
- data/lib/sequel/extensions/thread_local_timezones.rb +1 -1
- data/lib/sequel/model.rb +2 -1
- data/lib/sequel/model/associations.rb +115 -33
- data/lib/sequel/model/base.rb +91 -31
- data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
- data/lib/sequel/plugins/dataset_associations.rb +100 -0
- data/lib/sequel/plugins/force_encoding.rb +6 -6
- data/lib/sequel/plugins/identity_map.rb +1 -1
- data/lib/sequel/plugins/many_through_many.rb +6 -10
- data/lib/sequel/plugins/prepared_statements.rb +12 -1
- data/lib/sequel/plugins/prepared_statements_associations.rb +1 -1
- data/lib/sequel/plugins/rcte_tree.rb +29 -15
- data/lib/sequel/plugins/serialization.rb +6 -1
- data/lib/sequel/plugins/sharding.rb +0 -5
- data/lib/sequel/plugins/single_table_inheritance.rb +1 -1
- data/lib/sequel/plugins/typecast_on_load.rb +9 -12
- data/lib/sequel/plugins/update_primary_key.rb +1 -1
- data/lib/sequel/timezones.rb +42 -42
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/mssql_spec.rb +29 -29
- data/spec/adapters/mysql_spec.rb +86 -104
- data/spec/adapters/oracle_spec.rb +48 -76
- data/spec/adapters/postgres_spec.rb +98 -33
- data/spec/adapters/spec_helper.rb +0 -5
- data/spec/adapters/sqlite_spec.rb +24 -21
- data/spec/core/connection_pool_spec.rb +9 -15
- data/spec/core/core_sql_spec.rb +20 -31
- data/spec/core/database_spec.rb +491 -227
- data/spec/core/dataset_spec.rb +638 -1051
- data/spec/core/expression_filters_spec.rb +0 -1
- data/spec/core/mock_adapter_spec.rb +378 -0
- data/spec/core/object_graph_spec.rb +48 -114
- data/spec/core/schema_generator_spec.rb +3 -3
- data/spec/core/schema_spec.rb +51 -114
- data/spec/core/spec_helper.rb +3 -90
- data/spec/extensions/class_table_inheritance_spec.rb +1 -1
- data/spec/extensions/dataset_associations_spec.rb +199 -0
- data/spec/extensions/instance_hooks_spec.rb +71 -0
- data/spec/extensions/named_timezones_spec.rb +22 -2
- data/spec/extensions/nested_attributes_spec.rb +3 -0
- data/spec/extensions/schema_spec.rb +1 -1
- data/spec/extensions/serialization_modification_detection_spec.rb +1 -0
- data/spec/extensions/serialization_spec.rb +5 -8
- data/spec/extensions/spec_helper.rb +4 -0
- data/spec/extensions/thread_local_timezones_spec.rb +22 -2
- data/spec/extensions/typecast_on_load_spec.rb +1 -6
- data/spec/integration/associations_test.rb +123 -12
- data/spec/integration/dataset_test.rb +140 -47
- data/spec/integration/eager_loader_test.rb +19 -21
- data/spec/integration/model_test.rb +80 -1
- data/spec/integration/plugin_test.rb +179 -128
- data/spec/integration/prepared_statement_test.rb +92 -91
- data/spec/integration/schema_test.rb +42 -23
- data/spec/integration/spec_helper.rb +25 -31
- data/spec/integration/timezone_test.rb +38 -12
- data/spec/integration/transaction_test.rb +161 -34
- data/spec/integration/type_test.rb +3 -3
- data/spec/model/association_reflection_spec.rb +83 -7
- data/spec/model/associations_spec.rb +393 -676
- data/spec/model/base_spec.rb +186 -116
- data/spec/model/dataset_methods_spec.rb +7 -27
- data/spec/model/eager_loading_spec.rb +343 -867
- data/spec/model/hooks_spec.rb +160 -79
- data/spec/model/model_spec.rb +118 -165
- data/spec/model/plugins_spec.rb +7 -13
- data/spec/model/record_spec.rb +138 -207
- data/spec/model/spec_helper.rb +10 -73
- metadata +14 -8
@@ -144,13 +144,6 @@ describe "An SQLite dataset" do
|
|
144
144
|
@d = SQLITE_DB[:items]
|
145
145
|
end
|
146
146
|
|
147
|
-
specify "should handle string pattern matches correctly" do
|
148
|
-
@d.literal(:x.like('a')).should == "(x LIKE 'a')"
|
149
|
-
@d.literal(~:x.like('a')).should == "NOT (x LIKE 'a')"
|
150
|
-
@d.literal(:x.ilike('a')).should == "(x LIKE 'a')"
|
151
|
-
@d.literal(~:x.ilike('a')).should == "NOT (x LIKE 'a')"
|
152
|
-
end
|
153
|
-
|
154
147
|
specify "should raise errors if given a regexp pattern match" do
|
155
148
|
proc{@d.literal(:x.like(/a/))}.should raise_error(Sequel::Error)
|
156
149
|
proc{@d.literal(~:x.like(/a/))}.should raise_error(Sequel::Error)
|
@@ -175,27 +168,27 @@ end
|
|
175
168
|
|
176
169
|
describe "An SQLite dataset AS clause" do
|
177
170
|
specify "should use a string literal for :col___alias" do
|
178
|
-
SQLITE_DB.literal(:c___a).should == "c AS 'a'"
|
171
|
+
SQLITE_DB.literal(:c___a).should == "`c` AS 'a'"
|
179
172
|
end
|
180
173
|
|
181
174
|
specify "should use a string literal for :table__col___alias" do
|
182
|
-
SQLITE_DB.literal(:t__c___a).should == "t
|
175
|
+
SQLITE_DB.literal(:t__c___a).should == "`t`.`c` AS 'a'"
|
183
176
|
end
|
184
177
|
|
185
178
|
specify "should use a string literal for :column.as(:alias)" do
|
186
|
-
SQLITE_DB.literal(:c.as(:a)).should == "c AS 'a'"
|
179
|
+
SQLITE_DB.literal(:c.as(:a)).should == "`c` AS 'a'"
|
187
180
|
end
|
188
181
|
|
189
182
|
specify "should use a string literal in the SELECT clause" do
|
190
|
-
SQLITE_DB[:t].select(:c___a).sql.should == "SELECT c AS 'a' FROM t"
|
183
|
+
SQLITE_DB[:t].select(:c___a).sql.should == "SELECT `c` AS 'a' FROM `t`"
|
191
184
|
end
|
192
185
|
|
193
186
|
specify "should use a string literal in the FROM clause" do
|
194
|
-
SQLITE_DB[:t___a].sql.should == "SELECT * FROM t AS 'a'"
|
187
|
+
SQLITE_DB[:t___a].sql.should == "SELECT * FROM `t` AS 'a'"
|
195
188
|
end
|
196
189
|
|
197
190
|
specify "should use a string literal in the JOIN clause" do
|
198
|
-
SQLITE_DB[:t].join_table(:natural, :j, nil, :a).sql.should == "SELECT * FROM t NATURAL JOIN j AS 'a'"
|
191
|
+
SQLITE_DB[:t].join_table(:natural, :j, nil, :a).sql.should == "SELECT * FROM `t` NATURAL JOIN `j` AS 'a'"
|
199
192
|
end
|
200
193
|
end
|
201
194
|
|
@@ -324,6 +317,15 @@ describe "A SQLite database" do
|
|
324
317
|
@db[:test2].first.should == {:name => 'mmm'}
|
325
318
|
end
|
326
319
|
|
320
|
+
specify "should keep a composite primary key when dropping columns" do
|
321
|
+
@db.create_table!(:test2){Integer :a; Integer :b; Integer :c; primary_key [:a, :b]}
|
322
|
+
@db.drop_column :test2, :c
|
323
|
+
@db[:test2].columns.should == [:a, :b]
|
324
|
+
@db[:test2] << {:a=>1, :b=>2}
|
325
|
+
@db[:test2] << {:a=>2, :b=>3}
|
326
|
+
proc{@db[:test2] << {:a=>2, :b=>3}}.should raise_error(Sequel::Error)
|
327
|
+
end
|
328
|
+
|
327
329
|
specify "should keep column attributes when dropping a column" do
|
328
330
|
@db.create_table! :test3 do
|
329
331
|
primary_key :id
|
@@ -423,14 +425,15 @@ describe "A SQLite database" do
|
|
423
425
|
specify "should choose a temporary table name that isn't already used when dropping or renaming columns" do
|
424
426
|
sqls = []
|
425
427
|
@db.loggers << (l=Class.new{%w'info error'.each{|m| define_method(m){|sql| sqls << sql}}}.new)
|
426
|
-
@db.
|
428
|
+
@db.tables.each{|t| @db.drop_table(t) if t.to_s =~ /test3/}
|
429
|
+
@db.create_table :test3 do
|
427
430
|
Integer :h
|
428
431
|
Integer :i
|
429
432
|
end
|
430
|
-
@db.create_table
|
433
|
+
@db.create_table :test3_backup0 do
|
431
434
|
Integer :j
|
432
435
|
end
|
433
|
-
@db.create_table
|
436
|
+
@db.create_table :test3_backup1 do
|
434
437
|
Integer :k
|
435
438
|
end
|
436
439
|
|
@@ -439,20 +442,20 @@ describe "A SQLite database" do
|
|
439
442
|
@db[:test3_backup1].columns.should == [:k]
|
440
443
|
sqls.clear
|
441
444
|
@db.drop_column(:test3, :i)
|
442
|
-
sqls.any?{|x| x =~ /\
|
443
|
-
sqls.any?{|x| x =~ /\
|
445
|
+
sqls.any?{|x| x =~ /\AALTER TABLE.*test3.*RENAME TO.*test3_backup2/}.should == true
|
446
|
+
sqls.any?{|x| x =~ /\AALTER TABLE.*test3.*RENAME TO.*test3_backup[01]/}.should == false
|
444
447
|
@db[:test3].columns.should == [:h]
|
445
448
|
@db[:test3_backup0].columns.should == [:j]
|
446
449
|
@db[:test3_backup1].columns.should == [:k]
|
447
450
|
|
448
|
-
@db.create_table
|
451
|
+
@db.create_table :test3_backup2 do
|
449
452
|
Integer :l
|
450
453
|
end
|
451
454
|
|
452
455
|
sqls.clear
|
453
456
|
@db.rename_column(:test3, :h, :i)
|
454
|
-
sqls.any?{|x| x =~ /\
|
455
|
-
sqls.any?{|x| x =~ /\
|
457
|
+
sqls.any?{|x| x =~ /\AALTER TABLE.*test3.*RENAME TO.*test3_backup3/}.should == true
|
458
|
+
sqls.any?{|x| x =~ /\AALTER TABLE.*test3.*RENAME TO.*test3_backup[012]/}.should == false
|
456
459
|
@db[:test3].columns.should == [:i]
|
457
460
|
@db[:test3_backup0].columns.should == [:j]
|
458
461
|
@db[:test3_backup1].columns.should == [:k]
|
@@ -124,36 +124,30 @@ describe "A connection pool handling connection errors" do
|
|
124
124
|
end
|
125
125
|
end
|
126
126
|
|
127
|
-
class DummyConnection
|
128
|
-
@@value = 0
|
129
|
-
def initialize
|
130
|
-
@@value += 1
|
131
|
-
end
|
132
|
-
|
133
|
-
def value
|
134
|
-
@@value
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
127
|
describe "ConnectionPool#hold" do
|
139
128
|
before do
|
140
|
-
|
129
|
+
value = 0
|
130
|
+
@c = Class.new do
|
131
|
+
define_method(:initialize){value += 1}
|
132
|
+
define_method(:value){value}
|
133
|
+
end
|
134
|
+
@pool = Sequel::ConnectionPool.get_pool(CONNECTION_POOL_DEFAULTS){@c.new}
|
141
135
|
end
|
142
136
|
|
143
137
|
specify "should pass the result of the connection maker proc to the supplied block" do
|
144
138
|
res = nil
|
145
139
|
@pool.hold {|c| res = c}
|
146
|
-
res.should be_a_kind_of(
|
140
|
+
res.should be_a_kind_of(@c)
|
147
141
|
res.value.should == 1
|
148
142
|
@pool.hold {|c| res = c}
|
149
|
-
res.should be_a_kind_of(
|
143
|
+
res.should be_a_kind_of(@c)
|
150
144
|
res.value.should == 1 # the connection maker is invoked only once
|
151
145
|
end
|
152
146
|
|
153
147
|
specify "should be re-entrant by the same thread" do
|
154
148
|
cc = nil
|
155
149
|
@pool.hold {|c| @pool.hold {|c| @pool.hold {|c| cc = c}}}
|
156
|
-
cc.should be_a_kind_of(
|
150
|
+
cc.should be_a_kind_of(@c)
|
157
151
|
end
|
158
152
|
|
159
153
|
specify "should catch exceptions and reraise them" do
|
data/spec/core/core_sql_spec.rb
CHANGED
@@ -75,16 +75,16 @@ end
|
|
75
75
|
|
76
76
|
describe "String#lit" do
|
77
77
|
before do
|
78
|
-
@ds = ds =
|
78
|
+
@ds = ds = Sequel::Database.new[:t]
|
79
79
|
end
|
80
|
+
|
80
81
|
specify "should return an LiteralString object" do
|
81
82
|
'xyz'.lit.should be_a_kind_of(Sequel::LiteralString)
|
82
83
|
'xyz'.lit.to_s.should == 'xyz'
|
83
84
|
end
|
84
85
|
|
85
86
|
specify "should inhibit string literalization" do
|
86
|
-
|
87
|
-
"UPDATE t SET stamp = NOW()"
|
87
|
+
@ds.update_sql(:stamp => "NOW()".lit).should == "UPDATE t SET stamp = NOW()"
|
88
88
|
end
|
89
89
|
|
90
90
|
specify "should return a PlaceholderLiteralString object if args are given" do
|
@@ -176,10 +176,8 @@ end
|
|
176
176
|
|
177
177
|
describe "Column references" do
|
178
178
|
before do
|
179
|
-
@
|
180
|
-
|
181
|
-
end
|
182
|
-
@ds = @c.new(MockDatabase.new)
|
179
|
+
@ds = Sequel::Database.new.dataset
|
180
|
+
def @ds.quoted_identifier(c); "`#{c}`"; end
|
183
181
|
@ds.quote_identifiers = true
|
184
182
|
end
|
185
183
|
|
@@ -289,7 +287,7 @@ end
|
|
289
287
|
|
290
288
|
describe "Dataset#literal" do
|
291
289
|
before do
|
292
|
-
@ds =
|
290
|
+
@ds = Sequel::Database.new.dataset
|
293
291
|
end
|
294
292
|
|
295
293
|
specify "should convert qualified symbol notation into dot notation" do
|
@@ -325,17 +323,12 @@ end
|
|
325
323
|
|
326
324
|
describe "Symbol" do
|
327
325
|
before do
|
328
|
-
@ds = Sequel::
|
326
|
+
@ds = Sequel::Database.new.dataset
|
329
327
|
end
|
330
328
|
|
331
|
-
specify "should support
|
329
|
+
specify "should support sql_function method" do
|
332
330
|
:COUNT.sql_function('1').to_s(@ds).should == "COUNT('1')"
|
333
|
-
|
334
|
-
|
335
|
-
specify "should inhibit string literalization" do
|
336
|
-
db = Sequel::Database.new
|
337
|
-
ds = db[:t]
|
338
|
-
ds.select(:COUNT.sql_function('1')).sql.should == "SELECT COUNT('1') FROM t"
|
331
|
+
@ds.select(:COUNT.sql_function('1')).sql.should == "SELECT COUNT('1')"
|
339
332
|
end
|
340
333
|
|
341
334
|
specify "should support cast method" do
|
@@ -367,22 +360,18 @@ describe "Symbol" do
|
|
367
360
|
end
|
368
361
|
|
369
362
|
specify "should allow database independent types when casting" do
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
type
|
376
|
-
end
|
363
|
+
db = @ds.db
|
364
|
+
def db.cast_type_literal(type)
|
365
|
+
return :foo if type == Integer
|
366
|
+
return :bar if type == String
|
367
|
+
type
|
377
368
|
end
|
378
|
-
@
|
379
|
-
:abc.cast(String).to_s(@ds).should == "CAST(abc AS
|
380
|
-
:abc.
|
381
|
-
:abc.
|
382
|
-
:abc.
|
383
|
-
:abc.
|
384
|
-
:abc.cast_numeric.to_s(@ds2).should == "CAST(abc AS foo)"
|
385
|
-
:abc.cast_numeric(String).to_s(@ds2).should == "CAST(abc AS bar)"
|
369
|
+
:abc.cast(String).to_s(@ds).should == "CAST(abc AS bar)"
|
370
|
+
:abc.cast(String).to_s(@ds).should == "CAST(abc AS bar)"
|
371
|
+
:abc.cast_string.to_s(@ds).should == "CAST(abc AS bar)"
|
372
|
+
:abc.cast_string(Integer).to_s(@ds).should == "CAST(abc AS foo)"
|
373
|
+
:abc.cast_numeric.to_s(@ds).should == "CAST(abc AS foo)"
|
374
|
+
:abc.cast_numeric(String).to_s(@ds).should == "CAST(abc AS bar)"
|
386
375
|
end
|
387
376
|
|
388
377
|
specify "should support SQL EXTRACT function via #extract " do
|
data/spec/core/database_spec.rb
CHANGED
@@ -74,46 +74,46 @@ describe "A new Database" do
|
|
74
74
|
Sequel.identifier_input_method = nil
|
75
75
|
Sequel::Database.identifier_input_method.should == ""
|
76
76
|
db = Sequel::Database.new(:identifier_input_method=>nil)
|
77
|
-
db.identifier_input_method.should
|
77
|
+
db.identifier_input_method.should be_nil
|
78
78
|
db.identifier_input_method = :downcase
|
79
79
|
db.identifier_input_method.should == :downcase
|
80
80
|
db = Sequel::Database.new(:identifier_input_method=>:upcase)
|
81
81
|
db.identifier_input_method.should == :upcase
|
82
82
|
db.identifier_input_method = nil
|
83
|
-
db.identifier_input_method.should
|
83
|
+
db.identifier_input_method.should be_nil
|
84
84
|
Sequel.identifier_input_method = :downcase
|
85
85
|
Sequel::Database.identifier_input_method.should == :downcase
|
86
86
|
db = Sequel::Database.new(:identifier_input_method=>nil)
|
87
|
-
db.identifier_input_method.should
|
87
|
+
db.identifier_input_method.should be_nil
|
88
88
|
db.identifier_input_method = :upcase
|
89
89
|
db.identifier_input_method.should == :upcase
|
90
90
|
db = Sequel::Database.new(:identifier_input_method=>:upcase)
|
91
91
|
db.identifier_input_method.should == :upcase
|
92
92
|
db.identifier_input_method = nil
|
93
|
-
db.identifier_input_method.should
|
93
|
+
db.identifier_input_method.should be_nil
|
94
94
|
end
|
95
95
|
|
96
96
|
specify "should respect the :identifier_output_method option" do
|
97
97
|
Sequel.identifier_output_method = nil
|
98
98
|
Sequel::Database.identifier_output_method.should == ""
|
99
99
|
db = Sequel::Database.new(:identifier_output_method=>nil)
|
100
|
-
db.identifier_output_method.should
|
100
|
+
db.identifier_output_method.should be_nil
|
101
101
|
db.identifier_output_method = :downcase
|
102
102
|
db.identifier_output_method.should == :downcase
|
103
103
|
db = Sequel::Database.new(:identifier_output_method=>:upcase)
|
104
104
|
db.identifier_output_method.should == :upcase
|
105
105
|
db.identifier_output_method = nil
|
106
|
-
db.identifier_output_method.should
|
106
|
+
db.identifier_output_method.should be_nil
|
107
107
|
Sequel.identifier_output_method = :downcase
|
108
108
|
Sequel::Database.identifier_output_method.should == :downcase
|
109
109
|
db = Sequel::Database.new(:identifier_output_method=>nil)
|
110
|
-
db.identifier_output_method.should
|
110
|
+
db.identifier_output_method.should be_nil
|
111
111
|
db.identifier_output_method = :upcase
|
112
112
|
db.identifier_output_method.should == :upcase
|
113
113
|
db = Sequel::Database.new(:identifier_output_method=>:upcase)
|
114
114
|
db.identifier_output_method.should == :upcase
|
115
115
|
db.identifier_output_method = nil
|
116
|
-
db.identifier_output_method.should
|
116
|
+
db.identifier_output_method.should be_nil
|
117
117
|
end
|
118
118
|
|
119
119
|
specify "should use the default Sequel.quote_identifiers value" do
|
@@ -384,10 +384,85 @@ describe "Database#dataset" do
|
|
384
384
|
end
|
385
385
|
end
|
386
386
|
|
387
|
+
describe "Database#dataset_class" do
|
388
|
+
before do
|
389
|
+
@db = Sequel::Database.new
|
390
|
+
@dsc = Class.new(Sequel::Dataset)
|
391
|
+
end
|
392
|
+
|
393
|
+
specify "should have setter set the class to use to create datasets" do
|
394
|
+
@db.dataset_class = @dsc
|
395
|
+
ds = @db.dataset
|
396
|
+
ds.should be_a_kind_of(@dsc)
|
397
|
+
ds.opts.should == {}
|
398
|
+
ds.db.should be(@db)
|
399
|
+
end
|
400
|
+
|
401
|
+
specify "should have getter return the class to use to create datasets" do
|
402
|
+
@db.dataset_class.should == Sequel::Dataset
|
403
|
+
@db.dataset_class = @dsc
|
404
|
+
@db.dataset_class.should == @dsc
|
405
|
+
end
|
406
|
+
end
|
407
|
+
|
408
|
+
describe "Database#extend_datasets" do
|
409
|
+
before do
|
410
|
+
@db = Sequel::Database.new
|
411
|
+
@m = Module.new{def foo() [3] end}
|
412
|
+
@m2 = Module.new{def foo() [4] + super end}
|
413
|
+
@db.extend_datasets(@m)
|
414
|
+
end
|
415
|
+
|
416
|
+
specify "should change the dataset class to a subclass the first time it is called" do
|
417
|
+
@db.dataset_class.superclass.should == Sequel::Dataset
|
418
|
+
end
|
419
|
+
|
420
|
+
specify "should not create a subclass of the dataset class if called more than once" do
|
421
|
+
@db.extend_datasets(@m2)
|
422
|
+
@db.dataset_class.superclass.should == Sequel::Dataset
|
423
|
+
end
|
424
|
+
|
425
|
+
specify "should make the dataset class include the module" do
|
426
|
+
@db.dataset_class.ancestors.should include(@m)
|
427
|
+
@db.dataset_class.ancestors.should_not include(@m2)
|
428
|
+
@db.extend_datasets(@m2)
|
429
|
+
@db.dataset_class.ancestors.should include(@m)
|
430
|
+
@db.dataset_class.ancestors.should include(@m2)
|
431
|
+
end
|
432
|
+
|
433
|
+
specify "should have datasets respond to the module's methods" do
|
434
|
+
@db.dataset.foo.should == [3]
|
435
|
+
@db.extend_datasets(@m2)
|
436
|
+
@db.dataset.foo.should == [4, 3]
|
437
|
+
end
|
438
|
+
|
439
|
+
specify "should take a block and create a module from it to use" do
|
440
|
+
@db.dataset.foo.should == [3]
|
441
|
+
@db.extend_datasets{def foo() [5] + super end}
|
442
|
+
@db.dataset.foo.should == [5, 3]
|
443
|
+
end
|
444
|
+
|
445
|
+
specify "should raise an error if both a module and a block are provided" do
|
446
|
+
proc{@db.extend_datasets(@m2){def foo() [5] + super end}}.should raise_error(Sequel::Error)
|
447
|
+
end
|
448
|
+
|
449
|
+
specify "should be able to override methods defined in the original Dataset class" do
|
450
|
+
@db.extend_datasets(Module.new{def select(*a, &block) super.order(*a, &block) end})
|
451
|
+
@db[:t].select(:a, :b).sql.should == 'SELECT a, b FROM t ORDER BY a, b'
|
452
|
+
end
|
453
|
+
|
454
|
+
specify "should reapply settings if dataset_class is chagned" do
|
455
|
+
c = Class.new(Sequel::Dataset)
|
456
|
+
@db.dataset_class = c
|
457
|
+
@db.dataset_class.superclass.should == c
|
458
|
+
@db.dataset_class.ancestors.should include(@m)
|
459
|
+
@db.dataset.foo.should == [3]
|
460
|
+
end
|
461
|
+
end
|
462
|
+
|
387
463
|
describe "Database#execute" do
|
388
464
|
specify "should raise Sequel::NotImplemented" do
|
389
465
|
proc {Sequel::Database.new.execute('blah blah')}.should raise_error(Sequel::NotImplemented)
|
390
|
-
proc {Sequel::Database.new << 'blah blah'}.should raise_error(Sequel::NotImplemented)
|
391
466
|
end
|
392
467
|
end
|
393
468
|
|
@@ -409,30 +484,39 @@ describe "Database#indexes" do
|
|
409
484
|
end
|
410
485
|
end
|
411
486
|
|
412
|
-
describe "Database
|
487
|
+
describe "Database#run" do
|
413
488
|
before do
|
414
|
-
|
415
|
-
@c = Class.new(Sequel::Database) do
|
416
|
-
define_method(:execute_ddl){|sql, *opts| sqls.clear; sqls << sql; sqls.concat(opts)}
|
417
|
-
end
|
418
|
-
@db = @c.new({})
|
489
|
+
@db = Sequel.mock(:servers=>{:s1=>{}})
|
419
490
|
end
|
420
491
|
|
421
|
-
specify "should
|
422
|
-
|
423
|
-
@sqls.should == ["DELETE FROM items"
|
424
|
-
@db.run("DELETE FROM items2")
|
425
|
-
@sqls.should == ["DELETE FROM items2", {}]
|
492
|
+
specify "should execute the code on the database" do
|
493
|
+
@db.run("DELETE FROM items")
|
494
|
+
@db.sqls.should == ["DELETE FROM items"]
|
426
495
|
end
|
427
496
|
|
428
497
|
specify "should return nil" do
|
429
|
-
|
430
|
-
@db.run("DELETE FROM items").should == nil
|
498
|
+
@db.run("DELETE FROM items").should be_nil
|
431
499
|
end
|
432
500
|
|
433
501
|
specify "should accept options passed to execute_ddl" do
|
434
502
|
@db.run("DELETE FROM items", :server=>:s1)
|
435
|
-
@sqls.should == ["DELETE FROM items
|
503
|
+
@db.sqls.should == ["DELETE FROM items -- s1"]
|
504
|
+
end
|
505
|
+
end
|
506
|
+
|
507
|
+
describe "Database#<<" do
|
508
|
+
before do
|
509
|
+
@db = Sequel.mock
|
510
|
+
end
|
511
|
+
|
512
|
+
specify "should execute the code on the database" do
|
513
|
+
@db << "DELETE FROM items"
|
514
|
+
@db.sqls.should == ["DELETE FROM items"]
|
515
|
+
end
|
516
|
+
|
517
|
+
specify "should be chainable" do
|
518
|
+
@db << "DELETE FROM items" << "DELETE FROM items2"
|
519
|
+
@db.sqls.should == ["DELETE FROM items", "DELETE FROM items2"]
|
436
520
|
end
|
437
521
|
end
|
438
522
|
|
@@ -442,19 +526,19 @@ describe "Database#synchronize" do
|
|
442
526
|
end
|
443
527
|
|
444
528
|
specify "should wrap the supplied block in pool.hold" do
|
445
|
-
|
529
|
+
q, q1, q2, q3 = Queue.new, Queue.new, Queue.new, Queue.new
|
446
530
|
c1, c2 = nil
|
447
|
-
t1 = Thread.new
|
448
|
-
|
531
|
+
t1 = Thread.new{@db.synchronize{|c| c1 = c; q.push nil; q1.pop}; q.push nil}
|
532
|
+
q.pop
|
449
533
|
c1.should == 12345
|
450
|
-
t2 = Thread.new
|
451
|
-
sleep 0.2
|
534
|
+
t2 = Thread.new{@db.synchronize{|c| c2 = c; q2.push nil}}
|
452
535
|
@db.pool.available_connections.should be_empty
|
453
536
|
c2.should be_nil
|
454
|
-
|
455
|
-
|
456
|
-
|
537
|
+
q1.push nil
|
538
|
+
q.pop
|
539
|
+
q2.pop
|
457
540
|
c2.should == 12345
|
541
|
+
t1.join
|
458
542
|
t2.join
|
459
543
|
end
|
460
544
|
end
|
@@ -464,7 +548,7 @@ describe "Database#test_connection" do
|
|
464
548
|
@db = Sequel::Database.new{@test = rand(100)}
|
465
549
|
end
|
466
550
|
|
467
|
-
specify "should
|
551
|
+
specify "should attempt to get a connection" do
|
468
552
|
@db.test_connection
|
469
553
|
@test.should_not be_nil
|
470
554
|
end
|
@@ -480,30 +564,21 @@ end
|
|
480
564
|
|
481
565
|
describe "Database#table_exists?" do
|
482
566
|
specify "should try to select the first record from the table's dataset" do
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
end
|
488
|
-
|
489
|
-
class Dummy3Database < Sequel::Database
|
490
|
-
attr_reader :sql, :transactions
|
491
|
-
def execute(sql, opts={}); @sql ||= []; @sql << sql; end
|
492
|
-
|
493
|
-
class DummyConnection
|
494
|
-
def initialize(db); @db = db; end
|
495
|
-
def execute(sql); @db.execute(sql); end
|
567
|
+
db = Sequel.mock(:fetch=>[Sequel::Error, [], [{:a=>1}]])
|
568
|
+
db.table_exists?(:a).should be_false
|
569
|
+
db.table_exists?(:b).should be_true
|
570
|
+
db.table_exists?(:c).should be_true
|
496
571
|
end
|
497
572
|
end
|
498
573
|
|
499
574
|
describe "Database#transaction" do
|
500
575
|
before do
|
501
|
-
@db =
|
576
|
+
@db = Sequel.mock(:servers=>{:test=>{}})
|
502
577
|
end
|
503
578
|
|
504
579
|
specify "should wrap the supplied block with BEGIN + COMMIT statements" do
|
505
580
|
@db.transaction{@db.execute 'DROP TABLE test;'}
|
506
|
-
@db.
|
581
|
+
@db.sqls.should == ['BEGIN', 'DROP TABLE test;', 'COMMIT']
|
507
582
|
end
|
508
583
|
|
509
584
|
specify "should support transaction isolation levels" do
|
@@ -511,7 +586,7 @@ describe "Database#transaction" do
|
|
511
586
|
[:uncommitted, :committed, :repeatable, :serializable].each do |l|
|
512
587
|
@db.transaction(:isolation=>l){@db.run "DROP TABLE #{l}"}
|
513
588
|
end
|
514
|
-
@db.
|
589
|
+
@db.sqls.should == ['BEGIN', 'SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED', 'DROP TABLE uncommitted', 'COMMIT',
|
515
590
|
'BEGIN', 'SET TRANSACTION ISOLATION LEVEL READ COMMITTED', 'DROP TABLE committed', 'COMMIT',
|
516
591
|
'BEGIN', 'SET TRANSACTION ISOLATION LEVEL REPEATABLE READ', 'DROP TABLE repeatable', 'COMMIT',
|
517
592
|
'BEGIN', 'SET TRANSACTION ISOLATION LEVEL SERIALIZABLE', 'DROP TABLE serializable', 'COMMIT']
|
@@ -523,7 +598,7 @@ describe "Database#transaction" do
|
|
523
598
|
@db.transaction_isolation_level = l
|
524
599
|
@db.transaction{@db.run "DROP TABLE #{l}"}
|
525
600
|
end
|
526
|
-
@db.
|
601
|
+
@db.sqls.should == ['BEGIN', 'SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED', 'DROP TABLE uncommitted', 'COMMIT',
|
527
602
|
'BEGIN', 'SET TRANSACTION ISOLATION LEVEL READ COMMITTED', 'DROP TABLE committed', 'COMMIT',
|
528
603
|
'BEGIN', 'SET TRANSACTION ISOLATION LEVEL REPEATABLE READ', 'DROP TABLE repeatable', 'COMMIT',
|
529
604
|
'BEGIN', 'SET TRANSACTION ISOLATION LEVEL SERIALIZABLE', 'DROP TABLE serializable', 'COMMIT']
|
@@ -538,12 +613,12 @@ describe "Database#transaction" do
|
|
538
613
|
end
|
539
614
|
end
|
540
615
|
@db.ret_commit
|
541
|
-
@db.
|
616
|
+
@db.sqls.should == ['BEGIN', 'DROP TABLE test;', 'COMMIT']
|
542
617
|
end
|
543
618
|
|
544
619
|
specify "should issue ROLLBACK if an exception is raised, and re-raise" do
|
545
620
|
@db.transaction {@db.execute 'DROP TABLE test'; raise RuntimeError} rescue nil
|
546
|
-
@db.
|
621
|
+
@db.sqls.should == ['BEGIN', 'DROP TABLE test', 'ROLLBACK']
|
547
622
|
|
548
623
|
proc {@db.transaction {raise RuntimeError}}.should raise_error(RuntimeError)
|
549
624
|
end
|
@@ -555,7 +630,50 @@ describe "Database#transaction" do
|
|
555
630
|
@db.drop_table(:b)
|
556
631
|
end
|
557
632
|
|
558
|
-
@db.
|
633
|
+
@db.sqls.should == ['BEGIN', 'DROP TABLE a', 'ROLLBACK']
|
634
|
+
end
|
635
|
+
|
636
|
+
specify "should have in_transaction? return true if inside a transaction" do
|
637
|
+
c = nil
|
638
|
+
@db.transaction{c = @db.in_transaction?}
|
639
|
+
c.should be_true
|
640
|
+
end
|
641
|
+
|
642
|
+
specify "should have in_transaction? handle sharding correctly" do
|
643
|
+
c = []
|
644
|
+
@db.transaction(:server=>:test){c << @db.in_transaction?}
|
645
|
+
@db.transaction(:server=>:test){c << @db.in_transaction?(:server=>:test)}
|
646
|
+
c.should == [false, true]
|
647
|
+
end
|
648
|
+
|
649
|
+
specify "should have in_transaction? return false if not in a transaction" do
|
650
|
+
@db.in_transaction?.should be_false
|
651
|
+
end
|
652
|
+
|
653
|
+
specify "should return nil if Sequel::Rollback is called in the transaction" do
|
654
|
+
@db.transaction{raise Sequel::Rollback}.should be_nil
|
655
|
+
end
|
656
|
+
|
657
|
+
specify "should reraise Sequel::Rollback errors when using :rollback=>:reraise option is given" do
|
658
|
+
proc {@db.transaction(:rollback=>:reraise){raise Sequel::Rollback}}.should raise_error(Sequel::Rollback)
|
659
|
+
@db.sqls.should == ['BEGIN', 'ROLLBACK']
|
660
|
+
proc {@db.transaction(:rollback=>:reraise){raise ArgumentError}}.should raise_error(ArgumentError)
|
661
|
+
@db.sqls.should == ['BEGIN', 'ROLLBACK']
|
662
|
+
@db.transaction(:rollback=>:reraise){1}.should == 1
|
663
|
+
@db.sqls.should == ['BEGIN', 'COMMIT']
|
664
|
+
end
|
665
|
+
|
666
|
+
specify "should always rollback if :rollback=>:always option is given" do
|
667
|
+
proc {@db.transaction(:rollback=>:always){raise ArgumentError}}.should raise_error(ArgumentError)
|
668
|
+
@db.sqls.should == ['BEGIN', 'ROLLBACK']
|
669
|
+
@db.transaction(:rollback=>:always){raise Sequel::Rollback}.should be_nil
|
670
|
+
@db.sqls.should == ['BEGIN', 'ROLLBACK']
|
671
|
+
@db.transaction(:rollback=>:always){1}.should be_nil
|
672
|
+
@db.sqls.should == ['BEGIN', 'ROLLBACK']
|
673
|
+
catch (:foo) do
|
674
|
+
@db.transaction(:rollback=>:always){throw :foo}
|
675
|
+
end
|
676
|
+
@db.sqls.should == ['BEGIN', 'ROLLBACK']
|
559
677
|
end
|
560
678
|
|
561
679
|
specify "should raise database errors when commiting a transaction as Sequel::DatabaseError" do
|
@@ -567,22 +685,36 @@ describe "Database#transaction" do
|
|
567
685
|
end
|
568
686
|
|
569
687
|
specify "should be re-entrant" do
|
570
|
-
|
688
|
+
q, q1 = Queue.new, Queue.new
|
571
689
|
cc = nil
|
572
690
|
t = Thread.new do
|
573
691
|
@db.transaction {@db.transaction {@db.transaction {|c|
|
574
692
|
cc = c
|
575
|
-
|
693
|
+
q.pop
|
694
|
+
q1.push nil
|
695
|
+
q.pop
|
576
696
|
}}}
|
577
697
|
end
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
698
|
+
q.push nil
|
699
|
+
q1.pop
|
700
|
+
cc.should be_a_kind_of(Sequel::Mock::Connection)
|
701
|
+
tr = @db.instance_variable_get(:@transactions)
|
702
|
+
tr.should == {cc=>{:savepoint_level=>1}}
|
703
|
+
q.push nil
|
582
704
|
t.join
|
583
|
-
|
705
|
+
tr.should be_empty
|
584
706
|
end
|
585
707
|
|
708
|
+
specify "should correctly handle nested transacation use with separate shards" do
|
709
|
+
@db.transaction do |c1|
|
710
|
+
@db.transaction(:server=>:test) do |c2|
|
711
|
+
c1.should_not == c2
|
712
|
+
@db.execute 'DROP TABLE test;'
|
713
|
+
end
|
714
|
+
end
|
715
|
+
@db.sqls.should == ['BEGIN', 'BEGIN -- test', 'DROP TABLE test;', 'COMMIT -- test', 'COMMIT']
|
716
|
+
end
|
717
|
+
|
586
718
|
if (!defined?(RUBY_ENGINE) or RUBY_ENGINE == 'ruby' or RUBY_ENGINE == 'rbx') and RUBY_VERSION < '1.9'
|
587
719
|
specify "should handle Thread#kill for transactions inside threads" do
|
588
720
|
q = Queue.new
|
@@ -598,35 +730,173 @@ describe "Database#transaction" do
|
|
598
730
|
q1.pop
|
599
731
|
t.kill
|
600
732
|
t.join
|
601
|
-
@db.
|
733
|
+
@db.sqls.should == ['BEGIN', 'DROP TABLE test', 'ROLLBACK']
|
602
734
|
end
|
603
735
|
end
|
736
|
+
|
737
|
+
specify "should raise an Error if after_commit or after_rollback is called without a block" do
|
738
|
+
proc{@db.after_commit}.should raise_error(Sequel::Error)
|
739
|
+
proc{@db.after_rollback}.should raise_error(Sequel::Error)
|
740
|
+
end
|
741
|
+
|
742
|
+
specify "should execute after_commit outside transactions" do
|
743
|
+
@db.after_commit{@db.execute('foo')}
|
744
|
+
@db.sqls.should == ['foo']
|
745
|
+
end
|
746
|
+
|
747
|
+
specify "should ignore after_rollback outside transactions" do
|
748
|
+
@db.after_rollback{@db.execute('foo')}
|
749
|
+
@db.sqls.should == []
|
750
|
+
end
|
751
|
+
|
752
|
+
specify "should support after_commit inside transactions" do
|
753
|
+
@db.transaction{@db.after_commit{@db.execute('foo')}}
|
754
|
+
@db.sqls.should == ['BEGIN', 'COMMIT', 'foo']
|
755
|
+
end
|
756
|
+
|
757
|
+
specify "should support after_rollback inside transactions" do
|
758
|
+
@db.transaction{@db.after_rollback{@db.execute('foo')}}
|
759
|
+
@db.sqls.should == ['BEGIN', 'COMMIT']
|
760
|
+
end
|
761
|
+
|
762
|
+
specify "should not call after_commit if the transaction rolls back" do
|
763
|
+
@db.transaction{@db.after_commit{@db.execute('foo')}; raise Sequel::Rollback}
|
764
|
+
@db.sqls.should == ['BEGIN', 'ROLLBACK']
|
765
|
+
end
|
766
|
+
|
767
|
+
specify "should call after_rollback if the transaction rolls back" do
|
768
|
+
@db.transaction{@db.after_rollback{@db.execute('foo')}; raise Sequel::Rollback}
|
769
|
+
@db.sqls.should == ['BEGIN', 'ROLLBACK', 'foo']
|
770
|
+
end
|
771
|
+
|
772
|
+
specify "should call multiple after_commit blocks in order if called inside transactions" do
|
773
|
+
@db.transaction{@db.after_commit{@db.execute('foo')}; @db.after_commit{@db.execute('bar')}}
|
774
|
+
@db.sqls.should == ['BEGIN', 'COMMIT', 'foo', 'bar']
|
775
|
+
end
|
776
|
+
|
777
|
+
specify "should call multiple after_rollback blocks in order if called inside transactions" do
|
778
|
+
@db.transaction{@db.after_rollback{@db.execute('foo')}; @db.after_rollback{@db.execute('bar')}; raise Sequel::Rollback}
|
779
|
+
@db.sqls.should == ['BEGIN', 'ROLLBACK', 'foo', 'bar']
|
780
|
+
end
|
781
|
+
|
782
|
+
specify "should support after_commit inside nested transactions" do
|
783
|
+
@db.transaction{@db.transaction{@db.after_commit{@db.execute('foo')}}}
|
784
|
+
@db.sqls.should == ['BEGIN', 'COMMIT', 'foo']
|
785
|
+
end
|
786
|
+
|
787
|
+
specify "should support after_rollback inside nested transactions" do
|
788
|
+
@db.transaction{@db.transaction{@db.after_rollback{@db.execute('foo')}}; raise Sequel::Rollback}
|
789
|
+
@db.sqls.should == ['BEGIN', 'ROLLBACK', 'foo']
|
790
|
+
end
|
791
|
+
|
792
|
+
specify "should support after_commit inside savepoints" do
|
793
|
+
@db.meta_def(:supports_savepoints?){true}
|
794
|
+
@db.transaction do
|
795
|
+
@db.after_commit{@db.execute('foo')}
|
796
|
+
@db.transaction(:savepoint=>true){@db.after_commit{@db.execute('bar')}}
|
797
|
+
@db.after_commit{@db.execute('baz')}
|
798
|
+
end
|
799
|
+
@db.sqls.should == ['BEGIN', 'SAVEPOINT autopoint_1', 'RELEASE SAVEPOINT autopoint_1', 'COMMIT', 'foo', 'bar', 'baz']
|
800
|
+
end
|
801
|
+
|
802
|
+
specify "should support after_rollback inside savepoints" do
|
803
|
+
@db.meta_def(:supports_savepoints?){true}
|
804
|
+
@db.transaction do
|
805
|
+
@db.after_rollback{@db.execute('foo')}
|
806
|
+
@db.transaction(:savepoint=>true){@db.after_rollback{@db.execute('bar')}}
|
807
|
+
@db.after_rollback{@db.execute('baz')}
|
808
|
+
raise Sequel::Rollback
|
809
|
+
end
|
810
|
+
@db.sqls.should == ['BEGIN', 'SAVEPOINT autopoint_1', 'RELEASE SAVEPOINT autopoint_1', 'ROLLBACK', 'foo', 'bar', 'baz']
|
811
|
+
end
|
812
|
+
|
813
|
+
specify "should raise an error if you attempt to use after_commit inside a prepared transaction" do
|
814
|
+
@db.meta_def(:supports_prepared_transactions?){true}
|
815
|
+
proc{@db.transaction(:prepare=>'XYZ'){@db.after_commit{@db.execute('foo')}}}.should raise_error(Sequel::Error)
|
816
|
+
@db.sqls.should == ['BEGIN', 'ROLLBACK']
|
817
|
+
end
|
818
|
+
|
819
|
+
specify "should raise an error if you attempt to use after_rollback inside a prepared transaction" do
|
820
|
+
@db.meta_def(:supports_prepared_transactions?){true}
|
821
|
+
proc{@db.transaction(:prepare=>'XYZ'){@db.after_rollback{@db.execute('foo')}}}.should raise_error(Sequel::Error)
|
822
|
+
@db.sqls.should == ['BEGIN', 'ROLLBACK']
|
823
|
+
end
|
824
|
+
|
825
|
+
specify "should raise an error if you attempt to use after_commit inside a savepoint in a prepared transaction" do
|
826
|
+
@db.meta_def(:supports_savepoints?){true}
|
827
|
+
@db.meta_def(:supports_prepared_transactions?){true}
|
828
|
+
proc{@db.transaction(:prepare=>'XYZ'){@db.transaction(:savepoint=>true){@db.after_commit{@db.execute('foo')}}}}.should raise_error(Sequel::Error)
|
829
|
+
@db.sqls.should == ['BEGIN', 'SAVEPOINT autopoint_1','ROLLBACK TO SAVEPOINT autopoint_1', 'ROLLBACK']
|
830
|
+
end
|
831
|
+
|
832
|
+
specify "should raise an error if you attempt to use after_rollback inside a savepoint in a prepared transaction" do
|
833
|
+
@db.meta_def(:supports_savepoints?){true}
|
834
|
+
@db.meta_def(:supports_prepared_transactions?){true}
|
835
|
+
proc{@db.transaction(:prepare=>'XYZ'){@db.transaction(:savepoint=>true){@db.after_rollback{@db.execute('foo')}}}}.should raise_error(Sequel::Error)
|
836
|
+
@db.sqls.should == ['BEGIN', 'SAVEPOINT autopoint_1','ROLLBACK TO SAVEPOINT autopoint_1', 'ROLLBACK']
|
837
|
+
end
|
604
838
|
end
|
605
839
|
|
840
|
+
describe "Sequel.transaction" do
|
841
|
+
before do
|
842
|
+
@sqls = []
|
843
|
+
@db1 = Sequel.mock(:append=>'1', :sqls=>@sqls)
|
844
|
+
@db2 = Sequel.mock(:append=>'2', :sqls=>@sqls)
|
845
|
+
@db3 = Sequel.mock(:append=>'3', :sqls=>@sqls)
|
846
|
+
end
|
847
|
+
|
848
|
+
specify "should run the block inside transacitons on all three databases" do
|
849
|
+
Sequel.transaction([@db1, @db2, @db3]){1}.should == 1
|
850
|
+
@sqls.should == ['BEGIN -- 1', 'BEGIN -- 2', 'BEGIN -- 3', 'COMMIT -- 3', 'COMMIT -- 2', 'COMMIT -- 1']
|
851
|
+
end
|
852
|
+
|
853
|
+
specify "should pass options to all the blocks" do
|
854
|
+
Sequel.transaction([@db1, @db2, @db3], :rollback=>:always){1}.should be_nil
|
855
|
+
@sqls.should == ['BEGIN -- 1', 'BEGIN -- 2', 'BEGIN -- 3', 'ROLLBACK -- 3', 'ROLLBACK -- 2', 'ROLLBACK -- 1']
|
856
|
+
end
|
857
|
+
|
858
|
+
specify "should handle Sequel::Rollback exceptions raised by the block to rollback on all databases" do
|
859
|
+
Sequel.transaction([@db1, @db2, @db3]){raise Sequel::Rollback}.should be_nil
|
860
|
+
@sqls.should == ['BEGIN -- 1', 'BEGIN -- 2', 'BEGIN -- 3', 'ROLLBACK -- 3', 'ROLLBACK -- 2', 'ROLLBACK -- 1']
|
861
|
+
end
|
862
|
+
|
863
|
+
specify "should handle nested transactions" do
|
864
|
+
Sequel.transaction([@db1, @db2, @db3]){Sequel.transaction([@db1, @db2, @db3]){1}}.should == 1
|
865
|
+
@sqls.should == ['BEGIN -- 1', 'BEGIN -- 2', 'BEGIN -- 3', 'COMMIT -- 3', 'COMMIT -- 2', 'COMMIT -- 1']
|
866
|
+
end
|
867
|
+
|
868
|
+
specify "should handle savepoints" do
|
869
|
+
Sequel.transaction([@db1, @db2, @db3]){Sequel.transaction([@db1, @db2, @db3], :savepoint=>true){1}}.should == 1
|
870
|
+
@sqls.should == ['BEGIN -- 1', 'BEGIN -- 2', 'BEGIN -- 3',
|
871
|
+
'SAVEPOINT autopoint_1 -- 1', 'SAVEPOINT autopoint_1 -- 2', 'SAVEPOINT autopoint_1 -- 3',
|
872
|
+
'RELEASE SAVEPOINT autopoint_1 -- 3', 'RELEASE SAVEPOINT autopoint_1 -- 2', 'RELEASE SAVEPOINT autopoint_1 -- 1',
|
873
|
+
'COMMIT -- 3', 'COMMIT -- 2', 'COMMIT -- 1']
|
874
|
+
end
|
875
|
+
end
|
876
|
+
|
606
877
|
describe "Database#transaction with savepoints" do
|
607
878
|
before do
|
608
|
-
@db =
|
609
|
-
@db.meta_def(:supports_savepoints?){true}
|
879
|
+
@db = Sequel.mock
|
610
880
|
end
|
611
881
|
|
612
882
|
specify "should wrap the supplied block with BEGIN + COMMIT statements" do
|
613
883
|
@db.transaction {@db.execute 'DROP TABLE test;'}
|
614
|
-
@db.
|
884
|
+
@db.sqls.should == ['BEGIN', 'DROP TABLE test;', 'COMMIT']
|
615
885
|
end
|
616
886
|
|
617
887
|
specify "should use savepoints if given the :savepoint option" do
|
618
888
|
@db.transaction{@db.transaction(:savepoint=>true){@db.execute 'DROP TABLE test;'}}
|
619
|
-
@db.
|
889
|
+
@db.sqls.should == ['BEGIN', 'SAVEPOINT autopoint_1', 'DROP TABLE test;', 'RELEASE SAVEPOINT autopoint_1', 'COMMIT']
|
620
890
|
end
|
621
891
|
|
622
892
|
specify "should not use a savepoints if no transaction is in progress" do
|
623
893
|
@db.transaction(:savepoint=>true){@db.execute 'DROP TABLE test;'}
|
624
|
-
@db.
|
894
|
+
@db.sqls.should == ['BEGIN', 'DROP TABLE test;', 'COMMIT']
|
625
895
|
end
|
626
896
|
|
627
897
|
specify "should reuse the current transaction if no :savepoint option is given" do
|
628
898
|
@db.transaction{@db.transaction{@db.execute 'DROP TABLE test;'}}
|
629
|
-
@db.
|
899
|
+
@db.sqls.should == ['BEGIN', 'DROP TABLE test;', 'COMMIT']
|
630
900
|
end
|
631
901
|
|
632
902
|
specify "should handle returning inside of the block by committing" do
|
@@ -638,7 +908,7 @@ describe "Database#transaction with savepoints" do
|
|
638
908
|
end
|
639
909
|
end
|
640
910
|
@db.ret_commit
|
641
|
-
@db.
|
911
|
+
@db.sqls.should == ['BEGIN', 'DROP TABLE test;', 'COMMIT']
|
642
912
|
end
|
643
913
|
|
644
914
|
specify "should handle returning inside of a savepoint by committing" do
|
@@ -652,34 +922,34 @@ describe "Database#transaction with savepoints" do
|
|
652
922
|
end
|
653
923
|
end
|
654
924
|
@db.ret_commit
|
655
|
-
@db.
|
925
|
+
@db.sqls.should == ['BEGIN', 'SAVEPOINT autopoint_1', 'DROP TABLE test;', 'RELEASE SAVEPOINT autopoint_1', 'COMMIT']
|
656
926
|
end
|
657
927
|
|
658
928
|
specify "should issue ROLLBACK if an exception is raised, and re-raise" do
|
659
929
|
@db.transaction {@db.execute 'DROP TABLE test'; raise RuntimeError} rescue nil
|
660
|
-
@db.
|
930
|
+
@db.sqls.should == ['BEGIN', 'DROP TABLE test', 'ROLLBACK']
|
661
931
|
|
662
932
|
proc {@db.transaction {raise RuntimeError}}.should raise_error(RuntimeError)
|
663
933
|
end
|
664
934
|
|
665
935
|
specify "should issue ROLLBACK SAVEPOINT if an exception is raised inside a savepoint, and re-raise" do
|
666
936
|
@db.transaction{@db.transaction(:savepoint=>true){@db.execute 'DROP TABLE test'; raise RuntimeError}} rescue nil
|
667
|
-
@db.
|
937
|
+
@db.sqls.should == ['BEGIN', 'SAVEPOINT autopoint_1', 'DROP TABLE test', 'ROLLBACK TO SAVEPOINT autopoint_1', 'ROLLBACK']
|
668
938
|
|
669
939
|
proc {@db.transaction {raise RuntimeError}}.should raise_error(RuntimeError)
|
670
940
|
end
|
671
941
|
|
672
|
-
specify "should issue ROLLBACK if Sequel::Rollback is
|
942
|
+
specify "should issue ROLLBACK if Sequel::Rollback is raised in the transaction" do
|
673
943
|
@db.transaction do
|
674
944
|
@db.drop_table(:a)
|
675
945
|
raise Sequel::Rollback
|
676
946
|
@db.drop_table(:b)
|
677
947
|
end
|
678
948
|
|
679
|
-
@db.
|
949
|
+
@db.sqls.should == ['BEGIN', 'DROP TABLE a', 'ROLLBACK']
|
680
950
|
end
|
681
951
|
|
682
|
-
specify "should issue ROLLBACK SAVEPOINT if Sequel::Rollback is
|
952
|
+
specify "should issue ROLLBACK SAVEPOINT if Sequel::Rollback is raised in a savepoint" do
|
683
953
|
@db.transaction do
|
684
954
|
@db.transaction(:savepoint=>true) do
|
685
955
|
@db.drop_table(:a)
|
@@ -688,7 +958,7 @@ describe "Database#transaction with savepoints" do
|
|
688
958
|
@db.drop_table(:b)
|
689
959
|
end
|
690
960
|
|
691
|
-
@db.
|
961
|
+
@db.sqls.should == ['BEGIN', 'SAVEPOINT autopoint_1', 'DROP TABLE a', 'ROLLBACK TO SAVEPOINT autopoint_1', 'DROP TABLE b', 'COMMIT']
|
692
962
|
end
|
693
963
|
|
694
964
|
specify "should raise database errors when commiting a transaction as Sequel::DatabaseError" do
|
@@ -704,37 +974,28 @@ end
|
|
704
974
|
|
705
975
|
describe "A Database adapter with a scheme" do
|
706
976
|
before do
|
707
|
-
|
708
|
-
|
709
|
-
DISCONNECTS.clear
|
710
|
-
else
|
711
|
-
DISCONNECTS = []
|
712
|
-
end
|
713
|
-
set_adapter_scheme :ccc
|
714
|
-
def disconnect
|
715
|
-
DISCONNECTS << self
|
716
|
-
end
|
717
|
-
end
|
977
|
+
@ccc = Class.new(Sequel::Database)
|
978
|
+
@ccc.send(:set_adapter_scheme, :ccc)
|
718
979
|
end
|
719
980
|
|
720
981
|
specify "should be registered in the ADAPTER_MAP" do
|
721
|
-
Sequel::ADAPTER_MAP[:ccc].should ==
|
982
|
+
Sequel::ADAPTER_MAP[:ccc].should == @ccc
|
722
983
|
end
|
723
984
|
|
724
985
|
specify "should give the database_type as the adapter scheme by default" do
|
725
|
-
|
986
|
+
@ccc.new.database_type.should == :ccc
|
726
987
|
end
|
727
988
|
|
728
989
|
specify "should be instantiated when its scheme is specified" do
|
729
990
|
c = Sequel::Database.connect('ccc://localhost/db')
|
730
|
-
c.should be_a_kind_of(
|
991
|
+
c.should be_a_kind_of(@ccc)
|
731
992
|
c.opts[:host].should == 'localhost'
|
732
993
|
c.opts[:database].should == 'db'
|
733
994
|
end
|
734
995
|
|
735
996
|
specify "should be accessible through Sequel.connect" do
|
736
997
|
c = Sequel.connect 'ccc://localhost/db'
|
737
|
-
c.should be_a_kind_of(
|
998
|
+
c.should be_a_kind_of(@ccc)
|
738
999
|
c.opts[:host].should == 'localhost'
|
739
1000
|
c.opts[:database].should == 'db'
|
740
1001
|
end
|
@@ -746,7 +1007,7 @@ describe "A Database adapter with a scheme" do
|
|
746
1007
|
returnValue = 'anything'
|
747
1008
|
|
748
1009
|
p = proc do |c|
|
749
|
-
c.should be_a_kind_of(
|
1010
|
+
c.should be_a_kind_of(@ccc)
|
750
1011
|
c.opts[:host].should == 'localhost'
|
751
1012
|
c.opts[:database].should == 'db'
|
752
1013
|
z = y
|
@@ -754,15 +1015,22 @@ describe "A Database adapter with a scheme" do
|
|
754
1015
|
x = c
|
755
1016
|
returnValue
|
756
1017
|
end
|
1018
|
+
|
1019
|
+
@ccc.class_eval do
|
1020
|
+
self::DISCONNECTS = []
|
1021
|
+
def disconnect
|
1022
|
+
self.class::DISCONNECTS << self
|
1023
|
+
end
|
1024
|
+
end
|
757
1025
|
Sequel::Database.connect('ccc://localhost/db', &p).should == returnValue
|
758
|
-
|
1026
|
+
@ccc::DISCONNECTS.should == [x]
|
759
1027
|
|
760
1028
|
Sequel.connect('ccc://localhost/db', &p).should == returnValue
|
761
|
-
|
1029
|
+
@ccc::DISCONNECTS.should == [y, x]
|
762
1030
|
|
763
1031
|
Sequel.send(:def_adapter_method, :ccc)
|
764
1032
|
Sequel.ccc('db', :host=>'localhost', &p).should == returnValue
|
765
|
-
|
1033
|
+
@ccc::DISCONNECTS.should == [z, y, x]
|
766
1034
|
end
|
767
1035
|
|
768
1036
|
specify "should be accessible through Sequel.<adapter>" do
|
@@ -773,31 +1041,31 @@ describe "A Database adapter with a scheme" do
|
|
773
1041
|
|
774
1042
|
c = Sequel.ccc('mydb')
|
775
1043
|
p = proc{c.opts.delete_if{|k,v| k == :disconnection_proc || k == :single_threaded}}
|
776
|
-
c.should be_a_kind_of(
|
777
|
-
p.call.should == {:adapter=>:ccc, :database => 'mydb', :adapter_class
|
1044
|
+
c.should be_a_kind_of(@ccc)
|
1045
|
+
p.call.should == {:adapter=>:ccc, :database => 'mydb', :adapter_class=>@ccc}
|
778
1046
|
|
779
1047
|
c = Sequel.ccc('mydb', :host => 'localhost')
|
780
|
-
c.should be_a_kind_of(
|
781
|
-
p.call.should == {:adapter=>:ccc, :database => 'mydb', :host => 'localhost', :adapter_class
|
1048
|
+
c.should be_a_kind_of(@ccc)
|
1049
|
+
p.call.should == {:adapter=>:ccc, :database => 'mydb', :host => 'localhost', :adapter_class=>@ccc}
|
782
1050
|
|
783
1051
|
c = Sequel.ccc
|
784
|
-
c.should be_a_kind_of(
|
785
|
-
p.call.should == {:adapter=>:ccc, :adapter_class
|
1052
|
+
c.should be_a_kind_of(@ccc)
|
1053
|
+
p.call.should == {:adapter=>:ccc, :adapter_class=>@ccc}
|
786
1054
|
|
787
1055
|
c = Sequel.ccc(:database => 'mydb', :host => 'localhost')
|
788
|
-
c.should be_a_kind_of(
|
789
|
-
p.call.should == {:adapter=>:ccc, :database => 'mydb', :host => 'localhost', :adapter_class
|
1056
|
+
c.should be_a_kind_of(@ccc)
|
1057
|
+
p.call.should == {:adapter=>:ccc, :database => 'mydb', :host => 'localhost', :adapter_class=>@ccc}
|
790
1058
|
end
|
791
1059
|
|
792
1060
|
specify "should be accessible through Sequel.connect with options" do
|
793
1061
|
c = Sequel.connect(:adapter => :ccc, :database => 'mydb')
|
794
|
-
c.should be_a_kind_of(
|
1062
|
+
c.should be_a_kind_of(@ccc)
|
795
1063
|
c.opts[:adapter].should == :ccc
|
796
1064
|
end
|
797
1065
|
|
798
1066
|
specify "should be accessible through Sequel.connect with URL parameters" do
|
799
1067
|
c = Sequel.connect 'ccc:///db?host=/tmp&user=test'
|
800
|
-
c.should be_a_kind_of(
|
1068
|
+
c.should be_a_kind_of(@ccc)
|
801
1069
|
c.opts[:host].should == '/tmp'
|
802
1070
|
c.opts[:database].should == 'db'
|
803
1071
|
c.opts[:user].should == 'test'
|
@@ -805,14 +1073,14 @@ describe "A Database adapter with a scheme" do
|
|
805
1073
|
|
806
1074
|
specify "should have URL parameters take precedence over fixed URL parts" do
|
807
1075
|
c = Sequel.connect 'ccc://localhost/db?host=a&database=b'
|
808
|
-
c.should be_a_kind_of(
|
1076
|
+
c.should be_a_kind_of(@ccc)
|
809
1077
|
c.opts[:host].should == 'a'
|
810
1078
|
c.opts[:database].should == 'b'
|
811
1079
|
end
|
812
1080
|
|
813
1081
|
specify "should have hash options take predence over URL parameters or parts" do
|
814
1082
|
c = Sequel.connect 'ccc://localhost/db?host=/tmp', :host=>'a', :database=>'b', :user=>'c'
|
815
|
-
c.should be_a_kind_of(
|
1083
|
+
c.should be_a_kind_of(@ccc)
|
816
1084
|
c.opts[:host].should == 'a'
|
817
1085
|
c.opts[:database].should == 'b'
|
818
1086
|
c.opts[:user].should == 'c'
|
@@ -820,7 +1088,7 @@ describe "A Database adapter with a scheme" do
|
|
820
1088
|
|
821
1089
|
specify "should unescape values of URL parameters and parts" do
|
822
1090
|
c = Sequel.connect 'ccc:///d%5bb%5d?host=domain%5cinstance'
|
823
|
-
c.should be_a_kind_of(
|
1091
|
+
c.should be_a_kind_of(@ccc)
|
824
1092
|
c.opts[:database].should == 'd[b]'
|
825
1093
|
c.opts[:host].should == 'domain\\instance'
|
826
1094
|
end
|
@@ -935,10 +1203,6 @@ describe "A single threaded database" do
|
|
935
1203
|
end
|
936
1204
|
|
937
1205
|
describe "A database" do
|
938
|
-
before do
|
939
|
-
Sequel::Database.single_threaded = false
|
940
|
-
end
|
941
|
-
|
942
1206
|
after do
|
943
1207
|
Sequel::Database.single_threaded = false
|
944
1208
|
end
|
@@ -983,11 +1247,7 @@ end
|
|
983
1247
|
|
984
1248
|
describe "Database#fetch" do
|
985
1249
|
before do
|
986
|
-
@db = Sequel
|
987
|
-
c = Class.new(Sequel::Dataset) do
|
988
|
-
def fetch_rows(sql); yield({:sql => sql}); end
|
989
|
-
end
|
990
|
-
@db.meta_def(:dataset) {c.new(self)}
|
1250
|
+
@db = Sequel.mock(:fetch=>proc{|sql| {:sql => sql}})
|
991
1251
|
end
|
992
1252
|
|
993
1253
|
specify "should create a dataset and invoke its fetch_rows method with the given sql" do
|
@@ -1034,21 +1294,17 @@ end
|
|
1034
1294
|
|
1035
1295
|
describe "Database#[]" do
|
1036
1296
|
before do
|
1037
|
-
@db = Sequel
|
1297
|
+
@db = Sequel.mock
|
1038
1298
|
end
|
1039
1299
|
|
1040
1300
|
specify "should return a dataset when symbols are given" do
|
1041
1301
|
ds = @db[:items]
|
1042
|
-
ds.
|
1302
|
+
ds.should be_a_kind_of(Sequel::Dataset)
|
1043
1303
|
ds.opts[:from].should == [:items]
|
1044
1304
|
end
|
1045
1305
|
|
1046
1306
|
specify "should return a dataset when a string is given" do
|
1047
|
-
|
1048
|
-
def fetch_rows(sql); yield({:sql => sql}); end
|
1049
|
-
end
|
1050
|
-
@db.meta_def(:dataset) {c.new(self)}
|
1051
|
-
|
1307
|
+
@db.fetch = proc{|sql| {:sql=>sql}}
|
1052
1308
|
sql = nil
|
1053
1309
|
@db['select * from xyz where x = ? and y = ?', 15, 'abc'].each {|r| sql = r[:sql]}
|
1054
1310
|
sql.should == "select * from xyz where x = 15 and y = 'abc'"
|
@@ -1056,53 +1312,36 @@ describe "Database#[]" do
|
|
1056
1312
|
end
|
1057
1313
|
|
1058
1314
|
describe "Database#inspect" do
|
1059
|
-
before do
|
1060
|
-
@db = DummyDatabase.new
|
1061
|
-
|
1062
|
-
@db.meta_def(:uri) {'blah://blahblah/blah'}
|
1063
|
-
end
|
1064
|
-
|
1065
1315
|
specify "should include the class name and the connection url" do
|
1066
|
-
|
1316
|
+
Sequel.connect('mock://foo/bar').inspect.should == '#<Sequel::Mock::Database: "mock://foo/bar">'
|
1067
1317
|
end
|
1068
1318
|
end
|
1069
1319
|
|
1070
1320
|
describe "Database#get" do
|
1071
1321
|
before do
|
1072
|
-
@
|
1073
|
-
def dataset
|
1074
|
-
ds = super
|
1075
|
-
def ds.get(*args, &block)
|
1076
|
-
@db.execute select(*args, &block).sql
|
1077
|
-
args
|
1078
|
-
end
|
1079
|
-
ds
|
1080
|
-
end
|
1081
|
-
end
|
1082
|
-
|
1083
|
-
@db = @c.new
|
1322
|
+
@db = Sequel.mock(:fetch=>{:a=>1})
|
1084
1323
|
end
|
1085
1324
|
|
1086
1325
|
specify "should use Dataset#get to get a single value" do
|
1087
|
-
@db.get(1).should ==
|
1088
|
-
@db.sqls.
|
1326
|
+
@db.get(1).should == 1
|
1327
|
+
@db.sqls.should == ['SELECT 1 LIMIT 1']
|
1089
1328
|
|
1090
1329
|
@db.get(:version.sql_function)
|
1091
|
-
@db.sqls.
|
1330
|
+
@db.sqls.should == ['SELECT version() LIMIT 1']
|
1092
1331
|
end
|
1093
1332
|
|
1094
1333
|
specify "should accept a block" do
|
1095
1334
|
@db.get{1}
|
1096
|
-
@db.sqls.
|
1335
|
+
@db.sqls.should == ['SELECT 1 LIMIT 1']
|
1097
1336
|
|
1098
1337
|
@db.get{version(1)}
|
1099
|
-
@db.sqls.
|
1338
|
+
@db.sqls.should == ['SELECT version(1) LIMIT 1']
|
1100
1339
|
end
|
1101
1340
|
end
|
1102
1341
|
|
1103
1342
|
describe "Database#call" do
|
1104
1343
|
specify "should call the prepared statement with the given name" do
|
1105
|
-
db =
|
1344
|
+
db = Sequel.mock(:fetch=>{:id => 1, :x => 1})
|
1106
1345
|
db[:items].prepare(:select, :select_all)
|
1107
1346
|
db.call(:select_all).should == [{:id => 1, :x => 1}]
|
1108
1347
|
db[:items].filter(:n=>:$n).prepare(:select, :select_n)
|
@@ -1114,146 +1353,129 @@ end
|
|
1114
1353
|
describe "Database#server_opts" do
|
1115
1354
|
specify "should return the general opts if no :servers option is used" do
|
1116
1355
|
opts = {:host=>1, :database=>2}
|
1117
|
-
|
1356
|
+
Sequel::Database.new(opts).send(:server_opts, :server1)[:host].should == 1
|
1118
1357
|
end
|
1119
1358
|
|
1120
1359
|
specify "should return the general opts if entry for the server is present in the :servers option" do
|
1121
1360
|
opts = {:host=>1, :database=>2, :servers=>{}}
|
1122
|
-
|
1361
|
+
Sequel::Database.new(opts).send(:server_opts, :server1)[:host].should == 1
|
1123
1362
|
end
|
1124
1363
|
|
1125
1364
|
specify "should return the general opts merged with the specific opts if given as a hash" do
|
1126
1365
|
opts = {:host=>1, :database=>2, :servers=>{:server1=>{:host=>3}}}
|
1127
|
-
|
1366
|
+
Sequel::Database.new(opts).send(:server_opts, :server1)[:host].should == 3
|
1128
1367
|
end
|
1129
1368
|
|
1130
1369
|
specify "should return the sgeneral opts merged with the specific opts if given as a proc" do
|
1131
1370
|
opts = {:host=>1, :database=>2, :servers=>{:server1=>proc{|db| {:host=>4}}}}
|
1132
|
-
|
1371
|
+
Sequel::Database.new(opts).send(:server_opts, :server1)[:host].should == 4
|
1133
1372
|
end
|
1134
1373
|
|
1135
1374
|
specify "should raise an error if the specific opts is not a proc or hash" do
|
1136
1375
|
opts = {:host=>1, :database=>2, :servers=>{:server1=>2}}
|
1137
|
-
proc{
|
1376
|
+
proc{Sequel::Database.new(opts).send(:server_opts, :server1)}.should raise_error(Sequel::Error)
|
1138
1377
|
end
|
1139
1378
|
end
|
1140
1379
|
|
1141
1380
|
describe "Database#add_servers" do
|
1142
1381
|
before do
|
1143
|
-
@db =
|
1144
|
-
def @db.connect(server)
|
1145
|
-
server_opts(server)
|
1146
|
-
end
|
1147
|
-
def @db.disconnect_connection(c)
|
1148
|
-
end
|
1382
|
+
@db = Sequel.mock(:host=>1, :database=>2, :servers=>{:server1=>{:host=>3}})
|
1149
1383
|
end
|
1150
1384
|
|
1151
1385
|
specify "should add new servers to the connection pool" do
|
1152
|
-
@db.synchronize{|c| c[:host].should == 1}
|
1153
|
-
@db.synchronize(:server1){|c| c[:host].should == 3}
|
1154
|
-
@db.synchronize(:server2){|c| c[:host].should == 1}
|
1386
|
+
@db.synchronize{|c| c.opts[:host].should == 1}
|
1387
|
+
@db.synchronize(:server1){|c| c.opts[:host].should == 3}
|
1388
|
+
@db.synchronize(:server2){|c| c.opts[:host].should == 1}
|
1155
1389
|
|
1156
1390
|
@db.add_servers(:server2=>{:host=>6})
|
1157
|
-
@db.synchronize{|c| c[:host].should == 1}
|
1158
|
-
@db.synchronize(:server1){|c| c[:host].should == 3}
|
1159
|
-
@db.synchronize(:server2){|c| c[:host].should == 6}
|
1391
|
+
@db.synchronize{|c| c.opts[:host].should == 1}
|
1392
|
+
@db.synchronize(:server1){|c| c.opts[:host].should == 3}
|
1393
|
+
@db.synchronize(:server2){|c| c.opts[:host].should == 6}
|
1160
1394
|
|
1161
1395
|
@db.disconnect
|
1162
|
-
@db.synchronize{|c| c[:host].should == 1}
|
1163
|
-
@db.synchronize(:server1){|c| c[:host].should == 3}
|
1164
|
-
@db.synchronize(:server2){|c| c[:host].should == 6}
|
1396
|
+
@db.synchronize{|c| c.opts[:host].should == 1}
|
1397
|
+
@db.synchronize(:server1){|c| c.opts[:host].should == 3}
|
1398
|
+
@db.synchronize(:server2){|c| c.opts[:host].should == 6}
|
1165
1399
|
end
|
1166
1400
|
|
1167
1401
|
specify "should replace options for future connections to existing servers" do
|
1168
|
-
@db.synchronize{|c| c[:host].should == 1}
|
1169
|
-
@db.synchronize(:server1){|c| c[:host].should == 3}
|
1170
|
-
@db.synchronize(:server2){|c| c[:host].should == 1}
|
1402
|
+
@db.synchronize{|c| c.opts[:host].should == 1}
|
1403
|
+
@db.synchronize(:server1){|c| c.opts[:host].should == 3}
|
1404
|
+
@db.synchronize(:server2){|c| c.opts[:host].should == 1}
|
1171
1405
|
|
1172
1406
|
@db.add_servers(:default=>proc{{:host=>4}}, :server1=>{:host=>8})
|
1173
|
-
@db.synchronize{|c| c[:host].should == 1}
|
1174
|
-
@db.synchronize(:server1){|c| c[:host].should == 3}
|
1175
|
-
@db.synchronize(:server2){|c| c[:host].should == 1}
|
1407
|
+
@db.synchronize{|c| c.opts[:host].should == 1}
|
1408
|
+
@db.synchronize(:server1){|c| c.opts[:host].should == 3}
|
1409
|
+
@db.synchronize(:server2){|c| c.opts[:host].should == 1}
|
1176
1410
|
|
1177
1411
|
@db.disconnect
|
1178
|
-
@db.synchronize{|c| c[:host].should == 4}
|
1179
|
-
@db.synchronize(:server1){|c| c[:host].should == 8}
|
1180
|
-
@db.synchronize(:server2){|c| c[:host].should == 4}
|
1412
|
+
@db.synchronize{|c| c.opts[:host].should == 4}
|
1413
|
+
@db.synchronize(:server1){|c| c.opts[:host].should == 8}
|
1414
|
+
@db.synchronize(:server2){|c| c.opts[:host].should == 4}
|
1181
1415
|
end
|
1182
1416
|
end
|
1183
1417
|
|
1184
1418
|
describe "Database#remove_servers" do
|
1185
1419
|
before do
|
1186
|
-
@db =
|
1187
|
-
def @db.connect(server)
|
1188
|
-
server_opts(server)
|
1189
|
-
end
|
1190
|
-
def @db.disconnect_connection(c)
|
1191
|
-
end
|
1420
|
+
@db = Sequel.mock(:host=>1, :database=>2, :servers=>{:server1=>{:host=>3}, :server2=>{:host=>4}})
|
1192
1421
|
end
|
1193
1422
|
|
1194
1423
|
specify "should remove servers from the connection pool" do
|
1195
|
-
@db.synchronize{|c| c[:host].should == 1}
|
1196
|
-
@db.synchronize(:server1){|c| c[:host].should == 3}
|
1197
|
-
@db.synchronize(:server2){|c| c[:host].should == 4}
|
1424
|
+
@db.synchronize{|c| c.opts[:host].should == 1}
|
1425
|
+
@db.synchronize(:server1){|c| c.opts[:host].should == 3}
|
1426
|
+
@db.synchronize(:server2){|c| c.opts[:host].should == 4}
|
1198
1427
|
|
1199
1428
|
@db.remove_servers(:server1, :server2)
|
1200
|
-
@db.synchronize{|c| c[:host].should == 1}
|
1201
|
-
@db.synchronize(:server1){|c| c[:host].should == 1}
|
1202
|
-
@db.synchronize(:server2){|c| c[:host].should == 1}
|
1429
|
+
@db.synchronize{|c| c.opts[:host].should == 1}
|
1430
|
+
@db.synchronize(:server1){|c| c.opts[:host].should == 1}
|
1431
|
+
@db.synchronize(:server2){|c| c.opts[:host].should == 1}
|
1203
1432
|
end
|
1204
1433
|
|
1205
1434
|
specify "should accept arrays of symbols" do
|
1206
1435
|
@db.remove_servers([:server1, :server2])
|
1207
|
-
@db.synchronize{|c| c[:host].should == 1}
|
1208
|
-
@db.synchronize(:server1){|c| c[:host].should == 1}
|
1209
|
-
@db.synchronize(:server2){|c| c[:host].should == 1}
|
1436
|
+
@db.synchronize{|c| c.opts[:host].should == 1}
|
1437
|
+
@db.synchronize(:server1){|c| c.opts[:host].should == 1}
|
1438
|
+
@db.synchronize(:server2){|c| c.opts[:host].should == 1}
|
1210
1439
|
end
|
1211
1440
|
|
1212
1441
|
specify "should allow removal while connections are still open" do
|
1213
1442
|
@db.synchronize do |c1|
|
1214
|
-
c1[:host].should == 1
|
1443
|
+
c1.opts[:host].should == 1
|
1215
1444
|
@db.synchronize(:server1) do |c2|
|
1216
|
-
c2[:host].should == 3
|
1445
|
+
c2.opts[:host].should == 3
|
1217
1446
|
@db.synchronize(:server2) do |c3|
|
1218
|
-
c3[:host].should == 4
|
1447
|
+
c3.opts[:host].should == 4
|
1219
1448
|
@db.remove_servers(:server1, :server2)
|
1220
1449
|
@db.synchronize(:server1) do |c4|
|
1221
1450
|
c4.should_not == c2
|
1222
1451
|
c4.should == c1
|
1223
|
-
c4[:host].should == 1
|
1452
|
+
c4.opts[:host].should == 1
|
1224
1453
|
@db.synchronize(:server2) do |c5|
|
1225
1454
|
c5.should_not == c3
|
1226
1455
|
c5.should == c1
|
1227
|
-
c5[:host].should == 1
|
1456
|
+
c5.opts[:host].should == 1
|
1228
1457
|
end
|
1229
1458
|
end
|
1230
|
-
c3[:host].should == 4
|
1459
|
+
c3.opts[:host].should == 4
|
1231
1460
|
end
|
1232
|
-
c2[:host].should == 3
|
1461
|
+
c2.opts[:host].should == 3
|
1233
1462
|
end
|
1234
|
-
c1[:host].should == 1
|
1463
|
+
c1.opts[:host].should == 1
|
1235
1464
|
end
|
1236
1465
|
end
|
1237
1466
|
end
|
1238
1467
|
|
1239
1468
|
describe "Database#each_server with do/jdbc adapter connection string without :adapter option" do
|
1240
|
-
|
1469
|
+
specify "should yield a separate database object for each server" do
|
1241
1470
|
klass = Class.new(Sequel::Database)
|
1242
|
-
klass.should_receive(:adapter_class).once.with(:jdbc).and_return(
|
1471
|
+
klass.should_receive(:adapter_class).once.with(:jdbc).and_return(Sequel::Mock::Database)
|
1243
1472
|
@db = klass.connect('jdbc:blah:', :host=>1, :database=>2, :servers=>{:server1=>{:host=>3}})
|
1244
|
-
def @db.connect(server)
|
1245
|
-
server_opts(server)
|
1246
|
-
end
|
1247
|
-
def @db.disconnect_connection(c)
|
1248
|
-
end
|
1249
|
-
end
|
1250
1473
|
|
1251
|
-
specify "should yield a separate database object for each server" do
|
1252
1474
|
hosts = []
|
1253
1475
|
@db.each_server do |db|
|
1254
1476
|
db.should be_a_kind_of(Sequel::Database)
|
1255
1477
|
db.should_not == @db
|
1256
|
-
db.opts[:adapter_class].should ==
|
1478
|
+
db.opts[:adapter_class].should == Sequel::Mock::Database
|
1257
1479
|
db.opts[:database].should == 2
|
1258
1480
|
hosts << db.opts[:host]
|
1259
1481
|
end
|
@@ -1263,12 +1485,7 @@ end
|
|
1263
1485
|
|
1264
1486
|
describe "Database#each_server" do
|
1265
1487
|
before do
|
1266
|
-
@db = Sequel.
|
1267
|
-
def @db.connect(server)
|
1268
|
-
server_opts(server)
|
1269
|
-
end
|
1270
|
-
def @db.disconnect_connection(c)
|
1271
|
-
end
|
1488
|
+
@db = Sequel.mock(:host=>1, :database=>2, :servers=>{:server1=>{:host=>3}, :server2=>{:host=>4}})
|
1272
1489
|
end
|
1273
1490
|
|
1274
1491
|
specify "should yield a separate database object for each server" do
|
@@ -1299,21 +1516,25 @@ describe "Database#each_server" do
|
|
1299
1516
|
end
|
1300
1517
|
|
1301
1518
|
describe "Database#raise_error" do
|
1519
|
+
before do
|
1520
|
+
@db = Sequel.mock
|
1521
|
+
end
|
1522
|
+
|
1302
1523
|
specify "should reraise if the exception class is not in opts[:classes]" do
|
1303
1524
|
e = Class.new(StandardError)
|
1304
|
-
proc{
|
1525
|
+
proc{@db.send(:raise_error, e.new(''), :classes=>[])}.should raise_error(e)
|
1305
1526
|
end
|
1306
1527
|
|
1307
|
-
specify "should convert the exception to a DatabaseError if the exception class is
|
1308
|
-
proc{
|
1528
|
+
specify "should convert the exception to a DatabaseError if the exception class is in opts[:classes]" do
|
1529
|
+
proc{@db.send(:raise_error, Interrupt.new(''), :classes=>[Interrupt])}.should raise_error(Sequel::DatabaseError)
|
1309
1530
|
end
|
1310
1531
|
|
1311
1532
|
specify "should convert the exception to a DatabaseError if opts[:classes] if not present" do
|
1312
|
-
proc{
|
1533
|
+
proc{@db.send(:raise_error, Interrupt.new(''))}.should raise_error(Sequel::DatabaseError)
|
1313
1534
|
end
|
1314
1535
|
|
1315
1536
|
specify "should convert the exception to a DatabaseDisconnectError if opts[:disconnect] is true" do
|
1316
|
-
proc{
|
1537
|
+
proc{@db.send(:raise_error, Interrupt.new(''), :disconnect=>true)}.should raise_error(Sequel::DatabaseDisconnectError)
|
1317
1538
|
end
|
1318
1539
|
end
|
1319
1540
|
|
@@ -1373,6 +1594,49 @@ describe "Database#typecast_value" do
|
|
1373
1594
|
@db.typecast_value(:date, :year=>Date.today.year, :month=>Date.today.month, :day=>Date.today.day).should == Date.today
|
1374
1595
|
end
|
1375
1596
|
|
1597
|
+
specify "should have Sequel.application_to_database_timestamp convert to Sequel.database_timezone" do
|
1598
|
+
begin
|
1599
|
+
t = Time.utc(2011, 1, 2, 3, 4, 5) # UTC Time
|
1600
|
+
t2 = Time.mktime(2011, 1, 2, 3, 4, 5) # Local Time
|
1601
|
+
t3 = Time.utc(2011, 1, 2, 3, 4, 5) - (t - t2) # Local Time in UTC Time
|
1602
|
+
t4 = Time.mktime(2011, 1, 2, 3, 4, 5) + (t - t2) # UTC Time in Local Time
|
1603
|
+
Sequel.application_timezone = :utc
|
1604
|
+
Sequel.database_timezone = :local
|
1605
|
+
Sequel.application_to_database_timestamp(t).should == t4
|
1606
|
+
Sequel.application_timezone = :local
|
1607
|
+
Sequel.database_timezone = :utc
|
1608
|
+
Sequel.application_to_database_timestamp(t2).should == t3
|
1609
|
+
ensure
|
1610
|
+
Sequel.default_timezone = nil
|
1611
|
+
end
|
1612
|
+
end
|
1613
|
+
|
1614
|
+
specify "should have Database#to_application_timestamp convert values using the database's timezone" do
|
1615
|
+
begin
|
1616
|
+
t = Time.utc(2011, 1, 2, 3, 4, 5) # UTC Time
|
1617
|
+
t2 = Time.mktime(2011, 1, 2, 3, 4, 5) # Local Time
|
1618
|
+
t3 = Time.utc(2011, 1, 2, 3, 4, 5) - (t - t2) # Local Time in UTC Time
|
1619
|
+
t4 = Time.mktime(2011, 1, 2, 3, 4, 5) + (t - t2) # UTC Time in Local Time
|
1620
|
+
Sequel.default_timezone = :utc
|
1621
|
+
@db.to_application_timestamp('2011-01-02 03:04:05').should == t
|
1622
|
+
Sequel.database_timezone = :local
|
1623
|
+
@db.to_application_timestamp('2011-01-02 03:04:05').should == t3
|
1624
|
+
Sequel.default_timezone = :local
|
1625
|
+
@db.to_application_timestamp('2011-01-02 03:04:05').should == t2
|
1626
|
+
Sequel.database_timezone = :utc
|
1627
|
+
@db.to_application_timestamp('2011-01-02 03:04:05').should == t4
|
1628
|
+
|
1629
|
+
Sequel.default_timezone = :utc
|
1630
|
+
@db.timezone = :local
|
1631
|
+
@db.to_application_timestamp('2011-01-02 03:04:05').should == t3
|
1632
|
+
Sequel.default_timezone = :local
|
1633
|
+
@db.timezone = :utc
|
1634
|
+
@db.to_application_timestamp('2011-01-02 03:04:05').should == t4
|
1635
|
+
ensure
|
1636
|
+
Sequel.default_timezone = nil
|
1637
|
+
end
|
1638
|
+
end
|
1639
|
+
|
1376
1640
|
specify "should typecast datetime values to Sequel.datetime_class with correct timezone handling" do
|
1377
1641
|
t = Time.utc(2011, 1, 2, 3, 4, 5) # UTC Time
|
1378
1642
|
t2 = Time.mktime(2011, 1, 2, 3, 4, 5) # Local Time
|
@@ -1596,7 +1860,7 @@ describe "Database#blank_object?" do
|
|
1596
1860
|
end
|
1597
1861
|
|
1598
1862
|
describe "Database#schema_autoincrementing_primary_key?" do
|
1599
|
-
specify "should whether the parsed schema row indicates a primary key" do
|
1863
|
+
specify "should indicate whether the parsed schema row indicates a primary key" do
|
1600
1864
|
m = Sequel::Database.new.method(:schema_autoincrementing_primary_key?)
|
1601
1865
|
m.call(:primary_key=>true).should == true
|
1602
1866
|
m.call(:primary_key=>false).should == false
|
@@ -1652,7 +1916,7 @@ describe "Database#column_schema_to_ruby_default" do
|
|
1652
1916
|
db = Sequel::Database.new
|
1653
1917
|
m = db.method(:column_schema_to_ruby_default)
|
1654
1918
|
p = lambda{|d,t| m.call(d,t)}
|
1655
|
-
p[nil, :integer].should
|
1919
|
+
p[nil, :integer].should be_nil
|
1656
1920
|
p['1', :integer].should == 1
|
1657
1921
|
p['-1', :integer].should == -1
|
1658
1922
|
p['1.0', :float].should == 1.0
|
@@ -1672,12 +1936,12 @@ describe "Database#column_schema_to_ruby_default" do
|
|
1672
1936
|
p["'\\a''b'", :string].should == "\\a'b"
|
1673
1937
|
p["'NULL'", :string].should == "NULL"
|
1674
1938
|
p["'2009-10-29'", :date].should == Date.new(2009,10,29)
|
1675
|
-
p["CURRENT_TIMESTAMP", :date].should
|
1676
|
-
p["today()", :date].should
|
1939
|
+
p["CURRENT_TIMESTAMP", :date].should be_nil
|
1940
|
+
p["today()", :date].should be_nil
|
1677
1941
|
p["'2009-10-29T10:20:30-07:00'", :datetime].should == DateTime.parse('2009-10-29T10:20:30-07:00')
|
1678
1942
|
p["'2009-10-29 10:20:30'", :datetime].should == DateTime.parse('2009-10-29 10:20:30')
|
1679
1943
|
p["'10:20:30'", :time].should == Time.parse('10:20:30')
|
1680
|
-
p["NaN", :float].should
|
1944
|
+
p["NaN", :float].should be_nil
|
1681
1945
|
|
1682
1946
|
db.meta_def(:database_type){:postgres}
|
1683
1947
|
p["''::text", :string].should == ""
|
@@ -1701,8 +1965,8 @@ describe "Database#column_schema_to_ruby_default" do
|
|
1701
1965
|
p["2009-10-29", :date].should == Date.new(2009,10,29)
|
1702
1966
|
p["2009-10-29 10:20:30", :datetime].should == DateTime.parse('2009-10-29 10:20:30')
|
1703
1967
|
p["10:20:30", :time].should == Time.parse('10:20:30')
|
1704
|
-
p["CURRENT_DATE", :date].should
|
1705
|
-
p["CURRENT_TIMESTAMP", :datetime].should
|
1968
|
+
p["CURRENT_DATE", :date].should be_nil
|
1969
|
+
p["CURRENT_TIMESTAMP", :datetime].should be_nil
|
1706
1970
|
p["a", :enum].should == "a"
|
1707
1971
|
|
1708
1972
|
db.meta_def(:database_type){:mssql}
|