sequel 3.23.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 (76) hide show
  1. data/CHANGELOG +64 -0
  2. data/doc/association_basics.rdoc +43 -5
  3. data/doc/model_hooks.rdoc +64 -27
  4. data/doc/prepared_statements.rdoc +8 -4
  5. data/doc/reflection.rdoc +8 -2
  6. data/doc/release_notes/3.23.0.txt +1 -1
  7. data/doc/release_notes/3.24.0.txt +420 -0
  8. data/lib/sequel/adapters/db2.rb +8 -1
  9. data/lib/sequel/adapters/firebird.rb +25 -9
  10. data/lib/sequel/adapters/informix.rb +4 -19
  11. data/lib/sequel/adapters/jdbc.rb +34 -17
  12. data/lib/sequel/adapters/jdbc/h2.rb +5 -0
  13. data/lib/sequel/adapters/jdbc/informix.rb +31 -0
  14. data/lib/sequel/adapters/jdbc/jtds.rb +34 -0
  15. data/lib/sequel/adapters/jdbc/mssql.rb +0 -32
  16. data/lib/sequel/adapters/jdbc/mysql.rb +9 -0
  17. data/lib/sequel/adapters/jdbc/sqlserver.rb +46 -0
  18. data/lib/sequel/adapters/postgres.rb +30 -1
  19. data/lib/sequel/adapters/shared/access.rb +10 -0
  20. data/lib/sequel/adapters/shared/informix.rb +45 -0
  21. data/lib/sequel/adapters/shared/mssql.rb +82 -8
  22. data/lib/sequel/adapters/shared/mysql.rb +25 -7
  23. data/lib/sequel/adapters/shared/postgres.rb +39 -6
  24. data/lib/sequel/adapters/shared/sqlite.rb +57 -5
  25. data/lib/sequel/adapters/sqlite.rb +8 -3
  26. data/lib/sequel/adapters/swift/mysql.rb +9 -0
  27. data/lib/sequel/ast_transformer.rb +190 -0
  28. data/lib/sequel/core.rb +1 -1
  29. data/lib/sequel/database/misc.rb +6 -0
  30. data/lib/sequel/database/query.rb +33 -3
  31. data/lib/sequel/database/schema_methods.rb +6 -2
  32. data/lib/sequel/dataset/features.rb +6 -0
  33. data/lib/sequel/dataset/prepared_statements.rb +17 -2
  34. data/lib/sequel/dataset/query.rb +17 -0
  35. data/lib/sequel/dataset/sql.rb +2 -53
  36. data/lib/sequel/exceptions.rb +4 -0
  37. data/lib/sequel/extensions/to_dot.rb +95 -83
  38. data/lib/sequel/model.rb +5 -0
  39. data/lib/sequel/model/associations.rb +80 -14
  40. data/lib/sequel/model/base.rb +182 -55
  41. data/lib/sequel/model/exceptions.rb +3 -1
  42. data/lib/sequel/plugins/association_pks.rb +6 -4
  43. data/lib/sequel/plugins/defaults_setter.rb +58 -0
  44. data/lib/sequel/plugins/many_through_many.rb +8 -3
  45. data/lib/sequel/plugins/prepared_statements.rb +140 -0
  46. data/lib/sequel/plugins/prepared_statements_associations.rb +84 -0
  47. data/lib/sequel/plugins/prepared_statements_safe.rb +72 -0
  48. data/lib/sequel/plugins/prepared_statements_with_pk.rb +59 -0
  49. data/lib/sequel/sql.rb +8 -0
  50. data/lib/sequel/version.rb +1 -1
  51. data/spec/adapters/postgres_spec.rb +43 -18
  52. data/spec/core/connection_pool_spec.rb +56 -77
  53. data/spec/core/database_spec.rb +25 -0
  54. data/spec/core/dataset_spec.rb +127 -16
  55. data/spec/core/expression_filters_spec.rb +13 -0
  56. data/spec/core/schema_spec.rb +6 -1
  57. data/spec/extensions/association_pks_spec.rb +7 -0
  58. data/spec/extensions/defaults_setter_spec.rb +64 -0
  59. data/spec/extensions/many_through_many_spec.rb +60 -4
  60. data/spec/extensions/nested_attributes_spec.rb +1 -0
  61. data/spec/extensions/prepared_statements_associations_spec.rb +126 -0
  62. data/spec/extensions/prepared_statements_safe_spec.rb +69 -0
  63. data/spec/extensions/prepared_statements_spec.rb +72 -0
  64. data/spec/extensions/prepared_statements_with_pk_spec.rb +38 -0
  65. data/spec/extensions/to_dot_spec.rb +3 -5
  66. data/spec/integration/associations_test.rb +155 -1
  67. data/spec/integration/dataset_test.rb +8 -1
  68. data/spec/integration/plugin_test.rb +119 -0
  69. data/spec/integration/prepared_statement_test.rb +72 -1
  70. data/spec/integration/schema_test.rb +66 -8
  71. data/spec/integration/transaction_test.rb +40 -0
  72. data/spec/model/associations_spec.rb +349 -8
  73. data/spec/model/base_spec.rb +59 -0
  74. data/spec/model/hooks_spec.rb +161 -0
  75. data/spec/model/record_spec.rb +24 -0
  76. metadata +21 -4
@@ -174,6 +174,15 @@ describe "Database schema modifiers" do
174
174
  @db.create_table!(:items, :temp=>true){Integer :number}
175
175
  end
176
176
 
177
+ specify "should have create_table? only create the table if it doesn't already exist" do
178
+ @db.create_table!(:items){String :a}
179
+ @db.create_table?(:items){String :b}
180
+ @db[:items].columns.should == [:a]
181
+ @db.drop_table(:items) rescue nil
182
+ @db.create_table?(:items){String :b}
183
+ @db[:items].columns.should == [:b]
184
+ end
185
+
177
186
  specify "should rename tables correctly" do
178
187
  @db.drop_table(:items) rescue nil
179
188
  @db.create_table!(:items2){Integer :number}
@@ -362,25 +371,74 @@ describe "Database#tables" do
362
371
  "xxxxx#{@@xxxxx += 1}"
363
372
  end
364
373
  end
365
- @iom = INTEGRATION_DB.identifier_output_method
366
- @iim = INTEGRATION_DB.identifier_input_method
374
+ @db = INTEGRATION_DB
375
+ @db.create_table(:sequel_test_table){Integer :a}
376
+ @db.create_view :sequel_test_view, @db[:sequel_test_table]
377
+ @iom = @db.identifier_output_method
378
+ @iim = @db.identifier_input_method
367
379
  clear_sqls
368
380
  end
369
381
  after do
370
- INTEGRATION_DB.identifier_output_method = @iom
371
- INTEGRATION_DB.identifier_input_method = @iim
382
+ @db.drop_view :sequel_test_view
383
+ @db.drop_table :sequel_test_table
384
+ @db.identifier_output_method = @iom
385
+ @db.identifier_input_method = @iim
386
+ end
387
+
388
+ specify "should return an array of symbols" do
389
+ ts = @db.tables
390
+ ts.should be_a_kind_of(Array)
391
+ ts.each{|t| t.should be_a_kind_of(Symbol)}
392
+ ts.should include(:sequel_test_table)
393
+ ts.should_not include(:sequel_test_view)
394
+ end
395
+
396
+ specify "should respect the database's identifier_output_method" do
397
+ @db.identifier_output_method = :xxxxx
398
+ @db.identifier_input_method = :xxxxx
399
+ @db.tables.each{|t| t.to_s.should =~ /\Ax{5}\d+\z/}
400
+ end
401
+ end
402
+ end
403
+
404
+ begin
405
+ INTEGRATION_DB.views
406
+ rescue Sequel::NotImplemented
407
+ rescue
408
+ describe "Database#views" do
409
+ before do
410
+ class ::String
411
+ @@xxxxx = 0
412
+ def xxxxx
413
+ "xxxxx#{@@xxxxx += 1}"
414
+ end
415
+ end
416
+ @db = INTEGRATION_DB
417
+ @db.create_table(:sequel_test_table){Integer :a}
418
+ @db.create_view :sequel_test_view, @db[:sequel_test_table]
419
+ @iom = @db.identifier_output_method
420
+ @iim = @db.identifier_input_method
421
+ clear_sqls
422
+ end
423
+ after do
424
+ @db.drop_view :sequel_test_view
425
+ @db.drop_table :sequel_test_table
426
+ @db.identifier_output_method = @iom
427
+ @db.identifier_input_method = @iim
372
428
  end
373
429
 
374
430
  specify "should return an array of symbols" do
375
- ts = INTEGRATION_DB.tables
431
+ ts = @db.views
376
432
  ts.should be_a_kind_of(Array)
377
433
  ts.each{|t| t.should be_a_kind_of(Symbol)}
434
+ ts.should_not include(:sequel_test_table)
435
+ ts.should include(:sequel_test_view)
378
436
  end
379
437
 
380
438
  specify "should respect the database's identifier_output_method" do
381
- INTEGRATION_DB.identifier_output_method = :xxxxx
382
- INTEGRATION_DB.identifier_input_method = :xxxxx
383
- INTEGRATION_DB.tables.each{|t| t.to_s.should =~ /\Ax{5}\d+\z/}
439
+ @db.identifier_output_method = :xxxxx
440
+ @db.identifier_input_method = :xxxxx
441
+ @db.views.each{|t| t.to_s.should =~ /\Ax{5}\d+\z/}
384
442
  end
385
443
  end
386
444
  end
@@ -134,4 +134,44 @@ describe "Database transactions" do
134
134
  @d.count.should == i + 1
135
135
  end
136
136
  end
137
+
138
+ if (! defined?(RUBY_ENGINE) or RUBY_ENGINE == 'ruby' or (RUBY_ENGINE == 'rbx' && ![[:do, :sqlite], [:tinytds, :mssql]].include?([INTEGRATION_DB.adapter_scheme, INTEGRATION_DB.database_type]))) and RUBY_VERSION < '1.9'
139
+ specify "should handle Thread#kill for transactions inside threads" do
140
+ q = Queue.new
141
+ q1 = Queue.new
142
+ t = Thread.new do
143
+ @db.transaction do
144
+ @d << {:name => 'abc', :value => 1}
145
+ q1.push nil
146
+ q.pop
147
+ @d << {:name => 'def', :value => 2}
148
+ end
149
+ end
150
+ q1.pop
151
+ t.kill
152
+ @d.count.should == 0
153
+ end
154
+
155
+ if INTEGRATION_DB.supports_savepoints?
156
+ specify "should handle Thread#kill for transactions with savepoints inside threads" do
157
+ q = Queue.new
158
+ q1 = Queue.new
159
+ t = Thread.new do
160
+ @db.transaction do
161
+ @d << {:name => 'abc', :value => 1}
162
+ @db.transaction(:savepoint=>true) do
163
+ @d << {:name => 'def', :value => 2}
164
+ q1.push nil
165
+ q.pop
166
+ @d << {:name => 'ghi', :value => 3}
167
+ end
168
+ @d << {:name => 'jkl', :value => 4}
169
+ end
170
+ end
171
+ q1.pop
172
+ t.kill
173
+ @d.count.should == 0
174
+ end
175
+ end
176
+ end
137
177
  end
@@ -1370,7 +1370,7 @@ describe Sequel::Model, "one_to_many" do
1370
1370
  @c2.one_to_many :attributes, :class => @c1
1371
1371
  n = @c2.new(:id => 1234)
1372
1372
  a = @c1.new(:id => 2345)
1373
- def a.valid?(opts); false; end
1373
+ def a.validate() errors.add(:id, 'foo') end
1374
1374
  proc{n.add_attribute(a)}.should raise_error(Sequel::Error)
1375
1375
  proc{n.remove_attribute(a)}.should raise_error(Sequel::Error)
1376
1376
  end
@@ -1379,7 +1379,7 @@ describe Sequel::Model, "one_to_many" do
1379
1379
  @c2.one_to_many :attributes, :class => @c1, :validate=>false
1380
1380
  n = @c2.new(:id => 1234)
1381
1381
  a = @c1.new(:id => 2345)
1382
- def a.valid?(opts); false; end
1382
+ def a.validate() errors.add(:id, 'foo') end
1383
1383
  n.add_attribute(a).should == a
1384
1384
  n.remove_attribute(a).should == a
1385
1385
  end
@@ -2282,7 +2282,7 @@ describe Sequel::Model, "many_to_many" do
2282
2282
  @c2.many_to_many :attributes, :class => @c1
2283
2283
  n = @c1.new
2284
2284
  a = @c2.load(:id=>123)
2285
- def n.valid?(opts); false; end
2285
+ def n.validate() errors.add(:id, 'foo') end
2286
2286
  proc{a.add_attribute(n)}.should raise_error(Sequel::ValidationFailed)
2287
2287
  end
2288
2288
 
@@ -2291,7 +2291,7 @@ describe Sequel::Model, "many_to_many" do
2291
2291
  n = @c1.new
2292
2292
  n.raise_on_save_failure = false
2293
2293
  a = @c2.load(:id=>123)
2294
- def n.valid?(opts); false; end
2294
+ def n.validate() errors.add(:id, 'foo') end
2295
2295
  proc{a.add_attribute(n)}.should raise_error(Sequel::Error)
2296
2296
  end
2297
2297
 
@@ -2299,7 +2299,7 @@ describe Sequel::Model, "many_to_many" do
2299
2299
  @c2.many_to_many :attributes, :class => @c1, :validate=>false
2300
2300
  n = @c1.new
2301
2301
  a = @c2.load(:id=>123)
2302
- def n.valid?(opts); false; end
2302
+ def n.validate() errors.add(:id, 'foo') end
2303
2303
  a.add_attribute(n)
2304
2304
  n.new?.should == false
2305
2305
  end
@@ -2795,7 +2795,7 @@ describe "Filtering by associations" do
2795
2795
  end
2796
2796
 
2797
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)))'
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
2799
  end
2800
2800
 
2801
2801
  it "should be able to filter on many_to_one associations with composite keys" do
@@ -2811,7 +2811,7 @@ describe "Filtering by associations" do
2811
2811
  end
2812
2812
 
2813
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))))'
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
2815
  end
2816
2816
 
2817
2817
  it "should work inside a complex filter" do
@@ -2828,16 +2828,357 @@ describe "Filtering by associations" do
2828
2828
  it "should raise for an invalid association type" do
2829
2829
  @Album.many_to_many :iatags, :clone=>:tags
2830
2830
  @Album.association_reflection(:iatags)[:type] = :foo
2831
- proc{@Album.filter(:mtmtags=>@Tag.load(:id=>3)).sql}.should raise_error(Sequel::Error)
2831
+ proc{@Album.filter(:iatags=>@Tag.load(:id=>3)).sql}.should raise_error(Sequel::Error)
2832
2832
  end
2833
2833
 
2834
2834
  it "should raise for an invalid associated object class " do
2835
2835
  proc{@Album.filter(:tags=>@Artist.load(:id=>3)).sql}.should raise_error(Sequel::Error)
2836
2836
  end
2837
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
+
2838
2851
  it "should work correctly in subclasses" do
2839
2852
  c = Class.new(@Album)
2840
2853
  c.many_to_one :sartist, :class=>@Artist
2841
2854
  c.filter(:sartist=>@Artist.load(:id=>3)).sql.should == 'SELECT * FROM albums WHERE (sartist_id = 3)'
2842
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
2843
3184
  end