sequel 3.30.0 → 3.31.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 (45) hide show
  1. data/CHANGELOG +40 -0
  2. data/Rakefile +12 -2
  3. data/doc/association_basics.rdoc +28 -0
  4. data/doc/dataset_filtering.rdoc +8 -0
  5. data/doc/opening_databases.rdoc +1 -0
  6. data/doc/release_notes/3.31.0.txt +146 -0
  7. data/lib/sequel/adapters/jdbc.rb +7 -6
  8. data/lib/sequel/adapters/jdbc/derby.rb +5 -0
  9. data/lib/sequel/adapters/jdbc/h2.rb +6 -1
  10. data/lib/sequel/adapters/mock.rb +21 -2
  11. data/lib/sequel/adapters/shared/db2.rb +10 -0
  12. data/lib/sequel/adapters/shared/mssql.rb +40 -5
  13. data/lib/sequel/adapters/shared/mysql.rb +19 -2
  14. data/lib/sequel/adapters/shared/oracle.rb +13 -1
  15. data/lib/sequel/adapters/shared/postgres.rb +52 -8
  16. data/lib/sequel/adapters/shared/sqlite.rb +4 -3
  17. data/lib/sequel/adapters/utils/stored_procedures.rb +1 -11
  18. data/lib/sequel/database/schema_generator.rb +9 -2
  19. data/lib/sequel/dataset/actions.rb +37 -19
  20. data/lib/sequel/dataset/features.rb +10 -0
  21. data/lib/sequel/dataset/prepared_statements.rb +0 -10
  22. data/lib/sequel/dataset/query.rb +13 -1
  23. data/lib/sequel/dataset/sql.rb +6 -1
  24. data/lib/sequel/model/associations.rb +14 -4
  25. data/lib/sequel/model/base.rb +10 -0
  26. data/lib/sequel/plugins/serialization.rb +82 -43
  27. data/lib/sequel/version.rb +1 -1
  28. data/spec/adapters/mssql_spec.rb +46 -0
  29. data/spec/adapters/mysql_spec.rb +3 -0
  30. data/spec/adapters/postgres_spec.rb +61 -24
  31. data/spec/core/database_spec.rb +31 -18
  32. data/spec/core/dataset_spec.rb +90 -13
  33. data/spec/core/mock_adapter_spec.rb +37 -0
  34. data/spec/extensions/instance_filters_spec.rb +1 -0
  35. data/spec/extensions/nested_attributes_spec.rb +1 -1
  36. data/spec/extensions/serialization_spec.rb +49 -5
  37. data/spec/extensions/sharding_spec.rb +1 -1
  38. data/spec/integration/associations_test.rb +15 -0
  39. data/spec/integration/dataset_test.rb +71 -0
  40. data/spec/integration/prepared_statement_test.rb +8 -0
  41. data/spec/model/association_reflection_spec.rb +27 -0
  42. data/spec/model/associations_spec.rb +18 -3
  43. data/spec/model/base_spec.rb +20 -0
  44. data/spec/model/eager_loading_spec.rb +21 -0
  45. metadata +4 -2
@@ -39,6 +39,12 @@ describe "Simple Dataset operations" do
39
39
  @ds.filter(:id=>2).first[:number].should == 20
40
40
  end
41
41
 
42
+ specify "should have insert_multiple return primary key values" do
43
+ @ds.insert_multiple([{:number=>20}, {:number=>30}]).should == [2, 3]
44
+ @ds.filter(:id=>2).get(:number).should == 20
45
+ @ds.filter(:id=>3).get(:number).should == 30
46
+ end
47
+
42
48
  specify "should join correctly" do
43
49
  @ds.join(:items___b, :id=>:id).select_all(:items).all.should == [{:id=>1, :number=>10}]
44
50
  end
@@ -713,6 +719,55 @@ describe "Sequel::Dataset#import and #multi_insert" do
713
719
  end
714
720
  end
715
721
 
722
+ describe "Sequel::Dataset#import and #multi_insert :return=>:primary_key " do
723
+ before do
724
+ @db = INTEGRATION_DB
725
+ @db.create_table!(:imp){primary_key :id; Integer :i}
726
+ @ds = @db[:imp]
727
+ end
728
+ after do
729
+ @db.drop_table(:imp)
730
+ end
731
+
732
+ specify "should return primary key values " do
733
+ @ds.multi_insert([{:i=>10}, {:i=>20}, {:i=>30}], :return=>:primary_key).should == [1, 2, 3]
734
+ @ds.import([:i], [[40], [50], [60]], :return=>:primary_key).should == [4, 5, 6]
735
+ @ds.order(:id).map([:id, :i]).should == [[1, 10], [2, 20], [3, 30], [4, 40], [5, 50], [6, 60]]
736
+ end
737
+
738
+ specify "should return primary key values when :slice is used" do
739
+ @ds.multi_insert([{:i=>10}, {:i=>20}, {:i=>30}], :return=>:primary_key, :slice=>2).should == [1, 2, 3]
740
+ @ds.import([:i], [[40], [50], [60]], :return=>:primary_key, :slice=>2).should == [4, 5, 6]
741
+ @ds.order(:id).map([:id, :i]).should == [[1, 10], [2, 20], [3, 30], [4, 40], [5, 50], [6, 60]]
742
+ end
743
+ end
744
+
745
+ describe "Sequel::Dataset convenience methods" do
746
+ before(:all) do
747
+ @db = INTEGRATION_DB
748
+ @db.create_table!(:a){Integer :a; Integer :b; Integer :c}
749
+ @ds = @db[:a]
750
+ @ds.insert(1, 3, 5)
751
+ @ds.insert(1, 3, 6)
752
+ @ds.insert(1, 4, 5)
753
+ @ds.insert(2, 3, 5)
754
+ @ds.insert(2, 4, 6)
755
+ end
756
+ after(:all) do
757
+ @db.drop_table(:a)
758
+ end
759
+
760
+ it "#group_rollup should include hierarchy of groupings" do
761
+ @ds.group_by(:a).group_rollup.select_map([:a, :sum.sql_function(:b).cast(Integer).as(:b), :sum.sql_function(:c).cast(Integer).as(:c)]).sort_by{|x| x.inspect}.should == [[1, 10, 16], [2, 7, 11], [nil, 17, 27]]
762
+ @ds.group_by(:a, :b).group_rollup.select_map([:a, :b, :sum.sql_function(:c).cast(Integer).as(:c)]).sort_by{|x| x.inspect}.should == [[1, 3, 11], [1, 4, 5], [1, nil, 16], [2, 3, 5], [2, 4, 6], [2, nil, 11], [nil, nil, 27]]
763
+ end if INTEGRATION_DB.dataset.supports_group_rollup?
764
+
765
+ it "#group_cube should include all combinations of groupings" do
766
+ @ds.group_by(:a).group_cube.select_map([:a, :sum.sql_function(:b).cast(Integer).as(:b), :sum.sql_function(:c).cast(Integer).as(:c)]).sort_by{|x| x.inspect}.should == [[1, 10, 16], [2, 7, 11], [nil, 17, 27]]
767
+ @ds.group_by(:a, :b).group_cube.select_map([:a, :b, :sum.sql_function(:c).cast(Integer).as(:c)]).sort_by{|x| x.inspect}.should == [[1, 3, 11], [1, 4, 5], [1, nil, 16], [2, 3, 5], [2, 4, 6], [2, nil, 11], [nil, 3, 16], [nil, 4, 11], [nil, nil, 27]]
768
+ end if INTEGRATION_DB.dataset.supports_group_cube?
769
+ end
770
+
716
771
  describe "Sequel::Dataset convenience methods" do
717
772
  before(:all) do
718
773
  @db = INTEGRATION_DB
@@ -738,6 +793,22 @@ describe "Sequel::Dataset convenience methods" do
738
793
  @ds.empty?.should == false
739
794
  end
740
795
 
796
+ it "#empty? should work correctly for datasets with limits" do
797
+ ds = @ds.limit(1)
798
+ ds.empty?.should == true
799
+ ds.insert(20, 10)
800
+ ds.empty?.should == false
801
+ end
802
+
803
+ it "#empty? should work correctly for datasets with limits and offsets" do
804
+ ds = @ds.limit(1, 1)
805
+ ds.empty?.should == true
806
+ ds.insert(20, 10)
807
+ ds.empty?.should == true
808
+ ds.insert(20, 10)
809
+ ds.empty?.should == false
810
+ end
811
+
741
812
  it "#group_and_count should return a grouping by count" do
742
813
  @ds.group_and_count(:a).order(:count).all.should == []
743
814
  @ds.insert(20, 10)
@@ -66,6 +66,10 @@ describe "Prepared Statements and Bound Arguments" do
66
66
  @ds.filter(:id=>:$i).filter(:numb=>@ds.select(:numb).filter(:numb=>:$n)).filter(:id=>:$j).call(:select, :n=>10, :i=>1, :j=>1).should == [{:id=>1, :numb=>10}]
67
67
  end
68
68
 
69
+ specify "should support subselects with exists with call" do
70
+ @ds.filter(:id=>:$i).filter(@ds.select(:numb).filter(:numb=>:$n).exists).filter(:id=>:$j).call(:select, :n=>10, :i=>1, :j=>1).should == [{:id=>1, :numb=>10}]
71
+ end
72
+
69
73
  specify "should support subselects with literal strings with call" do
70
74
  @ds.filter(:id=>:$i, :numb=>@ds.select(:numb).filter("numb = ?", :$n)).call(:select, :n=>10, :i=>1).should == [{:id=>1, :numb=>10}]
71
75
  end
@@ -151,6 +155,10 @@ describe "Prepared Statements and Bound Arguments" do
151
155
  @ds.filter(:id=>:$i).filter(:numb=>@ds.select(:numb).filter(:numb=>:$n)).filter(:id=>:$j).prepare(:select, :seq_select).call(:n=>10, :i=>1, :j=>1).should == [{:id=>1, :numb=>10}]
152
156
  end
153
157
 
158
+ specify "should support subselects with exists with prepare" do
159
+ @ds.filter(:id=>:$i).filter(@ds.select(:numb).filter(:numb=>:$n).exists).filter(:id=>:$j).prepare(:select, :seq_select).call(:n=>10, :i=>1, :j=>1).should == [{:id=>1, :numb=>10}]
160
+ end
161
+
154
162
  specify "should support subselects with literal strings with prepare" do
155
163
  @ds.filter(:id=>:$i, :numb=>@ds.select(:numb).filter("numb = ?", :$n)).prepare(:select, :seq_select).call(:n=>10, :i=>1).should == [{:id=>1, :numb=>10}]
156
164
  end
@@ -187,6 +187,33 @@ describe Sequel::Model::Associations::AssociationReflection, "#associated_object
187
187
  end
188
188
  end
189
189
 
190
+ describe Sequel::Model::Associations::AssociationReflection do
191
+ before do
192
+ @c = Class.new(Sequel::Model(:foo))
193
+ @c.meta_def(:name){"C"}
194
+ end
195
+
196
+ it "one_to_many #qualified_primary_key should be a qualified version of the primary key" do
197
+ @c.one_to_many :cs, :class=>@c
198
+ @c.dataset.literal(@c.association_reflection(:cs).qualified_primary_key).should == 'foo.id'
199
+ end
200
+
201
+ it "many_to_many #associated_key_column should be the left key" do
202
+ @c.many_to_many :cs, :class=>@c
203
+ @c.association_reflection(:cs).associated_key_column.should == :c_id
204
+ end
205
+
206
+ it "many_to_many #qualified_right_key should be a qualified version of the primary key" do
207
+ @c.many_to_many :cs, :class=>@c, :right_key=>:c2_id
208
+ @c.dataset.literal(@c.association_reflection(:cs).qualified_right_key).should == 'cs_cs.c2_id'
209
+ end
210
+
211
+ it "many_to_many #qualified_right_primary_key should be a qualified version of the primary key" do
212
+ @c.many_to_many :cs, :class=>@c
213
+ @c.dataset.literal(@c.association_reflection(:cs).qualified_right_primary_key).should == 'foo.id'
214
+ end
215
+ end
216
+
190
217
  describe Sequel::Model::Associations::AssociationReflection, "#remove_before_destroy?" do
191
218
  before do
192
219
  @c = Class.new(Sequel::Model(:foo))
@@ -148,6 +148,21 @@ describe Sequel::Model, "many_to_one" do
148
148
  MODEL_DB.sqls.should == ["SELECT * FROM nodes WHERE (nodes.id = 234) LIMIT 1"]
149
149
  end
150
150
 
151
+ it "should allow association with the same name as the key if :key_alias is given" do
152
+ @c2.def_column_alias(:parent_id_id, :parent_id)
153
+ @c2.many_to_one :parent_id, :key_column=>:parent_id, :class => @c2
154
+ d = @c2.load(:id => 1, :parent_id => 234)
155
+ d.parent_id_dataset.sql.should == "SELECT * FROM nodes WHERE (nodes.id = 234) LIMIT 1"
156
+ d.parent_id.should == @c2.load(:x => 1, :id => 1)
157
+ d.parent_id_id.should == 234
158
+ d[:parent_id].should == 234
159
+ MODEL_DB.sqls.should == ["SELECT * FROM nodes WHERE (nodes.id = 234) LIMIT 1"]
160
+
161
+ d.parent_id_id = 3
162
+ d.parent_id_id.should == 3
163
+ d[:parent_id].should == 3
164
+ end
165
+
151
166
  it "should use implicit class if omitted" do
152
167
  begin
153
168
  class ::ParParent < Sequel::Model; end
@@ -1181,7 +1196,7 @@ describe Sequel::Model, "one_to_many" do
1181
1196
  a = @c1.load(:id => 2345, :node_id => 1234)
1182
1197
  a.should == n.remove_attribute(a)
1183
1198
  a.values.should == {:node_id => nil, :id => 2345}
1184
- MODEL_DB.sqls.should == ["SELECT 1 FROM attributes WHERE ((attributes.node_id = 1234) AND (id = 2345)) LIMIT 1", 'UPDATE attributes SET node_id = NULL WHERE (id = 2345)']
1199
+ MODEL_DB.sqls.should == ["SELECT 1 AS one FROM attributes WHERE ((attributes.node_id = 1234) AND (id = 2345)) LIMIT 1", 'UPDATE attributes SET node_id = NULL WHERE (id = 2345)']
1185
1200
  end
1186
1201
 
1187
1202
  it "should have the remove_ method raise an error if the passed object is not already associated" do
@@ -1191,7 +1206,7 @@ describe Sequel::Model, "one_to_many" do
1191
1206
  a = @c1.load(:id => 2345, :node_id => 1234)
1192
1207
  @c1.dataset._fetch = []
1193
1208
  proc{n.remove_attribute(a)}.should raise_error(Sequel::Error)
1194
- MODEL_DB.sqls.should == ["SELECT 1 FROM attributes WHERE ((attributes.node_id = 1234) AND (id = 2345)) LIMIT 1"]
1209
+ MODEL_DB.sqls.should == ["SELECT 1 AS one FROM attributes WHERE ((attributes.node_id = 1234) AND (id = 2345)) LIMIT 1"]
1195
1210
  end
1196
1211
 
1197
1212
  it "should accept a hash for the add_ method and create a new record" do
@@ -1287,7 +1302,7 @@ describe Sequel::Model, "one_to_many" do
1287
1302
  n.remove_attribute(a).should == a
1288
1303
  sqls = MODEL_DB.sqls
1289
1304
  sqls.pop.should =~ /UPDATE attributes SET (node_id|y) = NULL, (node_id|y) = NULL WHERE \(id = 2345\)/
1290
- sqls.should == ["SELECT 1 FROM attributes WHERE ((attributes.node_id = 1234) AND (attributes.y = 5) AND (id = 2345)) LIMIT 1"]
1305
+ sqls.should == ["SELECT 1 AS one FROM attributes WHERE ((attributes.node_id = 1234) AND (attributes.y = 5) AND (id = 2345)) LIMIT 1"]
1291
1306
  end
1292
1307
 
1293
1308
  it "should accept a array of composite primary key values for the remove_ method and remove an existing record" do
@@ -35,6 +35,26 @@ describe "Model attribute setters" do
35
35
  end
36
36
  end
37
37
 
38
+ describe "Model.def_column_alias" do
39
+ before do
40
+ @o = Class.new(Sequel::Model(:items)) do
41
+ columns :id
42
+ def_column_alias(:id2, :id)
43
+ end.load(:id=>1)
44
+ MODEL_DB.reset
45
+ end
46
+
47
+ it "should create an getter alias for the column" do
48
+ @o.id2.should == 1
49
+ end
50
+
51
+ it "should create an setter alias for the column" do
52
+ @o.id2 = 2
53
+ @o.id2.should == 2
54
+ @o.values.should == {:id => 2}
55
+ end
56
+ end
57
+
38
58
  describe Sequel::Model, "dataset" do
39
59
  before do
40
60
  @a = Class.new(Sequel::Model(:items))
@@ -102,6 +102,16 @@ describe Sequel::Model, "#eager" do
102
102
  MODEL_DB.sqls.should == []
103
103
  end
104
104
 
105
+ it "should eagerly load a single many_to_one association with the same name as the column" do
106
+ EagerAlbum.def_column_alias(:band_id_id, :band_id)
107
+ EagerAlbum.many_to_one :band_id, :key_column=>:band_id, :class=>EagerBand
108
+ a = EagerAlbum.eager(:band_id).all
109
+ MODEL_DB.sqls.should == ['SELECT * FROM albums', 'SELECT * FROM bands WHERE (bands.id IN (2))']
110
+ a.should == [EagerAlbum.load(:id => 1, :band_id => 2)]
111
+ a.first.band_id.should == EagerBand.load(:id=>2)
112
+ MODEL_DB.sqls.should == []
113
+ end
114
+
105
115
  it "should eagerly load a single one_to_one association" do
106
116
  EagerAlbum.one_to_one :track, :class=>'EagerTrack', :key=>:album_id
107
117
  a = EagerAlbum.eager(:track).all
@@ -757,6 +767,17 @@ describe Sequel::Model, "#eager_graph" do
757
767
  a.first.band.should == GraphBand.load(:id => 2, :vocalist_id=>3)
758
768
  end
759
769
 
770
+ it "should eagerly load a single many_to_one association with the same name as a column" do
771
+ GraphAlbum.def_column_alias(:band_id_id, :band_id)
772
+ GraphAlbum.many_to_one :band_id, :key_column=>:band_id, :class=>GraphBand
773
+ ds = GraphAlbum.eager_graph(:band_id)
774
+ ds.sql.should == 'SELECT albums.id, albums.band_id, band_id.id AS band_id_id, band_id.vocalist_id FROM albums LEFT OUTER JOIN bands AS band_id ON (band_id.id = albums.band_id)'
775
+ ds._fetch = {:id=>1, :band_id=>2, :band_id_id=>2, :vocalist_id=>3}
776
+ a = ds.all
777
+ a.should == [GraphAlbum.load(:id => 1, :band_id => 2)]
778
+ a.first.band_id.should == GraphBand.load(:id => 2, :vocalist_id=>3)
779
+ end
780
+
760
781
  it "should eagerly load a single one_to_one association" do
761
782
  GraphAlbum.one_to_one :track, :class=>'GraphTrack', :key=>:album_id
762
783
  ds = GraphAlbum.eager_graph(:track)
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.30.0
4
+ version: 3.31.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-12-01 00:00:00.000000000 Z
12
+ date: 2012-01-03 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: The Database Toolkit for Ruby
15
15
  email: code@jeremyevans.net
@@ -89,6 +89,7 @@ extra_rdoc_files:
89
89
  - doc/release_notes/3.28.0.txt
90
90
  - doc/release_notes/3.29.0.txt
91
91
  - doc/release_notes/3.30.0.txt
92
+ - doc/release_notes/3.31.0.txt
92
93
  files:
93
94
  - MIT-LICENSE
94
95
  - CHANGELOG
@@ -156,6 +157,7 @@ files:
156
157
  - doc/release_notes/3.28.0.txt
157
158
  - doc/release_notes/3.29.0.txt
158
159
  - doc/release_notes/3.30.0.txt
160
+ - doc/release_notes/3.31.0.txt
159
161
  - doc/sharding.rdoc
160
162
  - doc/sql.rdoc
161
163
  - doc/validations.rdoc