sequel 4.9.0 → 4.10.0

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