sequel 3.31.0 → 3.32.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. data/CHANGELOG +54 -0
  2. data/MIT-LICENSE +1 -1
  3. data/doc/advanced_associations.rdoc +17 -0
  4. data/doc/association_basics.rdoc +74 -30
  5. data/doc/release_notes/3.32.0.txt +202 -0
  6. data/doc/schema_modification.rdoc +1 -1
  7. data/lib/sequel/adapters/jdbc/db2.rb +7 -0
  8. data/lib/sequel/adapters/jdbc/derby.rb +13 -0
  9. data/lib/sequel/adapters/jdbc/h2.rb +10 -1
  10. data/lib/sequel/adapters/jdbc/hsqldb.rb +7 -0
  11. data/lib/sequel/adapters/jdbc/oracle.rb +7 -0
  12. data/lib/sequel/adapters/mock.rb +4 -0
  13. data/lib/sequel/adapters/mysql.rb +3 -0
  14. data/lib/sequel/adapters/oracle.rb +7 -3
  15. data/lib/sequel/adapters/shared/db2.rb +9 -2
  16. data/lib/sequel/adapters/shared/mssql.rb +48 -2
  17. data/lib/sequel/adapters/shared/mysql.rb +24 -4
  18. data/lib/sequel/adapters/shared/oracle.rb +7 -6
  19. data/lib/sequel/adapters/shared/progress.rb +1 -1
  20. data/lib/sequel/adapters/shared/sqlite.rb +16 -10
  21. data/lib/sequel/core.rb +22 -0
  22. data/lib/sequel/database/query.rb +13 -4
  23. data/lib/sequel/dataset/actions.rb +20 -11
  24. data/lib/sequel/dataset/mutation.rb +7 -1
  25. data/lib/sequel/dataset/prepared_statements.rb +11 -0
  26. data/lib/sequel/dataset/sql.rb +21 -24
  27. data/lib/sequel/extensions/query.rb +1 -1
  28. data/lib/sequel/model.rb +5 -2
  29. data/lib/sequel/model/associations.rb +70 -16
  30. data/lib/sequel/model/base.rb +11 -6
  31. data/lib/sequel/plugins/active_model.rb +13 -1
  32. data/lib/sequel/plugins/composition.rb +43 -10
  33. data/lib/sequel/plugins/many_through_many.rb +4 -1
  34. data/lib/sequel/plugins/nested_attributes.rb +65 -10
  35. data/lib/sequel/plugins/serialization.rb +13 -8
  36. data/lib/sequel/plugins/serialization_modification_detection.rb +22 -10
  37. data/lib/sequel/version.rb +1 -1
  38. data/spec/adapters/mssql_spec.rb +33 -10
  39. data/spec/adapters/mysql_spec.rb +111 -91
  40. data/spec/adapters/oracle_spec.rb +18 -0
  41. data/spec/core/database_spec.rb +1 -0
  42. data/spec/core/dataset_spec.rb +110 -15
  43. data/spec/extensions/active_model_spec.rb +13 -0
  44. data/spec/extensions/many_through_many_spec.rb +14 -14
  45. data/spec/extensions/query_spec.rb +6 -0
  46. data/spec/extensions/serialization_modification_detection_spec.rb +36 -1
  47. data/spec/extensions/serialization_spec.rb +9 -0
  48. data/spec/integration/associations_test.rb +278 -154
  49. data/spec/integration/dataset_test.rb +39 -2
  50. data/spec/integration/plugin_test.rb +63 -3
  51. data/spec/integration/prepared_statement_test.rb +10 -3
  52. data/spec/integration/schema_test.rb +61 -14
  53. data/spec/integration/transaction_test.rb +10 -0
  54. data/spec/model/associations_spec.rb +170 -80
  55. data/spec/model/hooks_spec.rb +40 -0
  56. metadata +4 -2
@@ -31,6 +31,24 @@ describe "An Oracle database" do
31
31
  ORACLE_DB.pool.size.should == 0
32
32
  end
33
33
 
34
+ specify "should have working view_exists?" do
35
+ begin
36
+ ORACLE_DB.view_exists?(:cats).should be_false
37
+ ORACLE_DB.create_view(:cats, ORACLE_DB[:categories])
38
+ ORACLE_DB.view_exists?(:cats).should be_true
39
+ om = ORACLE_DB.identifier_output_method
40
+ im = ORACLE_DB.identifier_input_method
41
+ ORACLE_DB.identifier_output_method = :reverse
42
+ ORACLE_DB.identifier_input_method = :reverse
43
+ ORACLE_DB.view_exists?(:STAC).should be_true
44
+ ORACLE_DB.view_exists?(:cats).should be_false
45
+ ensure
46
+ ORACLE_DB.identifier_output_method = om
47
+ ORACLE_DB.identifier_input_method = im
48
+ ORACLE_DB.drop_view(:cats)
49
+ end
50
+ end
51
+
34
52
  specify "should be able to get current sequence value with SQL" do
35
53
  begin
36
54
  ORACLE_DB.create_table!(:foo){primary_key :id}
@@ -566,6 +566,7 @@ describe "Database#table_exists?" do
566
566
  specify "should try to select the first record from the table's dataset" do
567
567
  db = Sequel.mock(:fetch=>[Sequel::Error, [], [{:a=>1}]])
568
568
  db.table_exists?(:a).should be_false
569
+ db.sqls.should == ["SELECT NULL FROM a LIMIT 1"]
569
570
  db.table_exists?(:b).should be_true
570
571
  db.table_exists?(:c).should be_true
571
572
  end
@@ -495,29 +495,42 @@ describe "Dataset#where" do
495
495
  "SELECT * FROM test WHERE (gdp > (SELECT avg(gdp) FROM test WHERE (region = 'Asia')))"
496
496
  end
497
497
 
498
+ specify "should handle all types of IN/NOT IN queries with empty arrays" do
499
+ @dataset.filter(:id => []).sql.should == "SELECT * FROM test WHERE (id != id)"
500
+ @dataset.filter([:id1, :id2] => []).sql.should == "SELECT * FROM test WHERE ((id1 != id1) AND (id2 != id2))"
501
+ @dataset.exclude(:id => []).sql.should == "SELECT * FROM test WHERE (id = id)"
502
+ @dataset.exclude([:id1, :id2] => []).sql.should == "SELECT * FROM test WHERE ((id1 = id1) AND (id2 = id2))"
503
+ end
504
+
505
+ specify "should handle all types of IN/NOT IN queries with empty arrays" do
506
+ begin
507
+ Sequel.empty_array_handle_nulls = false
508
+ @dataset.filter(:id => []).sql.should == "SELECT * FROM test WHERE (1 = 0)"
509
+ @dataset.filter([:id1, :id2] => []).sql.should == "SELECT * FROM test WHERE (1 = 0)"
510
+ @dataset.exclude(:id => []).sql.should == "SELECT * FROM test WHERE (1 = 1)"
511
+ @dataset.exclude([:id1, :id2] => []).sql.should == "SELECT * FROM test WHERE (1 = 1)"
512
+ ensure
513
+ Sequel.empty_array_handle_nulls = true
514
+ end
515
+ end
516
+
498
517
  specify "should handle all types of IN/NOT IN queries" do
499
518
  @dataset.filter(:id => @d1.select(:id)).sql.should == "SELECT * FROM test WHERE (id IN (SELECT id FROM test WHERE (region = 'Asia')))"
500
- @dataset.filter(:id => []).sql.should == "SELECT * FROM test WHERE (id != id)"
501
519
  @dataset.filter(:id => [1, 2]).sql.should == "SELECT * FROM test WHERE (id IN (1, 2))"
502
520
  @dataset.filter([:id1, :id2] => @d1.select(:id1, :id2)).sql.should == "SELECT * FROM test WHERE ((id1, id2) IN (SELECT id1, id2 FROM test WHERE (region = 'Asia')))"
503
- @dataset.filter([:id1, :id2] => []).sql.should == "SELECT * FROM test WHERE ((id1 != id1) AND (id2 != id2))"
504
521
  @dataset.filter([:id1, :id2] => [[1, 2], [3,4]].sql_array).sql.should == "SELECT * FROM test WHERE ((id1, id2) IN ((1, 2), (3, 4)))"
505
522
  @dataset.filter([:id1, :id2] => [[1, 2], [3,4]]).sql.should == "SELECT * FROM test WHERE ((id1, id2) IN ((1, 2), (3, 4)))"
506
523
 
507
524
  @dataset.exclude(:id => @d1.select(:id)).sql.should == "SELECT * FROM test WHERE (id NOT IN (SELECT id FROM test WHERE (region = 'Asia')))"
508
- @dataset.exclude(:id => []).sql.should == "SELECT * FROM test WHERE (1 = 1)"
509
525
  @dataset.exclude(:id => [1, 2]).sql.should == "SELECT * FROM test WHERE (id NOT IN (1, 2))"
510
526
  @dataset.exclude([:id1, :id2] => @d1.select(:id1, :id2)).sql.should == "SELECT * FROM test WHERE ((id1, id2) NOT IN (SELECT id1, id2 FROM test WHERE (region = 'Asia')))"
511
- @dataset.exclude([:id1, :id2] => []).sql.should == "SELECT * FROM test WHERE (1 = 1)"
512
527
  @dataset.exclude([:id1, :id2] => [[1, 2], [3,4]].sql_array).sql.should == "SELECT * FROM test WHERE ((id1, id2) NOT IN ((1, 2), (3, 4)))"
513
528
  @dataset.exclude([:id1, :id2] => [[1, 2], [3,4]]).sql.should == "SELECT * FROM test WHERE ((id1, id2) NOT IN ((1, 2), (3, 4)))"
514
529
  end
515
530
 
516
531
  specify "should handle IN/NOT IN queries with multiple columns and an array where the database doesn't support it" do
517
532
  @dataset.meta_def(:supports_multiple_column_in?){false}
518
- @dataset.filter([:id1, :id2] => []).sql.should == "SELECT * FROM test WHERE ((id1 != id1) AND (id2 != id2))"
519
533
  @dataset.filter([:id1, :id2] => [[1, 2], [3,4]].sql_array).sql.should == "SELECT * FROM test WHERE (((id1 = 1) AND (id2 = 2)) OR ((id1 = 3) AND (id2 = 4)))"
520
- @dataset.exclude([:id1, :id2] => []).sql.should == "SELECT * FROM test WHERE (1 = 1)"
521
534
  @dataset.exclude([:id1, :id2] => [[1, 2], [3,4]].sql_array).sql.should == "SELECT * FROM test WHERE (((id1 != 1) OR (id2 != 2)) AND ((id1 != 3) OR (id2 != 4)))"
522
535
  end
523
536
 
@@ -537,10 +550,25 @@ describe "Dataset#where" do
537
550
  d1 = db[:test].select(:id1, :id2).filter(:region=>'Asia').columns(:id1, :id2)
538
551
  @dataset.filter([:id1, :id2] => d1).sql.should == "SELECT * FROM test WHERE ((id1 != id1) AND (id2 != id2))"
539
552
  db.sqls.should == ["SELECT id1, id2 FROM test WHERE (region = 'Asia')"]
540
- @dataset.exclude([:id1, :id2] => d1).sql.should == "SELECT * FROM test WHERE (1 = 1)"
553
+ @dataset.exclude([:id1, :id2] => d1).sql.should == "SELECT * FROM test WHERE ((id1 = id1) AND (id2 = id2))"
541
554
  db.sqls.should == ["SELECT id1, id2 FROM test WHERE (region = 'Asia')"]
542
555
  end
543
556
 
557
+ specify "should handle IN/NOT IN queries with multiple columns and an empty dataset where the database doesn't support it with correct NULL handling" do
558
+ begin
559
+ Sequel.empty_array_handle_nulls = false
560
+ @dataset.meta_def(:supports_multiple_column_in?){false}
561
+ db = Sequel.mock
562
+ d1 = db[:test].select(:id1, :id2).filter(:region=>'Asia').columns(:id1, :id2)
563
+ @dataset.filter([:id1, :id2] => d1).sql.should == "SELECT * FROM test WHERE (1 = 0)"
564
+ db.sqls.should == ["SELECT id1, id2 FROM test WHERE (region = 'Asia')"]
565
+ @dataset.exclude([:id1, :id2] => d1).sql.should == "SELECT * FROM test WHERE (1 = 1)"
566
+ db.sqls.should == ["SELECT id1, id2 FROM test WHERE (region = 'Asia')"]
567
+ ensure
568
+ Sequel.empty_array_handle_nulls = true
569
+ end
570
+ end
571
+
544
572
  specify "should handle IN/NOT IN queries for datasets with row_procs" do
545
573
  @dataset.meta_def(:supports_multiple_column_in?){false}
546
574
  db = Sequel.mock(:fetch=>[{:id1=>1, :id2=>2}, {:id1=>3, :id2=>4}])
@@ -1581,10 +1609,20 @@ describe "Dataset#limit" do
1581
1609
  end
1582
1610
 
1583
1611
  describe "Dataset#naked" do
1584
- specify "should remove any existing row_proc" do
1612
+ specify "should returned clone dataset without row_proc" do
1585
1613
  d = Sequel::Dataset.new(nil)
1586
1614
  d.row_proc = Proc.new{|r| r}
1587
1615
  d.naked.row_proc.should be_nil
1616
+ d.row_proc.should_not be_nil
1617
+ end
1618
+ end
1619
+
1620
+ describe "Dataset#naked!" do
1621
+ specify "should remove any existing row_proc" do
1622
+ d = Sequel::Dataset.new(nil)
1623
+ d.row_proc = Proc.new{|r| r}
1624
+ d.naked!.row_proc.should be_nil
1625
+ d.row_proc.should be_nil
1588
1626
  end
1589
1627
  end
1590
1628
 
@@ -2778,10 +2816,10 @@ describe "Dataset#multi_insert" do
2778
2816
 
2779
2817
  specify "should accept string keys as column names" do
2780
2818
  @ds.multi_insert([{'x'=>1, 'y'=>2}, {'x'=>3, 'y'=>4}])
2781
- @db.sqls.should == ['BEGIN',
2782
- "INSERT INTO items (x, y) VALUES (1, 2)",
2783
- "INSERT INTO items (x, y) VALUES (3, 4)",
2784
- 'COMMIT']
2819
+ sqls = @db.sqls
2820
+ ["INSERT INTO items (x, y) VALUES (1, 2)", "INSERT INTO items (y, x) VALUES (2, 1)"].should include(sqls.slice!(1))
2821
+ ["INSERT INTO items (x, y) VALUES (3, 4)", "INSERT INTO items (y, x) VALUES (4, 3)"].should include(sqls.slice!(1))
2822
+ sqls.should == ['BEGIN', 'COMMIT']
2785
2823
  end
2786
2824
 
2787
2825
  specify "should not do anything if no hashes are provided" do
@@ -3096,12 +3134,16 @@ describe "Dataset prepared statements and bound variables " do
3096
3134
 
3097
3135
  specify "#call should take a type and bind hash and interpolate it" do
3098
3136
  @ds.filter(:num=>:$n).call(:select, :n=>1)
3137
+ @ds.filter(:num=>:$n).call([:map, :a], :n=>1)
3138
+ @ds.filter(:num=>:$n).call([:to_hash, :a, :b], :n=>1)
3099
3139
  @ds.filter(:num=>:$n).call(:first, :n=>1)
3100
3140
  @ds.filter(:num=>:$n).call(:delete, :n=>1)
3101
3141
  @ds.filter(:num=>:$n).call(:update, {:n=>1, :n2=>2}, :num=>:$n2)
3102
3142
  @ds.call(:insert, {:n=>1}, :num=>:$n)
3103
3143
  @ds.call(:insert_select, {:n=>1}, :num=>:$n)
3104
3144
  @db.sqls.should == ['SELECT * FROM items WHERE (num = 1)',
3145
+ 'SELECT * FROM items WHERE (num = 1)',
3146
+ 'SELECT * FROM items WHERE (num = 1)',
3105
3147
  'SELECT * FROM items WHERE (num = 1) LIMIT 1',
3106
3148
  'DELETE FROM items WHERE (num = 1)',
3107
3149
  'UPDATE items SET num = 2 WHERE (num = 1)',
@@ -3112,20 +3154,26 @@ describe "Dataset prepared statements and bound variables " do
3112
3154
  specify "#prepare should take a type and name and store it in the database for later use with call" do
3113
3155
  pss = []
3114
3156
  pss << @ds.filter(:num=>:$n).prepare(:select, :sn)
3157
+ pss << @ds.filter(:num=>:$n).prepare([:map, :a], :sm)
3158
+ pss << @ds.filter(:num=>:$n).prepare([:to_hash, :a, :b], :sh)
3115
3159
  pss << @ds.filter(:num=>:$n).prepare(:first, :fn)
3116
3160
  pss << @ds.filter(:num=>:$n).prepare(:delete, :dn)
3117
3161
  pss << @ds.filter(:num=>:$n).prepare(:update, :un, :num=>:$n2)
3118
3162
  pss << @ds.prepare(:insert, :in, :num=>:$n)
3119
3163
  pss << @ds.prepare(:insert_select, :ins, :num=>:$n)
3120
- @db.prepared_statements.keys.sort_by{|k| k.to_s}.should == [:dn, :fn, :in, :ins, :sn, :un]
3121
- [:sn, :fn, :dn, :un, :in, :ins].each_with_index{|x, i| @db.prepared_statements[x].should == pss[i]}
3164
+ @db.prepared_statements.keys.sort_by{|k| k.to_s}.should == [:dn, :fn, :in, :ins, :sh, :sm, :sn, :un]
3165
+ [:sn, :sm, :sh, :fn, :dn, :un, :in, :ins].each_with_index{|x, i| @db.prepared_statements[x].should == pss[i]}
3122
3166
  @db.call(:sn, :n=>1)
3167
+ @db.call(:sm, :n=>1)
3168
+ @db.call(:sh, :n=>1)
3123
3169
  @db.call(:fn, :n=>1)
3124
3170
  @db.call(:dn, :n=>1)
3125
3171
  @db.call(:un, :n=>1, :n2=>2)
3126
3172
  @db.call(:in, :n=>1)
3127
3173
  @db.call(:ins, :n=>1)
3128
3174
  @db.sqls.should == ['SELECT * FROM items WHERE (num = 1)',
3175
+ 'SELECT * FROM items WHERE (num = 1)',
3176
+ 'SELECT * FROM items WHERE (num = 1)',
3129
3177
  'SELECT * FROM items WHERE (num = 1) LIMIT 1',
3130
3178
  'DELETE FROM items WHERE (num = 1)',
3131
3179
  'UPDATE items SET num = 2 WHERE (num = 1)',
@@ -3740,6 +3788,12 @@ describe "Sequel::Dataset#select_map" do
3740
3788
  @ds.db.sqls.should == ['SELECT a.b FROM t']
3741
3789
  end
3742
3790
 
3791
+ specify "should raise if multiple arguments and can't determine alias" do
3792
+ proc{@ds.select_map([:a.sql_function, :b])}.should raise_error(Sequel::Error)
3793
+ proc{@ds.select_map(:a.sql_function){b}}.should raise_error(Sequel::Error)
3794
+ proc{@ds.select_map{[a{}, b]}}.should raise_error(Sequel::Error)
3795
+ end
3796
+
3743
3797
  specify "should handle implicit aliases in arguments" do
3744
3798
  @ds.select_map(:a___b).should == [1, 2]
3745
3799
  @ds.db.sqls.should == ['SELECT a AS b FROM t']
@@ -3750,11 +3804,31 @@ describe "Sequel::Dataset#select_map" do
3750
3804
  @ds.db.sqls.should == ['SELECT a AS b FROM t']
3751
3805
  end
3752
3806
 
3807
+ specify "should handle identifiers with strings" do
3808
+ @ds.select_map([Sequel::SQL::Identifier.new('c'), :c]).should == [[1, 1], [2, 2]]
3809
+ @ds.db.sqls.should == ['SELECT c, c FROM t']
3810
+ end
3811
+
3753
3812
  specify "should accept a block" do
3754
3813
  @ds.select_map{a(t__c)}.should == [1, 2]
3755
3814
  @ds.db.sqls.should == ['SELECT a(t.c) FROM t']
3756
3815
  end
3757
3816
 
3817
+ specify "should accept a block with an array of columns" do
3818
+ @ds.select_map{[a(t__c).as(c), a(t__c).as(c)]}.should == [[1, 1], [2, 2]]
3819
+ @ds.db.sqls.should == ['SELECT a(t.c) AS c, a(t.c) AS c FROM t']
3820
+ end
3821
+
3822
+ specify "should accept a block with a column" do
3823
+ @ds.select_map(:c){a(t__c).as(c)}.should == [[1, 1], [2, 2]]
3824
+ @ds.db.sqls.should == ['SELECT c, a(t.c) AS c FROM t']
3825
+ end
3826
+
3827
+ specify "should accept a block and array of arguments" do
3828
+ @ds.select_map([:c, :c]){[a(t__c).as(c), a(t__c).as(c)]}.should == [[1, 1, 1, 1], [2, 2, 2, 2]]
3829
+ @ds.db.sqls.should == ['SELECT c, c, a(t.c) AS c, a(t.c) AS c FROM t']
3830
+ end
3831
+
3758
3832
  specify "should handle an array of columns" do
3759
3833
  @ds.select_map([:c, :c]).should == [[1, 1], [2, 2]]
3760
3834
  @ds.db.sqls.should == ['SELECT c, c FROM t']
@@ -3783,6 +3857,12 @@ describe "Sequel::Dataset#select_order_map" do
3783
3857
  @ds.db.sqls.should == ['SELECT a.b FROM t ORDER BY a.b']
3784
3858
  end
3785
3859
 
3860
+ specify "should raise if multiple arguments and can't determine alias" do
3861
+ proc{@ds.select_order_map([:a.sql_function, :b])}.should raise_error(Sequel::Error)
3862
+ proc{@ds.select_order_map(:a.sql_function){b}}.should raise_error(Sequel::Error)
3863
+ proc{@ds.select_order_map{[a{}, b]}}.should raise_error(Sequel::Error)
3864
+ end
3865
+
3786
3866
  specify "should handle implicit aliases in arguments" do
3787
3867
  @ds.select_order_map(:a___b).should == [1, 2]
3788
3868
  @ds.db.sqls.should == ['SELECT a AS b FROM t ORDER BY a']
@@ -3808,6 +3888,21 @@ describe "Sequel::Dataset#select_order_map" do
3808
3888
  @ds.db.sqls.should == ['SELECT a(t.c) FROM t ORDER BY a(t.c)']
3809
3889
  end
3810
3890
 
3891
+ specify "should accept a block with an array of columns" do
3892
+ @ds.select_order_map{[c.desc, a(t__c).as(c)]}.should == [[1, 1], [2, 2]]
3893
+ @ds.db.sqls.should == ['SELECT c, a(t.c) AS c FROM t ORDER BY c DESC, a(t.c)']
3894
+ end
3895
+
3896
+ specify "should accept a block with a column" do
3897
+ @ds.select_order_map(:c){a(t__c).as(c)}.should == [[1, 1], [2, 2]]
3898
+ @ds.db.sqls.should == ['SELECT c, a(t.c) AS c FROM t ORDER BY c, a(t.c)']
3899
+ end
3900
+
3901
+ specify "should accept a block and array of arguments" do
3902
+ @ds.select_order_map([:c, :c]){[a(t__c).as(c), c.desc]}.should == [[1, 1, 1, 1], [2, 2, 2, 2]]
3903
+ @ds.db.sqls.should == ['SELECT c, c, a(t.c) AS c, c FROM t ORDER BY c, c, a(t.c), c DESC']
3904
+ end
3905
+
3811
3906
  specify "should handle an array of columns" do
3812
3907
  @ds.select_order_map([:c, :c]).should == [[1, 1], [2, 2]]
3813
3908
  @ds.db.sqls.should == ['SELECT c, c FROM t ORDER BY c, c']
@@ -3873,7 +3968,7 @@ describe "Sequel::Dataset#select_hash" do
3873
3968
  end
3874
3969
 
3875
3970
  specify "should raise an error if the resulting symbol cannot be determined" do
3876
- proc{@ds.select_hash(:c.as(:a), 'foo')}.should raise_error(Sequel::Error)
3971
+ proc{@ds.select_hash(:c.as(:a), :b.sql_function)}.should raise_error(Sequel::Error)
3877
3972
  end
3878
3973
  end
3879
3974
 
@@ -24,6 +24,11 @@ describe "ActiveModel plugin" do
24
24
  columns :id, :id2
25
25
  def delete; end
26
26
  end
27
+ module ::Blog
28
+ class Post < Sequel::Model
29
+ plugin :active_model
30
+ end
31
+ end
27
32
  @c = AMLintTest
28
33
  @c.plugin :active_model
29
34
  @m = @model = @c.new
@@ -33,6 +38,7 @@ describe "ActiveModel plugin" do
33
38
  def teardown
34
39
  super
35
40
  Object.send(:remove_const, :AMLintTest)
41
+ Object.send(:remove_const, :Blog)
36
42
  end
37
43
  include ActiveModel::Lint::Tests
38
44
 
@@ -80,6 +86,13 @@ describe "ActiveModel plugin" do
80
86
  assert_equal false, @m.persisted?
81
87
  assert_equal false, @o.persisted?
82
88
  end
89
+
90
+ # Should return self, not a proxy object
91
+ def test__to_partial_path
92
+ assert_equal 'am_lint_tests/am_lint_test', @m.to_partial_path
93
+ assert_equal 'blog/posts/post', Blog::Post.new.to_partial_path
94
+ end
95
+
83
96
  end
84
97
  if defined?(MiniTest::Unit)
85
98
  tc.instance_methods.map{|x| x.to_s}.reject{|n| n !~ /\Atest_/}.each do |m|
@@ -101,52 +101,52 @@ describe Sequel::Model, "many_through_many" do
101
101
 
102
102
  it "should allowing filtering by many_through_many associations" do
103
103
  @c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]]
104
- @c1.filter(:tags=>@c2.load(:id=>1234)).sql.should == 'SELECT * FROM artists WHERE (id IN (SELECT albums_artists.artist_id FROM albums_artists INNER JOIN albums ON (albums.id = albums_artists.album_id) INNER JOIN albums_tags ON (albums_tags.album_id = albums.id) WHERE ((albums_tags.tag_id = 1234) AND (albums_artists.artist_id IS NOT NULL))))'
104
+ @c1.filter(:tags=>@c2.load(:id=>1234)).sql.should == 'SELECT * FROM artists WHERE (artists.id IN (SELECT albums_artists.artist_id FROM albums_artists INNER JOIN albums ON (albums.id = albums_artists.album_id) INNER JOIN albums_tags ON (albums_tags.album_id = albums.id) WHERE ((albums_tags.tag_id = 1234) AND (albums_artists.artist_id IS NOT NULL))))'
105
105
  end
106
106
 
107
107
  it "should allowing filtering by many_through_many associations with a single through table" do
108
108
  @c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id]]
109
- @c1.filter(:tags=>@c2.load(:id=>1234)).sql.should == 'SELECT * FROM artists WHERE (id IN (SELECT albums_artists.artist_id FROM albums_artists WHERE ((albums_artists.album_id = 1234) AND (albums_artists.artist_id IS NOT NULL))))'
109
+ @c1.filter(:tags=>@c2.load(:id=>1234)).sql.should == 'SELECT * FROM artists WHERE (artists.id IN (SELECT albums_artists.artist_id FROM albums_artists WHERE ((albums_artists.album_id = 1234) AND (albums_artists.artist_id IS NOT NULL))))'
110
110
  end
111
111
 
112
112
  it "should allowing filtering by many_through_many associations with aliased tables" do
113
113
  @c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums_artists, :id, :id], [:albums_artists, :album_id, :tag_id]]
114
- @c1.filter(:tags=>@c2.load(:id=>1234)).sql.should == 'SELECT * FROM artists WHERE (id IN (SELECT albums_artists.artist_id FROM albums_artists INNER JOIN albums_artists AS albums_artists_0 ON (albums_artists_0.id = albums_artists.album_id) INNER JOIN albums_artists AS albums_artists_1 ON (albums_artists_1.album_id = albums_artists_0.id) WHERE ((albums_artists_1.tag_id = 1234) AND (albums_artists.artist_id IS NOT NULL))))'
114
+ @c1.filter(:tags=>@c2.load(:id=>1234)).sql.should == 'SELECT * FROM artists WHERE (artists.id IN (SELECT albums_artists.artist_id FROM albums_artists INNER JOIN albums_artists AS albums_artists_0 ON (albums_artists_0.id = albums_artists.album_id) INNER JOIN albums_artists AS albums_artists_1 ON (albums_artists_1.album_id = albums_artists_0.id) WHERE ((albums_artists_1.tag_id = 1234) AND (albums_artists.artist_id IS NOT NULL))))'
115
115
  end
116
116
 
117
117
  it "should allowing filtering by many_through_many associations with composite keys" do
118
118
  @c1.many_through_many :tags, [[:albums_artists, [:b1, :b2], [:c1, :c2]], [:albums, [:d1, :d2], [:e1, :e2]], [:albums_tags, [:f1, :f2], [:g1, :g2]]], :right_primary_key=>[:h1, :h2], :left_primary_key=>[:id, :yyy]
119
- @c1.filter(:tags=>@c2.load(:h1=>1234, :h2=>85)).sql.should == 'SELECT * FROM artists WHERE ((id, yyy) IN (SELECT albums_artists.b1, albums_artists.b2 FROM albums_artists INNER JOIN albums ON ((albums.d1 = albums_artists.c1) AND (albums.d2 = albums_artists.c2)) INNER JOIN albums_tags ON ((albums_tags.f1 = albums.e1) AND (albums_tags.f2 = albums.e2)) WHERE ((albums_tags.g1 = 1234) AND (albums_tags.g2 = 85) AND (albums_artists.b1 IS NOT NULL) AND (albums_artists.b2 IS NOT NULL))))'
119
+ @c1.filter(:tags=>@c2.load(:h1=>1234, :h2=>85)).sql.should == 'SELECT * FROM artists WHERE ((artists.id, artists.yyy) IN (SELECT albums_artists.b1, albums_artists.b2 FROM albums_artists INNER JOIN albums ON ((albums.d1 = albums_artists.c1) AND (albums.d2 = albums_artists.c2)) INNER JOIN albums_tags ON ((albums_tags.f1 = albums.e1) AND (albums_tags.f2 = albums.e2)) WHERE ((albums_tags.g1 = 1234) AND (albums_tags.g2 = 85) AND (albums_artists.b1 IS NOT NULL) AND (albums_artists.b2 IS NOT NULL))))'
120
120
  end
121
121
 
122
122
  it "should allowing excluding by many_through_many associations" do
123
123
  @c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]]
124
- @c1.exclude(:tags=>@c2.load(:id=>1234)).sql.should == 'SELECT * FROM artists WHERE ((id NOT IN (SELECT albums_artists.artist_id FROM albums_artists INNER JOIN albums ON (albums.id = albums_artists.album_id) INNER JOIN albums_tags ON (albums_tags.album_id = albums.id) WHERE ((albums_tags.tag_id = 1234) AND (albums_artists.artist_id IS NOT NULL)))) OR (id IS NULL))'
124
+ @c1.exclude(:tags=>@c2.load(:id=>1234)).sql.should == 'SELECT * FROM artists WHERE ((artists.id NOT IN (SELECT albums_artists.artist_id FROM albums_artists INNER JOIN albums ON (albums.id = albums_artists.album_id) INNER JOIN albums_tags ON (albums_tags.album_id = albums.id) WHERE ((albums_tags.tag_id = 1234) AND (albums_artists.artist_id IS NOT NULL)))) OR (artists.id IS NULL))'
125
125
  end
126
126
 
127
127
  it "should allowing excluding by many_through_many associations with composite keys" do
128
128
  @c1.many_through_many :tags, [[:albums_artists, [:b1, :b2], [:c1, :c2]], [:albums, [:d1, :d2], [:e1, :e2]], [:albums_tags, [:f1, :f2], [:g1, :g2]]], :right_primary_key=>[:h1, :h2], :left_primary_key=>[:id, :yyy]
129
- @c1.exclude(:tags=>@c2.load(:h1=>1234, :h2=>85)).sql.should == 'SELECT * FROM artists WHERE (((id, yyy) NOT IN (SELECT albums_artists.b1, albums_artists.b2 FROM albums_artists INNER JOIN albums ON ((albums.d1 = albums_artists.c1) AND (albums.d2 = albums_artists.c2)) INNER JOIN albums_tags ON ((albums_tags.f1 = albums.e1) AND (albums_tags.f2 = albums.e2)) WHERE ((albums_tags.g1 = 1234) AND (albums_tags.g2 = 85) AND (albums_artists.b1 IS NOT NULL) AND (albums_artists.b2 IS NOT NULL)))) OR (id IS NULL) OR (yyy IS NULL))'
129
+ @c1.exclude(:tags=>@c2.load(:h1=>1234, :h2=>85)).sql.should == 'SELECT * FROM artists WHERE (((artists.id, artists.yyy) NOT IN (SELECT albums_artists.b1, albums_artists.b2 FROM albums_artists INNER JOIN albums ON ((albums.d1 = albums_artists.c1) AND (albums.d2 = albums_artists.c2)) INNER JOIN albums_tags ON ((albums_tags.f1 = albums.e1) AND (albums_tags.f2 = albums.e2)) WHERE ((albums_tags.g1 = 1234) AND (albums_tags.g2 = 85) AND (albums_artists.b1 IS NOT NULL) AND (albums_artists.b2 IS NOT NULL)))) OR (artists.id IS NULL) OR (artists.yyy IS NULL))'
130
130
  end
131
131
 
132
132
  it "should allowing filtering by multiple many_through_many associations" do
133
133
  @c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]]
134
- @c1.filter(:tags=>[@c2.load(:id=>1234), @c2.load(:id=>2345)]).sql.should == 'SELECT * FROM artists WHERE (id IN (SELECT albums_artists.artist_id FROM albums_artists INNER JOIN albums ON (albums.id = albums_artists.album_id) INNER JOIN albums_tags ON (albums_tags.album_id = albums.id) WHERE ((albums_tags.tag_id IN (1234, 2345)) AND (albums_artists.artist_id IS NOT NULL))))'
134
+ @c1.filter(:tags=>[@c2.load(:id=>1234), @c2.load(:id=>2345)]).sql.should == 'SELECT * FROM artists WHERE (artists.id IN (SELECT albums_artists.artist_id FROM albums_artists INNER JOIN albums ON (albums.id = albums_artists.album_id) INNER JOIN albums_tags ON (albums_tags.album_id = albums.id) WHERE ((albums_tags.tag_id IN (1234, 2345)) AND (albums_artists.artist_id IS NOT NULL))))'
135
135
  end
136
136
 
137
137
  it "should allowing filtering by multiple many_through_many associations with composite keys" do
138
138
  @c1.many_through_many :tags, [[:albums_artists, [:b1, :b2], [:c1, :c2]], [:albums, [:d1, :d2], [:e1, :e2]], [:albums_tags, [:f1, :f2], [:g1, :g2]]], :right_primary_key=>[:h1, :h2], :left_primary_key=>[:id, :yyy]
139
- @c1.filter(:tags=>[@c2.load(:h1=>1234, :h2=>85), @c2.load(:h1=>2345, :h2=>95)]).sql.should == 'SELECT * FROM artists WHERE ((id, yyy) IN (SELECT albums_artists.b1, albums_artists.b2 FROM albums_artists INNER JOIN albums ON ((albums.d1 = albums_artists.c1) AND (albums.d2 = albums_artists.c2)) INNER JOIN albums_tags ON ((albums_tags.f1 = albums.e1) AND (albums_tags.f2 = albums.e2)) WHERE (((albums_tags.g1, albums_tags.g2) IN ((1234, 85), (2345, 95))) AND (albums_artists.b1 IS NOT NULL) AND (albums_artists.b2 IS NOT NULL))))'
139
+ @c1.filter(:tags=>[@c2.load(:h1=>1234, :h2=>85), @c2.load(:h1=>2345, :h2=>95)]).sql.should == 'SELECT * FROM artists WHERE ((artists.id, artists.yyy) IN (SELECT albums_artists.b1, albums_artists.b2 FROM albums_artists INNER JOIN albums ON ((albums.d1 = albums_artists.c1) AND (albums.d2 = albums_artists.c2)) INNER JOIN albums_tags ON ((albums_tags.f1 = albums.e1) AND (albums_tags.f2 = albums.e2)) WHERE (((albums_tags.g1, albums_tags.g2) IN ((1234, 85), (2345, 95))) AND (albums_artists.b1 IS NOT NULL) AND (albums_artists.b2 IS NOT NULL))))'
140
140
  end
141
141
 
142
142
  it "should allowing excluding by multiple many_through_many associations" do
143
143
  @c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]]
144
- @c1.exclude(:tags=>[@c2.load(:id=>1234), @c2.load(:id=>2345)]).sql.should == 'SELECT * FROM artists WHERE ((id NOT IN (SELECT albums_artists.artist_id FROM albums_artists INNER JOIN albums ON (albums.id = albums_artists.album_id) INNER JOIN albums_tags ON (albums_tags.album_id = albums.id) WHERE ((albums_tags.tag_id IN (1234, 2345)) AND (albums_artists.artist_id IS NOT NULL)))) OR (id IS NULL))'
144
+ @c1.exclude(:tags=>[@c2.load(:id=>1234), @c2.load(:id=>2345)]).sql.should == 'SELECT * FROM artists WHERE ((artists.id NOT IN (SELECT albums_artists.artist_id FROM albums_artists INNER JOIN albums ON (albums.id = albums_artists.album_id) INNER JOIN albums_tags ON (albums_tags.album_id = albums.id) WHERE ((albums_tags.tag_id IN (1234, 2345)) AND (albums_artists.artist_id IS NOT NULL)))) OR (artists.id IS NULL))'
145
145
  end
146
146
 
147
147
  it "should allowing excluding by multiple many_through_many associations with composite keys" do
148
148
  @c1.many_through_many :tags, [[:albums_artists, [:b1, :b2], [:c1, :c2]], [:albums, [:d1, :d2], [:e1, :e2]], [:albums_tags, [:f1, :f2], [:g1, :g2]]], :right_primary_key=>[:h1, :h2], :left_primary_key=>[:id, :yyy]
149
- @c1.exclude(:tags=>[@c2.load(:h1=>1234, :h2=>85), @c2.load(:h1=>2345, :h2=>95)]).sql.should == 'SELECT * FROM artists WHERE (((id, yyy) NOT IN (SELECT albums_artists.b1, albums_artists.b2 FROM albums_artists INNER JOIN albums ON ((albums.d1 = albums_artists.c1) AND (albums.d2 = albums_artists.c2)) INNER JOIN albums_tags ON ((albums_tags.f1 = albums.e1) AND (albums_tags.f2 = albums.e2)) WHERE (((albums_tags.g1, albums_tags.g2) IN ((1234, 85), (2345, 95))) AND (albums_artists.b1 IS NOT NULL) AND (albums_artists.b2 IS NOT NULL)))) OR (id IS NULL) OR (yyy IS NULL))'
149
+ @c1.exclude(:tags=>[@c2.load(:h1=>1234, :h2=>85), @c2.load(:h1=>2345, :h2=>95)]).sql.should == 'SELECT * FROM artists WHERE (((artists.id, artists.yyy) NOT IN (SELECT albums_artists.b1, albums_artists.b2 FROM albums_artists INNER JOIN albums ON ((albums.d1 = albums_artists.c1) AND (albums.d2 = albums_artists.c2)) INNER JOIN albums_tags ON ((albums_tags.f1 = albums.e1) AND (albums_tags.f2 = albums.e2)) WHERE (((albums_tags.g1, albums_tags.g2) IN ((1234, 85), (2345, 95))) AND (albums_artists.b1 IS NOT NULL) AND (albums_artists.b2 IS NOT NULL)))) OR (artists.id IS NULL) OR (artists.yyy IS NULL))'
150
150
  end
151
151
 
152
152
  it "should allowing filtering/excluding many_through_many associations with NULL values" do
@@ -157,22 +157,22 @@ describe Sequel::Model, "many_through_many" do
157
157
 
158
158
  it "should allowing filtering by many_through_many association datasets" do
159
159
  @c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]]
160
- @c1.filter(:tags=>@c2.filter(:x=>1)).sql.should == 'SELECT * FROM artists WHERE (id IN (SELECT albums_artists.artist_id FROM albums_artists INNER JOIN albums ON (albums.id = albums_artists.album_id) INNER JOIN albums_tags ON (albums_tags.album_id = albums.id) WHERE ((albums_tags.tag_id IN (SELECT id FROM tags WHERE ((x = 1) AND (id IS NOT NULL)))) AND (albums_artists.artist_id IS NOT NULL))))'
160
+ @c1.filter(:tags=>@c2.filter(:x=>1)).sql.should == 'SELECT * FROM artists WHERE (artists.id IN (SELECT albums_artists.artist_id FROM albums_artists INNER JOIN albums ON (albums.id = albums_artists.album_id) INNER JOIN albums_tags ON (albums_tags.album_id = albums.id) WHERE ((albums_tags.tag_id IN (SELECT tags.id FROM tags WHERE ((x = 1) AND (tags.id IS NOT NULL)))) AND (albums_artists.artist_id IS NOT NULL))))'
161
161
  end
162
162
 
163
163
  it "should allowing filtering by many_through_many association datasets with composite keys" do
164
164
  @c1.many_through_many :tags, [[:albums_artists, [:b1, :b2], [:c1, :c2]], [:albums, [:d1, :d2], [:e1, :e2]], [:albums_tags, [:f1, :f2], [:g1, :g2]]], :right_primary_key=>[:h1, :h2], :left_primary_key=>[:id, :yyy]
165
- @c1.filter(:tags=>@c2.filter(:x=>1)).sql.should == 'SELECT * FROM artists WHERE ((id, yyy) IN (SELECT albums_artists.b1, albums_artists.b2 FROM albums_artists INNER JOIN albums ON ((albums.d1 = albums_artists.c1) AND (albums.d2 = albums_artists.c2)) INNER JOIN albums_tags ON ((albums_tags.f1 = albums.e1) AND (albums_tags.f2 = albums.e2)) WHERE (((albums_tags.g1, albums_tags.g2) IN (SELECT h1, h2 FROM tags WHERE ((x = 1) AND (h1 IS NOT NULL) AND (h2 IS NOT NULL)))) AND (albums_artists.b1 IS NOT NULL) AND (albums_artists.b2 IS NOT NULL))))'
165
+ @c1.filter(:tags=>@c2.filter(:x=>1)).sql.should == 'SELECT * FROM artists WHERE ((artists.id, artists.yyy) IN (SELECT albums_artists.b1, albums_artists.b2 FROM albums_artists INNER JOIN albums ON ((albums.d1 = albums_artists.c1) AND (albums.d2 = albums_artists.c2)) INNER JOIN albums_tags ON ((albums_tags.f1 = albums.e1) AND (albums_tags.f2 = albums.e2)) WHERE (((albums_tags.g1, albums_tags.g2) IN (SELECT tags.h1, tags.h2 FROM tags WHERE ((x = 1) AND (tags.h1 IS NOT NULL) AND (tags.h2 IS NOT NULL)))) AND (albums_artists.b1 IS NOT NULL) AND (albums_artists.b2 IS NOT NULL))))'
166
166
  end
167
167
 
168
168
  it "should allowing excluding by many_through_many association datasets" do
169
169
  @c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]]
170
- @c1.exclude(:tags=>@c2.filter(:x=>1)).sql.should == 'SELECT * FROM artists WHERE ((id NOT IN (SELECT albums_artists.artist_id FROM albums_artists INNER JOIN albums ON (albums.id = albums_artists.album_id) INNER JOIN albums_tags ON (albums_tags.album_id = albums.id) WHERE ((albums_tags.tag_id IN (SELECT id FROM tags WHERE ((x = 1) AND (id IS NOT NULL)))) AND (albums_artists.artist_id IS NOT NULL)))) OR (id IS NULL))'
170
+ @c1.exclude(:tags=>@c2.filter(:x=>1)).sql.should == 'SELECT * FROM artists WHERE ((artists.id NOT IN (SELECT albums_artists.artist_id FROM albums_artists INNER JOIN albums ON (albums.id = albums_artists.album_id) INNER JOIN albums_tags ON (albums_tags.album_id = albums.id) WHERE ((albums_tags.tag_id IN (SELECT tags.id FROM tags WHERE ((x = 1) AND (tags.id IS NOT NULL)))) AND (albums_artists.artist_id IS NOT NULL)))) OR (artists.id IS NULL))'
171
171
  end
172
172
 
173
173
  it "should allowing excluding by many_through_many association datasets with composite keys" do
174
174
  @c1.many_through_many :tags, [[:albums_artists, [:b1, :b2], [:c1, :c2]], [:albums, [:d1, :d2], [:e1, :e2]], [:albums_tags, [:f1, :f2], [:g1, :g2]]], :right_primary_key=>[:h1, :h2], :left_primary_key=>[:id, :yyy]
175
- @c1.exclude(:tags=>@c2.filter(:x=>1)).sql.should == 'SELECT * FROM artists WHERE (((id, yyy) NOT IN (SELECT albums_artists.b1, albums_artists.b2 FROM albums_artists INNER JOIN albums ON ((albums.d1 = albums_artists.c1) AND (albums.d2 = albums_artists.c2)) INNER JOIN albums_tags ON ((albums_tags.f1 = albums.e1) AND (albums_tags.f2 = albums.e2)) WHERE (((albums_tags.g1, albums_tags.g2) IN (SELECT h1, h2 FROM tags WHERE ((x = 1) AND (h1 IS NOT NULL) AND (h2 IS NOT NULL)))) AND (albums_artists.b1 IS NOT NULL) AND (albums_artists.b2 IS NOT NULL)))) OR (id IS NULL) OR (yyy IS NULL))'
175
+ @c1.exclude(:tags=>@c2.filter(:x=>1)).sql.should == 'SELECT * FROM artists WHERE (((artists.id, artists.yyy) NOT IN (SELECT albums_artists.b1, albums_artists.b2 FROM albums_artists INNER JOIN albums ON ((albums.d1 = albums_artists.c1) AND (albums.d2 = albums_artists.c2)) INNER JOIN albums_tags ON ((albums_tags.f1 = albums.e1) AND (albums_tags.f2 = albums.e2)) WHERE (((albums_tags.g1, albums_tags.g2) IN (SELECT tags.h1, tags.h2 FROM tags WHERE ((x = 1) AND (tags.h1 IS NOT NULL) AND (tags.h2 IS NOT NULL)))) AND (albums_artists.b1 IS NOT NULL) AND (albums_artists.b2 IS NOT NULL)))) OR (artists.id IS NULL) OR (artists.yyy IS NULL))'
176
176
  end
177
177
 
178
178
  it "should support a :conditions option" do
@@ -17,6 +17,12 @@ describe "Dataset#query" do
17
17
  @d = Sequel::Dataset.new(nil)
18
18
  end
19
19
 
20
+ specify "should allow cloning without arguments" do
21
+ q = @d.query {clone}
22
+ q.class.should == @d.class
23
+ q.sql.should == "SELECT *"
24
+ end
25
+
20
26
  specify "should support #from" do
21
27
  q = @d.query {from :xxx}
22
28
  q.class.should == @d.class
@@ -9,12 +9,20 @@ describe "serialization_modification_detection plugin" do
9
9
  plugin :serialization, :yaml, :h
10
10
  plugin :serialization_modification_detection
11
11
  end
12
- @o1 = @c.new
12
+ @o1 = @c.new(:h=>{})
13
13
  @o2 = @c.load(:id=>1, :h=>"--- {}\n\n")
14
+ @o3 = @c.new
15
+ @o4 = @c.load(:id=>1, :h=>nil)
14
16
  MODEL_DB.reset
15
17
  end
16
18
 
17
19
  it "should not detect columns that haven't been changed" do
20
+ @o1.changed_columns.should == []
21
+ @o1.h.should == {}
22
+ @o1.h[1] = 2
23
+ @o1.h.clear
24
+ @o1.changed_columns.should == []
25
+
18
26
  @o2.changed_columns.should == []
19
27
  @o2.h.should == {}
20
28
  @o2.h[1] = 2
@@ -23,15 +31,42 @@ describe "serialization_modification_detection plugin" do
23
31
  end
24
32
 
25
33
  it "should detect columns that have been changed" do
34
+ @o1.changed_columns.should == []
35
+ @o1.h.should == {}
36
+ @o1.h[1] = 2
37
+ @o1.changed_columns.should == [:h]
38
+
26
39
  @o2.changed_columns.should == []
27
40
  @o2.h.should == {}
28
41
  @o2.h[1] = 2
29
42
  @o2.changed_columns.should == [:h]
43
+
44
+ @o3.changed_columns.should == []
45
+ @o3.h.should == nil
46
+ @o3.h = {}
47
+ @o3.changed_columns.should == [:h]
48
+
49
+ @o4.changed_columns.should == []
50
+ @o4.h.should == nil
51
+ @o4.h = {}
52
+ @o4.changed_columns.should == [:h]
30
53
  end
31
54
 
32
55
  it "should report correct changed_columns after saving" do
56
+ @o1.h[1] = 2
57
+ @o1.save
58
+ @o1.changed_columns.should == []
59
+
33
60
  @o2.h[1] = 2
34
61
  @o2.save_changes
35
62
  @o2.changed_columns.should == []
63
+
64
+ @o3.h = {1=>2}
65
+ @o3.save
66
+ @o3.changed_columns.should == []
67
+
68
+ @o4.h = {1=>2}
69
+ @o4.save
70
+ @o4.changed_columns.should == []
36
71
  end
37
72
  end