sequel 4.7.0 → 4.8.0

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