sequel 3.43.0 → 3.44.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +32 -0
- data/doc/association_basics.rdoc +10 -3
- data/doc/release_notes/3.37.0.txt +1 -1
- data/doc/release_notes/3.44.0.txt +152 -0
- data/lib/sequel/adapters/ado.rb +0 -6
- data/lib/sequel/adapters/db2.rb +0 -3
- data/lib/sequel/adapters/dbi.rb +0 -6
- data/lib/sequel/adapters/ibmdb.rb +0 -3
- data/lib/sequel/adapters/jdbc.rb +8 -12
- data/lib/sequel/adapters/jdbc/as400.rb +2 -18
- data/lib/sequel/adapters/jdbc/derby.rb +10 -0
- data/lib/sequel/adapters/jdbc/h2.rb +10 -0
- data/lib/sequel/adapters/jdbc/hsqldb.rb +10 -0
- data/lib/sequel/adapters/jdbc/sqlite.rb +5 -0
- data/lib/sequel/adapters/jdbc/sqlserver.rb +2 -4
- data/lib/sequel/adapters/mock.rb +5 -0
- data/lib/sequel/adapters/mysql2.rb +4 -13
- data/lib/sequel/adapters/odbc.rb +0 -5
- data/lib/sequel/adapters/oracle.rb +3 -5
- data/lib/sequel/adapters/postgres.rb +2 -1
- data/lib/sequel/adapters/shared/access.rb +10 -0
- data/lib/sequel/adapters/shared/cubrid.rb +9 -0
- data/lib/sequel/adapters/shared/db2.rb +10 -0
- data/lib/sequel/adapters/shared/mssql.rb +10 -0
- data/lib/sequel/adapters/shared/mysql.rb +14 -0
- data/lib/sequel/adapters/shared/oracle.rb +15 -0
- data/lib/sequel/adapters/shared/postgres.rb +26 -2
- data/lib/sequel/adapters/shared/sqlite.rb +15 -0
- data/lib/sequel/adapters/tinytds.rb +5 -32
- data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +2 -37
- data/lib/sequel/core.rb +3 -3
- data/lib/sequel/database/misc.rb +40 -4
- data/lib/sequel/database/query.rb +1 -1
- data/lib/sequel/database/schema_methods.rb +33 -12
- data/lib/sequel/dataset/actions.rb +51 -2
- data/lib/sequel/dataset/features.rb +0 -6
- data/lib/sequel/dataset/sql.rb +1 -1
- data/lib/sequel/exceptions.rb +22 -7
- data/lib/sequel/extensions/columns_introspection.rb +30 -5
- data/lib/sequel/extensions/pg_auto_parameterize.rb +9 -0
- data/lib/sequel/model/associations.rb +50 -37
- data/lib/sequel/model/base.rb +30 -1
- data/lib/sequel/plugins/eager_each.rb +17 -21
- data/lib/sequel/plugins/identity_map.rb +2 -1
- data/lib/sequel/plugins/many_through_many.rb +1 -1
- data/lib/sequel/plugins/single_table_inheritance.rb +2 -2
- data/lib/sequel/plugins/tactical_eager_loading.rb +1 -1
- data/lib/sequel/sql.rb +4 -2
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/postgres_spec.rb +32 -2
- data/spec/adapters/sqlite_spec.rb +20 -0
- data/spec/core/database_spec.rb +40 -0
- data/spec/core/dataset_spec.rb +91 -4
- data/spec/core/mock_adapter_spec.rb +2 -1
- data/spec/core/schema_generator_spec.rb +4 -0
- data/spec/core/schema_spec.rb +9 -3
- data/spec/extensions/association_dependencies_spec.rb +3 -3
- data/spec/extensions/columns_introspection_spec.rb +28 -2
- data/spec/extensions/eager_each_spec.rb +0 -1
- data/spec/extensions/identity_map_spec.rb +3 -2
- data/spec/extensions/migration_spec.rb +6 -0
- data/spec/extensions/prepared_statements_associations_spec.rb +2 -2
- data/spec/extensions/rcte_tree_spec.rb +2 -2
- data/spec/extensions/single_table_inheritance_spec.rb +3 -0
- data/spec/extensions/tactical_eager_loading_spec.rb +1 -1
- data/spec/extensions/validation_class_methods_spec.rb +8 -0
- data/spec/integration/associations_test.rb +4 -4
- data/spec/integration/database_test.rb +68 -20
- data/spec/integration/dataset_test.rb +48 -0
- data/spec/integration/schema_test.rb +25 -1
- data/spec/model/associations_spec.rb +21 -8
- data/spec/model/dataset_methods_spec.rb +58 -18
- metadata +4 -2
@@ -439,8 +439,9 @@ describe "Sequel Mock Adapter" do
|
|
439
439
|
end
|
440
440
|
end
|
441
441
|
|
442
|
-
specify "should automatically set version for postgres" do
|
442
|
+
specify "should automatically set version for postgres and mssql" do
|
443
443
|
Sequel.mock(:host=>'postgres').server_version.should == 90103
|
444
|
+
Sequel.mock(:host=>'mssql').server_version.should == 10000000
|
444
445
|
end
|
445
446
|
|
446
447
|
specify "should stub out the primary_key method for postgres" do
|
@@ -19,6 +19,10 @@ describe Sequel::Schema::Generator do
|
|
19
19
|
@columns, @indexes, @constraints = @generator.columns, @generator.indexes, @generator.constraints
|
20
20
|
end
|
21
21
|
|
22
|
+
it "should respond to everything" do
|
23
|
+
@generator.respond_to?(:foo).should be_true
|
24
|
+
end if RUBY_VERSION >= '1.9'
|
25
|
+
|
22
26
|
it "should primary key column first" do
|
23
27
|
@columns.first[:name].should == :id
|
24
28
|
@columns.first[:primary_key].should == true
|
data/spec/core/schema_spec.rb
CHANGED
@@ -1219,14 +1219,20 @@ describe "Database#create_view" do
|
|
1219
1219
|
@db.create_view :test, @db[:items].select(:a, :b).order(:c)
|
1220
1220
|
@db.sqls.should == ['CREATE VIEW test AS SELECT a, b FROM items ORDER BY c']
|
1221
1221
|
@db.create_or_replace_view :sch__test, "SELECT * FROM xyz"
|
1222
|
-
@db.sqls.should == ['
|
1222
|
+
@db.sqls.should == ['DROP VIEW sch.test', 'CREATE VIEW sch.test AS SELECT * FROM xyz']
|
1223
1223
|
end
|
1224
1224
|
|
1225
1225
|
specify "should construct proper SQL with dataset" do
|
1226
1226
|
@db.create_or_replace_view :test, @db[:items].select(:a, :b).order(:c)
|
1227
|
-
@db.sqls.should == ['
|
1227
|
+
@db.sqls.should == ['DROP VIEW test', 'CREATE VIEW test AS SELECT a, b FROM items ORDER BY c']
|
1228
1228
|
@db.create_or_replace_view Sequel.identifier(:test), @db[:items].select(:a, :b).order(:c)
|
1229
|
-
@db.sqls.should == ['
|
1229
|
+
@db.sqls.should == ['DROP VIEW test', 'CREATE VIEW test AS SELECT a, b FROM items ORDER BY c']
|
1230
|
+
end
|
1231
|
+
|
1232
|
+
specify "should use CREATE OR REPLACE VIEW if such syntax is supported" do
|
1233
|
+
def @db.supports_create_or_replace_view?() true end
|
1234
|
+
@db.create_or_replace_view :test, @db[:items]
|
1235
|
+
@db.sqls.should == ['CREATE OR REPLACE VIEW test AS SELECT * FROM items']
|
1230
1236
|
end
|
1231
1237
|
end
|
1232
1238
|
|
@@ -33,13 +33,13 @@ describe "AssociationDependencies plugin" do
|
|
33
33
|
specify "should allow destroying associated one_to_one associated object" do
|
34
34
|
@Artist.add_association_dependencies :first_album=>:destroy
|
35
35
|
@Artist.load(:id=>2, :name=>'Ar').destroy
|
36
|
-
MODEL_DB.sqls.should == ['SELECT * FROM albums WHERE ((
|
36
|
+
MODEL_DB.sqls.should == ['SELECT * FROM albums WHERE ((position = 1) AND (albums.artist_id = 2)) LIMIT 1', 'DELETE FROM albums WHERE id = 1', 'DELETE FROM artists WHERE id = 2']
|
37
37
|
end
|
38
38
|
|
39
39
|
specify "should allow deleting associated one_to_one associated object" do
|
40
40
|
@Artist.add_association_dependencies :first_album=>:delete
|
41
41
|
@Artist.load(:id=>2, :name=>'Ar').destroy
|
42
|
-
MODEL_DB.sqls.should == ['DELETE FROM albums WHERE ((
|
42
|
+
MODEL_DB.sqls.should == ['DELETE FROM albums WHERE ((position = 1) AND (albums.artist_id = 2))', 'DELETE FROM artists WHERE id = 2']
|
43
43
|
end
|
44
44
|
|
45
45
|
specify "should allow destroying associated one_to_many objects" do
|
@@ -57,7 +57,7 @@ describe "AssociationDependencies plugin" do
|
|
57
57
|
specify "should allow nullifying associated one_to_one objects" do
|
58
58
|
@Artist.add_association_dependencies :first_album=>:nullify
|
59
59
|
@Artist.load(:id=>2, :name=>'Ar').destroy
|
60
|
-
MODEL_DB.sqls.should == ['UPDATE albums SET artist_id = NULL WHERE ((
|
60
|
+
MODEL_DB.sqls.should == ['UPDATE albums SET artist_id = NULL WHERE ((position = 1) AND (artist_id = 2))', 'DELETE FROM artists WHERE id = 2']
|
61
61
|
end
|
62
62
|
|
63
63
|
specify "should allow nullifying associated one_to_many objects" do
|
@@ -25,10 +25,10 @@ end
|
|
25
25
|
|
26
26
|
describe "columns_introspection extension" do
|
27
27
|
before do
|
28
|
-
@db =
|
28
|
+
@db = Sequel.mock
|
29
29
|
@ds = @db[:a]
|
30
30
|
@ds.extend(Sequel::ColumnsIntrospection.dup) # dup to allow multiple places in class hierarchy
|
31
|
-
@db.
|
31
|
+
@db.sqls
|
32
32
|
end
|
33
33
|
|
34
34
|
specify "should not issue a database query if the columns are already loaded" do
|
@@ -74,6 +74,32 @@ describe "columns_introspection extension" do
|
|
74
74
|
@db.sqls.length.should == 0
|
75
75
|
end
|
76
76
|
|
77
|
+
specify "should handle selecting * from a single subselect with no joins without a database query if the subselect's columns can be handled" do
|
78
|
+
@ds.select(:x).from_self.columns.should == [:x]
|
79
|
+
@db.sqls.length.should == 0
|
80
|
+
@ds.select(:x).from_self.from_self.columns.should == [:x]
|
81
|
+
@db.sqls.length.should == 0
|
82
|
+
end
|
83
|
+
|
84
|
+
specify "should handle selecting * from a single table with no joins without a database query if the database has cached schema columns for the table" do
|
85
|
+
@db.instance_variable_set(:@schemas, "a"=>[[:x, {}]])
|
86
|
+
@ds.columns.should == [:x]
|
87
|
+
@db.sqls.length.should == 0
|
88
|
+
end
|
89
|
+
|
90
|
+
specify "should issue a database query for multiple subselects or joins" do
|
91
|
+
@ds.from(@ds.select(:x), @ds.select(:y)).columns
|
92
|
+
@db.sqls.length.should == 1
|
93
|
+
@ds.select(:x).from_self.natural_join(:a).columns
|
94
|
+
@db.sqls.length.should == 1
|
95
|
+
end
|
96
|
+
|
97
|
+
specify "should issue a database query when common table expressions are used" do
|
98
|
+
@db.instance_variable_set(:@schemas, "a"=>[[:x, {}]])
|
99
|
+
@ds.with(:a, @ds).columns
|
100
|
+
@db.sqls.length.should == 1
|
101
|
+
end
|
102
|
+
|
77
103
|
specify "should issue a database query if the wildcard is selected" do
|
78
104
|
@ds.columns
|
79
105
|
@db.sqls.length.should == 1
|
@@ -30,5 +30,4 @@ describe "Sequel::Plugins::EagerEach" do
|
|
30
30
|
a.map{|c| c.associations[:children]}.should == [[@c.load(:id=>3, :parent_id=>1), @c.load(:id=>4, :parent_id=>1)], [@c.load(:id=>5, :parent_id=>2), @c.load(:id=>6, :parent_id=>2)]]
|
31
31
|
@c.db.sqls.should == ['SELECT items.id, items.parent_id, children.id AS children_id, children.parent_id AS children_parent_id FROM items LEFT OUTER JOIN items AS children ON (children.parent_id = items.id)']
|
32
32
|
end
|
33
|
-
|
34
33
|
end
|
@@ -282,9 +282,10 @@ describe "Sequel::Plugins::IdentityMap" do
|
|
282
282
|
|
283
283
|
it "should work correctly when eagerly loading many_to_many associations with composite keys" do
|
284
284
|
@c1.columns :id, :id2
|
285
|
-
@c2.columns :id
|
285
|
+
@c2.columns :id, :id2
|
286
286
|
@c1.set_primary_key :id, :id2
|
287
|
-
@
|
287
|
+
@c2.set_primary_key :id, :id2
|
288
|
+
@c1.many_to_many :artists, :class=>@c2, :left_key=>[:album_id1, :album_id2], :right_key=>[:artist_id1, :artist_id2], :join_table=>:aa
|
288
289
|
@c1.dataset._fetch = [{:id=>1, :id2=>4}, {:id=>2, :id2=>5}, {:id=>3, :id2=>6}]
|
289
290
|
@c2.dataset._fetch = [ {:id=>1, :x_foreign_key_0_x=>1, :x_foreign_key_1_x=>4}, {:id=>1, :x_foreign_key_0_x=>2, :x_foreign_key_1_x=>5}, {:id=>2, :x_foreign_key_0_x=>1, :x_foreign_key_1_x=>4}, {:id=>2, :x_foreign_key_0_x=>2, :x_foreign_key_1_x=>5}, {:id=>3, :x_foreign_key_0_x=>1, :x_foreign_key_1_x=>4}, {:id=>3, :x_foreign_key_0_x=>1, :x_foreign_key_1_x=>4}]
|
290
291
|
|
@@ -55,6 +55,12 @@ describe "Migration.apply" do
|
|
55
55
|
m.apply(@db, :up).should == nil
|
56
56
|
m.apply(@db, :down).should == nil
|
57
57
|
end
|
58
|
+
|
59
|
+
specify "should respond to the methods the database responds to" do
|
60
|
+
m = Sequel::Migration.new(Sequel.mock)
|
61
|
+
m.respond_to?(:foo).should be_false
|
62
|
+
m.respond_to?(:execute).should be_true
|
63
|
+
end if RUBY_VERSION >= '1.9'
|
58
64
|
end
|
59
65
|
|
60
66
|
describe "SimpleMigration#apply" do
|
@@ -92,7 +92,7 @@ describe "Sequel::Plugins::AssociationPks" do
|
|
92
92
|
specify "should run a regular query if :conditions option is used when defining the association" do
|
93
93
|
@Artist.one_to_many :albums, :class=>@Album, :key=>:artist_id, :conditions=>{:a=>1}
|
94
94
|
@Artist.load(:id=>1).albums
|
95
|
-
@db.sqls.should == ["SELECT * FROM albums WHERE ((
|
95
|
+
@db.sqls.should == ["SELECT * FROM albums WHERE ((a = 1) AND (albums.artist_id = 1))"]
|
96
96
|
end
|
97
97
|
|
98
98
|
specify "should run a regular query if :dataset option is used when defining the association" do
|
@@ -106,6 +106,6 @@ describe "Sequel::Plugins::AssociationPks" do
|
|
106
106
|
@Artist.one_to_many :albums, :class=>@Album, :key=>:artist_id, :conditions=>{:a=>1}
|
107
107
|
@Artist.one_to_many :oalbums, :clone=>:albums
|
108
108
|
@Artist.load(:id=>1).oalbums
|
109
|
-
@db.sqls.should == ["SELECT * FROM albums WHERE ((
|
109
|
+
@db.sqls.should == ["SELECT * FROM albums WHERE ((a = 1) AND (albums.artist_id = 1))"]
|
110
110
|
end
|
111
111
|
end
|
@@ -49,8 +49,8 @@ describe Sequel::Model, "rcte_tree" do
|
|
49
49
|
|
50
50
|
it "should use the correct SQL for lazy associations with :conditions option" do
|
51
51
|
@c.plugin :rcte_tree, :conditions => {:i => 1}
|
52
|
-
@o.parent_dataset.sql.should == 'SELECT * FROM nodes WHERE ((
|
53
|
-
@o.children_dataset.sql.should == 'SELECT * FROM nodes WHERE ((
|
52
|
+
@o.parent_dataset.sql.should == 'SELECT * FROM nodes WHERE ((i = 1) AND (nodes.id = 1)) LIMIT 1'
|
53
|
+
@o.children_dataset.sql.should == 'SELECT * FROM nodes WHERE ((i = 1) AND (nodes.parent_id = 2))'
|
54
54
|
@o.ancestors_dataset.sql.should == 'WITH t AS (SELECT * FROM nodes WHERE ((id = 1) AND (i = 1)) UNION ALL SELECT nodes.* FROM nodes INNER JOIN t ON (t.parent_id = nodes.id) WHERE (i = 1)) SELECT * FROM t AS nodes WHERE (i = 1)'
|
55
55
|
@o.descendants_dataset.sql.should == 'WITH t AS (SELECT * FROM nodes WHERE ((parent_id = 2) AND (i = 1)) UNION ALL SELECT nodes.* FROM nodes INNER JOIN t ON (t.id = nodes.parent_id) WHERE (i = 1)) SELECT * FROM t AS nodes WHERE (i = 1)'
|
56
56
|
end
|
@@ -158,6 +158,9 @@ describe Sequel::Model, "#sti_key" do
|
|
158
158
|
StiTest2.create.kind.should == 4
|
159
159
|
StiTest3.create.kind.should == 5
|
160
160
|
StiTest4.create.kind.should == 6
|
161
|
+
|
162
|
+
class ::StiTest5 < ::StiTest4; end
|
163
|
+
StiTest5.create.kind.should == nil
|
161
164
|
end
|
162
165
|
|
163
166
|
it "should infer key_map from model_map if provided as a hash" do
|
@@ -25,7 +25,7 @@ describe "Sequel::Plugins::TacticalEagerLoading" do
|
|
25
25
|
Object.send(:remove_const, :TaticalEagerLoadingModel)
|
26
26
|
end
|
27
27
|
|
28
|
-
it "Dataset#all should set the retrieved_by and
|
28
|
+
it "Dataset#all should set the retrieved_by and retrieved_with attributes" do
|
29
29
|
ts = @c.all
|
30
30
|
ts.map{|x| [x.retrieved_by, x.retrieved_with]}.should == [[@ds,ts], [@ds,ts], [@ds,ts], [@ds,ts]]
|
31
31
|
end
|
@@ -138,6 +138,14 @@ describe Sequel::Model do
|
|
138
138
|
o.valid?.should == false
|
139
139
|
o.errors.full_messages.should == ['blah is not cool']
|
140
140
|
end
|
141
|
+
|
142
|
+
specify "should have the validates block have appropriate respond_to?" do
|
143
|
+
c = nil
|
144
|
+
@c.validates{c = respond_to?(:foo)}
|
145
|
+
c.should be_false
|
146
|
+
@c.validates{c = respond_to?(:length_of)}
|
147
|
+
c.should be_true
|
148
|
+
end if RUBY_VERSION >= '1.9'
|
141
149
|
end
|
142
150
|
|
143
151
|
describe Sequel::Model do
|
@@ -51,8 +51,8 @@ shared_examples_for "eager limit strategies" do
|
|
51
51
|
end
|
52
52
|
|
53
53
|
specify "should correctly handle limits and offsets when eager loading many_to_many associations" do
|
54
|
-
if @els == {:eager_limit_strategy=>:correlated_subquery} && Sequel.guarded?(:derby)
|
55
|
-
pending("
|
54
|
+
if @els == {:eager_limit_strategy=>:correlated_subquery} && Sequel.guarded?(:derby, :mssql)
|
55
|
+
pending("correlated subqueries on many_to_many associations not supported")
|
56
56
|
end
|
57
57
|
Album.many_to_many :first_two_tags, {:clone=>:first_two_tags}.merge(@els) if @els
|
58
58
|
Album.many_to_many :second_two_tags, {:clone=>:second_two_tags}.merge(@els) if @els
|
@@ -76,8 +76,8 @@ shared_examples_for "eager limit strategies" do
|
|
76
76
|
end
|
77
77
|
|
78
78
|
specify "should correctly handle limits and offsets when eager loading many_through_many associations" do
|
79
|
-
if @els == {:eager_limit_strategy=>:correlated_subquery} && Sequel.guarded?(:derby)
|
80
|
-
pending("
|
79
|
+
if @els == {:eager_limit_strategy=>:correlated_subquery} && Sequel.guarded?(:derby, :mssql)
|
80
|
+
pending("correlated subqueries on many_through_many associations not supported")
|
81
81
|
end
|
82
82
|
Artist.many_through_many :first_two_tags, {:clone=>:first_two_tags}.merge(@els) if @els
|
83
83
|
Artist.many_through_many :second_two_tags, {:clone=>:second_two_tags}.merge(@els) if @els
|
@@ -1,28 +1,76 @@
|
|
1
1
|
require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper.rb')
|
2
2
|
|
3
3
|
describe Sequel::Database do
|
4
|
+
before do
|
5
|
+
@db = INTEGRATION_DB
|
6
|
+
end
|
7
|
+
|
4
8
|
specify "should provide disconnect functionality" do
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
+
@db.disconnect
|
10
|
+
@db.pool.size.should == 0
|
11
|
+
@db.test_connection
|
12
|
+
@db.pool.size.should == 1
|
9
13
|
end
|
10
14
|
|
11
15
|
specify "should provide disconnect functionality after preparing a statement" do
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
16
|
+
@db.create_table!(:items){Integer :i}
|
17
|
+
@db[:items].prepare(:first, :a).call
|
18
|
+
@db.disconnect
|
19
|
+
@db.pool.size.should == 0
|
20
|
+
@db.drop_table?(:items)
|
17
21
|
end
|
18
22
|
|
19
23
|
specify "should raise Sequel::DatabaseError on invalid SQL" do
|
20
|
-
proc{
|
24
|
+
proc{@db << "SELECT"}.should raise_error(Sequel::DatabaseError)
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "constraint violations" do
|
28
|
+
before do
|
29
|
+
@db.drop_table?(:test2, :test)
|
30
|
+
end
|
31
|
+
after do
|
32
|
+
@db.drop_table?(:test2, :test)
|
33
|
+
end
|
34
|
+
|
35
|
+
cspecify "should raise Sequel::UniqueConstraintViolation when a unique constraint is violated", [:jdbc, :sqlite], [:db2] do
|
36
|
+
@db.create_table!(:test){String :a, :unique=>true, :null=>false}
|
37
|
+
@db[:test].insert('1')
|
38
|
+
proc{@db[:test].insert('1')}.should raise_error(Sequel::UniqueConstraintViolation)
|
39
|
+
@db[:test].insert('2')
|
40
|
+
proc{@db[:test].update(:a=>'1')}.should raise_error(Sequel::UniqueConstraintViolation)
|
41
|
+
end
|
42
|
+
|
43
|
+
cspecify "should raise Sequel::CheckConstraintViolation when a check constraint is violated", :mysql, :sqlite, [:db2] do
|
44
|
+
@db.create_table!(:test){String :a; check Sequel.~(:a=>'1')}
|
45
|
+
proc{@db[:test].insert('1')}.should raise_error(Sequel::CheckConstraintViolation)
|
46
|
+
@db[:test].insert('2')
|
47
|
+
proc{@db[:test].insert('1')}.should raise_error(Sequel::CheckConstraintViolation)
|
48
|
+
end
|
49
|
+
|
50
|
+
cspecify "should raise Sequel::ForeignKeyConstraintViolation when a foreign key constraint is violated", [:jdbc, :sqlite], [:db2] do
|
51
|
+
@db.create_table!(:test, :engine=>:InnoDB){primary_key :id}
|
52
|
+
@db.create_table!(:test2, :engine=>:InnoDB){foreign_key :tid, :test}
|
53
|
+
proc{@db[:test2].insert(:tid=>1)}.should raise_error(Sequel::ForeignKeyConstraintViolation)
|
54
|
+
@db[:test].insert
|
55
|
+
@db[:test2].insert(:tid=>1)
|
56
|
+
proc{@db[:test2].where(:tid=>1).update(:tid=>3)}.should raise_error(Sequel::ForeignKeyConstraintViolation)
|
57
|
+
proc{@db[:test].where(:id=>1).delete}.should raise_error(Sequel::ForeignKeyConstraintViolation)
|
58
|
+
end
|
59
|
+
|
60
|
+
cspecify "should raise Sequel::NotNullConstraintViolation when a not null constraint is violated", [:jdbc, :sqlite], [:db2] do
|
61
|
+
@db.create_table!(:test){Integer :a, :null=>false}
|
62
|
+
proc{@db[:test].insert(:a=>nil)}.should raise_error(Sequel::NotNullConstraintViolation)
|
63
|
+
unless @db.database_type == :mysql
|
64
|
+
# Broken mysql silently changes NULL here to 0, and doesn't raise an exception.
|
65
|
+
@db[:test].insert(2)
|
66
|
+
proc{@db[:test].update(:a=>nil)}.should raise_error(Sequel::NotNullConstraintViolation)
|
67
|
+
end
|
68
|
+
end
|
21
69
|
end
|
22
70
|
|
23
71
|
specify "should store underlying wrapped exception in Sequel::DatabaseError" do
|
24
72
|
begin
|
25
|
-
|
73
|
+
@db << "SELECT"
|
26
74
|
rescue Sequel::DatabaseError=>e
|
27
75
|
if defined?(Java::JavaLang::Exception)
|
28
76
|
(e.wrapped_exception.is_a?(Exception) || e.wrapped_exception.is_a?(Java::JavaLang::Exception)).should be_true
|
@@ -33,20 +81,20 @@ describe Sequel::Database do
|
|
33
81
|
end
|
34
82
|
|
35
83
|
specify "should not have the connection pool swallow non-StandardError based exceptions" do
|
36
|
-
proc{
|
84
|
+
proc{@db.pool.hold{raise Interrupt, "test"}}.should raise_error(Interrupt)
|
37
85
|
end
|
38
86
|
|
39
87
|
specify "should be able to disconnect connections more than once without exceptions" do
|
40
|
-
conn =
|
41
|
-
|
42
|
-
|
43
|
-
|
88
|
+
conn = @db.synchronize{|c| c}
|
89
|
+
@db.disconnect
|
90
|
+
@db.disconnect_connection(conn)
|
91
|
+
@db.disconnect_connection(conn)
|
44
92
|
end
|
45
93
|
|
46
94
|
cspecify "should provide ability to check connections for validity", [:do, :postgres] do
|
47
|
-
conn =
|
48
|
-
|
49
|
-
|
50
|
-
|
95
|
+
conn = @db.synchronize{|c| c}
|
96
|
+
@db.valid_connection?(conn).should be_true
|
97
|
+
@db.disconnect
|
98
|
+
@db.valid_connection?(conn).should be_false
|
51
99
|
end
|
52
100
|
end
|
@@ -98,6 +98,28 @@ describe "Simple Dataset operations" do
|
|
98
98
|
@ds.all.should == [{:id=>1, :number=>10}]
|
99
99
|
end
|
100
100
|
|
101
|
+
specify "should iterate over records as they come in" do
|
102
|
+
called = false
|
103
|
+
@ds.each{|row| called = true; row.should == {:id=>1, :number=>10}}
|
104
|
+
called.should == true
|
105
|
+
end
|
106
|
+
|
107
|
+
specify "should support iterating over large numbers of records with paged_each" do
|
108
|
+
(2..100).each{|i| @ds.insert(:number=>i*10)}
|
109
|
+
|
110
|
+
rows = []
|
111
|
+
@ds.order(:number).paged_each(:rows_per_fetch=>5){|row| rows << row}
|
112
|
+
rows.should == (1..100).map{|i| {:id=>i, :number=>i*10}}
|
113
|
+
|
114
|
+
rows = []
|
115
|
+
@ds.order(:number).paged_each(:rows_per_fetch=>3){|row| rows << row}
|
116
|
+
rows.should == (1..100).map{|i| {:id=>i, :number=>i*10}}
|
117
|
+
|
118
|
+
rows = []
|
119
|
+
@ds.order(:number).limit(50, 25).paged_each(:rows_per_fetch=>3){|row| rows << row}
|
120
|
+
rows.should == (26..75).map{|i| {:id=>i, :number=>i*10}}
|
121
|
+
end
|
122
|
+
|
101
123
|
specify "should fetch all results correctly" do
|
102
124
|
@ds.all.should == [{:id=>1, :number=>10}]
|
103
125
|
end
|
@@ -170,6 +192,32 @@ describe "Simple Dataset operations" do
|
|
170
192
|
@ds.where(:id=>@ds.select(:id).order(:id).limit(2, 1)).all.should == [{:id=>2, :number=>20}]
|
171
193
|
end
|
172
194
|
|
195
|
+
specify "should fetch correctly when using limit and offset in a from_self" do
|
196
|
+
@ds.insert(:number=>20)
|
197
|
+
ds = @ds.order(:id).limit(1, 1).from_self
|
198
|
+
ds.all.should == [{:number=>20, :id=>2}]
|
199
|
+
ds.columns.should == [:id, :number]
|
200
|
+
@ds.order(:id).limit(1, 1).columns.should == [:id, :number]
|
201
|
+
end
|
202
|
+
|
203
|
+
specify "should fetch correctly when using nested limit and offset in a from_self" do
|
204
|
+
@ds.insert(:number=>20)
|
205
|
+
@ds.insert(:number=>30)
|
206
|
+
ds = @ds.order(:id).limit(2, 1).from_self.reverse_order(:number).limit(1, 1)
|
207
|
+
ds.all.should == [{:number=>20, :id=>2}]
|
208
|
+
ds.columns.should == [:id, :number]
|
209
|
+
@ds.order(:id).limit(2, 1).from_self.reverse_order(:number).limit(1, 1).columns.should == [:id, :number]
|
210
|
+
|
211
|
+
ds = @ds.order(:id).limit(3, 1).from_self.limit(2, 1).from_self.limit(1, 1)
|
212
|
+
ds.all.should == []
|
213
|
+
ds.columns.should == [:id, :number]
|
214
|
+
|
215
|
+
@ds.insert(:number=>40)
|
216
|
+
ds = @ds.order(:id).limit(3, 1).from_self.reverse_order(:number).limit(2, 1).from_self.reverse_order(:id).limit(1, 1)
|
217
|
+
ds.all.should == [{:number=>20, :id=>2}]
|
218
|
+
ds.columns.should == [:id, :number]
|
219
|
+
end
|
220
|
+
|
173
221
|
specify "should alias columns correctly" do
|
174
222
|
@ds.select(:id___x, :number___n).first.should == {:x=>1, :n=>10}
|
175
223
|
end
|
@@ -274,6 +274,30 @@ describe "Database schema modifiers" do
|
|
274
274
|
@db[:items2].all.should == [{:number=>10}]
|
275
275
|
end
|
276
276
|
|
277
|
+
describe "views" do
|
278
|
+
before do
|
279
|
+
@db.drop_view(:items_view) rescue nil
|
280
|
+
@db.create_table(:items){Integer :number}
|
281
|
+
@ds.insert(:number=>1)
|
282
|
+
@ds.insert(:number=>2)
|
283
|
+
end
|
284
|
+
after do
|
285
|
+
@db.drop_view(:items_view)
|
286
|
+
end
|
287
|
+
|
288
|
+
specify "should create views correctly" do
|
289
|
+
@db.create_view(:items_view, @ds.where(:number=>1))
|
290
|
+
@db[:items_view].map(:number).should == [1]
|
291
|
+
end
|
292
|
+
|
293
|
+
specify "should create or replace views correctly" do
|
294
|
+
@db.create_or_replace_view(:items_view, @ds.where(:number=>1))
|
295
|
+
@db[:items_view].map(:number).should == [1]
|
296
|
+
@db.create_or_replace_view(:items_view, @ds.where(:number=>2))
|
297
|
+
@db[:items_view].map(:number).should == [2]
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
277
301
|
specify "should handle create table in a rolled back transaction" do
|
278
302
|
@db.drop_table?(:items)
|
279
303
|
@db.transaction(:rollback=>:always){@db.create_table(:items){Integer :number}}
|
@@ -298,7 +322,7 @@ describe "Database schema modifiers" do
|
|
298
322
|
specify "should create temporary tables without raising an exception" do
|
299
323
|
@db.create_table!(:items, :temp=>true){Integer :number}
|
300
324
|
end
|
301
|
-
|
325
|
+
|
302
326
|
specify "should have create_table? only create the table if it doesn't already exist" do
|
303
327
|
@db.create_table!(:items){String :a}
|
304
328
|
@db.create_table?(:items){String :b}
|