sequel 3.36.1 → 3.37.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 (108) hide show
  1. data/CHANGELOG +84 -0
  2. data/Rakefile +13 -0
  3. data/bin/sequel +12 -16
  4. data/doc/advanced_associations.rdoc +36 -67
  5. data/doc/association_basics.rdoc +11 -16
  6. data/doc/release_notes/3.37.0.txt +338 -0
  7. data/doc/schema_modification.rdoc +4 -0
  8. data/lib/sequel/adapters/jdbc/h2.rb +1 -1
  9. data/lib/sequel/adapters/jdbc/postgresql.rb +26 -8
  10. data/lib/sequel/adapters/mysql2.rb +4 -3
  11. data/lib/sequel/adapters/odbc/mssql.rb +2 -2
  12. data/lib/sequel/adapters/postgres.rb +4 -60
  13. data/lib/sequel/adapters/shared/mssql.rb +2 -1
  14. data/lib/sequel/adapters/shared/mysql.rb +0 -5
  15. data/lib/sequel/adapters/shared/postgres.rb +68 -2
  16. data/lib/sequel/adapters/shared/sqlite.rb +17 -1
  17. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +12 -1
  18. data/lib/sequel/adapters/utils/pg_types.rb +76 -0
  19. data/lib/sequel/core.rb +13 -0
  20. data/lib/sequel/database/misc.rb +41 -1
  21. data/lib/sequel/database/schema_generator.rb +23 -10
  22. data/lib/sequel/database/schema_methods.rb +26 -4
  23. data/lib/sequel/dataset/graph.rb +2 -1
  24. data/lib/sequel/dataset/query.rb +62 -2
  25. data/lib/sequel/extensions/_pretty_table.rb +7 -3
  26. data/lib/sequel/extensions/arbitrary_servers.rb +5 -4
  27. data/lib/sequel/extensions/blank.rb +4 -0
  28. data/lib/sequel/extensions/columns_introspection.rb +13 -2
  29. data/lib/sequel/extensions/core_extensions.rb +6 -0
  30. data/lib/sequel/extensions/eval_inspect.rb +158 -0
  31. data/lib/sequel/extensions/inflector.rb +4 -0
  32. data/lib/sequel/extensions/looser_typecasting.rb +5 -4
  33. data/lib/sequel/extensions/migration.rb +4 -1
  34. data/lib/sequel/extensions/named_timezones.rb +4 -0
  35. data/lib/sequel/extensions/null_dataset.rb +4 -0
  36. data/lib/sequel/extensions/pagination.rb +4 -0
  37. data/lib/sequel/extensions/pg_array.rb +219 -168
  38. data/lib/sequel/extensions/pg_array_ops.rb +7 -2
  39. data/lib/sequel/extensions/pg_auto_parameterize.rb +10 -4
  40. data/lib/sequel/extensions/pg_hstore.rb +3 -1
  41. data/lib/sequel/extensions/pg_hstore_ops.rb +7 -2
  42. data/lib/sequel/extensions/pg_inet.rb +28 -3
  43. data/lib/sequel/extensions/pg_interval.rb +192 -0
  44. data/lib/sequel/extensions/pg_json.rb +21 -9
  45. data/lib/sequel/extensions/pg_range.rb +487 -0
  46. data/lib/sequel/extensions/pg_range_ops.rb +122 -0
  47. data/lib/sequel/extensions/pg_statement_cache.rb +3 -2
  48. data/lib/sequel/extensions/pretty_table.rb +12 -1
  49. data/lib/sequel/extensions/query.rb +4 -0
  50. data/lib/sequel/extensions/query_literals.rb +6 -6
  51. data/lib/sequel/extensions/schema_dumper.rb +39 -38
  52. data/lib/sequel/extensions/select_remove.rb +4 -0
  53. data/lib/sequel/extensions/server_block.rb +3 -2
  54. data/lib/sequel/extensions/split_array_nil.rb +65 -0
  55. data/lib/sequel/extensions/sql_expr.rb +4 -0
  56. data/lib/sequel/extensions/string_date_time.rb +4 -0
  57. data/lib/sequel/extensions/thread_local_timezones.rb +9 -3
  58. data/lib/sequel/extensions/to_dot.rb +4 -0
  59. data/lib/sequel/model/associations.rb +150 -91
  60. data/lib/sequel/plugins/identity_map.rb +2 -2
  61. data/lib/sequel/plugins/list.rb +1 -0
  62. data/lib/sequel/plugins/many_through_many.rb +33 -32
  63. data/lib/sequel/plugins/nested_attributes.rb +11 -3
  64. data/lib/sequel/plugins/rcte_tree.rb +2 -2
  65. data/lib/sequel/plugins/schema.rb +1 -1
  66. data/lib/sequel/sql.rb +14 -14
  67. data/lib/sequel/version.rb +2 -2
  68. data/spec/adapters/mysql_spec.rb +25 -0
  69. data/spec/adapters/postgres_spec.rb +572 -28
  70. data/spec/adapters/sqlite_spec.rb +16 -1
  71. data/spec/core/database_spec.rb +61 -2
  72. data/spec/core/dataset_spec.rb +92 -0
  73. data/spec/core/expression_filters_spec.rb +12 -0
  74. data/spec/extensions/arbitrary_servers_spec.rb +1 -1
  75. data/spec/extensions/boolean_readers_spec.rb +25 -25
  76. data/spec/extensions/eval_inspect_spec.rb +58 -0
  77. data/spec/extensions/json_serializer_spec.rb +0 -6
  78. data/spec/extensions/list_spec.rb +1 -1
  79. data/spec/extensions/looser_typecasting_spec.rb +7 -7
  80. data/spec/extensions/many_through_many_spec.rb +81 -0
  81. data/spec/extensions/nested_attributes_spec.rb +21 -4
  82. data/spec/extensions/pg_array_ops_spec.rb +1 -11
  83. data/spec/extensions/pg_array_spec.rb +181 -90
  84. data/spec/extensions/pg_auto_parameterize_spec.rb +3 -3
  85. data/spec/extensions/pg_hstore_spec.rb +1 -3
  86. data/spec/extensions/pg_inet_spec.rb +6 -1
  87. data/spec/extensions/pg_interval_spec.rb +73 -0
  88. data/spec/extensions/pg_json_spec.rb +5 -9
  89. data/spec/extensions/pg_range_ops_spec.rb +49 -0
  90. data/spec/extensions/pg_range_spec.rb +372 -0
  91. data/spec/extensions/pg_statement_cache_spec.rb +1 -2
  92. data/spec/extensions/query_literals_spec.rb +1 -2
  93. data/spec/extensions/schema_dumper_spec.rb +48 -89
  94. data/spec/extensions/serialization_spec.rb +1 -5
  95. data/spec/extensions/server_block_spec.rb +2 -2
  96. data/spec/extensions/spec_helper.rb +12 -2
  97. data/spec/extensions/split_array_nil_spec.rb +24 -0
  98. data/spec/integration/associations_test.rb +4 -4
  99. data/spec/integration/database_test.rb +2 -2
  100. data/spec/integration/dataset_test.rb +4 -4
  101. data/spec/integration/eager_loader_test.rb +6 -6
  102. data/spec/integration/plugin_test.rb +2 -2
  103. data/spec/integration/spec_helper.rb +2 -2
  104. data/spec/model/association_reflection_spec.rb +5 -0
  105. data/spec/model/associations_spec.rb +156 -49
  106. data/spec/model/eager_loading_spec.rb +137 -2
  107. data/spec/model/model_spec.rb +10 -10
  108. metadata +15 -2
@@ -887,11 +887,11 @@ describe "Sequel::Model Associations with clashing column names" do
887
887
  @Bar = Class.new(Sequel::Model(:bars))
888
888
  @Foo.def_column_alias(:obj_id, :object_id)
889
889
  @Bar.def_column_alias(:obj_id, :object_id)
890
- @Foo.one_to_many :bars, :primary_key=>:obj_id, :primary_key_column=>:object_id, :key=>:object_id, :key_method=>:obj_id, :eager_loader_key=>:object_id, :class=>@Bar
891
- @Foo.one_to_one :bar, :primary_key=>:obj_id, :primary_key_column=>:object_id, :key=>:object_id, :key_method=>:obj_id, :eager_loader_key=>:object_id, :class=>@Bar
890
+ @Foo.one_to_many :bars, :primary_key=>:obj_id, :primary_key_column=>:object_id, :key=>:object_id, :key_method=>:obj_id, :class=>@Bar
891
+ @Foo.one_to_one :bar, :primary_key=>:obj_id, :primary_key_column=>:object_id, :key=>:object_id, :key_method=>:obj_id, :class=>@Bar
892
892
  @Bar.many_to_one :foo, :key=>:obj_id, :key_column=>:object_id, :primary_key=>:object_id, :primary_key_method=>:obj_id, :class=>@Foo
893
- @Foo.many_to_many :mtmbars, :join_table=>:bars_foos, :left_primary_key=>:obj_id, :left_primary_key_column=>:object_id, :right_primary_key=>:object_id, :right_primary_key_method=>:obj_id, :left_key=>:foo_id, :right_key=>:object_id, :eager_loader_key=>:object_id, :class=>@Bar
894
- @Bar.many_to_many :mtmfoos, :join_table=>:bars_foos, :left_primary_key=>:obj_id, :left_primary_key_column=>:object_id, :right_primary_key=>:object_id, :right_primary_key_method=>:obj_id, :left_key=>:object_id, :right_key=>:foo_id, :eager_loader_key=>:object_id, :class=>@Foo
893
+ @Foo.many_to_many :mtmbars, :join_table=>:bars_foos, :left_primary_key=>:obj_id, :left_primary_key_column=>:object_id, :right_primary_key=>:object_id, :right_primary_key_method=>:obj_id, :left_key=>:foo_id, :right_key=>:object_id, :class=>@Bar
894
+ @Bar.many_to_many :mtmfoos, :join_table=>:bars_foos, :left_primary_key=>:obj_id, :left_primary_key_column=>:object_id, :right_primary_key=>:object_id, :right_primary_key_method=>:obj_id, :left_key=>:object_id, :right_key=>:foo_id, :class=>@Foo
895
895
  @foo = @Foo.create(:obj_id=>2)
896
896
  @bar = @Bar.create(:obj_id=>2)
897
897
  @Foo.db[:bars_foos].insert(2, 2)
@@ -2,10 +2,10 @@ require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper.rb')
2
2
 
3
3
  describe Sequel::Database do
4
4
  specify "should provide disconnect functionality" do
5
- INTEGRATION_DB.test_connection
6
- INTEGRATION_DB.pool.size.should == 1
7
5
  INTEGRATION_DB.disconnect
8
6
  INTEGRATION_DB.pool.size.should == 0
7
+ INTEGRATION_DB.test_connection
8
+ INTEGRATION_DB.pool.size.should == 1
9
9
  end
10
10
 
11
11
  specify "should provide disconnect functionality after preparing a statement" do
@@ -150,7 +150,7 @@ describe "Simple Dataset operations" do
150
150
  @db.drop_table(:items2)
151
151
  end
152
152
 
153
- cspecify "should fetch correctly with a limit and offset without an order", :db2, :mssql, :oracle do
153
+ specify "should fetch correctly with a limit and offset without an order" do
154
154
  @ds.limit(2, 1).all.should == []
155
155
  end
156
156
 
@@ -301,11 +301,11 @@ describe Sequel::Database do
301
301
  "\\'dingo",
302
302
  "\\\\''dingo",
303
303
  ].each do |str|
304
- INTEGRATION_DB.get(str.as(:a)).should == str
304
+ INTEGRATION_DB.get(str.cast(String)).should == str
305
305
  str = "1#{str}1"
306
- INTEGRATION_DB.get(str.as(:a)).should == str
306
+ INTEGRATION_DB.get(str.cast(String)).should == str
307
307
  str = "#{str}#{str}"
308
- INTEGRATION_DB.get(str.as(:a)).should == str
308
+ INTEGRATION_DB.get(str.cast(String)).should == str
309
309
  end
310
310
  end
311
311
 
@@ -12,7 +12,7 @@ describe "Eagerly loading a tree structure" do
12
12
  one_to_many :children, :key=>:parent_id
13
13
 
14
14
  # Only useful when eager loading
15
- many_to_one :ancestors, :eager_loader=>(proc do |eo|
15
+ many_to_one :ancestors, :eager_loader_key=>nil, :eager_loader=>(proc do |eo|
16
16
  # Handle cases where the root node has the same parent_id as primary_key
17
17
  # and also when it is NULL
18
18
  non_root_nodes = eo[:rows].reject do |n|
@@ -36,7 +36,7 @@ describe "Eagerly loading a tree structure" do
36
36
  end
37
37
  end
38
38
  end)
39
- many_to_one :descendants, :eager_loader=>(proc do |eo|
39
+ many_to_one :descendants, :eager_loader_key=>nil, :eager_loader=>(proc do |eo|
40
40
  id_map = {}
41
41
  eo[:rows].each do |n|
42
42
  # Initialize an empty array of child associations for each parent node
@@ -185,7 +185,7 @@ describe "has_many :through has_many and has_one :through belongs_to" do
185
185
  end
186
186
  end), \
187
187
  :eager_loader=>(proc do |eo|
188
- id_map = eo[:key_hash][Firm.primary_key]
188
+ id_map = eo[:id_map]
189
189
  eo[:rows].each{|firm| firm.associations[:invoices] = []}
190
190
  Invoice.eager_graph(:client).filter(:client__firm_id=>id_map.keys).all do |inv|
191
191
  id_map[inv.client.firm_id].each do |firm|
@@ -526,7 +526,7 @@ describe "many_to_one/one_to_many not referencing primary key" do
526
526
  many_to_one :client, :key=>:client_name, \
527
527
  :dataset=>proc{Client.filter(:name=>client_name)}, \
528
528
  :eager_loader=>(proc do |eo|
529
- id_map = eo[:key_hash][:client_name]
529
+ id_map = eo[:id_map]
530
530
  eo[:rows].each{|inv| inv.associations[:client] = nil}
531
531
  Client.filter(:name=>id_map.keys).all do |client|
532
532
  id_map[client.name].each{|inv| inv.associations[:client] = client}
@@ -629,11 +629,11 @@ describe "statistics associations" do
629
629
  :dataset=>proc{Ticket.filter(:project_id=>id).select{sum(hours).as(hours)}},
630
630
  :eager_loader=>(proc do |eo|
631
631
  eo[:rows].each{|p| p.associations[:ticket_hours] = nil}
632
- Ticket.filter(:project_id=>eo[:key_hash][:id].keys).
632
+ Ticket.filter(:project_id=>eo[:id_map].keys).
633
633
  group(:project_id).
634
634
  select{[project_id.as(project_id), sum(hours).as(hours)]}.
635
635
  all do |t|
636
- p = eo[:key_hash][:id][t.values.delete(:project_id)].first
636
+ p = eo[:id_map][t.values.delete(:project_id)].first
637
637
  p.associations[:ticket_hours] = t
638
638
  end
639
639
  end)
@@ -100,7 +100,7 @@ describe "Class Table Inheritance Plugin" do
100
100
  Employee.filter(:id=>@i2).all.first.manager.id.should == @i4
101
101
  end
102
102
 
103
- cspecify "should insert rows into all tables", [:amalgalite], [:jdbc, :sqlite] do
103
+ cspecify "should insert rows into all tables", [proc{|db| db.sqlite_version < 30709}, :sqlite] do
104
104
  e = Executive.create(:name=>'Ex2', :num_managers=>8, :num_staff=>9)
105
105
  i = e.id
106
106
  @db[:employees][:id=>i].should == {:id=>i, :name=>'Ex2', :kind=>'Executive'}
@@ -139,7 +139,7 @@ describe "Class Table Inheritance Plugin" do
139
139
  Executive.limit(1).eager(:staff_members).first.staff_members.should == [Staff[@i2]]
140
140
  end
141
141
 
142
- cspecify "should handle eagerly graphing one_to_many relationships", [:amalgalite], [:jdbc, :sqlite] do
142
+ cspecify "should handle eagerly graphing one_to_many relationships", [proc{|db| db.sqlite_version < 30709}, :sqlite] do
143
143
  es = Executive.limit(1).eager_graph(:staff_members).all
144
144
  es.should == [Executive[@i4]]
145
145
  es.map{|x| x.staff_members}.should == [[Staff[@i2]]]
@@ -42,7 +42,7 @@ def Sequel.guarded?(*checked)
42
42
  return c if c.first == INTEGRATION_DB.adapter_scheme
43
43
  when 2
44
44
  if c.first.is_a?(Proc)
45
- return c if c.first.call(INTEGRATION_DB) && c.last == INTEGRATION_DB.database_type
45
+ return c if c.last == INTEGRATION_DB.database_type && c.first.call(INTEGRATION_DB)
46
46
  elsif c.last.is_a?(Proc)
47
47
  return c if c.first == INTEGRATION_DB.adapter_scheme && c.last.call(INTEGRATION_DB)
48
48
  else
@@ -69,7 +69,7 @@ end
69
69
 
70
70
  def self.cspecify(message, *checked, &block)
71
71
  if pending = Sequel.guarded?(*checked)
72
- specify(message){pending("Not yet working on #{Array(pending).join(', ')}", &block)}
72
+ specify(message){pending("Not yet working on #{Array(pending).map{|x| x.is_a?(Proc) ? :proc : x}.join(', ')}", &block)}
73
73
  else
74
74
  specify(message, &block)
75
75
  end
@@ -193,6 +193,11 @@ describe Sequel::Model::Associations::AssociationReflection do
193
193
  @c.meta_def(:name){"C"}
194
194
  end
195
195
 
196
+ it "#eager_loading_predicate_key should be an alias of predicate_key for backwards compatibility" do
197
+ @c.one_to_many :cs, :class=>@c
198
+ @c.dataset.literal(@c.association_reflection(:cs).eager_loading_predicate_key).should == 'foo.c_id'
199
+ end
200
+
196
201
  it "one_to_many #qualified_primary_key should be a qualified version of the primary key" do
197
202
  @c.one_to_many :cs, :class=>@c
198
203
  @c.dataset.literal(@c.association_reflection(:cs).qualified_primary_key).should == 'foo.id'
@@ -125,6 +125,18 @@ describe Sequel::Model, "associate" do
125
125
  end
126
126
  end
127
127
 
128
+ it "should raise an error if attempting to clone an association of differing type" do
129
+ c = Class.new(Sequel::Model(:c))
130
+ c.many_to_one :c
131
+ proc{c.one_to_many :cs, :clone=>:c}.should raise_error(Sequel::Error)
132
+ end
133
+
134
+ it "should allow cloning of one_to_many to one_to_one associations and vice-versa" do
135
+ c = Class.new(Sequel::Model(:c))
136
+ c.one_to_one :c
137
+ proc{c.one_to_many :cs, :clone=>:c}.should_not raise_error(Sequel::Error)
138
+ proc{c.one_to_one :c2, :clone=>:cs}.should_not raise_error(Sequel::Error)
139
+ end
128
140
  end
129
141
 
130
142
  describe Sequel::Model, "many_to_one" do
@@ -672,7 +684,7 @@ describe Sequel::Model, "one_to_one" do
672
684
  sqls = MODEL_DB.sqls
673
685
  ['INSERT INTO attributes (node_id, id) VALUES (1234, 3)',
674
686
  'INSERT INTO attributes (id, node_id) VALUES (3, 1234)'].should(include(sqls.slice! 1))
675
- sqls.should == ['UPDATE attributes SET node_id = NULL WHERE ((node_id = 1234) AND (id != 3))', "SELECT * FROM attributes WHERE (id = 3) LIMIT 1"]
687
+ sqls.should == ['UPDATE attributes SET node_id = NULL WHERE (node_id = 1234)', "SELECT * FROM attributes WHERE (id = 3) LIMIT 1"]
676
688
 
677
689
  @c2.new(:id => 1234).attribute.should == attrib
678
690
  attrib = @c1.load(:id=>3)
@@ -711,7 +723,7 @@ describe Sequel::Model, "one_to_one" do
711
723
  sqls = MODEL_DB.sqls
712
724
  ['INSERT INTO attributes (node_id, id) VALUES (5, 3)',
713
725
  'INSERT INTO attributes (id, node_id) VALUES (3, 5)'].should(include(sqls.slice! 1))
714
- sqls.should == ['UPDATE attributes SET node_id = NULL WHERE ((node_id = 5) AND (id != 3))', "SELECT * FROM attributes WHERE (id = 3) LIMIT 1"]
726
+ sqls.should == ['UPDATE attributes SET node_id = NULL WHERE (node_id = 5)', "SELECT * FROM attributes WHERE (id = 3) LIMIT 1"]
715
727
 
716
728
  @c2.new(:id => 321, :xxx=>5).attribute.should == attrib
717
729
  attrib = @c1.load(:id=>3)
@@ -845,38 +857,6 @@ describe Sequel::Model, "one_to_one" do
845
857
  MODEL_DB.sqls.should == []
846
858
  end
847
859
 
848
- it "should define a setter method" do
849
- @c2.one_to_one :parent, :class => @c2
850
-
851
- d = @c2.new(:id => 1)
852
- f = @c2.new(:id => 3, :node_id=> 4321)
853
- @c2.dataset._fetch = @c2.instance_dataset._fetch = {:id => 3, :node_id=>1}
854
- d.parent = f
855
- f.values.should == {:id => 3, :node_id=>1}
856
- d.parent.should == f
857
- sqls = MODEL_DB.sqls
858
- ["INSERT INTO nodes (node_id, id) VALUES (1, 3)",
859
- "INSERT INTO nodes (id, node_id) VALUES (3, 1)"].should include(sqls.slice! 1)
860
- sqls.should == ["UPDATE nodes SET node_id = NULL WHERE ((node_id = 1) AND (id != 3))", "SELECT * FROM nodes WHERE (id = 3) LIMIT 1"]
861
-
862
- d.parent = nil
863
- d.parent.should == nil
864
- MODEL_DB.sqls.should == ["UPDATE nodes SET node_id = NULL WHERE (node_id = 1)"]
865
- end
866
-
867
- it "should have the setter method respect the :primary_key option" do
868
- @c2.one_to_one :parent, :class => @c2, :primary_key=>:blah
869
- d = @c2.new(:id => 1, :blah => 3)
870
- e = @c2.new(:id => 4321, :node_id=>444)
871
- @c2.dataset._fetch = @c2.instance_dataset._fetch = {:id => 4321, :node_id => 3}
872
- d.parent = e
873
- e.values.should == {:id => 4321, :node_id => 3}
874
- sqls = MODEL_DB.sqls
875
- ["INSERT INTO nodes (node_id, id) VALUES (3, 4321)",
876
- "INSERT INTO nodes (id, node_id) VALUES (4321, 3)"].should include(sqls.slice! 1)
877
- sqls.should == ["UPDATE nodes SET node_id = NULL WHERE ((node_id = 3) AND (id != 4321))", "SELECT * FROM nodes WHERE (id = 4321) LIMIT 1"]
878
- end
879
-
880
860
  it "should have the setter method respect the :key option" do
881
861
  @c2.one_to_one :parent, :class => @c2, :key=>:blah
882
862
  d = @c2.new(:id => 3)
@@ -887,7 +867,7 @@ describe Sequel::Model, "one_to_one" do
887
867
  sqls = MODEL_DB.sqls
888
868
  ["INSERT INTO nodes (blah, id) VALUES (3, 4321)",
889
869
  "INSERT INTO nodes (id, blah) VALUES (4321, 3)"].should include(sqls.slice! 1)
890
- sqls.should == ["UPDATE nodes SET blah = NULL WHERE ((blah = 3) AND (id != 4321))", "SELECT * FROM nodes WHERE (id = 4321) LIMIT 1"]
870
+ sqls.should == ["UPDATE nodes SET blah = NULL WHERE (blah = 3)", "SELECT * FROM nodes WHERE (id = 4321) LIMIT 1"]
891
871
  end
892
872
 
893
873
  it "should persist changes to associated object when the setter is called" do
@@ -1796,7 +1776,7 @@ describe Sequel::Model, "many_to_many" do
1796
1776
  attr_accessor :yyy
1797
1777
  def self.name; 'Attribute'; end
1798
1778
  def self.to_s; 'Attribute'; end
1799
- columns :id, :y
1779
+ columns :id, :y, :z
1800
1780
  end
1801
1781
 
1802
1782
  @c2 = Class.new(Sequel::Model(:nodes)) do
@@ -1841,6 +1821,11 @@ describe Sequel::Model, "many_to_many" do
1841
1821
  end
1842
1822
  end
1843
1823
 
1824
+ it "should respect :eager_loader_predicate_key when lazily loading" do
1825
+ @c2.many_to_many :attributes, :class => @c1, :eager_loading_predicate_key=>Sequel.subscript(:attributes_nodes__node_id, 0)
1826
+ @c2.new(:id => 1234).attributes_dataset.sql.should == 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON ((attributes_nodes.attribute_id = attributes.id) AND (attributes_nodes.node_id[0] = 1234))'
1827
+ end
1828
+
1844
1829
  it "should use explicit key values and join table if given" do
1845
1830
  @c2.many_to_many :attributes, :class => @c1, :left_key => :nodeid, :right_key => :attributeid, :join_table => :attribute2node
1846
1831
  @c2.new(:id => 1234).attributes_dataset.sql.should == 'SELECT attributes.* FROM attributes INNER JOIN attribute2node ON ((attribute2node.attributeid = attributes.id) AND (attribute2node.nodeid = 1234))'
@@ -2058,9 +2043,9 @@ describe Sequel::Model, "many_to_many" do
2058
2043
  end
2059
2044
 
2060
2045
  it "should have the add_ method respect composite keys" do
2061
- @c2.many_to_many :attributes, :class => @c1, :left_key=>[:l1, :l2], :right_key=>[:r1, :r2], :left_primary_key=>[:id, :x], :right_primary_key=>[:id, :y]
2046
+ @c2.many_to_many :attributes, :class => @c1, :left_key=>[:l1, :l2], :right_key=>[:r1, :r2], :left_primary_key=>[:id, :x], :right_primary_key=>[:id, :z]
2062
2047
  n = @c2.load(:id => 1234, :x=>5)
2063
- a = @c1.load(:id => 2345, :y=>8)
2048
+ a = @c1.load(:id => 2345, :z=>8)
2064
2049
  a.should == n.add_attribute(a)
2065
2050
  sqls = MODEL_DB.sqls
2066
2051
  m = /INSERT INTO attributes_nodes \((\w+), (\w+), (\w+), (\w+)\) VALUES \((\d+), (\d+), (\d+), (\d+)\)/.match(sqls.pop)
@@ -2080,14 +2065,14 @@ describe Sequel::Model, "many_to_many" do
2080
2065
  end
2081
2066
 
2082
2067
  it "should have the add_ method respect composite keys" do
2083
- @c2.many_to_many :attributes, :class => @c1, :left_key=>[:l1, :l2], :right_key=>[:r1, :r2], :left_primary_key=>[:id, :x], :right_primary_key=>[:id, :y]
2084
- @c1.set_primary_key [:id, :y]
2068
+ @c2.many_to_many :attributes, :class => @c1, :left_key=>[:l1, :l2], :right_key=>[:r1, :r2], :left_primary_key=>[:id, :x], :right_primary_key=>[:id, :z]
2069
+ @c1.set_primary_key [:id, :z]
2085
2070
  n = @c2.load(:id => 1234, :x=>5)
2086
- a = @c1.load(:id => 2345, :y=>8)
2087
- @c1.dataset._fetch = {:id => 2345, :y=>8}
2071
+ a = @c1.load(:id => 2345, :z=>8)
2072
+ @c1.dataset._fetch = {:id => 2345, :z=>8}
2088
2073
  n.add_attribute([2345, 8]).should == a
2089
2074
  sqls = MODEL_DB.sqls
2090
- sqls.shift.should =~ /SELECT \* FROM attributes WHERE \(\((id|y) = (8|2345)\) AND \((id|y) = (8|2345)\)\) LIMIT 1/
2075
+ sqls.shift.should =~ /SELECT \* FROM attributes WHERE \(\((id|z) = (8|2345)\) AND \((id|z) = (8|2345)\)\) LIMIT 1/
2091
2076
  sqls.pop.should =~ /INSERT INTO attributes_nodes \([lr][12], [lr][12], [lr][12], [lr][12]\) VALUES \((1234|5|2345|8), (1234|5|2345|8), (1234|5|2345|8), (1234|5|2345|8)\)/
2092
2077
  sqls.should == []
2093
2078
  end
@@ -2102,9 +2087,9 @@ describe Sequel::Model, "many_to_many" do
2102
2087
  end
2103
2088
 
2104
2089
  it "should have the remove_ method respect composite keys" do
2105
- @c2.many_to_many :attributes, :class => @c1, :left_key=>[:l1, :l2], :right_key=>[:r1, :r2], :left_primary_key=>[:id, :x], :right_primary_key=>[:id, :y]
2090
+ @c2.many_to_many :attributes, :class => @c1, :left_key=>[:l1, :l2], :right_key=>[:r1, :r2], :left_primary_key=>[:id, :x], :right_primary_key=>[:id, :z]
2106
2091
  n = @c2.load(:id => 1234, :x=>5)
2107
- a = @c1.load(:id => 2345, :y=>8)
2092
+ a = @c1.load(:id => 2345, :z=>8)
2108
2093
  a.should == n.remove_attribute(a)
2109
2094
  MODEL_DB.sqls.should == ["DELETE FROM attributes_nodes WHERE ((l1 = 1234) AND (l2 = 5) AND (r1 = 2345) AND (r2 = 8))"]
2110
2095
  end
@@ -2964,11 +2949,11 @@ describe "Sequel::Model Associations with clashing column names" do
2964
2949
  @Bar.columns :id, :object_id
2965
2950
  @Foo.def_column_alias(:obj_id, :object_id)
2966
2951
  @Bar.def_column_alias(:obj_id, :object_id)
2967
- @Foo.one_to_many :bars, :primary_key=>:obj_id, :primary_key_column=>:object_id, :key=>:object_id, :key_method=>:obj_id, :eager_loader_key=>:object_id, :class=>@Bar
2968
- @Foo.one_to_one :bar, :primary_key=>:obj_id, :primary_key_column=>:object_id, :key=>:object_id, :key_method=>:obj_id, :eager_loader_key=>:object_id, :class=>@Bar
2952
+ @Foo.one_to_many :bars, :primary_key=>:obj_id, :primary_key_column=>:object_id, :key=>:object_id, :key_method=>:obj_id, :class=>@Bar
2953
+ @Foo.one_to_one :bar, :primary_key=>:obj_id, :primary_key_column=>:object_id, :key=>:object_id, :key_method=>:obj_id, :class=>@Bar
2969
2954
  @Bar.many_to_one :foo, :key=>:obj_id, :key_column=>:object_id, :primary_key=>:object_id, :primary_key_method=>:obj_id, :class=>@Foo
2970
- @Foo.many_to_many :mtmbars, :join_table=>:bars_foos, :left_primary_key=>:obj_id, :left_primary_key_column=>:object_id, :right_primary_key=>:object_id, :right_primary_key_method=>:obj_id, :left_key=>:foo_id, :right_key=>:object_id, :eager_loader_key=>:object_id, :class=>@Bar
2971
- @Bar.many_to_many :mtmfoos, :join_table=>:bars_foos, :left_primary_key=>:obj_id, :left_primary_key_column=>:object_id, :right_primary_key=>:object_id, :right_primary_key_method=>:obj_id, :left_key=>:object_id, :right_key=>:foo_id, :eager_loader_key=>:object_id, :class=>@Foo
2955
+ @Foo.many_to_many :mtmbars, :join_table=>:bars_foos, :left_primary_key=>:obj_id, :left_primary_key_column=>:object_id, :right_primary_key=>:object_id, :right_primary_key_method=>:obj_id, :left_key=>:foo_id, :right_key=>:object_id, :class=>@Bar
2956
+ @Bar.many_to_many :mtmfoos, :join_table=>:bars_foos, :left_primary_key=>:obj_id, :left_primary_key_column=>:object_id, :right_primary_key=>:object_id, :right_primary_key_method=>:obj_id, :left_key=>:object_id, :right_key=>:foo_id, :class=>@Foo
2972
2957
  @foo = @Foo.load(:id=>1, :object_id=>2)
2973
2958
  @bar = @Bar.load(:id=>1, :object_id=>2)
2974
2959
  @db.sqls
@@ -2976,33 +2961,61 @@ describe "Sequel::Model Associations with clashing column names" do
2976
2961
 
2977
2962
  it "should have working regular association methods" do
2978
2963
  @Bar.first.foo.should == @foo
2964
+ @db.sqls.should == ["SELECT * FROM bars LIMIT 1", "SELECT * FROM foos WHERE (foos.object_id = 2) LIMIT 1"]
2979
2965
  @Foo.first.bars.should == [@bar]
2966
+ @db.sqls.should == ["SELECT * FROM foos LIMIT 1", "SELECT * FROM bars WHERE (bars.object_id = 2)"]
2980
2967
  @Foo.first.bar.should == @bar
2968
+ @db.sqls.should == ["SELECT * FROM foos LIMIT 1", "SELECT * FROM bars WHERE (bars.object_id = 2) LIMIT 1"]
2981
2969
  @Foo.first.mtmbars.should == [@bar]
2970
+ @db.sqls.should == ["SELECT * FROM foos LIMIT 1", "SELECT bars.* FROM bars INNER JOIN bars_foos ON ((bars_foos.object_id = bars.object_id) AND (bars_foos.foo_id = 2))"]
2982
2971
  @Bar.first.mtmfoos.should == [@foo]
2972
+ @db.sqls.should == ["SELECT * FROM bars LIMIT 1", "SELECT foos.* FROM foos INNER JOIN bars_foos ON ((bars_foos.foo_id = foos.object_id) AND (bars_foos.object_id = 2))"]
2983
2973
  end
2984
2974
 
2985
2975
  it "should have working eager loading methods" do
2986
2976
  @Bar.eager(:foo).all.map{|o| [o, o.foo]}.should == [[@bar, @foo]]
2977
+ @db.sqls.should == ["SELECT * FROM bars", "SELECT * FROM foos WHERE (foos.object_id IN (2))"]
2987
2978
  @Foo.eager(:bars).all.map{|o| [o, o.bars]}.should == [[@foo, [@bar]]]
2979
+ @db.sqls.should == ["SELECT * FROM foos", "SELECT * FROM bars WHERE (bars.object_id IN (2))"]
2988
2980
  @Foo.eager(:bar).all.map{|o| [o, o.bar]}.should == [[@foo, @bar]]
2981
+ @db.sqls.should == ["SELECT * FROM foos", "SELECT * FROM bars WHERE (bars.object_id IN (2))"]
2989
2982
  @db.fetch = [[{:id=>1, :object_id=>2}], [{:id=>1, :object_id=>2, :x_foreign_key_x=>2}]]
2990
2983
  @Foo.eager(:mtmbars).all.map{|o| [o, o.mtmbars]}.should == [[@foo, [@bar]]]
2984
+ @db.sqls.should == ["SELECT * FROM foos", "SELECT bars.*, bars_foos.foo_id AS x_foreign_key_x FROM bars INNER JOIN bars_foos ON ((bars_foos.object_id = bars.object_id) AND (bars_foos.foo_id IN (2)))"]
2991
2985
  @db.fetch = [[{:id=>1, :object_id=>2}], [{:id=>1, :object_id=>2, :x_foreign_key_x=>2}]]
2992
2986
  @Bar.eager(:mtmfoos).all.map{|o| [o, o.mtmfoos]}.should == [[@bar, [@foo]]]
2987
+ @db.sqls.should == ["SELECT * FROM bars", "SELECT foos.*, bars_foos.object_id AS x_foreign_key_x FROM foos INNER JOIN bars_foos ON ((bars_foos.foo_id = foos.object_id) AND (bars_foos.object_id IN (2)))"]
2993
2988
  end
2994
2989
 
2995
2990
  it "should have working eager graphing methods" do
2996
2991
  @db.fetch = {:id=>1, :object_id=>2, :foo_id=>1, :foo_object_id=>2}
2997
2992
  @Bar.eager_graph(:foo).all.map{|o| [o, o.foo]}.should == [[@bar, @foo]]
2993
+ @db.sqls.should == ["SELECT bars.id, bars.object_id, foo.id AS foo_id, foo.object_id AS foo_object_id FROM bars LEFT OUTER JOIN foos AS foo ON (foo.object_id = bars.object_id)"]
2998
2994
  @db.fetch = {:id=>1, :object_id=>2, :bars_id=>1, :bars_object_id=>2}
2999
2995
  @Foo.eager_graph(:bars).all.map{|o| [o, o.bars]}.should == [[@foo, [@bar]]]
2996
+ @db.sqls.should == ["SELECT foos.id, foos.object_id, bars.id AS bars_id, bars.object_id AS bars_object_id FROM foos LEFT OUTER JOIN bars ON (bars.object_id = foos.object_id)"]
3000
2997
  @db.fetch = {:id=>1, :object_id=>2, :bar_id=>1, :bar_object_id=>2}
3001
2998
  @Foo.eager_graph(:bar).all.map{|o| [o, o.bar]}.should == [[@foo, @bar]]
2999
+ @db.sqls.should == ["SELECT foos.id, foos.object_id, bar.id AS bar_id, bar.object_id AS bar_object_id FROM foos LEFT OUTER JOIN bars AS bar ON (bar.object_id = foos.object_id)"]
3002
3000
  @db.fetch = {:id=>1, :object_id=>2, :mtmfoos_id=>1, :mtmfoos_object_id=>2}
3003
3001
  @Bar.eager_graph(:mtmfoos).all.map{|o| [o, o.mtmfoos]}.should == [[@bar, [@foo]]]
3002
+ @db.sqls.should == ["SELECT bars.id, bars.object_id, mtmfoos.id AS mtmfoos_id, mtmfoos.object_id AS mtmfoos_object_id FROM bars LEFT OUTER JOIN bars_foos ON (bars_foos.object_id = bars.object_id) LEFT OUTER JOIN foos AS mtmfoos ON (mtmfoos.object_id = bars_foos.foo_id)"]
3004
3003
  @db.fetch = {:id=>1, :object_id=>2, :mtmbars_id=>1, :mtmbars_object_id=>2}
3005
3004
  @Foo.eager_graph(:mtmbars).all.map{|o| [o, o.mtmbars]}.should == [[@foo, [@bar]]]
3005
+ @db.sqls.should == ["SELECT foos.id, foos.object_id, mtmbars.id AS mtmbars_id, mtmbars.object_id AS mtmbars_object_id FROM foos LEFT OUTER JOIN bars_foos ON (bars_foos.foo_id = foos.object_id) LEFT OUTER JOIN bars AS mtmbars ON (mtmbars.object_id = bars_foos.object_id)"]
3006
+ end
3007
+
3008
+ it "should have working filter by associations with model instances" do
3009
+ @Bar.first(:foo=>@foo).should == @bar
3010
+ @db.sqls.should == ["SELECT * FROM bars WHERE (bars.object_id = 2) LIMIT 1"]
3011
+ @Foo.first(:bars=>@bar).should == @foo
3012
+ @db.sqls.should == ["SELECT * FROM foos WHERE (foos.object_id = 2) LIMIT 1"]
3013
+ @Foo.first(:bar=>@bar).should == @foo
3014
+ @db.sqls.should == ["SELECT * FROM foos WHERE (foos.object_id = 2) LIMIT 1"]
3015
+ @Foo.first(:mtmbars=>@bar).should == @foo
3016
+ @db.sqls.should == ["SELECT * FROM foos WHERE (foos.object_id IN (SELECT bars_foos.foo_id FROM bars_foos WHERE ((bars_foos.object_id = 2) AND (bars_foos.foo_id IS NOT NULL)))) LIMIT 1"]
3017
+ @Bar.first(:mtmfoos=>@foo).should == @bar
3018
+ @db.sqls.should == ["SELECT * FROM bars WHERE (bars.object_id IN (SELECT bars_foos.object_id FROM bars_foos WHERE ((bars_foos.foo_id = 2) AND (bars_foos.object_id IS NOT NULL)))) LIMIT 1"]
3006
3019
  end
3007
3020
 
3008
3021
  it "should have working modification methods" do
@@ -3045,6 +3058,100 @@ describe "Sequel::Model Associations with clashing column names" do
3045
3058
  end
3046
3059
  end
3047
3060
 
3061
+ describe "Sequel::Model Associations with non-column expression keys" do
3062
+ before do
3063
+ @db = Sequel.mock(:fetch=>{:id=>1, :object_ids=>[2]})
3064
+ @Foo = Class.new(Sequel::Model(@db[:foos]))
3065
+ @Bar = Class.new(Sequel::Model(@db[:bars]))
3066
+ @Foo.columns :id, :object_ids
3067
+ @Bar.columns :id, :object_ids
3068
+ m = Module.new{def obj_id; object_ids[0]; end}
3069
+ @Foo.include m
3070
+ @Bar.include m
3071
+
3072
+ @Foo.one_to_many :bars, :primary_key=>:obj_id, :primary_key_column=>Sequel.subscript(:object_ids, 0), :key=>Sequel.subscript(:object_ids, 0), :key_method=>:obj_id, :class=>@Bar
3073
+ @Foo.one_to_one :bar, :primary_key=>:obj_id, :primary_key_column=>Sequel.subscript(:object_ids, 0), :key=>Sequel.subscript(:object_ids, 0), :key_method=>:obj_id, :class=>@Bar
3074
+ @Bar.many_to_one :foo, :key=>:obj_id, :key_column=>Sequel.subscript(:object_ids, 0), :primary_key=>Sequel.subscript(:object_ids, 0), :primary_key_method=>:obj_id, :class=>@Foo
3075
+ @Foo.many_to_many :mtmbars, :join_table=>:bars_foos, :left_primary_key=>:obj_id, :left_primary_key_column=>Sequel.subscript(:object_ids, 0), :right_primary_key=>Sequel.subscript(:object_ids, 0), :right_primary_key_method=>:obj_id, :left_key=>Sequel.subscript(:foo_ids, 0), :right_key=>Sequel.subscript(:bar_ids, 0), :class=>@Bar
3076
+ @Bar.many_to_many :mtmfoos, :join_table=>:bars_foos, :left_primary_key=>:obj_id, :left_primary_key_column=>Sequel.subscript(:object_ids, 0), :right_primary_key=>Sequel.subscript(:object_ids, 0), :right_primary_key_method=>:obj_id, :left_key=>Sequel.subscript(:bar_ids, 0), :right_key=>Sequel.subscript(:foo_ids, 0), :class=>@Foo
3077
+ @foo = @Foo.load(:id=>1, :object_ids=>[2])
3078
+ @bar = @Bar.load(:id=>1, :object_ids=>[2])
3079
+ @db.sqls
3080
+ end
3081
+
3082
+ it "should have working regular association methods" do
3083
+ @Bar.first.foo.should == @foo
3084
+ @db.sqls.should == ["SELECT * FROM bars LIMIT 1", "SELECT * FROM foos WHERE (foos.object_ids[0] = 2) LIMIT 1"]
3085
+ @Foo.first.bars.should == [@bar]
3086
+ @db.sqls.should == ["SELECT * FROM foos LIMIT 1", "SELECT * FROM bars WHERE (bars.object_ids[0] = 2)"]
3087
+ @Foo.first.bar.should == @bar
3088
+ @db.sqls.should == ["SELECT * FROM foos LIMIT 1", "SELECT * FROM bars WHERE (bars.object_ids[0] = 2) LIMIT 1"]
3089
+ @Foo.first.mtmbars.should == [@bar]
3090
+ @db.sqls.should == ["SELECT * FROM foos LIMIT 1", "SELECT bars.* FROM bars INNER JOIN bars_foos ON ((bars_foos.bar_ids[0] = bars.object_ids[0]) AND (bars_foos.foo_ids[0] = 2))"]
3091
+ @Bar.first.mtmfoos.should == [@foo]
3092
+ @db.sqls.should == ["SELECT * FROM bars LIMIT 1", "SELECT foos.* FROM foos INNER JOIN bars_foos ON ((bars_foos.foo_ids[0] = foos.object_ids[0]) AND (bars_foos.bar_ids[0] = 2))"]
3093
+ end
3094
+
3095
+ it "should have working eager loading methods" do
3096
+ @Bar.eager(:foo).all.map{|o| [o, o.foo]}.should == [[@bar, @foo]]
3097
+ @db.sqls.should == ["SELECT * FROM bars", "SELECT * FROM foos WHERE (foos.object_ids[0] IN (2))"]
3098
+ @Foo.eager(:bars).all.map{|o| [o, o.bars]}.should == [[@foo, [@bar]]]
3099
+ @db.sqls.should == ["SELECT * FROM foos", "SELECT * FROM bars WHERE (bars.object_ids[0] IN (2))"]
3100
+ @Foo.eager(:bar).all.map{|o| [o, o.bar]}.should == [[@foo, @bar]]
3101
+ @db.sqls.should == ["SELECT * FROM foos", "SELECT * FROM bars WHERE (bars.object_ids[0] IN (2))"]
3102
+ @db.fetch = [[{:id=>1, :object_ids=>[2]}], [{:id=>1, :object_ids=>[2], :x_foreign_key_x=>2}]]
3103
+ @Foo.eager(:mtmbars).all.map{|o| [o, o.mtmbars]}.should == [[@foo, [@bar]]]
3104
+ @db.sqls.should == ["SELECT * FROM foos", "SELECT bars.*, bars_foos.foo_ids[0] AS x_foreign_key_x FROM bars INNER JOIN bars_foos ON ((bars_foos.bar_ids[0] = bars.object_ids[0]) AND (bars_foos.foo_ids[0] IN (2)))"]
3105
+ @db.fetch = [[{:id=>1, :object_ids=>[2]}], [{:id=>1, :object_ids=>[2], :x_foreign_key_x=>2}]]
3106
+ @Bar.eager(:mtmfoos).all.map{|o| [o, o.mtmfoos]}.should == [[@bar, [@foo]]]
3107
+ @db.sqls.should == ["SELECT * FROM bars", "SELECT foos.*, bars_foos.bar_ids[0] AS x_foreign_key_x FROM foos INNER JOIN bars_foos ON ((bars_foos.foo_ids[0] = foos.object_ids[0]) AND (bars_foos.bar_ids[0] IN (2)))"]
3108
+ end
3109
+
3110
+ it "should have working eager graphing methods" do
3111
+ @db.fetch = {:id=>1, :object_ids=>[2], :foo_id=>1, :foo_object_ids=>[2]}
3112
+ @Bar.eager_graph(:foo).all.map{|o| [o, o.foo]}.should == [[@bar, @foo]]
3113
+ @db.sqls.should == ["SELECT bars.id, bars.object_ids, foo.id AS foo_id, foo.object_ids AS foo_object_ids FROM bars LEFT OUTER JOIN foos AS foo ON (foo.object_ids[0] = bars.object_ids[0])"]
3114
+ @db.fetch = {:id=>1, :object_ids=>[2], :bars_id=>1, :bars_object_ids=>[2]}
3115
+ @Foo.eager_graph(:bars).all.map{|o| [o, o.bars]}.should == [[@foo, [@bar]]]
3116
+ @db.sqls.should == ["SELECT foos.id, foos.object_ids, bars.id AS bars_id, bars.object_ids AS bars_object_ids FROM foos LEFT OUTER JOIN bars ON (bars.object_ids[0] = foos.object_ids[0])"]
3117
+ @db.fetch = {:id=>1, :object_ids=>[2], :bar_id=>1, :bar_object_ids=>[2]}
3118
+ @Foo.eager_graph(:bar).all.map{|o| [o, o.bar]}.should == [[@foo, @bar]]
3119
+ @db.sqls.should == ["SELECT foos.id, foos.object_ids, bar.id AS bar_id, bar.object_ids AS bar_object_ids FROM foos LEFT OUTER JOIN bars AS bar ON (bar.object_ids[0] = foos.object_ids[0])"]
3120
+ @db.fetch = {:id=>1, :object_ids=>[2], :mtmfoos_id=>1, :mtmfoos_object_ids=>[2]}
3121
+ @Bar.eager_graph(:mtmfoos).all.map{|o| [o, o.mtmfoos]}.should == [[@bar, [@foo]]]
3122
+ @db.sqls.should == ["SELECT bars.id, bars.object_ids, mtmfoos.id AS mtmfoos_id, mtmfoos.object_ids AS mtmfoos_object_ids FROM bars LEFT OUTER JOIN bars_foos ON (bars_foos.bar_ids[0] = bars.object_ids[0]) LEFT OUTER JOIN foos AS mtmfoos ON (mtmfoos.object_ids[0] = bars_foos.foo_ids[0])"]
3123
+ @db.fetch = {:id=>1, :object_ids=>[2], :mtmbars_id=>1, :mtmbars_object_ids=>[2]}
3124
+ @Foo.eager_graph(:mtmbars).all.map{|o| [o, o.mtmbars]}.should == [[@foo, [@bar]]]
3125
+ @db.sqls.should == ["SELECT foos.id, foos.object_ids, mtmbars.id AS mtmbars_id, mtmbars.object_ids AS mtmbars_object_ids FROM foos LEFT OUTER JOIN bars_foos ON (bars_foos.foo_ids[0] = foos.object_ids[0]) LEFT OUTER JOIN bars AS mtmbars ON (mtmbars.object_ids[0] = bars_foos.bar_ids[0])"]
3126
+ end
3127
+
3128
+ it "should have working filter by associations with model instances" do
3129
+ @Bar.first(:foo=>@foo).should == @bar
3130
+ @db.sqls.should == ["SELECT * FROM bars WHERE (bars.object_ids[0] = 2) LIMIT 1"]
3131
+ @Foo.first(:bars=>@bar).should == @foo
3132
+ @db.sqls.should == ["SELECT * FROM foos WHERE (foos.object_ids[0] = 2) LIMIT 1"]
3133
+ @Foo.first(:bar=>@bar).should == @foo
3134
+ @db.sqls.should == ["SELECT * FROM foos WHERE (foos.object_ids[0] = 2) LIMIT 1"]
3135
+ @Foo.first(:mtmbars=>@bar).should == @foo
3136
+ @db.sqls.should == ["SELECT * FROM foos WHERE (foos.object_ids[0] IN (SELECT bars_foos.foo_ids[0] FROM bars_foos WHERE ((bars_foos.bar_ids[0] = 2) AND (bars_foos.foo_ids[0] IS NOT NULL)))) LIMIT 1"]
3137
+ @Bar.first(:mtmfoos=>@foo).should == @bar
3138
+ @db.sqls.should == ["SELECT * FROM bars WHERE (bars.object_ids[0] IN (SELECT bars_foos.bar_ids[0] FROM bars_foos WHERE ((bars_foos.foo_ids[0] = 2) AND (bars_foos.bar_ids[0] IS NOT NULL)))) LIMIT 1"]
3139
+ end
3140
+
3141
+ it "should have working filter by associations with model datasets" do
3142
+ @Bar.first(:foo=>@Foo.where(:id=>@foo.id)).should == @bar
3143
+ @db.sqls.should == ["SELECT * FROM bars WHERE (bars.object_ids[0] IN (SELECT foos.object_ids[0] FROM foos WHERE ((id = 1) AND (foos.object_ids[0] IS NOT NULL)))) LIMIT 1"]
3144
+ @Foo.first(:bars=>@Bar.where(:id=>@bar.id)).should == @foo
3145
+ @db.sqls.should == ["SELECT * FROM foos WHERE (foos.object_ids[0] IN (SELECT bars.object_ids[0] FROM bars WHERE ((id = 1) AND (bars.object_ids[0] IS NOT NULL)))) LIMIT 1"]
3146
+ @Foo.first(:bar=>@Bar.where(:id=>@bar.id)).should == @foo
3147
+ @db.sqls.should == ["SELECT * FROM foos WHERE (foos.object_ids[0] IN (SELECT bars.object_ids[0] FROM bars WHERE ((id = 1) AND (bars.object_ids[0] IS NOT NULL)))) LIMIT 1"]
3148
+ @Foo.first(:mtmbars=>@Bar.where(:id=>@bar.id)).should == @foo
3149
+ @db.sqls.should == ["SELECT * FROM foos WHERE (foos.object_ids[0] IN (SELECT bars_foos.foo_ids[0] FROM bars_foos WHERE ((bars_foos.bar_ids[0] IN (SELECT bars.object_ids[0] FROM bars WHERE ((id = 1) AND (bars.object_ids[0] IS NOT NULL)))) AND (bars_foos.foo_ids[0] IS NOT NULL)))) LIMIT 1"]
3150
+ @Bar.first(:mtmfoos=>@Foo.where(:id=>@foo.id)).should == @bar
3151
+ @db.sqls.should == ["SELECT * FROM bars WHERE (bars.object_ids[0] IN (SELECT bars_foos.bar_ids[0] FROM bars_foos WHERE ((bars_foos.foo_ids[0] IN (SELECT foos.object_ids[0] FROM foos WHERE ((id = 1) AND (foos.object_ids[0] IS NOT NULL)))) AND (bars_foos.bar_ids[0] IS NOT NULL)))) LIMIT 1"]
3152
+ end
3153
+ end
3154
+
3048
3155
  describe "Model#pk_or_nil" do
3049
3156
  before do
3050
3157
  @m = Class.new(Sequel::Model)