sequel 3.40.0 → 3.41.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. data/CHANGELOG +40 -0
  2. data/README.rdoc +2 -2
  3. data/doc/advanced_associations.rdoc +12 -0
  4. data/doc/bin_sequel.rdoc +144 -0
  5. data/doc/migration.rdoc +1 -1
  6. data/doc/object_model.rdoc +29 -0
  7. data/doc/release_notes/3.41.0.txt +155 -0
  8. data/lib/sequel/adapters/ado.rb +4 -4
  9. data/lib/sequel/adapters/amalgalite.rb +0 -5
  10. data/lib/sequel/adapters/cubrid.rb +2 -2
  11. data/lib/sequel/adapters/db2.rb +9 -5
  12. data/lib/sequel/adapters/dbi.rb +4 -6
  13. data/lib/sequel/adapters/do.rb +4 -5
  14. data/lib/sequel/adapters/firebird.rb +8 -4
  15. data/lib/sequel/adapters/ibmdb.rb +2 -3
  16. data/lib/sequel/adapters/informix.rb +0 -6
  17. data/lib/sequel/adapters/jdbc.rb +11 -7
  18. data/lib/sequel/adapters/jdbc/db2.rb +22 -0
  19. data/lib/sequel/adapters/jdbc/derby.rb +5 -5
  20. data/lib/sequel/adapters/jdbc/h2.rb +0 -5
  21. data/lib/sequel/adapters/jdbc/jtds.rb +1 -1
  22. data/lib/sequel/adapters/jdbc/sqlserver.rb +6 -0
  23. data/lib/sequel/adapters/mock.rb +3 -3
  24. data/lib/sequel/adapters/mysql.rb +7 -7
  25. data/lib/sequel/adapters/mysql2.rb +0 -5
  26. data/lib/sequel/adapters/odbc.rb +4 -4
  27. data/lib/sequel/adapters/openbase.rb +4 -6
  28. data/lib/sequel/adapters/oracle.rb +14 -6
  29. data/lib/sequel/adapters/postgres.rb +12 -8
  30. data/lib/sequel/adapters/shared/db2.rb +5 -0
  31. data/lib/sequel/adapters/shared/firebird.rb +10 -0
  32. data/lib/sequel/adapters/shared/mssql.rb +43 -1
  33. data/lib/sequel/adapters/shared/mysql.rb +1 -0
  34. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +1 -1
  35. data/lib/sequel/adapters/shared/postgres.rb +12 -0
  36. data/lib/sequel/adapters/shared/sqlite.rb +32 -0
  37. data/lib/sequel/adapters/sqlite.rb +9 -8
  38. data/lib/sequel/adapters/swift.rb +3 -8
  39. data/lib/sequel/adapters/tinytds.rb +5 -5
  40. data/lib/sequel/connection_pool.rb +13 -19
  41. data/lib/sequel/connection_pool/sharded_single.rb +12 -12
  42. data/lib/sequel/connection_pool/sharded_threaded.rb +37 -17
  43. data/lib/sequel/connection_pool/single.rb +6 -3
  44. data/lib/sequel/connection_pool/threaded.rb +33 -13
  45. data/lib/sequel/database/connecting.rb +28 -1
  46. data/lib/sequel/database/logging.rb +1 -1
  47. data/lib/sequel/database/misc.rb +2 -5
  48. data/lib/sequel/database/query.rb +2 -2
  49. data/lib/sequel/database/schema_generator.rb +1 -1
  50. data/lib/sequel/database/schema_methods.rb +3 -0
  51. data/lib/sequel/dataset/query.rb +8 -4
  52. data/lib/sequel/dataset/sql.rb +7 -0
  53. data/lib/sequel/extensions/arbitrary_servers.rb +1 -1
  54. data/lib/sequel/extensions/connection_validator.rb +109 -0
  55. data/lib/sequel/extensions/pg_array.rb +2 -0
  56. data/lib/sequel/extensions/pg_hstore.rb +2 -0
  57. data/lib/sequel/extensions/pg_json.rb +4 -0
  58. data/lib/sequel/extensions/pg_range.rb +1 -0
  59. data/lib/sequel/extensions/pg_row.rb +4 -0
  60. data/lib/sequel/plugins/prepared_statements.rb +2 -1
  61. data/lib/sequel/plugins/single_table_inheritance.rb +53 -10
  62. data/lib/sequel/plugins/touch.rb +18 -6
  63. data/lib/sequel/plugins/validation_class_methods.rb +1 -0
  64. data/lib/sequel/plugins/validation_helpers.rb +3 -1
  65. data/lib/sequel/sql.rb +61 -19
  66. data/lib/sequel/version.rb +1 -1
  67. data/spec/adapters/firebird_spec.rb +52 -38
  68. data/spec/adapters/mssql_spec.rb +67 -0
  69. data/spec/adapters/mysql_spec.rb +192 -116
  70. data/spec/adapters/postgres_spec.rb +133 -70
  71. data/spec/adapters/spec_helper.rb +7 -0
  72. data/spec/adapters/sqlite_spec.rb +34 -1
  73. data/spec/core/connection_pool_spec.rb +79 -75
  74. data/spec/core/database_spec.rb +9 -4
  75. data/spec/core/dataset_spec.rb +15 -0
  76. data/spec/core/expression_filters_spec.rb +40 -2
  77. data/spec/extensions/connection_validator_spec.rb +118 -0
  78. data/spec/extensions/pg_array_spec.rb +4 -0
  79. data/spec/extensions/single_table_inheritance_spec.rb +42 -0
  80. data/spec/extensions/touch_spec.rb +40 -0
  81. data/spec/extensions/validation_class_methods_spec.rb +19 -1
  82. data/spec/extensions/validation_helpers_spec.rb +17 -0
  83. data/spec/integration/database_test.rb +14 -0
  84. data/spec/integration/dataset_test.rb +3 -3
  85. data/spec/integration/plugin_test.rb +41 -12
  86. data/spec/integration/schema_test.rb +14 -0
  87. data/spec/integration/spec_helper.rb +7 -0
  88. data/spec/integration/type_test.rb +3 -0
  89. metadata +9 -3
@@ -37,7 +37,8 @@ describe "A new Database" do
37
37
 
38
38
  specify "should pass the supplied block to the connection pool" do
39
39
  cc = nil
40
- d = Sequel::Database.new {1234}
40
+ d = Sequel::Database.new
41
+ d.meta_def(:connect){|c| 1234}
41
42
  d.synchronize {|c| cc = c}
42
43
  cc.should == 1234
43
44
  end
@@ -538,7 +539,8 @@ end
538
539
 
539
540
  describe "Database#synchronize" do
540
541
  before do
541
- @db = Sequel::Database.new(:max_connections => 1){12345}
542
+ @db = Sequel::Database.new(:max_connections => 1)
543
+ @db.meta_def(:connect){|c| 12345}
542
544
  end
543
545
 
544
546
  specify "should wrap the supplied block in pool.hold" do
@@ -561,7 +563,9 @@ end
561
563
 
562
564
  describe "Database#test_connection" do
563
565
  before do
564
- @db = Sequel::Database.new{@test = rand(100)}
566
+ @db = Sequel::Database.new
567
+ pr = proc{@test = rand(100)}
568
+ @db.meta_def(:connect){|c| pr.call}
565
569
  end
566
570
 
567
571
  specify "should attempt to get a connection" do
@@ -1258,7 +1262,8 @@ end
1258
1262
  describe "A single threaded database" do
1259
1263
  before do
1260
1264
  conn = 1234567
1261
- @db = Sequel::Database.new(:single_threaded => true) do
1265
+ @db = Sequel::Database.new(:single_threaded => true)
1266
+ @db.meta_def(:connect) do |c|
1262
1267
  conn += 1
1263
1268
  end
1264
1269
  end
@@ -1588,6 +1588,15 @@ describe "Dataset#reverse_order" do
1588
1588
  specify "should have #reverse alias" do
1589
1589
  @dataset.order(:name).reverse.sql.should == 'SELECT * FROM test ORDER BY name DESC'
1590
1590
  end
1591
+
1592
+ specify "should accept a block" do
1593
+ @dataset.reverse{name}.sql.should == 'SELECT * FROM test ORDER BY name DESC'
1594
+ @dataset.reverse_order{name}.sql.should == 'SELECT * FROM test ORDER BY name DESC'
1595
+ @dataset.reverse(:foo){name}.sql.should == 'SELECT * FROM test ORDER BY foo DESC, name DESC'
1596
+ @dataset.reverse_order(:foo){name}.sql.should == 'SELECT * FROM test ORDER BY foo DESC, name DESC'
1597
+ @dataset.reverse(Sequel.desc(:foo)){name}.sql.should == 'SELECT * FROM test ORDER BY foo ASC, name DESC'
1598
+ @dataset.reverse_order(Sequel.desc(:foo)){name}.sql.should == 'SELECT * FROM test ORDER BY foo ASC, name DESC'
1599
+ end
1591
1600
  end
1592
1601
 
1593
1602
  describe "Dataset#limit" do
@@ -1620,6 +1629,12 @@ describe "Dataset#limit" do
1620
1629
  @dataset.limit(6, Sequel.function(:a) - 1).sql.should == 'SELECT * FROM test LIMIT 6 OFFSET (a() - 1)'
1621
1630
  end
1622
1631
 
1632
+ specify "should be able to reset limit and offset with nil values" do
1633
+ @dataset.limit(6).limit(nil).sql.should == 'SELECT * FROM test'
1634
+ @dataset.limit(6, 1).limit(nil).sql.should == 'SELECT * FROM test OFFSET 1'
1635
+ @dataset.limit(6, 1).limit(nil, nil).sql.should == 'SELECT * FROM test'
1636
+ end
1637
+
1623
1638
  specify "should work with fixed sql datasets" do
1624
1639
  @dataset.opts[:sql] = 'select * from cccc'
1625
1640
  @dataset.limit(6, 10).sql.should == 'SELECT * FROM (select * from cccc) AS t1 LIMIT 6 OFFSET 10'
@@ -551,8 +551,8 @@ describe "Sequel core extension replacements" do
551
551
  Sequel.expr({1=>2}).should be_a_kind_of(Sequel::SQL::BooleanExpression)
552
552
  Sequel.expr([[1, 2]]).should be_a_kind_of(Sequel::SQL::BooleanExpression)
553
553
  Sequel.expr([1]).should be_a_kind_of(Sequel::SQL::Wrapper)
554
- Sequel.expr{|o| o.should be_a_kind_of(Sequel::SQL::VirtualRow)}
555
- Sequel.expr{self.should be_a_kind_of(Sequel::SQL::VirtualRow)}
554
+ Sequel.expr{|o| o.a}.should be_a_kind_of(Sequel::SQL::Identifier)
555
+ Sequel.expr{a}.should be_a_kind_of(Sequel::SQL::Identifier)
556
556
  Sequel.expr(:a).should be_a_kind_of(Sequel::SQL::Identifier)
557
557
  Sequel.expr(:a__b).should be_a_kind_of(Sequel::SQL::QualifiedIdentifier)
558
558
  Sequel.expr(:a___c).should be_a_kind_of(Sequel::SQL::AliasedExpression)
@@ -966,3 +966,41 @@ describe "Sequel.recursive_map" do
966
966
  Sequel.recursive_map([[nil]], proc{|s| s.to_i}).should == [[nil]]
967
967
  end
968
968
  end
969
+
970
+ describe "Sequel.delay" do
971
+ before do
972
+ @o = Class.new do
973
+ def a
974
+ @a ||= 0
975
+ @a += 1
976
+ end
977
+ def _a
978
+ @a
979
+ end
980
+
981
+ attr_accessor :b
982
+ end.new
983
+ end
984
+
985
+ specify "should delay calling the block until literalization" do
986
+ ds = Sequel.mock[:b].where(:a=>Sequel.delay{@o.a})
987
+ @o._a.should be_nil
988
+ ds.sql.should == "SELECT * FROM b WHERE (a = 1)"
989
+ @o._a.should == 1
990
+ ds.sql.should == "SELECT * FROM b WHERE (a = 2)"
991
+ @o._a.should == 2
992
+ end
993
+
994
+ specify "should have the condition specifier handling respect delayed evaluations" do
995
+ ds = Sequel.mock[:b].where(:a=>Sequel.delay{@o.b})
996
+ ds.sql.should == "SELECT * FROM b WHERE (a IS NULL)"
997
+ @o.b = 1
998
+ ds.sql.should == "SELECT * FROM b WHERE (a = 1)"
999
+ @o.b = [1, 2]
1000
+ ds.sql.should == "SELECT * FROM b WHERE (a IN (1, 2))"
1001
+ end
1002
+
1003
+ specify "should raise if called without a block" do
1004
+ proc{Sequel.delay}.should raise_error(Sequel::Error)
1005
+ end
1006
+ end
@@ -0,0 +1,118 @@
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
+
3
+ shared_examples_for "Sequel::ConnectionValidator" do
4
+ before do
5
+ @db.extend(Module.new do
6
+ def disconnect_connection(conn)
7
+ @sqls << 'disconnect'
8
+ end
9
+ def valid_connection?(conn)
10
+ super
11
+ conn.valid
12
+ end
13
+ def connect(server)
14
+ conn = super
15
+ conn.extend(Module.new do
16
+ attr_accessor :valid
17
+ end)
18
+ conn.valid = true
19
+ conn
20
+ end
21
+ end)
22
+ @db.extension(:connection_validator)
23
+ end
24
+
25
+ it "should still allow new connections" do
26
+ @db.synchronize{|c| c}.should be_a_kind_of(Sequel::Mock::Connection)
27
+ end
28
+
29
+ it "should only validate if connection idle longer than timeout" do
30
+ c1 = @db.synchronize{|c| c}
31
+ @db.sqls.should == []
32
+ @db.synchronize{|c| c}.should equal(c1)
33
+ @db.sqls.should == []
34
+ @db.pool.connection_validation_timeout = -1
35
+ @db.synchronize{|c| c}.should equal(c1)
36
+ @db.sqls.should == ['SELECT NULL']
37
+ @db.pool.connection_validation_timeout = 1
38
+ @db.synchronize{|c| c}.should equal(c1)
39
+ @db.sqls.should == []
40
+ @db.synchronize{|c| c}.should equal(c1)
41
+ @db.sqls.should == []
42
+ end
43
+
44
+ it "should disconnect connection if not valid" do
45
+ c1 = @db.synchronize{|c| c}
46
+ @db.sqls.should == []
47
+ c1.valid = false
48
+ @db.pool.connection_validation_timeout = -1
49
+ c2 = @db.synchronize{|c| c}
50
+ @db.sqls.should == ['SELECT NULL', 'disconnect']
51
+ c2.should_not equal(c1)
52
+ end
53
+
54
+ it "should disconnect multiple connections repeatedly if they are not valid" do
55
+ q, q1 = Queue.new, Queue.new
56
+ c1 = nil
57
+ c2 = nil
58
+ @db.pool.connection_validation_timeout = -1
59
+ @db.synchronize do |c|
60
+ Thread.new do
61
+ @db.synchronize do |cc|
62
+ c2 = cc
63
+ end
64
+ q1.pop
65
+ q.push nil
66
+ end
67
+ q1.push nil
68
+ q.pop
69
+ c1 = c
70
+ end
71
+ c1.valid = false
72
+ c2.valid = false
73
+
74
+ c3 = @db.synchronize{|c| c}
75
+ @db.sqls.should == ['SELECT NULL', 'disconnect', 'SELECT NULL', 'disconnect']
76
+ c3.should_not equal(c1)
77
+ c3.should_not equal(c2)
78
+ end
79
+
80
+ it "should not leak connection references" do
81
+ c1 = @db.synchronize do |c|
82
+ @db.pool.instance_variable_get(:@connection_timestamps).should == {}
83
+ c
84
+ end
85
+ @db.pool.instance_variable_get(:@connection_timestamps).should have_key(c1)
86
+
87
+ c1.valid = false
88
+ @db.pool.connection_validation_timeout = -1
89
+ c2 = @db.synchronize do |c|
90
+ @db.pool.instance_variable_get(:@connection_timestamps).should == {}
91
+ c
92
+ end
93
+ c2.should_not equal(c1)
94
+ @db.pool.instance_variable_get(:@connection_timestamps).should_not have_key(c1)
95
+ @db.pool.instance_variable_get(:@connection_timestamps).should have_key(c2)
96
+ end
97
+
98
+ it "should handle case where determining validity requires a connection" do
99
+ @db.meta_def(:valid_connection?){|c| synchronize{}; true}
100
+ @db.pool.connection_validation_timeout = -1
101
+ c1 = @db.synchronize{|c| c}
102
+ @db.synchronize{|c| c}.should equal(c1)
103
+ end
104
+ end
105
+
106
+ describe "Sequel::ConnectionValidator with threaded pool" do
107
+ before do
108
+ @db = Sequel.mock
109
+ end
110
+ it_should_behave_like "Sequel::ConnectionValidator"
111
+ end
112
+ describe "Sequel::ConnectionValidator with sharded threaded pool" do
113
+ before do
114
+ @db = Sequel.mock(:servers=>{})
115
+ end
116
+ it_should_behave_like "Sequel::ConnectionValidator"
117
+ end
118
+
@@ -231,6 +231,10 @@ describe "pg_array extension" do
231
231
  proc{@db.typecast_value(:integer_array, {})}.should raise_error(Sequel::InvalidValue)
232
232
  end
233
233
 
234
+ it "should support SQL::AliasMethods" do
235
+ @db.select(Sequel.pg_array([1], :integer).as(:col1)).sql.should == 'SELECT ARRAY[1]::integer[] AS col1'
236
+ end
237
+
234
238
  it "should support registering custom array types" do
235
239
  Sequel::Postgres::PGArray.register('foo')
236
240
  @db.typecast_value(:foo_array, []).should be_a_kind_of(Sequel::Postgres::PGArray)
@@ -181,5 +181,47 @@ describe Sequel::Model, "#sti_key" do
181
181
  proc{StiTest2.dataset.row_proc.call(:kind=>1)}.should raise_error(Sequel::Error)
182
182
  proc{StiTest2.dataset.row_proc.call(:kind=>2)}.should raise_error(Sequel::Error)
183
183
  end
184
+
185
+ it "should work with non-bijective mappings" do
186
+ StiTest2.plugin :single_table_inheritance, :kind, :model_map=>{0=>'StiTest3', 1=>'StiTest3', 2=>'StiTest4'}
187
+ class ::StiTest3 < ::StiTest2; end
188
+ class ::StiTest4 < ::StiTest2; end
189
+ StiTest2.dataset.row_proc.call(:kind=>0).should be_a_instance_of(StiTest3)
190
+ StiTest2.dataset.row_proc.call(:kind=>1).should be_a_instance_of(StiTest3)
191
+ StiTest2.dataset.row_proc.call(:kind=>2).should be_a_instance_of(StiTest4)
192
+
193
+ StiTest3.create.kind.should == 1
194
+ StiTest4.create.kind.should == 2
195
+ end
196
+
197
+ it "should work with non-bijective mappings and key map procs" do
198
+ StiTest2.plugin :single_table_inheritance, :kind,
199
+ :key_map=>proc{|model| model.to_s == 'StiTest4' ? 2 : [0,1] }
200
+ class ::StiTest3 < ::StiTest2; end
201
+ class ::StiTest4 < ::StiTest2; end
202
+
203
+ StiTest2.dataset.sql.should == "SELECT * FROM sti_test2s"
204
+ StiTest3.dataset.sql.should == "SELECT * FROM sti_test2s WHERE (sti_test2s.kind IN (0, 1))"
205
+ StiTest4.dataset.sql.should == "SELECT * FROM sti_test2s WHERE (sti_test2s.kind IN (2))"
206
+ end
207
+
208
+ it "should create correct sql with non-bijective mappings" do
209
+ StiTest2.plugin :single_table_inheritance, :kind, :model_map=>{0=>'StiTest3', 1=>'StiTest3', 2=>'StiTest4'}
210
+ class ::StiTest3 < ::StiTest2; end
211
+ class ::StiTest4 < ::StiTest2; end
212
+
213
+ StiTest2.dataset.sql.should == "SELECT * FROM sti_test2s"
214
+ StiTest3.dataset.sql.should == "SELECT * FROM sti_test2s WHERE (sti_test2s.kind IN (0, 1))"
215
+ end
216
+
217
+ it "should honor a :key_chooser" do
218
+ StiTest2.plugin :single_table_inheritance, :kind, :key_chooser => proc{|inst| inst.model.to_s.downcase }
219
+ class ::StiTest3 < ::StiTest2; end
220
+ class ::StiTest4 < ::StiTest2; end
221
+
222
+ StiTest3.create.kind.should == 'stitest3'
223
+ StiTest4.create.kind.should == 'stitest4'
224
+ end
225
+
184
226
  end
185
227
  end
@@ -110,6 +110,46 @@ describe "Touch plugin" do
110
110
  "UPDATE artists SET updated_at = CURRENT_TIMESTAMP WHERE (artists.id = 1)"]
111
111
  end
112
112
 
113
+ specify "should be able to touch many_to_one associations" do
114
+ @Album.plugin :touch, :associations=>:artist
115
+ @Album.load(:id=>3, :artist_id=>4).touch
116
+ MODEL_DB.sqls.should == ["UPDATE albums SET updated_at = CURRENT_TIMESTAMP WHERE (id = 3)",
117
+ "UPDATE artists SET updated_at = CURRENT_TIMESTAMP WHERE (artists.id = 4)"]
118
+ end
119
+
120
+ specify "should be able to touch many_to_one associations" do
121
+ @Artist.one_to_one :album, :class=>@Album, :key=>:artist_id
122
+ @Artist.plugin :touch, :associations=>:album
123
+ @a.touch
124
+ MODEL_DB.sqls.should == ["UPDATE artists SET updated_at = CURRENT_TIMESTAMP WHERE (id = 1)",
125
+ "UPDATE albums SET updated_at = CURRENT_TIMESTAMP WHERE (albums.artist_id = 1)"]
126
+ end
127
+
128
+ specify "should be able to touch many_to_many associations" do
129
+ @Artist.many_to_many :albums, :class=>@Album, :left_key=>:artist_id, :join_table=>:aa
130
+ @Artist.plugin :touch, :associations=>:albums
131
+ @a.touch
132
+ MODEL_DB.sqls.should == ["UPDATE artists SET updated_at = CURRENT_TIMESTAMP WHERE (id = 1)",
133
+ "SELECT albums.* FROM albums INNER JOIN aa ON ((aa.album_id = albums.id) AND (aa.artist_id = 1))",
134
+ "UPDATE albums SET updated_at = CURRENT_TIMESTAMP WHERE (id = 1)"]
135
+ end
136
+
137
+ specify "should be able to touch many_through_many associations" do
138
+ @Artist.plugin :many_through_many
139
+ @Artist.many_through_many :albums, [[:aa, :artist_id, :album_id]], :class=>@Album
140
+ @Artist.plugin :touch, :associations=>:albums
141
+ @a.touch
142
+ MODEL_DB.sqls.should == ["UPDATE artists SET updated_at = CURRENT_TIMESTAMP WHERE (id = 1)",
143
+ "SELECT albums.* FROM albums INNER JOIN aa ON ((aa.album_id = albums.id) AND (aa.artist_id = 1))",
144
+ "UPDATE albums SET updated_at = CURRENT_TIMESTAMP WHERE (id = 1)"]
145
+ end
146
+
147
+ specify "should handle touching many_to_one associations with no associated object" do
148
+ @Album.plugin :touch, :associations=>:artist
149
+ @Album.load(:id=>3, :artist_id=>nil).touch
150
+ MODEL_DB.sqls.should == ["UPDATE albums SET updated_at = CURRENT_TIMESTAMP WHERE (id = 3)"]
151
+ end
152
+
113
153
  specify "should not update a column that doesn't exist" do
114
154
  @Album.plugin :touch, :column=>:x
115
155
  a = @Album.load(:id=>1)
@@ -578,7 +578,7 @@ describe Sequel::Model do
578
578
  specify "should validate uniqueness_of with allow_missing => true" do
579
579
  @c.validates_uniqueness_of :value, :allow_missing => true
580
580
  @m.should be_valid
581
- @m.value = nil
581
+ @m.value = 1
582
582
  @m.should_not be_valid
583
583
  end
584
584
  end
@@ -858,6 +858,12 @@ describe Sequel::Model, "Validations" do
858
858
  @user = User.new(:username => "0records", :password => "anothertest")
859
859
  @user.should be_valid
860
860
  @user.errors.full_messages.should == []
861
+
862
+ User.db.sqls
863
+ @user = User.new(:password => "anothertest")
864
+ @user.should be_valid
865
+ @user.errors.full_messages.should == []
866
+ User.db.sqls.should == []
861
867
  end
862
868
 
863
869
  it "should validate the uniqueness of multiple columns" do
@@ -907,6 +913,18 @@ describe Sequel::Model, "Validations" do
907
913
  @user = User.new(:username => "0records", :password => "anothertest")
908
914
  @user.should be_valid
909
915
  @user.errors.full_messages.should == []
916
+
917
+ User.db.sqls
918
+ @user = User.new(:password => "anothertest")
919
+ @user.should be_valid
920
+ @user.errors.full_messages.should == []
921
+ @user = User.new(:username => "0records")
922
+ @user.should be_valid
923
+ @user.errors.full_messages.should == []
924
+ @user = User.new
925
+ @user.should be_valid
926
+ @user.errors.full_messages.should == []
927
+ User.db.sqls.should == []
910
928
  end
911
929
 
912
930
  it "should have a validates block that contains multiple validations" do
@@ -331,6 +331,11 @@ describe "Sequel::Plugins::ValidationHelpers" do
331
331
  @user = @c.load(:id=>3, :username => "0records", :password => "anothertest")
332
332
  @user.should be_valid
333
333
 
334
+ MODEL_DB.sqls
335
+ @user = @c.new(:password => "anothertest")
336
+ @user.should be_valid
337
+ MODEL_DB.sqls.should == []
338
+
334
339
  @user = @c.new(:username => "1record", :password => "anothertest")
335
340
  @user.should_not be_valid
336
341
  @user.errors.full_messages.should == ['username is already taken']
@@ -369,6 +374,18 @@ describe "Sequel::Plugins::ValidationHelpers" do
369
374
  @user = @c.load(:id=>3, :username => "0records", :password => "anothertest")
370
375
  @user.should be_valid
371
376
 
377
+ MODEL_DB.sqls
378
+ @user = @c.new(:password => "anothertest")
379
+ @user.should be_valid
380
+ @user.errors.full_messages.should == []
381
+ @user = @c.new(:username => "0records")
382
+ @user.should be_valid
383
+ @user.errors.full_messages.should == []
384
+ @user = @c.new
385
+ @user.should be_valid
386
+ @user.errors.full_messages.should == []
387
+ MODEL_DB.sqls.should == []
388
+
372
389
  @user = @c.new(:username => "1record", :password => "anothertest")
373
390
  @user.should_not be_valid
374
391
  @user.errors.full_messages.should == ['username and password is already taken']
@@ -35,4 +35,18 @@ describe Sequel::Database do
35
35
  specify "should not have the connection pool swallow non-StandardError based exceptions" do
36
36
  proc{INTEGRATION_DB.pool.hold{raise Interrupt, "test"}}.should raise_error(Interrupt)
37
37
  end
38
+
39
+ specify "should be able to disconnect connections more than once without exceptions" do
40
+ conn = INTEGRATION_DB.synchronize{|c| c}
41
+ INTEGRATION_DB.disconnect
42
+ INTEGRATION_DB.disconnect_connection(conn)
43
+ INTEGRATION_DB.disconnect_connection(conn)
44
+ end
45
+
46
+ cspecify "should provide ability to check connections for validity", [:do, :postgres] do
47
+ conn = INTEGRATION_DB.synchronize{|c| c}
48
+ INTEGRATION_DB.valid_connection?(conn).should be_true
49
+ INTEGRATION_DB.disconnect
50
+ INTEGRATION_DB.valid_connection?(conn).should be_false
51
+ end
38
52
  end
@@ -717,19 +717,19 @@ describe Sequel::SQL::Constants do
717
717
  cspecify "should have working CURRENT_TIME", [:do, :mysql], [:jdbc, :sqlite], [:mysql2] do
718
718
  @db.create_table!(:constants){Time :t, :only_time=>true}
719
719
  @ds.insert(:t=>Sequel::CURRENT_TIME)
720
- (Time.now - @c[@ds.get(:t)]).should be_within(2).of(0)
720
+ (Time.now - @c[@ds.get(:t)]).should be_within(60).of(0)
721
721
  end
722
722
 
723
723
  cspecify "should have working CURRENT_TIMESTAMP", [:jdbc, :sqlite], [:swift] do
724
724
  @db.create_table!(:constants){DateTime :ts}
725
725
  @ds.insert(:ts=>Sequel::CURRENT_TIMESTAMP)
726
- (Time.now - @c[@ds.get(:ts)]).should be_within(2).of(0)
726
+ (Time.now - @c[@ds.get(:ts)]).should be_within(60).of(0)
727
727
  end
728
728
 
729
729
  cspecify "should have working CURRENT_TIMESTAMP when used as a column default", [:jdbc, :sqlite], [:swift] do
730
730
  @db.create_table!(:constants){DateTime :ts, :default=>Sequel::CURRENT_TIMESTAMP}
731
731
  @ds.insert
732
- (Time.now - @c[@ds.get(:ts)]).should be_within(2).of(0)
732
+ (Time.now - @c[@ds.get(:ts)]).should be_within(60).of(0)
733
733
  end
734
734
  end
735
735