sequel 3.36.1 → 3.37.0

Sign up to get free protection for your applications and to get access to all the features.
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)