sequel 3.40.0 → 3.41.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +40 -0
- data/README.rdoc +2 -2
- data/doc/advanced_associations.rdoc +12 -0
- data/doc/bin_sequel.rdoc +144 -0
- data/doc/migration.rdoc +1 -1
- data/doc/object_model.rdoc +29 -0
- data/doc/release_notes/3.41.0.txt +155 -0
- data/lib/sequel/adapters/ado.rb +4 -4
- data/lib/sequel/adapters/amalgalite.rb +0 -5
- data/lib/sequel/adapters/cubrid.rb +2 -2
- data/lib/sequel/adapters/db2.rb +9 -5
- data/lib/sequel/adapters/dbi.rb +4 -6
- data/lib/sequel/adapters/do.rb +4 -5
- data/lib/sequel/adapters/firebird.rb +8 -4
- data/lib/sequel/adapters/ibmdb.rb +2 -3
- data/lib/sequel/adapters/informix.rb +0 -6
- data/lib/sequel/adapters/jdbc.rb +11 -7
- data/lib/sequel/adapters/jdbc/db2.rb +22 -0
- data/lib/sequel/adapters/jdbc/derby.rb +5 -5
- data/lib/sequel/adapters/jdbc/h2.rb +0 -5
- data/lib/sequel/adapters/jdbc/jtds.rb +1 -1
- data/lib/sequel/adapters/jdbc/sqlserver.rb +6 -0
- data/lib/sequel/adapters/mock.rb +3 -3
- data/lib/sequel/adapters/mysql.rb +7 -7
- data/lib/sequel/adapters/mysql2.rb +0 -5
- data/lib/sequel/adapters/odbc.rb +4 -4
- data/lib/sequel/adapters/openbase.rb +4 -6
- data/lib/sequel/adapters/oracle.rb +14 -6
- data/lib/sequel/adapters/postgres.rb +12 -8
- data/lib/sequel/adapters/shared/db2.rb +5 -0
- data/lib/sequel/adapters/shared/firebird.rb +10 -0
- data/lib/sequel/adapters/shared/mssql.rb +43 -1
- data/lib/sequel/adapters/shared/mysql.rb +1 -0
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +1 -1
- data/lib/sequel/adapters/shared/postgres.rb +12 -0
- data/lib/sequel/adapters/shared/sqlite.rb +32 -0
- data/lib/sequel/adapters/sqlite.rb +9 -8
- data/lib/sequel/adapters/swift.rb +3 -8
- data/lib/sequel/adapters/tinytds.rb +5 -5
- data/lib/sequel/connection_pool.rb +13 -19
- data/lib/sequel/connection_pool/sharded_single.rb +12 -12
- data/lib/sequel/connection_pool/sharded_threaded.rb +37 -17
- data/lib/sequel/connection_pool/single.rb +6 -3
- data/lib/sequel/connection_pool/threaded.rb +33 -13
- data/lib/sequel/database/connecting.rb +28 -1
- data/lib/sequel/database/logging.rb +1 -1
- data/lib/sequel/database/misc.rb +2 -5
- data/lib/sequel/database/query.rb +2 -2
- data/lib/sequel/database/schema_generator.rb +1 -1
- data/lib/sequel/database/schema_methods.rb +3 -0
- data/lib/sequel/dataset/query.rb +8 -4
- data/lib/sequel/dataset/sql.rb +7 -0
- data/lib/sequel/extensions/arbitrary_servers.rb +1 -1
- data/lib/sequel/extensions/connection_validator.rb +109 -0
- data/lib/sequel/extensions/pg_array.rb +2 -0
- data/lib/sequel/extensions/pg_hstore.rb +2 -0
- data/lib/sequel/extensions/pg_json.rb +4 -0
- data/lib/sequel/extensions/pg_range.rb +1 -0
- data/lib/sequel/extensions/pg_row.rb +4 -0
- data/lib/sequel/plugins/prepared_statements.rb +2 -1
- data/lib/sequel/plugins/single_table_inheritance.rb +53 -10
- data/lib/sequel/plugins/touch.rb +18 -6
- data/lib/sequel/plugins/validation_class_methods.rb +1 -0
- data/lib/sequel/plugins/validation_helpers.rb +3 -1
- data/lib/sequel/sql.rb +61 -19
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/firebird_spec.rb +52 -38
- data/spec/adapters/mssql_spec.rb +67 -0
- data/spec/adapters/mysql_spec.rb +192 -116
- data/spec/adapters/postgres_spec.rb +133 -70
- data/spec/adapters/spec_helper.rb +7 -0
- data/spec/adapters/sqlite_spec.rb +34 -1
- data/spec/core/connection_pool_spec.rb +79 -75
- data/spec/core/database_spec.rb +9 -4
- data/spec/core/dataset_spec.rb +15 -0
- data/spec/core/expression_filters_spec.rb +40 -2
- data/spec/extensions/connection_validator_spec.rb +118 -0
- data/spec/extensions/pg_array_spec.rb +4 -0
- data/spec/extensions/single_table_inheritance_spec.rb +42 -0
- data/spec/extensions/touch_spec.rb +40 -0
- data/spec/extensions/validation_class_methods_spec.rb +19 -1
- data/spec/extensions/validation_helpers_spec.rb +17 -0
- data/spec/integration/database_test.rb +14 -0
- data/spec/integration/dataset_test.rb +3 -3
- data/spec/integration/plugin_test.rb +41 -12
- data/spec/integration/schema_test.rb +14 -0
- data/spec/integration/spec_helper.rb +7 -0
- data/spec/integration/type_test.rb +3 -0
- metadata +9 -3
data/spec/core/database_spec.rb
CHANGED
@@ -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
|
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)
|
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
|
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)
|
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
|
data/spec/core/dataset_spec.rb
CHANGED
@@ -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::
|
555
|
-
Sequel.expr{
|
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 =
|
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(
|
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(
|
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(
|
732
|
+
(Time.now - @c[@ds.get(:ts)]).should be_within(60).of(0)
|
733
733
|
end
|
734
734
|
end
|
735
735
|
|