sequel 4.9.0 → 4.10.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 (110) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +79 -1
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  5. data/Rakefile +2 -12
  6. data/bin/sequel +1 -0
  7. data/doc/advanced_associations.rdoc +82 -25
  8. data/doc/association_basics.rdoc +21 -22
  9. data/doc/core_extensions.rdoc +1 -1
  10. data/doc/opening_databases.rdoc +7 -0
  11. data/doc/release_notes/4.10.0.txt +226 -0
  12. data/doc/security.rdoc +1 -0
  13. data/doc/testing.rdoc +7 -7
  14. data/doc/transactions.rdoc +8 -0
  15. data/lib/sequel/adapters/jdbc.rb +160 -168
  16. data/lib/sequel/adapters/jdbc/db2.rb +17 -18
  17. data/lib/sequel/adapters/jdbc/derby.rb +5 -28
  18. data/lib/sequel/adapters/jdbc/h2.rb +11 -22
  19. data/lib/sequel/adapters/jdbc/hsqldb.rb +31 -18
  20. data/lib/sequel/adapters/jdbc/jtds.rb +0 -15
  21. data/lib/sequel/adapters/jdbc/oracle.rb +36 -35
  22. data/lib/sequel/adapters/jdbc/postgresql.rb +72 -90
  23. data/lib/sequel/adapters/jdbc/sqlanywhere.rb +18 -16
  24. data/lib/sequel/adapters/jdbc/sqlite.rb +7 -0
  25. data/lib/sequel/adapters/jdbc/sqlserver.rb +10 -30
  26. data/lib/sequel/adapters/jdbc/transactions.rb +5 -6
  27. data/lib/sequel/adapters/openbase.rb +1 -7
  28. data/lib/sequel/adapters/postgres.rb +1 -1
  29. data/lib/sequel/adapters/shared/access.rb +3 -6
  30. data/lib/sequel/adapters/shared/cubrid.rb +24 -9
  31. data/lib/sequel/adapters/shared/db2.rb +13 -5
  32. data/lib/sequel/adapters/shared/firebird.rb +16 -16
  33. data/lib/sequel/adapters/shared/informix.rb +2 -5
  34. data/lib/sequel/adapters/shared/mssql.rb +72 -63
  35. data/lib/sequel/adapters/shared/mysql.rb +72 -40
  36. data/lib/sequel/adapters/shared/oracle.rb +27 -15
  37. data/lib/sequel/adapters/shared/postgres.rb +24 -44
  38. data/lib/sequel/adapters/shared/progress.rb +1 -5
  39. data/lib/sequel/adapters/shared/sqlanywhere.rb +26 -18
  40. data/lib/sequel/adapters/shared/sqlite.rb +21 -6
  41. data/lib/sequel/adapters/utils/emulate_offset_with_reverse_and_count.rb +8 -1
  42. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +8 -2
  43. data/lib/sequel/adapters/utils/split_alter_table.rb +8 -0
  44. data/lib/sequel/core.rb +14 -9
  45. data/lib/sequel/database/dataset_defaults.rb +1 -0
  46. data/lib/sequel/database/misc.rb +12 -0
  47. data/lib/sequel/database/query.rb +4 -1
  48. data/lib/sequel/database/schema_methods.rb +3 -2
  49. data/lib/sequel/database/transactions.rb +47 -17
  50. data/lib/sequel/dataset/features.rb +12 -2
  51. data/lib/sequel/dataset/mutation.rb +2 -0
  52. data/lib/sequel/dataset/placeholder_literalizer.rb +12 -4
  53. data/lib/sequel/dataset/prepared_statements.rb +6 -0
  54. data/lib/sequel/dataset/query.rb +1 -1
  55. data/lib/sequel/dataset/sql.rb +132 -70
  56. data/lib/sequel/extensions/columns_introspection.rb +1 -1
  57. data/lib/sequel/extensions/null_dataset.rb +8 -4
  58. data/lib/sequel/extensions/pg_array.rb +4 -4
  59. data/lib/sequel/extensions/pg_row.rb +1 -0
  60. data/lib/sequel/model/associations.rb +468 -188
  61. data/lib/sequel/model/base.rb +88 -13
  62. data/lib/sequel/plugins/association_pks.rb +23 -64
  63. data/lib/sequel/plugins/auto_validations.rb +3 -2
  64. data/lib/sequel/plugins/dataset_associations.rb +1 -3
  65. data/lib/sequel/plugins/many_through_many.rb +18 -65
  66. data/lib/sequel/plugins/pg_array_associations.rb +97 -86
  67. data/lib/sequel/plugins/prepared_statements.rb +2 -1
  68. data/lib/sequel/plugins/prepared_statements_associations.rb +36 -27
  69. data/lib/sequel/plugins/rcte_tree.rb +12 -16
  70. data/lib/sequel/plugins/sharding.rb +21 -3
  71. data/lib/sequel/plugins/single_table_inheritance.rb +2 -1
  72. data/lib/sequel/plugins/subclasses.rb +1 -9
  73. data/lib/sequel/plugins/tactical_eager_loading.rb +9 -0
  74. data/lib/sequel/plugins/tree.rb +2 -2
  75. data/lib/sequel/plugins/validation_class_methods.rb +1 -1
  76. data/lib/sequel/version.rb +1 -1
  77. data/spec/adapters/mssql_spec.rb +57 -15
  78. data/spec/adapters/mysql_spec.rb +11 -0
  79. data/spec/bin_spec.rb +2 -2
  80. data/spec/core/database_spec.rb +38 -4
  81. data/spec/core/dataset_spec.rb +45 -7
  82. data/spec/core/placeholder_literalizer_spec.rb +17 -0
  83. data/spec/core/schema_spec.rb +6 -1
  84. data/spec/extensions/active_model_spec.rb +18 -9
  85. data/spec/extensions/association_pks_spec.rb +20 -18
  86. data/spec/extensions/association_proxies_spec.rb +9 -9
  87. data/spec/extensions/auto_validations_spec.rb +6 -0
  88. data/spec/extensions/columns_introspection_spec.rb +1 -0
  89. data/spec/extensions/constraint_validations_spec.rb +3 -1
  90. data/spec/extensions/many_through_many_spec.rb +191 -111
  91. data/spec/extensions/pg_array_associations_spec.rb +133 -103
  92. data/spec/extensions/prepared_statements_associations_spec.rb +23 -4
  93. data/spec/extensions/rcte_tree_spec.rb +35 -27
  94. data/spec/extensions/sequel_3_dataset_methods_spec.rb +0 -1
  95. data/spec/extensions/sharding_spec.rb +2 -2
  96. data/spec/extensions/tactical_eager_loading_spec.rb +4 -0
  97. data/spec/extensions/to_dot_spec.rb +1 -0
  98. data/spec/extensions/touch_spec.rb +2 -2
  99. data/spec/integration/associations_test.rb +130 -37
  100. data/spec/integration/dataset_test.rb +17 -0
  101. data/spec/integration/model_test.rb +17 -0
  102. data/spec/integration/schema_test.rb +14 -0
  103. data/spec/integration/transaction_test.rb +25 -1
  104. data/spec/model/association_reflection_spec.rb +63 -24
  105. data/spec/model/associations_spec.rb +104 -57
  106. data/spec/model/base_spec.rb +14 -1
  107. data/spec/model/class_dataset_methods_spec.rb +1 -0
  108. data/spec/model/eager_loading_spec.rb +221 -74
  109. data/spec/model/model_spec.rb +119 -1
  110. metadata +4 -2
@@ -22,8 +22,10 @@ describe "Sequel::Plugins::PreparedStatementsAssociations" do
22
22
  @Artist.one_to_one :album, :class=>@Album, :key=>:artist_id
23
23
  @Album.many_to_one :artist, :class=>@Artist
24
24
  @Album.many_to_many :tags, :class=>@Tag, :join_table=>:albums_tags, :left_key=>:album_id
25
+ @Album.one_through_one :tag, :clone=>:tags
25
26
  @Artist.plugin :many_through_many
26
27
  @Artist.many_through_many :tags, [[:albums, :artist_id, :id], [:albums_tags, :album_id, :tag_id]], :class=>@Tag
28
+ @Artist.one_through_many :tag, :clone=>:tags
27
29
  @db.sqls
28
30
  end
29
31
 
@@ -38,10 +40,16 @@ describe "Sequel::Plugins::PreparedStatementsAssociations" do
38
40
  @db.sqls.should == ["SELECT * FROM artists WHERE (artists.id = 2) LIMIT 1 -- prepared"]
39
41
 
40
42
  @Album.load(:id=>1, :artist_id=>2).tags
41
- @db.sqls.should == ["SELECT tags.* FROM tags INNER JOIN albums_tags ON ((albums_tags.tag_id = tags.id) AND (albums_tags.album_id = 1)) -- prepared"]
43
+ @db.sqls.should == ["SELECT tags.* FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) WHERE (albums_tags.album_id = 1) -- prepared"]
44
+
45
+ @Album.load(:id=>1, :artist_id=>2).tag
46
+ @db.sqls.should == ["SELECT tags.* FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) WHERE (albums_tags.album_id = 1) LIMIT 1 -- prepared"]
42
47
 
43
48
  @Artist.load(:id=>1).tags
44
- @db.sqls.should == ["SELECT tags.* FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON ((albums.id = albums_tags.album_id) AND (albums.artist_id = 1)) -- prepared"]
49
+ @db.sqls.should == ["SELECT tags.* FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) WHERE (albums.artist_id = 1) -- prepared"]
50
+
51
+ @Artist.load(:id=>1).tag
52
+ @db.sqls.should == ["SELECT tags.* FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) WHERE (albums.artist_id = 1) LIMIT 1 -- prepared"]
45
53
  end
46
54
 
47
55
  specify "should run correct SQL for composite key associations" do
@@ -49,7 +57,10 @@ describe "Sequel::Plugins::PreparedStatementsAssociations" do
49
57
  @Artist.one_to_one :album, :class=>@Album, :key=>[:artist_id, :artist_id2], :primary_key=>[:id, :id2]
50
58
  @Album.many_to_one :artist, :class=>@Artist, :key=>[:artist_id, :artist_id2], :primary_key=>[:id, :id2]
51
59
  @Album.many_to_many :tags, :class=>@Tag, :join_table=>:albums_tags, :left_key=>[:album_id, :album_id2], :right_key=>[:tag_id, :tag_id2], :right_primary_key=>[:id, :id2], :left_primary_key=>[:id, :id2]
60
+ @Album.one_through_one :tag, :clone=>:tags
61
+
52
62
  @Artist.many_through_many :tags, [[:albums, [:artist_id, :artist_id2], [:id, :id2]], [:albums_tags, [:album_id, :album_id2], [:tag_id, :tag_id2]]], :class=>@Tag, :right_primary_key=>[:id, :id2], :left_primary_key=>[:id, :id2]
63
+ @Artist.one_through_many :tag, :clone=>:tags
53
64
 
54
65
  @Artist.load(:id=>1, :id2=>2).albums
55
66
  @db.sqls.should == ["SELECT * FROM albums WHERE ((albums.artist_id = 1) AND (albums.artist_id2 = 2)) -- prepared"]
@@ -61,10 +72,16 @@ describe "Sequel::Plugins::PreparedStatementsAssociations" do
61
72
  @db.sqls.should == ["SELECT * FROM artists WHERE ((artists.id = 2) AND (artists.id2 = 3)) LIMIT 1 -- prepared"]
62
73
 
63
74
  @Album.load(:id=>1, :artist_id=>2, :id2=>3).tags
64
- @db.sqls.should == ["SELECT tags.* FROM tags INNER JOIN albums_tags ON ((albums_tags.tag_id = tags.id) AND (albums_tags.tag_id2 = tags.id2) AND (albums_tags.album_id = 1) AND (albums_tags.album_id2 = 3)) -- prepared"]
75
+ @db.sqls.should == ["SELECT tags.* FROM tags INNER JOIN albums_tags ON ((albums_tags.tag_id = tags.id) AND (albums_tags.tag_id2 = tags.id2)) WHERE ((albums_tags.album_id = 1) AND (albums_tags.album_id2 = 3)) -- prepared"]
76
+
77
+ @Album.load(:id=>1, :artist_id=>2, :id2=>3).tag
78
+ @db.sqls.should == ["SELECT tags.* FROM tags INNER JOIN albums_tags ON ((albums_tags.tag_id = tags.id) AND (albums_tags.tag_id2 = tags.id2)) WHERE ((albums_tags.album_id = 1) AND (albums_tags.album_id2 = 3)) LIMIT 1 -- prepared"]
65
79
 
66
80
  @Artist.load(:id=>1, :id2=>2).tags
67
- @db.sqls.should == ["SELECT tags.* FROM tags INNER JOIN albums_tags ON ((albums_tags.tag_id = tags.id) AND (albums_tags.tag_id2 = tags.id2)) INNER JOIN albums ON ((albums.id = albums_tags.album_id) AND (albums.id2 = albums_tags.album_id2) AND (albums.artist_id = 1) AND (albums.artist_id2 = 2)) -- prepared"]
81
+ @db.sqls.should == ["SELECT tags.* FROM tags INNER JOIN albums_tags ON ((albums_tags.tag_id = tags.id) AND (albums_tags.tag_id2 = tags.id2)) INNER JOIN albums ON ((albums.id = albums_tags.album_id) AND (albums.id2 = albums_tags.album_id2)) WHERE ((albums.artist_id = 1) AND (albums.artist_id2 = 2)) -- prepared"]
82
+
83
+ @Artist.load(:id=>1, :id2=>2).tag
84
+ @db.sqls.should == ["SELECT tags.* FROM tags INNER JOIN albums_tags ON ((albums_tags.tag_id = tags.id) AND (albums_tags.tag_id2 = tags.id2)) INNER JOIN albums ON ((albums.id = albums_tags.album_id) AND (albums.id2 = albums_tags.album_id2)) WHERE ((albums.artist_id = 1) AND (albums.artist_id2 = 2)) LIMIT 1 -- prepared"]
68
85
  end
69
86
 
70
87
  specify "should not run query if no objects can be associated" do
@@ -76,6 +93,8 @@ describe "Sequel::Plugins::PreparedStatementsAssociations" do
76
93
  specify "should run a regular query if there is a callback" do
77
94
  @Artist.load(:id=>1).albums(proc{|ds| ds})
78
95
  @db.sqls.should == ["SELECT * FROM albums WHERE (albums.artist_id = 1)"]
96
+ @Artist.load(:id=>1).album(proc{|ds| ds})
97
+ @db.sqls.should == ["SELECT * FROM albums WHERE (albums.artist_id = 1) LIMIT 1"]
79
98
  end
80
99
 
81
100
  specify "should run a regular query if :prepared_statement=>false option is used for the association" do
@@ -2,14 +2,18 @@ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
2
 
3
3
  describe Sequel::Model, "rcte_tree" do
4
4
  before do
5
- @c = Class.new(Sequel::Model(DB[:nodes]))
5
+ @db = Sequel.mock
6
+ @db.extend_datasets do
7
+ def supports_cte?(*) true end
8
+ end
9
+ @c = Class.new(Sequel::Model(@db[:nodes]))
6
10
  @c.class_eval do
7
11
  def self.name; 'Node'; end
8
12
  columns :id, :name, :parent_id, :i, :pi
9
13
  end
10
14
  @ds = @c.dataset
11
15
  @o = @c.load(:id=>2, :parent_id=>1, :name=>'AA', :i=>3, :pi=>4)
12
- DB.reset
16
+ @db.sqls
13
17
  end
14
18
 
15
19
  it "should define the correct associations" do
@@ -44,11 +48,11 @@ describe Sequel::Model, "rcte_tree" do
44
48
  @c.plugin :rcte_tree
45
49
  @ds._fetch = [[{:id=>1, :name=>'A', :parent_id=>3}]]
46
50
  @c.eager(:ancestors).all
47
- DB.sqls.should == ["SELECT * FROM nodes", "WITH t(x_root_x, id, name, parent_id, i, pi) AS (SELECT id AS x_root_x, nodes.id, nodes.name, nodes.parent_id, nodes.i, nodes.pi FROM nodes WHERE (id IN (3)) UNION ALL SELECT t.x_root_x, nodes.id, nodes.name, nodes.parent_id, nodes.i, nodes.pi FROM nodes INNER JOIN t ON (t.parent_id = nodes.id)) SELECT * FROM t AS nodes"]
51
+ @db.sqls.should == ["SELECT * FROM nodes", "WITH t(x_root_x, id, name, parent_id, i, pi) AS (SELECT id AS x_root_x, nodes.id, nodes.name, nodes.parent_id, nodes.i, nodes.pi FROM nodes WHERE (id IN (3)) UNION ALL SELECT t.x_root_x, nodes.id, nodes.name, nodes.parent_id, nodes.i, nodes.pi FROM nodes INNER JOIN t ON (t.parent_id = nodes.id)) SELECT * FROM t AS nodes"]
48
52
 
49
53
  @ds._fetch = [[{:id=>1, :name=>'A', :parent_id=>3}]]
50
54
  @c.eager(:descendants).all
51
- DB.sqls.should == ["SELECT * FROM nodes", "WITH t(x_root_x, id, name, parent_id, i, pi) AS (SELECT parent_id AS x_root_x, nodes.id, nodes.name, nodes.parent_id, nodes.i, nodes.pi FROM nodes WHERE (parent_id IN (1)) UNION ALL SELECT t.x_root_x, nodes.id, nodes.name, nodes.parent_id, nodes.i, nodes.pi FROM nodes INNER JOIN t ON (t.id = nodes.parent_id)) SELECT * FROM t AS nodes"]
55
+ @db.sqls.should == ["SELECT * FROM nodes", "WITH t(x_root_x, id, name, parent_id, i, pi) AS (SELECT parent_id AS x_root_x, nodes.id, nodes.name, nodes.parent_id, nodes.i, nodes.pi FROM nodes WHERE (parent_id IN (1)) UNION ALL SELECT t.x_root_x, nodes.id, nodes.name, nodes.parent_id, nodes.i, nodes.pi FROM nodes INNER JOIN t ON (t.id = nodes.parent_id)) SELECT * FROM t AS nodes"]
52
56
  end
53
57
 
54
58
  it "should use the correct SQL for lazy associations when giving options" do
@@ -114,7 +118,7 @@ describe Sequel::Model, "rcte_tree" do
114
118
  {:id=>1, :name=>'00', :parent_id=>8, :x_root_x=>1}, {:id=>1, :name=>'00', :parent_id=>8, :x_root_x=>2},
115
119
  {:id=>8, :name=>'?', :parent_id=>nil, :x_root_x=>2}, {:id=>8, :name=>'?', :parent_id=>nil, :x_root_x=>1}]]
116
120
  os = @ds.eager(:ancestors).all
117
- sqls = DB.sqls
121
+ sqls = @db.sqls
118
122
  sqls.first.should == "SELECT * FROM nodes"
119
123
  sqls.last.should =~ /WITH t AS \(SELECT id AS x_root_x, nodes\.\* FROM nodes WHERE \(id IN \([12], [12]\)\) UNION ALL SELECT t\.x_root_x, nodes\.\* FROM nodes INNER JOIN t ON \(t\.parent_id = nodes\.id\)\) SELECT \* FROM t AS nodes/
120
124
  os.should == [@c.load(:id=>2, :parent_id=>1, :name=>'AA'), @c.load(:id=>6, :parent_id=>2, :name=>'C'), @c.load(:id=>7, :parent_id=>1, :name=>'D'), @c.load(:id=>9, :parent_id=>nil, :name=>'E')]
@@ -126,7 +130,7 @@ describe Sequel::Model, "rcte_tree" do
126
130
  os.map{|o| o.parent.parent if o.parent}.should == [@c.load(:id=>8, :name=>'?', :parent_id=>nil), @c.load(:id=>1, :name=>'00', :parent_id=>8), @c.load(:id=>8, :name=>'?', :parent_id=>nil), nil]
127
131
  os.map{|o| o.parent.parent.parent if o.parent and o.parent.parent}.should == [nil, @c.load(:id=>8, :name=>'?', :parent_id=>nil), nil, nil]
128
132
  os.map{|o| o.parent.parent.parent.parent if o.parent and o.parent.parent and o.parent.parent.parent}.should == [nil, nil, nil, nil]
129
- DB.sqls.should == []
133
+ @db.sqls.should == []
130
134
  end
131
135
 
132
136
  it "should eagerly load ancestors when giving options" do
@@ -136,7 +140,7 @@ describe Sequel::Model, "rcte_tree" do
136
140
  {:i=>1, :name=>'00', :pi=>8, :kal=>1}, {:i=>1, :name=>'00', :pi=>8, :kal=>2},
137
141
  {:i=>8, :name=>'?', :pi=>nil, :kal=>2}, {:i=>8, :name=>'?', :pi=>nil, :kal=>1}]]
138
142
  os = @ds.eager(:as).all
139
- sqls = DB.sqls
143
+ sqls = @db.sqls
140
144
  sqls.first.should == "SELECT * FROM nodes"
141
145
  sqls.last.should =~ /WITH cte AS \(SELECT i AS kal, nodes\.\* FROM nodes WHERE \(i IN \([12], [12]\)\) UNION ALL SELECT cte\.kal, nodes\.\* FROM nodes INNER JOIN cte ON \(cte\.pi = nodes\.i\)\) SELECT \* FROM cte/
142
146
  os.should == [@c.load(:i=>2, :pi=>1, :name=>'AA'), @c.load(:i=>6, :pi=>2, :name=>'C'), @c.load(:i=>7, :pi=>1, :name=>'D'), @c.load(:i=>9, :pi=>nil, :name=>'E')]
@@ -157,7 +161,7 @@ describe Sequel::Model, "rcte_tree" do
157
161
  {:id=>1, :name=>'00', :parent_id=>8, :x_root_x=>1}, {:id=>1, :name=>'00', :parent_id=>8, :x_root_x=>2},
158
162
  {:id=>8, :name=>'?', :parent_id=>nil, :x_root_x=>2}, {:id=>8, :name=>'?', :parent_id=>nil, :x_root_x=>1}]]
159
163
  @ds.eager(:ancestors).all
160
- sqls = DB.sqls
164
+ sqls = @db.sqls
161
165
  sqls.first.should == "SELECT * FROM nodes"
162
166
  sqls.last.should =~ /WITH t AS \(SELECT id AS x_root_x, nodes\.\* FROM nodes WHERE \(\(id IN \([12], [12]\)\) AND \(i = 1\)\) UNION ALL SELECT t\.x_root_x, nodes\.\* FROM nodes INNER JOIN t ON \(t\.parent_id = nodes\.id\) WHERE \(i = 1\)\) SELECT \* FROM t AS nodes WHERE \(i = 1\)/
163
167
  end
@@ -169,7 +173,7 @@ describe Sequel::Model, "rcte_tree" do
169
173
  {:id=>3, :name=>'00', :parent_id=>6, :x_root_x=>6}, {:id=>3, :name=>'00', :parent_id=>6, :x_root_x=>2},
170
174
  {:id=>4, :name=>'?', :parent_id=>7, :x_root_x=>7}, {:id=>5, :name=>'?', :parent_id=>4, :x_root_x=>7}]]
171
175
  os = @ds.eager(:descendants).all
172
- sqls = DB.sqls
176
+ sqls = @db.sqls
173
177
  sqls.first.should == "SELECT * FROM nodes"
174
178
  sqls.last.should =~ /WITH t AS \(SELECT parent_id AS x_root_x, nodes\.\* FROM nodes WHERE \(parent_id IN \([267], [267], [267]\)\) UNION ALL SELECT t\.x_root_x, nodes\.\* FROM nodes INNER JOIN t ON \(t\.id = nodes\.parent_id\)\) SELECT \* FROM t AS nodes/
175
179
  os.should == [@c.load(:id=>2, :parent_id=>1, :name=>'AA'), @c.load(:id=>6, :parent_id=>2, :name=>'C'), @c.load(:id=>7, :parent_id=>1, :name=>'D')]
@@ -179,7 +183,7 @@ describe Sequel::Model, "rcte_tree" do
179
183
  os.map{|o| o.children}.should == [[@c.load(:id=>6, :parent_id=>2, :name=>'C'), @c.load(:id=>9, :parent_id=>2, :name=>'E')], [@c.load(:id=>3, :name=>'00', :parent_id=>6)], [@c.load(:id=>4, :name=>'?', :parent_id=>7)]]
180
184
  os.map{|o1| o1.children.map{|o2| o2.children}}.should == [[[@c.load(:id=>3, :name=>'00', :parent_id=>6)], []], [[]], [[@c.load(:id=>5, :name=>'?', :parent_id=>4)]]]
181
185
  os.map{|o1| o1.children.map{|o2| o2.children.map{|o3| o3.children}}}.should == [[[[]], []], [[]], [[[]]]]
182
- DB.sqls.should == []
186
+ @db.sqls.should == []
183
187
  end
184
188
 
185
189
  it "should eagerly load descendants when giving options" do
@@ -189,7 +193,7 @@ describe Sequel::Model, "rcte_tree" do
189
193
  {:i=>3, :name=>'00', :pi=>6, :kal=>6}, {:i=>3, :name=>'00', :pi=>6, :kal=>2},
190
194
  {:i=>4, :name=>'?', :pi=>7, :kal=>7}, {:i=>5, :name=>'?', :pi=>4, :kal=>7}]]
191
195
  os = @ds.eager(:ds).all
192
- sqls = DB.sqls
196
+ sqls = @db.sqls
193
197
  sqls.first.should == "SELECT * FROM nodes"
194
198
  sqls.last.should =~ /WITH cte AS \(SELECT pi AS kal, nodes\.\* FROM nodes WHERE \(pi IN \([267], [267], [267]\)\) UNION ALL SELECT cte\.kal, nodes\.\* FROM nodes INNER JOIN cte ON \(cte\.i = nodes\.pi\)\) SELECT \* FROM cte/
195
199
  os.should == [@c.load(:i=>2, :pi=>1, :name=>'AA'), @c.load(:i=>6, :pi=>2, :name=>'C'), @c.load(:i=>7, :pi=>1, :name=>'D')]
@@ -199,7 +203,7 @@ describe Sequel::Model, "rcte_tree" do
199
203
  os.map{|o| o.cs}.should == [[@c.load(:i=>6, :pi=>2, :name=>'C'), @c.load(:i=>9, :pi=>2, :name=>'E')], [@c.load(:i=>3, :name=>'00', :pi=>6)], [@c.load(:i=>4, :name=>'?', :pi=>7)]]
200
204
  os.map{|o1| o1.cs.map{|o2| o2.cs}}.should == [[[@c.load(:i=>3, :name=>'00', :pi=>6)], []], [[]], [[@c.load(:i=>5, :name=>'?', :pi=>4)]]]
201
205
  os.map{|o1| o1.cs.map{|o2| o2.cs.map{|o3| o3.cs}}}.should == [[[[]], []], [[]], [[[]]]]
202
- DB.sqls.should == []
206
+ @db.sqls.should == []
203
207
  end
204
208
 
205
209
  it "should eagerly load descendants to a given level" do
@@ -209,7 +213,7 @@ describe Sequel::Model, "rcte_tree" do
209
213
  {:id=>3, :name=>'00', :parent_id=>6, :x_root_x=>6, :x_level_x=>0}, {:id=>3, :name=>'00', :parent_id=>6, :x_root_x=>2, :x_level_x=>1},
210
214
  {:id=>4, :name=>'?', :parent_id=>7, :x_root_x=>7, :x_level_x=>0}, {:id=>5, :name=>'?', :parent_id=>4, :x_root_x=>7, :x_level_x=>1}]]
211
215
  os = @ds.eager(:descendants=>2).all
212
- sqls = DB.sqls
216
+ sqls = @db.sqls
213
217
  sqls.first.should == "SELECT * FROM nodes"
214
218
  sqls.last.should =~ /WITH t AS \(SELECT parent_id AS x_root_x, nodes\.\*, CAST\(0 AS integer\) AS x_level_x FROM nodes WHERE \(parent_id IN \([267], [267], [267]\)\) UNION ALL SELECT t\.x_root_x, nodes\.\*, \(t\.x_level_x \+ 1\) AS x_level_x FROM nodes INNER JOIN t ON \(t\.id = nodes\.parent_id\) WHERE \(t\.x_level_x < 1\)\) SELECT \* FROM t AS nodes/
215
219
  os.should == [@c.load(:id=>2, :parent_id=>1, :name=>'AA'), @c.load(:id=>6, :parent_id=>2, :name=>'C'), @c.load(:id=>7, :parent_id=>1, :name=>'D')]
@@ -219,7 +223,7 @@ describe Sequel::Model, "rcte_tree" do
219
223
  os.map{|o| o.associations[:children]}.should == [[@c.load(:id=>6, :parent_id=>2, :name=>'C'), @c.load(:id=>9, :parent_id=>2, :name=>'E')], [@c.load(:id=>3, :name=>'00', :parent_id=>6)], [@c.load(:id=>4, :name=>'?', :parent_id=>7)]]
220
224
  os.map{|o1| o1.associations[:children].map{|o2| o2.associations[:children]}}.should == [[[@c.load(:id=>3, :name=>'00', :parent_id=>6)], []], [[]], [[@c.load(:id=>5, :name=>'?', :parent_id=>4)]]]
221
225
  os.map{|o1| o1.associations[:children].map{|o2| o2.associations[:children].map{|o3| o3.associations[:children]}}}.should == [[[[]], []], [[]], [[nil]]]
222
- DB.sqls.should == []
226
+ @db.sqls.should == []
223
227
  end
224
228
 
225
229
  it "should eagerly load descendants to a given level when giving options" do
@@ -229,7 +233,7 @@ describe Sequel::Model, "rcte_tree" do
229
233
  {:i=>3, :name=>'00', :pi=>6, :kal=>6, :lal=>0}, {:i=>3, :name=>'00', :pi=>6, :kal=>2, :lal=>1},
230
234
  {:i=>4, :name=>'?', :pi=>7, :kal=>7, :lal=>0}, {:i=>5, :name=>'?', :pi=>4, :kal=>7, :lal=>1}]]
231
235
  os = @ds.eager(:ds=>2).all
232
- sqls = DB.sqls
236
+ sqls = @db.sqls
233
237
  sqls.first.should == "SELECT * FROM nodes"
234
238
  sqls.last.should =~ /WITH cte AS \(SELECT pi AS kal, nodes\.\*, CAST\(0 AS integer\) AS lal FROM nodes WHERE \(pi IN \([267], [267], [267]\)\) UNION ALL SELECT cte\.kal, nodes\.\*, \(cte\.lal \+ 1\) AS lal FROM nodes INNER JOIN cte ON \(cte\.i = nodes\.pi\) WHERE \(cte\.lal < 1\)\) SELECT \* FROM cte/
235
239
  os.should == [@c.load(:i=>2, :pi=>1, :name=>'AA'), @c.load(:i=>6, :pi=>2, :name=>'C'), @c.load(:i=>7, :pi=>1, :name=>'D')]
@@ -239,7 +243,7 @@ describe Sequel::Model, "rcte_tree" do
239
243
  os.map{|o| o.associations[:cs]}.should == [[@c.load(:i=>6, :pi=>2, :name=>'C'), @c.load(:i=>9, :pi=>2, :name=>'E')], [@c.load(:i=>3, :name=>'00', :pi=>6)], [@c.load(:i=>4, :name=>'?', :pi=>7)]]
240
244
  os.map{|o1| o1.associations[:cs].map{|o2| o2.associations[:cs]}}.should == [[[@c.load(:i=>3, :name=>'00', :pi=>6)], []], [[]], [[@c.load(:i=>5, :name=>'?', :pi=>4)]]]
241
245
  os.map{|o1| o1.associations[:cs].map{|o2| o2.associations[:cs].map{|o3| o3.associations[:cs]}}}.should == [[[[]], []], [[]], [[nil]]]
242
- DB.sqls.should == []
246
+ @db.sqls.should == []
243
247
  end
244
248
 
245
249
  it "should eagerly load descendants respecting association option :conditions" do
@@ -249,7 +253,7 @@ describe Sequel::Model, "rcte_tree" do
249
253
  {:id=>3, :name=>'00', :parent_id=>6, :x_root_x=>6}, {:id=>3, :name=>'00', :parent_id=>6, :x_root_x=>2},
250
254
  {:id=>4, :name=>'?', :parent_id=>7, :x_root_x=>7}, {:id=>5, :name=>'?', :parent_id=>4, :x_root_x=>7}]]
251
255
  @ds.eager(:descendants).all
252
- sqls = DB.sqls
256
+ sqls = @db.sqls
253
257
  sqls.first.should == "SELECT * FROM nodes"
254
258
  sqls.last.should =~ /WITH t AS \(SELECT parent_id AS x_root_x, nodes\.\* FROM nodes WHERE \(\(parent_id IN \([267], [267], [267]\)\) AND \(i = 1\)\) UNION ALL SELECT t\.x_root_x, nodes\.\* FROM nodes INNER JOIN t ON \(t\.id = nodes\.parent_id\) WHERE \(i = 1\)\) SELECT \* FROM t AS nodes WHERE \(i = 1\)/
255
259
  end
@@ -257,7 +261,11 @@ end
257
261
 
258
262
  describe Sequel::Model, "rcte_tree with composite keys" do
259
263
  before do
260
- @c = Class.new(Sequel::Model(DB[:nodes]))
264
+ @db = Sequel.mock
265
+ @db.extend_datasets do
266
+ def supports_cte?(*) true end
267
+ end
268
+ @c = Class.new(Sequel::Model(@db[:nodes]))
261
269
  @c.class_eval do
262
270
  def self.name; 'Node'; end
263
271
  columns :id, :id2, :name, :parent_id, :parent_id2, :i, :pi
@@ -265,7 +273,7 @@ describe Sequel::Model, "rcte_tree with composite keys" do
265
273
  end
266
274
  @ds = @c.dataset
267
275
  @o = @c.load(:id=>2, :id2=>5, :parent_id=>1, :parent_id2=>6, :name=>'AA', :i=>3, :pi=>4)
268
- DB.reset
276
+ @db.sqls
269
277
  end
270
278
 
271
279
  it "should use the correct SQL for lazy associations" do
@@ -288,11 +296,11 @@ describe Sequel::Model, "rcte_tree with composite keys" do
288
296
  @c.plugin :rcte_tree, :key=>[:parent_id, :parent_id2]
289
297
  @ds._fetch = [[{:id=>1, :id2=>2, :name=>'A', :parent_id=>3, :parent_id2=>4}]]
290
298
  @c.eager(:ancestors).all
291
- DB.sqls.should == ["SELECT * FROM nodes", "WITH t(x_root_x_0, x_root_x_1, id, id2, name, parent_id, parent_id2, i, pi) AS (SELECT id AS x_root_x_0, id2 AS x_root_x_1, nodes.id, nodes.id2, nodes.name, nodes.parent_id, nodes.parent_id2, nodes.i, nodes.pi FROM nodes WHERE ((id, id2) IN ((3, 4))) UNION ALL SELECT t.x_root_x_0, t.x_root_x_1, nodes.id, nodes.id2, nodes.name, nodes.parent_id, nodes.parent_id2, nodes.i, nodes.pi FROM nodes INNER JOIN t ON ((t.parent_id = nodes.id) AND (t.parent_id2 = nodes.id2))) SELECT * FROM t AS nodes"]
299
+ @db.sqls.should == ["SELECT * FROM nodes", "WITH t(x_root_x_0, x_root_x_1, id, id2, name, parent_id, parent_id2, i, pi) AS (SELECT id AS x_root_x_0, id2 AS x_root_x_1, nodes.id, nodes.id2, nodes.name, nodes.parent_id, nodes.parent_id2, nodes.i, nodes.pi FROM nodes WHERE ((id, id2) IN ((3, 4))) UNION ALL SELECT t.x_root_x_0, t.x_root_x_1, nodes.id, nodes.id2, nodes.name, nodes.parent_id, nodes.parent_id2, nodes.i, nodes.pi FROM nodes INNER JOIN t ON ((t.parent_id = nodes.id) AND (t.parent_id2 = nodes.id2))) SELECT * FROM t AS nodes"]
292
300
 
293
301
  @ds._fetch = [[{:id=>1, :id2=>2, :name=>'A', :parent_id=>3, :parent_id2=>4}]]
294
302
  @c.eager(:descendants).all
295
- DB.sqls.should == ["SELECT * FROM nodes", "WITH t(x_root_x_0, x_root_x_1, id, id2, name, parent_id, parent_id2, i, pi) AS (SELECT parent_id AS x_root_x_0, parent_id2 AS x_root_x_1, nodes.id, nodes.id2, nodes.name, nodes.parent_id, nodes.parent_id2, nodes.i, nodes.pi FROM nodes WHERE ((parent_id, parent_id2) IN ((1, 2))) UNION ALL SELECT t.x_root_x_0, t.x_root_x_1, nodes.id, nodes.id2, nodes.name, nodes.parent_id, nodes.parent_id2, nodes.i, nodes.pi FROM nodes INNER JOIN t ON ((t.id = nodes.parent_id) AND (t.id2 = nodes.parent_id2))) SELECT * FROM t AS nodes"]
303
+ @db.sqls.should == ["SELECT * FROM nodes", "WITH t(x_root_x_0, x_root_x_1, id, id2, name, parent_id, parent_id2, i, pi) AS (SELECT parent_id AS x_root_x_0, parent_id2 AS x_root_x_1, nodes.id, nodes.id2, nodes.name, nodes.parent_id, nodes.parent_id2, nodes.i, nodes.pi FROM nodes WHERE ((parent_id, parent_id2) IN ((1, 2))) UNION ALL SELECT t.x_root_x_0, t.x_root_x_1, nodes.id, nodes.id2, nodes.name, nodes.parent_id, nodes.parent_id2, nodes.i, nodes.pi FROM nodes INNER JOIN t ON ((t.id = nodes.parent_id) AND (t.id2 = nodes.parent_id2))) SELECT * FROM t AS nodes"]
296
304
  end
297
305
 
298
306
  it "should add all parent associations when lazily loading ancestors" do
@@ -322,7 +330,7 @@ describe Sequel::Model, "rcte_tree with composite keys" do
322
330
  {:id=>1, :id2=>2, :name=>'00', :parent_id=>8, :parent_id2=>9, :x_root_x_0=>1, :x_root_x_1=>2}, {:id=>1, :id2=>2, :name=>'00', :parent_id=>8, :parent_id2=>9, :x_root_x_0=>2, :x_root_x_1=>3},
323
331
  {:id=>8, :id2=>9, :name=>'?', :parent_id=>nil, :parent_id2=>nil, :x_root_x_0=>2, :x_root_x_1=>3}, {:id=>8, :id2=>9, :name=>'?', :parent_id=>nil, :parent_id2=>nil, :x_root_x_0=>1, :x_root_x_1=>2}]]
324
332
  os = @ds.eager(:ancestors).all
325
- sqls = DB.sqls
333
+ sqls = @db.sqls
326
334
  sqls.first.should == "SELECT * FROM nodes"
327
335
  sqls.last.should =~ /WITH t AS \(SELECT id AS x_root_x_0, id2 AS x_root_x_1, nodes\.\* FROM nodes WHERE \(\(id, id2\) IN \(\([12], [23]\), \([12], [23]\)\)\) UNION ALL SELECT t\.x_root_x_0, t\.x_root_x_1, nodes\.\* FROM nodes INNER JOIN t ON \(\(t\.parent_id = nodes\.id\) AND \(t\.parent_id2 = nodes\.id2\)\)\) SELECT \* FROM t AS nodes/
328
336
  os.should == [@c.load(:id=>2, :id2=>3, :parent_id=>1, :parent_id2=>2, :name=>'AA'), @c.load(:id=>6, :id2=>7, :parent_id=>2, :parent_id2=>3, :name=>'C'), @c.load(:id=>7, :id2=>8, :parent_id=>1, :parent_id2=>2, :name=>'D'), @c.load(:id=>9, :id2=>10, :parent_id=>nil, :parent_id2=>nil, :name=>'E')]
@@ -334,7 +342,7 @@ describe Sequel::Model, "rcte_tree with composite keys" do
334
342
  os.map{|o| o.parent.parent if o.parent}.should == [@c.load(:id=>8, :id2=>9, :name=>'?', :parent_id=>nil, :parent_id2=>nil), @c.load(:id=>1, :id2=>2, :name=>'00', :parent_id=>8, :parent_id2=>9), @c.load(:id=>8, :id2=>9, :name=>'?', :parent_id=>nil, :parent_id2=>nil), nil]
335
343
  os.map{|o| o.parent.parent.parent if o.parent and o.parent.parent}.should == [nil, @c.load(:id=>8, :id2=>9, :name=>'?', :parent_id=>nil, :parent_id2=>nil), nil, nil]
336
344
  os.map{|o| o.parent.parent.parent.parent if o.parent and o.parent.parent and o.parent.parent.parent}.should == [nil, nil, nil, nil]
337
- DB.sqls.should == []
345
+ @db.sqls.should == []
338
346
  end
339
347
 
340
348
  it "should eagerly load descendants" do
@@ -344,7 +352,7 @@ describe Sequel::Model, "rcte_tree with composite keys" do
344
352
  {:id=>3, :id2=>4, :name=>'00', :parent_id=>6, :parent_id2=>7, :x_root_x_0=>6, :x_root_x_1=>7}, {:id=>3, :id2=>4, :name=>'00', :parent_id=>6, :parent_id2=>7, :x_root_x_0=>2, :x_root_x_1=>3},
345
353
  {:id=>4, :id2=>5, :name=>'?', :parent_id=>7, :parent_id2=>8, :x_root_x_0=>7, :x_root_x_1=>8}, {:id=>5, :id2=>6, :name=>'?', :parent_id=>4, :parent_id2=>5, :x_root_x_0=>7, :x_root_x_1=>8}]]
346
354
  os = @ds.eager(:descendants).all
347
- sqls = DB.sqls
355
+ sqls = @db.sqls
348
356
  sqls.first.should == "SELECT * FROM nodes"
349
357
  sqls.last.should =~ /WITH t AS \(SELECT parent_id AS x_root_x_0, parent_id2 AS x_root_x_1, nodes\.\* FROM nodes WHERE \(\(parent_id, parent_id2\) IN \(\([267], [378]\), \([267], [378]\), \([267], [378]\)\)\) UNION ALL SELECT t\.x_root_x_0, t\.x_root_x_1, nodes\.\* FROM nodes INNER JOIN t ON \(\(t\.id = nodes\.parent_id\) AND \(t\.id2 = nodes\.parent_id2\)\)\) SELECT \* FROM t AS nodes/
350
358
  os.should == [@c.load(:id=>2, :id2=>3, :parent_id=>1, :parent_id2=>2, :name=>'AA'), @c.load(:id=>6, :id2=>7, :parent_id=>2, :parent_id2=>3, :name=>'C'), @c.load(:id=>7, :id2=>8, :parent_id=>1, :parent_id2=>2, :name=>'D')]
@@ -354,7 +362,7 @@ describe Sequel::Model, "rcte_tree with composite keys" do
354
362
  os.map{|o| o.children}.should == [[@c.load(:id=>6, :id2=>7, :parent_id=>2, :parent_id2=>3, :name=>'C'), @c.load(:id=>9, :id2=>10, :parent_id=>2, :parent_id2=>3, :name=>'E')], [@c.load(:id=>3, :id2=>4, :name=>'00', :parent_id=>6, :parent_id2=>7)], [@c.load(:id=>4, :id2=>5, :name=>'?', :parent_id=>7, :parent_id2=>8)]]
355
363
  os.map{|o1| o1.children.map{|o2| o2.children}}.should == [[[@c.load(:id=>3, :id2=>4, :name=>'00', :parent_id=>6, :parent_id2=>7)], []], [[]], [[@c.load(:id=>5, :id2=>6, :name=>'?', :parent_id=>4, :parent_id2=>5)]]]
356
364
  os.map{|o1| o1.children.map{|o2| o2.children.map{|o3| o3.children}}}.should == [[[[]], []], [[]], [[[]]]]
357
- DB.sqls.should == []
365
+ @db.sqls.should == []
358
366
  end
359
367
 
360
368
  it "should eagerly load descendants to a given level" do
@@ -364,7 +372,7 @@ describe Sequel::Model, "rcte_tree with composite keys" do
364
372
  {:id=>3, :id2=>4, :name=>'00', :parent_id=>6, :parent_id2=>7, :x_root_x_0=>6, :x_root_x_1=>7, :x_level_x=>0}, {:id=>3, :id2=>4, :name=>'00', :parent_id=>6, :parent_id2=>7, :x_root_x_0=>2, :x_root_x_1=>3, :x_level_x=>1},
365
373
  {:id=>4, :id2=>5, :name=>'?', :parent_id=>7, :parent_id2=>8, :x_root_x_0=>7, :x_root_x_1=>8, :x_level_x=>0}, {:id=>5, :id2=>6, :name=>'?', :parent_id=>4, :parent_id2=>5, :x_root_x_0=>7, :x_root_x_1=>8, :x_level_x=>1}]]
366
374
  os = @ds.eager(:descendants=>2).all
367
- sqls = DB.sqls
375
+ sqls = @db.sqls
368
376
  sqls.first.should == "SELECT * FROM nodes"
369
377
  sqls.last.should =~ /WITH t AS \(SELECT parent_id AS x_root_x_0, parent_id2 AS x_root_x_1, nodes\.\*, CAST\(0 AS integer\) AS x_level_x FROM nodes WHERE \(\(parent_id, parent_id2\) IN \(\([267], [378]\), \([267], [378]\), \([267], [378]\)\)\) UNION ALL SELECT t\.x_root_x_0, t\.x_root_x_1, nodes\.\*, \(t\.x_level_x \+ 1\) AS x_level_x FROM nodes INNER JOIN t ON \(\(t\.id = nodes\.parent_id\) AND \(t\.id2 = nodes\.parent_id2\)\) WHERE \(t\.x_level_x < 1\)\) SELECT \* FROM t AS nodes/
370
378
  os.should == [@c.load(:id=>2, :id2=>3, :parent_id=>1, :parent_id=>2, :name=>'AA'), @c.load(:id=>6, :id2=>7, :parent_id=>2, :parent_id2=>3, :name=>'C'), @c.load(:id=>7, :id2=>8, :parent_id=>1, :parent_id2=>2, :name=>'D')]
@@ -374,6 +382,6 @@ describe Sequel::Model, "rcte_tree with composite keys" do
374
382
  os.map{|o| o.associations[:children]}.should == [[@c.load(:id=>6, :id2=>7, :parent_id=>2, :parent_id2=>3, :name=>'C'), @c.load(:id=>9, :id2=>10, :parent_id=>2, :parent_id2=>3, :name=>'E')], [@c.load(:id=>3, :id2=>4, :name=>'00', :parent_id=>6, :parent_id2=>7)], [@c.load(:id=>4, :id2=>5, :name=>'?', :parent_id=>7, :parent_id2=>8)]]
375
383
  os.map{|o1| o1.associations[:children].map{|o2| o2.associations[:children]}}.should == [[[@c.load(:id=>3, :id2=>4, :name=>'00', :parent_id=>6, :parent_id2=>7)], []], [[]], [[@c.load(:id=>5, :id2=>6, :name=>'?', :parent_id=>4, :parent_id2=>5)]]]
376
384
  os.map{|o1| o1.associations[:children].map{|o2| o2.associations[:children].map{|o3| o3.associations[:children]}}}.should == [[[[]], []], [[]], [[nil]]]
377
- DB.sqls.should == []
385
+ @db.sqls.should == []
378
386
  end
379
387
  end
@@ -71,7 +71,6 @@ describe "Dataset#opts=" do
71
71
  specify "should change the dataset's opts" do
72
72
  db = Sequel.mock
73
73
  ds = db[:items].extension(:sequel_3_dataset_methods)
74
- db2 = Sequel.mock
75
74
  ds.sql.should == 'SELECT * FROM items'
76
75
  ds.opts = {}
77
76
  ds.sql.should == 'SELECT *'
@@ -113,7 +113,7 @@ describe "sharding plugin" do
113
113
  album.artist.update(:name=>'AS')
114
114
  @db.sqls.should == ["SELECT * FROM artists WHERE (artists.id = 2) LIMIT 1 -- s1", "UPDATE artists SET name = 'AS' WHERE (id = 2) -- s1"]
115
115
  album.tags.map{|a| a.update(:name=>'SR')}
116
- @db.sqls.should == ["SELECT tags.* FROM tags INNER JOIN albums_tags ON ((albums_tags.tag_id = tags.id) AND (albums_tags.album_id = 1)) -- s1", "UPDATE tags SET name = 'SR' WHERE (id = 3) -- s1"]
116
+ @db.sqls.should == ["SELECT tags.* FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) WHERE (albums_tags.album_id = 1) -- s1", "UPDATE tags SET name = 'SR' WHERE (id = 3) -- s1"]
117
117
  @Artist.server(:s2).first.albums.map{|a| a.update(:name=>'MO')}
118
118
  @db.sqls.should == ["SELECT * FROM artists LIMIT 1 -- s2", "SELECT * FROM albums WHERE (albums.artist_id = 2) -- s2", "UPDATE albums SET name = 'MO' WHERE (id = 1) -- s2"]
119
119
  end
@@ -145,7 +145,7 @@ describe "sharding plugin" do
145
145
  sqls.should == ["SELECT * FROM albums WHERE ((albums.artist_id = 2) AND (albums.id = 1)) LIMIT 1 -- s2"]
146
146
 
147
147
  album.remove_tag(3)
148
- @db.sqls.should == ["SELECT tags.* FROM tags INNER JOIN albums_tags ON ((albums_tags.tag_id = tags.id) AND (albums_tags.album_id = 1)) WHERE (tags.id = 3) LIMIT 1 -- s1", "DELETE FROM albums_tags WHERE ((album_id = 1) AND (tag_id = 3)) -- s1"]
148
+ @db.sqls.should == ["SELECT tags.* FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) WHERE ((albums_tags.album_id = 1) AND (tags.id = 3)) LIMIT 1 -- s1", "DELETE FROM albums_tags WHERE ((album_id = 1) AND (tag_id = 3)) -- s1"]
149
149
  end
150
150
 
151
151
  specify "should have objects retrieved from a specific shard remove all associated objects from that shard" do
@@ -75,4 +75,8 @@ describe "Sequel::Plugins::TacticalEagerLoading" do
75
75
  ts.map{|x| x.children}.should == [[], [], [ts[0]], [ts[1]]]
76
76
  DB.sqls.length.should == 1
77
77
  end
78
+
79
+ it "#marshallable should make marshalling not fail" do
80
+ proc{Marshal.dump(@c.all.map{|x| x.marshallable!})}.should_not raise_error
81
+ end
78
82
  end
@@ -25,6 +25,7 @@ END
25
25
  end
26
26
 
27
27
  it "should handle WITH" do
28
+ def @ds.supports_cte?(*) true end
28
29
  a = dot(@ds.with(:a, @ds))
29
30
  a[0..3].should == ["1 -> 2 [label=\"with\"];", "2 [label=\"Array\"];", "2 -> 3 [label=\"0\"];", "3 [label=\"Hash\"];"]
30
31
  [["3 -> 4 [label=\"dataset\"];", "4 [label=\"Dataset\"];", "3 -> 5 [label=\"name\"];", "5 [label=\":a\"];"],
@@ -139,7 +139,7 @@ describe "Touch plugin" do
139
139
  @Artist.plugin :touch, :associations=>:albums
140
140
  @a.touch
141
141
  DB.sqls.should == ["UPDATE artists SET updated_at = CURRENT_TIMESTAMP WHERE (id = 1)",
142
- "SELECT albums.* FROM albums INNER JOIN aa ON ((aa.album_id = albums.id) AND (aa.artist_id = 1))",
142
+ "SELECT albums.* FROM albums INNER JOIN aa ON (aa.album_id = albums.id) WHERE (aa.artist_id = 1)",
143
143
  "UPDATE albums SET updated_at = CURRENT_TIMESTAMP WHERE (id = 1)"]
144
144
  end
145
145
 
@@ -149,7 +149,7 @@ describe "Touch plugin" do
149
149
  @Artist.plugin :touch, :associations=>:albums
150
150
  @a.touch
151
151
  DB.sqls.should == ["UPDATE artists SET updated_at = CURRENT_TIMESTAMP WHERE (id = 1)",
152
- "SELECT albums.* FROM albums INNER JOIN aa ON ((aa.album_id = albums.id) AND (aa.artist_id = 1))",
152
+ "SELECT albums.* FROM albums INNER JOIN aa ON (aa.album_id = albums.id) WHERE (aa.artist_id = 1)",
153
153
  "UPDATE albums SET updated_at = CURRENT_TIMESTAMP WHERE (id = 1)"]
154
154
  end
155
155
 
@@ -4,7 +4,7 @@ shared_examples_for "one_to_one eager limit strategies" do
4
4
  specify "eager loading one_to_one associations should work correctly" do
5
5
  Artist.one_to_one :first_album, {:clone=>:first_album}.merge(@els) if @els
6
6
  Artist.one_to_one :last_album, {:clone=>:last_album}.merge(@els) if @els
7
- Artist.one_to_one :second_album, {:clone=>:second_album}.merge(@els) if @els
7
+ Artist.one_to_one :second_album, {:clone=>:second_album}.merge(@els) if @els && @els[:eager_limit_strategy] != :distinct_on
8
8
  @album.update(:artist => @artist)
9
9
  diff_album = @diff_album.call
10
10
  ar = @pr.call[1]
@@ -29,7 +29,9 @@ shared_examples_for "one_to_one eager limit strategies" do
29
29
  [@album, same_album].should include(a.first.first_album)
30
30
  a.last.first_album.should == nil
31
31
  end
32
+ end
32
33
 
34
+ shared_examples_for "one_to_one eager_graph limit strategies" do
33
35
  specify "eager graphing one_to_one associations should work correctly" do
34
36
  @album.update(:artist => @artist)
35
37
  diff_album = @diff_album.call
@@ -50,12 +52,14 @@ shared_examples_for "one_to_one eager limit strategies" do
50
52
  a.last.last_album.should == nil
51
53
  a.first.last_album.values.should == diff_album.values
52
54
 
53
- a = ds.eager_graph_with_options(:second_album, limit_strategy).all
54
- a = ds.eager_graph(:second_album).all
55
- a.should == [@artist, ar]
56
- a.first.second_album.should == diff_album
57
- a.last.second_album.should == nil
58
- a.first.second_album.values.should == diff_album.values
55
+ if @els[:eager_limit_strategy] != :distinct_on && (@els[:eager_limit_strategy] != :correlated_subquery || Album.dataset.supports_offsets_in_correlated_subqueries?)
56
+ a = ds.eager_graph_with_options(:second_album, limit_strategy).all
57
+ a = ds.eager_graph(:second_album).all
58
+ a.should == [@artist, ar]
59
+ a.first.second_album.should == diff_album
60
+ a.last.second_album.should == nil
61
+ a.first.second_album.values.should == diff_album.values
62
+ end
59
63
 
60
64
  same_album = @same_album.call
61
65
  a = ds.eager_graph_with_options(:first_album, limit_strategy).all
@@ -93,7 +97,9 @@ shared_examples_for "one_to_many eager limit strategies" do
93
97
  ars.first.not_first_albums.map{|x| x.values}.should == [middle_album, diff_album].map{|x| x.values}
94
98
  ars.first.last_two_albums.map{|x| x.values}.should == [diff_album, middle_album].map{|x| x.values}
95
99
  end
100
+ end
96
101
 
102
+ shared_examples_for "one_to_many eager_graph limit strategies" do
97
103
  specify "should correctly handle limits and offsets when eager graphing one_to_many associations" do
98
104
  @album.update(:artist => @artist)
99
105
  middle_album = @middle_album.call
@@ -108,17 +114,19 @@ shared_examples_for "one_to_many eager limit strategies" do
108
114
  ars.last.first_two_albums.should == []
109
115
  ars.first.first_two_albums.map{|x| x.values}.should == [@album, middle_album].map{|x| x.values}
110
116
 
111
- ars = ds.eager_graph_with_options(:second_two_albums, limit_strategy).all
112
- ars.should == [@artist, ar]
113
- ars.first.second_two_albums.should == [middle_album, diff_album]
114
- ars.last.second_two_albums.should == []
115
- ars.first.second_two_albums.map{|x| x.values}.should == [middle_album, diff_album].map{|x| x.values}
117
+ if @els[:eager_limit_strategy] != :correlated_subquery || Album.dataset.supports_offsets_in_correlated_subqueries?
118
+ ars = ds.eager_graph_with_options(:second_two_albums, limit_strategy).all
119
+ ars.should == [@artist, ar]
120
+ ars.first.second_two_albums.should == [middle_album, diff_album]
121
+ ars.last.second_two_albums.should == []
122
+ ars.first.second_two_albums.map{|x| x.values}.should == [middle_album, diff_album].map{|x| x.values}
116
123
 
117
- ars = ds.eager_graph_with_options(:not_first_albums, limit_strategy).all
118
- ars.should == [@artist, ar]
119
- ars.first.not_first_albums.should == [middle_album, diff_album]
120
- ars.last.not_first_albums.should == []
121
- ars.first.not_first_albums.map{|x| x.values}.should == [middle_album, diff_album].map{|x| x.values}
124
+ ars = ds.eager_graph_with_options(:not_first_albums, limit_strategy).all
125
+ ars.should == [@artist, ar]
126
+ ars.first.not_first_albums.should == [middle_album, diff_album]
127
+ ars.last.not_first_albums.should == []
128
+ ars.first.not_first_albums.map{|x| x.values}.should == [middle_album, diff_album].map{|x| x.values}
129
+ end
122
130
 
123
131
  ars = ds.eager_graph_with_options(:last_two_albums, limit_strategy).all
124
132
  ars.should == [@artist, ar]
@@ -131,7 +139,7 @@ end
131
139
  shared_examples_for "one_through_one eager limit strategies" do
132
140
  specify "should correctly handle offsets when eager loading one_through_one associations" do
133
141
  Album.one_through_one :first_tag, {:clone=>:first_tag}.merge(@els) if @els
134
- Album.one_through_one :second_tag, {:clone=>:second_tag}.merge(@els) if @els
142
+ Album.one_through_one :second_tag, {:clone=>:second_tag}.merge(@els) if @els && @els[:eager_limit_strategy] != :distinct_on
135
143
  Album.one_through_one :last_tag, {:clone=>:last_tag}.merge(@els) if @els
136
144
  tu, tv = @other_tags.call
137
145
  al = @pr.call.first
@@ -150,7 +158,9 @@ shared_examples_for "one_through_one eager limit strategies" do
150
158
  als.first.second_tag.values.should == tu.values
151
159
  als.first.last_tag.values.should == tv.values
152
160
  end
161
+ end
153
162
 
163
+ shared_examples_for "one_through_one eager_graph limit strategies" do
154
164
  specify "should correctly handle offsets when eager graphing one_through_one associations" do
155
165
  tu, tv = @other_tags.call
156
166
  al = @pr.call.first
@@ -163,7 +173,7 @@ shared_examples_for "one_through_one eager limit strategies" do
163
173
  als.last.first_tag.should == nil
164
174
  als.first.first_tag.values.should == @tag.values
165
175
 
166
- als = ds.eager_graph_with_options(:second_tag, limit_strategy).all
176
+ als = ds.eager_graph_with_options(:second_tag, @els[:eager_limit_strategy] != :distinct_on ? limit_strategy : {}).all
167
177
  als.should == [@album, al]
168
178
  als.first.second_tag.should == tu
169
179
  als.last.second_tag.should == nil
@@ -203,7 +213,9 @@ shared_examples_for "many_to_many eager limit strategies" do
203
213
  als.first.not_first_tags.map{|x| x.values}.should == [tu, tv].map{|x| x.values}
204
214
  als.first.last_two_tags.map{|x| x.values}.should == [tv, tu].map{|x| x.values}
205
215
  end
216
+ end
206
217
 
218
+ shared_examples_for "many_to_many eager_graph limit strategies" do
207
219
  specify "should correctly handle limits and offsets when eager loading many_to_many associations" do
208
220
  tu, tv = @other_tags.call
209
221
  al = @pr.call.first
@@ -266,7 +278,9 @@ shared_examples_for "many_through_many eager limit strategies" do
266
278
  ars.first.not_first_tags.map{|x| x.values}.should == [tu, tv].map{|x| x.values}
267
279
  ars.first.last_two_tags.map{|x| x.values}.should == [tv, tu].map{|x| x.values}
268
280
  end
281
+ end
269
282
 
283
+ shared_examples_for "many_through_many eager_graph limit strategies" do
270
284
  specify "should correctly handle limits and offsets when eager loading many_through_many associations" do
271
285
  @album.update(:artist => @artist)
272
286
  tu, tv = @other_tags.call
@@ -305,7 +319,7 @@ end
305
319
  shared_examples_for "one_through_many eager limit strategies" do
306
320
  specify "should correctly handle offsets when eager loading one_through_many associations" do
307
321
  Artist.one_through_many :first_tag, {:clone=>:first_tag}.merge(@els) if @els
308
- Artist.one_through_many :second_tag, {:clone=>:second_tag}.merge(@els) if @els
322
+ Artist.one_through_many :second_tag, {:clone=>:second_tag}.merge(@els) if @els && @els[:eager_limit_strategy] != :distinct_on
309
323
  Artist.one_through_many :last_tag, {:clone=>:last_tag}.merge(@els) if @els
310
324
  @album.update(:artist => @artist)
311
325
  tu, tv = @other_tags.call
@@ -327,7 +341,9 @@ shared_examples_for "one_through_many eager limit strategies" do
327
341
  ars.first.second_tag.values.should == tu.values
328
342
  ars.first.last_tag.values.should == tv.values
329
343
  end
344
+ end
330
345
 
346
+ shared_examples_for "one_through_many eager_graph limit strategies" do
331
347
  specify "should correctly handle offsets when eager graphing one_through_many associations" do
332
348
  @album.update(:artist => @artist)
333
349
  tu, tv = @other_tags.call
@@ -343,7 +359,7 @@ shared_examples_for "one_through_many eager limit strategies" do
343
359
  ars.last.first_tag.should == tu
344
360
  ars.first.first_tag.values.should == @tag.values
345
361
 
346
- ars = ds.eager_graph_with_options(:second_tag, limit_strategy).all
362
+ ars = ds.eager_graph_with_options(:second_tag, @els[:eager_limit_strategy] != :distinct_on ? limit_strategy : {}).all
347
363
  ars.should == [@artist, ar]
348
364
  ars.first.second_tag.should == tu
349
365
  ars.last.second_tag.should == nil
@@ -366,6 +382,15 @@ shared_examples_for "eager limit strategies" do
366
382
  it_should_behave_like "one_through_many eager limit strategies"
367
383
  end
368
384
 
385
+ shared_examples_for "eager_graph limit strategies" do
386
+ it_should_behave_like "one_to_one eager_graph limit strategies"
387
+ it_should_behave_like "one_to_many eager_graph limit strategies"
388
+ it_should_behave_like "many_to_many eager_graph limit strategies"
389
+ it_should_behave_like "one_through_one eager_graph limit strategies"
390
+ it_should_behave_like "many_through_many eager_graph limit strategies"
391
+ it_should_behave_like "one_through_many eager_graph limit strategies"
392
+ end
393
+
369
394
  shared_examples_for "filtering/excluding by associations" do
370
395
  specify "should handle association inner joins" do
371
396
  @Artist.association_join(:albums).all.should == []
@@ -1008,7 +1033,7 @@ shared_examples_for "filtering/excluding by associations" do
1008
1033
  end
1009
1034
  end
1010
1035
 
1011
- shared_examples_for "filter by associations singular association limit strategies" do
1036
+ shared_examples_for "filter by associations one_to_one limit strategies" do
1012
1037
  specify "filter by associations with limited one_to_one associations should work correctly" do
1013
1038
  Artist.one_to_one :first_album, {:clone=>:first_album}.merge(@els)
1014
1039
  Artist.one_to_one :last_album, {:clone=>:last_album}.merge(@els)
@@ -1023,10 +1048,12 @@ shared_examples_for "filter by associations singular association limit strategie
1023
1048
  ds.exclude(:first_album=>@album).all.should == [ar]
1024
1049
  ds.exclude(:first_album=>diff_album).all.should == [@artist, ar]
1025
1050
 
1026
- ds.where(:second_album=>@album).all.should == []
1027
- ds.where(:second_album=>diff_album).all.should == [@artist]
1028
- ds.exclude(:second_album=>@album).all.should == [@artist, ar]
1029
- ds.exclude(:second_album=>diff_album).all.should == [ar]
1051
+ if @els[:eager_limit_strategy] != :distinct_on && (@els[:eager_limit_strategy] != :correlated_subquery || Album.dataset.supports_offsets_in_correlated_subqueries?)
1052
+ ds.where(:second_album=>@album).all.should == []
1053
+ ds.where(:second_album=>diff_album).all.should == [@artist]
1054
+ ds.exclude(:second_album=>@album).all.should == [@artist, ar]
1055
+ ds.exclude(:second_album=>diff_album).all.should == [ar]
1056
+ end
1030
1057
 
1031
1058
  ds.where(:last_album=>@album).all.should == []
1032
1059
  ds.where(:last_album=>diff_album).all.should == [@artist]
@@ -1038,11 +1065,15 @@ shared_examples_for "filter by associations singular association limit strategie
1038
1065
  ds.where(:first_album=>[@album, diff_album]).all.should == [ar]
1039
1066
  ds.exclude(:first_album=>[@album, diff_album]).all.should == [@artist]
1040
1067
  end
1068
+ end
1069
+
1070
+ shared_examples_for "filter by associations singular association limit strategies" do
1071
+ it_should_behave_like "filter by associations one_to_one limit strategies"
1041
1072
 
1042
1073
  specify "dataset associations with limited one_to_one associations should work correctly" do
1043
1074
  Artist.one_to_one :first_album, {:clone=>:first_album}.merge(@els)
1044
1075
  Artist.one_to_one :last_album, {:clone=>:last_album}.merge(@els)
1045
- Artist.one_to_one :second_album, {:clone=>:second_album}.merge(@els)
1076
+ Artist.one_to_one :second_album, {:clone=>:second_album}.merge(@els) if @els[:eager_limit_strategy] != :distinct_on
1046
1077
  @album.update(:artist => @artist)
1047
1078
  diff_album = @diff_album.call
1048
1079
  ar = @pr.call[1]
@@ -1063,7 +1094,7 @@ shared_examples_for "filter by associations singular association limit strategie
1063
1094
 
1064
1095
  specify "filter by associations with limited one_through_one associations should work correctly" do
1065
1096
  Album.one_through_one :first_tag, {:clone=>:first_tag}.merge(@els)
1066
- Album.one_through_one :second_tag, {:clone=>:second_tag}.merge(@els)
1097
+ Album.one_through_one :second_tag, {:clone=>:second_tag}.merge(@els) if @els[:eager_limit_strategy] != :distinct_on
1067
1098
  Album.one_through_one :last_tag, {:clone=>:last_tag}.merge(@els)
1068
1099
  tu, tv = @other_tags.call
1069
1100
  al = @pr.call.first
@@ -1104,7 +1135,7 @@ shared_examples_for "filter by associations singular association limit strategie
1104
1135
 
1105
1136
  specify "dataset associations with limited one_through_one associations should work correctly" do
1106
1137
  Album.one_through_one :first_tag, {:clone=>:first_tag}.merge(@els)
1107
- Album.one_through_one :second_tag, {:clone=>:second_tag}.merge(@els)
1138
+ Album.one_through_one :second_tag, {:clone=>:second_tag}.merge(@els) if @els[:eager_limit_strategy] != :distinct_on
1108
1139
  Album.one_through_one :last_tag, {:clone=>:last_tag}.merge(@els)
1109
1140
  tu, tv = @other_tags.call
1110
1141
  al = @pr.call.first
@@ -1135,7 +1166,7 @@ shared_examples_for "filter by associations singular association limit strategie
1135
1166
 
1136
1167
  specify "filter by associations with limited one_through_many associations should work correctly" do
1137
1168
  Artist.one_through_many :first_tag, {:clone=>:first_tag}.merge(@els)
1138
- Artist.one_through_many :second_tag, {:clone=>:second_tag}.merge(@els)
1169
+ Artist.one_through_many :second_tag, {:clone=>:second_tag}.merge(@els) if @els[:eager_limit_strategy] != :distinct_on
1139
1170
  Artist.one_through_many :last_tag, {:clone=>:last_tag}.merge(@els)
1140
1171
  @album.update(:artist => @artist)
1141
1172
  tu, tv = @other_tags.call
@@ -1178,7 +1209,7 @@ shared_examples_for "filter by associations singular association limit strategie
1178
1209
 
1179
1210
  specify "dataset associations with limited one_through_many associations should work correctly" do
1180
1211
  Artist.one_through_many :first_tag, {:clone=>:first_tag}.merge(@els)
1181
- Artist.one_through_many :second_tag, {:clone=>:second_tag}.merge(@els)
1212
+ Artist.one_through_many :second_tag, {:clone=>:second_tag}.merge(@els) if @els[:eager_limit_strategy] != :distinct_on
1182
1213
  Artist.one_through_many :last_tag, {:clone=>:last_tag}.merge(@els)
1183
1214
  @album.update(:artist => @artist)
1184
1215
  tu, tv = @other_tags.call
@@ -1210,9 +1241,7 @@ shared_examples_for "filter by associations singular association limit strategie
1210
1241
  end
1211
1242
  end
1212
1243
 
1213
- shared_examples_for "filter by associations limit strategies" do
1214
- it_should_behave_like "filter by associations singular association limit strategies"
1215
-
1244
+ shared_examples_for "filter by associations one_to_many limit strategies" do
1216
1245
  specify "filter by associations with limited one_to_many associations should work correctly" do
1217
1246
  Artist.one_to_many :first_two_albums, {:clone=>:first_two_albums}.merge(@els)
1218
1247
  Artist.one_to_many :second_two_albums, {:clone=>:second_two_albums}.merge(@els)
@@ -1231,7 +1260,13 @@ shared_examples_for "filter by associations limit strategies" do
1231
1260
  ds.exclude(:first_two_albums=>middle_album).all.should == [ar]
1232
1261
  ds.exclude(:first_two_albums=>diff_album).all.should == [@artist, ar]
1233
1262
 
1234
- [:second_two_albums, :not_first_albums, :last_two_albums].each do |a|
1263
+ assocs = if @els[:eager_limit_strategy] != :correlated_subquery || Album.dataset.supports_offsets_in_correlated_subqueries?
1264
+ [:second_two_albums, :not_first_albums, :last_two_albums]
1265
+ else
1266
+ [:last_two_albums]
1267
+ end
1268
+
1269
+ assocs.each do |a|
1235
1270
  ds.where(a=>@album).all.should == []
1236
1271
  ds.where(a=>middle_album).all.should == [@artist]
1237
1272
  ds.where(a=>diff_album).all.should == [@artist]
@@ -1245,6 +1280,11 @@ shared_examples_for "filter by associations limit strategies" do
1245
1280
  ds.where(:first_two_albums=>[@album, diff_album]).all.should == [ar]
1246
1281
  ds.exclude(:first_two_albums=>[@album, diff_album]).all.should == [@artist]
1247
1282
  end
1283
+ end
1284
+
1285
+ shared_examples_for "filter by associations limit strategies" do
1286
+ it_should_behave_like "filter by associations singular association limit strategies"
1287
+ it_should_behave_like "filter by associations one_to_many limit strategies"
1248
1288
 
1249
1289
  specify "dataset associations with limited one_to_many associations should work correctly" do
1250
1290
  Artist.one_to_many :first_two_albums, {:clone=>:first_two_albums}.merge(@els)
@@ -1660,20 +1700,31 @@ shared_examples_for "regular and composite key associations" do
1660
1700
  it_should_behave_like "filtering/excluding by associations"
1661
1701
  end
1662
1702
 
1703
+ describe "with default/union :eager_limit_strategy" do
1704
+ before do
1705
+ @els = {}
1706
+ end
1707
+ it_should_behave_like "eager limit strategies"
1708
+ end
1709
+
1663
1710
  describe "with :eager_limit_strategy=>:ruby" do
1664
1711
  before do
1665
1712
  @els = {:eager_limit_strategy=>:ruby}
1666
1713
  end
1667
1714
  it_should_behave_like "eager limit strategies"
1715
+ it_should_behave_like "eager_graph limit strategies"
1668
1716
  end
1669
1717
 
1670
- describe "with :eager_limit_strategy=>true" do
1718
+ describe "with :eager_limit_strategy=>:distinct_on" do
1671
1719
  before do
1672
- @els = {:eager_limit_strategy=>true}
1720
+ @els = {:eager_limit_strategy=>:distinct_on}
1673
1721
  end
1674
1722
  it_should_behave_like "one_to_one eager limit strategies"
1675
1723
  it_should_behave_like "one_through_one eager limit strategies"
1676
1724
  it_should_behave_like "one_through_many eager limit strategies"
1725
+ it_should_behave_like "one_to_one eager_graph limit strategies"
1726
+ it_should_behave_like "one_through_one eager_graph limit strategies"
1727
+ it_should_behave_like "one_through_many eager_graph limit strategies"
1677
1728
  it_should_behave_like "filter by associations singular association limit strategies"
1678
1729
  end if DB.dataset.supports_ordered_distinct_on?
1679
1730
 
@@ -1682,6 +1733,7 @@ shared_examples_for "regular and composite key associations" do
1682
1733
  @els = {:eager_limit_strategy=>:window_function}
1683
1734
  end
1684
1735
  it_should_behave_like "eager limit strategies"
1736
+ it_should_behave_like "eager_graph limit strategies"
1685
1737
  it_should_behave_like "filter by associations limit strategies"
1686
1738
  end if DB.dataset.supports_window_functions?
1687
1739
 
@@ -1833,6 +1885,34 @@ describe "Sequel::Model Simple Associations" do
1833
1885
 
1834
1886
  it_should_behave_like "regular and composite key associations"
1835
1887
 
1888
+ describe "with :correlated_subquery limit strategy" do
1889
+ before do
1890
+ @els = {:eager_limit_strategy=>:correlated_subquery}
1891
+ end
1892
+
1893
+ it_should_behave_like "one_to_one eager_graph limit strategies"
1894
+ it_should_behave_like "one_to_many eager_graph limit strategies"
1895
+ it_should_behave_like "filter by associations one_to_one limit strategies"
1896
+ it_should_behave_like "filter by associations one_to_many limit strategies"
1897
+ end if DB.dataset.supports_limits_in_correlated_subqueries?
1898
+
1899
+ specify "should handle eager loading limited associations for many objects" do
1900
+ @db[:artists].import([:name], (1..99).map{|i| [i.to_s]})
1901
+ artists = Artist.eager(:albums).all
1902
+ artists.length.should == 100
1903
+ artists.each{|a| a.albums.should == []}
1904
+ artists = Artist.eager(:first_two_albums).all
1905
+ artists.length.should == 100
1906
+ artists.each{|a| a.first_two_albums.should == []}
1907
+ @db[:albums].insert([:artist_id], @db[:artists].select(:id))
1908
+ artists = Artist.eager(:albums).all
1909
+ artists.length.should == 100
1910
+ artists.each{|a| a.albums.length.should == 1}
1911
+ artists = Artist.eager(:first_two_albums).all
1912
+ artists.length.should == 100
1913
+ artists.each{|a| a.first_two_albums.length.should == 1}
1914
+ end
1915
+
1836
1916
  specify "should handle many_to_one associations with same name as :key" do
1837
1917
  Album.def_column_alias(:artist_id_id, :artist_id)
1838
1918
  Album.many_to_one :artist_id, :key_column =>:artist_id, :class=>Artist
@@ -2058,6 +2138,17 @@ describe "Sequel::Model Composite Key Associations" do
2058
2138
 
2059
2139
  it_should_behave_like "regular and composite key associations"
2060
2140
 
2141
+ describe "with :correlated_subquery limit strategy" do
2142
+ before do
2143
+ @els = {:eager_limit_strategy=>:correlated_subquery}
2144
+ end
2145
+
2146
+ it_should_behave_like "one_to_one eager_graph limit strategies"
2147
+ it_should_behave_like "one_to_many eager_graph limit strategies"
2148
+ it_should_behave_like "filter by associations one_to_one limit strategies"
2149
+ it_should_behave_like "filter by associations one_to_many limit strategies"
2150
+ end if DB.dataset.supports_limits_in_correlated_subqueries? && DB.dataset.supports_multiple_column_in?
2151
+
2061
2152
  specify "should have add method accept hashes and create new records" do
2062
2153
  @artist.remove_all_albums
2063
2154
  Album.dataset.delete
@@ -2168,6 +2259,7 @@ describe "Sequel::Model pg_array_to_many" do
2168
2259
 
2169
2260
  it_should_behave_like "basic regular and composite key associations"
2170
2261
  it_should_behave_like "many_to_many eager limit strategies"
2262
+ it_should_behave_like "many_to_many eager_graph limit strategies"
2171
2263
 
2172
2264
  it "should handle adding and removing entries in array" do
2173
2265
  a = Album.create
@@ -2248,6 +2340,7 @@ describe "Sequel::Model many_to_pg_array" do
2248
2340
 
2249
2341
  it_should_behave_like "basic regular and composite key associations"
2250
2342
  it_should_behave_like "many_to_many eager limit strategies"
2343
+ it_should_behave_like "many_to_many eager_graph limit strategies"
2251
2344
 
2252
2345
  it "should handle adding and removing entries in array" do
2253
2346
  a = Album.create