sequel 4.21.0 → 4.22.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +32 -0
- data/README.rdoc +3 -4
- data/doc/opening_databases.rdoc +10 -75
- data/doc/release_notes/4.22.0.txt +72 -0
- data/lib/sequel/adapters/ado/access.rb +1 -1
- data/lib/sequel/adapters/cubrid.rb +3 -3
- data/lib/sequel/adapters/db2.rb +1 -0
- data/lib/sequel/adapters/dbi.rb +1 -0
- data/lib/sequel/adapters/fdbsql.rb +3 -2
- data/lib/sequel/adapters/firebird.rb +1 -0
- data/lib/sequel/adapters/ibmdb.rb +1 -21
- data/lib/sequel/adapters/informix.rb +1 -0
- data/lib/sequel/adapters/jdbc.rb +37 -49
- data/lib/sequel/adapters/jdbc/fdbsql.rb +1 -0
- data/lib/sequel/adapters/mysql.rb +5 -3
- data/lib/sequel/adapters/mysql2.rb +5 -2
- data/lib/sequel/adapters/odbc.rb +8 -4
- data/lib/sequel/adapters/openbase.rb +1 -0
- data/lib/sequel/adapters/oracle.rb +3 -46
- data/lib/sequel/adapters/postgres.rb +3 -36
- data/lib/sequel/adapters/shared/access.rb +1 -1
- data/lib/sequel/adapters/shared/fdbsql.rb +3 -3
- data/lib/sequel/adapters/shared/mssql.rb +1 -1
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +12 -44
- data/lib/sequel/adapters/shared/oracle.rb +6 -2
- data/lib/sequel/adapters/shared/postgres.rb +6 -6
- data/lib/sequel/adapters/shared/sqlite.rb +1 -1
- data/lib/sequel/adapters/sqlite.rb +3 -46
- data/lib/sequel/adapters/tinytds.rb +12 -28
- data/lib/sequel/adapters/utils/pg_types.rb +1 -1
- data/lib/sequel/connection_pool/sharded_threaded.rb +63 -16
- data/lib/sequel/connection_pool/threaded.rb +72 -18
- data/lib/sequel/core.rb +1 -1
- data/lib/sequel/database/connecting.rb +2 -2
- data/lib/sequel/database/misc.rb +5 -5
- data/lib/sequel/database/query.rb +3 -2
- data/lib/sequel/database/schema_generator.rb +19 -19
- data/lib/sequel/database/schema_methods.rb +2 -2
- data/lib/sequel/database/transactions.rb +3 -3
- data/lib/sequel/dataset/actions.rb +18 -8
- data/lib/sequel/dataset/graph.rb +2 -2
- data/lib/sequel/dataset/prepared_statements.rb +28 -1
- data/lib/sequel/dataset/query.rb +7 -7
- data/lib/sequel/exceptions.rb +27 -24
- data/lib/sequel/extensions/_pretty_table.rb +1 -1
- data/lib/sequel/extensions/constraint_validations.rb +2 -2
- data/lib/sequel/extensions/date_arithmetic.rb +2 -2
- data/lib/sequel/extensions/pg_array.rb +10 -1
- data/lib/sequel/extensions/pg_row.rb +1 -1
- data/lib/sequel/extensions/pg_static_cache_updater.rb +1 -1
- data/lib/sequel/extensions/schema_dumper.rb +8 -8
- data/lib/sequel/extensions/split_array_nil.rb +1 -1
- data/lib/sequel/model.rb +1 -1
- data/lib/sequel/model/associations.rb +18 -11
- data/lib/sequel/model/base.rb +15 -15
- data/lib/sequel/model/exceptions.rb +11 -2
- data/lib/sequel/plugins/accessed_columns.rb +1 -1
- data/lib/sequel/plugins/auto_validations.rb +1 -1
- data/lib/sequel/plugins/boolean_readers.rb +1 -1
- data/lib/sequel/plugins/class_table_inheritance.rb +4 -7
- data/lib/sequel/plugins/composition.rb +1 -1
- data/lib/sequel/plugins/constraint_validations.rb +2 -2
- data/lib/sequel/plugins/csv_serializer.rb +171 -0
- data/lib/sequel/plugins/dirty.rb +2 -2
- data/lib/sequel/plugins/hook_class_methods.rb +1 -1
- data/lib/sequel/plugins/instance_hooks.rb +1 -1
- data/lib/sequel/plugins/many_through_many.rb +1 -1
- data/lib/sequel/plugins/nested_attributes.rb +5 -5
- data/lib/sequel/plugins/pg_array_associations.rb +4 -4
- data/lib/sequel/plugins/prepared_statements.rb +2 -2
- data/lib/sequel/plugins/prepared_statements_safe.rb +1 -1
- data/lib/sequel/plugins/serialization.rb +6 -6
- data/lib/sequel/plugins/serialization_modification_detection.rb +1 -1
- data/lib/sequel/plugins/sharding.rb +3 -1
- data/lib/sequel/plugins/single_table_inheritance.rb +5 -13
- data/lib/sequel/plugins/static_cache.rb +2 -2
- data/lib/sequel/plugins/tactical_eager_loading.rb +1 -1
- data/lib/sequel/plugins/tree.rb +1 -1
- data/lib/sequel/plugins/validation_class_methods.rb +2 -2
- data/lib/sequel/plugins/validation_helpers.rb +4 -4
- data/lib/sequel/plugins/xml_serializer.rb +3 -3
- data/lib/sequel/sql.rb +1 -1
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/postgres_spec.rb +17 -0
- data/spec/core/connection_pool_spec.rb +1 -1
- data/spec/core/dataset_spec.rb +22 -0
- data/spec/extensions/auto_validations_spec.rb +1 -1
- data/spec/extensions/blacklist_security_spec.rb +2 -2
- data/spec/extensions/csv_serializer_spec.rb +173 -0
- data/spec/extensions/json_serializer_spec.rb +2 -2
- data/spec/extensions/nested_attributes_spec.rb +9 -9
- data/spec/extensions/pg_array_spec.rb +5 -0
- data/spec/extensions/single_table_inheritance_spec.rb +21 -0
- data/spec/extensions/touch_spec.rb +1 -1
- data/spec/extensions/tree_spec.rb +4 -0
- data/spec/extensions/xml_serializer_spec.rb +3 -3
- data/spec/integration/prepared_statement_test.rb +1 -1
- data/spec/integration/schema_test.rb +7 -0
- data/spec/integration/type_test.rb +2 -2
- data/spec/model/associations_spec.rb +108 -14
- data/spec/model/base_spec.rb +8 -8
- data/spec/model/record_spec.rb +7 -7
- metadata +6 -2
@@ -11,7 +11,7 @@ describe "Sequel::Plugins::AutoValidations" do
|
|
11
11
|
[:name, {:primary_key=>false, :type=>:string, :allow_null=>false, :max_length=>50}],
|
12
12
|
[:num, {:primary_key=>false, :type=>:integer, :allow_null=>true}],
|
13
13
|
[:d, {:primary_key=>false, :type=>:date, :allow_null=>false}],
|
14
|
-
[:nnd, {:primary_key=>false, :type=>:string, :allow_null=>false, :
|
14
|
+
[:nnd, {:primary_key=>false, :type=>:string, :allow_null=>false, :default=>'nnd'}]]
|
15
15
|
end
|
16
16
|
def db.supports_index_parsing?() true end
|
17
17
|
def db.indexes(t, *)
|
@@ -16,8 +16,8 @@ describe Sequel::Model, "#(set|update)_except" do
|
|
16
16
|
|
17
17
|
it "should raise errors if not all hash fields can be set and strict_param_setting is true" do
|
18
18
|
@c.strict_param_setting = true
|
19
|
-
proc{@c.new.set_except({:x => 1, :y => 2, :z=>3, :id=>4}, :x, :y)}.should raise_error(Sequel::
|
20
|
-
proc{@c.new.set_except({:x => 1, :y => 2, :z=>3}, :x, :y)}.should raise_error(Sequel::
|
19
|
+
proc{@c.new.set_except({:x => 1, :y => 2, :z=>3, :id=>4}, :x, :y)}.should raise_error(Sequel::MassAssignmentRestriction)
|
20
|
+
proc{@c.new.set_except({:x => 1, :y => 2, :z=>3}, :x, :y)}.should raise_error(Sequel::MassAssignmentRestriction)
|
21
21
|
(o = @c.new).set_except({:z => 3}, :x, :y)
|
22
22
|
o.values.should == {:z=>3}
|
23
23
|
end
|
@@ -0,0 +1,173 @@
|
|
1
|
+
require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
|
2
|
+
|
3
|
+
describe "Sequel::Plugins::CsvSerializer" do
|
4
|
+
before do
|
5
|
+
artist = @Artist = Class.new(Sequel::Model(:artists))
|
6
|
+
@Artist.class_eval do
|
7
|
+
def self.name; 'Artist' end
|
8
|
+
unrestrict_primary_key
|
9
|
+
plugin :csv_serializer
|
10
|
+
columns :id, :name
|
11
|
+
def_column_accessor :id, :name
|
12
|
+
@db_schema = {:id=>{:type=>:integer}}
|
13
|
+
end
|
14
|
+
@Album = Class.new(Sequel::Model(:albums))
|
15
|
+
@Album.class_eval do
|
16
|
+
def self.name; 'Album' end
|
17
|
+
unrestrict_primary_key
|
18
|
+
attr_accessor :blah
|
19
|
+
plugin :csv_serializer
|
20
|
+
columns :id, :name, :artist_id
|
21
|
+
def_column_accessor :id, :name, :artist_id
|
22
|
+
@db_schema = {:id=>{:type=>:integer}, :artist_id=>{:type=>:integer}}
|
23
|
+
many_to_one :artist, :class=>artist
|
24
|
+
end
|
25
|
+
@artist = @Artist.load(:id=>2, :name=>'YJM')
|
26
|
+
@artist.associations[:albums] = []
|
27
|
+
@album = @Album.load(:id=>1, :name=>'RF')
|
28
|
+
@album.artist = @artist
|
29
|
+
@album.blah = 'Blah'
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should round trip successfully" do
|
33
|
+
@Artist.from_csv(@artist.to_csv).should == @artist
|
34
|
+
@Album.from_csv(@album.to_csv).should == @album
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should handle ruby objects in values" do
|
38
|
+
@Artist.send(:define_method, :name=) do |v|
|
39
|
+
super(Date.parse(v))
|
40
|
+
end
|
41
|
+
a = @Artist.load(:name=>Date.today)
|
42
|
+
opts = {:columns=>[:name]}
|
43
|
+
@Artist.from_csv(a.to_csv(opts), opts).should == a
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should handle the :only option" do
|
47
|
+
@Artist.from_csv(@artist.to_csv(:only=>:name), :only=>:name).should == @Artist.load(:name=>@artist.name)
|
48
|
+
@Album.from_csv(@album.to_csv(:only=>[:id, :name]), :only=>[:id, :name]).should == @Album.load(:id=>@album.id, :name=>@album.name)
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should handle the :except option" do
|
52
|
+
@Artist.from_csv(@artist.to_csv(:except=>:id), :except=>:id).should == @Artist.load(:name=>@artist.name)
|
53
|
+
@Album.from_csv(@album.to_csv(:except=>[:id, :artist_id]), :except=>[:id, :artist_id]).should == @Album.load(:name=>@album.name)
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should handle the :include option for arbitrary attributes" do
|
57
|
+
@Album.from_csv(@album.to_csv(:include=>:blah), :include=>:blah).blah.should == @album.blah
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should handle multiple inclusions using an array for the :include option" do
|
61
|
+
a = @Album.from_csv(@album.to_csv(:include=>[:blah]), :include=>:blah)
|
62
|
+
a.blah.should == @album.blah
|
63
|
+
end
|
64
|
+
|
65
|
+
it "#from_csv should set column values" do
|
66
|
+
@artist.from_csv('AS', :only=>:name)
|
67
|
+
@artist.name.should == 'AS'
|
68
|
+
@artist.id.should == 2
|
69
|
+
|
70
|
+
@artist.from_csv('1', :only=>:id)
|
71
|
+
@artist.name.should == 'AS'
|
72
|
+
@artist.id.should == 1
|
73
|
+
end
|
74
|
+
|
75
|
+
it ".array_from_csv should support :headers to specify headers" do
|
76
|
+
@albums = @Album.array_from_csv("AS,2\nDF,3", :headers=>['name', 'artist_id'])
|
77
|
+
@albums.map(&:name).should == %w'AS DF'
|
78
|
+
@albums.map(&:artist_id).should == [2, 3]
|
79
|
+
|
80
|
+
@albums = @Album.array_from_csv("2,AS\n3,DF", :headers=>[nil, 'name'])
|
81
|
+
@albums.map(&:name).should == %w'AS DF'
|
82
|
+
@albums.map(&:artist_id).should == [nil, nil]
|
83
|
+
end
|
84
|
+
|
85
|
+
it ".from_csv should support :headers to specify headers" do
|
86
|
+
@album = @Album.from_csv('AS,2', :headers=>['name', 'artist_id'])
|
87
|
+
@album.name.should == 'AS'
|
88
|
+
@album.artist_id.should == 2
|
89
|
+
|
90
|
+
@album = @Album.from_csv('2,AS', :headers=>[nil, 'name'])
|
91
|
+
@album.name.should == 'AS'
|
92
|
+
@album.artist_id.should == nil
|
93
|
+
end
|
94
|
+
|
95
|
+
it "#from_csv should support :headers to specify headers" do
|
96
|
+
@album.from_csv('AS,2', :headers=>['name'])
|
97
|
+
@album.name.should == 'AS'
|
98
|
+
@album.artist_id.should == 2
|
99
|
+
|
100
|
+
@album.from_csv('2,AS', :headers=>[nil, 'name'])
|
101
|
+
@album.name.should == 'AS'
|
102
|
+
@album.artist_id.should == 2
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should support a to_csv class and dataset method" do
|
106
|
+
@Album.dataset._fetch = {:id=>1, :name=>'RF', :artist_id=>2}
|
107
|
+
@Artist.dataset._fetch = {:id=>2, :name=>'YJM'}
|
108
|
+
@Album.array_from_csv(@Album.to_csv).should == [@album]
|
109
|
+
@Album.array_from_csv(@Album.dataset.to_csv(:only=>:name), :only=>:name).should == [@Album.load(:name=>@album.name)]
|
110
|
+
end
|
111
|
+
|
112
|
+
it "should have dataset to_csv method respect :array option" do
|
113
|
+
a = @Album.new(:id=>1, :name=>'RF', :artist_id=>3)
|
114
|
+
@Album.array_from_csv(@Album.to_csv(:array=>[a])).should == [a]
|
115
|
+
end
|
116
|
+
|
117
|
+
it "#to_csv should respect class options" do
|
118
|
+
@Album = Class.new(Sequel::Model(:albums))
|
119
|
+
artist = @Artist
|
120
|
+
@Album.class_eval do
|
121
|
+
attr_accessor :blah
|
122
|
+
plugin :csv_serializer, :except => :id, :write_headers=>true, :include=>:blah
|
123
|
+
columns :id, :name, :artist_id
|
124
|
+
many_to_one :artist, :class=>artist
|
125
|
+
end
|
126
|
+
@album = @Album.load(:id=>2, :name=>'JK')
|
127
|
+
@album.artist = @artist
|
128
|
+
@album.blah = 'Gak'
|
129
|
+
|
130
|
+
@album.to_csv.should == "name,artist_id,blah\nJK,2,Gak\n"
|
131
|
+
@album.to_csv(:write_headers=>false).should == "JK,2,Gak\n"
|
132
|
+
@album.to_csv(:headers=>[:name]).should == "name\nJK\n"
|
133
|
+
@album.to_csv(:headers=>[:name, :id]).should == "name,id\nJK,2\n"
|
134
|
+
@album.to_csv(:only=>[:name]).should == "name,blah\nJK,Gak\n"
|
135
|
+
@album.to_csv(:except=>nil).should == "id,name,artist_id,blah\n2,JK,2,Gak\n"
|
136
|
+
@album.to_csv(:except=>[:blah]).should == "id,name,artist_id\n2,JK,2\n"
|
137
|
+
end
|
138
|
+
|
139
|
+
it "should store the default options in csv_serializer_opts" do
|
140
|
+
@Album.csv_serializer_opts.should == {}
|
141
|
+
c = Class.new(@Album)
|
142
|
+
@Album.csv_serializer_opts[:include] = :blah
|
143
|
+
c.plugin :csv_serializer, :naked=>false
|
144
|
+
c.csv_serializer_opts.should == {:naked=>false}
|
145
|
+
@Album.csv_serializer_opts.should == {:include=>:blah}
|
146
|
+
end
|
147
|
+
|
148
|
+
it "should work correctly when subclassing" do
|
149
|
+
@Artist2 = Class.new(@Artist)
|
150
|
+
@Artist2.plugin :csv_serializer, :only=>:name
|
151
|
+
@Artist3 = Class.new(@Artist2)
|
152
|
+
@Artist3.from_csv(@Artist3.load(:id=>2, :name=>'YYY').to_csv).should == @Artist3.load(:name=>'YYY')
|
153
|
+
end
|
154
|
+
|
155
|
+
it "should raise an error if attempting to set a restricted column and :all_columns is not used" do
|
156
|
+
@Artist.restrict_primary_key
|
157
|
+
proc{@Artist.from_csv(@artist.to_csv)}.should raise_error(Sequel::MassAssignmentRestriction)
|
158
|
+
end
|
159
|
+
|
160
|
+
it "should use a dataset's selected columns" do
|
161
|
+
columns = [:id]
|
162
|
+
ds = @Artist.select(*columns).limit(1)
|
163
|
+
ds.instance_variable_set(:@columns, columns)
|
164
|
+
ds._fetch = [:id => 10]
|
165
|
+
ds.to_csv(:write_headers => true).should == "id\n10\n"
|
166
|
+
end
|
167
|
+
|
168
|
+
it "should pass all the examples from the documentation" do
|
169
|
+
@album.to_csv(:write_headers=>true).should == "id,name,artist_id\n1,RF,2\n"
|
170
|
+
@album.to_csv(:only=>:name).should == "RF\n"
|
171
|
+
@album.to_csv(:except=>[:id, :artist_id]).should == "RF\n"
|
172
|
+
end
|
173
|
+
end
|
@@ -157,7 +157,7 @@ describe "Sequel::Plugins::JsonSerializer" do
|
|
157
157
|
|
158
158
|
it "should raise an exception for json keys that aren't associations, columns, or setter methods" do
|
159
159
|
Album.send(:undef_method, :blah=)
|
160
|
-
proc{Album.from_json(@album.to_json(:include=>:blah))}.should raise_error(Sequel::
|
160
|
+
proc{Album.from_json(@album.to_json(:include=>:blah))}.should raise_error(Sequel::MassAssignmentRestriction)
|
161
161
|
end
|
162
162
|
|
163
163
|
it "should support a to_json class and dataset method" do
|
@@ -269,7 +269,7 @@ describe "Sequel::Plugins::JsonSerializer" do
|
|
269
269
|
|
270
270
|
it "should raise an error if attempting to set a restricted column and :all_columns is not used" do
|
271
271
|
Artist.restrict_primary_key
|
272
|
-
proc{Artist.from_json(@artist.to_json)}.should raise_error(Sequel::
|
272
|
+
proc{Artist.from_json(@artist.to_json)}.should raise_error(Sequel::MassAssignmentRestriction)
|
273
273
|
end
|
274
274
|
|
275
275
|
it "should raise an error if an unsupported association is passed in the :associations option" do
|
@@ -433,7 +433,7 @@ describe "NestedAttributes plugin" do
|
|
433
433
|
ar = @Artist.load(:id=>20, :name=>'Ar')
|
434
434
|
a.associations[:artist] = ar
|
435
435
|
@Album.nested_attributes :artist
|
436
|
-
proc{a.set(:artist_attributes=>{:id=>'20', :_delete=>'1'})}.should raise_error(Sequel::
|
436
|
+
proc{a.set(:artist_attributes=>{:id=>'20', :_delete=>'1'})}.should raise_error(Sequel::MassAssignmentRestriction)
|
437
437
|
@Album.nested_attributes :artist, :destroy=>true
|
438
438
|
proc{a.set(:artist_attributes=>{:id=>'20', :_delete=>'1'})}.should_not raise_error
|
439
439
|
end
|
@@ -443,7 +443,7 @@ describe "NestedAttributes plugin" do
|
|
443
443
|
ar = @Artist.load(:id=>20, :name=>'Ar')
|
444
444
|
a.associations[:artist] = ar
|
445
445
|
@Album.nested_attributes :artist
|
446
|
-
proc{a.set(:artist_attributes=>{:id=>'20', :_remove=>'1'})}.should raise_error(Sequel::
|
446
|
+
proc{a.set(:artist_attributes=>{:id=>'20', :_remove=>'1'})}.should raise_error(Sequel::MassAssignmentRestriction)
|
447
447
|
@Album.nested_attributes :artist, :remove=>true
|
448
448
|
proc{a.set(:artist_attributes=>{:id=>'20', :_remove=>'1'})}.should_not raise_error
|
449
449
|
end
|
@@ -545,7 +545,7 @@ describe "NestedAttributes plugin" do
|
|
545
545
|
|
546
546
|
it "should not accept nested attributes unless explicitly specified" do
|
547
547
|
@Artist.many_to_many :tags, :class=>@Tag, :left_key=>:album_id, :right_key=>:tag_id, :join_table=>:at
|
548
|
-
proc{@Artist.create({:name=>'Ar', :tags_attributes=>[{:name=>'T'}]})}.should raise_error(Sequel::
|
548
|
+
proc{@Artist.create({:name=>'Ar', :tags_attributes=>[{:name=>'T'}]})}.should raise_error(Sequel::MassAssignmentRestriction)
|
549
549
|
@db.sqls.should == []
|
550
550
|
end
|
551
551
|
|
@@ -646,8 +646,8 @@ describe "NestedAttributes plugin" do
|
|
646
646
|
"UPDATE tags SET name = 'T2' WHERE (id = 30)",
|
647
647
|
"INSERT INTO tags (name) VALUES ('T3')",
|
648
648
|
["INSERT INTO at (album_id, tag_id) VALUES (10, 1)", "INSERT INTO at (tag_id, album_id) VALUES (1, 10)"])
|
649
|
-
proc{al.set(:tags_attributes=>[{:id=>30, :name=>'T2', :number=>3}])}.should raise_error(Sequel::
|
650
|
-
proc{al.set(:tags_attributes=>[{:name=>'T2', :number=>3}])}.should raise_error(Sequel::
|
649
|
+
proc{al.set(:tags_attributes=>[{:id=>30, :name=>'T2', :number=>3}])}.should raise_error(Sequel::MassAssignmentRestriction)
|
650
|
+
proc{al.set(:tags_attributes=>[{:name=>'T2', :number=>3}])}.should raise_error(Sequel::MassAssignmentRestriction)
|
651
651
|
end
|
652
652
|
|
653
653
|
it "should accept a proc for the :fields option that accepts the associated object and returns an array of fields" do
|
@@ -664,8 +664,8 @@ describe "NestedAttributes plugin" do
|
|
664
664
|
"UPDATE tags SET name = 'T2' WHERE (id = 30)",
|
665
665
|
"INSERT INTO tags (name) VALUES ('T3')",
|
666
666
|
["INSERT INTO at (album_id, tag_id) VALUES (10, 1)", "INSERT INTO at (tag_id, album_id) VALUES (1, 10)"])
|
667
|
-
proc{al.set(:tags_attributes=>[{:id=>30, :name=>'T2', :number=>3}])}.should raise_error(Sequel::
|
668
|
-
proc{al.set(:tags_attributes=>[{:name=>'T2', :number=>3}])}.should raise_error(Sequel::
|
667
|
+
proc{al.set(:tags_attributes=>[{:id=>30, :name=>'T2', :number=>3}])}.should raise_error(Sequel::MassAssignmentRestriction)
|
668
|
+
proc{al.set(:tags_attributes=>[{:name=>'T2', :number=>3}])}.should raise_error(Sequel::MassAssignmentRestriction)
|
669
669
|
end
|
670
670
|
|
671
671
|
it "should allow per-call options via the set_nested_attributes method" do
|
@@ -682,8 +682,8 @@ describe "NestedAttributes plugin" do
|
|
682
682
|
"UPDATE tags SET name = 'T2' WHERE (id = 30)",
|
683
683
|
"INSERT INTO tags (name) VALUES ('T3')",
|
684
684
|
["INSERT INTO at (album_id, tag_id) VALUES (10, 1)", "INSERT INTO at (tag_id, album_id) VALUES (1, 10)"])
|
685
|
-
proc{al.set_nested_attributes(:tags, [{:id=>30, :name=>'T2', :number=>3}], :fields=>[:name])}.should raise_error(Sequel::
|
686
|
-
proc{al.set_nested_attributes(:tags, [{:name=>'T2', :number=>3}], :fields=>[:name])}.should raise_error(Sequel::
|
685
|
+
proc{al.set_nested_attributes(:tags, [{:id=>30, :name=>'T2', :number=>3}], :fields=>[:name])}.should raise_error(Sequel::MassAssignmentRestriction)
|
686
|
+
proc{al.set_nested_attributes(:tags, [{:name=>'T2', :number=>3}], :fields=>[:name])}.should raise_error(Sequel::MassAssignmentRestriction)
|
687
687
|
end
|
688
688
|
|
689
689
|
it "should have set_nested_attributes method raise error if called with a bad association" do
|
@@ -387,4 +387,9 @@ describe "pg_array extension" do
|
|
387
387
|
@db.schema_type_class(:banana_array).should == Sequel::Postgres::PGArray
|
388
388
|
@db.schema_type_class(:integer).should == Integer
|
389
389
|
end
|
390
|
+
|
391
|
+
it "should convert ruby arrays to pg arrays as :default option values" do
|
392
|
+
@db.create_table('a'){column :b, 'c[]', :default=>[]; Integer :d}
|
393
|
+
@db.sqls.should == ['CREATE TABLE a (b c[] DEFAULT (ARRAY[]::c[]), d integer)']
|
394
|
+
end
|
390
395
|
end
|
@@ -77,6 +77,13 @@ describe Sequel::Model, "single table inheritance plugin" do
|
|
77
77
|
DB.sqls.should == ["INSERT INTO sti_tests (kind) VALUES ('StiTest')", "SELECT * FROM sti_tests WHERE (id = 10) LIMIT 1", "INSERT INTO sti_tests (kind) VALUES ('StiTestSub1')", "SELECT * FROM sti_tests WHERE ((sti_tests.kind IN ('StiTestSub1')) AND (id = 10)) LIMIT 1", "INSERT INTO sti_tests (kind) VALUES ('StiTestSub2')", "SELECT * FROM sti_tests WHERE ((sti_tests.kind IN ('StiTestSub2')) AND (id = 10)) LIMIT 1"]
|
78
78
|
end
|
79
79
|
|
80
|
+
it "should destroy the model correctly" do
|
81
|
+
StiTest.load(:id=>1).destroy
|
82
|
+
StiTestSub1.load(:id=>1).destroy
|
83
|
+
StiTestSub2.load(:id=>1).destroy
|
84
|
+
DB.sqls.should == ["DELETE FROM sti_tests WHERE id = 1", "DELETE FROM sti_tests WHERE ((sti_tests.kind IN ('StiTestSub1')) AND (id = 1))", "DELETE FROM sti_tests WHERE ((sti_tests.kind IN ('StiTestSub2')) AND (id = 1))"]
|
85
|
+
end
|
86
|
+
|
80
87
|
it "should handle validations on the type column field" do
|
81
88
|
o = StiTestSub1.new
|
82
89
|
def o.validate
|
@@ -200,6 +207,7 @@ describe Sequel::Model, "single table inheritance plugin" do
|
|
200
207
|
StiTest2.dataset.row_proc.call(:kind=>0).should be_a_instance_of(StiTest2)
|
201
208
|
StiTest2.dataset.row_proc.call(:kind=>1).should be_a_instance_of(StiTest3)
|
202
209
|
StiTest2.dataset.row_proc.call(:kind=>2).should be_a_instance_of(StiTest4)
|
210
|
+
StiTest3.sti_model_map.should == StiTest2.sti_model_map
|
203
211
|
|
204
212
|
StiTest2.create.kind.should == 4
|
205
213
|
StiTest3.create.kind.should == 5
|
@@ -264,6 +272,19 @@ describe Sequel::Model, "single table inheritance plugin" do
|
|
264
272
|
"SELECT * FROM sti_test2s WHERE (sti_test2s.kind IN (1, 0))"].should include(StiTest3.dataset.sql)
|
265
273
|
end
|
266
274
|
|
275
|
+
it "should destroy the model correctly" do
|
276
|
+
StiTest2.plugin :single_table_inheritance, :kind, :model_map=>{'sti3'=>'StiTest3', 'sti3b'=>'StiTest3', 'sti4'=>'StiTest4'}
|
277
|
+
class ::StiTest3 < ::StiTest2; end
|
278
|
+
class ::StiTest4 < ::StiTest2; end
|
279
|
+
StiTest2.load(:id=>1).destroy
|
280
|
+
StiTest3.load(:id=>1).destroy
|
281
|
+
sqls = DB.sqls
|
282
|
+
sqls.shift.should == "DELETE FROM sti_test2s WHERE id = 1"
|
283
|
+
["DELETE FROM sti_test2s WHERE ((sti_test2s.kind IN ('sti3', 'sti3b')) AND (id = 1))",
|
284
|
+
"DELETE FROM sti_test2s WHERE ((sti_test2s.kind IN ('sti3b', 'sti3')) AND (id = 1))"].should include(sqls.pop)
|
285
|
+
sqls.should == []
|
286
|
+
end
|
287
|
+
|
267
288
|
it "should honor a :key_chooser" do
|
268
289
|
StiTest2.plugin :single_table_inheritance, :kind, :key_chooser => proc{|inst| inst.model.to_s.downcase }
|
269
290
|
class ::StiTest3 < ::StiTest2; end
|
@@ -171,7 +171,7 @@ describe "Touch plugin" do
|
|
171
171
|
|
172
172
|
specify "should raise an error if given a column argument in touch that doesn't exist" do
|
173
173
|
@Artist.plugin :touch
|
174
|
-
proc{@a.touch(:x)}.should raise_error(Sequel::
|
174
|
+
proc{@a.touch(:x)}.should raise_error(Sequel::MassAssignmentRestriction)
|
175
175
|
end
|
176
176
|
|
177
177
|
specify "should raise an Error when a nonexistent association is given" do
|
@@ -23,6 +23,10 @@ describe Sequel::Model, "tree plugin" do
|
|
23
23
|
@c.associations.sort_by{|x| x.to_s}.should == [:children, :parent]
|
24
24
|
end
|
25
25
|
|
26
|
+
it "should define the correct reciprocals" do
|
27
|
+
@c.associations.sort_by{|x| x.to_s}.map{|x| @c.association_reflection(x).reciprocal}.should == [:parent, :children]
|
28
|
+
end
|
29
|
+
|
26
30
|
it "should define the correct associations when giving options" do
|
27
31
|
klass(:children=>{:name=>:cs}, :parent=>{:name=>:p}).associations.sort_by{|x| x.to_s}.should == [:cs, :p]
|
28
32
|
end
|
@@ -149,7 +149,7 @@ describe "Sequel::Plugins::XmlSerializer" do
|
|
149
149
|
|
150
150
|
it "should raise an exception for xml tags that aren't associations, columns, or setter methods" do
|
151
151
|
Album.send(:undef_method, :blah=)
|
152
|
-
proc{Album.from_xml(@album.to_xml(:include=>:blah))}.should raise_error(Sequel::
|
152
|
+
proc{Album.from_xml(@album.to_xml(:include=>:blah))}.should raise_error(Sequel::MassAssignmentRestriction)
|
153
153
|
end
|
154
154
|
|
155
155
|
it "should support a to_xml class and dataset method" do
|
@@ -184,7 +184,7 @@ describe "Sequel::Plugins::XmlSerializer" do
|
|
184
184
|
|
185
185
|
it "should raise an error if attempting to set a restricted column and :all_columns is not used" do
|
186
186
|
Artist.restrict_primary_key
|
187
|
-
proc{Artist.from_xml(@artist.to_xml)}.should raise_error(Sequel::
|
187
|
+
proc{Artist.from_xml(@artist.to_xml)}.should raise_error(Sequel::MassAssignmentRestriction)
|
188
188
|
end
|
189
189
|
|
190
190
|
it "should raise an error if an unsupported association is passed in the :associations option" do
|
@@ -193,7 +193,7 @@ describe "Sequel::Plugins::XmlSerializer" do
|
|
193
193
|
end
|
194
194
|
|
195
195
|
it "should raise an error if using from_xml and XML represents an array" do
|
196
|
-
proc{Artist.from_xml(Artist.to_xml(:array=>[@artist]))}.should raise_error(Sequel::
|
196
|
+
proc{Artist.from_xml(Artist.to_xml(:array=>[@artist]))}.should raise_error(Sequel::MassAssignmentRestriction)
|
197
197
|
end
|
198
198
|
|
199
199
|
it "should raise an error if using array_from_xml and XML does not represent an array" do
|
@@ -355,7 +355,7 @@ describe "Bound Argument Types" do
|
|
355
355
|
@ds.filter(:s=>:$x).prepare(:first, :ps_string).call(:x=>@vs[:s])[:s].should == @vs[:s]
|
356
356
|
end
|
357
357
|
|
358
|
-
cspecify "should handle boolean type", [:do, :sqlite], [:
|
358
|
+
cspecify "should handle boolean type", [:do, :sqlite], [:jdbc, :sqlite], [:jdbc, :db2], :oracle do
|
359
359
|
@ds.filter(:b=>:$x).prepare(:first, :ps_string).call(:x=>@vs[:b])[:b].should == @vs[:b]
|
360
360
|
end
|
361
361
|
end
|
@@ -113,6 +113,13 @@ describe "Database schema parser" do
|
|
113
113
|
DB.schema(:items).first.last[:ruby_default].should == 'blah'
|
114
114
|
end
|
115
115
|
|
116
|
+
specify "should make :default nil for a NULL default" do
|
117
|
+
DB.create_table!(:items){Integer :number}
|
118
|
+
DB.schema(:items).first.last[:default].should == nil
|
119
|
+
DB.create_table!(:items){Integer :number, :default=>0}
|
120
|
+
DB.schema(:items).first.last[:default].should_not == nil
|
121
|
+
end
|
122
|
+
|
116
123
|
specify "should parse current timestamp defaults from the schema properly" do
|
117
124
|
DB.create_table!(:items){Time :a, :default=>Sequel::CURRENT_TIMESTAMP}
|
118
125
|
DB.schema(:items).first.last[:ruby_default].should == Sequel::CURRENT_TIMESTAMP
|
@@ -113,7 +113,7 @@ describe "Supported types" do
|
|
113
113
|
ds.first[:name].should be_a_kind_of(::Sequel::SQL::Blob)
|
114
114
|
end
|
115
115
|
|
116
|
-
cspecify "should support generic boolean type", [:do, :sqlite], [:jdbc, :sqlite], [:jdbc, :db2],
|
116
|
+
cspecify "should support generic boolean type", [:do, :sqlite], [:jdbc, :sqlite], [:jdbc, :db2], :oracle do
|
117
117
|
ds = create_items_table_with_column(:number, TrueClass)
|
118
118
|
ds.insert(:number => true)
|
119
119
|
ds.all.should == [{:number=>true}]
|
@@ -122,7 +122,7 @@ describe "Supported types" do
|
|
122
122
|
ds.all.should == [{:number=>true}]
|
123
123
|
end
|
124
124
|
|
125
|
-
cspecify "should support generic boolean type with defaults", [:do, :sqlite], [:jdbc, :sqlite], [:jdbc, :db2],
|
125
|
+
cspecify "should support generic boolean type with defaults", [:do, :sqlite], [:jdbc, :sqlite], [:jdbc, :db2], :oracle do
|
126
126
|
ds = create_items_table_with_column(:number, TrueClass, :default=>true)
|
127
127
|
ds.insert
|
128
128
|
ds.all.should == [{:number=>true}]
|
@@ -672,20 +672,33 @@ describe Sequel::Model, "many_to_one" do
|
|
672
672
|
end
|
673
673
|
|
674
674
|
it "should raise error and not call internal add or remove method if before callback returns false, even if raise_on_save_failure is false" do
|
675
|
-
# The reason for this is that assignment in ruby always returns the argument instead of the result
|
676
|
-
# of the method, so we can't return nil to signal that the association callback prevented the modification
|
677
675
|
p = @c2.new
|
678
676
|
c = @c2.load(:id=>123)
|
679
677
|
p.raise_on_save_failure = false
|
680
678
|
@c2.many_to_one :parent, :class => @c2, :before_set=>:bs
|
681
679
|
def p.bs(x) false end
|
682
680
|
p.should_not_receive(:_parent=)
|
683
|
-
proc{p.parent = c}.should raise_error(Sequel::
|
681
|
+
proc{p.parent = c}.should raise_error(Sequel::HookFailed)
|
682
|
+
|
683
|
+
p.parent.should == nil
|
684
|
+
p.associations[:parent] = c
|
685
|
+
p.parent.should == c
|
686
|
+
proc{p.parent = nil}.should raise_error(Sequel::HookFailed)
|
687
|
+
end
|
688
|
+
|
689
|
+
it "should raise error and not call internal add or remove method if before callback calls cancel_action, even if raise_on_save_failure is false" do
|
690
|
+
p = @c2.new
|
691
|
+
c = @c2.load(:id=>123)
|
692
|
+
p.raise_on_save_failure = false
|
693
|
+
@c2.many_to_one :parent, :class => @c2, :before_set=>:bs
|
694
|
+
def p.bs(x) cancel_action end
|
695
|
+
p.should_not_receive(:_parent=)
|
696
|
+
proc{p.parent = c}.should raise_error(Sequel::HookFailed)
|
684
697
|
|
685
698
|
p.parent.should == nil
|
686
699
|
p.associations[:parent] = c
|
687
700
|
p.parent.should == c
|
688
|
-
proc{p.parent = nil}.should raise_error(Sequel::
|
701
|
+
proc{p.parent = nil}.should raise_error(Sequel::HookFailed)
|
689
702
|
end
|
690
703
|
|
691
704
|
it "should raise an error if a callback is not a proc or symbol" do
|
@@ -1095,20 +1108,33 @@ describe Sequel::Model, "one_to_one" do
|
|
1095
1108
|
end
|
1096
1109
|
|
1097
1110
|
it "should raise error and not call internal add or remove method if before callback returns false, even if raise_on_save_failure is false" do
|
1098
|
-
|
1099
|
-
# of the method, so we can't return nil to signal that the association callback prevented the modification
|
1100
|
-
p = @c2.new
|
1111
|
+
p = @c2.load(:id=>321)
|
1101
1112
|
c = @c2.load(:id=>123)
|
1102
1113
|
p.raise_on_save_failure = false
|
1103
1114
|
@c2.one_to_one :parent, :class => @c2, :before_set=>:bs
|
1104
1115
|
def p.bs(x) false end
|
1105
1116
|
p.should_not_receive(:_parent=)
|
1106
|
-
proc{p.parent = c}.should raise_error(Sequel::
|
1117
|
+
proc{p.parent = c}.should raise_error(Sequel::HookFailed)
|
1107
1118
|
|
1108
|
-
p.parent.should == nil
|
1119
|
+
p.associations[:parent].should == nil
|
1109
1120
|
p.associations[:parent] = c
|
1110
1121
|
p.parent.should == c
|
1111
|
-
proc{p.parent = nil}.should raise_error(Sequel::
|
1122
|
+
proc{p.parent = nil}.should raise_error(Sequel::HookFailed)
|
1123
|
+
end
|
1124
|
+
|
1125
|
+
it "should raise error and not call internal add or remove method if before callback returns false, even if raise_on_save_failure is false" do
|
1126
|
+
p = @c2.load(:id=>321)
|
1127
|
+
c = @c2.load(:id=>123)
|
1128
|
+
p.raise_on_save_failure = false
|
1129
|
+
@c2.one_to_one :parent, :class => @c2, :before_set=>:bs
|
1130
|
+
def p.bs(x) cancel_action end
|
1131
|
+
p.should_not_receive(:_parent=)
|
1132
|
+
proc{p.parent = c}.should raise_error(Sequel::HookFailed)
|
1133
|
+
|
1134
|
+
p.associations[:parent].should == nil
|
1135
|
+
p.associations[:parent] = c
|
1136
|
+
p.parent.should == c
|
1137
|
+
proc{p.parent = nil}.should raise_error(Sequel::HookFailed)
|
1112
1138
|
end
|
1113
1139
|
|
1114
1140
|
it "should not validate the associated object in setter if the :validate=>false option is used" do
|
@@ -1837,11 +1863,11 @@ describe Sequel::Model, "one_to_many" do
|
|
1837
1863
|
p.should_not_receive(:_add_attribute)
|
1838
1864
|
p.should_not_receive(:_remove_attribute)
|
1839
1865
|
p.associations[:attributes] = []
|
1840
|
-
proc{p.add_attribute(c)}.should raise_error(Sequel::
|
1866
|
+
proc{p.add_attribute(c)}.should raise_error(Sequel::HookFailed)
|
1841
1867
|
p.attributes.should == []
|
1842
1868
|
p.associations[:attributes] = [c]
|
1843
1869
|
p.should_receive(:br).once.with(c).and_return(false)
|
1844
|
-
proc{p.remove_attribute(c)}.should raise_error(Sequel::
|
1870
|
+
proc{p.remove_attribute(c)}.should raise_error(Sequel::HookFailed)
|
1845
1871
|
p.attributes.should == [c]
|
1846
1872
|
end
|
1847
1873
|
|
@@ -1861,6 +1887,39 @@ describe Sequel::Model, "one_to_many" do
|
|
1861
1887
|
p.remove_attribute(c).should == nil
|
1862
1888
|
p.attributes.should == [c]
|
1863
1889
|
end
|
1890
|
+
|
1891
|
+
it "should raise error and not call internal add or remove method if before callback calls cancel_action if raise_on_save_failure is true" do
|
1892
|
+
p = @c2.load(:id=>10)
|
1893
|
+
c = @c1.load(:id=>123)
|
1894
|
+
@c2.one_to_many :attributes, :class => @c1, :before_add=>:ba, :before_remove=>:br
|
1895
|
+
def p.ba(o); cancel_action; end
|
1896
|
+
p.should_not_receive(:_add_attribute)
|
1897
|
+
p.should_not_receive(:_remove_attribute)
|
1898
|
+
p.associations[:attributes] = []
|
1899
|
+
proc{p.add_attribute(c)}.should raise_error(Sequel::HookFailed)
|
1900
|
+
p.attributes.should == []
|
1901
|
+
p.associations[:attributes] = [c]
|
1902
|
+
def p.br(o); cancel_action; end
|
1903
|
+
proc{p.remove_attribute(c)}.should raise_error(Sequel::HookFailed)
|
1904
|
+
p.attributes.should == [c]
|
1905
|
+
end
|
1906
|
+
|
1907
|
+
it "should return nil and not call internal add or remove method if before callback calls cancel_action if raise_on_save_failure is false" do
|
1908
|
+
p = @c2.load(:id=>10)
|
1909
|
+
c = @c1.load(:id=>123)
|
1910
|
+
p.raise_on_save_failure = false
|
1911
|
+
@c2.one_to_many :attributes, :class => @c1, :before_add=>:ba, :before_remove=>:br
|
1912
|
+
def p.ba(o); cancel_action; end
|
1913
|
+
p.should_not_receive(:_add_attribute)
|
1914
|
+
p.should_not_receive(:_remove_attribute)
|
1915
|
+
p.associations[:attributes] = []
|
1916
|
+
p.add_attribute(c).should == nil
|
1917
|
+
p.attributes.should == []
|
1918
|
+
p.associations[:attributes] = [c]
|
1919
|
+
def p.br(o); cancel_action; end
|
1920
|
+
p.remove_attribute(c).should == nil
|
1921
|
+
p.attributes.should == [c]
|
1922
|
+
end
|
1864
1923
|
end
|
1865
1924
|
|
1866
1925
|
describe Sequel::Model, "many_to_many" do
|
@@ -2642,11 +2701,11 @@ describe Sequel::Model, "many_to_many" do
|
|
2642
2701
|
p.should_not_receive(:_remove_attribute)
|
2643
2702
|
p.associations[:attributes] = []
|
2644
2703
|
p.raise_on_save_failure = true
|
2645
|
-
proc{p.add_attribute(c)}.should raise_error(Sequel::
|
2704
|
+
proc{p.add_attribute(c)}.should raise_error(Sequel::HookFailed)
|
2646
2705
|
p.attributes.should == []
|
2647
2706
|
p.associations[:attributes] = [c]
|
2648
2707
|
p.should_receive(:br).once.with(c).and_return(false)
|
2649
|
-
proc{p.remove_attribute(c)}.should raise_error(Sequel::
|
2708
|
+
proc{p.remove_attribute(c)}.should raise_error(Sequel::HookFailed)
|
2650
2709
|
p.attributes.should == [c]
|
2651
2710
|
end
|
2652
2711
|
|
@@ -2667,6 +2726,41 @@ describe Sequel::Model, "many_to_many" do
|
|
2667
2726
|
p.attributes.should == [c]
|
2668
2727
|
end
|
2669
2728
|
|
2729
|
+
it "should raise error and not call internal add or remove method if before callback calls cancel_action if raise_on_save_failure is true" do
|
2730
|
+
p = @c2.load(:id=>10)
|
2731
|
+
c = @c1.load(:id=>123)
|
2732
|
+
@c2.many_to_many :attributes, :class => @c1, :before_add=>:ba, :before_remove=>:br
|
2733
|
+
def p.ba(o) cancel_action end
|
2734
|
+
p.should_receive(:ba).once.with(c).and_return(false)
|
2735
|
+
p.should_not_receive(:_add_attribute)
|
2736
|
+
p.should_not_receive(:_remove_attribute)
|
2737
|
+
p.associations[:attributes] = []
|
2738
|
+
p.raise_on_save_failure = true
|
2739
|
+
proc{p.add_attribute(c)}.should raise_error(Sequel::HookFailed)
|
2740
|
+
p.attributes.should == []
|
2741
|
+
p.associations[:attributes] = [c]
|
2742
|
+
def p.br(o) cancel_action end
|
2743
|
+
proc{p.remove_attribute(c)}.should raise_error(Sequel::HookFailed)
|
2744
|
+
p.attributes.should == [c]
|
2745
|
+
end
|
2746
|
+
|
2747
|
+
it "should return nil and not call internal add or remove method if before callback calls cancel_action if raise_on_save_failure is false" do
|
2748
|
+
p = @c2.load(:id=>10)
|
2749
|
+
c = @c1.load(:id=>123)
|
2750
|
+
p.raise_on_save_failure = false
|
2751
|
+
@c2.many_to_many :attributes, :class => @c1, :before_add=>:ba, :before_remove=>:br
|
2752
|
+
def p.ba(o) cancel_action end
|
2753
|
+
p.should_not_receive(:_add_attribute)
|
2754
|
+
p.should_not_receive(:_remove_attribute)
|
2755
|
+
p.associations[:attributes] = []
|
2756
|
+
p.add_attribute(c).should == nil
|
2757
|
+
p.attributes.should == []
|
2758
|
+
p.associations[:attributes] = [c]
|
2759
|
+
def p.br(o) cancel_action end
|
2760
|
+
p.remove_attribute(c).should == nil
|
2761
|
+
p.attributes.should == [c]
|
2762
|
+
end
|
2763
|
+
|
2670
2764
|
it "should support a :uniq option that removes duplicates from the association" do
|
2671
2765
|
@c2.many_to_many :attributes, :class => @c1, :uniq=>true
|
2672
2766
|
@c1.dataset._fetch = [{:id=>20}, {:id=>30}, {:id=>20}, {:id=>30}]
|