sequel 4.7.0 → 4.8.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 (50) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +46 -0
  3. data/README.rdoc +25 -1
  4. data/doc/active_record.rdoc +1 -1
  5. data/doc/advanced_associations.rdoc +143 -17
  6. data/doc/association_basics.rdoc +80 -59
  7. data/doc/release_notes/4.8.0.txt +175 -0
  8. data/lib/sequel/adapters/odbc.rb +1 -1
  9. data/lib/sequel/adapters/odbc/mssql.rb +4 -2
  10. data/lib/sequel/adapters/shared/postgres.rb +19 -3
  11. data/lib/sequel/adapters/shared/sqlite.rb +3 -3
  12. data/lib/sequel/ast_transformer.rb +1 -1
  13. data/lib/sequel/dataset/actions.rb +1 -1
  14. data/lib/sequel/dataset/graph.rb +23 -9
  15. data/lib/sequel/dataset/misc.rb +2 -2
  16. data/lib/sequel/dataset/sql.rb +3 -3
  17. data/lib/sequel/extensions/columns_introspection.rb +1 -1
  18. data/lib/sequel/extensions/mssql_emulate_lateral_with_apply.rb +1 -1
  19. data/lib/sequel/extensions/pg_array.rb +1 -1
  20. data/lib/sequel/extensions/pg_array_ops.rb +6 -0
  21. data/lib/sequel/extensions/pg_hstore_ops.rb +7 -0
  22. data/lib/sequel/extensions/pg_json_ops.rb +5 -0
  23. data/lib/sequel/extensions/query.rb +8 -2
  24. data/lib/sequel/extensions/to_dot.rb +1 -1
  25. data/lib/sequel/model/associations.rb +476 -152
  26. data/lib/sequel/plugins/class_table_inheritance.rb +11 -3
  27. data/lib/sequel/plugins/dataset_associations.rb +21 -18
  28. data/lib/sequel/plugins/many_through_many.rb +87 -20
  29. data/lib/sequel/plugins/nested_attributes.rb +12 -0
  30. data/lib/sequel/plugins/pg_array_associations.rb +31 -12
  31. data/lib/sequel/plugins/single_table_inheritance.rb +9 -1
  32. data/lib/sequel/sql.rb +1 -0
  33. data/lib/sequel/version.rb +1 -1
  34. data/spec/adapters/mssql_spec.rb +2 -2
  35. data/spec/adapters/postgres_spec.rb +7 -0
  36. data/spec/core/object_graph_spec.rb +250 -196
  37. data/spec/extensions/core_refinements_spec.rb +1 -1
  38. data/spec/extensions/dataset_associations_spec.rb +100 -6
  39. data/spec/extensions/many_through_many_spec.rb +1002 -19
  40. data/spec/extensions/nested_attributes_spec.rb +24 -0
  41. data/spec/extensions/pg_array_associations_spec.rb +17 -12
  42. data/spec/extensions/pg_array_spec.rb +4 -2
  43. data/spec/extensions/spec_helper.rb +1 -1
  44. data/spec/integration/associations_test.rb +1003 -48
  45. data/spec/integration/dataset_test.rb +12 -5
  46. data/spec/integration/prepared_statement_test.rb +1 -1
  47. data/spec/integration/type_test.rb +1 -1
  48. data/spec/model/associations_spec.rb +467 -130
  49. data/spec/model/eager_loading_spec.rb +332 -5
  50. metadata +5 -3
@@ -1,12 +1,12 @@
1
1
  require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper')
2
2
 
3
- describe Sequel::Dataset, " graphing" do
3
+ describe Sequel::Dataset, "graphing" do
4
4
  before do
5
5
  @db = Sequel.mock(:columns=>proc do |sql|
6
6
  case sql
7
7
  when /points/
8
8
  [:id, :x, :y]
9
- when /lines/
9
+ when /lines|foo/
10
10
  [:id, :x, :y, :graph_id]
11
11
  else
12
12
  [:id, :name, :x, :y, :lines_x]
@@ -19,205 +19,259 @@ describe Sequel::Dataset, " graphing" do
19
19
  @db.sqls
20
20
  end
21
21
 
22
- it "#graph should not modify the current dataset's opts" do
23
- o1 = @ds1.opts
24
- o2 = o1.dup
25
- ds1 = @ds1.graph(@ds2, :x=>:id)
26
- @ds1.opts.should == o1
27
- @ds1.opts.should == o2
28
- ds1.opts.should_not == o1
22
+ describe "#graph" do
23
+ it "should not modify the current dataset's opts" do
24
+ o1 = @ds1.opts
25
+ o2 = o1.dup
26
+ ds1 = @ds1.graph(@ds2, :x=>:id)
27
+ @ds1.opts.should == o1
28
+ @ds1.opts.should == o2
29
+ ds1.opts.should_not == o1
30
+ end
31
+
32
+ it "should not modify the current dataset's opts if current dataset is already graphed" do
33
+ ds2 = @ds1.graph(@ds2)
34
+ proc{@ds1.graph(@ds2)}.should_not raise_error
35
+ proc{ds2.graph(@ds3)}.should_not raise_error
36
+ proc{ds2.graph(@ds3)}.should_not raise_error
37
+ end
38
+
39
+ it "should accept a simple dataset and pass the table to join" do
40
+ ds = @ds1.graph(@ds2, :x=>:id)
41
+ ds.sql.should == 'SELECT points.id, points.x, points.y, lines.id AS lines_id, lines.x AS lines_x, lines.y AS lines_y, lines.graph_id FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)'
42
+ end
43
+
44
+ it "should use currently selected columns as the basis for the selected columns in a new graph" do
45
+ ds = @ds1.select(:id).graph(@ds2, :x=>:id)
46
+ ds.sql.should == 'SELECT points.id, lines.id AS lines_id, lines.x, lines.y, lines.graph_id FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)'
47
+
48
+ ds = @ds1.select(:id, :x).graph(@ds2, :x=>:id)
49
+ ds.sql.should == 'SELECT points.id, points.x, lines.id AS lines_id, lines.x AS lines_x, lines.y, lines.graph_id FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)'
50
+
51
+ ds = @ds1.select(Sequel.identifier(:id), Sequel.qualify(:points, :x)).graph(@ds2, :x=>:id)
52
+ ds.sql.should == 'SELECT points.id, points.x, lines.id AS lines_id, lines.x AS lines_x, lines.y, lines.graph_id FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)'
53
+
54
+ ds = @ds1.select(Sequel.identifier(:id).qualify(:points), Sequel.identifier(:x).as(:y)).graph(@ds2, :x=>:id)
55
+ ds.sql.should == 'SELECT points.id, points.x AS y, lines.id AS lines_id, lines.x, lines.y AS lines_y, lines.graph_id FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)'
56
+
57
+ ds = @ds1.select(:id, Sequel.identifier(:x).qualify(Sequel.identifier(:points)).as(Sequel.identifier(:y))).graph(@ds2, :x=>:id)
58
+ ds.sql.should == 'SELECT points.id, points.x AS y, lines.id AS lines_id, lines.x, lines.y AS lines_y, lines.graph_id FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)'
59
+ end
60
+
61
+ it "should raise error if currently selected expressions cannot be handled" do
62
+ proc{@ds1.select(1).graph(@ds2, :x=>:id)}.should raise_error(Sequel::Error)
63
+ end
64
+
65
+ it "should accept a complex dataset and pass it directly to join" do
66
+ ds = @ds1.graph(@ds2.select_all(:lines), {:x=>:id})
67
+ ds.sql.should == 'SELECT points.id, points.x, points.y, lines.id AS lines_id, lines.x AS lines_x, lines.y AS lines_y, lines.graph_id FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)'
68
+ end
69
+
70
+ it "should accept a complex dataset and pass it directly to join" do
71
+ ds = @ds1.graph(@ds2.filter(:x=>1), {:x=>:id})
72
+ ds.sql.should == 'SELECT points.id, points.x, points.y, t1.id AS t1_id, t1.x AS t1_x, t1.y AS t1_y, t1.graph_id FROM points LEFT OUTER JOIN (SELECT * FROM lines WHERE (x = 1)) AS t1 ON (t1.x = points.id)'
73
+ ds = @ds1.graph(@ds2.select_all(:lines).filter(:x=>1), {:x=>:id})
74
+ ds.sql.should == 'SELECT points.id, points.x, points.y, t1.id AS t1_id, t1.x AS t1_x, t1.y AS t1_y, t1.graph_id FROM points LEFT OUTER JOIN (SELECT lines.* FROM lines WHERE (x = 1)) AS t1 ON (t1.x = points.id)'
75
+ end
76
+
77
+ it "should work on from_self datasets" do
78
+ ds = @ds1.from_self.graph(@ds2, :x=>:id)
79
+ ds.sql.should == 'SELECT t1.id, t1.x, t1.y, lines.id AS lines_id, lines.x AS lines_x, lines.y AS lines_y, lines.graph_id FROM (SELECT * FROM points) AS t1 LEFT OUTER JOIN lines ON (lines.x = t1.id)'
80
+ ds = @ds1.graph(@ds2.from_self, :x=>:id)
81
+ ds.sql.should == 'SELECT points.id, points.x, points.y, t1.id AS t1_id, t1.x AS t1_x, t1.y AS t1_y, t1.graph_id FROM points LEFT OUTER JOIN (SELECT * FROM (SELECT * FROM lines) AS t1) AS t1 ON (t1.x = points.id)'
82
+ ds = @ds1.from_self.from_self.graph(@ds2.from_self.from_self, :x=>:id)
83
+ ds.sql.should == 'SELECT t1.id, t1.x, t1.y, t2.id AS t2_id, t2.x AS t2_x, t2.y AS t2_y, t2.graph_id FROM (SELECT * FROM (SELECT * FROM points) AS t1) AS t1 LEFT OUTER JOIN (SELECT * FROM (SELECT * FROM (SELECT * FROM lines) AS t1) AS t1) AS t2 ON (t2.x = t1.id)'
84
+ ds = @ds1.from(@ds1, @ds3).graph(@ds2.from_self, :x=>:id)
85
+ ds.sql.should == 'SELECT t1.id, t1.x, t1.y, t3.id AS t3_id, t3.x AS t3_x, t3.y AS t3_y, t3.graph_id FROM (SELECT * FROM (SELECT * FROM points) AS t1, (SELECT * FROM graphs) AS t2) AS t1 LEFT OUTER JOIN (SELECT * FROM (SELECT * FROM lines) AS t1) AS t3 ON (t3.x = t1.id)'
86
+ end
87
+
88
+ it "should accept a symbol table name as the dataset" do
89
+ ds = @ds1.graph(:lines, :x=>:id)
90
+ ds.sql.should == 'SELECT points.id, points.x, points.y, lines.id AS lines_id, lines.x AS lines_x, lines.y AS lines_y, lines.graph_id FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)'
91
+ end
92
+
93
+ it "should accept a schema qualified symbolic table name as the dataset" do
94
+ ds = @ds1.graph(:schema__lines, :x=>:id)
95
+ ds.sql.should == 'SELECT points.id, points.x, points.y, lines.id AS lines_id, lines.x AS lines_x, lines.y AS lines_y, lines.graph_id FROM points LEFT OUTER JOIN schema.lines AS lines ON (lines.x = points.id)'
96
+ end
97
+
98
+ it "allows giving table alias in symbolic argument" do
99
+ ds = @ds1.graph(:lines___sketch, :x=>:id)
100
+ ds.sql.should == 'SELECT points.id, points.x, points.y, sketch.id AS sketch_id, sketch.x AS sketch_x, sketch.y AS sketch_y, sketch.graph_id FROM points LEFT OUTER JOIN lines AS sketch ON (sketch.x = points.id)'
101
+ ds = @ds1.graph(:schema__lines___sketch, :x=>:id)
102
+ ds.sql.should == 'SELECT points.id, points.x, points.y, sketch.id AS sketch_id, sketch.x AS sketch_x, sketch.y AS sketch_y, sketch.graph_id FROM points LEFT OUTER JOIN schema.lines AS sketch ON (sketch.x = points.id)'
103
+ end
104
+
105
+ it "should accept a SQL::Identifier as the dataset" do
106
+ ds = @ds1.graph(Sequel.identifier(:lines), :x=>:id)
107
+ ds.sql.should == 'SELECT points.id, points.x, points.y, lines.id AS lines_id, lines.x AS lines_x, lines.y AS lines_y, lines.graph_id FROM points LEFT OUTER JOIN lines AS lines ON (lines.x = points.id)'
108
+ ds = @ds1.graph(Sequel.identifier('lines'), :x=>:id)
109
+ ds.sql.should == 'SELECT points.id, points.x, points.y, lines.id AS lines_id, lines.x AS lines_x, lines.y AS lines_y, lines.graph_id FROM points LEFT OUTER JOIN lines AS lines ON (lines.x = points.id)'
110
+ end
111
+
112
+ it "should accept a SQL::QualifiedIdentifier as the dataset" do
113
+ ds = @ds1.graph(Sequel.qualify(:schema, :lines), :x=>:id)
114
+ ds.sql.should == 'SELECT points.id, points.x, points.y, lines.id AS lines_id, lines.x AS lines_x, lines.y AS lines_y, lines.graph_id FROM points LEFT OUTER JOIN schema.lines AS lines ON (lines.x = points.id)'
115
+ ds = @ds1.graph(Sequel.qualify('schema', 'lines'), :x=>:id)
116
+ ds.sql.should == 'SELECT points.id, points.x, points.y, lines.id AS lines_id, lines.x AS lines_x, lines.y AS lines_y, lines.graph_id FROM points LEFT OUTER JOIN schema.lines AS lines ON (lines.x = points.id)'
117
+ ds = @ds1.graph(Sequel.qualify(Sequel.identifier(:schema), Sequel.identifier(:lines)), :x=>:id)
118
+ ds.sql.should == 'SELECT points.id, points.x, points.y, lines.id AS lines_id, lines.x AS lines_x, lines.y AS lines_y, lines.graph_id FROM points LEFT OUTER JOIN schema.lines AS lines ON (lines.x = points.id)'
119
+ ds = @ds1.graph(Sequel.qualify(Sequel.identifier('schema'), Sequel.identifier('lines')), :x=>:id)
120
+ ds.sql.should == 'SELECT points.id, points.x, points.y, lines.id AS lines_id, lines.x AS lines_x, lines.y AS lines_y, lines.graph_id FROM points LEFT OUTER JOIN schema.lines AS lines ON (lines.x = points.id)'
121
+ end
122
+
123
+ it "should accept a SQL::AliasedExpression as the dataset" do
124
+ ds = @ds1.graph(Sequel.as(:lines, :foo), :x=>:id)
125
+ ds.sql.should == 'SELECT points.id, points.x, points.y, foo.id AS foo_id, foo.x AS foo_x, foo.y AS foo_y, foo.graph_id FROM points LEFT OUTER JOIN lines AS foo ON (foo.x = points.id)'
126
+ ds = @ds1.graph(Sequel.as(:schema__lines, :foo), :x=>:id)
127
+ ds.sql.should == 'SELECT points.id, points.x, points.y, foo.id AS foo_id, foo.x AS foo_x, foo.y AS foo_y, foo.graph_id FROM points LEFT OUTER JOIN schema.lines AS foo ON (foo.x = points.id)'
128
+ ds = @ds1.graph(Sequel.as(Sequel.identifier(:lines), :foo), :x=>:id)
129
+ ds.sql.should == 'SELECT points.id, points.x, points.y, foo.id AS foo_id, foo.x AS foo_x, foo.y AS foo_y, foo.graph_id FROM points LEFT OUTER JOIN lines AS foo ON (foo.x = points.id)'
130
+ ds = @ds1.graph(Sequel.as(Sequel.qualify(:schema, :lines), :foo), :x=>:id)
131
+ ds.sql.should == 'SELECT points.id, points.x, points.y, foo.id AS foo_id, foo.x AS foo_x, foo.y AS foo_y, foo.graph_id FROM points LEFT OUTER JOIN schema.lines AS foo ON (foo.x = points.id)'
132
+ end
133
+
134
+ it "should raise an error if a symbol, dataset, or model is not used" do
135
+ proc{@ds1.graph(Object.new, :x=>:id)}.should raise_error(Sequel::Error)
136
+ end
137
+
138
+ it "should accept a :table_alias option" do
139
+ ds = @ds1.graph(:lines, {:x=>:id}, :table_alias=>:planes)
140
+ ds.sql.should == 'SELECT points.id, points.x, points.y, planes.id AS planes_id, planes.x AS planes_x, planes.y AS planes_y, planes.graph_id FROM points LEFT OUTER JOIN lines AS planes ON (planes.x = points.id)'
141
+ end
142
+
143
+ it "should accept a :implicit_qualifier option" do
144
+ ds = @ds1.graph(:lines, {:x=>:id}, :implicit_qualifier=>:planes)
145
+ ds.sql.should == 'SELECT points.id, points.x, points.y, lines.id AS lines_id, lines.x AS lines_x, lines.y AS lines_y, lines.graph_id FROM points LEFT OUTER JOIN lines ON (lines.x = planes.id)'
146
+ end
147
+
148
+ it "should accept a :join_type option" do
149
+ ds = @ds1.graph(:lines, {:x=>:id}, :join_type=>:inner)
150
+ ds.sql.should == 'SELECT points.id, points.x, points.y, lines.id AS lines_id, lines.x AS lines_x, lines.y AS lines_y, lines.graph_id FROM points INNER JOIN lines ON (lines.x = points.id)'
151
+ end
152
+
153
+ it "should not select any columns from the graphed table if :select option is false" do
154
+ ds = @ds1.graph(:lines, {:x=>:id}, :select=>false).graph(:graphs, :id=>:graph_id)
155
+ ds.sql.should == 'SELECT points.id, points.x, points.y, graphs.id AS graphs_id, graphs.name, graphs.x AS graphs_x, graphs.y AS graphs_y, graphs.lines_x FROM points LEFT OUTER JOIN lines ON (lines.x = points.id) LEFT OUTER JOIN graphs ON (graphs.id = lines.graph_id)'
156
+ end
157
+
158
+ it "should use the given columns if :select option is used" do
159
+ ds = @ds1.graph(:lines, {:x=>:id}, :select=>[:x, :graph_id]).graph(:graphs, :id=>:graph_id)
160
+ ds.sql.should == 'SELECT points.id, points.x, points.y, lines.x AS lines_x, lines.graph_id, graphs.id AS graphs_id, graphs.name, graphs.x AS graphs_x, graphs.y AS graphs_y, graphs.lines_x AS graphs_lines_x FROM points LEFT OUTER JOIN lines ON (lines.x = points.id) LEFT OUTER JOIN graphs ON (graphs.id = lines.graph_id)'
161
+ end
162
+
163
+ it "should pass all join_conditions to join_table" do
164
+ ds = @ds1.graph(@ds2, [[:x, :id], [:y, :id]])
165
+ ds.sql.should == 'SELECT points.id, points.x, points.y, lines.id AS lines_id, lines.x AS lines_x, lines.y AS lines_y, lines.graph_id FROM points LEFT OUTER JOIN lines ON ((lines.x = points.id) AND (lines.y = points.id))'
166
+ end
167
+
168
+ it "should accept a block instead of conditions and pass it to join_table" do
169
+ ds = @ds1.graph(@ds2){|ja, lja, js| [[Sequel.qualify(ja, :x), Sequel.qualify(lja, :id)], [Sequel.qualify(ja, :y), Sequel.qualify(lja, :id)]]}
170
+ ds.sql.should == 'SELECT points.id, points.x, points.y, lines.id AS lines_id, lines.x AS lines_x, lines.y AS lines_y, lines.graph_id FROM points LEFT OUTER JOIN lines ON ((lines.x = points.id) AND (lines.y = points.id))'
171
+ end
172
+
173
+ it "should not add columns if graph is called after set_graph_aliases" do
174
+ ds = @ds1.set_graph_aliases([[:x,[:points, :x]], [:y,[:lines, :y]]])
175
+ ds.sql.should == 'SELECT points.x, lines.y FROM points'
176
+ ds = ds.graph(:lines, :x=>:id)
177
+ ds.sql.should == 'SELECT points.x, lines.y FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)'
178
+ end
179
+
180
+ it "should allow graphing of multiple datasets" do
181
+ ds = @ds1.graph(@ds2, :x=>:id).graph(@ds3, :id=>:graph_id)
182
+ ds.sql.should == 'SELECT points.id, points.x, points.y, lines.id AS lines_id, lines.x AS lines_x, lines.y AS lines_y, lines.graph_id, graphs.id AS graphs_id, graphs.name, graphs.x AS graphs_x, graphs.y AS graphs_y, graphs.lines_x AS graphs_lines_x FROM points LEFT OUTER JOIN lines ON (lines.x = points.id) LEFT OUTER JOIN graphs ON (graphs.id = lines.graph_id)'
183
+ end
184
+
185
+ it "should allow graphing of the same dataset multiple times" do
186
+ ds = @ds1.graph(@ds2, :x=>:id).graph(@ds2, {:y=>:points__id}, :table_alias=>:graph)
187
+ ds.sql.should == 'SELECT points.id, points.x, points.y, lines.id AS lines_id, lines.x AS lines_x, lines.y AS lines_y, lines.graph_id, graph.id AS graph_id_0, graph.x AS graph_x, graph.y AS graph_y, graph.graph_id AS graph_graph_id FROM points LEFT OUTER JOIN lines ON (lines.x = points.id) LEFT OUTER JOIN lines AS graph ON (graph.y = points.id)'
188
+ end
189
+
190
+ it "should raise an error if the table/table alias has already been used" do
191
+ proc{@ds1.graph(@ds1, :x=>:id)}.should raise_error(Sequel::Error)
192
+ proc{@ds1.graph(@ds2, :x=>:id)}.should_not raise_error
193
+ proc{@ds1.graph(@ds2, :x=>:id).graph(@ds2, :x=>:id)}.should raise_error(Sequel::Error)
194
+ proc{@ds1.graph(@ds2, :x=>:id).graph(@ds2, {:x=>:id}, :table_alias=>:blah)}.should_not raise_error
195
+ end
29
196
  end
30
197
 
31
- it "#graph should not modify the current dataset's opts if current dataset is already graphed" do
32
- ds2 = @ds1.graph(@ds2)
33
- proc{@ds1.graph(@ds2)}.should_not raise_error
34
- proc{ds2.graph(@ds3)}.should_not raise_error
35
- proc{ds2.graph(@ds3)}.should_not raise_error
198
+ describe "#set_graph_aliases" do
199
+ it "should not modify the current dataset's opts" do
200
+ o1 = @ds1.opts
201
+ o2 = o1.dup
202
+ ds1 = @ds1.set_graph_aliases(:x=>[:graphs,:id])
203
+ @ds1.opts.should == o1
204
+ @ds1.opts.should == o2
205
+ ds1.opts.should_not == o1
206
+ end
207
+
208
+ it "should specify the graph mapping" do
209
+ ds = @ds1.graph(:lines, :x=>:id)
210
+ ds.sql.should == 'SELECT points.id, points.x, points.y, lines.id AS lines_id, lines.x AS lines_x, lines.y AS lines_y, lines.graph_id FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)'
211
+ ds = ds.set_graph_aliases(:x=>[:points, :x], :y=>[:lines, :y])
212
+ ['SELECT points.x, lines.y FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)',
213
+ 'SELECT lines.y, points.x FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)'
214
+ ].should(include(ds.sql))
215
+ end
216
+
217
+ it "should allow a third entry to specify an expression to use other than the default" do
218
+ ds = @ds1.graph(:lines, :x=>:id).set_graph_aliases(:x=>[:points, :x, 1], :y=>[:lines, :y, Sequel.function(:random)])
219
+ ['SELECT 1 AS x, random() AS y FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)',
220
+ 'SELECT random() AS y, 1 AS x FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)'
221
+ ].should(include(ds.sql))
222
+ end
223
+
224
+ it "should allow a single array entry to specify a table, assuming the same column as the key" do
225
+ ds = @ds1.graph(:lines, :x=>:id).set_graph_aliases(:x=>[:points], :y=>[:lines])
226
+ ['SELECT points.x, lines.y FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)',
227
+ 'SELECT lines.y, points.x FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)'
228
+ ].should(include(ds.sql))
229
+ end
230
+
231
+ it "should allow hash values to be symbols specifying table, assuming the same column as the key" do
232
+ ds = @ds1.graph(:lines, :x=>:id).set_graph_aliases(:x=>:points, :y=>:lines)
233
+ ['SELECT points.x, lines.y FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)',
234
+ 'SELECT lines.y, points.x FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)'
235
+ ].should(include(ds.sql))
236
+ end
237
+
238
+ it "should only alias columns if necessary" do
239
+ ds = @ds1.set_graph_aliases(:x=>[:points, :x], :y=>[:lines, :y])
240
+ ['SELECT points.x, lines.y FROM points',
241
+ 'SELECT lines.y, points.x FROM points'
242
+ ].should(include(ds.sql))
243
+
244
+ ds = @ds1.set_graph_aliases(:x1=>[:points, :x], :y=>[:lines, :y])
245
+ ['SELECT points.x AS x1, lines.y FROM points',
246
+ 'SELECT lines.y, points.x AS x1 FROM points'
247
+ ].should(include(ds.sql))
248
+ end
36
249
  end
37
250
 
38
- it "#graph should accept a simple dataset and pass the table to join" do
39
- ds = @ds1.graph(@ds2, :x=>:id)
40
- ds.sql.should == 'SELECT points.id, points.x, points.y, lines.id AS lines_id, lines.x AS lines_x, lines.y AS lines_y, lines.graph_id FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)'
251
+ describe "#add_graph_aliases" do
252
+ it "should not modify the current dataset's opts" do
253
+ ds1 = @ds1.set_graph_aliases(:x=>[:graphs,:id])
254
+ o1 = ds1.opts
255
+ o2 = o1.dup
256
+ ds2 = ds1.add_graph_aliases(:y=>[:blah,:id])
257
+ ds1.opts.should == o1
258
+ ds1.opts.should == o2
259
+ ds2.opts.should_not == o1
260
+ end
261
+
262
+ it "should add columns to the graph mapping" do
263
+ @ds1.graph(:lines, :x=>:id).set_graph_aliases(:x=>[:points, :q]).add_graph_aliases(:y=>[:lines, :r]).sql.should == 'SELECT points.q AS x, lines.r AS y FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)'
264
+ end
265
+
266
+ it "should raise an error if called without existing graph aliases" do
267
+ proc{@ds1.add_graph_aliases(:y=>[:lines, :r])}.should raise_error(Sequel::Error)
268
+ end
41
269
  end
42
270
 
43
- it "#graph should use currently selected columns as the basis for the selected columns in a new graph" do
44
- ds = @ds1.select(:id).graph(@ds2, :x=>:id)
45
- ds.sql.should == 'SELECT points.id, lines.id AS lines_id, lines.x, lines.y, lines.graph_id FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)'
46
-
47
- ds = @ds1.select(:id, :x).graph(@ds2, :x=>:id)
48
- ds.sql.should == 'SELECT points.id, points.x, lines.id AS lines_id, lines.x AS lines_x, lines.y, lines.graph_id FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)'
49
-
50
- ds = @ds1.select(Sequel.identifier(:id), Sequel.qualify(:points, :x)).graph(@ds2, :x=>:id)
51
- ds.sql.should == 'SELECT points.id, points.x, lines.id AS lines_id, lines.x AS lines_x, lines.y, lines.graph_id FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)'
52
-
53
- ds = @ds1.select(Sequel.identifier(:id).qualify(:points), Sequel.identifier(:x).as(:y)).graph(@ds2, :x=>:id)
54
- ds.sql.should == 'SELECT points.id, points.x AS y, lines.id AS lines_id, lines.x, lines.y AS lines_y, lines.graph_id FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)'
55
-
56
- ds = @ds1.select(:id, Sequel.identifier(:x).qualify(Sequel.identifier(:points)).as(Sequel.identifier(:y))).graph(@ds2, :x=>:id)
57
- ds.sql.should == 'SELECT points.id, points.x AS y, lines.id AS lines_id, lines.x, lines.y AS lines_y, lines.graph_id FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)'
58
- end
59
-
60
- it "#graph should raise error if currently selected expressions cannot be handled" do
61
- proc{@ds1.select(1).graph(@ds2, :x=>:id)}.should raise_error(Sequel::Error)
62
- end
63
-
64
- it "#graph should accept a complex dataset and pass it directly to join" do
65
- ds = @ds1.graph(@ds2.select_all(:lines), {:x=>:id})
66
- ds.sql.should == 'SELECT points.id, points.x, points.y, lines.id AS lines_id, lines.x AS lines_x, lines.y AS lines_y, lines.graph_id FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)'
67
- end
68
-
69
- it "#graph should accept a complex dataset and pass it directly to join" do
70
- ds = @ds1.graph(@ds2.filter(:x=>1), {:x=>:id})
71
- ds.sql.should == 'SELECT points.id, points.x, points.y, t1.id AS t1_id, t1.x AS t1_x, t1.y AS t1_y, t1.graph_id FROM points LEFT OUTER JOIN (SELECT * FROM lines WHERE (x = 1)) AS t1 ON (t1.x = points.id)'
72
- ds = @ds1.graph(@ds2.select_all(:lines).filter(:x=>1), {:x=>:id})
73
- ds.sql.should == 'SELECT points.id, points.x, points.y, t1.id AS t1_id, t1.x AS t1_x, t1.y AS t1_y, t1.graph_id FROM points LEFT OUTER JOIN (SELECT lines.* FROM lines WHERE (x = 1)) AS t1 ON (t1.x = points.id)'
74
- end
75
-
76
- it "#graph should work on from_self datasets" do
77
- ds = @ds1.from_self.graph(@ds2, :x=>:id)
78
- ds.sql.should == 'SELECT t1.id, t1.x, t1.y, lines.id AS lines_id, lines.x AS lines_x, lines.y AS lines_y, lines.graph_id FROM (SELECT * FROM points) AS t1 LEFT OUTER JOIN lines ON (lines.x = t1.id)'
79
- ds = @ds1.graph(@ds2.from_self, :x=>:id)
80
- ds.sql.should == 'SELECT points.id, points.x, points.y, t1.id AS t1_id, t1.x AS t1_x, t1.y AS t1_y, t1.graph_id FROM points LEFT OUTER JOIN (SELECT * FROM (SELECT * FROM lines) AS t1) AS t1 ON (t1.x = points.id)'
81
- ds = @ds1.from_self.from_self.graph(@ds2.from_self.from_self, :x=>:id)
82
- ds.sql.should == 'SELECT t1.id, t1.x, t1.y, t2.id AS t2_id, t2.x AS t2_x, t2.y AS t2_y, t2.graph_id FROM (SELECT * FROM (SELECT * FROM points) AS t1) AS t1 LEFT OUTER JOIN (SELECT * FROM (SELECT * FROM (SELECT * FROM lines) AS t1) AS t1) AS t2 ON (t2.x = t1.id)'
83
- ds = @ds1.from(@ds1, @ds3).graph(@ds2.from_self, :x=>:id)
84
- ds.sql.should == 'SELECT t1.id, t1.x, t1.y, t3.id AS t3_id, t3.x AS t3_x, t3.y AS t3_y, t3.graph_id FROM (SELECT * FROM (SELECT * FROM points) AS t1, (SELECT * FROM graphs) AS t2) AS t1 LEFT OUTER JOIN (SELECT * FROM (SELECT * FROM lines) AS t1) AS t3 ON (t3.x = t1.id)'
85
- end
86
-
87
- it "#graph should accept a symbol table name as the dataset" do
88
- ds = @ds1.graph(:lines, :x=>:id)
89
- ds.sql.should == 'SELECT points.id, points.x, points.y, lines.id AS lines_id, lines.x AS lines_x, lines.y AS lines_y, lines.graph_id FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)'
90
- end
91
-
92
- it "#graph should raise an error if a symbol, dataset, or model is not used" do
93
- proc{@ds1.graph(Object.new, :x=>:id)}.should raise_error(Sequel::Error)
94
- end
95
-
96
- it "#graph should accept a :table_alias option" do
97
- ds = @ds1.graph(:lines, {:x=>:id}, :table_alias=>:planes)
98
- ds.sql.should == 'SELECT points.id, points.x, points.y, planes.id AS planes_id, planes.x AS planes_x, planes.y AS planes_y, planes.graph_id FROM points LEFT OUTER JOIN lines AS planes ON (planes.x = points.id)'
99
- end
100
-
101
- it "#graph should accept a :implicit_qualifier option" do
102
- ds = @ds1.graph(:lines, {:x=>:id}, :implicit_qualifier=>:planes)
103
- ds.sql.should == 'SELECT points.id, points.x, points.y, lines.id AS lines_id, lines.x AS lines_x, lines.y AS lines_y, lines.graph_id FROM points LEFT OUTER JOIN lines ON (lines.x = planes.id)'
104
- end
105
-
106
- it "#graph should accept a :join_type option" do
107
- ds = @ds1.graph(:lines, {:x=>:id}, :join_type=>:inner)
108
- ds.sql.should == 'SELECT points.id, points.x, points.y, lines.id AS lines_id, lines.x AS lines_x, lines.y AS lines_y, lines.graph_id FROM points INNER JOIN lines ON (lines.x = points.id)'
109
- end
110
-
111
- it "#graph should not select any columns from the graphed table if :select option is false" do
112
- ds = @ds1.graph(:lines, {:x=>:id}, :select=>false).graph(:graphs, :id=>:graph_id)
113
- ds.sql.should == 'SELECT points.id, points.x, points.y, graphs.id AS graphs_id, graphs.name, graphs.x AS graphs_x, graphs.y AS graphs_y, graphs.lines_x FROM points LEFT OUTER JOIN lines ON (lines.x = points.id) LEFT OUTER JOIN graphs ON (graphs.id = lines.graph_id)'
114
- end
115
-
116
- it "#graph should use the given columns if :select option is used" do
117
- ds = @ds1.graph(:lines, {:x=>:id}, :select=>[:x, :graph_id]).graph(:graphs, :id=>:graph_id)
118
- ds.sql.should == 'SELECT points.id, points.x, points.y, lines.x AS lines_x, lines.graph_id, graphs.id AS graphs_id, graphs.name, graphs.x AS graphs_x, graphs.y AS graphs_y, graphs.lines_x AS graphs_lines_x FROM points LEFT OUTER JOIN lines ON (lines.x = points.id) LEFT OUTER JOIN graphs ON (graphs.id = lines.graph_id)'
119
- end
120
-
121
- it "#graph should pass all join_conditions to join_table" do
122
- ds = @ds1.graph(@ds2, [[:x, :id], [:y, :id]])
123
- ds.sql.should == 'SELECT points.id, points.x, points.y, lines.id AS lines_id, lines.x AS lines_x, lines.y AS lines_y, lines.graph_id FROM points LEFT OUTER JOIN lines ON ((lines.x = points.id) AND (lines.y = points.id))'
124
- end
125
-
126
- it "#graph should accept a block instead of conditions and pass it to join_table" do
127
- ds = @ds1.graph(@ds2){|ja, lja, js| [[Sequel.qualify(ja, :x), Sequel.qualify(lja, :id)], [Sequel.qualify(ja, :y), Sequel.qualify(lja, :id)]]}
128
- ds.sql.should == 'SELECT points.id, points.x, points.y, lines.id AS lines_id, lines.x AS lines_x, lines.y AS lines_y, lines.graph_id FROM points LEFT OUTER JOIN lines ON ((lines.x = points.id) AND (lines.y = points.id))'
129
- end
130
-
131
- it "#graph should not add columns if graph is called after set_graph_aliases" do
132
- ds = @ds1.set_graph_aliases([[:x,[:points, :x]], [:y,[:lines, :y]]])
133
- ds.sql.should == 'SELECT points.x, lines.y FROM points'
134
- ds = ds.graph(:lines, :x=>:id)
135
- ds.sql.should == 'SELECT points.x, lines.y FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)'
136
- end
137
-
138
- it "#graph should allow graphing of multiple datasets" do
139
- ds = @ds1.graph(@ds2, :x=>:id).graph(@ds3, :id=>:graph_id)
140
- ds.sql.should == 'SELECT points.id, points.x, points.y, lines.id AS lines_id, lines.x AS lines_x, lines.y AS lines_y, lines.graph_id, graphs.id AS graphs_id, graphs.name, graphs.x AS graphs_x, graphs.y AS graphs_y, graphs.lines_x AS graphs_lines_x FROM points LEFT OUTER JOIN lines ON (lines.x = points.id) LEFT OUTER JOIN graphs ON (graphs.id = lines.graph_id)'
141
- end
142
-
143
- it "#graph should allow graphing of the same dataset multiple times" do
144
- ds = @ds1.graph(@ds2, :x=>:id).graph(@ds2, {:y=>:points__id}, :table_alias=>:graph)
145
- ds.sql.should == 'SELECT points.id, points.x, points.y, lines.id AS lines_id, lines.x AS lines_x, lines.y AS lines_y, lines.graph_id, graph.id AS graph_id_0, graph.x AS graph_x, graph.y AS graph_y, graph.graph_id AS graph_graph_id FROM points LEFT OUTER JOIN lines ON (lines.x = points.id) LEFT OUTER JOIN lines AS graph ON (graph.y = points.id)'
146
- end
147
-
148
- it "#graph should raise an error if the table/table alias has already been used" do
149
- proc{@ds1.graph(@ds1, :x=>:id)}.should raise_error(Sequel::Error)
150
- proc{@ds1.graph(@ds2, :x=>:id)}.should_not raise_error
151
- proc{@ds1.graph(@ds2, :x=>:id).graph(@ds2, :x=>:id)}.should raise_error(Sequel::Error)
152
- proc{@ds1.graph(@ds2, :x=>:id).graph(@ds2, {:x=>:id}, :table_alias=>:blah)}.should_not raise_error
153
- end
154
-
155
- it "#set_graph_aliases and #add_graph_aliases should not modify the current dataset's opts" do
156
- o1 = @ds1.opts
157
- o2 = o1.dup
158
- ds1 = @ds1.set_graph_aliases(:x=>[:graphs,:id])
159
- @ds1.opts.should == o1
160
- @ds1.opts.should == o2
161
- ds1.opts.should_not == o1
162
- o3 = ds1.opts
163
- ds2 = ds1.add_graph_aliases(:y=>[:blah,:id])
164
- ds1.opts.should == o3
165
- ds1.opts.should == o3
166
- ds2.opts.should_not == o2
167
- end
168
-
169
- it "#set_graph_aliases should specify the graph mapping" do
170
- ds = @ds1.graph(:lines, :x=>:id)
171
- ds.sql.should == 'SELECT points.id, points.x, points.y, lines.id AS lines_id, lines.x AS lines_x, lines.y AS lines_y, lines.graph_id FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)'
172
- ds = ds.set_graph_aliases(:x=>[:points, :x], :y=>[:lines, :y])
173
- ['SELECT points.x, lines.y FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)',
174
- 'SELECT lines.y, points.x FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)'
175
- ].should(include(ds.sql))
176
- end
177
-
178
- it "#add_graph_aliases should add columns to the graph mapping" do
179
- @ds1.graph(:lines, :x=>:id).set_graph_aliases(:x=>[:points, :q]).add_graph_aliases(:y=>[:lines, :r]).sql.should == 'SELECT points.q AS x, lines.r AS y FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)'
180
- end
181
-
182
- it "#add_graph_aliases should raise an error if called without existing graph aliases" do
183
- proc{@ds1.add_graph_aliases(:y=>[:lines, :r])}.should raise_error(Sequel::Error)
184
- end
185
-
186
- it "#set_graph_aliases should allow a third entry to specify an expression to use other than the default" do
187
- ds = @ds1.graph(:lines, :x=>:id).set_graph_aliases(:x=>[:points, :x, 1], :y=>[:lines, :y, Sequel.function(:random)])
188
- ['SELECT 1 AS x, random() AS y FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)',
189
- 'SELECT random() AS y, 1 AS x FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)'
190
- ].should(include(ds.sql))
191
- end
192
-
193
- it "#set_graph_aliases should allow a single array entry to specify a table, assuming the same column as the key" do
194
- ds = @ds1.graph(:lines, :x=>:id).set_graph_aliases(:x=>[:points], :y=>[:lines])
195
- ['SELECT points.x, lines.y FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)',
196
- 'SELECT lines.y, points.x FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)'
197
- ].should(include(ds.sql))
198
- end
199
-
200
- it "#set_graph_aliases should allow hash values to be symbols specifying table, assuming the same column as the key" do
201
- ds = @ds1.graph(:lines, :x=>:id).set_graph_aliases(:x=>:points, :y=>:lines)
202
- ['SELECT points.x, lines.y FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)',
203
- 'SELECT lines.y, points.x FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)'
204
- ].should(include(ds.sql))
205
- end
206
-
207
- it "#set_graph_aliases should only alias columns if necessary" do
208
- ds = @ds1.set_graph_aliases(:x=>[:points, :x], :y=>[:lines, :y])
209
- ['SELECT points.x, lines.y FROM points',
210
- 'SELECT lines.y, points.x FROM points'
211
- ].should(include(ds.sql))
212
-
213
- ds = @ds1.set_graph_aliases(:x1=>[:points, :x], :y=>[:lines, :y])
214
- ['SELECT points.x AS x1, lines.y FROM points',
215
- 'SELECT lines.y, points.x AS x1 FROM points'
216
- ].should(include(ds.sql))
217
- end
218
-
219
- it "#ungraphed should remove the splitting of result sets into component tables" do
220
- @db.fetch = {:id=>1,:x=>2,:y=>3,:lines_id=>4,:lines_x=>5,:lines_y=>6,:graph_id=>7}
221
- @ds1.graph(@ds2, :x=>:id).ungraphed.all.should == [{:id=>1,:x=>2,:y=>3,:lines_id=>4,:lines_x=>5,:lines_y=>6,:graph_id=>7}]
271
+ describe "#ungraphed" do
272
+ it "should remove the splitting of result sets into component tables" do
273
+ @db.fetch = {:id=>1,:x=>2,:y=>3,:lines_id=>4,:lines_x=>5,:lines_y=>6,:graph_id=>7}
274
+ @ds1.graph(@ds2, :x=>:id).ungraphed.all.should == [{:id=>1,:x=>2,:y=>3,:lines_id=>4,:lines_x=>5,:lines_y=>6,:graph_id=>7}]
275
+ end
222
276
  end
223
277
  end