sequel 3.21.0 → 3.24.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 (104) hide show
  1. data/CHANGELOG +112 -0
  2. data/README.rdoc +15 -1
  3. data/doc/association_basics.rdoc +159 -40
  4. data/doc/model_hooks.rdoc +64 -27
  5. data/doc/prepared_statements.rdoc +8 -4
  6. data/doc/reflection.rdoc +8 -2
  7. data/doc/release_notes/3.22.0.txt +39 -0
  8. data/doc/release_notes/3.23.0.txt +172 -0
  9. data/doc/release_notes/3.24.0.txt +420 -0
  10. data/doc/virtual_rows.rdoc +2 -2
  11. data/lib/sequel/adapters/ado.rb +2 -1
  12. data/lib/sequel/adapters/db2.rb +8 -1
  13. data/lib/sequel/adapters/firebird.rb +25 -9
  14. data/lib/sequel/adapters/informix.rb +4 -19
  15. data/lib/sequel/adapters/jdbc/h2.rb +5 -0
  16. data/lib/sequel/adapters/jdbc/informix.rb +31 -0
  17. data/lib/sequel/adapters/jdbc/jtds.rb +34 -0
  18. data/lib/sequel/adapters/jdbc/mssql.rb +0 -32
  19. data/lib/sequel/adapters/jdbc/mysql.rb +9 -0
  20. data/lib/sequel/adapters/jdbc/sqlserver.rb +46 -0
  21. data/lib/sequel/adapters/jdbc.rb +39 -20
  22. data/lib/sequel/adapters/odbc.rb +2 -0
  23. data/lib/sequel/adapters/oracle.rb +12 -0
  24. data/lib/sequel/adapters/postgres.rb +30 -1
  25. data/lib/sequel/adapters/shared/access.rb +10 -0
  26. data/lib/sequel/adapters/shared/informix.rb +45 -0
  27. data/lib/sequel/adapters/shared/mssql.rb +106 -11
  28. data/lib/sequel/adapters/shared/mysql.rb +25 -7
  29. data/lib/sequel/adapters/shared/postgres.rb +39 -6
  30. data/lib/sequel/adapters/shared/sqlite.rb +57 -5
  31. data/lib/sequel/adapters/sqlite.rb +8 -3
  32. data/lib/sequel/adapters/swift/mysql.rb +9 -0
  33. data/lib/sequel/adapters/tinytds.rb +4 -3
  34. data/lib/sequel/ast_transformer.rb +190 -0
  35. data/lib/sequel/core.rb +1 -1
  36. data/lib/sequel/database/connecting.rb +1 -1
  37. data/lib/sequel/database/misc.rb +6 -0
  38. data/lib/sequel/database/query.rb +33 -3
  39. data/lib/sequel/database/schema_methods.rb +13 -4
  40. data/lib/sequel/dataset/features.rb +6 -0
  41. data/lib/sequel/dataset/prepared_statements.rb +17 -2
  42. data/lib/sequel/dataset/query.rb +17 -0
  43. data/lib/sequel/dataset/sql.rb +2 -53
  44. data/lib/sequel/exceptions.rb +4 -0
  45. data/lib/sequel/extensions/columns_introspection.rb +61 -0
  46. data/lib/sequel/extensions/migration.rb +4 -3
  47. data/lib/sequel/extensions/to_dot.rb +95 -83
  48. data/lib/sequel/model/associations.rb +234 -32
  49. data/lib/sequel/model/base.rb +187 -60
  50. data/lib/sequel/model/exceptions.rb +3 -1
  51. data/lib/sequel/model.rb +5 -0
  52. data/lib/sequel/plugins/association_pks.rb +6 -4
  53. data/lib/sequel/plugins/defaults_setter.rb +58 -0
  54. data/lib/sequel/plugins/identity_map.rb +2 -2
  55. data/lib/sequel/plugins/many_through_many.rb +33 -3
  56. data/lib/sequel/plugins/prepared_statements.rb +140 -0
  57. data/lib/sequel/plugins/prepared_statements_associations.rb +84 -0
  58. data/lib/sequel/plugins/prepared_statements_safe.rb +72 -0
  59. data/lib/sequel/plugins/prepared_statements_with_pk.rb +59 -0
  60. data/lib/sequel/plugins/serialization_modification_detection.rb +51 -0
  61. data/lib/sequel/plugins/single_table_inheritance.rb +2 -0
  62. data/lib/sequel/plugins/xml_serializer.rb +1 -1
  63. data/lib/sequel/sql.rb +8 -0
  64. data/lib/sequel/version.rb +1 -1
  65. data/spec/adapters/mssql_spec.rb +36 -0
  66. data/spec/adapters/mysql_spec.rb +6 -0
  67. data/spec/adapters/postgres_spec.rb +43 -18
  68. data/spec/adapters/spec_helper.rb +5 -0
  69. data/spec/core/connection_pool_spec.rb +56 -77
  70. data/spec/core/database_spec.rb +33 -0
  71. data/spec/core/dataset_spec.rb +127 -16
  72. data/spec/core/expression_filters_spec.rb +13 -0
  73. data/spec/core/schema_spec.rb +13 -1
  74. data/spec/core/spec_helper.rb +5 -0
  75. data/spec/extensions/association_pks_spec.rb +7 -0
  76. data/spec/extensions/columns_introspection_spec.rb +91 -0
  77. data/spec/extensions/defaults_setter_spec.rb +64 -0
  78. data/spec/extensions/many_through_many_spec.rb +77 -0
  79. data/spec/extensions/migration_spec.rb +17 -17
  80. data/spec/extensions/nested_attributes_spec.rb +1 -0
  81. data/spec/extensions/prepared_statements_associations_spec.rb +126 -0
  82. data/spec/extensions/prepared_statements_safe_spec.rb +69 -0
  83. data/spec/extensions/prepared_statements_spec.rb +72 -0
  84. data/spec/extensions/prepared_statements_with_pk_spec.rb +38 -0
  85. data/spec/extensions/serialization_modification_detection_spec.rb +36 -0
  86. data/spec/extensions/single_table_inheritance_spec.rb +11 -0
  87. data/spec/extensions/spec_helper.rb +3 -1
  88. data/spec/extensions/to_dot_spec.rb +3 -5
  89. data/spec/extensions/xml_serializer_spec.rb +12 -0
  90. data/spec/integration/associations_test.rb +212 -0
  91. data/spec/integration/dataset_test.rb +8 -1
  92. data/spec/integration/plugin_test.rb +134 -0
  93. data/spec/integration/prepared_statement_test.rb +72 -1
  94. data/spec/integration/schema_test.rb +66 -8
  95. data/spec/integration/spec_helper.rb +5 -0
  96. data/spec/integration/transaction_test.rb +40 -0
  97. data/spec/integration/type_test.rb +7 -0
  98. data/spec/model/associations_spec.rb +463 -5
  99. data/spec/model/base_spec.rb +59 -0
  100. data/spec/model/eager_loading_spec.rb +269 -1
  101. data/spec/model/hooks_spec.rb +161 -0
  102. data/spec/model/record_spec.rb +30 -0
  103. data/spec/model/spec_helper.rb +5 -0
  104. metadata +29 -4
@@ -357,6 +357,28 @@ describe Sequel::Model, "many_to_one" do
357
357
  MODEL_DB.sqls.should == ["SELECT * FROM nodes WHERE (nodes.id = 234) LIMIT 1"]
358
358
  end
359
359
 
360
+ it "should use a callback if given one as the argument" do
361
+ @c2.many_to_one :parent, :class => @c2
362
+
363
+ d = @c2.create(:id => 1)
364
+ MODEL_DB.reset
365
+ d.parent_id = 234
366
+ d.associations[:parent] = 42
367
+ d.parent(proc{|ds| ds.filter{name > 'M'}}).should_not == 42
368
+ MODEL_DB.sqls.should == ["SELECT * FROM nodes WHERE ((nodes.id = 234) AND (name > 'M')) LIMIT 1"]
369
+ end
370
+
371
+ it "should use a block given to the association method as a callback on ruby 1.8.7+" do
372
+ @c2.many_to_one :parent, :class => @c2
373
+
374
+ d = @c2.create(:id => 1)
375
+ MODEL_DB.reset
376
+ d.parent_id = 234
377
+ d.associations[:parent] = 42
378
+ d.parent{|ds| ds.filter{name > 'M'}}.should_not == 42
379
+ MODEL_DB.sqls.should == ["SELECT * FROM nodes WHERE ((nodes.id = 234) AND (name > 'M')) LIMIT 1"]
380
+ end if RUBY_VERSION >= '1.8.7'
381
+
360
382
  it "should have the setter add to the reciprocal one_to_many cached association list if it exists" do
361
383
  @c2.many_to_one :parent, :class => @c2
362
384
  @c2.one_to_many :children, :class => @c2, :key=>:parent_id
@@ -1149,6 +1171,16 @@ describe Sequel::Model, "one_to_many" do
1149
1171
  v.model.should == Historical::Value
1150
1172
  end
1151
1173
 
1174
+ it "should use a callback if given one as the argument" do
1175
+ @c2.one_to_many :attributes, :class => @c1, :key => :nodeid
1176
+
1177
+ d = @c2.create(:id => 1234)
1178
+ MODEL_DB.reset
1179
+ d.associations[:attributes] = []
1180
+ d.attributes(proc{|ds| ds.filter{name > 'M'}}).should_not == []
1181
+ MODEL_DB.sqls.should == ["SELECT * FROM attributes WHERE ((attributes.nodeid = 1234) AND (name > 'M'))"]
1182
+ end
1183
+
1152
1184
  it "should use explicit key if given" do
1153
1185
  @c2.one_to_many :attributes, :class => @c1, :key => :nodeid
1154
1186
 
@@ -1338,7 +1370,7 @@ describe Sequel::Model, "one_to_many" do
1338
1370
  @c2.one_to_many :attributes, :class => @c1
1339
1371
  n = @c2.new(:id => 1234)
1340
1372
  a = @c1.new(:id => 2345)
1341
- def a.valid?(opts); false; end
1373
+ def a.validate() errors.add(:id, 'foo') end
1342
1374
  proc{n.add_attribute(a)}.should raise_error(Sequel::Error)
1343
1375
  proc{n.remove_attribute(a)}.should raise_error(Sequel::Error)
1344
1376
  end
@@ -1347,7 +1379,7 @@ describe Sequel::Model, "one_to_many" do
1347
1379
  @c2.one_to_many :attributes, :class => @c1, :validate=>false
1348
1380
  n = @c2.new(:id => 1234)
1349
1381
  a = @c1.new(:id => 2345)
1350
- def a.valid?(opts); false; end
1382
+ def a.validate() errors.add(:id, 'foo') end
1351
1383
  n.add_attribute(a).should == a
1352
1384
  n.remove_attribute(a).should == a
1353
1385
  end
@@ -2250,7 +2282,7 @@ describe Sequel::Model, "many_to_many" do
2250
2282
  @c2.many_to_many :attributes, :class => @c1
2251
2283
  n = @c1.new
2252
2284
  a = @c2.load(:id=>123)
2253
- def n.valid?(opts); false; end
2285
+ def n.validate() errors.add(:id, 'foo') end
2254
2286
  proc{a.add_attribute(n)}.should raise_error(Sequel::ValidationFailed)
2255
2287
  end
2256
2288
 
@@ -2259,7 +2291,7 @@ describe Sequel::Model, "many_to_many" do
2259
2291
  n = @c1.new
2260
2292
  n.raise_on_save_failure = false
2261
2293
  a = @c2.load(:id=>123)
2262
- def n.valid?(opts); false; end
2294
+ def n.validate() errors.add(:id, 'foo') end
2263
2295
  proc{a.add_attribute(n)}.should raise_error(Sequel::Error)
2264
2296
  end
2265
2297
 
@@ -2267,7 +2299,7 @@ describe Sequel::Model, "many_to_many" do
2267
2299
  @c2.many_to_many :attributes, :class => @c1, :validate=>false
2268
2300
  n = @c1.new
2269
2301
  a = @c2.load(:id=>123)
2270
- def n.valid?(opts); false; end
2302
+ def n.validate() errors.add(:id, 'foo') end
2271
2303
  a.add_attribute(n)
2272
2304
  n.new?.should == false
2273
2305
  end
@@ -2724,3 +2756,429 @@ describe Sequel::Model, " association reflection methods" do
2724
2756
  c.instance_methods.map{|x| x.to_s}.should include('parent')
2725
2757
  end
2726
2758
  end
2759
+
2760
+ describe "Filtering by associations" do
2761
+ before do
2762
+ @Album = Class.new(Sequel::Model(:albums))
2763
+ artist = @Artist = Class.new(Sequel::Model(:artists))
2764
+ tag = @Tag = Class.new(Sequel::Model(:tags))
2765
+ track = @Track = Class.new(Sequel::Model(:tracks))
2766
+ album_info = @AlbumInfo = Class.new(Sequel::Model(:album_infos))
2767
+ @Artist.columns :id, :id1, :id2
2768
+ @Tag.columns :id, :tid1, :tid2
2769
+ @Track.columns :id, :album_id, :album_id1, :album_id2
2770
+ @AlbumInfo.columns :id, :album_id, :album_id1, :album_id2
2771
+ @Album.class_eval do
2772
+ columns :id, :id1, :id2, :artist_id, :artist_id1, :artist_id2
2773
+ many_to_one :artist, :class=>artist
2774
+ one_to_many :tracks, :class=>track, :key=>:album_id
2775
+ one_to_one :album_info, :class=>album_info, :key=>:album_id
2776
+ many_to_many :tags, :class=>tag, :left_key=>:album_id, :join_table=>:albums_tags
2777
+
2778
+ many_to_one :cartist, :class=>artist, :key=>[:artist_id1, :artist_id2], :primary_key=>[:id1, :id2]
2779
+ one_to_many :ctracks, :class=>track, :key=>[:album_id1, :album_id2], :primary_key=>[:id1, :id2]
2780
+ one_to_one :calbum_info, :class=>album_info, :key=>[:album_id1, :album_id2], :primary_key=>[:id1, :id2]
2781
+ many_to_many :ctags, :class=>tag, :left_key=>[:album_id1, :album_id2], :left_primary_key=>[:id1, :id2], :right_key=>[:tag_id1, :tag_id2], :right_primary_key=>[:tid1, :tid2], :join_table=>:albums_tags
2782
+ end
2783
+ end
2784
+
2785
+ it "should be able to filter on many_to_one associations" do
2786
+ @Album.filter(:artist=>@Artist.load(:id=>3)).sql.should == 'SELECT * FROM albums WHERE (artist_id = 3)'
2787
+ end
2788
+
2789
+ it "should be able to filter on one_to_many associations" do
2790
+ @Album.filter(:tracks=>@Track.load(:album_id=>3)).sql.should == 'SELECT * FROM albums WHERE (id = 3)'
2791
+ end
2792
+
2793
+ it "should be able to filter on one_to_one associations" do
2794
+ @Album.filter(:album_info=>@AlbumInfo.load(:album_id=>3)).sql.should == 'SELECT * FROM albums WHERE (id = 3)'
2795
+ end
2796
+
2797
+ it "should be able to filter on many_to_many associations" do
2798
+ @Album.filter(:tags=>@Tag.load(:id=>3)).sql.should == 'SELECT * FROM albums WHERE (id IN (SELECT album_id FROM albums_tags WHERE ((tag_id = 3) AND (album_id IS NOT NULL))))'
2799
+ end
2800
+
2801
+ it "should be able to filter on many_to_one associations with composite keys" do
2802
+ @Album.filter(:cartist=>@Artist.load(:id1=>3, :id2=>4)).sql.should == 'SELECT * FROM albums WHERE ((artist_id1 = 3) AND (artist_id2 = 4))'
2803
+ end
2804
+
2805
+ it "should be able to filter on one_to_many associations with composite keys" do
2806
+ @Album.filter(:ctracks=>@Track.load(:album_id1=>3, :album_id2=>4)).sql.should == 'SELECT * FROM albums WHERE ((id1 = 3) AND (id2 = 4))'
2807
+ end
2808
+
2809
+ it "should be able to filter on one_to_one associations with composite keys" do
2810
+ @Album.filter(:calbum_info=>@AlbumInfo.load(:album_id1=>3, :album_id2=>4)).sql.should == 'SELECT * FROM albums WHERE ((id1 = 3) AND (id2 = 4))'
2811
+ end
2812
+
2813
+ it "should be able to filter on many_to_many associations with composite keys" do
2814
+ @Album.filter(:ctags=>@Tag.load(:tid1=>3, :tid2=>4)).sql.should == 'SELECT * FROM albums WHERE ((id1, id2) IN (SELECT album_id1, album_id2 FROM albums_tags WHERE ((tag_id1 = 3) AND (tag_id2 = 4) AND (album_id1 IS NOT NULL) AND (album_id2 IS NOT NULL))))'
2815
+ end
2816
+
2817
+ it "should work inside a complex filter" do
2818
+ artist = @Artist.load(:id=>3)
2819
+ @Album.filter{foo & {:artist=>artist}}.sql.should == 'SELECT * FROM albums WHERE (foo AND (artist_id = 3))'
2820
+ track = @Track.load(:album_id=>4)
2821
+ @Album.filter{foo & [[:artist, artist], [:tracks, track]]}.sql.should == 'SELECT * FROM albums WHERE (foo AND (artist_id = 3) AND (id = 4))'
2822
+ end
2823
+
2824
+ it "should raise for an invalid association name" do
2825
+ proc{@Album.filter(:foo=>@Artist.load(:id=>3)).sql}.should raise_error(Sequel::Error)
2826
+ end
2827
+
2828
+ it "should raise for an invalid association type" do
2829
+ @Album.many_to_many :iatags, :clone=>:tags
2830
+ @Album.association_reflection(:iatags)[:type] = :foo
2831
+ proc{@Album.filter(:iatags=>@Tag.load(:id=>3)).sql}.should raise_error(Sequel::Error)
2832
+ end
2833
+
2834
+ it "should raise for an invalid associated object class " do
2835
+ proc{@Album.filter(:tags=>@Artist.load(:id=>3)).sql}.should raise_error(Sequel::Error)
2836
+ end
2837
+
2838
+ it "should raise for an invalid associated object class when multiple objects are used" do
2839
+ proc{@Album.filter(:tags=>[@Tag.load(:id=>3), @Artist.load(:id=>3)]).sql}.should raise_error(Sequel::Error)
2840
+ end
2841
+
2842
+ it "should correctly handle case when a multiple value association is used" do
2843
+ proc{@Album.filter(:tags=>[@Tag.load(:id=>3), @Artist.load(:id=>3)]).sql}.should raise_error(Sequel::Error)
2844
+ end
2845
+
2846
+ it "should not affect non-association IN/NOT IN filtering with an empty array" do
2847
+ @Album.filter(:tag_id=>[]).sql.should == 'SELECT * FROM albums WHERE (tag_id != tag_id)'
2848
+ @Album.exclude(:tag_id=>[]).sql.should == 'SELECT * FROM albums WHERE (1 = 1)'
2849
+ end
2850
+
2851
+ it "should work correctly in subclasses" do
2852
+ c = Class.new(@Album)
2853
+ c.many_to_one :sartist, :class=>@Artist
2854
+ c.filter(:sartist=>@Artist.load(:id=>3)).sql.should == 'SELECT * FROM albums WHERE (sartist_id = 3)'
2855
+ end
2856
+
2857
+ it "should be able to exclude on many_to_one associations" do
2858
+ @Album.exclude(:artist=>@Artist.load(:id=>3)).sql.should == 'SELECT * FROM albums WHERE ((artist_id != 3) OR (artist_id IS NULL))'
2859
+ end
2860
+
2861
+ it "should be able to exclude on one_to_many associations" do
2862
+ @Album.exclude(:tracks=>@Track.load(:album_id=>3)).sql.should == 'SELECT * FROM albums WHERE ((id != 3) OR (id IS NULL))'
2863
+ end
2864
+
2865
+ it "should be able to exclude on one_to_one associations" do
2866
+ @Album.exclude(:album_info=>@AlbumInfo.load(:album_id=>3)).sql.should == 'SELECT * FROM albums WHERE ((id != 3) OR (id IS NULL))'
2867
+ end
2868
+
2869
+ it "should be able to exclude on many_to_many associations" do
2870
+ @Album.exclude(:tags=>@Tag.load(:id=>3)).sql.should == 'SELECT * FROM albums WHERE ((id NOT IN (SELECT album_id FROM albums_tags WHERE ((tag_id = 3) AND (album_id IS NOT NULL)))) OR (id IS NULL))'
2871
+ end
2872
+
2873
+ it "should be able to exclude on many_to_one associations with composite keys" do
2874
+ @Album.exclude(:cartist=>@Artist.load(:id1=>3, :id2=>4)).sql.should == 'SELECT * FROM albums WHERE ((artist_id1 != 3) OR (artist_id2 != 4) OR (artist_id1 IS NULL) OR (artist_id2 IS NULL))'
2875
+ end
2876
+
2877
+ it "should be able to exclude on one_to_many associations with composite keys" do
2878
+ @Album.exclude(:ctracks=>@Track.load(:album_id1=>3, :album_id2=>4)).sql.should == 'SELECT * FROM albums WHERE ((id1 != 3) OR (id2 != 4) OR (id1 IS NULL) OR (id2 IS NULL))'
2879
+ end
2880
+
2881
+ it "should be able to exclude on one_to_one associations with composite keys" do
2882
+ @Album.exclude(:calbum_info=>@AlbumInfo.load(:album_id1=>3, :album_id2=>4)).sql.should == 'SELECT * FROM albums WHERE ((id1 != 3) OR (id2 != 4) OR (id1 IS NULL) OR (id2 IS NULL))'
2883
+ end
2884
+
2885
+ it "should be able to exclude on many_to_many associations with composite keys" do
2886
+ @Album.exclude(:ctags=>@Tag.load(:tid1=>3, :tid2=>4)).sql.should == 'SELECT * FROM albums WHERE (((id1, id2) NOT IN (SELECT album_id1, album_id2 FROM albums_tags WHERE ((tag_id1 = 3) AND (tag_id2 = 4) AND (album_id1 IS NOT NULL) AND (album_id2 IS NOT NULL)))) OR (id1 IS NULL) OR (id2 IS NULL))'
2887
+ end
2888
+
2889
+ it "should be able to filter on multiple many_to_one associations" do
2890
+ @Album.filter(:artist=>[@Artist.load(:id=>3), @Artist.load(:id=>4)]).sql.should == 'SELECT * FROM albums WHERE (artist_id IN (3, 4))'
2891
+ end
2892
+
2893
+ it "should be able to filter on multiple one_to_many associations" do
2894
+ @Album.filter(:tracks=>[@Track.load(:album_id=>3), @Track.load(:album_id=>4)]).sql.should == 'SELECT * FROM albums WHERE (id IN (3, 4))'
2895
+ end
2896
+
2897
+ it "should be able to filter on multiple one_to_one associations" do
2898
+ @Album.filter(:album_info=>[@AlbumInfo.load(:album_id=>3), @AlbumInfo.load(:album_id=>4)]).sql.should == 'SELECT * FROM albums WHERE (id IN (3, 4))'
2899
+ end
2900
+
2901
+ it "should be able to filter on multiple many_to_many associations" do
2902
+ @Album.filter(:tags=>[@Tag.load(:id=>3), @Tag.load(:id=>4)]).sql.should == 'SELECT * FROM albums WHERE (id IN (SELECT album_id FROM albums_tags WHERE ((tag_id IN (3, 4)) AND (album_id IS NOT NULL))))'
2903
+ end
2904
+
2905
+ it "should be able to filter on multiple many_to_one associations with composite keys" do
2906
+ @Album.filter(:cartist=>[@Artist.load(:id1=>3, :id2=>4), @Artist.load(:id1=>5, :id2=>6)]).sql.should == 'SELECT * FROM albums WHERE ((artist_id1, artist_id2) IN ((3, 4), (5, 6)))'
2907
+ end
2908
+
2909
+ it "should be able to filter on multiple one_to_many associations with composite keys" do
2910
+ @Album.filter(:ctracks=>[@Track.load(:album_id1=>3, :album_id2=>4), @Track.load(:album_id1=>5, :album_id2=>6)]).sql.should == 'SELECT * FROM albums WHERE ((id1, id2) IN ((3, 4), (5, 6)))'
2911
+ end
2912
+
2913
+ it "should be able to filter on multiple one_to_one associations with composite keys" do
2914
+ @Album.filter(:calbum_info=>[@AlbumInfo.load(:album_id1=>3, :album_id2=>4), @AlbumInfo.load(:album_id1=>5, :album_id2=>6)]).sql.should == 'SELECT * FROM albums WHERE ((id1, id2) IN ((3, 4), (5, 6)))'
2915
+ end
2916
+
2917
+ it "should be able to filter on multiple many_to_many associations with composite keys" do
2918
+ @Album.filter(:ctags=>[@Tag.load(:tid1=>3, :tid2=>4), @Tag.load(:tid1=>5, :tid2=>6)]).sql.should == 'SELECT * FROM albums WHERE ((id1, id2) IN (SELECT album_id1, album_id2 FROM albums_tags WHERE (((tag_id1, tag_id2) IN ((3, 4), (5, 6))) AND (album_id1 IS NOT NULL) AND (album_id2 IS NOT NULL))))'
2919
+ end
2920
+
2921
+ it "should be able to exclude on multiple many_to_one associations" do
2922
+ @Album.exclude(:artist=>[@Artist.load(:id=>3), @Artist.load(:id=>4)]).sql.should == 'SELECT * FROM albums WHERE ((artist_id NOT IN (3, 4)) OR (artist_id IS NULL))'
2923
+ end
2924
+
2925
+ it "should be able to exclude on multiple one_to_many associations" do
2926
+ @Album.exclude(:tracks=>[@Track.load(:album_id=>3), @Track.load(:album_id=>4)]).sql.should == 'SELECT * FROM albums WHERE ((id NOT IN (3, 4)) OR (id IS NULL))'
2927
+ end
2928
+
2929
+ it "should be able to exclude on multiple one_to_one associations" do
2930
+ @Album.exclude(:album_info=>[@AlbumInfo.load(:album_id=>3), @AlbumInfo.load(:album_id=>4)]).sql.should == 'SELECT * FROM albums WHERE ((id NOT IN (3, 4)) OR (id IS NULL))'
2931
+ end
2932
+
2933
+ it "should be able to exclude on multiple many_to_many associations" do
2934
+ @Album.exclude(:tags=>[@Tag.load(:id=>3), @Tag.load(:id=>4)]).sql.should == 'SELECT * FROM albums WHERE ((id NOT IN (SELECT album_id FROM albums_tags WHERE ((tag_id IN (3, 4)) AND (album_id IS NOT NULL)))) OR (id IS NULL))'
2935
+ end
2936
+
2937
+ it "should be able to exclude on multiple many_to_one associations with composite keys" do
2938
+ @Album.exclude(:cartist=>[@Artist.load(:id1=>3, :id2=>4), @Artist.load(:id1=>5, :id2=>6)]).sql.should == 'SELECT * FROM albums WHERE (((artist_id1, artist_id2) NOT IN ((3, 4), (5, 6))) OR (artist_id1 IS NULL) OR (artist_id2 IS NULL))'
2939
+ end
2940
+
2941
+ it "should be able to exclude on multiple one_to_many associations with composite keys" do
2942
+ @Album.exclude(:ctracks=>[@Track.load(:album_id1=>3, :album_id2=>4), @Track.load(:album_id1=>5, :album_id2=>6)]).sql.should == 'SELECT * FROM albums WHERE (((id1, id2) NOT IN ((3, 4), (5, 6))) OR (id1 IS NULL) OR (id2 IS NULL))'
2943
+ end
2944
+
2945
+ it "should be able to exclude on multiple one_to_one associations with composite keys" do
2946
+ @Album.exclude(:calbum_info=>[@AlbumInfo.load(:album_id1=>3, :album_id2=>4), @AlbumInfo.load(:album_id1=>5, :album_id2=>6)]).sql.should == 'SELECT * FROM albums WHERE (((id1, id2) NOT IN ((3, 4), (5, 6))) OR (id1 IS NULL) OR (id2 IS NULL))'
2947
+ end
2948
+
2949
+ it "should be able to exclude on multiple many_to_many associations with composite keys" do
2950
+ @Album.exclude(:ctags=>[@Tag.load(:tid1=>3, :tid2=>4), @Tag.load(:tid1=>5, :tid2=>6)]).sql.should == 'SELECT * FROM albums WHERE (((id1, id2) NOT IN (SELECT album_id1, album_id2 FROM albums_tags WHERE (((tag_id1, tag_id2) IN ((3, 4), (5, 6))) AND (album_id1 IS NOT NULL) AND (album_id2 IS NOT NULL)))) OR (id1 IS NULL) OR (id2 IS NULL))'
2951
+ end
2952
+
2953
+ it "should be able to handle NULL values when filtering many_to_one associations" do
2954
+ @Album.filter(:artist=>@Artist.new).sql.should == 'SELECT * FROM albums WHERE \'f\''
2955
+ end
2956
+
2957
+ it "should be able to handle NULL values when filtering one_to_many associations" do
2958
+ @Album.filter(:tracks=>@Track.new).sql.should == 'SELECT * FROM albums WHERE \'f\''
2959
+ end
2960
+
2961
+ it "should be able to handle NULL values when filtering one_to_one associations" do
2962
+ @Album.filter(:album_info=>@AlbumInfo.new).sql.should == 'SELECT * FROM albums WHERE \'f\''
2963
+ end
2964
+
2965
+ it "should be able to handle NULL values when filtering many_to_many associations" do
2966
+ @Album.filter(:tags=>@Tag.new).sql.should == 'SELECT * FROM albums WHERE \'f\''
2967
+ end
2968
+
2969
+ it "should be able to handle filteringing with NULL values for many_to_one associations with composite keys" do
2970
+ @Album.filter(:cartist=>@Artist.load(:id2=>4)).sql.should == 'SELECT * FROM albums WHERE \'f\''
2971
+ @Album.filter(:cartist=>@Artist.load(:id1=>3)).sql.should == 'SELECT * FROM albums WHERE \'f\''
2972
+ @Album.filter(:cartist=>@Artist.new).sql.should == 'SELECT * FROM albums WHERE \'f\''
2973
+ end
2974
+
2975
+ it "should be able to filtering with NULL values for one_to_many associations with composite keys" do
2976
+ @Album.filter(:ctracks=>@Track.load(:album_id2=>4)).sql.should == 'SELECT * FROM albums WHERE \'f\''
2977
+ @Album.filter(:ctracks=>@Track.load(:album_id1=>3)).sql.should == 'SELECT * FROM albums WHERE \'f\''
2978
+ @Album.filter(:ctracks=>@Track.new).sql.should == 'SELECT * FROM albums WHERE \'f\''
2979
+ end
2980
+
2981
+ it "should be able to filtering with NULL values for one_to_one associations with composite keys" do
2982
+ @Album.filter(:calbum_info=>@AlbumInfo.load(:album_id2=>4)).sql.should == 'SELECT * FROM albums WHERE \'f\''
2983
+ @Album.filter(:calbum_info=>@AlbumInfo.load(:album_id1=>3)).sql.should == 'SELECT * FROM albums WHERE \'f\''
2984
+ @Album.filter(:calbum_info=>@AlbumInfo.new).sql.should == 'SELECT * FROM albums WHERE \'f\''
2985
+ end
2986
+
2987
+ it "should be able to filtering with NULL values for many_to_many associations with composite keys" do
2988
+ @Album.filter(:ctags=>@Tag.load(:tid1=>3)).sql.should == 'SELECT * FROM albums WHERE \'f\''
2989
+ @Album.filter(:ctags=>@Tag.load(:tid2=>4)).sql.should == 'SELECT * FROM albums WHERE \'f\''
2990
+ @Album.filter(:ctags=>@Tag.new).sql.should == 'SELECT * FROM albums WHERE \'f\''
2991
+ end
2992
+
2993
+ it "should be able to handle NULL values when excluding many_to_one associations" do
2994
+ @Album.exclude(:artist=>@Artist.new).sql.should == 'SELECT * FROM albums WHERE \'t\''
2995
+ end
2996
+
2997
+ it "should be able to handle NULL values when excluding one_to_many associations" do
2998
+ @Album.exclude(:tracks=>@Track.new).sql.should == 'SELECT * FROM albums WHERE \'t\''
2999
+ end
3000
+
3001
+ it "should be able to handle NULL values when excluding one_to_one associations" do
3002
+ @Album.exclude(:album_info=>@AlbumInfo.new).sql.should == 'SELECT * FROM albums WHERE \'t\''
3003
+ end
3004
+
3005
+ it "should be able to handle NULL values when excluding many_to_many associations" do
3006
+ @Album.exclude(:tags=>@Tag.new).sql.should == 'SELECT * FROM albums WHERE \'t\''
3007
+ end
3008
+
3009
+ it "should be able to handle excluding with NULL values for many_to_one associations with composite keys" do
3010
+ @Album.exclude(:cartist=>@Artist.load(:id2=>4)).sql.should == 'SELECT * FROM albums WHERE \'t\''
3011
+ @Album.exclude(:cartist=>@Artist.load(:id1=>3)).sql.should == 'SELECT * FROM albums WHERE \'t\''
3012
+ @Album.exclude(:cartist=>@Artist.new).sql.should == 'SELECT * FROM albums WHERE \'t\''
3013
+ end
3014
+
3015
+ it "should be able to excluding with NULL values for one_to_many associations with composite keys" do
3016
+ @Album.exclude(:ctracks=>@Track.load(:album_id2=>4)).sql.should == 'SELECT * FROM albums WHERE \'t\''
3017
+ @Album.exclude(:ctracks=>@Track.load(:album_id1=>3)).sql.should == 'SELECT * FROM albums WHERE \'t\''
3018
+ @Album.exclude(:ctracks=>@Track.new).sql.should == 'SELECT * FROM albums WHERE \'t\''
3019
+ end
3020
+
3021
+ it "should be able to excluding with NULL values for one_to_one associations with composite keys" do
3022
+ @Album.exclude(:calbum_info=>@AlbumInfo.load(:album_id2=>4)).sql.should == 'SELECT * FROM albums WHERE \'t\''
3023
+ @Album.exclude(:calbum_info=>@AlbumInfo.load(:album_id1=>3)).sql.should == 'SELECT * FROM albums WHERE \'t\''
3024
+ @Album.exclude(:calbum_info=>@AlbumInfo.new).sql.should == 'SELECT * FROM albums WHERE \'t\''
3025
+ end
3026
+
3027
+ it "should be able to excluding with NULL values for many_to_many associations with composite keys" do
3028
+ @Album.exclude(:ctags=>@Tag.load(:tid1=>3)).sql.should == 'SELECT * FROM albums WHERE \'t\''
3029
+ @Album.exclude(:ctags=>@Tag.load(:tid2=>4)).sql.should == 'SELECT * FROM albums WHERE \'t\''
3030
+ @Album.exclude(:ctags=>@Tag.new).sql.should == 'SELECT * FROM albums WHERE \'t\''
3031
+ end
3032
+
3033
+ it "should be able to handle NULL values when filtering multiple many_to_one associations" do
3034
+ @Album.filter(:artist=>[@Artist.load(:id=>3), @Artist.new]).sql.should == 'SELECT * FROM albums WHERE (artist_id IN (3))'
3035
+ @Album.filter(:artist=>[@Artist.new, @Artist.new]).sql.should == 'SELECT * FROM albums WHERE \'f\''
3036
+ end
3037
+
3038
+ it "should be able to handle NULL values when filtering multiple one_to_many associations" do
3039
+ @Album.filter(:tracks=>[@Track.load(:album_id=>3), @Track.new]).sql.should == 'SELECT * FROM albums WHERE (id IN (3))'
3040
+ @Album.filter(:tracks=>[@Track.new, @Track.new]).sql.should == 'SELECT * FROM albums WHERE \'f\''
3041
+ end
3042
+
3043
+ it "should be able to handle NULL values when filtering multiple one_to_one associations" do
3044
+ @Album.filter(:album_info=>[@AlbumInfo.load(:album_id=>3), @AlbumInfo.new]).sql.should == 'SELECT * FROM albums WHERE (id IN (3))'
3045
+ @Album.filter(:album_info=>[@AlbumInfo.new, @AlbumInfo.new]).sql.should == 'SELECT * FROM albums WHERE \'f\''
3046
+ end
3047
+
3048
+ it "should be able to handle NULL values when filtering multiple many_to_many associations" do
3049
+ @Album.filter(:tags=>[@Tag.load(:id=>3), @Tag.new]).sql.should == 'SELECT * FROM albums WHERE (id IN (SELECT album_id FROM albums_tags WHERE ((tag_id IN (3)) AND (album_id IS NOT NULL))))'
3050
+ @Album.filter(:tags=>[@Tag.new, @Tag.new]).sql.should == 'SELECT * FROM albums WHERE \'f\''
3051
+ end
3052
+
3053
+ it "should be able to handle NULL values when filtering multiple many_to_one associations with composite keys" do
3054
+ @Album.filter(:cartist=>[@Artist.load(:id1=>3, :id2=>4), @Artist.load(:id1=>3)]).sql.should == 'SELECT * FROM albums WHERE ((artist_id1, artist_id2) IN ((3, 4)))'
3055
+ @Album.filter(:cartist=>[@Artist.load(:id1=>3, :id2=>4), @Artist.new]).sql.should == 'SELECT * FROM albums WHERE ((artist_id1, artist_id2) IN ((3, 4)))'
3056
+ end
3057
+
3058
+ it "should be able handle NULL values when filtering multiple one_to_many associations with composite keys" do
3059
+ @Album.filter(:ctracks=>[@Track.load(:album_id1=>3, :album_id2=>4), @Track.load(:album_id1=>3)]).sql.should == 'SELECT * FROM albums WHERE ((id1, id2) IN ((3, 4)))'
3060
+ @Album.filter(:ctracks=>[@Track.load(:album_id1=>3, :album_id2=>4), @Track.new]).sql.should == 'SELECT * FROM albums WHERE ((id1, id2) IN ((3, 4)))'
3061
+ end
3062
+
3063
+ it "should be able to handle NULL values when filtering multiple one_to_one associations with composite keys" do
3064
+ @Album.filter(:calbum_info=>[@AlbumInfo.load(:album_id1=>3, :album_id2=>4), @AlbumInfo.load(:album_id1=>5)]).sql.should == 'SELECT * FROM albums WHERE ((id1, id2) IN ((3, 4)))'
3065
+ @Album.filter(:calbum_info=>[@AlbumInfo.load(:album_id1=>3, :album_id2=>4), @AlbumInfo.new]).sql.should == 'SELECT * FROM albums WHERE ((id1, id2) IN ((3, 4)))'
3066
+ end
3067
+
3068
+ it "should be able to handle NULL values when filtering multiple many_to_many associations with composite keys" do
3069
+ @Album.filter(:ctags=>[@Tag.load(:tid1=>3, :tid2=>4), @Tag.load(:tid1=>5)]).sql.should == 'SELECT * FROM albums WHERE ((id1, id2) IN (SELECT album_id1, album_id2 FROM albums_tags WHERE (((tag_id1, tag_id2) IN ((3, 4))) AND (album_id1 IS NOT NULL) AND (album_id2 IS NOT NULL))))'
3070
+ @Album.filter(:ctags=>[@Tag.load(:tid1=>3, :tid2=>4), @Tag.new]).sql.should == 'SELECT * FROM albums WHERE ((id1, id2) IN (SELECT album_id1, album_id2 FROM albums_tags WHERE (((tag_id1, tag_id2) IN ((3, 4))) AND (album_id1 IS NOT NULL) AND (album_id2 IS NOT NULL))))'
3071
+ end
3072
+
3073
+ it "should be able to handle NULL values when excluding multiple many_to_one associations" do
3074
+ @Album.exclude(:artist=>[@Artist.load(:id=>3), @Artist.new]).sql.should == 'SELECT * FROM albums WHERE ((artist_id NOT IN (3)) OR (artist_id IS NULL))'
3075
+ @Album.exclude(:artist=>[@Artist.new, @Artist.new]).sql.should == 'SELECT * FROM albums WHERE \'t\''
3076
+ end
3077
+
3078
+ it "should be able to handle NULL values when excluding multiple one_to_many associations" do
3079
+ @Album.exclude(:tracks=>[@Track.load(:album_id=>3), @Track.new]).sql.should == 'SELECT * FROM albums WHERE ((id NOT IN (3)) OR (id IS NULL))'
3080
+ @Album.exclude(:tracks=>[@Track.new, @Track.new]).sql.should == 'SELECT * FROM albums WHERE \'t\''
3081
+ end
3082
+
3083
+ it "should be able to handle NULL values when excluding multiple one_to_one associations" do
3084
+ @Album.exclude(:album_info=>[@AlbumInfo.load(:album_id=>3), @AlbumInfo.new]).sql.should == 'SELECT * FROM albums WHERE ((id NOT IN (3)) OR (id IS NULL))'
3085
+ @Album.exclude(:album_info=>[@AlbumInfo.new, @AlbumInfo.new]).sql.should == 'SELECT * FROM albums WHERE \'t\''
3086
+ end
3087
+
3088
+ it "should be able to handle NULL values when excluding multiple many_to_many associations" do
3089
+ @Album.exclude(:tags=>[@Tag.load(:id=>3), @Tag.new]).sql.should == 'SELECT * FROM albums WHERE ((id NOT IN (SELECT album_id FROM albums_tags WHERE ((tag_id IN (3)) AND (album_id IS NOT NULL)))) OR (id IS NULL))'
3090
+ @Album.exclude(:tags=>[@Tag.new, @Tag.new]).sql.should == 'SELECT * FROM albums WHERE \'t\''
3091
+ end
3092
+
3093
+ it "should be able to handle NULL values when excluding multiple many_to_one associations with composite keys" do
3094
+ @Album.exclude(:cartist=>[@Artist.load(:id1=>3, :id2=>4), @Artist.load(:id1=>3)]).sql.should == 'SELECT * FROM albums WHERE (((artist_id1, artist_id2) NOT IN ((3, 4))) OR (artist_id1 IS NULL) OR (artist_id2 IS NULL))'
3095
+ @Album.exclude(:cartist=>[@Artist.load(:id1=>3, :id2=>4), @Artist.new]).sql.should == 'SELECT * FROM albums WHERE (((artist_id1, artist_id2) NOT IN ((3, 4))) OR (artist_id1 IS NULL) OR (artist_id2 IS NULL))'
3096
+ end
3097
+
3098
+ it "should be able handle NULL values when excluding multiple one_to_many associations with composite keys" do
3099
+ @Album.exclude(:ctracks=>[@Track.load(:album_id1=>3, :album_id2=>4), @Track.load(:album_id1=>3)]).sql.should == 'SELECT * FROM albums WHERE (((id1, id2) NOT IN ((3, 4))) OR (id1 IS NULL) OR (id2 IS NULL))'
3100
+ @Album.exclude(:ctracks=>[@Track.load(:album_id1=>3, :album_id2=>4), @Track.new]).sql.should == 'SELECT * FROM albums WHERE (((id1, id2) NOT IN ((3, 4))) OR (id1 IS NULL) OR (id2 IS NULL))'
3101
+ end
3102
+
3103
+ it "should be able to handle NULL values when excluding multiple one_to_one associations with composite keys" do
3104
+ @Album.exclude(:calbum_info=>[@AlbumInfo.load(:album_id1=>3, :album_id2=>4), @AlbumInfo.load(:album_id1=>5)]).sql.should == 'SELECT * FROM albums WHERE (((id1, id2) NOT IN ((3, 4))) OR (id1 IS NULL) OR (id2 IS NULL))'
3105
+ @Album.exclude(:calbum_info=>[@AlbumInfo.load(:album_id1=>3, :album_id2=>4), @AlbumInfo.new]).sql.should == 'SELECT * FROM albums WHERE (((id1, id2) NOT IN ((3, 4))) OR (id1 IS NULL) OR (id2 IS NULL))'
3106
+ end
3107
+
3108
+ it "should be able to handle NULL values when excluding multiple many_to_many associations with composite keys" do
3109
+ @Album.exclude(:ctags=>[@Tag.load(:tid1=>3, :tid2=>4), @Tag.load(:tid1=>5)]).sql.should == 'SELECT * FROM albums WHERE (((id1, id2) NOT IN (SELECT album_id1, album_id2 FROM albums_tags WHERE (((tag_id1, tag_id2) IN ((3, 4))) AND (album_id1 IS NOT NULL) AND (album_id2 IS NOT NULL)))) OR (id1 IS NULL) OR (id2 IS NULL))'
3110
+ @Album.exclude(:ctags=>[@Tag.load(:tid1=>3, :tid2=>4), @Tag.new]).sql.should == 'SELECT * FROM albums WHERE (((id1, id2) NOT IN (SELECT album_id1, album_id2 FROM albums_tags WHERE (((tag_id1, tag_id2) IN ((3, 4))) AND (album_id1 IS NOT NULL) AND (album_id2 IS NOT NULL)))) OR (id1 IS NULL) OR (id2 IS NULL))'
3111
+ end
3112
+
3113
+ it "should be able to filter on many_to_one association datasets" do
3114
+ @Album.filter(:artist=>@Artist.filter(:x=>1)).sql.should == 'SELECT * FROM albums WHERE (artist_id IN (SELECT id FROM artists WHERE ((x = 1) AND (id IS NOT NULL))))'
3115
+ end
3116
+
3117
+ it "should be able to filter on one_to_many association datasets" do
3118
+ @Album.filter(:tracks=>@Track.filter(:x=>1)).sql.should == 'SELECT * FROM albums WHERE (id IN (SELECT album_id FROM tracks WHERE ((x = 1) AND (album_id IS NOT NULL))))'
3119
+ end
3120
+
3121
+ it "should be able to filter on one_to_one association datasets" do
3122
+ @Album.filter(:album_info=>@AlbumInfo.filter(:x=>1)).sql.should == 'SELECT * FROM albums WHERE (id IN (SELECT album_id FROM album_infos WHERE ((x = 1) AND (album_id IS NOT NULL))))'
3123
+ end
3124
+
3125
+ it "should be able to filter on many_to_many association datasets" do
3126
+ @Album.filter(:tags=>@Tag.filter(:x=>1)).sql.should == 'SELECT * FROM albums WHERE (id IN (SELECT album_id FROM albums_tags WHERE ((tag_id IN (SELECT id FROM tags WHERE ((x = 1) AND (id IS NOT NULL)))) AND (album_id IS NOT NULL))))'
3127
+ end
3128
+
3129
+ it "should be able to filter on many_to_one association datasets with composite keys" do
3130
+ @Album.filter(:cartist=>@Artist.filter(:x=>1)).sql.should == 'SELECT * FROM albums WHERE ((artist_id1, artist_id2) IN (SELECT id1, id2 FROM artists WHERE ((x = 1) AND (id1 IS NOT NULL) AND (id2 IS NOT NULL))))'
3131
+ end
3132
+
3133
+ it "should be able to filter on one_to_many association datasets with composite keys" do
3134
+ @Album.filter(:ctracks=>@Track.filter(:x=>1)).sql.should == 'SELECT * FROM albums WHERE ((id1, id2) IN (SELECT album_id1, album_id2 FROM tracks WHERE ((x = 1) AND (album_id1 IS NOT NULL) AND (album_id2 IS NOT NULL))))'
3135
+ end
3136
+
3137
+ it "should be able to filter on one_to_one association datasets with composite keys" do
3138
+ @Album.filter(:calbum_info=>@AlbumInfo.filter(:x=>1)).sql.should == 'SELECT * FROM albums WHERE ((id1, id2) IN (SELECT album_id1, album_id2 FROM album_infos WHERE ((x = 1) AND (album_id1 IS NOT NULL) AND (album_id2 IS NOT NULL))))'
3139
+ end
3140
+
3141
+ it "should be able to filter on many_to_many association datasets with composite keys" do
3142
+ @Album.filter(:ctags=>@Tag.filter(:x=>1)).sql.should == 'SELECT * FROM albums WHERE ((id1, id2) IN (SELECT album_id1, album_id2 FROM albums_tags WHERE (((tag_id1, tag_id2) IN (SELECT tid1, tid2 FROM tags WHERE ((x = 1) AND (tid1 IS NOT NULL) AND (tid2 IS NOT NULL)))) AND (album_id1 IS NOT NULL) AND (album_id2 IS NOT NULL))))'
3143
+ end
3144
+
3145
+ it "should be able to exclude on many_to_one association datasets" do
3146
+ @Album.exclude(:artist=>@Artist.filter(:x=>1)).sql.should == 'SELECT * FROM albums WHERE ((artist_id NOT IN (SELECT id FROM artists WHERE ((x = 1) AND (id IS NOT NULL)))) OR (artist_id IS NULL))'
3147
+ end
3148
+
3149
+ it "should be able to exclude on one_to_many association datasets" do
3150
+ @Album.exclude(:tracks=>@Track.filter(:x=>1)).sql.should == 'SELECT * FROM albums WHERE ((id NOT IN (SELECT album_id FROM tracks WHERE ((x = 1) AND (album_id IS NOT NULL)))) OR (id IS NULL))'
3151
+ end
3152
+
3153
+ it "should be able to exclude on one_to_one association datasets" do
3154
+ @Album.exclude(:album_info=>@AlbumInfo.filter(:x=>1)).sql.should == 'SELECT * FROM albums WHERE ((id NOT IN (SELECT album_id FROM album_infos WHERE ((x = 1) AND (album_id IS NOT NULL)))) OR (id IS NULL))'
3155
+ end
3156
+
3157
+ it "should be able to exclude on many_to_many association datasets" do
3158
+ @Album.exclude(:tags=>@Tag.filter(:x=>1)).sql.should == 'SELECT * FROM albums WHERE ((id NOT IN (SELECT album_id FROM albums_tags WHERE ((tag_id IN (SELECT id FROM tags WHERE ((x = 1) AND (id IS NOT NULL)))) AND (album_id IS NOT NULL)))) OR (id IS NULL))'
3159
+ end
3160
+
3161
+ it "should be able to exclude on many_to_one association datasets with composite keys" do
3162
+ @Album.exclude(:cartist=>@Artist.filter(:x=>1)).sql.should == 'SELECT * FROM albums WHERE (((artist_id1, artist_id2) NOT IN (SELECT id1, id2 FROM artists WHERE ((x = 1) AND (id1 IS NOT NULL) AND (id2 IS NOT NULL)))) OR (artist_id1 IS NULL) OR (artist_id2 IS NULL))'
3163
+ end
3164
+
3165
+ it "should be able to exclude on one_to_many association datasets with composite keys" do
3166
+ @Album.exclude(:ctracks=>@Track.filter(:x=>1)).sql.should == 'SELECT * FROM albums WHERE (((id1, id2) NOT IN (SELECT album_id1, album_id2 FROM tracks WHERE ((x = 1) AND (album_id1 IS NOT NULL) AND (album_id2 IS NOT NULL)))) OR (id1 IS NULL) OR (id2 IS NULL))'
3167
+ end
3168
+
3169
+ it "should be able to exclude on one_to_one association datasets with composite keys" do
3170
+ @Album.exclude(:calbum_info=>@AlbumInfo.filter(:x=>1)).sql.should == 'SELECT * FROM albums WHERE (((id1, id2) NOT IN (SELECT album_id1, album_id2 FROM album_infos WHERE ((x = 1) AND (album_id1 IS NOT NULL) AND (album_id2 IS NOT NULL)))) OR (id1 IS NULL) OR (id2 IS NULL))'
3171
+ end
3172
+
3173
+ it "should be able to exclude on many_to_many association datasets with composite keys" do
3174
+ @Album.exclude(:ctags=>@Tag.filter(:x=>1)).sql.should == 'SELECT * FROM albums WHERE (((id1, id2) NOT IN (SELECT album_id1, album_id2 FROM albums_tags WHERE (((tag_id1, tag_id2) IN (SELECT tid1, tid2 FROM tags WHERE ((x = 1) AND (tid1 IS NOT NULL) AND (tid2 IS NOT NULL)))) AND (album_id1 IS NOT NULL) AND (album_id2 IS NOT NULL)))) OR (id1 IS NULL) OR (id2 IS NULL))'
3175
+ end
3176
+
3177
+ it "should do a regular IN query if the dataset for a different model is used" do
3178
+ @Album.filter(:artist=>@Album.select(:x)).sql.should == 'SELECT * FROM albums WHERE (artist IN (SELECT x FROM albums))'
3179
+ end
3180
+
3181
+ it "should do a regular IN query if a non-model dataset is used" do
3182
+ @Album.filter(:artist=>@Album.db.from(:albums).select(:x)).sql.should == 'SELECT * FROM albums WHERE (artist IN (SELECT x FROM albums))'
3183
+ end
3184
+ end
@@ -485,3 +485,62 @@ describe Sequel::Model, ".[] optimization" do
485
485
  @c[1]
486
486
  end
487
487
  end
488
+
489
+ describe "Model datasets #with_pk" do
490
+ before do
491
+ @c = Class.new(Sequel::Model(:a))
492
+ @ds = @c.dataset
493
+ def @ds.fetch_rows(sql)
494
+ db << sql
495
+ yield(:id=>1)
496
+ end
497
+ @sqls = MODEL_DB.sqls
498
+ @sqls.clear
499
+ end
500
+
501
+ it "should return the first record where the primary key matches" do
502
+ @ds.with_pk(1).should == @c.load(:id=>1)
503
+ @sqls.should == ["SELECT * FROM a WHERE (id = 1) LIMIT 1"]
504
+ end
505
+
506
+ it "should handle existing filters" do
507
+ @ds.filter(:a=>2).with_pk(1)
508
+ @sqls.should == ["SELECT * FROM a WHERE ((a = 2) AND (id = 1)) LIMIT 1"]
509
+ end
510
+
511
+ it "should work with string values" do
512
+ @ds.with_pk("foo")
513
+ @sqls.should == ["SELECT * FROM a WHERE (id = 'foo') LIMIT 1"]
514
+ end
515
+
516
+ it "should handle an array for composite primary keys" do
517
+ @c.set_primary_key :id1, :id2
518
+ @ds.with_pk([1, 2])
519
+ @sqls.should == ["SELECT * FROM a WHERE ((id1 = 1) AND (id2 = 2)) LIMIT 1"]
520
+ end
521
+
522
+ it "should raise an error if a single primary key is given when a composite primary key should be used" do
523
+ @c.set_primary_key :id1, :id2
524
+ proc{@ds.with_pk(1)}.should raise_error(Sequel::Error)
525
+ end
526
+
527
+ it "should raise an error if a composite primary key is given when a single primary key should be used" do
528
+ proc{@ds.with_pk([1, 2])}.should raise_error(Sequel::Error)
529
+ end
530
+
531
+ it "should raise an error if the wrong number of composite keys is given" do
532
+ @c.set_primary_key :id1, :id2
533
+ proc{@ds.with_pk([1, 2, 3])}.should raise_error(Sequel::Error)
534
+ end
535
+
536
+ it "should have #[] consider an integer as a primary key lookup" do
537
+ @ds[1].should == @c.load(:id=>1)
538
+ @sqls.should == ["SELECT * FROM a WHERE (id = 1) LIMIT 1"]
539
+ end
540
+
541
+ it "should not have #[] consider a string as a primary key lookup" do
542
+ @ds['foo'].should == @c.load(:id=>1)
543
+ @sqls.should == ["SELECT * FROM a WHERE (foo) LIMIT 1"]
544
+ end
545
+
546
+ end