sequel 2.7.1 → 2.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +56 -0
- data/README +1 -0
- data/Rakefile +1 -1
- data/lib/sequel_core.rb +9 -16
- data/lib/sequel_core/adapters/ado.rb +6 -15
- data/lib/sequel_core/adapters/db2.rb +8 -10
- data/lib/sequel_core/adapters/dbi.rb +6 -4
- data/lib/sequel_core/adapters/informix.rb +21 -22
- data/lib/sequel_core/adapters/jdbc.rb +69 -10
- data/lib/sequel_core/adapters/jdbc/postgresql.rb +1 -0
- data/lib/sequel_core/adapters/mysql.rb +81 -13
- data/lib/sequel_core/adapters/odbc.rb +32 -4
- data/lib/sequel_core/adapters/openbase.rb +6 -5
- data/lib/sequel_core/adapters/oracle.rb +23 -7
- data/lib/sequel_core/adapters/postgres.rb +42 -32
- data/lib/sequel_core/adapters/shared/mssql.rb +37 -62
- data/lib/sequel_core/adapters/shared/mysql.rb +22 -7
- data/lib/sequel_core/adapters/shared/oracle.rb +27 -48
- data/lib/sequel_core/adapters/shared/postgres.rb +64 -43
- data/lib/sequel_core/adapters/shared/progress.rb +31 -0
- data/lib/sequel_core/adapters/shared/sqlite.rb +15 -4
- data/lib/sequel_core/adapters/sqlite.rb +6 -14
- data/lib/sequel_core/connection_pool.rb +47 -13
- data/lib/sequel_core/database.rb +60 -35
- data/lib/sequel_core/database/schema.rb +4 -4
- data/lib/sequel_core/dataset.rb +12 -3
- data/lib/sequel_core/dataset/convenience.rb +4 -13
- data/lib/sequel_core/dataset/prepared_statements.rb +30 -28
- data/lib/sequel_core/dataset/sql.rb +144 -85
- data/lib/sequel_core/dataset/stored_procedures.rb +75 -0
- data/lib/sequel_core/dataset/unsupported.rb +31 -0
- data/lib/sequel_core/exceptions.rb +6 -0
- data/lib/sequel_core/schema/generator.rb +4 -3
- data/lib/sequel_core/schema/sql.rb +41 -23
- data/lib/sequel_core/sql.rb +29 -1
- data/lib/sequel_model/associations.rb +1 -1
- data/lib/sequel_model/record.rb +31 -28
- data/spec/adapters/mysql_spec.rb +37 -4
- data/spec/adapters/oracle_spec.rb +26 -4
- data/spec/adapters/sqlite_spec.rb +7 -0
- data/spec/integration/prepared_statement_test.rb +24 -0
- data/spec/integration/schema_test.rb +1 -1
- data/spec/sequel_core/connection_pool_spec.rb +49 -2
- data/spec/sequel_core/core_sql_spec.rb +9 -2
- data/spec/sequel_core/database_spec.rb +64 -14
- data/spec/sequel_core/dataset_spec.rb +105 -7
- data/spec/sequel_core/schema_spec.rb +40 -12
- data/spec/sequel_core/spec_helper.rb +1 -0
- data/spec/sequel_model/spec_helper.rb +1 -0
- metadata +6 -3
data/spec/adapters/mysql_spec.rb
CHANGED
@@ -12,7 +12,6 @@ unless defined?(MYSQL_SOCKET_FILE)
|
|
12
12
|
end
|
13
13
|
|
14
14
|
MYSQL_URI = URI.parse(MYSQL_DB.uri)
|
15
|
-
MYSQL_DB_NAME = (m = /\/(.*)/.match(MYSQL_URI.path)) && m[1]
|
16
15
|
|
17
16
|
MYSQL_DB.create_table! :items do
|
18
17
|
text :name
|
@@ -482,23 +481,32 @@ context "A MySQL database" do
|
|
482
481
|
@db << 'DELETE FROM items'
|
483
482
|
@db[:items].first.should == nil
|
484
483
|
end
|
484
|
+
|
485
|
+
specify "should handle multiple select statements at once" do
|
486
|
+
@db << 'DELETE FROM items; '
|
487
|
+
|
488
|
+
@db[:items].delete
|
489
|
+
@db[:items].insert(:name => 'tutu', :value => 1234)
|
490
|
+
@db["SELECT * FROM items; SELECT * FROM items"].all.should == \
|
491
|
+
[{:name => 'tutu', :value => 1234}, {:name => 'tutu', :value => 1234}]
|
492
|
+
end
|
485
493
|
end
|
486
494
|
|
487
495
|
# Socket tests should only be run if the MySQL server is on localhost
|
488
496
|
if %w'localhost 127.0.0.1 ::1'.include? MYSQL_URI.host
|
489
497
|
context "A MySQL database" do
|
490
498
|
specify "should accept a socket option" do
|
491
|
-
db = Sequel.mysql(
|
499
|
+
db = Sequel.mysql(MYSQL_DB.opts[:database], :host => 'localhost', :user => MYSQL_DB.opts[:user], :password => MYSQL_DB.opts[:password], :socket => MYSQL_SOCKET_FILE)
|
492
500
|
proc {db.test_connection}.should_not raise_error
|
493
501
|
end
|
494
502
|
|
495
503
|
specify "should accept a socket option without host option" do
|
496
|
-
db = Sequel.mysql(
|
504
|
+
db = Sequel.mysql(MYSQL_DB.opts[:database], :user => MYSQL_DB.opts[:user], :password => MYSQL_DB.opts[:password], :socket => MYSQL_SOCKET_FILE)
|
497
505
|
proc {db.test_connection}.should_not raise_error
|
498
506
|
end
|
499
507
|
|
500
508
|
specify "should fail to connect with invalid socket" do
|
501
|
-
db = Sequel.mysql(
|
509
|
+
db = Sequel.mysql(MYSQL_DB.opts[:database], :user => MYSQL_DB.opts[:user], :password => MYSQL_DB.opts[:password], :socket =>'blah')
|
502
510
|
proc {db.test_connection}.should raise_error
|
503
511
|
end
|
504
512
|
end
|
@@ -761,3 +769,28 @@ context "MySQL::Dataset#complex_expression_sql" do
|
|
761
769
|
@d.literal([:x].sql_string_join(' ')).should == "x"
|
762
770
|
end
|
763
771
|
end
|
772
|
+
|
773
|
+
context "MySQL Stored Procedures" do
|
774
|
+
teardown do
|
775
|
+
MYSQL_DB.execute('DROP PROCEDURE test_sproc')
|
776
|
+
end
|
777
|
+
|
778
|
+
specify "should be callable on the database object" do
|
779
|
+
MYSQL_DB.execute('CREATE PROCEDURE test_sproc() BEGIN DELETE FROM items; END')
|
780
|
+
MYSQL_DB[:items].delete
|
781
|
+
MYSQL_DB[:items].insert(:value=>1)
|
782
|
+
MYSQL_DB[:items].count.should == 1
|
783
|
+
MYSQL_DB.call_sproc(:test_sproc)
|
784
|
+
MYSQL_DB[:items].count.should == 0
|
785
|
+
end
|
786
|
+
|
787
|
+
specify "should be callable on the dataset object" do
|
788
|
+
MYSQL_DB.execute('CREATE PROCEDURE test_sproc(a INTEGER) BEGIN SELECT *, a AS b FROM items; END')
|
789
|
+
@d = MYSQL_DB[:items]
|
790
|
+
@d.call_sproc(:select, :test_sproc, 3).should == []
|
791
|
+
@d.insert(:value=>1)
|
792
|
+
@d.call_sproc(:select, :test_sproc, 4).should == [{:id=>nil, :value=>1, :b=>4}]
|
793
|
+
@d.row_proc = proc{|r| r.keys.each{|k| r[k] *= 2 if r[k].is_a?(Integer)}; r}
|
794
|
+
@d.call_sproc(:select, :test_sproc, 3).should == [{:id=>nil, :value=>2, :b=>6}]
|
795
|
+
end
|
796
|
+
end
|
@@ -71,7 +71,7 @@ context "An Oracle dataset" do
|
|
71
71
|
{:name => 'def'}
|
72
72
|
]
|
73
73
|
|
74
|
-
@d.order(:value.
|
74
|
+
@d.order(:value.desc).limit(1).to_a.should == [
|
75
75
|
{:name => 'def', :value => 789}
|
76
76
|
]
|
77
77
|
|
@@ -80,7 +80,7 @@ context "An Oracle dataset" do
|
|
80
80
|
{:name => 'abc', :value => 456}
|
81
81
|
]
|
82
82
|
|
83
|
-
@d.order(:value.
|
83
|
+
@d.order(:value.desc).filter(:name => 'abc').to_a.should == [
|
84
84
|
{:name => 'abc', :value => 456},
|
85
85
|
{:name => 'abc', :value => 123}
|
86
86
|
]
|
@@ -89,7 +89,7 @@ context "An Oracle dataset" do
|
|
89
89
|
{:name => 'abc', :value => 123}
|
90
90
|
]
|
91
91
|
|
92
|
-
@d.filter(:name => 'abc').order(:value.
|
92
|
+
@d.filter(:name => 'abc').order(:value.desc).limit(1).to_a.should == [
|
93
93
|
{:name => 'abc', :value => 456}
|
94
94
|
]
|
95
95
|
|
@@ -214,9 +214,31 @@ context "Joined Oracle dataset" do
|
|
214
214
|
{:id => 4, :title => 'ddd', :cat_name => nil}
|
215
215
|
]
|
216
216
|
|
217
|
-
@d1.left_outer_join(:categories, :id => :category_id).select(:books__id, :title, :cat_name).order(:books__id.
|
217
|
+
@d1.left_outer_join(:categories, :id => :category_id).select(:books__id, :title, :cat_name).order(:books__id.desc).limit(2, 0).to_a.should == [
|
218
218
|
{:id => 4, :title => 'ddd', :cat_name => nil},
|
219
219
|
{:id => 3, :title => 'ccc', :cat_name => 'rails'}
|
220
220
|
]
|
221
221
|
end
|
222
222
|
end
|
223
|
+
|
224
|
+
context "Oracle aliasing" do
|
225
|
+
setup do
|
226
|
+
@d1 = ORACLE_DB[:books]
|
227
|
+
@d1.delete # remove all records
|
228
|
+
@d1 << {:id => 1, :title => 'aaa', :category_id => 100}
|
229
|
+
@d1 << {:id => 2, :title => 'bbb', :category_id => 100}
|
230
|
+
@d1 << {:id => 3, :title => 'bbb', :category_id => 100}
|
231
|
+
end
|
232
|
+
|
233
|
+
specify "should allow columns to be renamed" do
|
234
|
+
@d1.select(:title.as(:name)).order_by(:id).to_a.should == [
|
235
|
+
{ :name => 'aaa' },
|
236
|
+
{ :name => 'bbb' },
|
237
|
+
{ :name => 'bbb' },
|
238
|
+
]
|
239
|
+
end
|
240
|
+
|
241
|
+
specify "nested queries should work" do
|
242
|
+
@d1.select(:title).group_by(:title).count.should == 2
|
243
|
+
end
|
244
|
+
end
|
@@ -415,6 +415,13 @@ context "A SQLite database" do
|
|
415
415
|
@db[:test2].first.should == {:name => 'mmm'}
|
416
416
|
end
|
417
417
|
|
418
|
+
specify "should support drop_column operations in a transaction" do
|
419
|
+
@db.transaction{@db.drop_column :test2, :value}
|
420
|
+
@db[:test2].columns.should == [:name]
|
421
|
+
@db[:test2] << {:name => 'mmm'}
|
422
|
+
@db[:test2].first.should == {:name => 'mmm'}
|
423
|
+
end
|
424
|
+
|
418
425
|
specify "should not support rename_column operations" do
|
419
426
|
proc {@db.rename_column :test2, :value, :zyx}.should raise_error(Sequel::Error)
|
420
427
|
end
|
@@ -24,6 +24,30 @@ describe "Prepared Statements and Bound Arguments" do
|
|
24
24
|
@ds.filter(:number=>@ds.ba(:$n)).call(:first, :n=>10).should == {:id=>1, :number=>10}
|
25
25
|
end
|
26
26
|
|
27
|
+
specify "should support placeholder literal strings" do
|
28
|
+
@ds.filter("number = ?", @ds.ba(:$n)).call(:select, :n=>10).should == [{:id=>1, :number=>10}]
|
29
|
+
end
|
30
|
+
|
31
|
+
specify "should support datasets with static sql and placeholders" do
|
32
|
+
INTEGRATION_DB["SELECT * FROM items WHERE number = ?", @ds.ba(:$n)].call(:select, :n=>10).should == [{:id=>1, :number=>10}]
|
33
|
+
end
|
34
|
+
|
35
|
+
specify "should support subselects" do
|
36
|
+
@ds.filter(:id=>:$i).filter(:number=>@ds.select(:number).filter(:number=>@ds.ba(:$n))).filter(:id=>:$j).call(:select, :n=>10, :i=>1, :j=>1).should == [{:id=>1, :number=>10}]
|
37
|
+
end
|
38
|
+
|
39
|
+
specify "should support subselects with literal strings" do
|
40
|
+
@ds.filter(:id=>:$i, :number=>@ds.select(:number).filter("number = ?", @ds.ba(:$n))).call(:select, :n=>10, :i=>1).should == [{:id=>1, :number=>10}]
|
41
|
+
end
|
42
|
+
|
43
|
+
specify "should support subselects with static sql and placeholders" do
|
44
|
+
@ds.filter(:id=>:$i, :number=>INTEGRATION_DB["SELECT number FROM items WHERE number = ?", @ds.ba(:$n)]).call(:select, :n=>10, :i=>1).should == [{:id=>1, :number=>10}]
|
45
|
+
end
|
46
|
+
|
47
|
+
specify "should support subselects of subselects" do
|
48
|
+
@ds.filter(:id=>:$i).filter(:number=>@ds.select(:number).filter(:number=>@ds.select(:number).filter(:number=>@ds.ba(:$n)))).filter(:id=>:$j).call(:select, :n=>10, :i=>1, :j=>1).should == [{:id=>1, :number=>10}]
|
49
|
+
end
|
50
|
+
|
27
51
|
specify "should support bound variables with insert" do
|
28
52
|
@ds.call(:insert, {:n=>20, :i=>100}, :id=>@ds.ba(:$i), :number=>@ds.ba(:$n))
|
29
53
|
@ds.count.should == 2
|
@@ -9,7 +9,7 @@ describe "Database schema parser" do
|
|
9
9
|
INTEGRATION_DB.create_table!(:items){integer :number}
|
10
10
|
schema = INTEGRATION_DB.schema(nil, :reload=>true)
|
11
11
|
schema.should be_a_kind_of(Hash)
|
12
|
-
schema.
|
12
|
+
schema[:items].should_not == nil
|
13
13
|
end
|
14
14
|
|
15
15
|
specify "should not issue an sql query if the schema has been loaded unless :reload is true" do
|
@@ -23,7 +23,7 @@ end
|
|
23
23
|
context "A connection pool handling connections" do
|
24
24
|
setup do
|
25
25
|
@max_size = 2
|
26
|
-
@cpool = Sequel::ConnectionPool.new(CONNECTION_POOL_DEFAULTS.merge(:max_connections=>@max_size)) {:got_connection}
|
26
|
+
@cpool = Sequel::ConnectionPool.new(CONNECTION_POOL_DEFAULTS.merge(:disconnection_proc=>proc{|c| @max_size=3}, :max_connections=>@max_size)) {:got_connection}
|
27
27
|
end
|
28
28
|
|
29
29
|
specify "#hold should increment #created_count" do
|
@@ -61,6 +61,31 @@ context "A connection pool handling connections" do
|
|
61
61
|
@cpool.send(:make_new, :default).should == nil
|
62
62
|
@cpool.created_count.should == 2
|
63
63
|
end
|
64
|
+
|
65
|
+
specify ":disconnection_proc option should set the disconnection proc to use" do
|
66
|
+
@max_size.should == 2
|
67
|
+
proc{@cpool.hold{raise Sequel::DatabaseDisconnectError}}.should raise_error(Sequel::DatabaseDisconnectError)
|
68
|
+
@max_size.should == 3
|
69
|
+
end
|
70
|
+
|
71
|
+
specify "#disconnection_proc= should set the disconnection proc to use" do
|
72
|
+
a = 1
|
73
|
+
@cpool.disconnection_proc = proc{|c| a += 1}
|
74
|
+
proc{@cpool.hold{raise Sequel::DatabaseDisconnectError}}.should raise_error(Sequel::DatabaseDisconnectError)
|
75
|
+
a.should == 2
|
76
|
+
end
|
77
|
+
|
78
|
+
specify "#hold should remove the connection if a DatabaseDisconnectError is raised" do
|
79
|
+
@cpool.created_count.should == 0
|
80
|
+
@cpool.hold{Thread.new{@cpool.hold{}}; sleep 0.01}
|
81
|
+
@cpool.created_count.should == 2
|
82
|
+
proc{@cpool.hold{raise Sequel::DatabaseDisconnectError}}.should raise_error(Sequel::DatabaseDisconnectError)
|
83
|
+
@cpool.created_count.should == 1
|
84
|
+
proc{@cpool.hold{raise Sequel::DatabaseDisconnectError}}.should raise_error(Sequel::DatabaseDisconnectError)
|
85
|
+
@cpool.created_count.should == 0
|
86
|
+
proc{@cpool.hold{raise Sequel::DatabaseDisconnectError}}.should raise_error(Sequel::DatabaseDisconnectError)
|
87
|
+
@cpool.created_count.should == 0
|
88
|
+
end
|
64
89
|
end
|
65
90
|
|
66
91
|
class DummyConnection
|
@@ -423,7 +448,8 @@ end
|
|
423
448
|
|
424
449
|
context "A single threaded pool with multiple servers" do
|
425
450
|
setup do
|
426
|
-
@
|
451
|
+
@max_size=2
|
452
|
+
@pool = Sequel::SingleThreadedPool.new(CONNECTION_POOL_DEFAULTS.merge(:disconnection_proc=>proc{|c| @max_size=3}, :servers=>{:read_only=>{}})){|server| server}
|
427
453
|
end
|
428
454
|
|
429
455
|
specify "should use the :default server by default" do
|
@@ -462,4 +488,25 @@ context "A single threaded pool with multiple servers" do
|
|
462
488
|
@pool.conn.should == nil
|
463
489
|
@pool.conn(:read_only).should == nil
|
464
490
|
end
|
491
|
+
|
492
|
+
specify ":disconnection_proc option should set the disconnection proc to use" do
|
493
|
+
@max_size.should == 2
|
494
|
+
proc{@pool.hold{raise Sequel::DatabaseDisconnectError}}.should raise_error(Sequel::DatabaseDisconnectError)
|
495
|
+
@max_size.should == 3
|
496
|
+
end
|
497
|
+
|
498
|
+
specify "#disconnection_proc= should set the disconnection proc to use" do
|
499
|
+
a = 1
|
500
|
+
@pool.disconnection_proc = proc{|c| a += 1}
|
501
|
+
proc{@pool.hold{raise Sequel::DatabaseDisconnectError}}.should raise_error(Sequel::DatabaseDisconnectError)
|
502
|
+
a.should == 2
|
503
|
+
end
|
504
|
+
|
505
|
+
specify "#hold should remove the connection if a DatabaseDisconnectError is raised" do
|
506
|
+
@pool.instance_variable_get(:@conns).length.should == 0
|
507
|
+
@pool.hold{}
|
508
|
+
@pool.instance_variable_get(:@conns).length.should == 1
|
509
|
+
proc{@pool.hold{raise Sequel::DatabaseDisconnectError}}.should raise_error(Sequel::DatabaseDisconnectError)
|
510
|
+
@pool.instance_variable_get(:@conns).length.should == 0
|
511
|
+
end
|
465
512
|
end
|
@@ -259,12 +259,18 @@ context "Symbol#*" do
|
|
259
259
|
:xyz.*(3).to_s(@ds).should == '(xyz * 3)'
|
260
260
|
:abc.*(5).to_s(@ds).should == '(abc * 5)'
|
261
261
|
end
|
262
|
+
|
263
|
+
specify "should support qualified symbols if no argument" do
|
264
|
+
:xyz__abc.*.to_s(@ds).should == 'xyz.abc.*'
|
265
|
+
end
|
266
|
+
|
262
267
|
end
|
263
268
|
|
264
269
|
context "Symbol" do
|
265
270
|
before do
|
266
271
|
@ds = Sequel::Dataset.new(nil)
|
267
272
|
@ds.quote_identifiers = true
|
273
|
+
@ds.upcase_identifiers = true
|
268
274
|
end
|
269
275
|
|
270
276
|
specify "#identifier should format an identifier" do
|
@@ -276,11 +282,12 @@ context "Symbol" do
|
|
276
282
|
end
|
277
283
|
|
278
284
|
specify "should be able to qualify an identifier" do
|
279
|
-
@ds.literal(:xyz.identifier.qualify(:xyz__abc)).should == '"
|
285
|
+
@ds.literal(:xyz.identifier.qualify(:xyz__abc)).should == '"XYZ"."ABC"."XYZ"'
|
280
286
|
end
|
281
287
|
|
282
288
|
specify "should be able to specify a schema.table.column" do
|
283
|
-
@ds.literal(:column.qualify(:
|
289
|
+
@ds.literal(:column.qualify(:table.qualify(:schema))).should == '"SCHEMA"."TABLE"."COLUMN"'
|
290
|
+
@ds.literal(:column.qualify(:table__name.identifier.qualify(:schema))).should == '"SCHEMA"."TABLE__NAME"."COLUMN"'
|
284
291
|
end
|
285
292
|
end
|
286
293
|
|
@@ -6,6 +6,7 @@ context "A new Database" do
|
|
6
6
|
end
|
7
7
|
teardown do
|
8
8
|
Sequel.quote_identifiers = false
|
9
|
+
Sequel.upcase_identifiers = false
|
9
10
|
end
|
10
11
|
|
11
12
|
specify "should receive options" do
|
@@ -39,15 +40,41 @@ context "A new Database" do
|
|
39
40
|
cc.should == 1234
|
40
41
|
end
|
41
42
|
|
42
|
-
specify "should respect the :
|
43
|
-
db = Sequel::Database.new(:
|
44
|
-
db.quote_identifiers?.should == false
|
43
|
+
specify "should respect the :single_threaded option" do
|
44
|
+
db = Sequel::Database.new(:single_threaded=>true)
|
45
45
|
db.pool.should be_a_kind_of(Sequel::SingleThreadedPool)
|
46
|
-
db = Sequel::Database.new(:
|
47
|
-
db.quote_identifiers?.should == true
|
46
|
+
db = Sequel::Database.new(:single_threaded=>false)
|
48
47
|
db.pool.should be_a_kind_of(Sequel::ConnectionPool)
|
49
48
|
end
|
50
49
|
|
50
|
+
specify "should respect the :quote_identifiers option" do
|
51
|
+
db = Sequel::Database.new(:quote_identifiers=>false)
|
52
|
+
db.quote_identifiers?.should == false
|
53
|
+
db = Sequel::Database.new(:quote_identifiers=>true)
|
54
|
+
db.quote_identifiers?.should == true
|
55
|
+
end
|
56
|
+
|
57
|
+
specify "should respect the :upcase_identifiers option" do
|
58
|
+
Sequel.upcase_identifiers = false
|
59
|
+
db = Sequel::Database.new(:upcase_identifiers=>false)
|
60
|
+
db.upcase_identifiers?.should == false
|
61
|
+
db.upcase_identifiers = true
|
62
|
+
db.upcase_identifiers?.should == true
|
63
|
+
db = Sequel::Database.new(:upcase_identifiers=>true)
|
64
|
+
db.upcase_identifiers?.should == true
|
65
|
+
db.upcase_identifiers = false
|
66
|
+
db.upcase_identifiers?.should == false
|
67
|
+
Sequel.upcase_identifiers = true
|
68
|
+
db = Sequel::Database.new(:upcase_identifiers=>false)
|
69
|
+
db.upcase_identifiers?.should == false
|
70
|
+
db.upcase_identifiers = true
|
71
|
+
db.upcase_identifiers?.should == true
|
72
|
+
db = Sequel::Database.new(:upcase_identifiers=>true)
|
73
|
+
db.upcase_identifiers?.should == true
|
74
|
+
db.upcase_identifiers = false
|
75
|
+
db.upcase_identifiers?.should == false
|
76
|
+
end
|
77
|
+
|
51
78
|
specify "should use the default Sequel.quote_identifiers value" do
|
52
79
|
Sequel.quote_identifiers = true
|
53
80
|
Sequel::Database.new({}).quote_identifiers?.should == true
|
@@ -59,6 +86,26 @@ context "A new Database" do
|
|
59
86
|
Sequel::Database.new({}).quote_identifiers?.should == false
|
60
87
|
end
|
61
88
|
|
89
|
+
specify "should use the default Sequel.upcase_identifiers value" do
|
90
|
+
Sequel.upcase_identifiers = true
|
91
|
+
Sequel::Database.new({}).upcase_identifiers?.should == true
|
92
|
+
Sequel.upcase_identifiers = false
|
93
|
+
Sequel::Database.new({}).upcase_identifiers?.should == false
|
94
|
+
Sequel::Database.upcase_identifiers = true
|
95
|
+
Sequel::Database.new({}).upcase_identifiers?.should == true
|
96
|
+
Sequel::Database.upcase_identifiers = false
|
97
|
+
Sequel::Database.new({}).upcase_identifiers?.should == false
|
98
|
+
end
|
99
|
+
|
100
|
+
specify "should respect the upcase_indentifiers_default method if Sequel.upcase_identifiers = nil" do
|
101
|
+
Sequel.upcase_identifiers = nil
|
102
|
+
Sequel::Database.new({}).upcase_identifiers?.should == true
|
103
|
+
x = Class.new(Sequel::Database){def upcase_identifiers_default; false end}
|
104
|
+
x.new({}).upcase_identifiers?.should == false
|
105
|
+
y = Class.new(Sequel::Database){def upcase_identifiers_default; true end}
|
106
|
+
y.new({}).upcase_identifiers?.should == true
|
107
|
+
end
|
108
|
+
|
62
109
|
specify "should just use a :uri option for jdbc with the full connection string" do
|
63
110
|
Sequel::Database.should_receive(:adapter_class).once.with(:jdbc).and_return(Sequel::Database)
|
64
111
|
db = Sequel.connect('jdbc:test://host/db_name')
|
@@ -67,15 +114,20 @@ context "A new Database" do
|
|
67
114
|
end
|
68
115
|
end
|
69
116
|
|
70
|
-
context "Database#
|
71
|
-
specify "should
|
72
|
-
|
117
|
+
context "Database#disconnect" do
|
118
|
+
specify "should call pool.disconnect" do
|
119
|
+
d = Sequel::Database.new
|
120
|
+
p = d.pool
|
121
|
+
a = 1
|
122
|
+
p.meta_def(:disconnect){a += 1}
|
123
|
+
d.disconnect.should == 2
|
124
|
+
a.should == 2
|
73
125
|
end
|
74
126
|
end
|
75
127
|
|
76
|
-
context "Database#
|
128
|
+
context "Database#connect" do
|
77
129
|
specify "should raise Sequel::Error::NotImplemented" do
|
78
|
-
proc {Sequel::Database.new.
|
130
|
+
proc {Sequel::Database.new.connect}.should raise_error(NotImplementedError)
|
79
131
|
end
|
80
132
|
end
|
81
133
|
|
@@ -437,14 +489,12 @@ end
|
|
437
489
|
context "Database#table_exists?" do
|
438
490
|
setup do
|
439
491
|
@db = DummyDatabase.new
|
440
|
-
@db.
|
492
|
+
@db.instance_variable_set(:@schemas, {:a=>[]})
|
441
493
|
@db2 = DummyDatabase.new
|
442
494
|
end
|
443
495
|
|
444
|
-
specify "should use
|
496
|
+
specify "should use schema information if available" do
|
445
497
|
@db.table_exists?(:a).should be_true
|
446
|
-
@db.table_exists?(:b).should be_true
|
447
|
-
@db.table_exists?(:c).should be_false
|
448
498
|
end
|
449
499
|
|
450
500
|
specify "should otherwise try to select the first record from the table's dataset" do
|
@@ -191,6 +191,26 @@ context "A dataset with multiple tables in its FROM clause" do
|
|
191
191
|
end
|
192
192
|
end
|
193
193
|
|
194
|
+
context "Dataset#exists" do
|
195
|
+
setup do
|
196
|
+
@ds1 = Sequel::Dataset.new(nil).from(:test)
|
197
|
+
@ds2 = @ds1.filter(:price < 100)
|
198
|
+
@ds3 = @ds1.filter(:price > 50)
|
199
|
+
end
|
200
|
+
|
201
|
+
specify "should work in filters" do
|
202
|
+
@ds1.filter(@ds2.exists).sql.should ==
|
203
|
+
'SELECT * FROM test WHERE (EXISTS (SELECT * FROM test WHERE (price < 100)))'
|
204
|
+
@ds1.filter(@ds2.exists & @ds3.exists).sql.should ==
|
205
|
+
'SELECT * FROM test WHERE (EXISTS (SELECT * FROM test WHERE (price < 100)) AND EXISTS (SELECT * FROM test WHERE (price > 50)))'
|
206
|
+
end
|
207
|
+
|
208
|
+
specify "should work in select" do
|
209
|
+
@ds1.select(@ds2.exists.as(:a), @ds3.exists.as(:b)).sql.should ==
|
210
|
+
'SELECT EXISTS (SELECT * FROM test WHERE (price < 100)) AS a, EXISTS (SELECT * FROM test WHERE (price > 50)) AS b FROM test'
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
194
214
|
context "Dataset#where" do
|
195
215
|
setup do
|
196
216
|
@dataset = Sequel::Dataset.new(nil).from(:test)
|
@@ -1309,6 +1329,23 @@ context "Dataset#join_table" do
|
|
1309
1329
|
'SELECT * FROM "foo" AS "f" INNER JOIN "bar" ON ("bar"."id" = "f"."bar_id")'
|
1310
1330
|
end
|
1311
1331
|
|
1332
|
+
specify "should support implicit schemas in from table symbols" do
|
1333
|
+
@d.from(:s__t).join(:u__v, {:id => :player_id}).sql.should ==
|
1334
|
+
'SELECT * FROM "s"."t" INNER JOIN "u"."v" ON ("u"."v"."id" = "s"."t"."player_id")'
|
1335
|
+
end
|
1336
|
+
|
1337
|
+
specify "should support implicit aliases in from table symbols" do
|
1338
|
+
@d.from(:t___z).join(:v___y, {:id => :player_id}).sql.should ==
|
1339
|
+
'SELECT * FROM "t" AS "z" INNER JOIN "v" AS "y" ON ("y"."id" = "z"."player_id")'
|
1340
|
+
@d.from(:s__t___z).join(:u__v___y, {:id => :player_id}).sql.should ==
|
1341
|
+
'SELECT * FROM "s"."t" AS "z" INNER JOIN "u"."v" AS "y" ON ("y"."id" = "z"."player_id")'
|
1342
|
+
end
|
1343
|
+
|
1344
|
+
specify "should support AliasedExpressions" do
|
1345
|
+
@d.from(:s.as(:t)).join(:u.as(:v), {:id => :player_id}).sql.should ==
|
1346
|
+
'SELECT * FROM "s" AS "t" INNER JOIN "u" AS "v" ON ("v"."id" = "t"."player_id")'
|
1347
|
+
end
|
1348
|
+
|
1312
1349
|
specify "should support the :implicit_qualifier option" do
|
1313
1350
|
@d.from('stats').join('players', {:id => :player_id}, :implicit_qualifier=>:p).sql.should ==
|
1314
1351
|
'SELECT * FROM "stats" INNER JOIN "players" ON ("players"."id" = "p"."player_id")'
|
@@ -2874,14 +2911,12 @@ end
|
|
2874
2911
|
context "Dataset#table_exists?" do
|
2875
2912
|
setup do
|
2876
2913
|
@db = DummyMummyDatabase.new
|
2877
|
-
@db.
|
2914
|
+
@db.instance_variable_set(:@schemas, {:a=>[]})
|
2878
2915
|
@db2 = DummyMummyDatabase.new
|
2879
2916
|
end
|
2880
2917
|
|
2881
|
-
specify "should use
|
2918
|
+
specify "should use the database schema if available" do
|
2882
2919
|
@db[:a].table_exists?.should be_true
|
2883
|
-
@db[:b].table_exists?.should be_true
|
2884
|
-
@db[:c].table_exists?.should be_false
|
2885
2920
|
end
|
2886
2921
|
|
2887
2922
|
specify "should otherwise try to select the first record from the table's dataset" do
|
@@ -3053,10 +3088,14 @@ context "Dataset prepared statements and bound variables " do
|
|
3053
3088
|
def @db.execute(sql, opts={})
|
3054
3089
|
@sqls << sql
|
3055
3090
|
end
|
3056
|
-
|
3057
|
-
|
3058
|
-
|
3091
|
+
def @db.dataset
|
3092
|
+
ds = super()
|
3093
|
+
def ds.fetch_rows(sql, &block)
|
3094
|
+
execute(sql)
|
3095
|
+
end
|
3096
|
+
ds
|
3059
3097
|
end
|
3098
|
+
@ds = @db[:items]
|
3060
3099
|
end
|
3061
3100
|
|
3062
3101
|
specify "#call should take a type and bind hash and interpolate it" do
|
@@ -3097,6 +3136,36 @@ context "Dataset prepared statements and bound variables " do
|
|
3097
3136
|
@ds.filter(:num=>:$n).prepare(:select, :sn).inspect.should == \
|
3098
3137
|
'<Sequel::Dataset/PreparedStatement "SELECT * FROM items WHERE (num = $n)">'
|
3099
3138
|
end
|
3139
|
+
|
3140
|
+
specify "should handle literal strings" do
|
3141
|
+
@ds.filter("num = ?", :$n).call(:select, :n=>1)
|
3142
|
+
@db.sqls.should == ['SELECT * FROM items WHERE (num = 1)']
|
3143
|
+
end
|
3144
|
+
|
3145
|
+
specify "should handle datasets using static sql and placeholders" do
|
3146
|
+
@db["SELECT * FROM items WHERE (num = ?)", :$n].call(:select, :n=>1)
|
3147
|
+
@db.sqls.should == ['SELECT * FROM items WHERE (num = 1)']
|
3148
|
+
end
|
3149
|
+
|
3150
|
+
specify "should handle subselects" do
|
3151
|
+
@ds.filter(:$b).filter(:num=>@ds.select(:num).filter(:num=>:$n)).filter(:$c).call(:select, :n=>1, :b=>0, :c=>2)
|
3152
|
+
@db.sqls.should == ['SELECT * FROM items WHERE ((0 AND (num IN (SELECT num FROM items WHERE (num = 1)))) AND 2)']
|
3153
|
+
end
|
3154
|
+
|
3155
|
+
specify "should handle subselects in subselects" do
|
3156
|
+
@ds.filter(:$b).filter(:num=>@ds.select(:num).filter(:num=>@ds.select(:num).filter(:num=>:$n))).call(:select, :n=>1, :b=>0)
|
3157
|
+
@db.sqls.should == ['SELECT * FROM items WHERE (0 AND (num IN (SELECT num FROM items WHERE (num IN (SELECT num FROM items WHERE (num = 1))))))']
|
3158
|
+
end
|
3159
|
+
|
3160
|
+
specify "should handle subselects with literal strings" do
|
3161
|
+
@ds.filter(:$b).filter(:num=>@ds.select(:num).filter("num = ?", :$n)).call(:select, :n=>1, :b=>0)
|
3162
|
+
@db.sqls.should == ['SELECT * FROM items WHERE (0 AND (num IN (SELECT num FROM items WHERE (num = 1))))']
|
3163
|
+
end
|
3164
|
+
|
3165
|
+
specify "should handle subselects with static sql and placeholders" do
|
3166
|
+
@ds.filter(:$b).filter(:num=>@db["SELECT num FROM items WHERE (num = ?)", :$n]).call(:select, :n=>1, :b=>0)
|
3167
|
+
@db.sqls.should == ['SELECT * FROM items WHERE (0 AND (num IN (SELECT num FROM items WHERE (num = 1))))']
|
3168
|
+
end
|
3100
3169
|
end
|
3101
3170
|
|
3102
3171
|
context Sequel::Dataset::UnnumberedArgumentMapper do
|
@@ -3233,3 +3302,32 @@ context "Sequel::Dataset#each" do
|
|
3233
3302
|
end
|
3234
3303
|
end
|
3235
3304
|
end
|
3305
|
+
|
3306
|
+
context Sequel::Dataset::UnsupportedIntersectExcept do
|
3307
|
+
before do
|
3308
|
+
@ds = Sequel::Dataset.new(nil).from(:items)
|
3309
|
+
@ds2 = Sequel::Dataset.new(nil).from(:i)
|
3310
|
+
@ds.extend(Sequel::Dataset::UnsupportedIntersectExcept)
|
3311
|
+
end
|
3312
|
+
|
3313
|
+
specify "should raise an error if INTERSECT or EXCEPT is USED" do
|
3314
|
+
@ds.union(@ds2).sql.should == 'SELECT * FROM items UNION SELECT * FROM i'
|
3315
|
+
proc{@ds.intersect(@ds2)}.should raise_error(Sequel::Error)
|
3316
|
+
proc{@ds.except(@ds2)}.should raise_error(Sequel::Error)
|
3317
|
+
end
|
3318
|
+
end
|
3319
|
+
|
3320
|
+
context Sequel::Dataset::UnsupportedIntersectExceptAll do
|
3321
|
+
before do
|
3322
|
+
@ds = Sequel::Dataset.new(nil).from(:items)
|
3323
|
+
@ds2 = Sequel::Dataset.new(nil).from(:i)
|
3324
|
+
@ds.extend(Sequel::Dataset::UnsupportedIntersectExceptAll)
|
3325
|
+
end
|
3326
|
+
|
3327
|
+
specify "should raise an error if INTERSECT or EXCEPT is USED" do
|
3328
|
+
@ds.intersect(@ds2).sql.should == 'SELECT * FROM items INTERSECT SELECT * FROM i'
|
3329
|
+
@ds.except(@ds2).sql.should == 'SELECT * FROM items EXCEPT SELECT * FROM i'
|
3330
|
+
proc{@ds.intersect(@ds2, true)}.should raise_error(Sequel::Error)
|
3331
|
+
proc{@ds.except(@ds2, true)}.should raise_error(Sequel::Error)
|
3332
|
+
end
|
3333
|
+
end
|