sequel 3.45.0 → 3.46.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.
- 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
|