sequel 4.43.0 → 4.44.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 (95) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +40 -0
  3. data/doc/active_record.rdoc +2 -2
  4. data/doc/code_order.rdoc +15 -0
  5. data/doc/dataset_filtering.rdoc +1 -1
  6. data/doc/model_dataset_method_design.rdoc +132 -0
  7. data/doc/opening_databases.rdoc +2 -2
  8. data/doc/release_notes/4.44.0.txt +125 -0
  9. data/lib/sequel/adapters/jdbc.rb +5 -1
  10. data/lib/sequel/adapters/jdbc/as400.rb +1 -1
  11. data/lib/sequel/adapters/postgres.rb +23 -14
  12. data/lib/sequel/core.rb +1 -1
  13. data/lib/sequel/database/schema_generator.rb +27 -0
  14. data/lib/sequel/dataset/actions.rb +1 -1
  15. data/lib/sequel/dataset/query.rb +5 -1
  16. data/lib/sequel/extensions/eval_inspect.rb +4 -4
  17. data/lib/sequel/extensions/implicit_subquery.rb +48 -0
  18. data/lib/sequel/extensions/to_dot.rb +1 -1
  19. data/lib/sequel/model.rb +3 -5
  20. data/lib/sequel/model/associations.rb +107 -4
  21. data/lib/sequel/model/base.rb +98 -12
  22. data/lib/sequel/model/dataset_module.rb +1 -1
  23. data/lib/sequel/plugins/active_model.rb +11 -3
  24. data/lib/sequel/plugins/association_dependencies.rb +7 -0
  25. data/lib/sequel/plugins/auto_validations.rb +10 -0
  26. data/lib/sequel/plugins/blacklist_security.rb +13 -4
  27. data/lib/sequel/plugins/class_table_inheritance.rb +11 -0
  28. data/lib/sequel/plugins/column_conflicts.rb +8 -0
  29. data/lib/sequel/plugins/composition.rb +12 -2
  30. data/lib/sequel/plugins/constraint_validations.rb +12 -0
  31. data/lib/sequel/plugins/csv_serializer.rb +9 -0
  32. data/lib/sequel/plugins/defaults_setter.rb +6 -0
  33. data/lib/sequel/plugins/force_encoding.rb +4 -3
  34. data/lib/sequel/plugins/hook_class_methods.rb +6 -0
  35. data/lib/sequel/plugins/input_transformer.rb +9 -0
  36. data/lib/sequel/plugins/insert_returning_select.rb +8 -0
  37. data/lib/sequel/plugins/instance_hooks.rb +4 -3
  38. data/lib/sequel/plugins/json_serializer.rb +9 -0
  39. data/lib/sequel/plugins/lazy_attributes.rb +7 -0
  40. data/lib/sequel/plugins/many_through_many.rb +13 -2
  41. data/lib/sequel/plugins/nested_attributes.rb +7 -0
  42. data/lib/sequel/plugins/pg_array_associations.rb +18 -2
  43. data/lib/sequel/plugins/pg_row.rb +3 -3
  44. data/lib/sequel/plugins/pg_typecast_on_load.rb +7 -0
  45. data/lib/sequel/plugins/prepared_statements.rb +2 -2
  46. data/lib/sequel/plugins/prepared_statements_safe.rb +7 -0
  47. data/lib/sequel/plugins/serialization.rb +9 -0
  48. data/lib/sequel/plugins/single_table_inheritance.rb +13 -1
  49. data/lib/sequel/plugins/subclasses.rb +15 -1
  50. data/lib/sequel/plugins/touch.rb +7 -0
  51. data/lib/sequel/plugins/tree.rb +7 -0
  52. data/lib/sequel/plugins/typecast_on_load.rb +7 -0
  53. data/lib/sequel/plugins/update_refresh.rb +24 -13
  54. data/lib/sequel/plugins/validation_class_methods.rb +13 -0
  55. data/lib/sequel/sql.rb +28 -0
  56. data/lib/sequel/version.rb +1 -1
  57. data/spec/adapters/postgres_spec.rb +18 -15
  58. data/spec/core/dataset_spec.rb +5 -0
  59. data/spec/core/expression_filters_spec.rb +33 -0
  60. data/spec/extensions/active_model_spec.rb +15 -1
  61. data/spec/extensions/association_dependencies_spec.rb +8 -0
  62. data/spec/extensions/auto_validations_spec.rb +8 -0
  63. data/spec/extensions/blacklist_security_spec.rb +6 -0
  64. data/spec/extensions/class_table_inheritance_spec.rb +9 -0
  65. data/spec/extensions/column_conflicts_spec.rb +6 -0
  66. data/spec/extensions/composition_spec.rb +8 -0
  67. data/spec/extensions/constraint_validations_plugin_spec.rb +12 -0
  68. data/spec/extensions/csv_serializer_spec.rb +7 -0
  69. data/spec/extensions/defaults_setter_spec.rb +7 -0
  70. data/spec/extensions/force_encoding_spec.rb +14 -0
  71. data/spec/extensions/hook_class_methods_spec.rb +10 -0
  72. data/spec/extensions/implicit_subquery_spec.rb +60 -0
  73. data/spec/extensions/input_transformer_spec.rb +10 -0
  74. data/spec/extensions/insert_returning_select_spec.rb +6 -0
  75. data/spec/extensions/json_serializer_spec.rb +7 -0
  76. data/spec/extensions/lazy_attributes_spec.rb +6 -0
  77. data/spec/extensions/many_through_many_spec.rb +44 -0
  78. data/spec/extensions/nested_attributes_spec.rb +5 -0
  79. data/spec/extensions/pg_array_associations_spec.rb +46 -0
  80. data/spec/extensions/pg_typecast_on_load_spec.rb +5 -0
  81. data/spec/extensions/prepared_statements_safe_spec.rb +5 -0
  82. data/spec/extensions/serialization_spec.rb +7 -0
  83. data/spec/extensions/single_table_inheritance_spec.rb +19 -2
  84. data/spec/extensions/subclasses_spec.rb +13 -0
  85. data/spec/extensions/to_dot_spec.rb +1 -1
  86. data/spec/extensions/touch_spec.rb +6 -0
  87. data/spec/extensions/tree_spec.rb +6 -0
  88. data/spec/extensions/typecast_on_load_spec.rb +6 -0
  89. data/spec/extensions/update_refresh_spec.rb +7 -1
  90. data/spec/extensions/validation_class_methods_spec.rb +13 -0
  91. data/spec/model/association_reflection_spec.rb +177 -0
  92. data/spec/model/associations_spec.rb +16 -0
  93. data/spec/model/dataset_methods_spec.rb +59 -0
  94. data/spec/model/model_spec.rb +59 -0
  95. 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)\\\".lit\"];"]
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