sequel 4.43.0 → 4.44.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +40 -0
- data/doc/active_record.rdoc +2 -2
- data/doc/code_order.rdoc +15 -0
- data/doc/dataset_filtering.rdoc +1 -1
- data/doc/model_dataset_method_design.rdoc +132 -0
- data/doc/opening_databases.rdoc +2 -2
- data/doc/release_notes/4.44.0.txt +125 -0
- data/lib/sequel/adapters/jdbc.rb +5 -1
- data/lib/sequel/adapters/jdbc/as400.rb +1 -1
- data/lib/sequel/adapters/postgres.rb +23 -14
- data/lib/sequel/core.rb +1 -1
- data/lib/sequel/database/schema_generator.rb +27 -0
- data/lib/sequel/dataset/actions.rb +1 -1
- data/lib/sequel/dataset/query.rb +5 -1
- data/lib/sequel/extensions/eval_inspect.rb +4 -4
- data/lib/sequel/extensions/implicit_subquery.rb +48 -0
- data/lib/sequel/extensions/to_dot.rb +1 -1
- data/lib/sequel/model.rb +3 -5
- data/lib/sequel/model/associations.rb +107 -4
- data/lib/sequel/model/base.rb +98 -12
- data/lib/sequel/model/dataset_module.rb +1 -1
- data/lib/sequel/plugins/active_model.rb +11 -3
- data/lib/sequel/plugins/association_dependencies.rb +7 -0
- data/lib/sequel/plugins/auto_validations.rb +10 -0
- data/lib/sequel/plugins/blacklist_security.rb +13 -4
- data/lib/sequel/plugins/class_table_inheritance.rb +11 -0
- data/lib/sequel/plugins/column_conflicts.rb +8 -0
- data/lib/sequel/plugins/composition.rb +12 -2
- data/lib/sequel/plugins/constraint_validations.rb +12 -0
- data/lib/sequel/plugins/csv_serializer.rb +9 -0
- data/lib/sequel/plugins/defaults_setter.rb +6 -0
- data/lib/sequel/plugins/force_encoding.rb +4 -3
- data/lib/sequel/plugins/hook_class_methods.rb +6 -0
- data/lib/sequel/plugins/input_transformer.rb +9 -0
- data/lib/sequel/plugins/insert_returning_select.rb +8 -0
- data/lib/sequel/plugins/instance_hooks.rb +4 -3
- data/lib/sequel/plugins/json_serializer.rb +9 -0
- data/lib/sequel/plugins/lazy_attributes.rb +7 -0
- data/lib/sequel/plugins/many_through_many.rb +13 -2
- data/lib/sequel/plugins/nested_attributes.rb +7 -0
- data/lib/sequel/plugins/pg_array_associations.rb +18 -2
- data/lib/sequel/plugins/pg_row.rb +3 -3
- data/lib/sequel/plugins/pg_typecast_on_load.rb +7 -0
- data/lib/sequel/plugins/prepared_statements.rb +2 -2
- data/lib/sequel/plugins/prepared_statements_safe.rb +7 -0
- data/lib/sequel/plugins/serialization.rb +9 -0
- data/lib/sequel/plugins/single_table_inheritance.rb +13 -1
- data/lib/sequel/plugins/subclasses.rb +15 -1
- data/lib/sequel/plugins/touch.rb +7 -0
- data/lib/sequel/plugins/tree.rb +7 -0
- data/lib/sequel/plugins/typecast_on_load.rb +7 -0
- data/lib/sequel/plugins/update_refresh.rb +24 -13
- data/lib/sequel/plugins/validation_class_methods.rb +13 -0
- data/lib/sequel/sql.rb +28 -0
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/postgres_spec.rb +18 -15
- data/spec/core/dataset_spec.rb +5 -0
- data/spec/core/expression_filters_spec.rb +33 -0
- data/spec/extensions/active_model_spec.rb +15 -1
- data/spec/extensions/association_dependencies_spec.rb +8 -0
- data/spec/extensions/auto_validations_spec.rb +8 -0
- data/spec/extensions/blacklist_security_spec.rb +6 -0
- data/spec/extensions/class_table_inheritance_spec.rb +9 -0
- data/spec/extensions/column_conflicts_spec.rb +6 -0
- data/spec/extensions/composition_spec.rb +8 -0
- data/spec/extensions/constraint_validations_plugin_spec.rb +12 -0
- data/spec/extensions/csv_serializer_spec.rb +7 -0
- data/spec/extensions/defaults_setter_spec.rb +7 -0
- data/spec/extensions/force_encoding_spec.rb +14 -0
- data/spec/extensions/hook_class_methods_spec.rb +10 -0
- data/spec/extensions/implicit_subquery_spec.rb +60 -0
- data/spec/extensions/input_transformer_spec.rb +10 -0
- data/spec/extensions/insert_returning_select_spec.rb +6 -0
- data/spec/extensions/json_serializer_spec.rb +7 -0
- data/spec/extensions/lazy_attributes_spec.rb +6 -0
- data/spec/extensions/many_through_many_spec.rb +44 -0
- data/spec/extensions/nested_attributes_spec.rb +5 -0
- data/spec/extensions/pg_array_associations_spec.rb +46 -0
- data/spec/extensions/pg_typecast_on_load_spec.rb +5 -0
- data/spec/extensions/prepared_statements_safe_spec.rb +5 -0
- data/spec/extensions/serialization_spec.rb +7 -0
- data/spec/extensions/single_table_inheritance_spec.rb +19 -2
- data/spec/extensions/subclasses_spec.rb +13 -0
- data/spec/extensions/to_dot_spec.rb +1 -1
- data/spec/extensions/touch_spec.rb +6 -0
- data/spec/extensions/tree_spec.rb +6 -0
- data/spec/extensions/typecast_on_load_spec.rb +6 -0
- data/spec/extensions/update_refresh_spec.rb +7 -1
- data/spec/extensions/validation_class_methods_spec.rb +13 -0
- data/spec/model/association_reflection_spec.rb +177 -0
- data/spec/model/associations_spec.rb +16 -0
- data/spec/model/dataset_methods_spec.rb +59 -0
- data/spec/model/model_spec.rb +59 -0
- metadata +8 -2
@@ -694,4 +694,9 @@ describe "NestedAttributes plugin" do
|
|
694
694
|
@Tag.columns :id, :name, :number
|
695
695
|
proc{@Album.load(:id=>10, :name=>'Al').set_nested_attributes(:tags, [{:id=>30, :name=>'T2', :number=>3}], :fields=>[:name])}.must_raise(Sequel::Error)
|
696
696
|
end
|
697
|
+
|
698
|
+
it "should freeze nested_attributes_module when freezing model class" do
|
699
|
+
@Artist.freeze
|
700
|
+
@Artist.nested_attributes_module.frozen?.must_equal true
|
701
|
+
end
|
697
702
|
end
|
@@ -735,3 +735,49 @@ describe Sequel::Model, "pg_array_associations" do
|
|
735
735
|
t.artists.must_equal [a]
|
736
736
|
end
|
737
737
|
end
|
738
|
+
|
739
|
+
describe "Sequel::Model.finalize_associations" do
|
740
|
+
before do
|
741
|
+
class ::Foo < Sequel::Model
|
742
|
+
plugin :pg_array_associations
|
743
|
+
many_to_pg_array :items
|
744
|
+
end
|
745
|
+
class ::Item < Sequel::Model
|
746
|
+
plugin :pg_array_associations
|
747
|
+
pg_array_to_many :foos
|
748
|
+
end
|
749
|
+
[Foo, Item].each(&:finalize_associations)
|
750
|
+
end
|
751
|
+
after do
|
752
|
+
Object.send(:remove_const, :Item)
|
753
|
+
Object.send(:remove_const, :Foo)
|
754
|
+
end
|
755
|
+
|
756
|
+
it "should finalize pg_array_to_many associations" do
|
757
|
+
r = Item.association_reflection(:foos)
|
758
|
+
r[:class].must_equal Foo
|
759
|
+
r[:_dataset].sql.must_equal "SELECT * FROM foos"
|
760
|
+
r[:associated_eager_dataset].sql.must_equal "SELECT * FROM foos"
|
761
|
+
r.fetch(:_eager_limit_strategy).must_be_nil
|
762
|
+
r[:filter_by_associations_conditions_dataset].sql.must_equal "SELECT array_agg(foos.id) FROM foos WHERE (foos.id IS NOT NULL)"
|
763
|
+
r[:predicate_key].must_equal Sequel.qualify(:foos, :id)
|
764
|
+
r[:predicate_keys].must_equal [Sequel.qualify(:foos, :id)]
|
765
|
+
r[:reciprocal].must_equal :items
|
766
|
+
r[:array_type].must_equal :integer
|
767
|
+
r[:primary_key].must_equal :id
|
768
|
+
r[:primary_key_method].must_equal :id
|
769
|
+
end
|
770
|
+
|
771
|
+
it "should finalize many_to_pg_array associations" do
|
772
|
+
r = Foo.association_reflection(:items)
|
773
|
+
r[:class].must_equal Item
|
774
|
+
r[:_dataset].sql.must_equal "SELECT * FROM items"
|
775
|
+
r[:associated_eager_dataset].sql.must_equal "SELECT * FROM items"
|
776
|
+
r.fetch(:_eager_limit_strategy).must_be_nil
|
777
|
+
r[:filter_by_associations_conditions_dataset].sql.must_equal "SELECT unnest(items.foo_ids) FROM items WHERE (items.foo_ids IS NOT NULL)"
|
778
|
+
r[:predicate_key].must_equal Sequel.qualify(:items, :foo_ids)
|
779
|
+
r[:predicate_keys].must_equal [Sequel.qualify(:items, :foo_ids)]
|
780
|
+
r[:reciprocal].must_equal :foos
|
781
|
+
r[:array_type].must_equal :integer
|
782
|
+
end
|
783
|
+
end
|
@@ -60,4 +60,9 @@ describe Sequel::Model, "PgTypecastOnLoad plugin" do
|
|
60
60
|
it "should not mark the object as modified" do
|
61
61
|
@c.first.modified?.must_equal false
|
62
62
|
end
|
63
|
+
|
64
|
+
it "should freeze pg_typecast_on_load_columns" do
|
65
|
+
@c.freeze
|
66
|
+
@c.pg_typecast_on_load_columns.frozen?.must_equal true
|
67
|
+
end
|
63
68
|
end
|
@@ -58,4 +58,9 @@ describe "prepared_statements_safe plugin" do
|
|
58
58
|
c1.prepared_statements_column_defaults.must_equal(:name=>'foo')
|
59
59
|
Class.new(c1).prepared_statements_column_defaults.must_equal(:name=>'foo')
|
60
60
|
end
|
61
|
+
|
62
|
+
it "should freeze prepared statement column defaults when freezing model class" do
|
63
|
+
@c.freeze
|
64
|
+
@c.prepared_statements_column_defaults.frozen?.must_equal true
|
65
|
+
end
|
61
66
|
end
|
@@ -361,4 +361,11 @@ describe "Serialization plugin" do
|
|
361
361
|
o.column_changes.must_equal(:abc=>[1, 2], :def=>["hello", "hello2"])
|
362
362
|
end
|
363
363
|
|
364
|
+
it "should freeze serialization metadata when freezing model class" do
|
365
|
+
@c.plugin :serialization, :yaml, :abc, :def
|
366
|
+
@c.freeze
|
367
|
+
@c.serialization_map.frozen?.must_equal true
|
368
|
+
@c.deserialization_map.frozen?.must_equal true
|
369
|
+
@c.serialization_module.frozen?.must_equal true
|
370
|
+
end
|
364
371
|
end
|
@@ -19,6 +19,16 @@ describe Sequel::Model, "single table inheritance plugin" do
|
|
19
19
|
Object.send(:remove_const, :StiTest)
|
20
20
|
end
|
21
21
|
|
22
|
+
it "should freeze sti metadata when freezing model class" do
|
23
|
+
StiTest.freeze
|
24
|
+
StiTest.sti_dataset.frozen?.must_equal true
|
25
|
+
|
26
|
+
StiTestSub1.freeze
|
27
|
+
StiTestSub1.sti_key_array.frozen?.must_equal true
|
28
|
+
|
29
|
+
proc{class ::StiTestSub1Sub1 < StiTestSub1; end}.must_raise RuntimeError, TypeError
|
30
|
+
end
|
31
|
+
|
22
32
|
it "should have simple_table = nil" do
|
23
33
|
StiTest.simple_table.must_equal "sti_tests"
|
24
34
|
StiTestSub1.simple_table.must_be_nil
|
@@ -180,8 +190,15 @@ describe Sequel::Model, "single table inheritance plugin" do
|
|
180
190
|
end
|
181
191
|
after do
|
182
192
|
Object.send(:remove_const, :StiTest2)
|
183
|
-
Object.send(:remove_const, :StiTest3)
|
184
|
-
Object.send(:remove_const, :StiTest4)
|
193
|
+
Object.send(:remove_const, :StiTest3) if defined?(StiTest3)
|
194
|
+
Object.send(:remove_const, :StiTest4) if defined?(StiTest4)
|
195
|
+
end
|
196
|
+
|
197
|
+
it "should freeze sti key and model map if given as hashes when freezing model class" do
|
198
|
+
StiTest2.plugin :single_table_inheritance, :kind, :model_map=>{0=>StiTest2, 1=>:StiTest3, 2=>'StiTest4'}, :key_map=>{StiTest2=>4, 'StiTest3'=>5, 'StiTest4'=>6}
|
199
|
+
StiTest2.freeze
|
200
|
+
StiTest2.sti_key_map.frozen?.must_equal true
|
201
|
+
StiTest2.sti_model_map.frozen?.must_equal true
|
185
202
|
end
|
186
203
|
|
187
204
|
it "should have working row_proc if using set_dataset in subclass to remove columns" do
|
@@ -50,6 +50,19 @@ describe Sequel::Model, "Subclasses plugin" do
|
|
50
50
|
sssc1.descendents.must_equal []
|
51
51
|
end
|
52
52
|
|
53
|
+
it "#freeze_descendents should finalize the associations for all descendents" do
|
54
|
+
sc1 = Class.new(@c)
|
55
|
+
sc1.set_dataset :bars
|
56
|
+
sc1.set_primary_key :foo
|
57
|
+
sc2 = Class.new(@c)
|
58
|
+
sc2.set_dataset :bazs
|
59
|
+
sc2.many_to_one :bar, :class=>sc1
|
60
|
+
@c.freeze_descendents
|
61
|
+
sc1.frozen?.must_equal true
|
62
|
+
sc2.frozen?.must_equal true
|
63
|
+
sc2.association_reflection(:bar)[:primary_key].must_equal :foo
|
64
|
+
end
|
65
|
+
|
53
66
|
it "plugin block should be called with each subclass created" do
|
54
67
|
c = Class.new(Sequel::Model)
|
55
68
|
a = []
|
@@ -80,7 +80,7 @@ END
|
|
80
80
|
end
|
81
81
|
|
82
82
|
it "should handle LiteralStrings" do
|
83
|
-
dot(@ds.filter('a')).must_equal ["1 -> 2 [label=\"where\"];", "2 [label=\"\\\"(a)\\\"
|
83
|
+
dot(@ds.filter('a')).must_equal ["1 -> 2 [label=\"where\"];", "2 [label=\"Sequel.lit(\\\"(a)\\\")\"];"]
|
84
84
|
end
|
85
85
|
|
86
86
|
it "should handle true, false, nil" do
|
@@ -208,4 +208,10 @@ describe "Touch plugin" do
|
|
208
208
|
DB.sqls.must_equal ["UPDATE artists SET modified_on = CURRENT_TIMESTAMP WHERE (id = 4)",
|
209
209
|
"UPDATE albums SET modified_on = CURRENT_TIMESTAMP WHERE (albums.artist_id = 4)"]
|
210
210
|
end
|
211
|
+
|
212
|
+
it "should freeze touched associations when freezing model class" do
|
213
|
+
@Artist.plugin :touch, :associations=>:albums
|
214
|
+
@Artist.freeze
|
215
|
+
@Artist.touched_associations.frozen?.must_equal true
|
216
|
+
end
|
211
217
|
end
|
@@ -274,5 +274,11 @@ describe Sequel::Model, "tree plugin with composite keys" do
|
|
274
274
|
@c.dataset = @c.dataset.with_fetch(:id=>1, :id2=>6, :parent_id=>nil, :parent_id2=>2, :name=>'r')
|
275
275
|
@c.root.update(:name => 'fdsa')
|
276
276
|
end
|
277
|
+
|
278
|
+
it "freezes tree_order if it is an array" do
|
279
|
+
@c.tree_order = [:id]
|
280
|
+
@c.freeze
|
281
|
+
@c.tree_order.frozen?.must_equal true
|
282
|
+
end
|
277
283
|
end
|
278
284
|
end
|
@@ -77,4 +77,10 @@ describe Sequel::Model, "TypecastOnLoad plugin" do
|
|
77
77
|
@c.plugin :typecast_on_load, :b
|
78
78
|
@c.load(:id=>1, :b=>"1", :y=>"0").modified?.must_equal false
|
79
79
|
end
|
80
|
+
|
81
|
+
it "should freeze typecast_on_load columns when freezing model class" do
|
82
|
+
@c.plugin :typecast_on_load, :b
|
83
|
+
@c.freeze
|
84
|
+
@c.typecast_on_load_columns.frozen?.must_equal true
|
85
|
+
end
|
80
86
|
end
|
@@ -38,7 +38,6 @@ describe "Sequel::Plugins::UpdateRefresh" do
|
|
38
38
|
o.name.must_equal 'b'
|
39
39
|
end
|
40
40
|
|
41
|
-
|
42
41
|
it "should refresh the instance after updating when returning specific columns" do
|
43
42
|
@db.extend_datasets{def supports_returning?(x) true end; def update_sql(*); sql = super; update_returning_sql(sql); sql end}
|
44
43
|
@c.plugin :insert_returning_select
|
@@ -50,4 +49,11 @@ describe "Sequel::Plugins::UpdateRefresh" do
|
|
50
49
|
@db.sqls.must_equal ["UPDATE test SET name = 'a' WHERE (id = 1) RETURNING id, name"]
|
51
50
|
o.name.must_equal 'b'
|
52
51
|
end
|
52
|
+
|
53
|
+
it "should freeze update refresh columns when freezing model class" do
|
54
|
+
@db.extend_datasets{def supports_returning?(x) true end; def update_sql(*); sql = super; update_returning_sql(sql); sql end}
|
55
|
+
@c.plugin :update_refresh, :columns => [ :a ]
|
56
|
+
@c.freeze
|
57
|
+
@c.update_refresh_columns.frozen?.must_equal true
|
58
|
+
end
|
53
59
|
end
|
@@ -16,6 +16,19 @@ describe Sequel::Model do
|
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
+
it "should freeze validation metadata when freezing model class" do
|
20
|
+
@c.validates_acceptance_of(:a)
|
21
|
+
@c.freeze
|
22
|
+
@c.validations.frozen?.must_equal true
|
23
|
+
@c.validations.values.all?(&:frozen?).must_equal true
|
24
|
+
@c.validation_reflections.frozen?.must_equal true
|
25
|
+
@c.validation_reflections.values.all? do |vs|
|
26
|
+
vs.frozen? && vs.all? do |v|
|
27
|
+
v.frozen? && v.last.frozen?
|
28
|
+
end
|
29
|
+
end.must_equal true
|
30
|
+
end
|
31
|
+
|
19
32
|
it "should respond to validations, has_validations?, and validation_reflections" do
|
20
33
|
@c.must_respond_to(:validations)
|
21
34
|
@c.must_respond_to(:has_validations?)
|
@@ -15,6 +15,19 @@ describe Sequel::Model::Associations::AssociationReflection, "#associated_class"
|
|
15
15
|
@c.association_reflection(:c).associated_class.must_equal ParParent
|
16
16
|
end
|
17
17
|
|
18
|
+
it "should have inspect include association class and representation of association definition " do
|
19
|
+
ParParent.many_to_one :c
|
20
|
+
ParParent.association_reflection(:c).inspect.must_equal "#<Sequel::Model::Associations::ManyToOneAssociationReflection ParParent.many_to_one :c>"
|
21
|
+
ParParent.many_to_one :c, :class=>ParParent
|
22
|
+
ParParent.association_reflection(:c).inspect.must_equal "#<Sequel::Model::Associations::ManyToOneAssociationReflection ParParent.many_to_one :c, :class=>ParParent>"
|
23
|
+
ParParent.many_to_one :c, :class=>ParParent, :key=>:c_id
|
24
|
+
["#<Sequel::Model::Associations::ManyToOneAssociationReflection ParParent.many_to_one :c, :key=>:c_id, :class=>ParParent>",
|
25
|
+
"#<Sequel::Model::Associations::ManyToOneAssociationReflection ParParent.many_to_one :c, :class=>ParParent, :key=>:c_id>"].must_include ParParent.association_reflection(:c).inspect
|
26
|
+
|
27
|
+
@c.one_to_many :foos do |ds| ds end
|
28
|
+
@c.association_reflection(:foos).inspect.must_equal "#<Sequel::Model::Associations::OneToManyAssociationReflection #{@c.to_s}.one_to_many :foos, :block=>#{@c.association_reflection(:foos)[:block].inspect}>"
|
29
|
+
end
|
30
|
+
|
18
31
|
it "should figure out the class if the :class value is not present" do
|
19
32
|
@c.many_to_one :c, :class=>'ParParent'
|
20
33
|
@c.association_reflection(:c).keys.wont_include(:class)
|
@@ -30,6 +43,17 @@ describe Sequel::Model::Associations::AssociationReflection, "#associated_class"
|
|
30
43
|
ParParent.many_to_one :par_parent, :class=>'ParParent', :class_namespace=>'ParParent'
|
31
44
|
ParParent.association_reflection(:par_parent).associated_class.must_equal ParParent::ParParent
|
32
45
|
end
|
46
|
+
|
47
|
+
it "should include association inspect output if an exception would be raised" do
|
48
|
+
r = @c.many_to_one(:c)
|
49
|
+
|
50
|
+
begin
|
51
|
+
r.associated_class
|
52
|
+
rescue NameError => e
|
53
|
+
end
|
54
|
+
|
55
|
+
e.message.must_include r.inspect
|
56
|
+
end
|
33
57
|
end
|
34
58
|
|
35
59
|
describe Sequel::Model::Associations::AssociationReflection, "#primary_key" do
|
@@ -563,3 +587,156 @@ describe Sequel::Model::Associations::AssociationReflection, "with default assoc
|
|
563
587
|
r[:bar].must_equal 2
|
564
588
|
end
|
565
589
|
end
|
590
|
+
|
591
|
+
describe "Sequel::Model.freeze" do
|
592
|
+
it "should freeze the model class and not allow any changes to associations" do
|
593
|
+
model = Class.new(Sequel::Model(:items))
|
594
|
+
model.many_to_one :foo, :class=>model, :key=>:id
|
595
|
+
model.default_association_options = {:read_only=>true}
|
596
|
+
model.freeze
|
597
|
+
|
598
|
+
model.association_reflections.frozen?.must_equal true
|
599
|
+
model.association_reflection(:foo).frozen?.must_equal true
|
600
|
+
model.autoreloading_associations.frozen?.must_equal true
|
601
|
+
model.autoreloading_associations[:id].frozen?.must_equal true
|
602
|
+
model.default_association_options.frozen?.must_equal true
|
603
|
+
end
|
604
|
+
|
605
|
+
it "should allow subclasses of frozen model classes to modify associations" do
|
606
|
+
model = Class.new(Sequel::Model(:items))
|
607
|
+
model.many_to_one :foo, :class=>model, :key=>:id
|
608
|
+
model.freeze
|
609
|
+
model = Class.new(model)
|
610
|
+
model.dataset = :items2
|
611
|
+
|
612
|
+
model.association_reflection(:foo).frozen?.must_equal true
|
613
|
+
model.autoreloading_associations.frozen?.must_equal false
|
614
|
+
model.autoreloading_associations[:id].frozen?.must_equal false
|
615
|
+
|
616
|
+
model.many_to_one :bar, :class=>model, :key=>:id
|
617
|
+
model.many_to_one :foo, :class=>model, :key=>:id
|
618
|
+
model.association_reflections.frozen?.must_equal false
|
619
|
+
model.association_reflection(:foo).frozen?.must_equal false
|
620
|
+
model.association_reflection(:bar).frozen?.must_equal false
|
621
|
+
|
622
|
+
model.default_association_options.frozen?.wont_equal true
|
623
|
+
model.default_association_options = {:read_only=>true}
|
624
|
+
model.default_association_options.frozen?.wont_equal true
|
625
|
+
end
|
626
|
+
end
|
627
|
+
|
628
|
+
describe "Sequel::Model.finalize_associations" do
|
629
|
+
before do
|
630
|
+
class ::MtmItem < Sequel::Model
|
631
|
+
set_primary_key :mtm_id
|
632
|
+
many_to_many :items
|
633
|
+
many_to_one :item
|
634
|
+
end
|
635
|
+
class ::OtoItem < Sequel::Model
|
636
|
+
set_primary_key :oto_id
|
637
|
+
end
|
638
|
+
class ::Item < Sequel::Model
|
639
|
+
many_to_one :item
|
640
|
+
one_to_many :items, :limit=>10
|
641
|
+
one_to_one :mtm_item
|
642
|
+
many_to_many :mtm_items
|
643
|
+
one_through_one :oto_item
|
644
|
+
end
|
645
|
+
[MtmItem, OtoItem, Item].each(&:finalize_associations)
|
646
|
+
end
|
647
|
+
after do
|
648
|
+
Object.send(:remove_const, :Item)
|
649
|
+
Object.send(:remove_const, :MtmItem)
|
650
|
+
Object.send(:remove_const, :OtoItem)
|
651
|
+
end
|
652
|
+
|
653
|
+
it "should finalize many_to_one associations" do
|
654
|
+
r = Item.association_reflection(:item)
|
655
|
+
r[:class].must_equal Item
|
656
|
+
r[:_dataset].sql.must_equal "SELECT * FROM items LIMIT 1"
|
657
|
+
r[:associated_eager_dataset].sql.must_equal "SELECT * FROM items"
|
658
|
+
r[:filter_by_associations_conditions_dataset].sql.must_equal "SELECT items.id FROM items WHERE (items.id IS NOT NULL)"
|
659
|
+
r[:placeholder_loader].wont_be_nil
|
660
|
+
r[:predicate_key].must_equal Sequel.qualify(:items, :id)
|
661
|
+
r[:primary_key].must_equal :id
|
662
|
+
r[:primary_keys].must_equal [:id]
|
663
|
+
r[:primary_key_method].must_equal :id
|
664
|
+
r[:primary_key_methods].must_equal [:id]
|
665
|
+
r[:qualified_primary_key].must_equal Sequel.qualify(:items, :id)
|
666
|
+
r.fetch(:reciprocal_type).must_equal :one_to_many
|
667
|
+
r.fetch(:reciprocal).must_equal :items
|
668
|
+
end
|
669
|
+
|
670
|
+
it "should finalize one_to_many associations" do
|
671
|
+
r = Item.association_reflection(:items)
|
672
|
+
r[:class].must_equal Item
|
673
|
+
r[:_dataset].sql.must_equal "SELECT * FROM items LIMIT 10"
|
674
|
+
r[:associated_eager_dataset].sql.must_equal "SELECT * FROM items"
|
675
|
+
r[:_eager_limit_strategy].must_equal :union
|
676
|
+
r[:filter_by_associations_conditions_dataset].sql.must_equal "SELECT items.item_id FROM items WHERE ((items.item_id IS NOT NULL) AND (items.id IN (SELECT t1.id FROM items AS t1 WHERE (t1.item_id = items.item_id) LIMIT 10)))"
|
677
|
+
r[:placeholder_loader].wont_be_nil
|
678
|
+
r[:predicate_key].must_equal Sequel.qualify(:items, :item_id)
|
679
|
+
r[:predicate_keys].must_equal [Sequel.qualify(:items, :item_id)]
|
680
|
+
r[:qualified_primary_key].must_equal Sequel.qualify(:items, :id)
|
681
|
+
r.fetch(:reciprocal).must_equal :item
|
682
|
+
end
|
683
|
+
|
684
|
+
it "should finalize one_to_one associations" do
|
685
|
+
r = Item.association_reflection(:mtm_item)
|
686
|
+
r[:class].must_equal MtmItem
|
687
|
+
r[:_dataset].sql.must_equal "SELECT * FROM mtm_items LIMIT 1"
|
688
|
+
r[:associated_eager_dataset].sql.must_equal "SELECT * FROM mtm_items"
|
689
|
+
r[:_eager_limit_strategy].must_be_nil
|
690
|
+
r[:filter_by_associations_conditions_dataset].sql.must_equal "SELECT mtm_items.item_id FROM mtm_items WHERE (mtm_items.item_id IS NOT NULL)"
|
691
|
+
r[:placeholder_loader].wont_be_nil
|
692
|
+
r[:predicate_key].must_equal Sequel.qualify(:mtm_items, :item_id)
|
693
|
+
r[:predicate_keys].must_equal [Sequel.qualify(:mtm_items, :item_id)]
|
694
|
+
r[:qualified_primary_key].must_equal Sequel.qualify(:items, :id)
|
695
|
+
r.fetch(:reciprocal).must_equal :item
|
696
|
+
end
|
697
|
+
|
698
|
+
it "should finalize many_to_many associations" do
|
699
|
+
r = Item.association_reflection(:mtm_items)
|
700
|
+
r[:class].must_equal MtmItem
|
701
|
+
r[:_dataset].sql.must_equal "SELECT mtm_items.* FROM mtm_items INNER JOIN items_mtm_items ON (items_mtm_items.mtm_item_id = mtm_items.mtm_id)"
|
702
|
+
r[:associated_eager_dataset].sql.must_equal "SELECT mtm_items.* FROM mtm_items INNER JOIN items_mtm_items ON (items_mtm_items.mtm_item_id = mtm_items.mtm_id)"
|
703
|
+
r[:_eager_limit_strategy].must_be_nil
|
704
|
+
r[:filter_by_associations_conditions_dataset].sql.must_equal "SELECT items_mtm_items.item_id FROM mtm_items INNER JOIN items_mtm_items ON (items_mtm_items.mtm_item_id = mtm_items.mtm_id) WHERE (items_mtm_items.item_id IS NOT NULL)"
|
705
|
+
r[:placeholder_loader].wont_be_nil
|
706
|
+
r[:predicate_key].must_equal Sequel.qualify(:items_mtm_items, :item_id)
|
707
|
+
r[:predicate_keys].must_equal [Sequel.qualify(:items_mtm_items, :item_id)]
|
708
|
+
r.fetch(:reciprocal).must_equal :items
|
709
|
+
r[:associated_key_array].must_equal [Sequel.qualify(:items_mtm_items, :item_id).as(:x_foreign_key_x)]
|
710
|
+
r[:qualified_right_key].must_equal Sequel.qualify(:items_mtm_items, :mtm_item_id)
|
711
|
+
r[:join_table_source].must_equal :items_mtm_items
|
712
|
+
r[:join_table_alias].must_equal :items_mtm_items
|
713
|
+
r[:qualified_right_primary_key].must_equal Sequel.qualify(:mtm_items, :mtm_id)
|
714
|
+
r[:right_primary_key].must_equal :mtm_id
|
715
|
+
r[:right_primary_keys].must_equal [:mtm_id]
|
716
|
+
r[:right_primary_key_method].must_equal :mtm_id
|
717
|
+
r[:right_primary_key_methods].must_equal [:mtm_id]
|
718
|
+
r[:select].must_equal Sequel::SQL::ColumnAll.new(:mtm_items)
|
719
|
+
end
|
720
|
+
|
721
|
+
it "should finalize one_through_one associations" do
|
722
|
+
r = Item.association_reflection(:oto_item)
|
723
|
+
r[:class].must_equal OtoItem
|
724
|
+
r[:_dataset].sql.must_equal "SELECT oto_items.* FROM oto_items INNER JOIN items_oto_items ON (items_oto_items.oto_item_id = oto_items.oto_id) LIMIT 1"
|
725
|
+
r[:associated_eager_dataset].sql.must_equal "SELECT oto_items.* FROM oto_items INNER JOIN items_oto_items ON (items_oto_items.oto_item_id = oto_items.oto_id)"
|
726
|
+
r[:_eager_limit_strategy].must_be_nil
|
727
|
+
r[:filter_by_associations_conditions_dataset].sql.must_equal "SELECT items_oto_items.item_id FROM oto_items INNER JOIN items_oto_items ON (items_oto_items.oto_item_id = oto_items.oto_id) WHERE (items_oto_items.item_id IS NOT NULL)"
|
728
|
+
r[:placeholder_loader].wont_be_nil
|
729
|
+
r[:predicate_key].must_equal Sequel.qualify(:items_oto_items, :item_id)
|
730
|
+
r[:predicate_keys].must_equal [Sequel.qualify(:items_oto_items, :item_id)]
|
731
|
+
r[:associated_key_array].must_equal [Sequel.qualify(:items_oto_items, :item_id).as(:x_foreign_key_x)]
|
732
|
+
r[:qualified_right_key].must_equal Sequel.qualify(:items_oto_items, :oto_item_id)
|
733
|
+
r[:join_table_source].must_equal :items_oto_items
|
734
|
+
r[:join_table_alias].must_equal :items_oto_items
|
735
|
+
r[:qualified_right_primary_key].must_equal Sequel.qualify(:oto_items, :oto_id)
|
736
|
+
r[:right_primary_key].must_equal :oto_id
|
737
|
+
r[:right_primary_keys].must_equal [:oto_id]
|
738
|
+
r[:right_primary_key_method].must_equal :oto_id
|
739
|
+
r[:right_primary_key_methods].must_equal [:oto_id]
|
740
|
+
r[:select].must_equal Sequel::SQL::ColumnAll.new(:oto_items)
|
741
|
+
end
|
742
|
+
end
|
@@ -4624,3 +4624,19 @@ describe "association autoreloading" do
|
|
4624
4624
|
DB.sqls.must_equal ['SELECT * FROM artists WHERE id = 1']
|
4625
4625
|
end
|
4626
4626
|
end
|
4627
|
+
|
4628
|
+
describe Sequel::Model, ".dataset_module" do
|
4629
|
+
before do
|
4630
|
+
@c = Class.new(Sequel::Model(:items))
|
4631
|
+
end
|
4632
|
+
|
4633
|
+
it "should have dataset_module support an eager method" do
|
4634
|
+
@c.many_to_one :foo, :class=>@c
|
4635
|
+
@c.many_to_one :bar, :class=>@c
|
4636
|
+
@c.many_to_one :baz, :class=>@c
|
4637
|
+
@c.many_to_one :quux, :class=>@c
|
4638
|
+
@c.dataset_module{eager(:foo, {:foo=>{:bar=>:baz}}, :quux)}
|
4639
|
+
@c.foo.opts[:eager].must_equal(:foo=>{:bar=>:baz}, :quux=>nil)
|
4640
|
+
@c.where(:bar).foo.opts[:eager].must_equal(:foo=>{:bar=>:baz}, :quux=>nil)
|
4641
|
+
end
|
4642
|
+
end
|