sequel 3.8.0 → 3.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. data/CHANGELOG +48 -0
  2. data/Rakefile +6 -28
  3. data/bin/sequel +7 -2
  4. data/doc/release_notes/3.9.0.txt +233 -0
  5. data/lib/sequel/adapters/ado.rb +4 -8
  6. data/lib/sequel/adapters/amalgalite.rb +1 -1
  7. data/lib/sequel/adapters/dbi.rb +3 -3
  8. data/lib/sequel/adapters/do.rb +7 -13
  9. data/lib/sequel/adapters/jdbc.rb +10 -16
  10. data/lib/sequel/adapters/jdbc/h2.rb +5 -0
  11. data/lib/sequel/adapters/mysql.rb +10 -23
  12. data/lib/sequel/adapters/odbc.rb +6 -10
  13. data/lib/sequel/adapters/postgres.rb +0 -5
  14. data/lib/sequel/adapters/shared/mssql.rb +17 -9
  15. data/lib/sequel/adapters/shared/mysql.rb +16 -7
  16. data/lib/sequel/adapters/shared/sqlite.rb +5 -0
  17. data/lib/sequel/adapters/sqlite.rb +2 -1
  18. data/lib/sequel/connection_pool.rb +67 -349
  19. data/lib/sequel/connection_pool/sharded_single.rb +84 -0
  20. data/lib/sequel/connection_pool/sharded_threaded.rb +211 -0
  21. data/lib/sequel/connection_pool/single.rb +29 -0
  22. data/lib/sequel/connection_pool/threaded.rb +150 -0
  23. data/lib/sequel/core.rb +46 -15
  24. data/lib/sequel/database.rb +11 -9
  25. data/lib/sequel/dataset/convenience.rb +23 -0
  26. data/lib/sequel/dataset/graph.rb +2 -2
  27. data/lib/sequel/dataset/query.rb +9 -5
  28. data/lib/sequel/dataset/sql.rb +87 -12
  29. data/lib/sequel/extensions/inflector.rb +8 -1
  30. data/lib/sequel/extensions/schema_dumper.rb +3 -4
  31. data/lib/sequel/model/associations.rb +5 -43
  32. data/lib/sequel/model/base.rb +9 -2
  33. data/lib/sequel/model/default_inflections.rb +1 -1
  34. data/lib/sequel/model/exceptions.rb +11 -1
  35. data/lib/sequel/model/inflections.rb +8 -1
  36. data/lib/sequel/model/plugins.rb +2 -12
  37. data/lib/sequel/plugins/active_model.rb +5 -0
  38. data/lib/sequel/plugins/association_dependencies.rb +1 -1
  39. data/lib/sequel/plugins/many_through_many.rb +1 -1
  40. data/lib/sequel/plugins/optimistic_locking.rb +65 -0
  41. data/lib/sequel/plugins/single_table_inheritance.rb +14 -3
  42. data/lib/sequel/plugins/validation_helpers.rb +2 -2
  43. data/lib/sequel/sql.rb +2 -2
  44. data/lib/sequel/timezones.rb +2 -2
  45. data/lib/sequel/version.rb +1 -1
  46. data/spec/adapters/mssql_spec.rb +19 -0
  47. data/spec/adapters/mysql_spec.rb +4 -0
  48. data/spec/adapters/postgres_spec.rb +180 -0
  49. data/spec/adapters/spec_helper.rb +15 -1
  50. data/spec/core/connection_pool_spec.rb +119 -78
  51. data/spec/core/database_spec.rb +41 -50
  52. data/spec/core/dataset_spec.rb +115 -4
  53. data/spec/extensions/active_model_spec.rb +40 -34
  54. data/spec/extensions/boolean_readers_spec.rb +1 -1
  55. data/spec/extensions/migration_spec.rb +43 -38
  56. data/spec/extensions/optimistic_locking_spec.rb +100 -0
  57. data/spec/extensions/schema_dumper_spec.rb +4 -4
  58. data/spec/extensions/single_table_inheritance_spec.rb +19 -11
  59. data/spec/integration/dataset_test.rb +44 -1
  60. data/spec/integration/plugin_test.rb +39 -0
  61. data/spec/integration/prepared_statement_test.rb +58 -7
  62. data/spec/integration/spec_helper.rb +4 -0
  63. data/spec/model/eager_loading_spec.rb +24 -0
  64. data/spec/model/validations_spec.rb +5 -1
  65. metadata +114 -106
@@ -66,7 +66,7 @@ end
66
66
  describe "Sequel::Database dump methods" do
67
67
  before do
68
68
  @d = Sequel::Database.new
69
- @d.meta_def(:tables){[:t1, :t2]}
69
+ @d.meta_def(:tables){|o| [:t1, :t2]}
70
70
  @d.meta_def(:schema) do |t, *o|
71
71
  case t
72
72
  when :t1
@@ -131,7 +131,7 @@ END_MIG
131
131
  end
132
132
 
133
133
  it "should sort table names when dumping a migration" do
134
- @d.meta_def(:tables){[:t2, :t1]}
134
+ @d.meta_def(:tables){|o| [:t2, :t1]}
135
135
  @d.dump_schema_migration.should == <<-END_MIG
136
136
  Class.new(Sequel::Migration) do
137
137
  def up
@@ -210,7 +210,7 @@ END_MIG
210
210
  end
211
211
 
212
212
  it "should support dumping just indexes as a migration" do
213
- @d.meta_def(:tables){[:t1]}
213
+ @d.meta_def(:tables){|o| [:t1]}
214
214
  @d.meta_def(:indexes) do |t|
215
215
  {:i1=>{:columns=>[:c1], :unique=>false},
216
216
  :t1_c2_c1_index=>{:columns=>[:c2, :c1], :unique=>true}}
@@ -311,7 +311,7 @@ create_table(:x) do
311
311
  String :c26, :fixed=>true
312
312
  String :c27, :fixed=>true
313
313
  String :c28
314
- String :c29
314
+ String :c29, :size=>255
315
315
  String :c30, :size=>30
316
316
  String :c31
317
317
  String :c32
@@ -41,8 +41,8 @@ describe Sequel::Model, "#sti_key" do
41
41
  end
42
42
  StiTest.all.collect{|x| x.class}.should == [StiTest, StiTestSub1, StiTestSub2]
43
43
  StiTest.dataset.sql.should == "SELECT * FROM sti_tests"
44
- StiTestSub1.dataset.sql.should == "SELECT * FROM sti_tests WHERE (blah = 'StiTestSub1')"
45
- StiTestSub2.dataset.sql.should == "SELECT * FROM sti_tests WHERE (blah = 'StiTestSub2')"
44
+ StiTestSub1.dataset.sql.should == "SELECT * FROM sti_tests WHERE (sti_tests.blah = 'StiTestSub1')"
45
+ StiTestSub2.dataset.sql.should == "SELECT * FROM sti_tests WHERE (sti_tests.blah = 'StiTestSub2')"
46
46
  end
47
47
 
48
48
  it "should return rows with the correct class based on the polymorphic_key value" do
@@ -54,13 +54,6 @@ describe Sequel::Model, "#sti_key" do
54
54
  StiTest.all.collect{|x| x.class}.should == [StiTest, StiTestSub1, StiTestSub2]
55
55
  end
56
56
 
57
- it "should fallback to the main class if polymophic_key value is NULL" do
58
- def @ds.fetch_rows(sql)
59
- yield({:kind=>nil})
60
- end
61
- StiTest.all.collect{|x| x.class}.should == [StiTest]
62
- end
63
-
64
57
  it "should fallback to the main class if the given class does not exist" do
65
58
  def @ds.fetch_rows(sql)
66
59
  yield({:kind=>'StiTestSub3'})
@@ -68,6 +61,21 @@ describe Sequel::Model, "#sti_key" do
68
61
  StiTest.all.collect{|x| x.class}.should == [StiTest]
69
62
  end
70
63
 
64
+ it "should fallback to the main class if the sti_key field is empty or nil without calling constantize" do
65
+ called = false
66
+ StiTest.meta_def(:constantize) do |s|
67
+ called = true
68
+ Object
69
+ end
70
+ StiTest.plugin :single_table_inheritance, :kind
71
+ def @ds.fetch_rows(sql)
72
+ yield({:kind=>''})
73
+ yield({:kind=>nil})
74
+ end
75
+ StiTest.all.collect{|x| x.class}.should == [StiTest, StiTest]
76
+ called.should == false
77
+ end
78
+
71
79
  it "should add a before_create hook that sets the model class name for the key" do
72
80
  StiTest.new.save
73
81
  StiTestSub1.new.save
@@ -82,7 +90,7 @@ describe Sequel::Model, "#sti_key" do
82
90
 
83
91
  it "should add a filter to model datasets inside subclasses hook to only retreive objects with the matching key" do
84
92
  StiTest.dataset.sql.should == "SELECT * FROM sti_tests"
85
- StiTestSub1.dataset.sql.should == "SELECT * FROM sti_tests WHERE (kind = 'StiTestSub1')"
86
- StiTestSub2.dataset.sql.should == "SELECT * FROM sti_tests WHERE (kind = 'StiTestSub2')"
93
+ StiTestSub1.dataset.sql.should == "SELECT * FROM sti_tests WHERE (sti_tests.kind = 'StiTestSub1')"
94
+ StiTestSub2.dataset.sql.should == "SELECT * FROM sti_tests WHERE (sti_tests.kind = 'StiTestSub2')"
87
95
  end
88
96
  end
@@ -715,6 +715,14 @@ describe "Sequel::Dataset DSL support" do
715
715
  @ds.exclude(:a=>nil).all.should == [{:a=>20, :b=>nil}]
716
716
  end
717
717
 
718
+ it "should work with arrays as hash values" do
719
+ @ds.insert(20, 10)
720
+ @ds.filter(:a=>[10]).all.should == []
721
+ @ds.filter(:a=>[20, 10]).all.should == [{:a=>20, :b=>10}]
722
+ @ds.exclude(:a=>[10]).all.should == [{:a=>20, :b=>10}]
723
+ @ds.exclude(:a=>[20, 10]).all.should == []
724
+ end
725
+
718
726
  it "should work with ranges as hash values" do
719
727
  @ds.insert(20, 10)
720
728
  @ds.filter(:a=>(10..30)).all.should == [{:a=>20, :b=>10}]
@@ -733,7 +741,7 @@ describe "Sequel::Dataset DSL support" do
733
741
  @ds.filter({15=>20}.case(0, :a) > 0).all.should == []
734
742
  end
735
743
 
736
- it "should work multiple value arrays" do
744
+ it "should work with multiple value arrays" do
737
745
  @ds.insert(20, 10)
738
746
  @ds.quote_identifiers = false
739
747
  @ds.filter([:a, :b]=>[[20, 10]].sql_array).all.should == [{:a=>20, :b=>10}]
@@ -746,6 +754,41 @@ describe "Sequel::Dataset DSL support" do
746
754
  @ds.exclude([:a, :b]=>[[20, 10], [1, 2]].sql_array).all.should == []
747
755
  @ds.exclude([:a, :b]=>[[10, 10], [20, 20]].sql_array).all.should == [{:a=>20, :b=>10}]
748
756
  end
757
+
758
+ it "should work with IN/NOT in with datasets" do
759
+ @ds.insert(20, 10)
760
+ ds = @ds.unordered
761
+ @ds.quote_identifiers = false
762
+
763
+ @ds.filter(:a=>ds.select(:a)).all.should == [{:a=>20, :b=>10}]
764
+ @ds.filter(:a=>ds.select(:a).where(:a=>15)).all.should == []
765
+ @ds.exclude(:a=>ds.select(:a)).all.should == []
766
+ @ds.exclude(:a=>ds.select(:a).where(:a=>15)).all.should == [{:a=>20, :b=>10}]
767
+
768
+ @ds.filter([:a, :b]=>ds.select(:a, :b)).all.should == [{:a=>20, :b=>10}]
769
+ @ds.filter([:a, :b]=>ds.select(:b, :a)).all.should == []
770
+ @ds.exclude([:a, :b]=>ds.select(:a, :b)).all.should == []
771
+ @ds.exclude([:a, :b]=>ds.select(:b, :a)).all.should == [{:a=>20, :b=>10}]
772
+
773
+ @ds.filter([:a, :b]=>ds.select(:a, :b).where(:a=>15)).all.should == []
774
+ @ds.exclude([:a, :b]=>ds.select(:a, :b).where(:a=>15)).all.should == [{:a=>20, :b=>10}]
775
+ end
776
+
777
+ specify "should work empty arrays" do
778
+ @ds.insert(20, 10)
779
+ @ds.filter(:a=>[]).all.should == []
780
+ @ds.exclude(:a=>[]).all.should == [{:a=>20, :b=>10}]
781
+ @ds.filter([:a, :b]=>[]).all.should == []
782
+ @ds.exclude([:a, :b]=>[]).all.should == [{:a=>20, :b=>10}]
783
+ end
784
+
785
+ specify "should work empty arrays with nulls" do
786
+ @ds.insert(nil, nil)
787
+ @ds.filter(:a=>[]).all.should == []
788
+ @ds.exclude(:a=>[]).all.should == [{:a=>nil, :b=>nil}]
789
+ @ds.filter([:a, :b]=>[]).all.should == []
790
+ @ds.exclude([:a, :b]=>[]).all.should == [{:a=>nil, :b=>nil}]
791
+ end
749
792
 
750
793
  it "should work multiple conditions" do
751
794
  @ds.insert(20, 10)
@@ -443,3 +443,42 @@ describe "Serialization plugin" do
443
443
  Item.first.stuff.should == Item.new
444
444
  end
445
445
  end
446
+
447
+ describe "OptimisticLocking plugin" do
448
+ before do
449
+ @db = INTEGRATION_DB
450
+ @db.create_table!(:people) do
451
+ primary_key :id
452
+ String :name
453
+ Integer :lock_version, :default=>0, :null=>false
454
+ end
455
+ class ::Person < Sequel::Model(@db)
456
+ plugin :optimistic_locking
457
+ create(:name=>'John')
458
+ end
459
+ end
460
+ after do
461
+ @db.drop_table(:people)
462
+ Object.send(:remove_const, :Person)
463
+ end
464
+
465
+ specify "should raise an error when updating a stale record" do
466
+ p1 = Person[1]
467
+ p2 = Person[1]
468
+ p1.update(:name=>'Jim')
469
+ proc{p2.update(:name=>'Bob')}.should raise_error(Sequel::Plugins::OptimisticLocking::Error)
470
+ end
471
+
472
+ specify "should raise an error when destroying a stale record" do
473
+ p1 = Person[1]
474
+ p2 = Person[1]
475
+ p1.update(:name=>'Jim')
476
+ proc{p2.destroy}.should raise_error(Sequel::Plugins::OptimisticLocking::Error)
477
+ end
478
+
479
+ specify "should not raise an error when updating the same record twice" do
480
+ p1 = Person[1]
481
+ p1.update(:name=>'Jim')
482
+ proc{p1.update(:name=>'Bob')}.should_not raise_error
483
+ end
484
+ end
@@ -49,36 +49,46 @@ describe "Prepared Statements and Bound Arguments" do
49
49
  @ds.filter(:number=>@ds.ba(:$n)).bind(:n=>1).bind(:n=>10).call(:first).should == {:id=>1, :number=>10}
50
50
  end
51
51
 
52
- specify "should support placeholder literal strings" do
52
+ specify "should support placeholder literal strings with call" do
53
53
  @ds.filter("number = ?", @ds.ba(:$n)).call(:select, :n=>10).should == [{:id=>1, :number=>10}]
54
54
  end
55
55
 
56
- specify "should support named placeholder literal strings and handle multiple named placeholders correctly" do
56
+ specify "should support named placeholder literal strings and handle multiple named placeholders correctly with call" do
57
57
  @ds.filter("number = :n", :n=>@ds.ba(:$n)).call(:select, :n=>10).should == [{:id=>1, :number=>10}]
58
58
  @ds.insert(:number=>20)
59
59
  @ds.insert(:number=>30)
60
60
  @ds.filter("number > :n1 AND number < :n2 AND number = :n3", :n3=>@ds.ba(:$n3), :n2=>@ds.ba(:$n2), :n1=>@ds.ba(:$n1)).call(:select, :n3=>20, :n2=>30, :n1=>10).should == [{:id=>2, :number=>20}]
61
61
  end
62
62
 
63
- specify "should support datasets with static sql and placeholders" do
63
+ specify "should support datasets with static sql and placeholders with call" do
64
64
  INTEGRATION_DB["SELECT * FROM items WHERE number = ?", @ds.ba(:$n)].call(:select, :n=>10).should == [{:id=>1, :number=>10}]
65
65
  end
66
66
 
67
- specify "should support subselects" do
67
+ specify "should support subselects with call" do
68
68
  @ds.filter(:id=>:$i).filter(:number=>@ds.select(:number).filter(:number=>@ds.ba(:$n))).filter(:id=>:$j).call(:select, :n=>10, :i=>1, :j=>1).should == [{:id=>1, :number=>10}]
69
69
  end
70
70
 
71
- specify "should support subselects with literal strings" do
71
+ specify "should support subselects with literal strings with call" do
72
72
  @ds.filter(:id=>:$i, :number=>@ds.select(:number).filter("number = ?", @ds.ba(:$n))).call(:select, :n=>10, :i=>1).should == [{:id=>1, :number=>10}]
73
73
  end
74
74
 
75
- specify "should support subselects with static sql and placeholders" do
75
+ specify "should support subselects with static sql and placeholders with call" do
76
76
  @ds.filter(:id=>:$i, :number=>INTEGRATION_DB["SELECT number FROM items WHERE number = ?", @ds.ba(:$n)]).call(:select, :n=>10, :i=>1).should == [{:id=>1, :number=>10}]
77
77
  end
78
78
 
79
- specify "should support subselects of subselects" do
79
+ specify "should support subselects of subselects with call" do
80
80
  @ds.filter(:id=>:$i).filter(:number=>@ds.select(:number).filter(:number=>@ds.select(:number).filter(:number=>@ds.ba(:$n)))).filter(:id=>:$j).call(:select, :n=>10, :i=>1, :j=>1).should == [{:id=>1, :number=>10}]
81
81
  end
82
+
83
+ specify "should support using a bound variable for a limit and offset" do
84
+ @ds.insert(:number=>20)
85
+ ds = @ds.limit(@ds.ba(:$n), @ds.ba(:$n2)).order(:id)
86
+ ds.call(:select, :n=>1, :n2=>0).should == [{:id=>1, :number=>10}]
87
+ ds.call(:select, :n=>1, :n2=>1).should == [{:id=>2, :number=>20}]
88
+ ds.call(:select, :n=>1, :n2=>2).should == []
89
+ ds.call(:select, :n=>2, :n2=>0).should == [{:id=>1, :number=>10}, {:id=>2, :number=>20}]
90
+ ds.call(:select, :n=>2, :n2=>1).should == [{:id=>2, :number=>20}]
91
+ end
82
92
 
83
93
  specify "should support bound variables with insert" do
84
94
  @ds.call(:insert, {:n=>20}, :number=>@ds.ba(:$n))
@@ -115,6 +125,47 @@ describe "Prepared Statements and Bound Arguments" do
115
125
  end
116
126
  end
117
127
 
128
+ specify "should support placeholder literal strings with prepare" do
129
+ @ds.filter("number = ?", @ds.ba(:$n)).prepare(:select, :seq_select).call(:n=>10).should == [{:id=>1, :number=>10}]
130
+ end
131
+
132
+ specify "should support named placeholder literal strings and handle multiple named placeholders correctly with prepare" do
133
+ @ds.filter("number = :n", :n=>@ds.ba(:$n)).prepare(:select, :seq_select).call(:n=>10).should == [{:id=>1, :number=>10}]
134
+ @ds.insert(:number=>20)
135
+ @ds.insert(:number=>30)
136
+ @ds.filter("number > :n1 AND number < :n2 AND number = :n3", :n3=>@ds.ba(:$n3), :n2=>@ds.ba(:$n2), :n1=>@ds.ba(:$n1)).call(:select, :n3=>20, :n2=>30, :n1=>10).should == [{:id=>2, :number=>20}]
137
+ end
138
+
139
+ specify "should support datasets with static sql and placeholders with prepare" do
140
+ INTEGRATION_DB["SELECT * FROM items WHERE number = ?", @ds.ba(:$n)].prepare(:select, :seq_select).call(:n=>10).should == [{:id=>1, :number=>10}]
141
+ end
142
+
143
+ specify "should support subselects with prepare" do
144
+ @ds.filter(:id=>:$i).filter(:number=>@ds.select(:number).filter(:number=>@ds.ba(:$n))).filter(:id=>:$j).prepare(:select, :seq_select).call(:n=>10, :i=>1, :j=>1).should == [{:id=>1, :number=>10}]
145
+ end
146
+
147
+ specify "should support subselects with literal strings with prepare" do
148
+ @ds.filter(:id=>:$i, :number=>@ds.select(:number).filter("number = ?", @ds.ba(:$n))).prepare(:select, :seq_select).call(:n=>10, :i=>1).should == [{:id=>1, :number=>10}]
149
+ end
150
+
151
+ specify "should support subselects with static sql and placeholders with prepare" do
152
+ @ds.filter(:id=>:$i, :number=>INTEGRATION_DB["SELECT number FROM items WHERE number = ?", @ds.ba(:$n)]).prepare(:select, :seq_select).call(:n=>10, :i=>1).should == [{:id=>1, :number=>10}]
153
+ end
154
+
155
+ specify "should support subselects of subselects with prepare" do
156
+ @ds.filter(:id=>:$i).filter(:number=>@ds.select(:number).filter(:number=>@ds.select(:number).filter(:number=>@ds.ba(:$n)))).filter(:id=>:$j).prepare(:select, :seq_select).call(:n=>10, :i=>1, :j=>1).should == [{:id=>1, :number=>10}]
157
+ end
158
+
159
+ specify "should support using a prepared_statement for a limit and offset" do
160
+ @ds.insert(:number=>20)
161
+ ps = @ds.limit(@ds.ba(:$n), @ds.ba(:$n2)).order(:id).prepare(:select, :seq_select)
162
+ ps.call(:n=>1, :n2=>0).should == [{:id=>1, :number=>10}]
163
+ ps.call(:n=>1, :n2=>1).should == [{:id=>2, :number=>20}]
164
+ ps.call(:n=>1, :n2=>2).should == []
165
+ ps.call(:n=>2, :n2=>0).should == [{:id=>1, :number=>10}, {:id=>2, :number=>20}]
166
+ ps.call(:n=>2, :n2=>1).should == [{:id=>2, :number=>20}]
167
+ end
168
+
118
169
  specify "should support prepared statements with insert" do
119
170
  @ds.prepare(:insert, :insert_n, :number=>@ds.ba(:$n))
120
171
  INTEGRATION_DB.call(:insert_n, :n=>20)
@@ -25,6 +25,10 @@ class Spec::Example::ExampleGroup
25
25
  INTEGRATION_DB.loggers.pop
26
26
  end
27
27
  end
28
+
29
+ def self.log_specify(message, &block)
30
+ specify(message){log{instance_eval(&block)}}
31
+ end
28
32
 
29
33
  def self.cspecify(message, *checked, &block)
30
34
  pending = false
@@ -1343,4 +1343,28 @@ describe Sequel::Model, "#eager_graph" do
1343
1343
  as.should == [GraphAlbum.load(:id=>3, :band_id=>2)]
1344
1344
  as.first.inner_genres.should == [GraphGenre.load(:id=>5), GraphGenre.load(:id=>6)]
1345
1345
  end
1346
+
1347
+ it "should handle eager loading with schemas and aliases of different types" do
1348
+ GraphAlbum.eager_graph(:band).join(:s__genres, [:b_id]).eager_graph(:genres).sql.should == 'SELECT albums.id, albums.band_id, band.id AS band_id_0, band.vocalist_id, genres_0.id AS genres_0_id FROM albums LEFT OUTER JOIN bands AS band ON (band.id = albums.band_id) INNER JOIN s.genres USING (b_id) LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres AS genres_0 ON (genres_0.id = ag.genre_id)'
1349
+ GraphAlbum.eager_graph(:band).join(:genres.qualify(:s), [:b_id]).eager_graph(:genres).sql.should == 'SELECT albums.id, albums.band_id, band.id AS band_id_0, band.vocalist_id, genres_0.id AS genres_0_id FROM albums LEFT OUTER JOIN bands AS band ON (band.id = albums.band_id) INNER JOIN s.genres USING (b_id) LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres AS genres_0 ON (genres_0.id = ag.genre_id)'
1350
+ GraphAlbum.eager_graph(:band).join(:s__b.as('genres'), [:b_id]).eager_graph(:genres).sql.should == 'SELECT albums.id, albums.band_id, band.id AS band_id_0, band.vocalist_id, genres_0.id AS genres_0_id FROM albums LEFT OUTER JOIN bands AS band ON (band.id = albums.band_id) INNER JOIN s.b AS genres USING (b_id) LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres AS genres_0 ON (genres_0.id = ag.genre_id)'
1351
+ GraphAlbum.eager_graph(:band).join(:s__b, [:b_id], :genres.identifier).eager_graph(:genres).sql.should == 'SELECT albums.id, albums.band_id, band.id AS band_id_0, band.vocalist_id, genres_0.id AS genres_0_id FROM albums LEFT OUTER JOIN bands AS band ON (band.id = albums.band_id) INNER JOIN s.b AS genres USING (b_id) LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres AS genres_0 ON (genres_0.id = ag.genre_id)'
1352
+ GraphAlbum.eager_graph(:band).join(:genres.identifier, [:b_id]).eager_graph(:genres).sql.should == 'SELECT albums.id, albums.band_id, band.id AS band_id_0, band.vocalist_id, genres_0.id AS genres_0_id FROM albums LEFT OUTER JOIN bands AS band ON (band.id = albums.band_id) INNER JOIN genres USING (b_id) LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres AS genres_0 ON (genres_0.id = ag.genre_id)'
1353
+ GraphAlbum.eager_graph(:band).join('genres', [:b_id]).eager_graph(:genres).sql.should == 'SELECT albums.id, albums.band_id, band.id AS band_id_0, band.vocalist_id, genres_0.id AS genres_0_id FROM albums LEFT OUTER JOIN bands AS band ON (band.id = albums.band_id) INNER JOIN genres USING (b_id) LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres AS genres_0 ON (genres_0.id = ag.genre_id)'
1354
+ end
1355
+
1356
+ it "should raise errors if invalid aliases or table styles are used" do
1357
+ proc{GraphAlbum.from_self(:alias=>:bands.qualify(:s)).eager_graph(:band)}.should raise_error(Sequel::Error)
1358
+ proc{GraphAlbum.from('?'.lit(:bands)).eager_graph(:band)}.should raise_error(Sequel::Error)
1359
+ end
1360
+
1361
+ it "should eagerly load schema qualified tables correctly with joins" do
1362
+ c1 = Class.new(GraphAlbum)
1363
+ c2 = Class.new(GraphGenre)
1364
+ c1.dataset = c1.dataset.from(:s__a)
1365
+ c2.dataset = c2.dataset.from(:s__g)
1366
+ c1.many_to_many :a_genres, :class=>c2, :left_primary_key=>:id, :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:s__ag
1367
+ ds = c1.join(:s__t, [:b_id]).eager_graph(:a_genres)
1368
+ ds.sql.should == 'SELECT a.id, a_genres.id AS a_genres_id FROM (SELECT * FROM s.a INNER JOIN s.t USING (b_id)) AS a LEFT OUTER JOIN s.ag AS ag ON (ag.album_id = a.id) LEFT OUTER JOIN s.g AS a_genres ON (a_genres.id = ag.genre_id)'
1369
+ end
1346
1370
  end
@@ -104,6 +104,10 @@ describe Sequel::Model do
104
104
  @o.errors[:score].should == ['too low']
105
105
  @o.errors[:blah].should be_empty
106
106
  end
107
+
108
+ specify "should allow raising of ValidationFailed with a string" do
109
+ proc{raise Sequel::ValidationFailed, "no reason"}.should raise_error(Sequel::ValidationFailed, "no reason")
110
+ end
107
111
  end
108
112
 
109
113
  describe "Model#save" do
@@ -139,7 +143,7 @@ describe "Model#save" do
139
143
  end
140
144
 
141
145
  specify "should raise error if validations fail and raise_on_save_faiure is true" do
142
- proc{@m.save}.should raise_error(Sequel::ValidationFailed)
146
+ proc{@m.save}.should raise_error(Sequel::ValidationFailed){ |e| e.errors.should == @m.errors }
143
147
  end
144
148
 
145
149
  specify "should return nil if validations fail and raise_on_save_faiure is false" do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sequel
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.8.0
4
+ version: 3.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Evans
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-01-04 00:00:00 -08:00
12
+ date: 2010-03-04 00:00:00 -08:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -23,6 +23,7 @@ extra_rdoc_files:
23
23
  - README.rdoc
24
24
  - CHANGELOG
25
25
  - COPYING
26
+ - doc/advanced_associations.rdoc
26
27
  - doc/cheat_sheet.rdoc
27
28
  - doc/dataset_filtering.rdoc
28
29
  - doc/opening_databases.rdoc
@@ -30,9 +31,8 @@ extra_rdoc_files:
30
31
  - doc/reflection.rdoc
31
32
  - doc/schema.rdoc
32
33
  - doc/sharding.rdoc
33
- - doc/advanced_associations.rdoc
34
34
  - doc/virtual_rows.rdoc
35
- - doc/release_notes/3.8.0.txt
35
+ - doc/release_notes/1.0.txt
36
36
  - doc/release_notes/1.1.txt
37
37
  - doc/release_notes/1.3.txt
38
38
  - doc/release_notes/1.4.0.txt
@@ -56,16 +56,23 @@ extra_rdoc_files:
56
56
  - doc/release_notes/3.3.0.txt
57
57
  - doc/release_notes/3.4.0.txt
58
58
  - doc/release_notes/3.5.0.txt
59
- - doc/release_notes/1.0.txt
60
59
  - doc/release_notes/3.6.0.txt
61
60
  - doc/release_notes/3.7.0.txt
61
+ - doc/release_notes/3.8.0.txt
62
+ - doc/release_notes/3.9.0.txt
62
63
  files:
63
64
  - COPYING
64
65
  - CHANGELOG
65
66
  - README.rdoc
66
67
  - Rakefile
67
68
  - bin/sequel
68
- - doc/release_notes/3.8.0.txt
69
+ - doc/advanced_associations.rdoc
70
+ - doc/cheat_sheet.rdoc
71
+ - doc/dataset_filtering.rdoc
72
+ - doc/opening_databases.rdoc
73
+ - doc/prepared_statements.rdoc
74
+ - doc/reflection.rdoc
75
+ - doc/release_notes/1.0.txt
69
76
  - doc/release_notes/1.1.txt
70
77
  - doc/release_notes/1.3.txt
71
78
  - doc/release_notes/1.4.0.txt
@@ -89,31 +96,22 @@ files:
89
96
  - doc/release_notes/3.3.0.txt
90
97
  - doc/release_notes/3.4.0.txt
91
98
  - doc/release_notes/3.5.0.txt
92
- - doc/release_notes/1.0.txt
93
99
  - doc/release_notes/3.6.0.txt
94
100
  - doc/release_notes/3.7.0.txt
95
- - doc/cheat_sheet.rdoc
96
- - doc/dataset_filtering.rdoc
97
- - doc/opening_databases.rdoc
98
- - doc/prepared_statements.rdoc
99
- - doc/reflection.rdoc
101
+ - doc/release_notes/3.8.0.txt
102
+ - doc/release_notes/3.9.0.txt
100
103
  - doc/schema.rdoc
101
104
  - doc/sharding.rdoc
102
- - doc/advanced_associations.rdoc
103
105
  - doc/virtual_rows.rdoc
104
- - spec/model/validations_spec.rb
105
- - spec/model/associations_spec.rb
106
- - spec/model/base_spec.rb
107
- - spec/model/dataset_methods_spec.rb
108
- - spec/model/eager_loading_spec.rb
109
- - spec/model/hooks_spec.rb
110
- - spec/model/inflector_spec.rb
111
- - spec/model/model_spec.rb
112
- - spec/model/plugins_spec.rb
113
- - spec/model/record_spec.rb
114
- - spec/model/spec_helper.rb
115
- - spec/model/association_reflection_spec.rb
116
- - spec/core/version_spec.rb
106
+ - spec/adapters/firebird_spec.rb
107
+ - spec/adapters/informix_spec.rb
108
+ - spec/adapters/mssql_spec.rb
109
+ - spec/adapters/mysql_spec.rb
110
+ - spec/adapters/oracle_spec.rb
111
+ - spec/adapters/postgres_spec.rb
112
+ - spec/adapters/spec_helper.rb
113
+ - spec/adapters/sqlite_spec.rb
114
+ - spec/core/connection_pool_spec.rb
117
115
  - spec/core/core_sql_spec.rb
118
116
  - spec/core/database_spec.rb
119
117
  - spec/core/dataset_spec.rb
@@ -122,8 +120,8 @@ files:
122
120
  - spec/core/schema_generator_spec.rb
123
121
  - spec/core/schema_spec.rb
124
122
  - spec/core/spec_helper.rb
125
- - spec/core/connection_pool_spec.rb
126
- - spec/extensions/validation_helpers_spec.rb
123
+ - spec/core/version_spec.rb
124
+ - spec/extensions/active_model_spec.rb
127
125
  - spec/extensions/association_dependencies_spec.rb
128
126
  - spec/extensions/association_proxies_spec.rb
129
127
  - spec/extensions/blank_spec.rb
@@ -137,13 +135,14 @@ files:
137
135
  - spec/extensions/instance_hooks_spec.rb
138
136
  - spec/extensions/lazy_attributes_spec.rb
139
137
  - spec/extensions/looser_typecasting_spec.rb
140
- - spec/extensions/query_spec.rb
141
138
  - spec/extensions/migration_spec.rb
142
139
  - spec/extensions/many_through_many_spec.rb
143
140
  - spec/extensions/named_timezones_spec.rb
144
141
  - spec/extensions/nested_attributes_spec.rb
142
+ - spec/extensions/optimistic_locking_spec.rb
145
143
  - spec/extensions/pagination_spec.rb
146
144
  - spec/extensions/pretty_table_spec.rb
145
+ - spec/extensions/query_spec.rb
147
146
  - spec/extensions/schema_dumper_spec.rb
148
147
  - spec/extensions/schema_spec.rb
149
148
  - spec/extensions/serialization_spec.rb
@@ -153,13 +152,13 @@ files:
153
152
  - spec/extensions/string_date_time_spec.rb
154
153
  - spec/extensions/subclasses_spec.rb
155
154
  - spec/extensions/tactical_eager_loading_spec.rb
156
- - spec/extensions/timestamps_spec.rb
157
155
  - spec/extensions/thread_local_timezones_spec.rb
156
+ - spec/extensions/timestamps_spec.rb
158
157
  - spec/extensions/touch_spec.rb
159
158
  - spec/extensions/typecast_on_load_spec.rb
160
159
  - spec/extensions/validation_class_methods_spec.rb
161
- - spec/extensions/active_model_spec.rb
162
- - spec/integration/type_test.rb
160
+ - spec/extensions/validation_helpers_spec.rb
161
+ - spec/integration/associations_test.rb
163
162
  - spec/integration/database_test.rb
164
163
  - spec/integration/dataset_test.rb
165
164
  - spec/integration/eager_loader_test.rb
@@ -170,29 +169,97 @@ files:
170
169
  - spec/integration/spec_helper.rb
171
170
  - spec/integration/timezone_test.rb
172
171
  - spec/integration/transaction_test.rb
173
- - spec/integration/associations_test.rb
174
- - spec/adapters/sqlite_spec.rb
175
- - spec/adapters/informix_spec.rb
176
- - spec/adapters/mssql_spec.rb
177
- - spec/adapters/mysql_spec.rb
178
- - spec/adapters/oracle_spec.rb
179
- - spec/adapters/postgres_spec.rb
180
- - spec/adapters/spec_helper.rb
181
- - spec/adapters/firebird_spec.rb
172
+ - spec/integration/type_test.rb
173
+ - spec/model/association_reflection_spec.rb
174
+ - spec/model/associations_spec.rb
175
+ - spec/model/base_spec.rb
176
+ - spec/model/dataset_methods_spec.rb
177
+ - spec/model/eager_loading_spec.rb
178
+ - spec/model/hooks_spec.rb
179
+ - spec/model/inflector_spec.rb
180
+ - spec/model/model_spec.rb
181
+ - spec/model/plugins_spec.rb
182
+ - spec/model/record_spec.rb
183
+ - spec/model/spec_helper.rb
184
+ - spec/model/validations_spec.rb
182
185
  - spec/rcov.opts
183
186
  - spec/spec_config.rb.example
184
187
  - spec/spec_config.rb
188
+ - lib/sequel.rb
189
+ - lib/sequel/adapters/ado.rb
190
+ - lib/sequel/adapters/ado/mssql.rb
191
+ - lib/sequel/adapters/amalgalite.rb
192
+ - lib/sequel/adapters/db2.rb
193
+ - lib/sequel/adapters/dbi.rb
194
+ - lib/sequel/adapters/do.rb
195
+ - lib/sequel/adapters/do/mysql.rb
196
+ - lib/sequel/adapters/do/postgres.rb
197
+ - lib/sequel/adapters/do/sqlite.rb
198
+ - lib/sequel/adapters/firebird.rb
199
+ - lib/sequel/adapters/informix.rb
200
+ - lib/sequel/adapters/jdbc.rb
201
+ - lib/sequel/adapters/jdbc/h2.rb
202
+ - lib/sequel/adapters/jdbc/mssql.rb
203
+ - lib/sequel/adapters/jdbc/mysql.rb
204
+ - lib/sequel/adapters/jdbc/oracle.rb
205
+ - lib/sequel/adapters/jdbc/postgresql.rb
206
+ - lib/sequel/adapters/jdbc/sqlite.rb
207
+ - lib/sequel/adapters/mysql.rb
208
+ - lib/sequel/adapters/odbc.rb
209
+ - lib/sequel/adapters/odbc/mssql.rb
210
+ - lib/sequel/adapters/openbase.rb
211
+ - lib/sequel/adapters/oracle.rb
212
+ - lib/sequel/adapters/postgres.rb
213
+ - lib/sequel/adapters/shared/mssql.rb
214
+ - lib/sequel/adapters/shared/mysql.rb
215
+ - lib/sequel/adapters/shared/oracle.rb
216
+ - lib/sequel/adapters/shared/postgres.rb
217
+ - lib/sequel/adapters/shared/progress.rb
218
+ - lib/sequel/adapters/shared/sqlite.rb
219
+ - lib/sequel/adapters/sqlite.rb
220
+ - lib/sequel/adapters/utils/stored_procedures.rb
221
+ - lib/sequel/connection_pool.rb
222
+ - lib/sequel/connection_pool/sharded_single.rb
223
+ - lib/sequel/connection_pool/sharded_threaded.rb
224
+ - lib/sequel/connection_pool/single.rb
225
+ - lib/sequel/connection_pool/threaded.rb
226
+ - lib/sequel/core.rb
227
+ - lib/sequel/core_sql.rb
228
+ - lib/sequel/database.rb
185
229
  - lib/sequel/database/schema_generator.rb
186
230
  - lib/sequel/database/schema_methods.rb
187
231
  - lib/sequel/database/schema_sql.rb
188
- - lib/sequel/model/errors.rb
232
+ - lib/sequel/dataset.rb
233
+ - lib/sequel/dataset/actions.rb
234
+ - lib/sequel/dataset/convenience.rb
235
+ - lib/sequel/dataset/features.rb
236
+ - lib/sequel/dataset/graph.rb
237
+ - lib/sequel/dataset/prepared_statements.rb
238
+ - lib/sequel/dataset/query.rb
239
+ - lib/sequel/dataset/sql.rb
240
+ - lib/sequel/exceptions.rb
241
+ - lib/sequel/extensions/blank.rb
242
+ - lib/sequel/extensions/inflector.rb
243
+ - lib/sequel/extensions/looser_typecasting.rb
244
+ - lib/sequel/extensions/migration.rb
245
+ - lib/sequel/extensions/named_timezones.rb
246
+ - lib/sequel/extensions/pagination.rb
247
+ - lib/sequel/extensions/pretty_table.rb
248
+ - lib/sequel/extensions/query.rb
249
+ - lib/sequel/extensions/schema_dumper.rb
250
+ - lib/sequel/extensions/sql_expr.rb
251
+ - lib/sequel/extensions/string_date_time.rb
252
+ - lib/sequel/extensions/thread_local_timezones.rb
253
+ - lib/sequel/metaprogramming.rb
254
+ - lib/sequel/model.rb
255
+ - lib/sequel/model/associations.rb
189
256
  - lib/sequel/model/base.rb
190
257
  - lib/sequel/model/default_inflections.rb
191
- - lib/sequel/model/associations.rb
258
+ - lib/sequel/model/errors.rb
192
259
  - lib/sequel/model/exceptions.rb
193
260
  - lib/sequel/model/inflections.rb
194
261
  - lib/sequel/model/plugins.rb
195
- - lib/sequel/plugins/validation_helpers.rb
262
+ - lib/sequel/plugins/active_model.rb
196
263
  - lib/sequel/plugins/association_dependencies.rb
197
264
  - lib/sequel/plugins/association_proxies.rb
198
265
  - lib/sequel/plugins/boolean_readers.rb
@@ -205,79 +272,20 @@ files:
205
272
  - lib/sequel/plugins/lazy_attributes.rb
206
273
  - lib/sequel/plugins/many_through_many.rb
207
274
  - lib/sequel/plugins/nested_attributes.rb
275
+ - lib/sequel/plugins/optimistic_locking.rb
208
276
  - lib/sequel/plugins/schema.rb
209
277
  - lib/sequel/plugins/serialization.rb
210
- - lib/sequel/plugins/single_table_inheritance.rb
211
278
  - lib/sequel/plugins/subclasses.rb
279
+ - lib/sequel/plugins/single_table_inheritance.rb
212
280
  - lib/sequel/plugins/tactical_eager_loading.rb
213
281
  - lib/sequel/plugins/timestamps.rb
214
282
  - lib/sequel/plugins/touch.rb
215
283
  - lib/sequel/plugins/typecast_on_load.rb
216
284
  - lib/sequel/plugins/validation_class_methods.rb
217
- - lib/sequel/plugins/active_model.rb
218
- - lib/sequel/extensions/thread_local_timezones.rb
219
- - lib/sequel/extensions/inflector.rb
220
- - lib/sequel/extensions/looser_typecasting.rb
221
- - lib/sequel/extensions/migration.rb
222
- - lib/sequel/extensions/named_timezones.rb
223
- - lib/sequel/extensions/pagination.rb
224
- - lib/sequel/extensions/pretty_table.rb
225
- - lib/sequel/extensions/query.rb
226
- - lib/sequel/extensions/schema_dumper.rb
227
- - lib/sequel/extensions/sql_expr.rb
228
- - lib/sequel/extensions/string_date_time.rb
229
- - lib/sequel/extensions/blank.rb
230
- - lib/sequel/dataset/graph.rb
231
- - lib/sequel/dataset/convenience.rb
232
- - lib/sequel/dataset/features.rb
233
- - lib/sequel/dataset/actions.rb
234
- - lib/sequel/dataset/prepared_statements.rb
235
- - lib/sequel/dataset/query.rb
236
- - lib/sequel/dataset/sql.rb
237
- - lib/sequel/adapters/do/mysql.rb
238
- - lib/sequel/adapters/do/postgres.rb
239
- - lib/sequel/adapters/do/sqlite.rb
240
- - lib/sequel/adapters/ado/mssql.rb
241
- - lib/sequel/adapters/shared/mssql.rb
242
- - lib/sequel/adapters/shared/mysql.rb
243
- - lib/sequel/adapters/shared/oracle.rb
244
- - lib/sequel/adapters/shared/postgres.rb
245
- - lib/sequel/adapters/shared/progress.rb
246
- - lib/sequel/adapters/shared/sqlite.rb
247
- - lib/sequel/adapters/odbc/mssql.rb
248
- - lib/sequel/adapters/jdbc/h2.rb
249
- - lib/sequel/adapters/jdbc/mssql.rb
250
- - lib/sequel/adapters/jdbc/mysql.rb
251
- - lib/sequel/adapters/jdbc/oracle.rb
252
- - lib/sequel/adapters/jdbc/postgresql.rb
253
- - lib/sequel/adapters/jdbc/sqlite.rb
254
- - lib/sequel/adapters/utils/stored_procedures.rb
255
- - lib/sequel/adapters/ado.rb
256
- - lib/sequel/adapters/firebird.rb
257
- - lib/sequel/adapters/informix.rb
258
- - lib/sequel/adapters/jdbc.rb
259
- - lib/sequel/adapters/dbi.rb
260
- - lib/sequel/adapters/mysql.rb
261
- - lib/sequel/adapters/odbc.rb
262
- - lib/sequel/adapters/db2.rb
263
- - lib/sequel/adapters/openbase.rb
264
- - lib/sequel/adapters/oracle.rb
265
- - lib/sequel/adapters/postgres.rb
266
- - lib/sequel/adapters/amalgalite.rb
267
- - lib/sequel/adapters/sqlite.rb
268
- - lib/sequel/adapters/do.rb
269
- - lib/sequel/exceptions.rb
270
- - lib/sequel/metaprogramming.rb
271
- - lib/sequel/model.rb
285
+ - lib/sequel/plugins/validation_helpers.rb
272
286
  - lib/sequel/sql.rb
273
287
  - lib/sequel/timezones.rb
274
288
  - lib/sequel/version.rb
275
- - lib/sequel/connection_pool.rb
276
- - lib/sequel/core.rb
277
- - lib/sequel/core_sql.rb
278
- - lib/sequel/database.rb
279
- - lib/sequel/dataset.rb
280
- - lib/sequel.rb
281
289
  - lib/sequel_core.rb
282
290
  - lib/sequel_model.rb
283
291
  has_rdoc: true