sequel 3.45.0 → 3.46.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG +34 -0
- data/README.rdoc +6 -0
- data/Rakefile +46 -33
- data/doc/release_notes/3.46.0.txt +122 -0
- data/doc/schema_modification.rdoc +42 -6
- data/doc/security.rdoc +379 -0
- data/doc/transactions.rdoc +1 -1
- data/lib/sequel/adapters/jdbc/as400.rb +1 -0
- data/lib/sequel/adapters/jdbc/h2.rb +11 -0
- data/lib/sequel/adapters/mysql2.rb +3 -9
- data/lib/sequel/adapters/postgres.rb +34 -2
- data/lib/sequel/adapters/shared/cubrid.rb +5 -0
- data/lib/sequel/adapters/shared/mssql.rb +27 -3
- data/lib/sequel/adapters/shared/mysql.rb +25 -4
- data/lib/sequel/adapters/shared/sqlite.rb +12 -1
- data/lib/sequel/connection_pool.rb +3 -3
- data/lib/sequel/connection_pool/sharded_threaded.rb +7 -8
- data/lib/sequel/connection_pool/threaded.rb +7 -8
- data/lib/sequel/core.rb +5 -2
- data/lib/sequel/database.rb +1 -1
- data/lib/sequel/database/connecting.rb +7 -7
- data/lib/sequel/database/features.rb +88 -0
- data/lib/sequel/database/misc.rb +14 -64
- data/lib/sequel/database/query.rb +0 -332
- data/lib/sequel/database/schema_generator.rb +36 -3
- data/lib/sequel/database/schema_methods.rb +48 -12
- data/lib/sequel/database/transactions.rb +344 -0
- data/lib/sequel/dataset/actions.rb +24 -9
- data/lib/sequel/dataset/mutation.rb +20 -0
- data/lib/sequel/dataset/query.rb +0 -17
- data/lib/sequel/dataset/sql.rb +7 -0
- data/lib/sequel/exceptions.rb +10 -6
- data/lib/sequel/extensions/_pretty_table.rb +2 -2
- data/lib/sequel/extensions/looser_typecasting.rb +10 -0
- data/lib/sequel/extensions/migration.rb +5 -2
- data/lib/sequel/model.rb +1 -1
- data/lib/sequel/model/associations.rb +16 -14
- data/lib/sequel/model/base.rb +14 -2
- data/lib/sequel/plugins/composition.rb +3 -3
- data/lib/sequel/plugins/dirty.rb +6 -6
- data/lib/sequel/plugins/hook_class_methods.rb +3 -0
- data/lib/sequel/plugins/serialization.rb +7 -17
- data/lib/sequel/plugins/string_stripper.rb +2 -1
- data/lib/sequel/plugins/validation_helpers.rb +1 -1
- data/lib/sequel/sql.rb +3 -0
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/mssql_spec.rb +21 -0
- data/spec/adapters/postgres_spec.rb +35 -8
- data/spec/core/database_spec.rb +4 -0
- data/spec/core/dataset_spec.rb +48 -2
- data/spec/core/schema_generator_spec.rb +10 -1
- data/spec/core/schema_spec.rb +69 -0
- data/spec/extensions/composition_spec.rb +21 -2
- data/spec/extensions/dirty_spec.rb +17 -10
- data/spec/extensions/eager_each_spec.rb +4 -1
- data/spec/extensions/looser_typecasting_spec.rb +16 -19
- data/spec/extensions/migration_spec.rb +7 -1
- data/spec/extensions/serialization_spec.rb +22 -0
- data/spec/extensions/single_table_inheritance_spec.rb +3 -2
- data/spec/extensions/validation_helpers_spec.rb +6 -0
- data/spec/integration/dataset_test.rb +5 -0
- data/spec/integration/schema_test.rb +16 -0
- data/spec/model/associations_spec.rb +40 -0
- data/spec/model/base_spec.rb +21 -1
- data/spec/model/record_spec.rb +3 -0
- metadata +14 -10
@@ -161,7 +161,7 @@ module Sequel
|
|
161
161
|
# Check if value is an instance of a class
|
162
162
|
def validates_type(klass, atts, opts={})
|
163
163
|
klass = klass.to_s.constantize if klass.is_a?(String) || klass.is_a?(Symbol)
|
164
|
-
validatable_attributes_for_type(:type, atts, opts){|a,v,m| validation_error_message(m, klass) if v && !v.is_a?(klass)}
|
164
|
+
validatable_attributes_for_type(:type, atts, opts){|a,v,m| validation_error_message(m, klass) if !v.nil? && !v.is_a?(klass)}
|
165
165
|
end
|
166
166
|
|
167
167
|
# Check attribute value(s) is not considered blank by the database, but allow false values.
|
data/lib/sequel/sql.rb
CHANGED
@@ -89,6 +89,9 @@ module Sequel
|
|
89
89
|
# Create a to_s instance method that takes a dataset, and calls
|
90
90
|
# the method provided on the dataset with args as the argument (self by default).
|
91
91
|
# Used to DRY up some code.
|
92
|
+
#
|
93
|
+
# Do not call this method with untrusted input, as that can result in
|
94
|
+
# arbitrary code execution.
|
92
95
|
def to_s_method(meth, args=:self) # :nodoc:
|
93
96
|
class_eval("def to_s(ds) ds.#{meth}(#{args}) end", __FILE__, __LINE__)
|
94
97
|
class_eval("def to_s_append(ds, sql) ds.#{meth}_append(sql, #{args}) end", __FILE__, __LINE__)
|
data/lib/sequel/version.rb
CHANGED
@@ -3,7 +3,7 @@ module Sequel
|
|
3
3
|
MAJOR = 3
|
4
4
|
# The minor version of Sequel. Bumped for every non-patch level
|
5
5
|
# release, generally around once a month.
|
6
|
-
MINOR =
|
6
|
+
MINOR = 46
|
7
7
|
# The tiny version of Sequel. Usually 0, only bumped for bugfix
|
8
8
|
# releases that fix regressions from previous versions.
|
9
9
|
TINY = 0
|
data/spec/adapters/mssql_spec.rb
CHANGED
@@ -55,6 +55,27 @@ describe "A MSSQL database" do
|
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
58
|
+
describe "MSSQL" do
|
59
|
+
before(:all) do
|
60
|
+
@db = MSSQL_DB
|
61
|
+
@db.create_table!(:test3){Integer :v3}
|
62
|
+
@db.create_table!(:test4){Integer :v4}
|
63
|
+
@db[:test3].import([:v3], [[1], [2]])
|
64
|
+
@db[:test4].import([:v4], [[1], [3]])
|
65
|
+
end
|
66
|
+
after(:all) do
|
67
|
+
@db.drop_table?(:test3, :test4)
|
68
|
+
end
|
69
|
+
|
70
|
+
specify "should should support CROSS APPLY" do
|
71
|
+
@db[:test3].cross_apply(@db[:test4].where(:test3__v3=>:test4__v4)).select_order_map([:v3, :v4]).should == [[1,1]]
|
72
|
+
end
|
73
|
+
|
74
|
+
specify "should should support OUTER APPLY" do
|
75
|
+
@db[:test3].outer_apply(@db[:test4].where(:test3__v3=>:test4__v4)).select_order_map([:v3, :v4]).should == [[1,1], [2, nil]]
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
58
79
|
# This spec is currently disabled as the SQL Server 2008 R2 Express doesn't support
|
59
80
|
# full text searching. Even if full text searching is supported,
|
60
81
|
# you may need to create a full text catalog on the database first via:
|
@@ -440,8 +440,8 @@ describe "A PostgreSQL dataset with a timestamp field" do
|
|
440
440
|
before(:all) do
|
441
441
|
@db = POSTGRES_DB
|
442
442
|
@db.create_table! :test3 do
|
443
|
-
|
444
|
-
|
443
|
+
Date :date
|
444
|
+
DateTime :time
|
445
445
|
end
|
446
446
|
@d = @db[:test3]
|
447
447
|
end
|
@@ -457,8 +457,8 @@ describe "A PostgreSQL dataset with a timestamp field" do
|
|
457
457
|
|
458
458
|
cspecify "should store milliseconds in time fields for Time objects", :do, :swift do
|
459
459
|
t = Time.now
|
460
|
-
@d << {:
|
461
|
-
t2 = @d
|
460
|
+
@d << {:time=>t}
|
461
|
+
t2 = @d.get(:time)
|
462
462
|
@d.literal(t2).should == @d.literal(t)
|
463
463
|
t2.strftime('%Y-%m-%d %H:%M:%S').should == t.strftime('%Y-%m-%d %H:%M:%S')
|
464
464
|
(t2.is_a?(Time) ? t2.usec : t2.strftime('%N').to_i/1000).should == t.usec
|
@@ -466,8 +466,8 @@ describe "A PostgreSQL dataset with a timestamp field" do
|
|
466
466
|
|
467
467
|
cspecify "should store milliseconds in time fields for DateTime objects", :do, :swift do
|
468
468
|
t = DateTime.now
|
469
|
-
@d << {:
|
470
|
-
t2 = @d
|
469
|
+
@d << {:time=>t}
|
470
|
+
t2 = @d.get(:time)
|
471
471
|
@d.literal(t2).should == @d.literal(t)
|
472
472
|
t2.strftime('%Y-%m-%d %H:%M:%S').should == t.strftime('%Y-%m-%d %H:%M:%S')
|
473
473
|
(t2.is_a?(Time) ? t2.usec : t2.strftime('%N').to_i/1000).should == t.strftime('%N').to_i/1000
|
@@ -475,7 +475,7 @@ describe "A PostgreSQL dataset with a timestamp field" do
|
|
475
475
|
|
476
476
|
if POSTGRES_DB.adapter_scheme == :postgres
|
477
477
|
specify "should handle infinite timestamps if convert_infinite_timestamps is set" do
|
478
|
-
@d << {:time=>Sequel.cast('infinity',
|
478
|
+
@d << {:time=>Sequel.cast('infinity', DateTime)}
|
479
479
|
@db.convert_infinite_timestamps = :nil
|
480
480
|
@db[:test3].get(:time).should == nil
|
481
481
|
@db.convert_infinite_timestamps = :string
|
@@ -483,7 +483,7 @@ describe "A PostgreSQL dataset with a timestamp field" do
|
|
483
483
|
@db.convert_infinite_timestamps = :float
|
484
484
|
@db[:test3].get(:time).should == 1.0/0.0
|
485
485
|
|
486
|
-
@d.update(:time=>Sequel.cast('-infinity',
|
486
|
+
@d.update(:time=>Sequel.cast('-infinity', DateTime))
|
487
487
|
@db.convert_infinite_timestamps = :nil
|
488
488
|
@db[:test3].get(:time).should == nil
|
489
489
|
@db.convert_infinite_timestamps = :string
|
@@ -500,6 +500,33 @@ describe "A PostgreSQL dataset with a timestamp field" do
|
|
500
500
|
c.new(:time=>1.0/0.0).time.should == 1.0/0.0
|
501
501
|
c.new(:time=>-1.0/0.0).time.should == -1.0/0.0
|
502
502
|
end
|
503
|
+
|
504
|
+
specify "should handle infinite dates if convert_infinite_timestamps is set" do
|
505
|
+
@d << {:date=>Sequel.cast('infinity', Date)}
|
506
|
+
@db.convert_infinite_timestamps = :nil
|
507
|
+
@db[:test3].get(:date).should == nil
|
508
|
+
@db.convert_infinite_timestamps = :string
|
509
|
+
@db[:test3].get(:date).should == 'infinity'
|
510
|
+
@db.convert_infinite_timestamps = :float
|
511
|
+
@db[:test3].get(:date).should == 1.0/0.0
|
512
|
+
|
513
|
+
@d.update(:date=>Sequel.cast('-infinity', :timestamp))
|
514
|
+
@db.convert_infinite_timestamps = :nil
|
515
|
+
@db[:test3].get(:date).should == nil
|
516
|
+
@db.convert_infinite_timestamps = :string
|
517
|
+
@db[:test3].get(:date).should == '-infinity'
|
518
|
+
@db.convert_infinite_timestamps = :float
|
519
|
+
@db[:test3].get(:date).should == -1.0/0.0
|
520
|
+
end
|
521
|
+
|
522
|
+
specify "should handle conversions from infinite strings/floats in models" do
|
523
|
+
c = Class.new(Sequel::Model(:test3))
|
524
|
+
@db.convert_infinite_timestamps = :float
|
525
|
+
c.new(:date=>'infinity').date.should == 'infinity'
|
526
|
+
c.new(:date=>'-infinity').date.should == '-infinity'
|
527
|
+
c.new(:date=>1.0/0.0).date.should == 1.0/0.0
|
528
|
+
c.new(:date=>-1.0/0.0).date.should == -1.0/0.0
|
529
|
+
end
|
503
530
|
end
|
504
531
|
|
505
532
|
specify "explain and analyze should not raise errors" do
|
data/spec/core/database_spec.rb
CHANGED
@@ -1663,6 +1663,10 @@ describe "Database#each_server with do/jdbc adapter connection string without :a
|
|
1663
1663
|
end
|
1664
1664
|
hosts.sort.should == [1, 3]
|
1665
1665
|
end
|
1666
|
+
|
1667
|
+
specify "should raise if not given a block" do
|
1668
|
+
proc{Sequel.mock.each_server}.should raise_error(Sequel::Error)
|
1669
|
+
end
|
1666
1670
|
end
|
1667
1671
|
|
1668
1672
|
describe "Database#each_server" do
|
data/spec/core/dataset_spec.rb
CHANGED
@@ -2465,8 +2465,7 @@ end
|
|
2465
2465
|
|
2466
2466
|
describe "Dataset #first and #last" do
|
2467
2467
|
before do
|
2468
|
-
@
|
2469
|
-
@d = @db[:test]
|
2468
|
+
@d = Sequel.mock(:fetch=>proc{|s| {:s=>s}})[:test]
|
2470
2469
|
end
|
2471
2470
|
|
2472
2471
|
specify "should return a single record if no argument is given" do
|
@@ -2504,6 +2503,10 @@ describe "Dataset #first and #last" do
|
|
2504
2503
|
i = rand(10) + 10
|
2505
2504
|
r = @d.order(:a).last(i){z > 26}.should == [{:s=>"SELECT * FROM test WHERE (z > 26) ORDER BY a DESC LIMIT #{i}"}]
|
2506
2505
|
end
|
2506
|
+
|
2507
|
+
specify "should return nil if no records match" do
|
2508
|
+
Sequel.mock[:t].first.should == nil
|
2509
|
+
end
|
2507
2510
|
|
2508
2511
|
specify "#last should raise if no order is given" do
|
2509
2512
|
proc {@d.last}.should raise_error(Sequel::Error)
|
@@ -2520,6 +2523,44 @@ describe "Dataset #first and #last" do
|
|
2520
2523
|
end
|
2521
2524
|
end
|
2522
2525
|
|
2526
|
+
describe "Dataset #first!" do
|
2527
|
+
before do
|
2528
|
+
@db = Sequel.mock(:fetch=>proc{|s| {:s=>s}})
|
2529
|
+
@d = @db[:test]
|
2530
|
+
end
|
2531
|
+
|
2532
|
+
specify "should return a single record if no argument is given" do
|
2533
|
+
@d.order(:a).first!.should == {:s=>'SELECT * FROM test ORDER BY a LIMIT 1'}
|
2534
|
+
end
|
2535
|
+
|
2536
|
+
specify "should return the first! matching record if argument is not an Integer" do
|
2537
|
+
@d.order(:a).first!(:z => 26).should == {:s=>'SELECT * FROM test WHERE (z = 26) ORDER BY a LIMIT 1'}
|
2538
|
+
@d.order(:a).first!('z = ?', 15).should == {:s=>'SELECT * FROM test WHERE (z = 15) ORDER BY a LIMIT 1'}
|
2539
|
+
end
|
2540
|
+
|
2541
|
+
specify "should set the limit and return an array of records if the given number is > 1" do
|
2542
|
+
i = rand(10) + 10
|
2543
|
+
r = @d.order(:a).first!(i).should == [{:s=>"SELECT * FROM test ORDER BY a LIMIT #{i}"}]
|
2544
|
+
end
|
2545
|
+
|
2546
|
+
specify "should return the first! matching record if a block is given without an argument" do
|
2547
|
+
@d.first!{z > 26}.should == {:s=>'SELECT * FROM test WHERE (z > 26) LIMIT 1'}
|
2548
|
+
end
|
2549
|
+
|
2550
|
+
specify "should combine block and standard argument filters if argument is not an Integer" do
|
2551
|
+
@d.first!(:y=>25){z > 26}.should == {:s=>'SELECT * FROM test WHERE ((z > 26) AND (y = 25)) LIMIT 1'}
|
2552
|
+
end
|
2553
|
+
|
2554
|
+
specify "should filter and return an array of records if an Integer argument is provided and a block is given" do
|
2555
|
+
i = rand(10) + 10
|
2556
|
+
r = @d.order(:a).first!(i){z > 26}.should == [{:s=>"SELECT * FROM test WHERE (z > 26) ORDER BY a LIMIT #{i}"}]
|
2557
|
+
end
|
2558
|
+
|
2559
|
+
specify "should raise NoMatchingRow exception if no rows match" do
|
2560
|
+
proc{Sequel.mock[:t].first!}.should raise_error(Sequel::NoMatchingRow)
|
2561
|
+
end
|
2562
|
+
end
|
2563
|
+
|
2523
2564
|
describe "Dataset compound operations" do
|
2524
2565
|
before do
|
2525
2566
|
@a = Sequel::Dataset.new(nil).from(:a).filter(:z => 1)
|
@@ -4038,6 +4079,11 @@ describe "Sequel::Dataset#select_map" do
|
|
4038
4079
|
@ds.db.sqls.should == ['SELECT c, c FROM t']
|
4039
4080
|
end
|
4040
4081
|
|
4082
|
+
specify "should raise an error for plain strings" do
|
4083
|
+
proc{@ds.select_map(['c', :c])}.should raise_error(Sequel::Error)
|
4084
|
+
@ds.db.sqls.should == []
|
4085
|
+
end
|
4086
|
+
|
4041
4087
|
specify "should accept a block" do
|
4042
4088
|
@ds.select_map{a(t__c)}.should == [1, 2]
|
4043
4089
|
@ds.db.sqls.should == ['SELECT a(t.c) FROM t']
|
@@ -121,6 +121,10 @@ describe Sequel::Schema::AlterTableGenerator do
|
|
121
121
|
add_foreign_key :node_id, :nodes
|
122
122
|
add_primary_key [:aaa, :bbb]
|
123
123
|
add_foreign_key [:node_id, :prop_id], :nodes_props
|
124
|
+
add_foreign_key [:node_id, :prop_id], :nodes_props, :name => :fkey
|
125
|
+
drop_foreign_key :node_id
|
126
|
+
drop_foreign_key [:node_id, :prop_id]
|
127
|
+
drop_foreign_key [:node_id, :prop_id], :name => :fkey
|
124
128
|
end
|
125
129
|
end
|
126
130
|
|
@@ -144,7 +148,12 @@ describe Sequel::Schema::AlterTableGenerator do
|
|
144
148
|
{:op => :add_column, :name => :id, :type => Integer, :primary_key=>true, :auto_increment=>true},
|
145
149
|
{:op => :add_column, :name => :node_id, :type => Integer, :table=>:nodes},
|
146
150
|
{:op => :add_constraint, :type => :primary_key, :columns => [:aaa, :bbb]},
|
147
|
-
{:op => :add_constraint, :type => :foreign_key, :columns => [:node_id, :prop_id], :table => :nodes_props}
|
151
|
+
{:op => :add_constraint, :type => :foreign_key, :columns => [:node_id, :prop_id], :table => :nodes_props},
|
152
|
+
{:op => :add_constraint, :type => :foreign_key, :columns => [:node_id, :prop_id], :table => :nodes_props, :name => :fkey},
|
153
|
+
{:op => :drop_constraint, :type => :foreign_key, :columns => [:node_id]},
|
154
|
+
{:op => :drop_column, :name => :node_id},
|
155
|
+
{:op => :drop_constraint, :type => :foreign_key, :columns => [:node_id, :prop_id]},
|
156
|
+
{:op => :drop_constraint, :type => :foreign_key, :columns => [:node_id, :prop_id], :name => :fkey},
|
148
157
|
]
|
149
158
|
end
|
150
159
|
end
|
data/spec/core/schema_spec.rb
CHANGED
@@ -113,6 +113,22 @@ describe "DB#create_table" do
|
|
113
113
|
@db.sqls.should == ['CREATE TABLE cats (id serial PRIMARY KEY)']
|
114
114
|
end
|
115
115
|
|
116
|
+
specify "should allow naming primary key constraint with :primary_key_constraint_name option" do
|
117
|
+
@db.create_table(:cats) do
|
118
|
+
primary_key :id, :primary_key_constraint_name=>:foo
|
119
|
+
end
|
120
|
+
@db.sqls.should == ['CREATE TABLE cats (id integer CONSTRAINT foo PRIMARY KEY AUTOINCREMENT)']
|
121
|
+
end
|
122
|
+
|
123
|
+
specify "should handling splitting named column constraints into table constraints if unsupported" do
|
124
|
+
def @db.supports_named_column_constraints?; false end
|
125
|
+
@db.create_table(:cats) do
|
126
|
+
primary_key :id, :primary_key_constraint_name=>:foo
|
127
|
+
foreign_key :cat_id, :cats, :unique=>true, :unique_constraint_name=>:bar, :foreign_key_constraint_name=>:baz, :deferrable=>true, :key=>:foo_id, :on_delete=>:cascade, :on_update=>:restrict
|
128
|
+
end
|
129
|
+
@db.sqls.should == ['CREATE TABLE cats (id integer AUTOINCREMENT, cat_id integer, CONSTRAINT foo PRIMARY KEY (id), CONSTRAINT baz FOREIGN KEY (cat_id) REFERENCES cats(foo_id) ON DELETE CASCADE ON UPDATE RESTRICT DEFERRABLE INITIALLY DEFERRED, CONSTRAINT bar UNIQUE (cat_id))']
|
130
|
+
end
|
131
|
+
|
116
132
|
specify "should accept and literalize default values" do
|
117
133
|
@db.create_table(:cats) do
|
118
134
|
integer :id, :default => 123
|
@@ -147,6 +163,13 @@ describe "DB#create_table" do
|
|
147
163
|
@db.sqls.should == ["CREATE TABLE cats (id integer, name text UNIQUE)"]
|
148
164
|
end
|
149
165
|
|
166
|
+
specify "should allow naming unique constraint with :unique_constraint_name option" do
|
167
|
+
@db.create_table(:cats) do
|
168
|
+
text :name, :unique => true, :unique_constraint_name=>:foo
|
169
|
+
end
|
170
|
+
@db.sqls.should == ["CREATE TABLE cats (name text CONSTRAINT foo UNIQUE)"]
|
171
|
+
end
|
172
|
+
|
150
173
|
specify "should handle not deferred unique constraints" do
|
151
174
|
@db.create_table(:cats) do
|
152
175
|
integer :id
|
@@ -227,6 +250,13 @@ describe "DB#create_table" do
|
|
227
250
|
@db.sqls.should == ["CREATE TABLE cats (project_id integer DEFAULT 3 REFERENCES projects)"]
|
228
251
|
end
|
229
252
|
|
253
|
+
specify "should allowing naming foreign key constraint with :foreign_key_constraint_name option" do
|
254
|
+
@db.create_table(:cats) do
|
255
|
+
foreign_key :project_id, :projects, :foreign_key_constraint_name=>:foo
|
256
|
+
end
|
257
|
+
@db.sqls.should == ["CREATE TABLE cats (project_id integer CONSTRAINT foo REFERENCES projects)"]
|
258
|
+
end
|
259
|
+
|
230
260
|
specify "should raise an error if the table argument to foreign_key isn't a hash, symbol, or nil" do
|
231
261
|
proc{@db.create_table(:cats){foreign_key :project_id, Object.new, :default=>3}}.should raise_error(Sequel::Error)
|
232
262
|
end
|
@@ -949,6 +979,45 @@ describe "DB#alter_table" do
|
|
949
979
|
@db.sqls.should == ["ALTER TABLE cats DROP CONSTRAINT valid_score CASCADE"]
|
950
980
|
end
|
951
981
|
|
982
|
+
specify "should support drop_foreign_key" do
|
983
|
+
def @db.foreign_key_list(table_name)
|
984
|
+
[{:name=>:cats_node_id_fkey, :columns=>[:node_id]}]
|
985
|
+
end
|
986
|
+
@db.alter_table(:cats) do
|
987
|
+
drop_foreign_key :node_id
|
988
|
+
end
|
989
|
+
@db.sqls.should == ["ALTER TABLE cats DROP CONSTRAINT cats_node_id_fkey", "ALTER TABLE cats DROP COLUMN node_id"]
|
990
|
+
end
|
991
|
+
|
992
|
+
specify "should support drop_foreign_key with composite foreign keys" do
|
993
|
+
def @db.foreign_key_list(table_name)
|
994
|
+
[{:name=>:cats_node_id_prop_id_fkey, :columns=>[:node_id, :prop_id]}]
|
995
|
+
end
|
996
|
+
@db.alter_table(:cats) do
|
997
|
+
drop_foreign_key [:node_id, :prop_id]
|
998
|
+
end
|
999
|
+
@db.sqls.should == ["ALTER TABLE cats DROP CONSTRAINT cats_node_id_prop_id_fkey"]
|
1000
|
+
|
1001
|
+
@db.alter_table(:cats) do
|
1002
|
+
drop_foreign_key [:node_id, :prop_id], :name => :cfk
|
1003
|
+
end
|
1004
|
+
@db.sqls.should == ["ALTER TABLE cats DROP CONSTRAINT cfk"]
|
1005
|
+
end
|
1006
|
+
|
1007
|
+
specify "should have drop_foreign_key raise Error if no name is found" do
|
1008
|
+
def @db.foreign_key_list(table_name)
|
1009
|
+
[{:name=>:cats_node_id_fkey, :columns=>[:foo_id]}]
|
1010
|
+
end
|
1011
|
+
lambda{@db.alter_table(:cats){drop_foreign_key :node_id}}.should raise_error(Sequel::Error)
|
1012
|
+
end
|
1013
|
+
|
1014
|
+
specify "should have drop_foreign_key raise Error if multiple foreign keys found" do
|
1015
|
+
def @db.foreign_key_list(table_name)
|
1016
|
+
[{:name=>:cats_node_id_fkey, :columns=>[:node_id]}, {:name=>:cats_node_id_fkey2, :columns=>[:node_id]}]
|
1017
|
+
end
|
1018
|
+
lambda{@db.alter_table(:cats){drop_foreign_key :node_id}}.should raise_error(Sequel::Error)
|
1019
|
+
end
|
1020
|
+
|
952
1021
|
specify "should support drop_index" do
|
953
1022
|
@db.alter_table(:cats) do
|
954
1023
|
drop_index :name
|
@@ -90,13 +90,32 @@ describe "Composition plugin" do
|
|
90
90
|
called.should == true
|
91
91
|
end
|
92
92
|
|
93
|
-
it "should clear compositions cache when
|
93
|
+
it "should clear compositions cache when using set_values" do
|
94
94
|
@c.composition :date, :composer=>proc{}, :decomposer=>proc{called = true}
|
95
95
|
@o.date = Date.new(3, 4, 5)
|
96
|
-
@o.
|
96
|
+
@o.set_values(:id=>1)
|
97
97
|
@o.compositions.should == {}
|
98
98
|
end
|
99
99
|
|
100
|
+
it "should clear compositions cache when refreshing" do
|
101
|
+
@c.composition :date, :composer=>proc{}, :decomposer=>proc{called = true}
|
102
|
+
@o.date = Date.new(3, 4, 5)
|
103
|
+
@o.refresh
|
104
|
+
@o.compositions.should == {}
|
105
|
+
end
|
106
|
+
|
107
|
+
it "should clear compositions cache when refreshing after save" do
|
108
|
+
@c.composition :date, :composer=>proc{}, :decomposer=>proc{called = true}
|
109
|
+
@c.create(:date=>Date.new(3, 4, 5)).compositions.should == {}
|
110
|
+
end
|
111
|
+
|
112
|
+
it "should clear compositions cache when saving with insert_select" do
|
113
|
+
def (@c.instance_dataset).supports_insert_select?() true end
|
114
|
+
def (@c.instance_dataset).insert_select(*) {:id=>1} end
|
115
|
+
@c.composition :date, :composer=>proc{}, :decomposer=>proc{called = true}
|
116
|
+
@c.create(:date=>Date.new(3, 4, 5)).compositions.should == {}
|
117
|
+
end
|
118
|
+
|
100
119
|
it "should instantiate compositions lazily" do
|
101
120
|
@c.composition :date, :mapping=>[:year, :month, :day]
|
102
121
|
@o.compositions.should == {}
|
@@ -88,6 +88,11 @@ describe "Sequel::Plugins::Dirty" do
|
|
88
88
|
@o.values.has_key?(:missing_changed).should == false
|
89
89
|
end
|
90
90
|
|
91
|
+
it "set_values should clear the cached initial values" do
|
92
|
+
@o.set_values(:id=>1)
|
93
|
+
@o.column_changes.should == {}
|
94
|
+
end
|
95
|
+
|
91
96
|
it "refresh should clear the cached initial values" do
|
92
97
|
@o.refresh
|
93
98
|
@o.column_changes.should == {}
|
@@ -116,16 +121,6 @@ describe "Sequel::Plugins::Dirty" do
|
|
116
121
|
o.column_change(:initial).should == [v, 'a']
|
117
122
|
end
|
118
123
|
end
|
119
|
-
|
120
|
-
it "save should clear the cached initial values" do
|
121
|
-
@o.save
|
122
|
-
@o.column_changes.should == {}
|
123
|
-
end
|
124
|
-
|
125
|
-
it "save_changes should clear the cached initial values" do
|
126
|
-
@o.save_changes
|
127
|
-
@o.column_changes.should == {}
|
128
|
-
end
|
129
124
|
end
|
130
125
|
|
131
126
|
describe "with new instance" do
|
@@ -136,6 +131,18 @@ describe "Sequel::Plugins::Dirty" do
|
|
136
131
|
end
|
137
132
|
|
138
133
|
it_should_behave_like "dirty plugin"
|
134
|
+
|
135
|
+
it "save should clear the cached initial values" do
|
136
|
+
@o.save
|
137
|
+
@o.column_changes.should == {}
|
138
|
+
end
|
139
|
+
|
140
|
+
it "save_changes should clear the cached initial values" do
|
141
|
+
def (@c.instance_dataset).supports_insert_select?() true end
|
142
|
+
def (@c.instance_dataset).insert_select(*) {:id=>1} end
|
143
|
+
@o.save
|
144
|
+
@o.column_changes.should == {}
|
145
|
+
end
|
139
146
|
end
|
140
147
|
|
141
148
|
describe "with existing instance" do
|
@@ -17,7 +17,10 @@ describe "Sequel::Plugins::EagerEach" do
|
|
17
17
|
ds.each{|c| a << c}
|
18
18
|
a.should == [@c.load(:id=>1, :parent_id=>nil), @c.load(:id=>2, :parent_id=>nil)]
|
19
19
|
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)]]
|
20
|
-
@c.db.sqls
|
20
|
+
sqls = @c.db.sqls
|
21
|
+
sqls.shift.should == 'SELECT * FROM items'
|
22
|
+
['SELECT * FROM items WHERE (items.parent_id IN (1, 2))',
|
23
|
+
'SELECT * FROM items WHERE (items.parent_id IN (2, 1))'].should include(sqls.pop)
|
21
24
|
end
|
22
25
|
|
23
26
|
it "should make #each on an eager_graph dataset do eager loading" do
|
@@ -4,36 +4,33 @@ describe "LooserTypecasting Extension" do
|
|
4
4
|
before do
|
5
5
|
@db = Sequel::Database.new({})
|
6
6
|
def @db.schema(*args)
|
7
|
-
[[:id, {}], [:z, {:type=>:float}], [:b, {:type=>:integer}]]
|
7
|
+
[[:id, {}], [:z, {:type=>:float}], [:b, {:type=>:integer}], [:d, {:type=>:decimal}]]
|
8
8
|
end
|
9
9
|
@c = Class.new(Sequel::Model(@db[:items]))
|
10
|
+
@db.extension(:looser_typecasting)
|
10
11
|
@c.instance_eval do
|
11
|
-
@columns = [:id, :b, :z]
|
12
|
+
@columns = [:id, :b, :z, :d]
|
12
13
|
def columns; @columns; end
|
13
14
|
end
|
14
15
|
end
|
15
16
|
|
16
|
-
specify "
|
17
|
-
proc{@c.new(:b=>'a')}.should raise_error(Sequel::InvalidValue)
|
18
|
-
@db.extension(:looser_typecasting)
|
17
|
+
specify "should not raise errors for invalid strings in integer columns" do
|
19
18
|
@c.new(:b=>'a').b.should == 0
|
20
|
-
|
21
|
-
o = Object.new
|
22
|
-
def o.to_i
|
23
|
-
1
|
24
|
-
end
|
25
|
-
@c.new(:b=>o).b.should == 1
|
19
|
+
@c.new(:b=>'a').b.should be_a_kind_of(Integer)
|
26
20
|
end
|
27
21
|
|
28
|
-
specify "
|
29
|
-
proc{@c.new(:z=>'a')}.should raise_error(Sequel::InvalidValue)
|
30
|
-
@db.extension(:looser_typecasting)
|
22
|
+
specify "should not raise errors for invalid strings in float columns" do
|
31
23
|
@c.new(:z=>'a').z.should == 0.0
|
24
|
+
@c.new(:z=>'a').z.should be_a_kind_of(Float)
|
25
|
+
end
|
32
26
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
27
|
+
specify "should not raise errors for invalid strings in decimal columns" do
|
28
|
+
@c.new(:d=>'a').d.should == 0.0
|
29
|
+
@c.new(:d=>'a').d.should be_a_kind_of(BigDecimal)
|
30
|
+
end
|
31
|
+
|
32
|
+
specify "should not affect conversions of other types in decimal columns" do
|
33
|
+
@c.new(:d=>1).d.should == 1
|
34
|
+
@c.new(:d=>'a').d.should be_a_kind_of(BigDecimal)
|
38
35
|
end
|
39
36
|
end
|