sequel 3.43.0 → 3.44.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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}
|