sequel 5.19.0 → 5.20.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +24 -0
- data/doc/release_notes/5.20.0.txt +89 -0
- data/doc/transactions.rdoc +38 -0
- data/lib/sequel/adapters/mysql2.rb +2 -2
- data/lib/sequel/adapters/shared/postgres.rb +5 -7
- data/lib/sequel/database/query.rb +1 -1
- data/lib/sequel/database/schema_generator.rb +1 -1
- data/lib/sequel/database/transactions.rb +57 -5
- data/lib/sequel/dataset/placeholder_literalizer.rb +4 -1
- data/lib/sequel/dataset/query.rb +1 -1
- data/lib/sequel/extensions/schema_dumper.rb +1 -1
- data/lib/sequel/model/associations.rb +35 -9
- data/lib/sequel/model/plugins.rb +104 -0
- data/lib/sequel/plugins/association_dependencies.rb +3 -3
- data/lib/sequel/plugins/association_pks.rb +14 -4
- data/lib/sequel/plugins/class_table_inheritance.rb +1 -0
- data/lib/sequel/plugins/composition.rb +13 -9
- data/lib/sequel/plugins/finder.rb +2 -2
- data/lib/sequel/plugins/hook_class_methods.rb +17 -5
- data/lib/sequel/plugins/inverted_subsets.rb +2 -2
- data/lib/sequel/plugins/pg_auto_constraint_validations.rb +61 -32
- data/lib/sequel/plugins/subset_conditions.rb +2 -2
- data/lib/sequel/plugins/validation_class_methods.rb +5 -3
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/postgres_spec.rb +32 -0
- data/spec/core/database_spec.rb +73 -2
- data/spec/core/schema_spec.rb +6 -0
- data/spec/extensions/class_table_inheritance_spec.rb +30 -8
- data/spec/extensions/core_refinements_spec.rb +1 -1
- data/spec/extensions/hook_class_methods_spec.rb +22 -0
- data/spec/extensions/migration_spec.rb +13 -0
- data/spec/extensions/pg_auto_constraint_validations_spec.rb +8 -0
- data/spec/extensions/s_spec.rb +1 -1
- data/spec/extensions/schema_dumper_spec.rb +4 -2
- data/spec/integration/plugin_test.rb +15 -0
- data/spec/integration/transaction_test.rb +50 -0
- data/spec/model/associations_spec.rb +84 -4
- data/spec/model/plugins_spec.rb +111 -0
- metadata +4 -2
@@ -26,8 +26,8 @@ module Sequel
|
|
26
26
|
# Album.where(Album.published_conditions | {ready: true}).sql
|
27
27
|
# # SELECT * FROM albums WHERE ((published IS TRUE) OR (ready IS TRUE))
|
28
28
|
module SubsetConditions
|
29
|
-
def self.apply(
|
30
|
-
|
29
|
+
def self.apply(model, &block)
|
30
|
+
model.instance_exec do
|
31
31
|
@dataset_module_class = Class.new(@dataset_module_class) do
|
32
32
|
include DatasetModuleMethods
|
33
33
|
end
|
@@ -188,13 +188,17 @@ module Sequel
|
|
188
188
|
# Sequel will attempt to insert a NULL value into the database, instead of using the
|
189
189
|
# database's default.
|
190
190
|
# :allow_nil :: Whether to skip the validation if the value is nil.
|
191
|
-
# :if :: A symbol (indicating an instance_method) or proc (which is
|
191
|
+
# :if :: A symbol (indicating an instance_method) or proc (which is used to define an instance method)
|
192
192
|
# skipping this validation if it returns nil or false.
|
193
193
|
# :tag :: The tag to use for this validation.
|
194
194
|
def validates_each(*atts, &block)
|
195
195
|
opts = extract_options!(atts)
|
196
196
|
blank_meth = db.method(:blank_object?).to_proc
|
197
197
|
blk = if (i = opts[:if]) || (am = opts[:allow_missing]) || (an = opts[:allow_nil]) || (ab = opts[:allow_blank])
|
198
|
+
if i.is_a?(Proc)
|
199
|
+
i = Plugins.def_sequel_method(self, "validation_class_methods_if", 0, &i)
|
200
|
+
end
|
201
|
+
|
198
202
|
proc do |o,a,v|
|
199
203
|
next if i && !validation_if_proc(o, i)
|
200
204
|
next if an && Array(v).all?(&:nil?)
|
@@ -434,8 +438,6 @@ module Sequel
|
|
434
438
|
case i
|
435
439
|
when Symbol
|
436
440
|
o.get_column_value(i)
|
437
|
-
when Proc
|
438
|
-
o.instance_exec(&i)
|
439
441
|
else
|
440
442
|
raise(::Sequel::Error, "invalid value for :if validation option")
|
441
443
|
end
|
data/lib/sequel/version.rb
CHANGED
@@ -6,7 +6,7 @@ module Sequel
|
|
6
6
|
|
7
7
|
# The minor version of Sequel. Bumped for every non-patch level
|
8
8
|
# release, generally around once a month.
|
9
|
-
MINOR =
|
9
|
+
MINOR = 20
|
10
10
|
|
11
11
|
# The tiny version of Sequel. Usually 0, only bumped for bugfix
|
12
12
|
# releases that fix regressions from previous versions.
|
@@ -104,6 +104,24 @@ describe "PostgreSQL", '#create_table' do
|
|
104
104
|
@db.check_constraints(:tmp_dolls).must_equal(:ic=>{:definition=>"CHECK ((i > 2))", :columns=>[:i]}, :jc=>{:definition=>"CHECK ((j > 2))", :columns=>[:j]}, :ijc=>{:definition=>"CHECK (((i - j) > 2))", :columns=>[:i, :j]})
|
105
105
|
end
|
106
106
|
|
107
|
+
it "should have #check_constraints return check constraints where columns are unknown" do
|
108
|
+
begin
|
109
|
+
@db.create_table(:tmp_dolls) do
|
110
|
+
Integer :i
|
111
|
+
Integer :j
|
112
|
+
end
|
113
|
+
@db.run "CREATE OR REPLACE FUNCTION valid_tmp_dolls(t1 tmp_dolls) RETURNS boolean AS 'SELECT false' LANGUAGE SQL;"
|
114
|
+
@db.alter_table(:tmp_dolls) do
|
115
|
+
add_constraint(:valid_tmp_dolls, Sequel.function(:valid_tmp_dolls, :tmp_dolls))
|
116
|
+
end
|
117
|
+
|
118
|
+
@db.check_constraints(:tmp_dolls).must_equal(:valid_tmp_dolls=>{:definition=>"CHECK (valid_tmp_dolls(tmp_dolls.*))", :columns=>[]})
|
119
|
+
ensure
|
120
|
+
@db.run "ALTER TABLE tmp_dolls DROP CONSTRAINT IF EXISTS valid_tmp_dolls"
|
121
|
+
@db.run "DROP FUNCTION IF EXISTS valid_tmp_dolls(tmp_dolls)"
|
122
|
+
end
|
123
|
+
end if DB.server_version >= 90000
|
124
|
+
|
107
125
|
it "should not allow to pass both :temp and :unlogged" do
|
108
126
|
proc do
|
109
127
|
@db.create_table(:temp_unlogged_dolls, :temp => true, :unlogged => true){text :name}
|
@@ -3988,6 +4006,10 @@ describe "pg_auto_constraint_validations plugin" do
|
|
3988
4006
|
constraint :valid_i, Sequel[:i] < 10
|
3989
4007
|
constraint(:valid_i_id, Sequel[:i] + Sequel[:id] < 20)
|
3990
4008
|
end
|
4009
|
+
@db.run "CREATE OR REPLACE FUNCTION valid_test1(t1 test1) RETURNS boolean AS 'SELECT t1.i != -100' LANGUAGE SQL;"
|
4010
|
+
@db.alter_table(:test1) do
|
4011
|
+
add_constraint(:valid_test1, Sequel.function(:valid_test1, :test1))
|
4012
|
+
end
|
3991
4013
|
@db.create_table!(:test2) do
|
3992
4014
|
Integer :test2_id, :primary_key=>true
|
3993
4015
|
foreign_key :test1_id, :test1
|
@@ -4008,6 +4030,8 @@ describe "pg_auto_constraint_validations plugin" do
|
|
4008
4030
|
@c2.insert(:test2_id=>3, :test1_id=>1)
|
4009
4031
|
end
|
4010
4032
|
after(:all) do
|
4033
|
+
@db.run "ALTER TABLE test1 DROP CONSTRAINT IF EXISTS valid_test1"
|
4034
|
+
@db.run "DROP FUNCTION IF EXISTS valid_test1(test1)"
|
4011
4035
|
@db.drop_table?(:test2, :test1)
|
4012
4036
|
end
|
4013
4037
|
|
@@ -4017,6 +4041,14 @@ describe "pg_auto_constraint_validations plugin" do
|
|
4017
4041
|
o.errors.must_equal(:i=>['is invalid'])
|
4018
4042
|
end
|
4019
4043
|
|
4044
|
+
it "should handle check constraint failures where the columns are unknown, if columns are explicitly specified" do
|
4045
|
+
o = @c1.new(:id=>5, :i=>-100)
|
4046
|
+
proc{o.save}.must_raise Sequel::CheckConstraintViolation
|
4047
|
+
@c1.pg_auto_constraint_validation_override(:valid_test1, :i, "should not be -100")
|
4048
|
+
proc{o.save}.must_raise Sequel::ValidationFailed
|
4049
|
+
o.errors.must_equal(:i=>['should not be -100'])
|
4050
|
+
end
|
4051
|
+
|
4020
4052
|
it "should handle check constraint failures as validation errors when updating" do
|
4021
4053
|
o = @c1.new(:id=>5, :i=>3)
|
4022
4054
|
o.save
|
data/spec/core/database_spec.rb
CHANGED
@@ -1140,15 +1140,86 @@ describe "Database#transaction with savepoint support" do
|
|
1140
1140
|
end
|
1141
1141
|
|
1142
1142
|
it "should support after_rollback inside savepoints" do
|
1143
|
-
@db.transaction do
|
1143
|
+
@db.transaction(:rollback=>:always) do
|
1144
1144
|
@db.after_rollback{@db.execute('foo')}
|
1145
1145
|
@db.transaction(:savepoint=>true){@db.after_rollback{@db.execute('bar')}}
|
1146
1146
|
@db.after_rollback{@db.execute('baz')}
|
1147
|
-
raise Sequel::Rollback
|
1148
1147
|
end
|
1149
1148
|
@db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1', 'RELEASE SAVEPOINT autopoint_1', 'ROLLBACK', 'foo', 'bar', 'baz']
|
1150
1149
|
end
|
1151
1150
|
|
1151
|
+
it "should run after_commit if savepoint rolled back" do
|
1152
|
+
@db.transaction do
|
1153
|
+
@db.after_commit{@db.execute('foo')}
|
1154
|
+
@db.transaction(:savepoint=>true, :rollback=>:always){@db.after_commit{@db.execute('bar')}}
|
1155
|
+
end
|
1156
|
+
@db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1', 'ROLLBACK TO SAVEPOINT autopoint_1', 'COMMIT', 'foo', 'bar']
|
1157
|
+
end
|
1158
|
+
|
1159
|
+
it "should not run after_commit if savepoint rolled back and :savepoint option used" do
|
1160
|
+
@db.transaction do
|
1161
|
+
@db.after_commit{@db.execute('foo')}
|
1162
|
+
@db.transaction(:savepoint=>true, :rollback=>:always){@db.after_commit(:savepoint=>true){@db.execute('bar')}}
|
1163
|
+
end
|
1164
|
+
@db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1', 'ROLLBACK TO SAVEPOINT autopoint_1', 'COMMIT', 'foo']
|
1165
|
+
end
|
1166
|
+
|
1167
|
+
it "should not run after_commit if higher-level savepoint rolled back and :savepoint option used" do
|
1168
|
+
@db.transaction do
|
1169
|
+
@db.after_commit{@db.execute('foo')}
|
1170
|
+
@db.transaction(:savepoint=>true, :rollback=>:always){@db.transaction(:savepoint=>true){@db.after_commit(:savepoint=>true){@db.execute('bar')}}}
|
1171
|
+
end
|
1172
|
+
@db.sqls.must_equal ["BEGIN", "SAVEPOINT autopoint_1", "SAVEPOINT autopoint_2", "RELEASE SAVEPOINT autopoint_2", "ROLLBACK TO SAVEPOINT autopoint_1", "COMMIT", "foo"]
|
1173
|
+
end
|
1174
|
+
|
1175
|
+
it "should not run after_commit if transaction rolled back and :savepoint option used" do
|
1176
|
+
@db.transaction(:rollback=>:always) do
|
1177
|
+
@db.after_commit{@db.execute('foo')}
|
1178
|
+
@db.transaction(:savepoint=>true){@db.transaction(:savepoint=>true){@db.after_commit(:savepoint=>true){@db.execute('bar')}}}
|
1179
|
+
end
|
1180
|
+
@db.sqls.must_equal ["BEGIN", "SAVEPOINT autopoint_1", "SAVEPOINT autopoint_2", "RELEASE SAVEPOINT autopoint_2", "RELEASE SAVEPOINT autopoint_1", "ROLLBACK"]
|
1181
|
+
end
|
1182
|
+
|
1183
|
+
it "should run after_rollback if savepoint rolls back" do
|
1184
|
+
@db.transaction(:rollback=>:always) do
|
1185
|
+
@db.after_rollback{@db.execute('foo')}
|
1186
|
+
@db.transaction(:savepoint=>true, :rollback=>:always){@db.after_rollback{@db.execute('bar')}}
|
1187
|
+
@db.after_rollback{@db.execute('baz')}
|
1188
|
+
end
|
1189
|
+
@db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1', 'ROLLBACK TO SAVEPOINT autopoint_1', 'ROLLBACK', 'foo', 'bar', 'baz']
|
1190
|
+
end
|
1191
|
+
|
1192
|
+
it "should run after_rollback when savepoint rolls back if :savepoint option used" do
|
1193
|
+
@db.transaction(:rollback=>:always) do
|
1194
|
+
@db.after_rollback{@db.execute('foo')}
|
1195
|
+
@db.transaction(:savepoint=>true, :rollback=>:always){@db.after_rollback(:savepoint=>true){@db.execute('bar')}}
|
1196
|
+
@db.after_rollback{@db.execute('baz')}
|
1197
|
+
end
|
1198
|
+
@db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1', 'ROLLBACK TO SAVEPOINT autopoint_1', 'bar', 'ROLLBACK', 'foo', 'baz']
|
1199
|
+
end
|
1200
|
+
|
1201
|
+
it "should run after_rollback if savepoint rolled back and :savepoint option used, even if transaction commits" do
|
1202
|
+
@db.transaction do
|
1203
|
+
@db.after_commit{@db.execute('foo')}
|
1204
|
+
@db.transaction(:savepoint=>true, :rollback=>:always){@db.after_rollback(:savepoint=>true){@db.execute('bar')}}
|
1205
|
+
end
|
1206
|
+
@db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1', 'ROLLBACK TO SAVEPOINT autopoint_1', 'bar', 'COMMIT', 'foo']
|
1207
|
+
end
|
1208
|
+
|
1209
|
+
it "should run after_rollback if higher-level savepoint rolled back and :savepoint option used" do
|
1210
|
+
@db.transaction do
|
1211
|
+
@db.transaction(:savepoint=>true, :rollback=>:always){@db.transaction(:savepoint=>true){@db.after_rollback(:savepoint=>true){@db.execute('bar')}}}
|
1212
|
+
end
|
1213
|
+
@db.sqls.must_equal ["BEGIN", "SAVEPOINT autopoint_1", "SAVEPOINT autopoint_2", "RELEASE SAVEPOINT autopoint_2", "ROLLBACK TO SAVEPOINT autopoint_1", "bar", "COMMIT"]
|
1214
|
+
end
|
1215
|
+
|
1216
|
+
it "should run after_rollback if transaction rolled back and :savepoint option used" do
|
1217
|
+
@db.transaction(:rollback=>:always) do
|
1218
|
+
@db.transaction(:savepoint=>true){@db.transaction(:savepoint=>true){@db.after_rollback(:savepoint=>true){@db.execute('bar')}}}
|
1219
|
+
end
|
1220
|
+
@db.sqls.must_equal ["BEGIN", "SAVEPOINT autopoint_1", "SAVEPOINT autopoint_2", "RELEASE SAVEPOINT autopoint_2", "RELEASE SAVEPOINT autopoint_1", "ROLLBACK", "bar"]
|
1221
|
+
end
|
1222
|
+
|
1152
1223
|
it "should raise an error if you attempt to use after_commit inside a savepoint in a prepared transaction" do
|
1153
1224
|
@db.define_singleton_method(:supports_prepared_transactions?){true}
|
1154
1225
|
proc{@db.transaction(:prepare=>'XYZ'){@db.transaction(:savepoint=>true){@db.after_commit{@db.execute('foo')}}}}.must_raise(Sequel::Error)
|
data/spec/core/schema_spec.rb
CHANGED
@@ -1777,17 +1777,21 @@ describe "Schema Parser" do
|
|
1777
1777
|
@db.schema(:text).first.last[:type].must_equal :string
|
1778
1778
|
@db.schema(:date).first.last[:type].must_equal :date
|
1779
1779
|
@db.schema(:datetime).first.last[:type].must_equal :datetime
|
1780
|
+
@db.schema(:smalldatetime).first.last[:type].must_equal :datetime
|
1780
1781
|
@db.schema(:timestamp).first.last[:type].must_equal :datetime
|
1781
1782
|
@db.schema(:"timestamp with time zone").first.last[:type].must_equal :datetime
|
1782
1783
|
@db.schema(:"timestamp without time zone").first.last[:type].must_equal :datetime
|
1783
1784
|
@db.schema(:time).first.last[:type].must_equal :time
|
1784
1785
|
@db.schema(:"time with time zone").first.last[:type].must_equal :time
|
1785
1786
|
@db.schema(:"time without time zone").first.last[:type].must_equal :time
|
1787
|
+
@db.schema(:bool).first.last[:type].must_equal :boolean
|
1786
1788
|
@db.schema(:boolean).first.last[:type].must_equal :boolean
|
1787
1789
|
@db.schema(:real).first.last[:type].must_equal :float
|
1788
1790
|
@db.schema(:float).first.last[:type].must_equal :float
|
1791
|
+
@db.schema(:"float unsigned").first.last[:type].must_equal :float
|
1789
1792
|
@db.schema(:double).first.last[:type].must_equal :float
|
1790
1793
|
@db.schema(:"double(1,2)").first.last[:type].must_equal :float
|
1794
|
+
@db.schema(:"double(1,2) unsigned").first.last[:type].must_equal :float
|
1791
1795
|
@db.schema(:"double precision").first.last[:type].must_equal :float
|
1792
1796
|
@db.schema(:number).first.last[:type].must_equal :decimal
|
1793
1797
|
@db.schema(:numeric).first.last[:type].must_equal :decimal
|
@@ -1801,6 +1805,8 @@ describe "Schema Parser" do
|
|
1801
1805
|
@db.schema(:nchar).first.last[:type].must_equal :string
|
1802
1806
|
@db.schema(:nvarchar).first.last[:type].must_equal :string
|
1803
1807
|
@db.schema(:ntext).first.last[:type].must_equal :string
|
1808
|
+
@db.schema(:clob).first.last[:type].must_equal :string
|
1809
|
+
@db.schema(:ntext).first.last[:type].must_equal :string
|
1804
1810
|
@db.schema(:smalldatetime).first.last[:type].must_equal :datetime
|
1805
1811
|
@db.schema(:binary).first.last[:type].must_equal :blob
|
1806
1812
|
@db.schema(:varbinary).first.last[:type].must_equal :blob
|
@@ -5,8 +5,8 @@ describe "class_table_inheritance plugin" do
|
|
5
5
|
@db = Sequel.mock(:numrows=>1, :autoid=>proc{|sql| 1})
|
6
6
|
def @db.supports_schema_parsing?() true end
|
7
7
|
def @db.schema(table, opts={})
|
8
|
-
{:employees=>[[:id, {:primary_key=>true, :type=>:integer}], [:name, {:type=>:string}], [:kind, {:type=>:string}]],
|
9
|
-
:managers=>[[:id, {:type=>:integer}], [:num_staff, {:type=>:integer}] ],
|
8
|
+
{:employees=>[[:id, {:primary_key=>true, :type=>:integer}], [:name, {:type=>:string, :allow_null=>false}], [:kind, {:type=>:string}]],
|
9
|
+
:managers=>[[:id, {:type=>:integer}], [:num_staff, {:type=>:integer, :allow_null=>false}] ],
|
10
10
|
:executives=>[[:id, {:type=>:integer}], [:num_managers, {:type=>:integer}]],
|
11
11
|
:staff=>[[:id, {:type=>:integer}], [:manager_id, {:type=>:integer}]],
|
12
12
|
}[table.is_a?(Sequel::Dataset) ? table.first_source_table : table]
|
@@ -23,7 +23,9 @@ describe "class_table_inheritance plugin" do
|
|
23
23
|
}[opts[:from] + (opts[:join] || []).map{|x| x.table}]
|
24
24
|
end
|
25
25
|
end
|
26
|
-
|
26
|
+
base = Sequel::Model(@db)
|
27
|
+
base.plugin :auto_validations if @use_auto_validations
|
28
|
+
class ::Employee < base
|
27
29
|
def _save_refresh; @values[:id] = 1 end
|
28
30
|
def self.columns
|
29
31
|
dataset.columns || dataset.opts[:from].first.expression.columns
|
@@ -114,6 +116,26 @@ describe "class_table_inheritance plugin" do
|
|
114
116
|
"SELECT * FROM (SELECT employees.id, employees.name, employees.kind, managers.num_staff, executives.num_managers FROM employees INNER JOIN managers ON (managers.id = employees.id) INNER JOIN executives ON (executives.id = managers.id) WHERE (employees.kind IN ('Ceo'))) AS employees WHERE (id = 1) LIMIT 1"]
|
115
117
|
end
|
116
118
|
|
119
|
+
describe "with auto_validations plugin" do
|
120
|
+
before(:all) do
|
121
|
+
@use_auto_validations = true
|
122
|
+
end
|
123
|
+
|
124
|
+
it "should work" do
|
125
|
+
e = Employee.new
|
126
|
+
e.valid?.must_equal false
|
127
|
+
e.errors.must_equal(:name=>["is not present"])
|
128
|
+
|
129
|
+
e = Manager.new
|
130
|
+
e.valid?.must_equal false
|
131
|
+
e.errors.must_equal(:name=>["is not present"], :num_staff=>["is not present"])
|
132
|
+
|
133
|
+
e = Executive.new
|
134
|
+
e.valid?.must_equal false
|
135
|
+
e.errors.must_equal(:name=>["is not present"], :num_staff=>["is not present"])
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
117
139
|
it "should return rows with the current class if sti_key is nil" do
|
118
140
|
Employee.plugin :class_table_inheritance
|
119
141
|
Employee.dataset.with_fetch([{:kind=>'Employee'}, {:kind=>'Manager'}, {:kind=>'Executive'}, {:kind=>'Ceo'}, {:kind=>'Staff'}, {:kind=>'Intern'}]).all.map{|x| x.class}.must_equal [Employee, Employee, Employee, Employee, Employee, Employee]
|
@@ -232,11 +254,11 @@ describe "class_table_inheritance plugin" do
|
|
232
254
|
end
|
233
255
|
|
234
256
|
it "should include schema for columns for tables for ancestor classes" do
|
235
|
-
Employee.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string}, :kind=>{:type=>:string})
|
236
|
-
Manager.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string}, :kind=>{:type=>:string}, :num_staff=>{:type=>:integer})
|
237
|
-
Executive.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string}, :kind=>{:type=>:string}, :num_staff=>{:type=>:integer}, :num_managers=>{:type=>:integer})
|
238
|
-
Staff.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string}, :kind=>{:type=>:string}, :manager_id=>{:type=>:integer})
|
239
|
-
Intern.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string}, :kind=>{:type=>:string})
|
257
|
+
Employee.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string, :allow_null=>false}, :kind=>{:type=>:string})
|
258
|
+
Manager.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string, :allow_null=>false}, :kind=>{:type=>:string}, :num_staff=>{:type=>:integer, :allow_null=>false})
|
259
|
+
Executive.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string, :allow_null=>false}, :kind=>{:type=>:string}, :num_staff=>{:type=>:integer, :allow_null=>false}, :num_managers=>{:type=>:integer})
|
260
|
+
Staff.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string, :allow_null=>false}, :kind=>{:type=>:string}, :manager_id=>{:type=>:integer})
|
261
|
+
Intern.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string, :allow_null=>false}, :kind=>{:type=>:string})
|
240
262
|
end
|
241
263
|
|
242
264
|
it "should use the correct primary key (which should have the same name in all subclasses)" do
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require_relative "spec_helper"
|
2
2
|
|
3
|
-
if (RUBY_VERSION >= '2.0.0' && RUBY_ENGINE == 'ruby')
|
3
|
+
if (RUBY_VERSION >= '2.0.0' && RUBY_ENGINE == 'ruby') || (RUBY_ENGINE == 'jruby' && (JRUBY_VERSION >= '9.3' || (JRUBY_VERSION.match(/\A9\.2\.(\d+)/) && $1.to_i >= 7)))
|
4
4
|
Sequel.extension :core_refinements, :pg_array, :pg_hstore, :pg_row, :pg_range, :pg_row_ops, :pg_range_ops, :pg_array_ops, :pg_hstore_ops, :pg_json, :pg_json_ops
|
5
5
|
using Sequel::CoreRefinements
|
6
6
|
|
@@ -22,6 +22,28 @@ describe Sequel::Model, "hook_class_methods plugin" do
|
|
22
22
|
hooks.values.all?(&:frozen?).must_equal true
|
23
23
|
end
|
24
24
|
|
25
|
+
deprecated ".hook_blocks method should yield each hook block" do
|
26
|
+
c = model_class.call Sequel::Model
|
27
|
+
a = []
|
28
|
+
c.hook_blocks(:before_save){|b| a << b}
|
29
|
+
a.must_equal []
|
30
|
+
|
31
|
+
pr = proc{adds << 'hi'}
|
32
|
+
c.before_save(&pr)
|
33
|
+
a = []
|
34
|
+
c.hook_blocks(:before_save){|b| a << b}
|
35
|
+
a.must_equal [pr]
|
36
|
+
|
37
|
+
c.before_save(&pr)
|
38
|
+
a = []
|
39
|
+
c.hook_blocks(:before_save){|b| a << b}
|
40
|
+
a.must_equal [pr, pr]
|
41
|
+
|
42
|
+
a = []
|
43
|
+
c.hook_blocks(:after_save){|b| a << b}
|
44
|
+
a.must_equal []
|
45
|
+
end
|
46
|
+
|
25
47
|
it "should be definable using a block" do
|
26
48
|
adds = []
|
27
49
|
c = model_class.call Sequel::Model do
|
@@ -195,6 +195,19 @@ describe "Reversible Migrations with Sequel.migration{change{}}" do
|
|
195
195
|
[:drop_table, :a, {:foo=>:bar}]]
|
196
196
|
end
|
197
197
|
|
198
|
+
it "should reverse add_foreign_key with :type option" do
|
199
|
+
Sequel.migration{change{alter_table(:t){add_foreign_key :b, :c, :type=>:f}}}.apply(@db, :down)
|
200
|
+
actions = @db.actions
|
201
|
+
actions.must_equal [[:alter_table, [[:drop_foreign_key, :b, {:type=>:f}]]]]
|
202
|
+
@db.sqls
|
203
|
+
db = Sequel.mock
|
204
|
+
args = nil
|
205
|
+
db.define_singleton_method(:foreign_key_list){|*a| args = a; [{:name=>:fbc, :columns=>[:b]}]}
|
206
|
+
db.alter_table(:t){send(*actions[0][1][0])}
|
207
|
+
db.sqls.must_equal ["ALTER TABLE t DROP CONSTRAINT fbc", "ALTER TABLE t DROP COLUMN b"]
|
208
|
+
args.must_equal [:t]
|
209
|
+
end
|
210
|
+
|
198
211
|
it "should reverse add_foreign_key with :foreign_key_constraint_name option" do
|
199
212
|
Sequel.migration{change{alter_table(:t){add_foreign_key :b, :c, :foreign_key_constraint_name=>:f}}}.apply(@db, :down)
|
200
213
|
actions = @db.actions
|
@@ -161,4 +161,12 @@ describe "pg_auto_constraint_validations plugin" do
|
|
161
161
|
proc{o.save}.must_raise Sequel::ValidationFailed
|
162
162
|
o.errors.must_equal(:i=>['is invalid'], :id=>['is invalid'])
|
163
163
|
end
|
164
|
+
|
165
|
+
it "should handle overridden constraint failures as validation errors when updating" do
|
166
|
+
o = @c.load(:i=>3)
|
167
|
+
@c.pg_auto_constraint_validation_override(:items_i_ocheck, :i, "foo bar")
|
168
|
+
@set_error[Sequel::CheckConstraintViolation, :constraint=>'items_i_ocheck']
|
169
|
+
proc{o.update(:i=>12)}.must_raise Sequel::ValidationFailed
|
170
|
+
o.errors.must_equal(:i=>['foo bar'])
|
171
|
+
end
|
164
172
|
end
|
data/spec/extensions/s_spec.rb
CHANGED
@@ -29,7 +29,7 @@ describe "s extension as refinement" do
|
|
29
29
|
end
|
30
30
|
|
31
31
|
|
32
|
-
if (RUBY_VERSION >= '2.0.0' && RUBY_ENGINE == 'ruby')
|
32
|
+
if (RUBY_VERSION >= '2.0.0' && RUBY_ENGINE == 'ruby') || (RUBY_ENGINE == 'jruby' && (JRUBY_VERSION >= '9.3' || (JRUBY_VERSION.match(/\A9\.2\.(\d+)/) && $1.to_i >= 7)))
|
33
33
|
using Sequel::S
|
34
34
|
|
35
35
|
describe "s extension as refinement" do
|
@@ -800,14 +800,16 @@ END_MIG
|
|
800
800
|
it "should convert mysql types to ruby types" do
|
801
801
|
def @d.schema(t, *o)
|
802
802
|
i = 0
|
803
|
-
['double(15,2)', 'double(7,1) unsigned'].map{|x| [:"c#{i+=1}", {:db_type=>x, :allow_null=>true}]}
|
803
|
+
['float unsigned', 'double(15,2)', 'double(7,1) unsigned'].map{|x| [:"c#{i+=1}", {:db_type=>x, :allow_null=>true}]}
|
804
804
|
end
|
805
805
|
@d.dump_table_schema(:x).must_equal((<<END_MIG).chomp)
|
806
806
|
create_table(:x) do
|
807
807
|
Float :c1
|
808
808
|
Float :c2
|
809
|
+
Float :c3
|
809
810
|
|
810
|
-
check Sequel::SQL::BooleanExpression.new(:>=, Sequel::SQL::Identifier.new(:
|
811
|
+
check Sequel::SQL::BooleanExpression.new(:>=, Sequel::SQL::Identifier.new(:c1), 0)
|
812
|
+
check Sequel::SQL::BooleanExpression.new(:>=, Sequel::SQL::Identifier.new(:c3), 0)
|
811
813
|
end
|
812
814
|
END_MIG
|
813
815
|
end
|
@@ -30,6 +30,7 @@ describe "Class Table Inheritance Plugin" do
|
|
30
30
|
end
|
31
31
|
class ::Manager < Employee
|
32
32
|
one_to_many :staff_members, :class=>:Staff
|
33
|
+
one_to_one :first_staff_member, :clone=>:staff_members, :order=>:id
|
33
34
|
end
|
34
35
|
class ::Executive < Manager
|
35
36
|
end
|
@@ -150,6 +151,8 @@ describe "Class Table Inheritance Plugin" do
|
|
150
151
|
m = Staff.first.manager
|
151
152
|
m.must_equal Manager[@i4]
|
152
153
|
m.must_be_kind_of(Executive)
|
154
|
+
Staff.first.update(:manager => Manager[@i3])
|
155
|
+
Staff.first.manager.must_equal Manager[@i3]
|
153
156
|
end
|
154
157
|
|
155
158
|
it "should handle eagerly loading many_to_one relationships" do
|
@@ -164,6 +167,18 @@ describe "Class Table Inheritance Plugin" do
|
|
164
167
|
|
165
168
|
it "should handle one_to_many relationships" do
|
166
169
|
Executive.first(:name=>'Ex').staff_members.must_equal [Staff[@i2]]
|
170
|
+
i6 = @db[:employees].insert(:name=>'S2', :kind=>'Staff')
|
171
|
+
@db[:staff].insert(:id=>i6, :manager_id=>@i4)
|
172
|
+
Executive.first(:name=>'Ex').add_staff_member(i6)
|
173
|
+
Executive.first(:name=>'Ex').staff_members{|ds| ds.order(:id)}.must_equal [Staff[@i2], Staff[i6]]
|
174
|
+
end
|
175
|
+
|
176
|
+
it "should handle one_to_many relationships" do
|
177
|
+
Executive.first(:name=>'Ex').first_staff_member.must_equal Staff[@i2]
|
178
|
+
i6 = @db[:employees].insert(:name=>'S2', :kind=>'Staff')
|
179
|
+
@db[:staff].insert(:id=>i6, :manager_id=>@i4)
|
180
|
+
Executive.first(:name=>'Ex').first_staff_member = Staff[i6]
|
181
|
+
Executive.first(:name=>'Ex').staff_members.must_equal [Staff[i6]]
|
167
182
|
end
|
168
183
|
|
169
184
|
it "should handle eagerly loading one_to_many relationships" do
|
@@ -496,6 +496,56 @@ describe "Database transactions" do
|
|
496
496
|
@db.transaction{@db.transaction(:savepoint=>true){@db.after_rollback{c = 1}}; c.must_be_nil; raise Sequel::Rollback}
|
497
497
|
c.must_equal 1
|
498
498
|
end
|
499
|
+
|
500
|
+
it "should support after_commit inside savepoints with :savepoint_option" do
|
501
|
+
c = nil
|
502
|
+
@db.transaction{@db.transaction(:savepoint=>true){@db.after_commit(:savepoint=>true){c = 1}}; c.must_be_nil}
|
503
|
+
c.must_equal 1
|
504
|
+
|
505
|
+
c = nil
|
506
|
+
@db.transaction{@db.transaction(:savepoint=>true){@db.transaction(:savepoint=>true){@db.after_commit(:savepoint=>true){c = 1}}}; c.must_be_nil}
|
507
|
+
c.must_equal 1
|
508
|
+
|
509
|
+
c = nil
|
510
|
+
@db.transaction{@db.transaction(:savepoint=>true, :rollback=>:always){@db.after_commit(:savepoint=>true){c = 1}}}
|
511
|
+
c.must_be_nil
|
512
|
+
|
513
|
+
@db.transaction(:rollback=>:always){@db.transaction(:savepoint=>true){@db.after_commit(:savepoint=>true){c = 1}}}
|
514
|
+
c.must_be_nil
|
515
|
+
|
516
|
+
@db.transaction(:rollback=>:always){@db.transaction(:savepoint=>true){@db.transaction(:savepoint=>true){@db.after_commit(:savepoint=>true){c = 1}}}}
|
517
|
+
c.must_be_nil
|
518
|
+
end
|
519
|
+
|
520
|
+
it "should support after_rollback inside savepoints with :savepoint_option" do
|
521
|
+
c = nil
|
522
|
+
@db.transaction{@db.transaction(:savepoint=>true, :rollback=>:always){@db.after_rollback(:savepoint=>true){c = 1}; c.must_be_nil}; c.must_equal 1}
|
523
|
+
c.must_equal 1
|
524
|
+
|
525
|
+
c = nil
|
526
|
+
@db.transaction(:rollback=>:always){@db.transaction(:savepoint=>true){@db.after_rollback(:savepoint=>true){c = 1}}; c.must_be_nil}
|
527
|
+
c.must_equal 1
|
528
|
+
|
529
|
+
c = nil
|
530
|
+
@db.transaction(:rollback=>:always){@db.transaction(:savepoint=>true, :rollback=>:always){@db.after_rollback(:savepoint=>true){c = 1}; c.must_be_nil}; c.must_equal 1}
|
531
|
+
c.must_equal 1
|
532
|
+
|
533
|
+
c = nil
|
534
|
+
@db.transaction(:rollback=>:always){@db.transaction(:savepoint=>true){@db.after_rollback(:savepoint=>true){c = 1}}; c.must_be_nil}
|
535
|
+
c.must_equal 1
|
536
|
+
|
537
|
+
c = nil
|
538
|
+
@db.transaction(:rollback=>:always){@db.transaction(:savepoint=>true){@db.transaction(:savepoint=>true){@db.after_rollback(:savepoint=>true){c = 1}}; c.must_be_nil}}
|
539
|
+
c.must_equal 1
|
540
|
+
|
541
|
+
c = nil
|
542
|
+
@db.transaction(:rollback=>:always){@db.transaction(:savepoint=>true){@db.transaction(:savepoint=>true, :rollback=>:always){@db.after_rollback(:savepoint=>true){c = 1}; c.must_be_nil}; c.must_equal 1}}
|
543
|
+
c.must_equal 1
|
544
|
+
|
545
|
+
c = nil
|
546
|
+
@db.transaction{@db.transaction(:savepoint=>true, :rollback=>:always){@db.transaction(:savepoint=>true){@db.after_rollback(:savepoint=>true){c = 1}}; c.must_be_nil}; c.must_equal 1}
|
547
|
+
c.must_equal 1
|
548
|
+
end
|
499
549
|
end
|
500
550
|
|
501
551
|
if DB.supports_prepared_transactions?
|