sequel 2.6.0 → 2.7.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. data/CHANGELOG +64 -0
  2. data/Rakefile +1 -1
  3. data/lib/sequel_core/adapters/jdbc.rb +6 -2
  4. data/lib/sequel_core/adapters/jdbc/oracle.rb +23 -0
  5. data/lib/sequel_core/adapters/oracle.rb +4 -77
  6. data/lib/sequel_core/adapters/postgres.rb +39 -26
  7. data/lib/sequel_core/adapters/shared/mssql.rb +0 -1
  8. data/lib/sequel_core/adapters/shared/mysql.rb +1 -1
  9. data/lib/sequel_core/adapters/shared/oracle.rb +82 -0
  10. data/lib/sequel_core/adapters/shared/postgres.rb +65 -46
  11. data/lib/sequel_core/core_ext.rb +10 -0
  12. data/lib/sequel_core/core_sql.rb +7 -0
  13. data/lib/sequel_core/database.rb +22 -0
  14. data/lib/sequel_core/database/schema.rb +1 -1
  15. data/lib/sequel_core/dataset.rb +29 -11
  16. data/lib/sequel_core/dataset/sql.rb +27 -7
  17. data/lib/sequel_core/migration.rb +20 -2
  18. data/lib/sequel_core/object_graph.rb +24 -10
  19. data/lib/sequel_core/schema/generator.rb +22 -9
  20. data/lib/sequel_core/schema/sql.rb +13 -9
  21. data/lib/sequel_core/sql.rb +27 -2
  22. data/lib/sequel_model/association_reflection.rb +251 -141
  23. data/lib/sequel_model/associations.rb +114 -61
  24. data/lib/sequel_model/base.rb +25 -21
  25. data/lib/sequel_model/eager_loading.rb +17 -40
  26. data/lib/sequel_model/hooks.rb +25 -24
  27. data/lib/sequel_model/record.rb +29 -51
  28. data/lib/sequel_model/schema.rb +1 -1
  29. data/lib/sequel_model/validations.rb +13 -3
  30. data/spec/adapters/postgres_spec.rb +104 -18
  31. data/spec/adapters/spec_helper.rb +4 -1
  32. data/spec/integration/eager_loader_test.rb +5 -4
  33. data/spec/integration/spec_helper.rb +4 -1
  34. data/spec/sequel_core/connection_pool_spec.rb +24 -24
  35. data/spec/sequel_core/core_sql_spec.rb +12 -0
  36. data/spec/sequel_core/dataset_spec.rb +77 -2
  37. data/spec/sequel_core/expression_filters_spec.rb +6 -0
  38. data/spec/sequel_core/object_graph_spec.rb +40 -2
  39. data/spec/sequel_core/schema_spec.rb +13 -0
  40. data/spec/sequel_model/association_reflection_spec.rb +8 -8
  41. data/spec/sequel_model/associations_spec.rb +164 -3
  42. data/spec/sequel_model/caching_spec.rb +2 -1
  43. data/spec/sequel_model/eager_loading_spec.rb +107 -3
  44. data/spec/sequel_model/hooks_spec.rb +38 -22
  45. data/spec/sequel_model/model_spec.rb +11 -35
  46. data/spec/sequel_model/plugins_spec.rb +4 -2
  47. data/spec/sequel_model/record_spec.rb +8 -5
  48. data/spec/sequel_model/validations_spec.rb +25 -0
  49. data/spec/spec_config.rb +4 -3
  50. metadata +21 -19
@@ -4,4 +4,7 @@ unless Object.const_defined?('Sequel')
4
4
  require 'sequel_core'
5
5
  Sequel.quote_identifiers = false
6
6
  end
7
- require File.join(File.dirname(__FILE__), '../spec_config.rb')
7
+ begin
8
+ require File.join(File.dirname(__FILE__), '../spec_config.rb')
9
+ rescue LoadError
10
+ end
@@ -228,7 +228,6 @@ describe "has_many :through has_many and has_one :through belongs_to" do
228
228
  firms.each{|firm| firm.associations[:invoices] = []}
229
229
  Invoice.eager_graph(:client).filter(:client__firm_id=>id_map.keys).all do |inv|
230
230
  id_map[inv.client.firm_id].each do |firm|
231
- inv.client.associations[:firm] = inv.associations[:firm] = firm
232
231
  firm.associations[:invoices] << inv
233
232
  end
234
233
  end
@@ -255,20 +254,22 @@ describe "has_many :through has_many and has_one :through belongs_to" do
255
254
  :after_load=>(proc do |inv, firm|
256
255
  # Delete the cached associations from firm, because it only has the
257
256
  # client with this invoice, instead of all clients of the firm
258
- inv.associations[:client] = firm.associations.delete(:clients).first
257
+ if c = firm.associations.delete(:clients)
258
+ firm.associations[:invoice_client] = c.first
259
+ end
260
+ inv.associations[:client] ||= firm.associations[:invoice_client]
259
261
  end), \
260
262
  :eager_loader=>(proc do |key_hash, invoices, associations|
261
263
  id_map = {}
262
264
  invoices.each do |inv|
263
265
  inv.associations[:firm] = nil
264
- inv.associations[:client] = nil
265
266
  (id_map[inv.client_id] ||= []) << inv
266
267
  end
267
268
  Firm.eager_graph(:clients).filter(:clients__id=>id_map.keys).all do |firm|
268
269
  # Delete the cached associations from firm, because it only has the
269
270
  # clients related the invoices being eagerly loaded, instead of all
270
271
  # clients of the firm.
271
- firm.associations.delete(:clients).each do |client|
272
+ firm.associations[:clients].each do |client|
272
273
  id_map[client.pk].each do |inv|
273
274
  inv.associations[:firm] = firm
274
275
  inv.associations[:client] = client
@@ -3,7 +3,10 @@ unless Object.const_defined?('Sequel')
3
3
  $:.unshift(File.join(File.dirname(__FILE__), "../../lib/"))
4
4
  require 'sequel'
5
5
  end
6
- require File.join(File.dirname(__FILE__), '../spec_config.rb')
6
+ begin
7
+ require File.join(File.dirname(__FILE__), '../spec_config.rb')
8
+ rescue LoadError
9
+ end
7
10
 
8
11
  $sqls = []
9
12
  def clear_sqls
@@ -137,13 +137,13 @@ context "A connection pool with a max size of 1" do
137
137
  specify "should let only one thread access the connection at any time" do
138
138
  cc,c1, c2 = nil
139
139
 
140
- t1 = Thread.new {@pool.hold {|c| cc = c; c1 = c.dup; while c == 'herro';sleep 0.1;end}}
141
- sleep 0.2
140
+ t1 = Thread.new {@pool.hold {|c| cc = c; c1 = c.dup; while c == 'herro';sleep 0.01;end}}
141
+ sleep 0.02
142
142
  cc.should == 'herro'
143
143
  c1.should == 'herro'
144
144
 
145
- t2 = Thread.new {@pool.hold {|c| c2 = c.dup; while c == 'hello';sleep 0.1;end}}
146
- sleep 0.2
145
+ t2 = Thread.new {@pool.hold {|c| c2 = c.dup; while c == 'hello';sleep 0.01;end}}
146
+ sleep 0.02
147
147
 
148
148
  # connection held by t1
149
149
  t1.should be_alive
@@ -157,7 +157,7 @@ context "A connection pool with a max size of 1" do
157
157
  @pool.allocated.should == {t1=>cc}
158
158
 
159
159
  cc.gsub!('rr', 'll')
160
- sleep 0.5
160
+ sleep 0.05
161
161
 
162
162
  # connection held by t2
163
163
  t1.should_not be_alive
@@ -169,7 +169,7 @@ context "A connection pool with a max size of 1" do
169
169
  @pool.allocated.should == {t2=>cc}
170
170
 
171
171
  cc.gsub!('ll', 'rr')
172
- sleep 0.5
172
+ sleep 0.05
173
173
 
174
174
  #connection released
175
175
  t2.should_not be_alive
@@ -215,8 +215,8 @@ context "A connection pool with a max size of 5" do
215
215
  threads = []
216
216
  stop = nil
217
217
 
218
- 5.times {|i| threads << Thread.new {@pool.hold {|c| cc[i] = c; while !stop;sleep 0.1;end}}; sleep 0.1}
219
- sleep 0.2
218
+ 5.times {|i| threads << Thread.new {@pool.hold {|c| cc[i] = c; while !stop;sleep 0.01;end}}; sleep 0.01}
219
+ sleep 0.02
220
220
  threads.each {|t| t.should be_alive}
221
221
  cc.size.should == 5
222
222
  @invoked_count.should == 5
@@ -228,16 +228,16 @@ context "A connection pool with a max size of 5" do
228
228
  @pool.allocated.should == h
229
229
 
230
230
  threads[0].raise "your'e dead"
231
- sleep 0.1
231
+ sleep 0.01
232
232
  threads[3].raise "your'e dead too"
233
233
 
234
- sleep 0.1
234
+ sleep 0.01
235
235
 
236
236
  @pool.available_connections.should == [1, 4]
237
237
  @pool.allocated.should == {threads[1]=>2, threads[2]=>3, threads[4]=>5}
238
238
 
239
239
  stop = true
240
- sleep 0.2
240
+ sleep 0.02
241
241
 
242
242
  @pool.available_connections.size.should == 5
243
243
  @pool.allocated.should be_empty
@@ -248,14 +248,14 @@ context "A connection pool with a max size of 5" do
248
248
  threads = []
249
249
  stop = nil
250
250
 
251
- 5.times {|i| threads << Thread.new {@pool.hold {|c| cc[i] = c; while !stop;sleep 0.1;end}}; sleep 0.1}
252
- sleep 0.2
251
+ 5.times {|i| threads << Thread.new {@pool.hold {|c| cc[i] = c; while !stop;sleep 0.01;end}}; sleep 0.01}
252
+ sleep 0.02
253
253
  threads.each {|t| t.should be_alive}
254
254
  @pool.available_connections.should be_empty
255
255
 
256
256
  3.times {|i| threads << Thread.new {@pool.hold {|c| cc[i + 5] = c}}}
257
257
 
258
- sleep 0.2
258
+ sleep 0.02
259
259
  threads[5].should be_alive
260
260
  threads[6].should be_alive
261
261
  threads[7].should be_alive
@@ -265,7 +265,7 @@ context "A connection pool with a max size of 5" do
265
265
  cc[7].should be_nil
266
266
 
267
267
  stop = true
268
- sleep 0.3
268
+ sleep 0.05
269
269
 
270
270
  threads.each {|t| t.should_not be_alive}
271
271
 
@@ -285,12 +285,12 @@ context "ConnectionPool#disconnect" do
285
285
  specify "should invoke the given block for each available connection" do
286
286
  threads = []
287
287
  stop = nil
288
- 5.times {|i| threads << Thread.new {@pool.hold {|c| while !stop;sleep 0.1;end}}; sleep 0.1}
288
+ 5.times {|i| threads << Thread.new {@pool.hold {|c| while !stop;sleep 0.01;end}}; sleep 0.01}
289
289
  while @pool.size < 5
290
- sleep 0.2
290
+ sleep 0.02
291
291
  end
292
292
  stop = true
293
- sleep 1
293
+ sleep 0.1
294
294
  threads.each {|t| t.join}
295
295
 
296
296
  @pool.size.should == 5
@@ -304,12 +304,12 @@ context "ConnectionPool#disconnect" do
304
304
  specify "should remove all available connections" do
305
305
  threads = []
306
306
  stop = nil
307
- 5.times {|i| threads << Thread.new {@pool.hold {|c| while !stop;sleep 0.1;end}}; sleep 0.1}
307
+ 5.times {|i| threads << Thread.new {@pool.hold {|c| while !stop;sleep 0.01;end}}; sleep 0.01}
308
308
  while @pool.size < 5
309
- sleep 0.2
309
+ sleep 0.02
310
310
  end
311
311
  stop = true
312
- sleep 1
312
+ sleep 0.1
313
313
  threads.each {|t| t.join}
314
314
 
315
315
  @pool.size.should == 5
@@ -320,12 +320,12 @@ context "ConnectionPool#disconnect" do
320
320
  specify "should not touch connections in use" do
321
321
  threads = []
322
322
  stop = nil
323
- 5.times {|i| threads << Thread.new {@pool.hold {|c| while !stop;sleep 0.1;end}}; sleep 0.1}
323
+ 5.times {|i| threads << Thread.new {@pool.hold {|c| while !stop;sleep 0.01;end}}; sleep 0.01}
324
324
  while @pool.size < 5
325
- sleep 0.2
325
+ sleep 0.02
326
326
  end
327
327
  stop = true
328
- sleep 1
328
+ sleep 0.1
329
329
  threads.each {|t| t.join}
330
330
 
331
331
  @pool.size.should == 5
@@ -51,6 +51,18 @@ context "Array#case and Hash#case" do
51
51
  end
52
52
  end
53
53
 
54
+ context "Array#sql_array" do
55
+ setup do
56
+ @d = Sequel::Dataset.new(nil)
57
+ end
58
+
59
+ specify "should treat the array as an SQL array instead of conditions" do
60
+ @d.literal([[:x, 1], [:y, 2]]).should == '((x = 1) AND (y = 2))'
61
+ @d.literal([[:x, 1], [:y, 2]].sql_array).should == '((x, 1), (y, 2))'
62
+ @d.filter([:a, :b]=>[[:x, 1], [:y, 2]].sql_array).sql.should == 'SELECT * WHERE ((a, b) IN ((x, 1), (y, 2)))'
63
+ end
64
+ end
65
+
54
66
  context "Array#to_sql" do
55
67
  specify "should concatenate multiple lines into a single string" do
56
68
  "SELECT * \r\nFROM items\r\n WHERE a = 1".split.to_sql. \
@@ -725,6 +725,15 @@ context "Dataset#from" do
725
725
  @dataset.from(:a[:i]).select_sql.should ==
726
726
  "SELECT * FROM a(i)"
727
727
  end
728
+
729
+ specify "should accept :schema__table___alias symbol format" do
730
+ @dataset.from(:abc__def).select_sql.should ==
731
+ "SELECT * FROM abc.def"
732
+ @dataset.from(:abc__def___d).select_sql.should ==
733
+ "SELECT * FROM abc.def AS d"
734
+ @dataset.from(:abc___def).select_sql.should ==
735
+ "SELECT * FROM abc AS def"
736
+ end
728
737
  end
729
738
 
730
739
  context "Dataset#select" do
@@ -1111,8 +1120,9 @@ context "Dataset#count" do
1111
1120
  end
1112
1121
 
1113
1122
  def fetch_rows(sql)
1123
+ @columns = [sql =~ /SELECT COUNT/i ? :count : :a]
1114
1124
  @@sql = sql
1115
- yield({1 => 1})
1125
+ yield({@columns.first=>1})
1116
1126
  end
1117
1127
  end
1118
1128
  @dataset = @c.new(nil).from(:test)
@@ -1148,6 +1158,14 @@ context "Dataset#count" do
1148
1158
  @dataset.graph(@dataset, [:a], :table_alias=>:test2).count.should == 1
1149
1159
  @c.sql.should == 'SELECT COUNT(*) FROM test LEFT OUTER JOIN test AS test2 USING (a) LIMIT 1'
1150
1160
  end
1161
+
1162
+ specify "should not cache the columns value" do
1163
+ ds = @dataset.from(:blah)
1164
+ ds.columns.should == [:a]
1165
+ ds.count.should == 1
1166
+ @c.sql.should == 'SELECT COUNT(*) FROM blah LIMIT 1'
1167
+ ds.columns.should == [:a]
1168
+ end
1151
1169
  end
1152
1170
 
1153
1171
 
@@ -1274,16 +1292,28 @@ context "Dataset#join_table" do
1274
1292
  'SELECT * FROM "items" INNER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
1275
1293
  end
1276
1294
 
1277
- specify "should support aliased tables" do
1295
+ specify "should support aliased tables using the deprecated argument" do
1278
1296
  @d.from('stats').join('players', {:id => :player_id}, 'p').sql.should ==
1279
1297
  'SELECT * FROM "stats" INNER JOIN "players" AS "p" ON ("p"."id" = "stats"."player_id")'
1298
+ end
1280
1299
 
1300
+ specify "should support aliased tables using the :table_alias option" do
1301
+ @d.from('stats').join('players', {:id => :player_id}, :table_alias=>:p).sql.should ==
1302
+ 'SELECT * FROM "stats" INNER JOIN "players" AS "p" ON ("p"."id" = "stats"."player_id")'
1303
+ end
1304
+
1305
+ specify "should support using an alias for the FROM when doing the first join with unqualified condition columns" do
1281
1306
  ds = MockDataset.new(nil).from(:foo => :f)
1282
1307
  ds.quote_identifiers = true
1283
1308
  ds.join_table(:inner, :bar, :id => :bar_id).sql.should ==
1284
1309
  'SELECT * FROM "foo" AS "f" INNER JOIN "bar" ON ("bar"."id" = "f"."bar_id")'
1285
1310
  end
1286
1311
 
1312
+ specify "should support the :implicit_qualifier option" do
1313
+ @d.from('stats').join('players', {:id => :player_id}, :implicit_qualifier=>:p).sql.should ==
1314
+ 'SELECT * FROM "stats" INNER JOIN "players" ON ("players"."id" = "p"."player_id")'
1315
+ end
1316
+
1287
1317
  specify "should allow for arbitrary conditions in the JOIN clause" do
1288
1318
  @d.join_table(:left_outer, :categories, :status => 0).sql.should ==
1289
1319
  'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."status" = 0)'
@@ -2953,6 +2983,11 @@ context "Dataset#grep" do
2953
2983
  @ds.grep(:title, [/^ruby/, 'ruby']).sql.should ==
2954
2984
  "SELECT * FROM posts WHERE (((title ~ '^ruby') OR (title LIKE 'ruby')))"
2955
2985
  end
2986
+
2987
+ specify "should support searching against other columns" do
2988
+ @ds.grep(:title, :body).sql.should ==
2989
+ "SELECT * FROM posts WHERE ((title LIKE body))"
2990
+ end
2956
2991
  end
2957
2992
 
2958
2993
  context "Sequel.use_parse_tree" do
@@ -3158,3 +3193,43 @@ context "Sequel::Dataset #set_overrides" do
3158
3193
  @ds.set_overrides(:x=>2).update_sql.should == "UPDATE items SET x = 1"
3159
3194
  end
3160
3195
  end
3196
+
3197
+ context "Sequel::Dataset#each" do
3198
+ before do
3199
+ @ds = Sequel::Dataset.new(nil).from(:items)
3200
+ def @ds.fetch_rows(sql)
3201
+ @columns = /count/i.match(sql) ? [:count] : [:a]
3202
+ yield({@columns.first=>sql})
3203
+ end
3204
+ end
3205
+
3206
+ specify "should not set the columns if passing an option that modifies them" do
3207
+ @ds.each(:select=>[:count]){}
3208
+ @ds.columns.should == [:a]
3209
+ @ds.each(:from=>[:count]){}
3210
+ @ds.columns.should == [:a]
3211
+ @ds.each(:join=>[Sequel::SQL::JoinClause.new(:natural, :count)]){}
3212
+ @ds.columns.should == [:a]
3213
+ @ds.each(:sql=>'SELECT COUNT'){}
3214
+ @ds.columns.should == [:a]
3215
+ end
3216
+
3217
+ specify "should have the correct columns inside the block regardless" do
3218
+ @ds.each(:select=>[:count]) do |x|
3219
+ x[:count].should == 'SELECT count FROM items'
3220
+ @ds.columns.should == [:count]
3221
+ end
3222
+ @ds.each(:from=>[:count]) do |x|
3223
+ x[:count].should == 'SELECT * FROM count'
3224
+ @ds.columns.should == [:count]
3225
+ end
3226
+ @ds.each(:join=>[Sequel::SQL::JoinClause.new(:natural, :count)]) do |x|
3227
+ x[:count].should == 'SELECT * FROM items NATURAL JOIN count'
3228
+ @ds.columns.should == [:count]
3229
+ end
3230
+ @ds.each(:sql=>'SELECT COUNT') do |x|
3231
+ x[:count].should == 'SELECT COUNT'
3232
+ @ds.columns.should == [:count]
3233
+ end
3234
+ end
3235
+ end
@@ -343,4 +343,10 @@ context "Blockless Ruby Filters" do
343
343
  ce.instance_variable_set(:@op, :BANG)
344
344
  proc{@d.lit(ce)}.should raise_error(Sequel::Error)
345
345
  end
346
+
347
+ it "should support equality comparison of two expressions" do
348
+ e1 = ~:comment.like('%:hidden:%')
349
+ e2 = ~:comment.like('%:hidden:%')
350
+ e1.should == e2
351
+ end
346
352
  end
@@ -55,6 +55,11 @@ describe Sequel::Dataset, " graphing" do
55
55
  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)'
56
56
  end
57
57
 
58
+ it "#graph should accept a :implicit_qualifier option" do
59
+ ds = @ds1.graph(:lines, {:x=>:id}, :implicit_qualifier=>:planes)
60
+ 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)'
61
+ end
62
+
58
63
  it "#graph should accept a :join_type option" do
59
64
  ds = @ds1.graph(:lines, {:x=>:id}, :join_type=>:inner)
60
65
  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)'
@@ -104,13 +109,19 @@ describe Sequel::Dataset, " graphing" do
104
109
  proc{@ds1.graph(@ds2, :x=>:id).graph(@ds2, {:x=>:id}, :table_alias=>:blah)}.should_not raise_error
105
110
  end
106
111
 
107
- it "#set_graph_aliases should not modify the current dataset's opts" do
112
+ it "#set_graph_aliases and #add_graph_aliases should not modify the current dataset's opts" do
108
113
  o1 = @ds1.opts
109
114
  o2 = o1.dup
110
115
  ds1 = @ds1.set_graph_aliases(:x=>[:graphs,:id])
111
116
  @ds1.opts.should == o1
112
117
  @ds1.opts.should == o2
113
118
  ds1.opts.should_not == o1
119
+ o3 = ds1.opts
120
+ o4 = o3.dup
121
+ ds2 = ds1.add_graph_aliases(:y=>[:blah,:id])
122
+ ds1.opts.should == o3
123
+ ds1.opts.should == o3
124
+ ds2.opts.should_not == o2
114
125
  end
115
126
 
116
127
  it "#set_graph_aliases should specify the graph mapping" do
@@ -122,6 +133,17 @@ describe Sequel::Dataset, " graphing" do
122
133
  ].should(include(ds.sql))
123
134
  end
124
135
 
136
+ it "#add_graph_aliases should add columns to the graph mapping" do
137
+ @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)'
138
+ end
139
+
140
+ it "#set_graph_aliases should allow a third entry to specify an expression to use other than the default" do
141
+ ds = @ds1.graph(:lines, :x=>:id).set_graph_aliases(:x=>[:points, :x, 1], :y=>[:lines, :y, :random[]])
142
+ ['SELECT 1 AS x, random() AS y FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)',
143
+ 'SELECT random() AS y, 1 AS x FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)'
144
+ ].should(include(ds.sql))
145
+ end
146
+
125
147
  it "#set_graph_aliases should only alias columns if necessary" do
126
148
  ds = @ds1.set_graph_aliases(:x=>[:points, :x], :y=>[:lines, :y])
127
149
  ['SELECT points.x, lines.y FROM points',
@@ -194,7 +216,7 @@ describe Sequel::Dataset, " graphing" do
194
216
  results.first.should == {:points=>{:id=>1, :x=>2, :y=>3}, :graphs=>{:id=>8, :name=>9, :x=>10, :y=>11, :lines_x=>12}}
195
217
  end
196
218
 
197
- it "#graph_each should only include the columns selected with #set_graph_aliases, if called" do
219
+ it "#graph_each should only include the columns selected with #set_graph_aliases and #add_graph_aliases, if called" do
198
220
  ds = @ds1.graph(:lines, :x=>:id).set_graph_aliases(:x=>[:points, :x], :y=>[:lines, :y])
199
221
  def ds.fetch_rows(sql, &block)
200
222
  yield({:x=>2,:y=>3})
@@ -210,6 +232,22 @@ describe Sequel::Dataset, " graphing" do
210
232
  results = ds.all
211
233
  results.length.should == 1
212
234
  results.first.should == {:points=>{:x=>2}, :lines=>nil}
235
+
236
+ ds = ds.add_graph_aliases(:q=>[:points, :r, 18])
237
+ def ds.fetch_rows(sql, &block)
238
+ yield({:x=>2, :q=>18})
239
+ end
240
+ ds.all.should == [{:points=>{:x=>2, :r=>18}, :lines=>nil}]
241
+ end
242
+
243
+ it "#graph_each should correctly map values when #set_graph_aliases is used with a third argument for each entry" do
244
+ ds = @ds1.graph(:lines, :x=>:id).set_graph_aliases(:x=>[:points, :z1, 2], :y=>[:lines, :z2, :random[]])
245
+ def ds.fetch_rows(sql, &block)
246
+ yield({:x=>2,:y=>3})
247
+ end
248
+ results = ds.all
249
+ results.length.should == 1
250
+ results.first.should == {:points=>{:z1=>2}, :lines=>{:z2=>3}}
213
251
  end
214
252
 
215
253
  it "#graph_each should run the row_proc and transform for graphed datasets" do
@@ -10,6 +10,19 @@ context "DB#create_table" do
10
10
  @db.sqls.should == ['CREATE TABLE cats ()']
11
11
  end
12
12
 
13
+ specify "should accept the table name in multiple formats" do
14
+ @db.create_table(:cats__cats) {}
15
+ @db.create_table("cats__cats1") {}
16
+ @db.create_table(:cats__cats2.identifier) {}
17
+ @db.create_table(:cats.qualify(:cats3)) {}
18
+ @db.sqls.should == ['CREATE TABLE cats.cats ()', 'CREATE TABLE cats__cats1 ()', 'CREATE TABLE cats__cats2 ()', 'CREATE TABLE cats3.cats ()']
19
+ end
20
+
21
+ specify "should raise an error if the table name argument is not valid" do
22
+ proc{@db.create_table(1) {}}.should raise_error(Sequel::Error)
23
+ proc{@db.create_table(:cats.as(:c)) {}}.should raise_error(Sequel::Error)
24
+ end
25
+
13
26
  specify "should accept multiple columns" do
14
27
  @db.create_table(:cats) do
15
28
  column :id, :integer