sequel 4.48.0 → 4.49.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +56 -0
- data/doc/advanced_associations.rdoc +1 -1
- data/doc/opening_databases.rdoc +3 -2
- data/doc/release_notes/4.49.0.txt +222 -0
- data/lib/sequel/adapters/ibmdb.rb +6 -1
- data/lib/sequel/adapters/jdbc.rb +3 -1
- data/lib/sequel/adapters/jdbc/h2.rb +10 -1
- data/lib/sequel/adapters/jdbc/postgresql.rb +3 -2
- data/lib/sequel/adapters/jdbc/sqlserver.rb +9 -2
- data/lib/sequel/adapters/mock.rb +3 -0
- data/lib/sequel/adapters/mysql2.rb +1 -1
- data/lib/sequel/adapters/postgres.rb +2 -1
- data/lib/sequel/adapters/shared/mysql.rb +4 -1
- data/lib/sequel/adapters/shared/oracle.rb +26 -3
- data/lib/sequel/connection_pool.rb +9 -2
- data/lib/sequel/connection_pool/sharded_single.rb +1 -1
- data/lib/sequel/connection_pool/sharded_threaded.rb +1 -1
- data/lib/sequel/connection_pool/single.rb +2 -2
- data/lib/sequel/connection_pool/threaded.rb +2 -2
- data/lib/sequel/database/connecting.rb +3 -3
- data/lib/sequel/database/dataset_defaults.rb +14 -1
- data/lib/sequel/dataset.rb +1 -1
- data/lib/sequel/dataset/actions.rb +54 -0
- data/lib/sequel/dataset/dataset_module.rb +58 -0
- data/lib/sequel/dataset/query.rb +3 -3
- data/lib/sequel/exceptions.rb +8 -0
- data/lib/sequel/extensions/_model_pg_row.rb +5 -2
- data/lib/sequel/extensions/current_datetime_timestamp.rb +2 -1
- data/lib/sequel/extensions/date_arithmetic.rb +1 -0
- data/lib/sequel/extensions/duplicate_columns_handler.rb +2 -2
- data/lib/sequel/extensions/migration.rb +5 -2
- data/lib/sequel/extensions/null_dataset.rb +1 -0
- data/lib/sequel/model/associations.rb +3 -0
- data/lib/sequel/model/base.rb +10 -55
- data/lib/sequel/model/dataset_module.rb +5 -43
- data/lib/sequel/model/errors.rb +2 -1
- data/lib/sequel/model/inflections.rb +17 -5
- data/lib/sequel/plugins/active_model.rb +2 -2
- data/lib/sequel/plugins/class_table_inheritance.rb +1 -0
- data/lib/sequel/plugins/composition.rb +2 -2
- data/lib/sequel/plugins/dataset_associations.rb +25 -13
- data/lib/sequel/plugins/json_serializer.rb +2 -2
- data/lib/sequel/plugins/pg_row.rb +4 -2
- data/lib/sequel/plugins/serialization.rb +1 -0
- data/lib/sequel/plugins/single_table_inheritance.rb +6 -1
- data/lib/sequel/plugins/touch.rb +2 -1
- data/lib/sequel/plugins/validation_helpers.rb +10 -2
- data/lib/sequel/sql.rb +16 -7
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/mssql_spec.rb +4 -4
- data/spec/adapters/mysql_spec.rb +5 -1
- data/spec/adapters/oracle_spec.rb +4 -0
- data/spec/bin_spec.rb +7 -1
- data/spec/core/connection_pool_spec.rb +28 -14
- data/spec/core/database_spec.rb +149 -0
- data/spec/core/dataset_spec.rb +173 -0
- data/spec/extensions/class_table_inheritance_spec.rb +58 -17
- data/spec/extensions/composition_spec.rb +13 -0
- data/spec/extensions/dataset_associations_spec.rb +12 -0
- data/spec/extensions/many_through_many_spec.rb +4 -4
- data/spec/extensions/null_dataset_spec.rb +1 -1
- data/spec/extensions/serialization_spec.rb +1 -1
- data/spec/extensions/single_table_inheritance_spec.rb +16 -0
- data/spec/extensions/validation_helpers_spec.rb +1 -2
- data/spec/integration/associations_test.rb +8 -0
- data/spec/integration/plugin_test.rb +8 -3
- data/spec/model/association_reflection_spec.rb +1 -1
- data/spec/model/associations_spec.rb +29 -9
- data/spec/model/class_dataset_methods_spec.rb +6 -0
- data/spec/model/eager_loading_spec.rb +8 -8
- data/spec/model/plugins_spec.rb +34 -0
- data/spec/model/record_spec.rb +1 -1
- data/spec/spec_config.rb +2 -0
- metadata +5 -2
data/spec/core/dataset_spec.rb
CHANGED
@@ -1895,6 +1895,126 @@ describe "Dataset#with_extend" do
|
|
1895
1895
|
end
|
1896
1896
|
end
|
1897
1897
|
|
1898
|
+
describe "Dataset#with_extend custom methods" do
|
1899
|
+
before do
|
1900
|
+
@ds = Sequel.mock[:items]
|
1901
|
+
end
|
1902
|
+
|
1903
|
+
it "should have dataset_module support a where method" do
|
1904
|
+
@ds = @ds.with_extend{where :released, :released}
|
1905
|
+
@ds.released.sql.must_equal 'SELECT * FROM items WHERE released'
|
1906
|
+
@ds.where(:foo).released.sql.must_equal 'SELECT * FROM items WHERE (foo AND released)'
|
1907
|
+
end
|
1908
|
+
|
1909
|
+
it "should have dataset_module support a having method" do
|
1910
|
+
@ds = @ds.with_extend{having(:released){released}}
|
1911
|
+
@ds.released.sql.must_equal 'SELECT * FROM items HAVING released'
|
1912
|
+
@ds.where(:foo).released.sql.must_equal 'SELECT * FROM items WHERE foo HAVING released'
|
1913
|
+
end
|
1914
|
+
|
1915
|
+
it "should have dataset_module support an exclude method" do
|
1916
|
+
@ds = @ds.with_extend{exclude :released, :released}
|
1917
|
+
@ds.released.sql.must_equal 'SELECT * FROM items WHERE NOT released'
|
1918
|
+
@ds.where(:foo).released.sql.must_equal 'SELECT * FROM items WHERE (foo AND NOT released)'
|
1919
|
+
end
|
1920
|
+
|
1921
|
+
it "should have dataset_module support an exclude_having method" do
|
1922
|
+
@ds = @ds.with_extend{exclude_having :released, :released}
|
1923
|
+
@ds.released.sql.must_equal 'SELECT * FROM items HAVING NOT released'
|
1924
|
+
@ds.where(:foo).released.sql.must_equal 'SELECT * FROM items WHERE foo HAVING NOT released'
|
1925
|
+
end
|
1926
|
+
|
1927
|
+
it "should have dataset_module support a distinct method" do
|
1928
|
+
@ds = @ds.with_extend{def supports_distinct_on?; true end; distinct :foo, :baz}
|
1929
|
+
@ds.foo.sql.must_equal 'SELECT DISTINCT ON (baz) * FROM items'
|
1930
|
+
@ds.where(:bar).foo.sql.must_equal 'SELECT DISTINCT ON (baz) * FROM items WHERE bar'
|
1931
|
+
end
|
1932
|
+
|
1933
|
+
it "should have dataset_module support a grep method" do
|
1934
|
+
@ds = @ds.with_extend{grep :foo, :baz, 'quux%'}
|
1935
|
+
@ds.foo.sql.must_equal 'SELECT * FROM items WHERE ((baz LIKE \'quux%\' ESCAPE \'\\\'))'
|
1936
|
+
@ds.where(:bar).foo.sql.must_equal 'SELECT * FROM items WHERE (bar AND ((baz LIKE \'quux%\' ESCAPE \'\\\')))'
|
1937
|
+
end
|
1938
|
+
|
1939
|
+
it "should have dataset_module support a group method" do
|
1940
|
+
@ds = @ds.with_extend{group :foo, :baz}
|
1941
|
+
@ds.foo.sql.must_equal 'SELECT * FROM items GROUP BY baz'
|
1942
|
+
@ds.where(:bar).foo.sql.must_equal 'SELECT * FROM items WHERE bar GROUP BY baz'
|
1943
|
+
end
|
1944
|
+
|
1945
|
+
it "should have dataset_module support a group_and_count method" do
|
1946
|
+
@ds = @ds.with_extend{group_and_count :foo, :baz}
|
1947
|
+
@ds.foo.sql.must_equal 'SELECT baz, count(*) AS count FROM items GROUP BY baz'
|
1948
|
+
@ds.where(:bar).foo.sql.must_equal 'SELECT baz, count(*) AS count FROM items WHERE bar GROUP BY baz'
|
1949
|
+
end
|
1950
|
+
|
1951
|
+
it "should have dataset_module support a group_append method" do
|
1952
|
+
@ds = @ds.with_extend{group_append :foo, :baz}
|
1953
|
+
@ds.foo.sql.must_equal 'SELECT * FROM items GROUP BY baz'
|
1954
|
+
@ds.group(:bar).foo.sql.must_equal 'SELECT * FROM items GROUP BY bar, baz'
|
1955
|
+
end
|
1956
|
+
|
1957
|
+
it "should have dataset_module support a limit method" do
|
1958
|
+
@ds = @ds.with_extend{limit :foo, 1}
|
1959
|
+
@ds.foo.sql.must_equal 'SELECT * FROM items LIMIT 1'
|
1960
|
+
@ds.where(:bar).foo.sql.must_equal 'SELECT * FROM items WHERE bar LIMIT 1'
|
1961
|
+
end
|
1962
|
+
|
1963
|
+
it "should have dataset_module support a offset method" do
|
1964
|
+
@ds = @ds.with_extend{offset :foo, 1}
|
1965
|
+
@ds.foo.sql.must_equal 'SELECT * FROM items OFFSET 1'
|
1966
|
+
@ds.where(:bar).foo.sql.must_equal 'SELECT * FROM items WHERE bar OFFSET 1'
|
1967
|
+
end
|
1968
|
+
|
1969
|
+
it "should have dataset_module support a order method" do
|
1970
|
+
@ds = @ds.with_extend{order(:foo){:baz}}
|
1971
|
+
@ds.foo.sql.must_equal 'SELECT * FROM items ORDER BY baz'
|
1972
|
+
@ds.where(:bar).foo.sql.must_equal 'SELECT * FROM items WHERE bar ORDER BY baz'
|
1973
|
+
end
|
1974
|
+
|
1975
|
+
it "should have dataset_module support a order_append method" do
|
1976
|
+
@ds = @ds.with_extend{order_append :foo, :baz}
|
1977
|
+
@ds.foo.sql.must_equal 'SELECT * FROM items ORDER BY baz'
|
1978
|
+
@ds.order(:bar).foo.sql.must_equal 'SELECT * FROM items ORDER BY bar, baz'
|
1979
|
+
end
|
1980
|
+
|
1981
|
+
it "should have dataset_module support a order_prepend method" do
|
1982
|
+
@ds = @ds.with_extend{order_prepend :foo, :baz}
|
1983
|
+
@ds.foo.sql.must_equal 'SELECT * FROM items ORDER BY baz'
|
1984
|
+
@ds.order(:bar).foo.sql.must_equal 'SELECT * FROM items ORDER BY baz, bar'
|
1985
|
+
end
|
1986
|
+
|
1987
|
+
it "should have dataset_module support a select method" do
|
1988
|
+
@ds = @ds.with_extend{select :foo, :baz}
|
1989
|
+
@ds.foo.sql.must_equal 'SELECT baz FROM items'
|
1990
|
+
@ds.where(:bar).foo.sql.must_equal 'SELECT baz FROM items WHERE bar'
|
1991
|
+
end
|
1992
|
+
|
1993
|
+
it "should have dataset_module support a select_all method" do
|
1994
|
+
@ds = @ds.with_extend{select_all :foo, :baz}
|
1995
|
+
@ds.foo.sql.must_equal 'SELECT baz.* FROM items'
|
1996
|
+
@ds.where(:bar).foo.sql.must_equal 'SELECT baz.* FROM items WHERE bar'
|
1997
|
+
end
|
1998
|
+
|
1999
|
+
it "should have dataset_module support a select_append method" do
|
2000
|
+
@ds = @ds.with_extend{select_append :foo, :baz}
|
2001
|
+
@ds.foo.sql.must_equal 'SELECT *, baz FROM items'
|
2002
|
+
@ds.where(:bar).foo.sql.must_equal 'SELECT *, baz FROM items WHERE bar'
|
2003
|
+
end
|
2004
|
+
|
2005
|
+
it "should have dataset_module support a select_group method" do
|
2006
|
+
@ds = @ds.with_extend{select_group :foo, :baz}
|
2007
|
+
@ds.foo.sql.must_equal 'SELECT baz FROM items GROUP BY baz'
|
2008
|
+
@ds.where(:bar).foo.sql.must_equal 'SELECT baz FROM items WHERE bar GROUP BY baz'
|
2009
|
+
end
|
2010
|
+
|
2011
|
+
it "should have dataset_module support a server method" do
|
2012
|
+
@ds = @ds.with_extend{server :foo, :baz}
|
2013
|
+
@ds.foo.opts[:server].must_equal :baz
|
2014
|
+
@ds.where(:bar).foo.opts[:server].must_equal :baz
|
2015
|
+
end
|
2016
|
+
end
|
2017
|
+
|
1898
2018
|
describe "Dataset#with_row_proc" do
|
1899
2019
|
it "should returned clone dataset with the given row_proc" do
|
1900
2020
|
d = Sequel.mock.dataset
|
@@ -5533,3 +5653,56 @@ describe "Dataset#output_identifier" do
|
|
5533
5653
|
meth.call('A').must_equal :a
|
5534
5654
|
end
|
5535
5655
|
end
|
5656
|
+
|
5657
|
+
describe "Dataset#where_all" do
|
5658
|
+
before do
|
5659
|
+
@ds = Sequel.mock(:fetch=>{:id=>1})[:items].freeze
|
5660
|
+
end
|
5661
|
+
|
5662
|
+
it "should filter dataset with condition, and return related rows" do
|
5663
|
+
5.times do
|
5664
|
+
@ds.where_all(:id=>1).must_equal [{:id=>1}]
|
5665
|
+
@ds.db.sqls.must_equal ['SELECT * FROM items WHERE (id = 1)']
|
5666
|
+
end
|
5667
|
+
end
|
5668
|
+
|
5669
|
+
it "should yield each row to the given block" do
|
5670
|
+
5.times do
|
5671
|
+
a = []
|
5672
|
+
@ds.where_all(:id=>1){|r| a << r}.must_equal [{:id=>1}]
|
5673
|
+
a.must_equal [{:id=>1}]
|
5674
|
+
@ds.db.sqls.must_equal ['SELECT * FROM items WHERE (id = 1)']
|
5675
|
+
end
|
5676
|
+
end
|
5677
|
+
end
|
5678
|
+
|
5679
|
+
describe "Dataset#where_each" do
|
5680
|
+
before do
|
5681
|
+
@ds = Sequel.mock(:fetch=>{:id=>1})[:items].freeze
|
5682
|
+
end
|
5683
|
+
|
5684
|
+
it "should yield each row to the given block" do
|
5685
|
+
5.times do
|
5686
|
+
a = []
|
5687
|
+
@ds.where_each(:id=>1){|r| a << r}
|
5688
|
+
a.must_equal [{:id=>1}]
|
5689
|
+
@ds.db.sqls.must_equal ['SELECT * FROM items WHERE (id = 1)']
|
5690
|
+
end
|
5691
|
+
end
|
5692
|
+
end
|
5693
|
+
|
5694
|
+
describe "Dataset#where_single_value" do
|
5695
|
+
before do
|
5696
|
+
@ds = Sequel.mock(:fetch=>{:id=>1})[:items].with_extend do
|
5697
|
+
select :only_id, :id
|
5698
|
+
end.freeze
|
5699
|
+
end
|
5700
|
+
|
5701
|
+
it "should return single value" do
|
5702
|
+
5.times do
|
5703
|
+
a = []
|
5704
|
+
@ds.only_id.where_single_value(:id=>1).must_equal 1
|
5705
|
+
@ds.db.sqls.must_equal ['SELECT id FROM items WHERE (id = 1) LIMIT 1']
|
5706
|
+
end
|
5707
|
+
end
|
5708
|
+
end
|
@@ -585,7 +585,7 @@ describe "class_table_inheritance plugin with :alias option" do
|
|
585
585
|
Executive.cti_models.first.must_equal Employee
|
586
586
|
end
|
587
587
|
|
588
|
-
|
588
|
+
deprecated "#cti_columns should be a mapping of table names to columns" do
|
589
589
|
Executive.cti_columns.must_equal(:employees=>[:id, :name, :kind], :managers=>[:id, :num_staff], :executives=>[:id, :num_managers])
|
590
590
|
end
|
591
591
|
|
@@ -1080,15 +1080,13 @@ describe "class_table_inheritance plugin with :alias option" do
|
|
1080
1080
|
class ::Staff < Employee
|
1081
1081
|
many_to_one :manager
|
1082
1082
|
end
|
1083
|
+
class ::Intern < Employee
|
1084
|
+
end
|
1083
1085
|
@ds = Employee.dataset
|
1084
1086
|
@db.sqls
|
1085
1087
|
end
|
1086
1088
|
after do
|
1087
|
-
Object.send(:remove_const,
|
1088
|
-
Object.send(:remove_const, :Executive)
|
1089
|
-
Object.send(:remove_const, :Manager)
|
1090
|
-
Object.send(:remove_const, :Staff)
|
1091
|
-
Object.send(:remove_const, :Employee)
|
1089
|
+
[:Intern, :Ceo, :Executive, :Manager, :Staff, :Employee].each{|s| Object.send(:remove_const, s)}
|
1092
1090
|
end
|
1093
1091
|
|
1094
1092
|
it "should freeze CTI information when freezing model class" do
|
@@ -1119,7 +1117,7 @@ describe "class_table_inheritance plugin with :alias option" do
|
|
1119
1117
|
Executive.cti_models.first.must_equal Employee
|
1120
1118
|
end
|
1121
1119
|
|
1122
|
-
|
1120
|
+
deprecated "#cti_columns should be a mapping of table names to columns" do
|
1123
1121
|
Executive.cti_columns.must_equal(:employees=>[:id, :name, :kind], :managers=>[:id, :num_staff], :executives=>[:id, :num_managers])
|
1124
1122
|
end
|
1125
1123
|
|
@@ -1128,6 +1126,7 @@ describe "class_table_inheritance plugin with :alias option" do
|
|
1128
1126
|
Executive.simple_table.must_be_nil
|
1129
1127
|
Ceo.simple_table.must_be_nil
|
1130
1128
|
Staff.simple_table.must_be_nil
|
1129
|
+
Intern.simple_table.must_be_nil
|
1131
1130
|
end
|
1132
1131
|
|
1133
1132
|
it "should have working row_proc if using set_dataset in subclass to remove columns" do
|
@@ -1142,10 +1141,11 @@ describe "class_table_inheritance plugin with :alias option" do
|
|
1142
1141
|
Executive.dataset.sql.must_equal '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)) AS employees'
|
1143
1142
|
Ceo.dataset.sql.must_equal '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'
|
1144
1143
|
Staff.dataset.sql.must_equal 'SELECT * FROM (SELECT employees.id, employees.name, employees.kind, staff.manager_id FROM employees INNER JOIN staff ON (staff.id = employees.id)) AS employees'
|
1144
|
+
Intern.dataset.sql.must_equal 'SELECT * FROM employees WHERE (employees.kind IN (\'Intern\'))'
|
1145
1145
|
end
|
1146
1146
|
|
1147
1147
|
it "should return rows with the correct class based on the polymorphic_key value" do
|
1148
|
-
@ds.with_fetch([{:kind=>'Employee'}, {:kind=>'Manager'}, {:kind=>'Executive'}, {:kind=>'Ceo'}, {:kind=>'Staff'}]).all.collect{|x| x.class}.must_equal [Employee, Manager, Executive, Ceo, Staff]
|
1148
|
+
@ds.with_fetch([{:kind=>'Employee'}, {:kind=>'Manager'}, {:kind=>'Executive'}, {:kind=>'Ceo'}, {:kind=>'Staff'}, {:kind=>'Intern'}]).all.collect{|x| x.class}.must_equal [Employee, Manager, Executive, Ceo, Staff, Intern]
|
1149
1149
|
end
|
1150
1150
|
|
1151
1151
|
it "should return rows with the correct class based on the polymorphic_key value for subclasses" do
|
@@ -1165,7 +1165,7 @@ describe "class_table_inheritance plugin with :alias option" do
|
|
1165
1165
|
|
1166
1166
|
it "should return rows with the current class if cti_key is nil" do
|
1167
1167
|
Employee.plugin(:class_table_inheritance, :alias=>:employees)
|
1168
|
-
Employee.dataset.with_fetch([{:kind=>'Employee'}, {:kind=>'Manager'}, {:kind=>'Executive'}, {:kind=>'Ceo'}, {:kind=>'Staff'}]).all.map{|x| x.class}.must_equal [Employee, Employee, Employee, Employee, Employee]
|
1168
|
+
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]
|
1169
1169
|
end
|
1170
1170
|
|
1171
1171
|
it "should return rows with the current class if cti_key is nil in subclasses" do
|
@@ -1178,15 +1178,17 @@ describe "class_table_inheritance plugin with :alias option" do
|
|
1178
1178
|
end
|
1179
1179
|
|
1180
1180
|
it "should handle a model map with integer values" do
|
1181
|
-
Employee.plugin(:class_table_inheritance, :key=>:kind, :model_map=>{0=>:Employee, 1=>:Manager, 2=>:Executive, 3=>:Ceo}, :alias=>:employees)
|
1181
|
+
Employee.plugin(:class_table_inheritance, :key=>:kind, :model_map=>{0=>:Employee, 1=>:Manager, 2=>:Executive, 3=>:Ceo, 4=>:Intern}, :alias=>:employees)
|
1182
|
+
Object.send(:remove_const, :Intern)
|
1182
1183
|
Object.send(:remove_const, :Ceo)
|
1183
1184
|
Object.send(:remove_const, :Executive)
|
1184
1185
|
Object.send(:remove_const, :Manager)
|
1186
|
+
class ::Intern < Employee; end
|
1185
1187
|
class ::Manager < Employee; end
|
1186
1188
|
class ::Executive < Manager; end
|
1187
1189
|
class ::Ceo < Executive; end
|
1188
|
-
Employee.dataset = Employee.dataset.with_fetch([{:kind=>nil},{:kind=>0},{:kind=>1}, {:kind=>2}, {:kind=>3}])
|
1189
|
-
Employee.all.collect{|x| x.class}.must_equal [Employee, Employee, Manager, Executive, Ceo]
|
1190
|
+
Employee.dataset = Employee.dataset.with_fetch([{:kind=>nil},{:kind=>0},{:kind=>1}, {:kind=>2}, {:kind=>3}, {:kind=>4}])
|
1191
|
+
Employee.all.collect{|x| x.class}.must_equal [Employee, Employee, Manager, Executive, Ceo, Intern]
|
1190
1192
|
Manager.dataset = Manager.dataset.with_fetch([{:kind=>nil},{:kind=>0},{:kind=>1}, {:kind=>2}, {:kind=>3}])
|
1191
1193
|
Manager.all.collect{|x| x.class}.must_equal [Manager, Employee, Manager, Executive, Ceo]
|
1192
1194
|
end
|
@@ -1204,6 +1206,11 @@ describe "class_table_inheritance plugin with :alias option" do
|
|
1204
1206
|
@db.sqls.must_equal ["INSERT INTO employees (kind) VALUES ('Employee')"]
|
1205
1207
|
end
|
1206
1208
|
|
1209
|
+
it "should sets the model class name for the key when creating new class records for subclass without separate table" do
|
1210
|
+
Intern.create
|
1211
|
+
@db.sqls.must_equal ["INSERT INTO employees (kind) VALUES ('Intern')"]
|
1212
|
+
end
|
1213
|
+
|
1207
1214
|
it "should sets the model class name for the key when creating new subclass records" do
|
1208
1215
|
Ceo.create
|
1209
1216
|
@db.sqls.must_equal ["INSERT INTO employees (kind) VALUES ('Ceo')",
|
@@ -1278,10 +1285,11 @@ describe "class_table_inheritance plugin with :alias option" do
|
|
1278
1285
|
Manager.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string}, :kind=>{:type=>:string}, :num_staff=>{:type=>:integer})
|
1279
1286
|
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})
|
1280
1287
|
Staff.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string}, :kind=>{:type=>:string}, :manager_id=>{:type=>:integer})
|
1288
|
+
Intern.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string}, :kind=>{:type=>:string})
|
1281
1289
|
end
|
1282
1290
|
|
1283
1291
|
it "should use the correct primary key (which should have the same name in all subclasses)" do
|
1284
|
-
[Employee, Manager, Executive, Ceo, Staff].each{|c| c.primary_key.must_equal :id}
|
1292
|
+
[Employee, Manager, Executive, Ceo, Staff, Intern].each{|c| c.primary_key.must_equal :id}
|
1285
1293
|
end
|
1286
1294
|
|
1287
1295
|
it "should have table_name return the table name of the most specific table" do
|
@@ -1290,20 +1298,43 @@ describe "class_table_inheritance plugin with :alias option" do
|
|
1290
1298
|
Executive.table_name.must_equal :employees
|
1291
1299
|
Ceo.table_name.must_equal :employees
|
1292
1300
|
Staff.table_name.must_equal :employees
|
1301
|
+
Intern.table_name.must_equal :employees
|
1293
1302
|
end
|
1294
1303
|
|
1295
1304
|
it "should delete the correct rows from all tables when deleting" do
|
1305
|
+
Employee.load(:id=>1).delete
|
1306
|
+
@db.sqls.must_equal ["DELETE FROM employees WHERE (id = 1)"]
|
1307
|
+
|
1308
|
+
Intern.load(:id=>1).delete
|
1309
|
+
@db.sqls.must_equal ["DELETE FROM employees WHERE (id = 1)"]
|
1310
|
+
|
1296
1311
|
Ceo.load(:id=>1).delete
|
1297
1312
|
@db.sqls.must_equal ["DELETE FROM executives WHERE (id = 1)", "DELETE FROM managers WHERE (id = 1)", "DELETE FROM employees WHERE (id = 1)"]
|
1298
1313
|
end
|
1299
1314
|
|
1300
1315
|
it "should not allow deletion of frozen object" do
|
1301
|
-
|
1302
|
-
|
1303
|
-
|
1304
|
-
|
1316
|
+
[Ceo, Executive, Employee, Manager, Intern].each do |c|
|
1317
|
+
o = c.load(:id=>1)
|
1318
|
+
o.freeze
|
1319
|
+
proc{o.delete}.must_raise(Sequel::Error)
|
1320
|
+
@db.sqls.must_equal []
|
1321
|
+
end
|
1305
1322
|
end
|
1306
1323
|
|
1324
|
+
it "should insert the correct rows into all tables when inserting into parent class" do
|
1325
|
+
Employee.create(:name=>'E')
|
1326
|
+
sqls = @db.sqls
|
1327
|
+
sqls.length.must_equal 1
|
1328
|
+
sqls[0].must_match(/INSERT INTO employees \((name|kind), (name|kind)\) VALUES \('(E|Employee)', '(E|Employee)'\)/)
|
1329
|
+
end
|
1330
|
+
|
1331
|
+
it "should insert the correct rows into all tables when inserting into subclass without separate table" do
|
1332
|
+
Intern.create(:name=>'E')
|
1333
|
+
sqls = @db.sqls
|
1334
|
+
sqls.length.must_equal 1
|
1335
|
+
sqls[0].must_match(/INSERT INTO employees \((name|kind), (name|kind)\) VALUES \('(E|Intern)', '(E|Intern)'\)/)
|
1336
|
+
end
|
1337
|
+
|
1307
1338
|
it "should insert the correct rows into all tables when inserting" do
|
1308
1339
|
Ceo.create(:num_managers=>3, :num_staff=>2, :name=>'E')
|
1309
1340
|
sqls = @db.sqls
|
@@ -1342,6 +1373,16 @@ describe "class_table_inheritance plugin with :alias option" do
|
|
1342
1373
|
sqls[2].must_match(/INSERT INTO executives \((num_managers|id), (num_managers|id)\) VALUES \([23], [23]\)/)
|
1343
1374
|
end
|
1344
1375
|
|
1376
|
+
it "should update the correct rows in all tables when updating parent class" do
|
1377
|
+
Employee.load(:id=>2).update(:name=>'E')
|
1378
|
+
@db.sqls.must_equal ["UPDATE employees SET name = 'E' WHERE (id = 2)"]
|
1379
|
+
end
|
1380
|
+
|
1381
|
+
it "should update the correct rows in all tables when updating subclass without separate table" do
|
1382
|
+
Intern.load(:id=>2).update(:name=>'E')
|
1383
|
+
@db.sqls.must_equal ["UPDATE employees SET name = 'E' WHERE (id = 2)"]
|
1384
|
+
end
|
1385
|
+
|
1345
1386
|
it "should update the correct rows in all tables when updating" do
|
1346
1387
|
Ceo.load(:id=>2).update(:num_managers=>3, :num_staff=>2, :name=>'E')
|
1347
1388
|
@db.sqls.must_equal ["UPDATE employees SET name = 'E' WHERE (id = 2)", "UPDATE managers SET num_staff = 2 WHERE (id = 2)", "UPDATE executives SET num_managers = 3 WHERE (id = 2)"]
|
@@ -44,6 +44,19 @@ describe "Composition plugin" do
|
|
44
44
|
o.valid?.must_equal true
|
45
45
|
end
|
46
46
|
|
47
|
+
it "should have decomposer work with column_conflicts plugin" do
|
48
|
+
@c.plugin :column_conflicts
|
49
|
+
@c.set_column_conflict! :year
|
50
|
+
@c.composition :date, :mapping=>[:year, :month, :day]
|
51
|
+
o = @c.new
|
52
|
+
def o.validate
|
53
|
+
[:year, :month, :day].each{|c| errors.add(c, "not present") unless send(c)}
|
54
|
+
end
|
55
|
+
o.valid?.must_equal false
|
56
|
+
o.date = Date.new(1, 2, 3)
|
57
|
+
o.valid?.must_equal true
|
58
|
+
end
|
59
|
+
|
47
60
|
it "should set column values even when not validating" do
|
48
61
|
@c.composition :date, :mapping=>[:year, :month, :day]
|
49
62
|
@c.load({}).set(:date=>Date.new(4, 8, 12)).save(:validate=>false)
|
@@ -13,14 +13,17 @@ describe "Sequel::Plugins::DatasetAssociations" do
|
|
13
13
|
@Artist = Class.new(@Base)
|
14
14
|
@Album = Class.new(@Base)
|
15
15
|
@Tag = Class.new(@Base)
|
16
|
+
@Track = Class.new(@Base)
|
16
17
|
|
17
18
|
def @Artist.name; 'Artist' end
|
18
19
|
def @Album.name; 'Album' end
|
19
20
|
def @Tag.name; 'Tag' end
|
21
|
+
def @Track.name; 'Track' end
|
20
22
|
|
21
23
|
@Artist.dataset = @db[:artists]
|
22
24
|
@Album.dataset = @db[:albums]
|
23
25
|
@Tag.dataset = @db[:tags]
|
26
|
+
@Track.dataset = @db[:tracks]
|
24
27
|
|
25
28
|
@Artist.columns :id, :name
|
26
29
|
@Album.columns :id, :name, :artist_id
|
@@ -28,6 +31,7 @@ describe "Sequel::Plugins::DatasetAssociations" do
|
|
28
31
|
|
29
32
|
@Album.plugin :many_through_many
|
30
33
|
@Artist.plugin :many_through_many
|
34
|
+
@Track.plugin :many_through_many
|
31
35
|
@Artist.plugin :pg_array_associations
|
32
36
|
@Tag.plugin :pg_array_associations
|
33
37
|
@Artist.one_to_many :albums, :class=>@Album
|
@@ -41,6 +45,7 @@ describe "Sequel::Plugins::DatasetAssociations" do
|
|
41
45
|
@Tag.many_to_pg_array :artists, :class=>@Artist
|
42
46
|
@Artist.many_through_many :tags, [[:albums, :artist_id, :id], [:albums_tags, :album_id, :tag_id]], :class=>@Tag
|
43
47
|
@Artist.one_through_many :otag, [[:albums, :artist_id, :id], [:albums_tags, :album_id, :tag_id]], :class=>@Tag
|
48
|
+
@Track.many_through_many :artist_tracks, [[:albums, :id, :artist_id], [:albums, :artist_id, :id]], :class=>@Track, :left_primary_key=>:album_id, :right_primary_key=>:album_id
|
44
49
|
end
|
45
50
|
|
46
51
|
it "should work for many_to_one associations" do
|
@@ -85,6 +90,13 @@ describe "Sequel::Plugins::DatasetAssociations" do
|
|
85
90
|
ds.sql.must_equal "SELECT tags.* FROM tags WHERE (tags.id IN (SELECT albums_tags.tag_id FROM artists INNER JOIN albums ON (albums.artist_id = artists.id) INNER JOIN albums_tags ON (albums_tags.album_id = albums.id) INNER JOIN tags ON (tags.id = albums_tags.tag_id) WHERE (albums.artist_id IN (SELECT artists.id FROM artists))))"
|
86
91
|
end
|
87
92
|
|
93
|
+
it "should work for self referential many_through_many associations" do
|
94
|
+
ds = @Track.artist_tracks
|
95
|
+
ds.must_be_kind_of(Sequel::Dataset)
|
96
|
+
ds.model.must_equal @Track
|
97
|
+
ds.sql.must_equal "SELECT tracks.* FROM tracks WHERE (tracks.album_id IN (SELECT albums_0.id FROM tracks INNER JOIN albums ON (albums.id = tracks.album_id) INNER JOIN albums AS albums_0 ON (albums_0.artist_id = albums.artist_id) INNER JOIN tracks AS tracks_0 ON (tracks_0.album_id = albums_0.id) WHERE (albums.id IN (SELECT tracks.album_id FROM tracks))))"
|
98
|
+
end
|
99
|
+
|
88
100
|
it "should work for many_through_many associations with a single join table" do
|
89
101
|
ds = @Album.mthm_tags
|
90
102
|
ds.must_be_kind_of(Sequel::Dataset)
|
@@ -59,10 +59,10 @@ describe Sequel::Model, "many_through_many" do
|
|
59
59
|
DB.sqls.must_equal []
|
60
60
|
end
|
61
61
|
|
62
|
-
it "should handle a :
|
62
|
+
it "should handle a :predicate_key option to change the SQL used in the lookup" do
|
63
63
|
@c1.dataset = @c1.dataset.with_fetch(:id=>1)
|
64
64
|
@c2.dataset = @c2.dataset.with_fetch(:id=>4, :x_foreign_key_x=>1)
|
65
|
-
@c1.many_through_many :tags, :through=>[[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :
|
65
|
+
@c1.many_through_many :tags, :through=>[[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :predicate_key=>(Sequel[:albums_artists][:artist_id] / 3)
|
66
66
|
a = @c1.eager(:tags).all
|
67
67
|
a.must_equal [@c1.load(:id => 1)]
|
68
68
|
DB.sqls.must_equal ['SELECT * FROM artists', "SELECT tags.*, (albums_artists.artist_id / 3) AS x_foreign_key_x FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) INNER JOIN albums_artists ON (albums_artists.album_id = albums.id) WHERE ((albums_artists.artist_id / 3) IN (1))"]
|
@@ -1231,10 +1231,10 @@ describe Sequel::Model, "one_through_many" do
|
|
1231
1231
|
DB.sqls.must_equal []
|
1232
1232
|
end
|
1233
1233
|
|
1234
|
-
it "should handle a :
|
1234
|
+
it "should handle a :predicate_key option to change the SQL used in the lookup" do
|
1235
1235
|
@c1.dataset = @c1.dataset.with_fetch(:id=>1)
|
1236
1236
|
@c2.dataset = @c2.dataset.with_fetch(:id=>4, :x_foreign_key_x=>1)
|
1237
|
-
@c1.one_through_many :tag, :through=>[[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :
|
1237
|
+
@c1.one_through_many :tag, :through=>[[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :predicate_key=>(Sequel[:albums_artists][:artist_id] / 3)
|
1238
1238
|
a = @c1.eager(:tag).all
|
1239
1239
|
a.must_equal [@c1.load(:id => 1)]
|
1240
1240
|
DB.sqls.must_equal ['SELECT * FROM artists', "SELECT tags.*, (albums_artists.artist_id / 3) AS x_foreign_key_x FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) INNER JOIN albums_artists ON (albums_artists.album_id = albums.id) WHERE ((albums_artists.artist_id / 3) IN (1))"]
|