sequel 4.48.0 → 4.49.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.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +56 -0
  3. data/doc/advanced_associations.rdoc +1 -1
  4. data/doc/opening_databases.rdoc +3 -2
  5. data/doc/release_notes/4.49.0.txt +222 -0
  6. data/lib/sequel/adapters/ibmdb.rb +6 -1
  7. data/lib/sequel/adapters/jdbc.rb +3 -1
  8. data/lib/sequel/adapters/jdbc/h2.rb +10 -1
  9. data/lib/sequel/adapters/jdbc/postgresql.rb +3 -2
  10. data/lib/sequel/adapters/jdbc/sqlserver.rb +9 -2
  11. data/lib/sequel/adapters/mock.rb +3 -0
  12. data/lib/sequel/adapters/mysql2.rb +1 -1
  13. data/lib/sequel/adapters/postgres.rb +2 -1
  14. data/lib/sequel/adapters/shared/mysql.rb +4 -1
  15. data/lib/sequel/adapters/shared/oracle.rb +26 -3
  16. data/lib/sequel/connection_pool.rb +9 -2
  17. data/lib/sequel/connection_pool/sharded_single.rb +1 -1
  18. data/lib/sequel/connection_pool/sharded_threaded.rb +1 -1
  19. data/lib/sequel/connection_pool/single.rb +2 -2
  20. data/lib/sequel/connection_pool/threaded.rb +2 -2
  21. data/lib/sequel/database/connecting.rb +3 -3
  22. data/lib/sequel/database/dataset_defaults.rb +14 -1
  23. data/lib/sequel/dataset.rb +1 -1
  24. data/lib/sequel/dataset/actions.rb +54 -0
  25. data/lib/sequel/dataset/dataset_module.rb +58 -0
  26. data/lib/sequel/dataset/query.rb +3 -3
  27. data/lib/sequel/exceptions.rb +8 -0
  28. data/lib/sequel/extensions/_model_pg_row.rb +5 -2
  29. data/lib/sequel/extensions/current_datetime_timestamp.rb +2 -1
  30. data/lib/sequel/extensions/date_arithmetic.rb +1 -0
  31. data/lib/sequel/extensions/duplicate_columns_handler.rb +2 -2
  32. data/lib/sequel/extensions/migration.rb +5 -2
  33. data/lib/sequel/extensions/null_dataset.rb +1 -0
  34. data/lib/sequel/model/associations.rb +3 -0
  35. data/lib/sequel/model/base.rb +10 -55
  36. data/lib/sequel/model/dataset_module.rb +5 -43
  37. data/lib/sequel/model/errors.rb +2 -1
  38. data/lib/sequel/model/inflections.rb +17 -5
  39. data/lib/sequel/plugins/active_model.rb +2 -2
  40. data/lib/sequel/plugins/class_table_inheritance.rb +1 -0
  41. data/lib/sequel/plugins/composition.rb +2 -2
  42. data/lib/sequel/plugins/dataset_associations.rb +25 -13
  43. data/lib/sequel/plugins/json_serializer.rb +2 -2
  44. data/lib/sequel/plugins/pg_row.rb +4 -2
  45. data/lib/sequel/plugins/serialization.rb +1 -0
  46. data/lib/sequel/plugins/single_table_inheritance.rb +6 -1
  47. data/lib/sequel/plugins/touch.rb +2 -1
  48. data/lib/sequel/plugins/validation_helpers.rb +10 -2
  49. data/lib/sequel/sql.rb +16 -7
  50. data/lib/sequel/version.rb +1 -1
  51. data/spec/adapters/mssql_spec.rb +4 -4
  52. data/spec/adapters/mysql_spec.rb +5 -1
  53. data/spec/adapters/oracle_spec.rb +4 -0
  54. data/spec/bin_spec.rb +7 -1
  55. data/spec/core/connection_pool_spec.rb +28 -14
  56. data/spec/core/database_spec.rb +149 -0
  57. data/spec/core/dataset_spec.rb +173 -0
  58. data/spec/extensions/class_table_inheritance_spec.rb +58 -17
  59. data/spec/extensions/composition_spec.rb +13 -0
  60. data/spec/extensions/dataset_associations_spec.rb +12 -0
  61. data/spec/extensions/many_through_many_spec.rb +4 -4
  62. data/spec/extensions/null_dataset_spec.rb +1 -1
  63. data/spec/extensions/serialization_spec.rb +1 -1
  64. data/spec/extensions/single_table_inheritance_spec.rb +16 -0
  65. data/spec/extensions/validation_helpers_spec.rb +1 -2
  66. data/spec/integration/associations_test.rb +8 -0
  67. data/spec/integration/plugin_test.rb +8 -3
  68. data/spec/model/association_reflection_spec.rb +1 -1
  69. data/spec/model/associations_spec.rb +29 -9
  70. data/spec/model/class_dataset_methods_spec.rb +6 -0
  71. data/spec/model/eager_loading_spec.rb +8 -8
  72. data/spec/model/plugins_spec.rb +34 -0
  73. data/spec/model/record_spec.rb +1 -1
  74. data/spec/spec_config.rb +2 -0
  75. metadata +5 -2
@@ -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
- it "#cti_columns should be a mapping of table names to columns" do
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, :Ceo)
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
- it "#cti_columns should be a mapping of table names to columns" do
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
- o = Ceo.load(:id=>1)
1302
- o.freeze
1303
- proc{o.delete}.must_raise(Sequel::Error)
1304
- @db.sqls.must_equal []
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 :eager_loading_predicate_key option to change the SQL used in the lookup" do
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]], :eager_loading_predicate_key=>(Sequel[:albums_artists][:artist_id] / 3)
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 :eager_loading_predicate_key option to change the SQL used in the lookup" do
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]], :eager_loading_predicate_key=>(Sequel[:albums_artists][:artist_id] / 3)
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))"]