sequel 2.6.0 → 2.7.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.
- data/CHANGELOG +64 -0
- data/Rakefile +1 -1
- data/lib/sequel_core/adapters/jdbc.rb +6 -2
- data/lib/sequel_core/adapters/jdbc/oracle.rb +23 -0
- data/lib/sequel_core/adapters/oracle.rb +4 -77
- data/lib/sequel_core/adapters/postgres.rb +39 -26
- data/lib/sequel_core/adapters/shared/mssql.rb +0 -1
- data/lib/sequel_core/adapters/shared/mysql.rb +1 -1
- data/lib/sequel_core/adapters/shared/oracle.rb +82 -0
- data/lib/sequel_core/adapters/shared/postgres.rb +65 -46
- data/lib/sequel_core/core_ext.rb +10 -0
- data/lib/sequel_core/core_sql.rb +7 -0
- data/lib/sequel_core/database.rb +22 -0
- data/lib/sequel_core/database/schema.rb +1 -1
- data/lib/sequel_core/dataset.rb +29 -11
- data/lib/sequel_core/dataset/sql.rb +27 -7
- data/lib/sequel_core/migration.rb +20 -2
- data/lib/sequel_core/object_graph.rb +24 -10
- data/lib/sequel_core/schema/generator.rb +22 -9
- data/lib/sequel_core/schema/sql.rb +13 -9
- data/lib/sequel_core/sql.rb +27 -2
- data/lib/sequel_model/association_reflection.rb +251 -141
- data/lib/sequel_model/associations.rb +114 -61
- data/lib/sequel_model/base.rb +25 -21
- data/lib/sequel_model/eager_loading.rb +17 -40
- data/lib/sequel_model/hooks.rb +25 -24
- data/lib/sequel_model/record.rb +29 -51
- data/lib/sequel_model/schema.rb +1 -1
- data/lib/sequel_model/validations.rb +13 -3
- data/spec/adapters/postgres_spec.rb +104 -18
- data/spec/adapters/spec_helper.rb +4 -1
- data/spec/integration/eager_loader_test.rb +5 -4
- data/spec/integration/spec_helper.rb +4 -1
- data/spec/sequel_core/connection_pool_spec.rb +24 -24
- data/spec/sequel_core/core_sql_spec.rb +12 -0
- data/spec/sequel_core/dataset_spec.rb +77 -2
- data/spec/sequel_core/expression_filters_spec.rb +6 -0
- data/spec/sequel_core/object_graph_spec.rb +40 -2
- data/spec/sequel_core/schema_spec.rb +13 -0
- data/spec/sequel_model/association_reflection_spec.rb +8 -8
- data/spec/sequel_model/associations_spec.rb +164 -3
- data/spec/sequel_model/caching_spec.rb +2 -1
- data/spec/sequel_model/eager_loading_spec.rb +107 -3
- data/spec/sequel_model/hooks_spec.rb +38 -22
- data/spec/sequel_model/model_spec.rb +11 -35
- data/spec/sequel_model/plugins_spec.rb +4 -2
- data/spec/sequel_model/record_spec.rb +8 -5
- data/spec/sequel_model/validations_spec.rb +25 -0
- data/spec/spec_config.rb +4 -3
- metadata +21 -19
@@ -18,21 +18,21 @@ describe Sequel::Model::Associations::AssociationReflection, "#associated_class"
|
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
-
describe Sequel::Model::Associations::AssociationReflection, "#
|
21
|
+
describe Sequel::Model::Associations::AssociationReflection, "#primary_key" do
|
22
22
|
before do
|
23
23
|
@c = Class.new(Sequel::Model)
|
24
24
|
class ::ParParent < Sequel::Model; end
|
25
25
|
end
|
26
26
|
|
27
|
-
it "should use the :
|
28
|
-
@c.many_to_one :c, :class=>ParParent, :
|
29
|
-
@c.association_reflection(:c).should include(:
|
30
|
-
@c.association_reflection(:c).
|
27
|
+
it "should use the :primary_key value if present" do
|
28
|
+
@c.many_to_one :c, :class=>ParParent, :primary_key=>:blah__blah
|
29
|
+
@c.association_reflection(:c).should include(:primary_key)
|
30
|
+
@c.association_reflection(:c).primary_key.should == :blah__blah
|
31
31
|
end
|
32
|
-
it "should use the associated table's primary key if :
|
32
|
+
it "should use the associated table's primary key if :primary_key is not present" do
|
33
33
|
@c.many_to_one :c, :class=>'ParParent'
|
34
|
-
@c.association_reflection(:c).should_not include(:
|
35
|
-
@c.association_reflection(:c).
|
34
|
+
@c.association_reflection(:c).should_not include(:primary_key)
|
35
|
+
@c.association_reflection(:c).primary_key.should == :id
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
@@ -46,7 +46,7 @@ end
|
|
46
46
|
describe Sequel::Model, "many_to_one" do
|
47
47
|
before do
|
48
48
|
MODEL_DB.reset
|
49
|
-
|
49
|
+
|
50
50
|
@c2 = Class.new(Sequel::Model(:nodes)) do
|
51
51
|
unrestrict_primary_key
|
52
52
|
columns :id, :parent_id, :par_parent_id, :blah
|
@@ -105,6 +105,12 @@ describe Sequel::Model, "many_to_one" do
|
|
105
105
|
MODEL_DB.sqls.should == ["SELECT * FROM nodes WHERE (nodes.id = 567) LIMIT 1"]
|
106
106
|
end
|
107
107
|
|
108
|
+
it "should use :primary_key option if given" do
|
109
|
+
@c2.many_to_one :parent, :class => @c2, :key => :blah, :primary_key => :pk
|
110
|
+
@c2.new(:id => 1, :blah => 567).parent
|
111
|
+
MODEL_DB.sqls.should == ["SELECT * FROM nodes WHERE (nodes.pk = 567) LIMIT 1"]
|
112
|
+
end
|
113
|
+
|
108
114
|
it "should use :select option if given" do
|
109
115
|
@c2.many_to_one :parent, :class => @c2, :key => :blah, :select=>[:id, :name]
|
110
116
|
@c2.new(:id => 1, :blah => 567).parent
|
@@ -157,6 +163,21 @@ describe Sequel::Model, "many_to_one" do
|
|
157
163
|
d.values.should == {:id => 1, :parent_id => 6677}
|
158
164
|
end
|
159
165
|
|
166
|
+
it "should have the setter method respect the :primary_key option" do
|
167
|
+
@c2.many_to_one :parent, :class => @c2, :primary_key=>:blah
|
168
|
+
|
169
|
+
d = @c2.new(:id => 1)
|
170
|
+
d.parent = @c2.new(:id => 4321, :blah=>444)
|
171
|
+
d.values.should == {:id => 1, :parent_id => 444}
|
172
|
+
|
173
|
+
d.parent = nil
|
174
|
+
d.values.should == {:id => 1, :parent_id => nil}
|
175
|
+
|
176
|
+
e = @c2.new(:id => 6677, :blah=>8)
|
177
|
+
d.parent = e
|
178
|
+
d.values.should == {:id => 1, :parent_id => 8}
|
179
|
+
end
|
180
|
+
|
160
181
|
it "should not persist changes until saved" do
|
161
182
|
@c2.many_to_one :parent, :class => @c2
|
162
183
|
|
@@ -289,6 +310,14 @@ describe Sequel::Model, "many_to_one" do
|
|
289
310
|
@c2.instance_methods.collect{|x| x.to_s}.should_not(include('parent='))
|
290
311
|
end
|
291
312
|
|
313
|
+
it "should not add associations methods directly to class" do
|
314
|
+
@c2.many_to_one :parent, :class => @c2
|
315
|
+
@c2.instance_methods.collect{|x| x.to_s}.should(include('parent'))
|
316
|
+
@c2.instance_methods.collect{|x| x.to_s}.should(include('parent='))
|
317
|
+
@c2.instance_methods(false).collect{|x| x.to_s}.should_not(include('parent'))
|
318
|
+
@c2.instance_methods(false).collect{|x| x.to_s}.should_not(include('parent='))
|
319
|
+
end
|
320
|
+
|
292
321
|
it "should raise an error if trying to set a model object that doesn't have a valid primary key" do
|
293
322
|
@c2.many_to_one :parent, :class => @c2
|
294
323
|
p = @c2.new
|
@@ -520,6 +549,18 @@ describe Sequel::Model, "one_to_many" do
|
|
520
549
|
MODEL_DB.sqls.should == ['UPDATE attributes SET node_id = NULL WHERE (id = 2345)']
|
521
550
|
end
|
522
551
|
|
552
|
+
it "should have add_ method respect the :primary_key option" do
|
553
|
+
@c2.one_to_many :attributes, :class => @c1, :primary_key=>:xxx
|
554
|
+
|
555
|
+
n = @c2.new(:id => 1234, :xxx=>5)
|
556
|
+
a = @c1.new(:id => 2345)
|
557
|
+
a.save!
|
558
|
+
MODEL_DB.reset
|
559
|
+
a.should == n.add_attribute(a)
|
560
|
+
MODEL_DB.sqls.should == ['UPDATE attributes SET node_id = 5 WHERE (id = 2345)']
|
561
|
+
end
|
562
|
+
|
563
|
+
|
523
564
|
it "should raise an error in add_ and remove_ if the passed object returns false to save (is not valid)" do
|
524
565
|
@c2.one_to_many :attributes, :class => @c1
|
525
566
|
n = @c2.new(:id => 1234)
|
@@ -540,6 +581,12 @@ describe Sequel::Model, "one_to_many" do
|
|
540
581
|
proc{a.remove_all_attributes}.should raise_error(Sequel::Error)
|
541
582
|
end
|
542
583
|
|
584
|
+
it "should use :primary_key option if given" do
|
585
|
+
@c1.one_to_many :nodes, :class => @c2, :primary_key => :node_id, :key=>:id
|
586
|
+
n = @c1.load(:id => 1234, :node_id=>4321)
|
587
|
+
n.nodes_dataset.sql.should == "SELECT * FROM nodes WHERE (nodes.id = 4321)"
|
588
|
+
end
|
589
|
+
|
543
590
|
it "should support a select option" do
|
544
591
|
@c2.one_to_many :attributes, :class => @c1, :select => [:id, :name]
|
545
592
|
|
@@ -727,6 +774,22 @@ describe Sequel::Model, "one_to_many" do
|
|
727
774
|
im.should_not(include('remove_all_attributes'))
|
728
775
|
end
|
729
776
|
|
777
|
+
it "should not add associations methods directly to class" do
|
778
|
+
@c2.one_to_many :attributes, :class => @c1
|
779
|
+
im = @c2.instance_methods.collect{|x| x.to_s}
|
780
|
+
im.should(include('attributes'))
|
781
|
+
im.should(include('attributes_dataset'))
|
782
|
+
im.should(include('add_attribute'))
|
783
|
+
im.should(include('remove_attribute'))
|
784
|
+
im.should(include('remove_all_attributes'))
|
785
|
+
im2 = @c2.instance_methods(false).collect{|x| x.to_s}
|
786
|
+
im2.should_not(include('attributes'))
|
787
|
+
im2.should_not(include('attributes_dataset'))
|
788
|
+
im2.should_not(include('add_attribute'))
|
789
|
+
im2.should_not(include('remove_attribute'))
|
790
|
+
im2.should_not(include('remove_all_attributes'))
|
791
|
+
end
|
792
|
+
|
730
793
|
it "should have has_many alias" do
|
731
794
|
@c2.has_many :attributes, :class => @c1
|
732
795
|
|
@@ -777,6 +840,12 @@ describe Sequel::Model, "one_to_many" do
|
|
777
840
|
MODEL_DB.sqls.first.should == 'UPDATE attributes SET node_id = NULL WHERE (node_id = 1234)'
|
778
841
|
end
|
779
842
|
|
843
|
+
it "should have the remove_all_ method respect the :primary_key option" do
|
844
|
+
@c2.one_to_many :attributes, :class => @c1, :primary_key=>:xxx
|
845
|
+
@c2.new(:id => 1234, :xxx=>5).remove_all_attributes
|
846
|
+
MODEL_DB.sqls.first.should == 'UPDATE attributes SET node_id = NULL WHERE (node_id = 5)'
|
847
|
+
end
|
848
|
+
|
780
849
|
it "remove_all should set the cached instance variable to []" do
|
781
850
|
@c2.one_to_many :attributes, :class => @c1
|
782
851
|
node = @c2.new(:id => 1234)
|
@@ -828,7 +897,7 @@ describe Sequel::Model, "one_to_many" do
|
|
828
897
|
att.values.should == {}
|
829
898
|
end
|
830
899
|
|
831
|
-
it "should not add a
|
900
|
+
it "should not add a setter method if the :one_to_one option is true and :read_only option is true" do
|
832
901
|
@c2.one_to_many :attributes, :class => @c1, :one_to_one=>true, :read_only=>true
|
833
902
|
im = @c2.instance_methods.collect{|x| x.to_s}
|
834
903
|
im.should(include('attribute'))
|
@@ -861,6 +930,25 @@ describe Sequel::Model, "one_to_many" do
|
|
861
930
|
MODEL_DB.sqls.last.should == 'UPDATE attributes SET node_id = NULL WHERE ((node_id = 1234) AND (id != 3))'
|
862
931
|
end
|
863
932
|
|
933
|
+
it "should have the setter method for the :one_to_one option respect the :primary_key option" do
|
934
|
+
@c2.one_to_many :attributes, :class => @c1, :one_to_one=>true, :primary_key=>:xxx
|
935
|
+
attrib = @c1.new(:id=>3)
|
936
|
+
d = @c1.dataset
|
937
|
+
def d.fetch_rows(s); yield({:id=>3}) end
|
938
|
+
@c2.new(:id => 1234, :xxx=>5).attribute = attrib
|
939
|
+
['INSERT INTO attributes (node_id, id) VALUES (5, 3)',
|
940
|
+
'INSERT INTO attributes (id, node_id) VALUES (3, 5)'].should(include(MODEL_DB.sqls.first))
|
941
|
+
MODEL_DB.sqls.last.should == 'UPDATE attributes SET node_id = NULL WHERE ((node_id = 5) AND (id != 3))'
|
942
|
+
MODEL_DB.sqls.length.should == 2
|
943
|
+
@c2.new(:id => 321, :xxx=>5).attribute.should == attrib
|
944
|
+
MODEL_DB.sqls.clear
|
945
|
+
attrib = @c1.load(:id=>3)
|
946
|
+
@c2.new(:id => 621, :xxx=>5).attribute = attrib
|
947
|
+
MODEL_DB.sqls.length.should == 2
|
948
|
+
MODEL_DB.sqls.first.should =~ /UPDATE attributes SET (node_id = 5, id = 3|id = 3, node_id = 5) WHERE \(id = 3\)/
|
949
|
+
MODEL_DB.sqls.last.should == 'UPDATE attributes SET node_id = NULL WHERE ((node_id = 5) AND (id != 3))'
|
950
|
+
end
|
951
|
+
|
864
952
|
it "should raise an error if the one_to_one getter would be the same as the association name" do
|
865
953
|
proc{@c2.one_to_many :song, :class => @c1, :one_to_one=>true}.should raise_error(Sequel::Error)
|
866
954
|
end
|
@@ -873,7 +961,7 @@ describe Sequel::Model, "one_to_many" do
|
|
873
961
|
|
874
962
|
it "should make non getter and setter methods private if :one_to_one option is used" do
|
875
963
|
@c2.one_to_many :attributes, :class => @c1, :one_to_one=>true do |ds| end
|
876
|
-
meths = @c2.private_instance_methods
|
964
|
+
meths = @c2.private_instance_methods.collect{|x| x.to_s}
|
877
965
|
meths.should(include("attributes"))
|
878
966
|
meths.should(include("add_attribute"))
|
879
967
|
meths.should(include("attributes_dataset"))
|
@@ -994,6 +1082,7 @@ describe Sequel::Model, "many_to_many" do
|
|
994
1082
|
|
995
1083
|
@c1 = Class.new(Sequel::Model(:attributes)) do
|
996
1084
|
unrestrict_primary_key
|
1085
|
+
attr_accessor :yyy
|
997
1086
|
def self.name; 'Attribute'; end
|
998
1087
|
def self.to_s; 'Attribute'; end
|
999
1088
|
columns :id
|
@@ -1081,6 +1170,11 @@ describe Sequel::Model, "many_to_many" do
|
|
1081
1170
|
a.sql.should == 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON ((attributes_nodes.attribute_id = attributes.id) AND (attributes_nodes.node_id = 1234)) ORDER BY blah1, blah2'
|
1082
1171
|
end
|
1083
1172
|
|
1173
|
+
it "should support :left_primary_key and :right_primary_key options" do
|
1174
|
+
@c2.many_to_many :attributes, :class => @c1, :left_primary_key=>:xxx, :right_primary_key=>:yyy
|
1175
|
+
@c2.new(:id => 1234, :xxx=>5).attributes_dataset.sql.should == 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON ((attributes_nodes.attribute_id = attributes.yyy) AND (attributes_nodes.node_id = 5))'
|
1176
|
+
end
|
1177
|
+
|
1084
1178
|
it "should support a select option" do
|
1085
1179
|
@c2.many_to_many :attributes, :class => @c1, :select => :blah
|
1086
1180
|
|
@@ -1182,6 +1276,26 @@ describe Sequel::Model, "many_to_many" do
|
|
1182
1276
|
MODEL_DB.sqls.first.should == 'DELETE FROM attributes_nodes WHERE ((node_id = 1234) AND (attribute_id = 2345))'
|
1183
1277
|
end
|
1184
1278
|
|
1279
|
+
it "should have the add_ method respect the :left_primary_key and :right_primary_key options" do
|
1280
|
+
@c2.many_to_many :attributes, :class => @c1, :left_primary_key=>:xxx, :right_primary_key=>:yyy
|
1281
|
+
|
1282
|
+
n = @c2.new(:id => 1234, :xxx=>5)
|
1283
|
+
a = @c1.new(:id => 2345, :yyy=>8)
|
1284
|
+
a.should == n.add_attribute(a)
|
1285
|
+
['INSERT INTO attributes_nodes (node_id, attribute_id) VALUES (5, 8)',
|
1286
|
+
'INSERT INTO attributes_nodes (attribute_id, node_id) VALUES (8, 5)'
|
1287
|
+
].should(include(MODEL_DB.sqls.first))
|
1288
|
+
end
|
1289
|
+
|
1290
|
+
it "should have the remove_ method respect the :left_primary_key and :right_primary_key options" do
|
1291
|
+
@c2.many_to_many :attributes, :class => @c1, :left_primary_key=>:xxx, :right_primary_key=>:yyy
|
1292
|
+
|
1293
|
+
n = @c2.new(:id => 1234, :xxx=>5)
|
1294
|
+
a = @c1.new(:id => 2345, :yyy=>8)
|
1295
|
+
a.should == n.remove_attribute(a)
|
1296
|
+
MODEL_DB.sqls.first.should == 'DELETE FROM attributes_nodes WHERE ((node_id = 5) AND (attribute_id = 8))'
|
1297
|
+
end
|
1298
|
+
|
1185
1299
|
it "should raise an error if the model object doesn't have a valid primary key" do
|
1186
1300
|
@c2.many_to_many :attributes, :class => @c1
|
1187
1301
|
a = @c2.new
|
@@ -1300,6 +1414,22 @@ describe Sequel::Model, "many_to_many" do
|
|
1300
1414
|
im.should_not(include('remove_all_attributes'))
|
1301
1415
|
end
|
1302
1416
|
|
1417
|
+
it "should not add associations methods directly to class" do
|
1418
|
+
@c2.many_to_many :attributes, :class => @c1
|
1419
|
+
im = @c2.instance_methods.collect{|x| x.to_s}
|
1420
|
+
im.should(include('attributes'))
|
1421
|
+
im.should(include('attributes_dataset'))
|
1422
|
+
im.should(include('add_attribute'))
|
1423
|
+
im.should(include('remove_attribute'))
|
1424
|
+
im.should(include('remove_all_attributes'))
|
1425
|
+
im2 = @c2.instance_methods(false).collect{|x| x.to_s}
|
1426
|
+
im2.should_not(include('attributes'))
|
1427
|
+
im2.should_not(include('attributes_dataset'))
|
1428
|
+
im2.should_not(include('add_attribute'))
|
1429
|
+
im2.should_not(include('remove_attribute'))
|
1430
|
+
im2.should_not(include('remove_all_attributes'))
|
1431
|
+
end
|
1432
|
+
|
1303
1433
|
it "should have has_and_belongs_to_many alias" do
|
1304
1434
|
@c2.has_and_belongs_to_many :attributes, :class => @c1
|
1305
1435
|
|
@@ -1315,6 +1445,12 @@ describe Sequel::Model, "many_to_many" do
|
|
1315
1445
|
MODEL_DB.sqls.first.should == 'DELETE FROM attributes_nodes WHERE (node_id = 1234)'
|
1316
1446
|
end
|
1317
1447
|
|
1448
|
+
it "should have the remove_all_ method respect the :left_primary_key option" do
|
1449
|
+
@c2.many_to_many :attributes, :class => @c1, :left_primary_key=>:xxx
|
1450
|
+
@c2.new(:id => 1234, :xxx=>5).remove_all_attributes
|
1451
|
+
MODEL_DB.sqls.first.should == 'DELETE FROM attributes_nodes WHERE (node_id = 5)'
|
1452
|
+
end
|
1453
|
+
|
1318
1454
|
it "remove_all should set the cached instance variable to []" do
|
1319
1455
|
@c2.many_to_many :attributes, :class => @c1
|
1320
1456
|
node = @c2.new(:id => 1234)
|
@@ -1463,6 +1599,20 @@ describe Sequel::Model, "many_to_many" do
|
|
1463
1599
|
p.remove_attribute(c).should == nil
|
1464
1600
|
p.attributes.should == [c]
|
1465
1601
|
end
|
1602
|
+
|
1603
|
+
it "should support a :uniq option that removes duplicates from the association" do
|
1604
|
+
h = []
|
1605
|
+
@c2.many_to_many :attributes, :class => @c1, :uniq=>true
|
1606
|
+
@c1.class_eval do
|
1607
|
+
def @dataset.fetch_rows(sql)
|
1608
|
+
yield({:id=>20})
|
1609
|
+
yield({:id=>30})
|
1610
|
+
yield({:id=>20})
|
1611
|
+
yield({:id=>30})
|
1612
|
+
end
|
1613
|
+
end
|
1614
|
+
@c2.load(:id=>10, :parent_id=>20).attributes.should == [@c1.load(:id=>20), @c1.load(:id=>30)]
|
1615
|
+
end
|
1466
1616
|
end
|
1467
1617
|
|
1468
1618
|
describe Sequel::Model, " association reflection methods" do
|
@@ -1514,4 +1664,15 @@ describe Sequel::Model, " association reflection methods" do
|
|
1514
1664
|
@c1.associate :one_to_many, :children, :class => @c1
|
1515
1665
|
@c1.associations.sort_by{|x|x.to_s}.should == [:children, :parent]
|
1516
1666
|
end
|
1667
|
+
|
1668
|
+
it "association reflections should be copied upon subclasing" do
|
1669
|
+
@c1.associate :many_to_one, :parent, :class => @c1
|
1670
|
+
c = Class.new(@c1)
|
1671
|
+
@c1.associations.should == [:parent]
|
1672
|
+
c.associations.should == [:parent]
|
1673
|
+
c.associate :many_to_one, :parent2, :class => @c1
|
1674
|
+
@c1.associations.should == [:parent]
|
1675
|
+
c.associations.sort_by{|x| x.to_s}.should == [:parent, :parent2]
|
1676
|
+
c.instance_methods.map{|x| x.to_s}.should include('parent')
|
1677
|
+
end
|
1517
1678
|
end
|
@@ -18,7 +18,7 @@ describe Sequel::Model, "#eager" do
|
|
18
18
|
end
|
19
19
|
|
20
20
|
class ::EagerBand < Sequel::Model(:bands)
|
21
|
-
columns :id
|
21
|
+
columns :id, :p_k
|
22
22
|
one_to_many :albums, :class=>'EagerAlbum', :key=>:band_id, :eager=>:tracks
|
23
23
|
one_to_many :graph_albums, :class=>'EagerAlbum', :key=>:band_id, :eager_graph=>:tracks
|
24
24
|
many_to_many :members, :class=>'EagerBandMember', :left_key=>:band_id, :right_key=>:member_id, :join_table=>:bm
|
@@ -38,7 +38,7 @@ describe Sequel::Model, "#eager" do
|
|
38
38
|
end
|
39
39
|
|
40
40
|
class ::EagerGenre < Sequel::Model(:genres)
|
41
|
-
columns :id
|
41
|
+
columns :id, :xxx
|
42
42
|
many_to_many :albums, :class=>'EagerAlbum', :left_key=>:genre_id, :right_key=>:album_id, :join_table=>:ag
|
43
43
|
end
|
44
44
|
|
@@ -418,6 +418,47 @@ describe Sequel::Model, "#eager" do
|
|
418
418
|
MODEL_DB.sqls.should == ['SELECT * FROM albums', "SELECT id, ag.album_id AS x_foreign_key_x FROM genres INNER JOIN ag ON ((ag.genre_id = genres.id) AND (ag.album_id IN (1)))"]
|
419
419
|
end
|
420
420
|
|
421
|
+
it "should respect the association's :primary_key option" do
|
422
|
+
EagerAlbum.many_to_one :special_band, :class=>:EagerBand, :primary_key=>:p_k, :key=>:band_id
|
423
|
+
EagerBand.dataset.extend(Module.new {
|
424
|
+
def fetch_rows(sql)
|
425
|
+
MODEL_DB.sqls << sql
|
426
|
+
yield({:p_k=>2, :id=>1})
|
427
|
+
end
|
428
|
+
})
|
429
|
+
as = EagerAlbum.eager(:special_band).all
|
430
|
+
MODEL_DB.sqls.should == ['SELECT * FROM albums', "SELECT * FROM bands WHERE (bands.p_k IN (2))"]
|
431
|
+
as.length.should == 1
|
432
|
+
as.first.special_band.should == EagerBand.load(:p_k=>2, :id=>1)
|
433
|
+
MODEL_DB.sqls.clear
|
434
|
+
EagerAlbum.one_to_many :special_tracks, :class=>:EagerTrack, :primary_key=>:band_id, :key=>:album_id
|
435
|
+
EagerTrack.dataset.extend(Module.new {
|
436
|
+
def fetch_rows(sql)
|
437
|
+
MODEL_DB.sqls << sql
|
438
|
+
yield({:album_id=>2, :id=>1})
|
439
|
+
end
|
440
|
+
})
|
441
|
+
as = EagerAlbum.eager(:special_tracks).all
|
442
|
+
MODEL_DB.sqls.should == ['SELECT * FROM albums', "SELECT * FROM tracks WHERE (tracks.album_id IN (2))"]
|
443
|
+
as.length.should == 1
|
444
|
+
as.first.special_tracks.should == [EagerTrack.load(:album_id=>2, :id=>1)]
|
445
|
+
end
|
446
|
+
|
447
|
+
it "should respect many_to_many association's :left_primary_key and :right_primary_key options" do
|
448
|
+
EagerAlbum.many_to_many :special_genres, :class=>:EagerGenre, :left_primary_key=>:band_id, :left_key=>:album_id, :right_primary_key=>:xxx, :right_key=>:genre_id, :join_table=>:ag
|
449
|
+
EagerGenre.dataset.extend(Module.new {
|
450
|
+
def fetch_rows(sql)
|
451
|
+
MODEL_DB.sqls << sql
|
452
|
+
yield({:x_foreign_key_x=>2, :id=>5})
|
453
|
+
yield({:x_foreign_key_x=>2, :id=>6})
|
454
|
+
end
|
455
|
+
})
|
456
|
+
as = EagerAlbum.eager(:special_genres).all
|
457
|
+
MODEL_DB.sqls.should == ['SELECT * FROM albums', "SELECT genres.*, ag.album_id AS x_foreign_key_x FROM genres INNER JOIN ag ON ((ag.genre_id = genres.xxx) AND (ag.album_id IN (2)))"]
|
458
|
+
as.length.should == 1
|
459
|
+
as.first.special_genres.should == [EagerGenre.load(:id=>5), EagerGenre.load(:id=>6)]
|
460
|
+
end
|
461
|
+
|
421
462
|
it "should use the :eager_loader association option when eager loading" do
|
422
463
|
EagerAlbum.many_to_one :special_band, :eager_loader=>(proc do |key_hash, records, assocs|
|
423
464
|
item = EagerBand.filter(:album_id=>records.collect{|r| [r.pk, r.pk*2]}.flatten).order(:name).first
|
@@ -427,7 +468,7 @@ describe Sequel::Model, "#eager" do
|
|
427
468
|
items = EagerTrack.filter(:album_id=>records.collect{|r| [r.pk, r.pk*2]}.flatten).all
|
428
469
|
records.each{|r| r.associations[:special_tracks] = items}
|
429
470
|
end)
|
430
|
-
EagerAlbum.many_to_many :special_genres, :eager_loader=>(proc do |key_hash, records, assocs|
|
471
|
+
EagerAlbum.many_to_many :special_genres, :class=>:EagerGenre, :eager_loader=>(proc do |key_hash, records, assocs|
|
431
472
|
items = EagerGenre.inner_join(:ag, [:genre_id]).filter(:album_id=>records.collect{|r| r.pk}).all
|
432
473
|
records.each{|r| r.associations[:special_genres] = items}
|
433
474
|
end)
|
@@ -455,6 +496,16 @@ describe Sequel::Model, "#eager" do
|
|
455
496
|
MODEL_DB.sqls.length.should == 4
|
456
497
|
end
|
457
498
|
|
499
|
+
it "should respect :after_load callbacks on associations when eager loading" do
|
500
|
+
EagerAlbum.many_to_one :al_band, :class=>'EagerBand', :key=>:band_id, :after_load=>proc{|o, a| a.id *=2}
|
501
|
+
EagerAlbum.one_to_many :al_tracks, :class=>'EagerTrack', :key=>:album_id, :after_load=>proc{|o, os| os.each{|a| a.id *=2}}
|
502
|
+
EagerAlbum.many_to_many :al_genres, :class=>'EagerGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :after_load=>proc{|o, os| os.each{|a| a.id *=2}}
|
503
|
+
a = EagerAlbum.eager(:al_band, :al_tracks, :al_genres).all.first
|
504
|
+
a.should == EagerAlbum.load(:id => 1, :band_id => 2)
|
505
|
+
a.al_band.should == EagerBand.load(:id=>4)
|
506
|
+
a.al_tracks.should == [EagerTrack.load(:id=>6, :album_id=>1)]
|
507
|
+
a.al_genres.should == [EagerGenre.load(:id=>8)]
|
508
|
+
end
|
458
509
|
end
|
459
510
|
|
460
511
|
describe Sequel::Model, "#eager_graph" do
|
@@ -902,6 +953,42 @@ describe Sequel::Model, "#eager_graph" do
|
|
902
953
|
a[3].album.band.members.last.values.should == {:id => 6}
|
903
954
|
end
|
904
955
|
|
956
|
+
it "should respect the association's :primary_key option" do
|
957
|
+
GraphAlbum.many_to_one :inner_band, :class=>'GraphBand', :key=>:band_id, :primary_key=>:vocalist_id
|
958
|
+
ds = GraphAlbum.eager_graph(:inner_band)
|
959
|
+
ds.sql.should == 'SELECT albums.id, albums.band_id, inner_band.id AS inner_band_id, inner_band.vocalist_id FROM albums LEFT OUTER JOIN bands AS inner_band ON (inner_band.vocalist_id = albums.band_id)'
|
960
|
+
def ds.fetch_rows(sql, &block)
|
961
|
+
yield({:id=>3, :band_id=>2, :inner_band_id=>5, :vocalist_id=>2})
|
962
|
+
end
|
963
|
+
as = ds.all
|
964
|
+
as.should == [GraphAlbum.load(:id=>3, :band_id=>2)]
|
965
|
+
as.first.inner_band.should == GraphBand.load(:id=>5, :vocalist_id=>2)
|
966
|
+
|
967
|
+
GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :primary_key=>:band_id
|
968
|
+
ds = GraphAlbum.eager_graph(:right_tracks)
|
969
|
+
ds.sql.should == 'SELECT albums.id, albums.band_id, right_tracks.id AS right_tracks_id, right_tracks.album_id FROM albums LEFT OUTER JOIN tracks AS right_tracks ON (right_tracks.album_id = albums.band_id)'
|
970
|
+
def ds.fetch_rows(sql, &block)
|
971
|
+
yield({:id=>3, :band_id=>2, :right_tracks_id=>5, :album_id=>2})
|
972
|
+
yield({:id=>3, :band_id=>2, :right_tracks_id=>6, :album_id=>2})
|
973
|
+
end
|
974
|
+
as = ds.all
|
975
|
+
as.should == [GraphAlbum.load(:id=>3, :band_id=>2)]
|
976
|
+
as.first.right_tracks.should == [GraphTrack.load(:id=>5, :album_id=>2), GraphTrack.load(:id=>6, :album_id=>2)]
|
977
|
+
end
|
978
|
+
|
979
|
+
it "should respect many_to_many association's :left_primary_key and :right_primary_key options" do
|
980
|
+
GraphAlbum.many_to_many :inner_genres, :class=>'GraphGenre', :left_key=>:album_id, :left_primary_key=>:band_id, :right_key=>:genre_id, :right_primary_key=>:xxx, :join_table=>:ag
|
981
|
+
ds = GraphAlbum.eager_graph(:inner_genres)
|
982
|
+
ds.sql.should == 'SELECT albums.id, albums.band_id, inner_genres.id AS inner_genres_id FROM albums LEFT OUTER JOIN ag ON (ag.album_id = albums.band_id) LEFT OUTER JOIN genres AS inner_genres ON (inner_genres.xxx = ag.genre_id)'
|
983
|
+
def ds.fetch_rows(sql, &block)
|
984
|
+
yield({:id=>3, :band_id=>2, :inner_genres_id=>5, :xxx=>12})
|
985
|
+
yield({:id=>3, :band_id=>2, :inner_genres_id=>6, :xxx=>22})
|
986
|
+
end
|
987
|
+
as = ds.all
|
988
|
+
as.should == [GraphAlbum.load(:id=>3, :band_id=>2)]
|
989
|
+
as.first.inner_genres.should == [GraphGenre.load(:id=>5), GraphGenre.load(:id=>6)]
|
990
|
+
end
|
991
|
+
|
905
992
|
it "should respect the association's :graph_select option" do
|
906
993
|
GraphAlbum.many_to_one :inner_band, :class=>'GraphBand', :key=>:band_id, :graph_select=>:vocalist_id
|
907
994
|
GraphAlbum.eager_graph(:inner_band).sql.should == 'SELECT albums.id, albums.band_id, inner_band.vocalist_id FROM albums LEFT OUTER JOIN bands AS inner_band ON (inner_band.id = albums.band_id)'
|
@@ -970,6 +1057,17 @@ describe Sequel::Model, "#eager_graph" do
|
|
970
1057
|
GraphAlbum.eager_graph(:active_genres).sql.should == "SELECT albums.id, albums.band_id, active_genres.id AS active_genres_id FROM albums LEFT OUTER JOIN ag ON ((ag.album_id = albums.id) AND ('t' = albums.active)) LEFT OUTER JOIN genres AS active_genres ON ((active_genres.id = ag.genre_id) AND ('t' = ag.active))"
|
971
1058
|
end
|
972
1059
|
|
1060
|
+
it "should respect the association's :eager_grapher option" do
|
1061
|
+
GraphAlbum.many_to_one :active_band, :class=>'GraphBand', :key=>:band_id, :eager_grapher=>proc{|ds, aa, ta| ds.graph(GraphBand, {:active=>true}, :table_alias=>aa, :join_type=>:inner)}
|
1062
|
+
GraphAlbum.eager_graph(:active_band).sql.should == "SELECT albums.id, albums.band_id, active_band.id AS active_band_id, active_band.vocalist_id FROM albums INNER JOIN bands AS active_band ON (active_band.active = 't')"
|
1063
|
+
|
1064
|
+
GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :eager_grapher=>proc{|ds, aa, ta| ds.graph(GraphTrack, nil, :join_type=>:natural, :table_alias=>aa)}
|
1065
|
+
GraphAlbum.eager_graph(:right_tracks).sql.should == 'SELECT albums.id, albums.band_id, right_tracks.id AS right_tracks_id, right_tracks.album_id FROM albums NATURAL JOIN tracks AS right_tracks'
|
1066
|
+
|
1067
|
+
GraphAlbum.many_to_many :active_genres, :class=>'GraphGenre', :eager_grapher=>proc{|ds, aa, ta| ds.graph(:ag, {:album_id=>:id}, :table_alias=>:a123, :implicit_qualifier=>ta).graph(GraphGenre, [:album_id], :table_alias=>aa)}
|
1068
|
+
GraphAlbum.eager_graph(:active_genres).sql.should == "SELECT albums.id, albums.band_id, active_genres.id AS active_genres_id FROM albums LEFT OUTER JOIN ag AS a123 ON (a123.album_id = albums.id) LEFT OUTER JOIN genres AS active_genres USING (album_id)"
|
1069
|
+
end
|
1070
|
+
|
973
1071
|
it "should respect the association's :graph_only_conditions option" do
|
974
1072
|
GraphAlbum.many_to_one :active_band, :class=>'GraphBand', :key=>:band_id, :graph_only_conditions=>{:active=>true}
|
975
1073
|
GraphAlbum.eager_graph(:active_band).sql.should == "SELECT albums.id, albums.band_id, active_band.id AS active_band_id, active_band.vocalist_id FROM albums LEFT OUTER JOIN bands AS active_band ON (active_band.active = 't')"
|
@@ -1026,4 +1124,10 @@ describe Sequel::Model, "#eager_graph" do
|
|
1026
1124
|
GraphAlbum.one_to_many :b_tracks, :class=>'GraphTrack', :key=>:album_id, :order=>[:id, :album_id]
|
1027
1125
|
GraphAlbum.eager_graph(:a_genres, :b_tracks).sql.should == 'SELECT albums.id, albums.band_id, a_genres.id AS a_genres_id, b_tracks.id AS b_tracks_id, b_tracks.album_id FROM albums LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres AS a_genres ON (a_genres.id = ag.genre_id) LEFT OUTER JOIN tracks AS b_tracks ON (b_tracks.album_id = albums.id) ORDER BY a_genres.id, b_tracks.id, b_tracks.album_id'
|
1028
1126
|
end
|
1127
|
+
|
1128
|
+
it "should use the correct qualifier when graphing multiple tables with extra conditions" do
|
1129
|
+
GraphAlbum.many_to_many :a_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag
|
1130
|
+
GraphAlbum.one_to_many :b_tracks, :class=>'GraphTrack', :key=>:album_id, :graph_conditions=>{:a=>:b}
|
1131
|
+
GraphAlbum.eager_graph(:a_genres, :b_tracks).sql.should == 'SELECT albums.id, albums.band_id, a_genres.id AS a_genres_id, b_tracks.id AS b_tracks_id, b_tracks.album_id FROM albums LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres AS a_genres ON (a_genres.id = ag.genre_id) LEFT OUTER JOIN tracks AS b_tracks ON ((b_tracks.album_id = albums.id) AND (b_tracks.a = albums.b))'
|
1132
|
+
end
|
1029
1133
|
end
|