sequel 5.19.0 → 5.20.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 +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?
|