sequel_core 1.4.0 → 1.5.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 (51) hide show
  1. data/CHANGELOG +74 -0
  2. data/COPYING +1 -0
  3. data/README +17 -6
  4. data/Rakefile +16 -21
  5. data/lib/sequel_core.rb +18 -28
  6. data/lib/sequel_core/adapters/ado.rb +3 -15
  7. data/lib/sequel_core/adapters/dbi.rb +1 -14
  8. data/lib/sequel_core/adapters/informix.rb +3 -3
  9. data/lib/sequel_core/adapters/jdbc.rb +2 -2
  10. data/lib/sequel_core/adapters/mysql.rb +39 -59
  11. data/lib/sequel_core/adapters/odbc.rb +18 -38
  12. data/lib/sequel_core/adapters/openbase.rb +1 -17
  13. data/lib/sequel_core/adapters/oracle.rb +1 -19
  14. data/lib/sequel_core/adapters/postgres.rb +20 -60
  15. data/lib/sequel_core/adapters/sqlite.rb +4 -8
  16. data/lib/sequel_core/connection_pool.rb +150 -0
  17. data/lib/sequel_core/core_ext.rb +41 -0
  18. data/lib/sequel_core/core_sql.rb +35 -38
  19. data/lib/sequel_core/database.rb +20 -17
  20. data/lib/sequel_core/dataset.rb +49 -80
  21. data/lib/sequel_core/dataset/callback.rb +11 -13
  22. data/lib/sequel_core/dataset/convenience.rb +18 -136
  23. data/lib/sequel_core/dataset/pagination.rb +81 -0
  24. data/lib/sequel_core/dataset/sequelizer.rb +5 -4
  25. data/lib/sequel_core/dataset/sql.rb +43 -33
  26. data/lib/sequel_core/deprecated.rb +200 -0
  27. data/lib/sequel_core/exceptions.rb +0 -14
  28. data/lib/sequel_core/object_graph.rb +199 -0
  29. data/lib/sequel_core/pretty_table.rb +27 -24
  30. data/lib/sequel_core/schema/generator.rb +16 -4
  31. data/lib/sequel_core/schema/sql.rb +5 -3
  32. data/lib/sequel_core/worker.rb +1 -1
  33. data/spec/adapters/informix_spec.rb +1 -47
  34. data/spec/adapters/mysql_spec.rb +85 -54
  35. data/spec/adapters/oracle_spec.rb +1 -57
  36. data/spec/adapters/postgres_spec.rb +66 -49
  37. data/spec/adapters/sqlite_spec.rb +4 -29
  38. data/spec/connection_pool_spec.rb +358 -0
  39. data/spec/core_sql_spec.rb +24 -19
  40. data/spec/database_spec.rb +13 -9
  41. data/spec/dataset_spec.rb +59 -78
  42. data/spec/object_graph_spec.rb +202 -0
  43. data/spec/pretty_table_spec.rb +1 -9
  44. data/spec/schema_generator_spec.rb +7 -1
  45. data/spec/schema_spec.rb +27 -0
  46. data/spec/sequelizer_spec.rb +2 -2
  47. data/spec/spec_helper.rb +4 -2
  48. metadata +16 -57
  49. data/lib/sequel_core/array_keys.rb +0 -322
  50. data/lib/sequel_core/model.rb +0 -8
  51. data/spec/array_keys_spec.rb +0 -682
@@ -46,7 +46,7 @@ context "Database#uri" do
46
46
  set_adapter_scheme :mau
47
47
  end
48
48
 
49
- @db = Sequel('mau://user:pass@localhost:9876/maumau')
49
+ @db = Sequel.connect('mau://user:pass@localhost:9876/maumau')
50
50
  end
51
51
 
52
52
  specify "should return the connection URI for the database" do
@@ -442,10 +442,10 @@ context "Database#transaction" do
442
442
  proc {@db.transaction {raise RuntimeError}}.should raise_error(RuntimeError)
443
443
  end
444
444
 
445
- specify "should issue ROLLBACK if rollback! is called in the transaction" do
445
+ specify "should issue ROLLBACK if Sequel::Error::Rollback is called in the transaction" do
446
446
  @db.transaction do
447
447
  @db.drop_table(:a)
448
- rollback!
448
+ raise Sequel::Error::Rollback
449
449
  @db.drop_table(:b)
450
450
  end
451
451
 
@@ -506,6 +506,7 @@ context "A Database adapter with a scheme" do
506
506
  c.opts[:database].should == 'db'
507
507
  end
508
508
 
509
+ ### DEPRECATED
509
510
  specify "should be accessible through Sequel()" do
510
511
  c = Sequel('ccc://localhost/db')
511
512
  c.should be_a_kind_of(CCC)
@@ -514,24 +515,27 @@ context "A Database adapter with a scheme" do
514
515
  end
515
516
 
516
517
  specify "should be accessible through Sequel.<adapter>" do
518
+ class << Sequel
519
+ def_adapter_method(:ccc)
520
+ end
517
521
  # invalid parameters
518
522
  proc {Sequel.ccc('abc', 'def')}.should raise_error(Sequel::Error)
519
523
 
520
524
  c = Sequel.ccc('mydb')
521
525
  c.should be_a_kind_of(CCC)
522
- c.opts.should == {:database => 'mydb'}
526
+ c.opts.should == {:adapter=>:ccc, :database => 'mydb'}
523
527
 
524
528
  c = Sequel.ccc('mydb', :host => 'localhost')
525
529
  c.should be_a_kind_of(CCC)
526
- c.opts.should == {:database => 'mydb', :host => 'localhost'}
530
+ c.opts.should == {:adapter=>:ccc, :database => 'mydb', :host => 'localhost'}
527
531
 
528
532
  c = Sequel.ccc
529
533
  c.should be_a_kind_of(CCC)
530
- c.opts.should == {}
534
+ c.opts.should == {:adapter=>:ccc}
531
535
 
532
536
  c = Sequel.ccc(:database => 'mydb', :host => 'localhost')
533
537
  c.should be_a_kind_of(CCC)
534
- c.opts.should == {:database => 'mydb', :host => 'localhost'}
538
+ c.opts.should == {:adapter=>:ccc, :database => 'mydb', :host => 'localhost'}
535
539
  end
536
540
 
537
541
  specify "should be accessible through Sequel.connect with options" do
@@ -836,7 +840,7 @@ context "Database.connect" do
836
840
  end
837
841
 
838
842
  specify "should accept hashes loaded from YAML files" do
839
- db = Sequel(YAML.load_file(@fn)['development'])
843
+ db = Sequel.connect(YAML.load_file(@fn)['development'])
840
844
  db.class.should == EEE
841
845
  db.opts[:database].should == 'mydb'
842
846
  db.opts[:user].should == 'mau'
@@ -877,4 +881,4 @@ context "Database#get" do
877
881
  @db.get(:version[])
878
882
  @db.sqls.last.should == 'SELECT version()'
879
883
  end
880
- end
884
+ end
data/spec/dataset_spec.rb CHANGED
@@ -127,33 +127,20 @@ context "A simple dataset" do
127
127
  @dataset.insert_sql({}).should == "INSERT INTO test DEFAULT VALUES"
128
128
  end
129
129
 
130
- specify "should format an insert statement with array with keys" do
131
- v = [1, 2, 3]
132
- v.keys = [:a, :b, :c]
133
- @dataset.insert_sql(v).should == "INSERT INTO test (a, b, c) VALUES (1, 2, 3)"
134
-
135
- v = []
136
- v.keys = [:a, :b]
137
- @dataset.insert_sql(v).should == "INSERT INTO test DEFAULT VALUES"
138
- end
139
-
140
130
  specify "should format an insert statement with string keys" do
141
131
  @dataset.insert_sql('name' => 'wxyz', 'price' => 342).
142
132
  should match(/INSERT INTO test \(name, price\) VALUES \('wxyz', 342\)|INSERT INTO test \(price, name\) VALUES \(342, 'wxyz'\)/)
143
133
  end
144
134
 
145
- specify "should format an insert statement with a model instance" do
135
+ specify "should format an insert statement with an object that respond_to? :values" do
146
136
  dbb = Sequel::Database.new
147
137
 
148
- @c = Class.new(Sequel::Model) do
149
- attr_accessor :values
150
- end
151
-
152
- v = @c.new; v.values = {:a => 1}
138
+ v = Object.new
139
+ def v.values; {:a => 1}; end
153
140
 
154
141
  @dataset.insert_sql(v).should == "INSERT INTO test (a) VALUES (1)"
155
142
 
156
- v = @c.new; v.values = {}
143
+ def v.values; {}; end
157
144
  @dataset.insert_sql(v).should == "INSERT INTO test DEFAULT VALUES"
158
145
  end
159
146
 
@@ -180,13 +167,6 @@ context "A simple dataset" do
180
167
  "UPDATE test SET x = y"
181
168
  end
182
169
 
183
- specify "should format an update statement with array with keys" do
184
- v = ['abc']
185
- v.keys = [:name]
186
-
187
- @dataset.update_sql(v).should == "UPDATE test SET name = 'abc'"
188
- end
189
-
190
170
  specify "should be able to return rows for arbitrary SQL" do
191
171
  @dataset.select_sql(:sql => 'xxx yyy zzz').should ==
192
172
  "xxx yyy zzz"
@@ -332,7 +312,7 @@ context "Dataset#where" do
332
312
 
333
313
  specify "should accept a subquery" do
334
314
  # select all countries that have GDP greater than the average for Asia
335
- @dataset.filter('gdp > ?', @d1.select(:gdp.AVG)).sql.should ==
315
+ @dataset.filter('gdp > ?', @d1.select(:avg[:gdp])).sql.should ==
336
316
  "SELECT * FROM test WHERE gdp > (SELECT avg(gdp) FROM test WHERE (region = 'Asia'))"
337
317
 
338
318
  @dataset.filter(:id => @d1.select(:id)).sql.should ==
@@ -346,7 +326,7 @@ context "Dataset#where" do
346
326
  end
347
327
 
348
328
  specify "should accept proc expressions" do
349
- d = @d1.select(:gdp.AVG)
329
+ d = @d1.select(:avg[:gdp])
350
330
  @dataset.filter {:gdp > d}.sql.should ==
351
331
  "SELECT * FROM test WHERE (gdp > (SELECT avg(gdp) FROM test WHERE (region = 'Asia')))"
352
332
 
@@ -501,7 +481,7 @@ end
501
481
  context "Dataset#having" do
502
482
  setup do
503
483
  @dataset = Sequel::Dataset.new(nil).from(:test)
504
- @grouped = @dataset.group(:region).select(:region, :population.SUM, :gdp.AVG)
484
+ @grouped = @dataset.group(:region).select(:region, :sum[:population], :avg[:gdp])
505
485
  @d1 = @grouped.having('sum(population) > 10')
506
486
  @d2 = @grouped.having(:region => 'Asia')
507
487
  @columns = "region, sum(population), avg(gdp)"
@@ -581,6 +561,9 @@ context "Dataset#literal" do
581
561
  @dataset.literal('a"x"bc').should == "'a\"x\"bc'"
582
562
  @dataset.literal("a'bc").should == "'a''bc'"
583
563
  @dataset.literal("a''bc").should == "'a''''bc'"
564
+ @dataset.literal("a\\bc").should == "'a\\\\bc'"
565
+ @dataset.literal("a\\\\bc").should == "'a\\\\\\\\bc'"
566
+ @dataset.literal("a\\'bc").should == "'a\\\\''bc'"
584
567
  end
585
568
 
586
569
  specify "should literalize numbers properly" do
@@ -718,9 +701,9 @@ context "Dataset#select" do
718
701
  'SELECT test.d AS e, test.cc FROM test'
719
702
 
720
703
  # symbol helpers
721
- @d.select(:test.ALL).sql.should ==
704
+ @d.select(:test.*).sql.should ==
722
705
  'SELECT test.* FROM test'
723
- @d.select(:test__name.AS(:n)).sql.should ==
706
+ @d.select(:test__name.as(:n)).sql.should ==
724
707
  'SELECT test.name AS n FROM test'
725
708
  @d.select(:test__name___n).sql.should ==
726
709
  'SELECT test.name AS n FROM test'
@@ -776,7 +759,7 @@ context "Dataset#select_more" do
776
759
 
777
760
  specify "should add to the currently selected columns" do
778
761
  @d.select(:a).select_more(:b).sql.should == 'SELECT a, b FROM test'
779
- @d.select(:a.all).select_more(:b.all).sql.should == 'SELECT a.*, b.* FROM test'
762
+ @d.select(:a.*).select_more(:b.*).sql.should == 'SELECT a.*, b.* FROM test'
780
763
  end
781
764
  end
782
765
 
@@ -791,7 +774,7 @@ context "Dataset#order" do
791
774
  end
792
775
 
793
776
  specify "should accept multiple arguments" do
794
- @dataset.order(:name, :price.DESC).sql.should ==
777
+ @dataset.order(:name, :price.desc).sql.should ==
795
778
  'SELECT * FROM test ORDER BY name, price DESC'
796
779
  end
797
780
 
@@ -833,7 +816,7 @@ context "Dataset#order_by" do
833
816
  end
834
817
 
835
818
  specify "should accept multiple arguments" do
836
- @dataset.order_by(:name, :price.DESC).sql.should ==
819
+ @dataset.order_by(:name, :price.desc).sql.should ==
837
820
  'SELECT * FROM test ORDER BY name, price DESC'
838
821
  end
839
822
 
@@ -864,7 +847,7 @@ context "Dataset#order_more" do
864
847
  end
865
848
 
866
849
  specify "should add to a previous ordering" do
867
- @dataset.order(:name).order_more(:stamp.DESC).sql.should ==
850
+ @dataset.order(:name).order_more(:stamp.desc).sql.should ==
868
851
  'SELECT * FROM test ORDER BY name, stamp DESC'
869
852
  end
870
853
  end
@@ -880,24 +863,24 @@ context "Dataset#reverse_order" do
880
863
  end
881
864
 
882
865
  specify "should invert the order given" do
883
- @dataset.reverse_order(:name.DESC).sql.should ==
866
+ @dataset.reverse_order(:name.desc).sql.should ==
884
867
  'SELECT * FROM test ORDER BY name'
885
868
  end
886
869
 
887
870
  specify "should invert the order for ASC expressions" do
888
- @dataset.reverse_order(:name.ASC).sql.should ==
871
+ @dataset.reverse_order(:name.asc).sql.should ==
889
872
  'SELECT * FROM test ORDER BY name DESC'
890
873
  end
891
874
 
892
875
  specify "should accept multiple arguments" do
893
- @dataset.reverse_order(:name, :price.DESC).sql.should ==
876
+ @dataset.reverse_order(:name, :price.desc).sql.should ==
894
877
  'SELECT * FROM test ORDER BY name DESC, price'
895
878
  end
896
879
 
897
880
  specify "should reverse a previous ordering if no arguments are given" do
898
881
  @dataset.order(:name).reverse_order.sql.should ==
899
882
  'SELECT * FROM test ORDER BY name DESC'
900
- @dataset.order(:clumsy.DESC, :fool).reverse_order.sql.should ==
883
+ @dataset.order(:clumsy.desc, :fool).reverse_order.sql.should ==
901
884
  'SELECT * FROM test ORDER BY clumsy, fool DESC'
902
885
  end
903
886
 
@@ -965,13 +948,13 @@ context "Dataset#qualified_column_name" do
965
948
  end
966
949
 
967
950
  specify "should return the same if already qualified" do
968
- @dataset.qualified_column_name('test.a'.lit, :items).should == 'test.a'
969
- @dataset.qualified_column_name(:ccc__b, :items).should == :ccc__b
951
+ @dataset.send(:qualified_column_name, 'test.a'.lit, :items).should == 'test.a'
952
+ @dataset.send(:qualified_column_name, :ccc__b, :items).should == :ccc__b
970
953
  end
971
954
 
972
955
  specify "should qualify the column with the supplied table name" do
973
- @dataset.qualified_column_name('a'.lit, :items).to_s(@dataset).should == 'items.a'
974
- @dataset.qualified_column_name(:b1, :items).to_s(@dataset).should == 'items.b1'
956
+ @dataset.send(:qualified_column_name, 'a'.lit, :items).to_s(@dataset).should == 'items.a'
957
+ @dataset.send(:qualified_column_name, :b1, :items).to_s(@dataset).should == 'items.b1'
975
958
  end
976
959
  end
977
960
 
@@ -1250,6 +1233,17 @@ context "Dataset#join_table" do
1250
1233
  'SELECT * FROM items LEFT OUTER JOIN (SELECT * FROM categories WHERE (active = \'t\')) t1 ON (t1.item_id = items.id)'
1251
1234
  end
1252
1235
 
1236
+ specify "should support joining multiple datasets" do
1237
+ ds = Sequel::Dataset.new(nil).from(:categories)
1238
+ ds2 = Sequel::Dataset.new(nil).from(:nodes).select(:name)
1239
+ ds3 = Sequel::Dataset.new(nil).from(:attributes).filter("name = 'blah'")
1240
+
1241
+ @d.join_table(:left_outer, ds, :item_id => :id).join_table(:inner, ds2, :node_id=>:id).join_table(:right_outer, ds3, :attribute_id=>:id).sql.should ==
1242
+ 'SELECT * FROM items LEFT OUTER JOIN (SELECT * FROM categories) t1 ON (t1.item_id = items.id) ' \
1243
+ 'INNER JOIN (SELECT name FROM nodes) t2 ON (t2.node_id = t1.id) ' \
1244
+ "RIGHT OUTER JOIN (SELECT * FROM attributes WHERE name = 'blah') t3 ON (t3.attribute_id = t2.id)"
1245
+ end
1246
+
1253
1247
  specify "should support joining objects that respond to :table_name" do
1254
1248
  ds = Object.new
1255
1249
  def ds.table_name; :categories end
@@ -1515,16 +1509,16 @@ context "Dataset#last" do
1515
1509
 
1516
1510
  specify "should invert the order" do
1517
1511
  @d.order(:a).last
1518
- @d.literal(@c.last_dataset.opts[:order]).should == @d.literal([:a.DESC])
1512
+ @d.literal(@c.last_dataset.opts[:order]).should == @d.literal([:a.desc])
1519
1513
 
1520
- @d.order(:b.DESC).last
1514
+ @d.order(:b.desc).last
1521
1515
  @d.literal(@c.last_dataset.opts[:order]).should == @d.literal(:b)
1522
1516
 
1523
1517
  @d.order(:c, :d).last
1524
- @d.literal(@c.last_dataset.opts[:order]).should == @d.literal([:c.DESC, :d.DESC])
1518
+ @d.literal(@c.last_dataset.opts[:order]).should == @d.literal([:c.desc, :d.desc])
1525
1519
 
1526
- @d.order(:e.DESC, :f).last
1527
- @d.literal(@c.last_dataset.opts[:order]).should == @d.literal([:e, :f.DESC])
1520
+ @d.order(:e.desc, :f).last
1521
+ @d.literal(@c.last_dataset.opts[:order]).should == @d.literal([:e, :f.desc])
1528
1522
  end
1529
1523
 
1530
1524
  specify "should return the first matching record if a hash is specified" do
@@ -1704,7 +1698,7 @@ context "Dataset#set_row_proc" do
1704
1698
  end
1705
1699
 
1706
1700
  specify "should cause dataset to pass all rows through the filter" do
1707
- @dataset.set_row_proc {|h| h[:der] = h[:kind] + 2; h}
1701
+ @dataset.row_proc = proc{|h| h[:der] = h[:kind] + 2; h}
1708
1702
 
1709
1703
  rows = @dataset.all
1710
1704
  rows.size.should == 10
@@ -1713,7 +1707,7 @@ context "Dataset#set_row_proc" do
1713
1707
  end
1714
1708
 
1715
1709
  specify "should be copied over when dataset is cloned" do
1716
- @dataset.set_row_proc {|h| h[:der] = h[:kind] + 2; h}
1710
+ @dataset.row_proc = proc{|h| h[:der] = h[:kind] + 2; h}
1717
1711
 
1718
1712
  @dataset.filter(:a => 1).first.should == {:kind => 1, :der => 3}
1719
1713
  end
@@ -2039,6 +2033,11 @@ context "A paginated dataset" do
2039
2033
  @paginated = @d.paginate(1, 20)
2040
2034
  end
2041
2035
 
2036
+ specify "should raise an error if the dataset already has a limit" do
2037
+ proc{@d.limit(10).paginate(1,10)}.should raise_error(Sequel::Error)
2038
+ proc{@paginated.paginate(2,20)}.should raise_error(Sequel::Error)
2039
+ end
2040
+
2042
2041
  specify "should set the limit and offset options correctly" do
2043
2042
  @paginated.opts[:limit].should == 20
2044
2043
  @paginated.opts[:offset].should == 0
@@ -2095,6 +2094,10 @@ context "Dataset#each_page" do
2095
2094
  @d.meta_def(:count) {153}
2096
2095
  end
2097
2096
 
2097
+ specify "should raise an error if the dataset already has a limit" do
2098
+ proc{@d.limit(10).each_page(10){}}.should raise_error(Sequel::Error)
2099
+ end
2100
+
2098
2101
  specify "should iterate over each page in the resultset as a paginated dataset" do
2099
2102
  a = []
2100
2103
  @d.each_page(50) {|p| a << p}
@@ -2484,7 +2487,7 @@ context "Dataset#transform" do
2484
2487
  end
2485
2488
 
2486
2489
  specify "should work correctly together with set_row_proc" do
2487
- @ds.set_row_proc {|r| r[:z] = r[:x] * 2; r}
2490
+ @ds.row_proc = proc{|r| r[:z] = r[:x] * 2; r}
2488
2491
  @ds.raw = {:x => Marshal.dump("wow"), :y => 'hello'}
2489
2492
  @ds.first.should == {:x => "wow", :y => 'hello', :z => "wowwow"}
2490
2493
 
@@ -2550,7 +2553,7 @@ context "Dataset#transform" do
2550
2553
  @ds2.insert(:x => :toast)
2551
2554
  @ds2.sql.should == "INSERT INTO items (x) VALUES ('#{:toast.to_yaml}')"
2552
2555
 
2553
- @ds.set_row_proc {|r| r[:z] = r[:x] * 2; r}
2556
+ @ds.row_proc = proc{|r| r[:z] = r[:x] * 2; r}
2554
2557
  @ds.raw = {:x => "wow".to_yaml, :y => 'hello'}
2555
2558
  @ds.first.should == {:x => "wow", :y => 'hello', :z => "wowwow"}
2556
2559
  f = nil
@@ -2578,7 +2581,7 @@ context "Dataset#transform" do
2578
2581
  @ds2.insert(:x => :toast)
2579
2582
  @ds2.sql.should == "INSERT INTO items (x) VALUES ('#{Base64.encode64(Marshal.dump(:toast))}')"
2580
2583
 
2581
- @ds.set_row_proc {|r| r[:z] = r[:x] * 2; r}
2584
+ @ds.row_proc = proc{|r| r[:z] = r[:x] * 2; r}
2582
2585
  @ds.raw = {:x => Base64.encode64(Marshal.dump("wow")), :y => 'hello'}
2583
2586
  @ds.first.should == {:x => "wow", :y => 'hello', :z => "wowwow"}
2584
2587
  f = nil
@@ -2616,11 +2619,10 @@ context "Dataset#to_csv" do
2616
2619
  setup do
2617
2620
  @c = Class.new(Sequel::Dataset) do
2618
2621
  attr_accessor :data
2619
- attr_accessor :cols
2622
+ attr_accessor :columns
2620
2623
 
2621
2624
  def fetch_rows(sql, &block)
2622
- @columns = @cols
2623
- @data.each {|r| r.keys = @columns; block[r]}
2625
+ @data.each(&block)
2624
2626
  end
2625
2627
 
2626
2628
  # naked should return self here because to_csv wants a naked result set.
@@ -2630,11 +2632,8 @@ context "Dataset#to_csv" do
2630
2632
  end
2631
2633
 
2632
2634
  @ds = @c.new(nil).from(:items)
2633
-
2634
- @ds.cols = [:a, :b, :c]
2635
- @ds.data = [
2636
- [1, 2, 3], [4, 5, 6], [7, 8, 9]
2637
- ]
2635
+ @ds.columns = [:a, :b, :c]
2636
+ @ds.data = [ {:a=>1, :b=>2, :c=>3}, {:a=>4, :b=>5, :c=>6}, {:a=>7, :b=>8, :c=>9} ]
2638
2637
  end
2639
2638
 
2640
2639
  specify "should format a CSV representation of the records" do
@@ -2648,25 +2647,7 @@ context "Dataset#to_csv" do
2648
2647
  end
2649
2648
  end
2650
2649
 
2651
- context "Dataset#each_hash" do
2652
- setup do
2653
- @c = Class.new(Sequel::Dataset) do
2654
- def each(&block)
2655
- a = [[1, 2, 3], [4, 5, 6]]
2656
- a.each {|r| r.keys = [:a, :b, :c]; block[r]}
2657
- end
2658
- end
2659
-
2660
- @ds = @c.new(nil).from(:items)
2661
- end
2662
-
2663
- specify "should yield records converted to hashes" do
2664
- hashes = []
2665
- @ds.each_hash {|h| hashes << h}
2666
- hashes.should == [{:a => 1, :b => 2, :c => 3}, {:a => 4, :b => 5, :c => 6}]
2667
- end
2668
- end
2669
-
2650
+ ### DEPRECATED
2670
2651
  context "Dataset magic methods" do
2671
2652
  setup do
2672
2653
  @c = Class.new(Sequel::Dataset) do
@@ -0,0 +1,202 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ describe Sequel::Dataset, " graphing" do
4
+ before do
5
+ dbc = Class.new
6
+ @db = dbc.new
7
+ @ds1 = Sequel::Dataset.new(@db).from(:points)
8
+ @ds2 = Sequel::Dataset.new(@db).from(:lines)
9
+ @ds3 = Sequel::Dataset.new(@db).from(:graphs)
10
+ dss = {:points=>@ds1, :lines=>@ds2, :graphs=>@ds3}
11
+ dbc.send(:define_method, :[]){|ds| dss[ds]}
12
+ def @ds1.columns; [:id, :x, :y] end
13
+ def @ds2.columns; [:id, :x, :y, :graph_id] end
14
+ def @ds3.columns; [:id, :name, :x, :y, :lines_x] end
15
+ end
16
+
17
+ it "#graph should not modify the current dataset's opts" do
18
+ o1 = @ds1.opts
19
+ o2 = o1.dup
20
+ ds1 = @ds1.graph(@ds2, :x=>:id)
21
+ @ds1.opts.should == o1
22
+ @ds1.opts.should == o2
23
+ ds1.opts.should_not == o1
24
+ end
25
+
26
+ it "#graph should accept a dataset as the dataset" do
27
+ ds = @ds1.graph(@ds2, :x=>:id)
28
+ 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)'
29
+ end
30
+
31
+ it "#graph should accept a symbol table name as the dataset" do
32
+ ds = @ds1.graph(:lines, :x=>:id)
33
+ 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)'
34
+ end
35
+
36
+ it "#graph should accept an object that responds to dataset as the dataset" do
37
+ oc = Class.new
38
+ o = oc.new
39
+ ds = @ds2
40
+ oc.send(:define_method, :dataset){ds}
41
+ ds = @ds1.graph(o, :x=>:id)
42
+ 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)'
43
+ ds = :lines
44
+ oc.send(:define_method, :dataset){ds}
45
+ ds = @ds1.graph(o, :x=>:id)
46
+ 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)'
47
+ end
48
+
49
+ it "#graph should accept a :table_alias option" do
50
+ ds = @ds1.graph(:lines, {:x=>:id}, :table_alias=>:planes)
51
+ 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 planes ON (planes.x = points.id)'
52
+ end
53
+
54
+ it "#graph should accept a :join_type option" do
55
+ ds = @ds1.graph(:lines, {:x=>:id}, :join_type=>:inner)
56
+ 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)'
57
+ end
58
+
59
+ it "#graph should accept a :select_option" do
60
+ ds = @ds1.graph(:lines, {:x=>:id}, :select=>false).graph(:graphs, :id=>:graph_id)
61
+ 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)'
62
+ end
63
+
64
+ it "#graph should pass all join_conditions to join_table" do
65
+ ds = @ds1.graph(@ds2, :x=>:id, :y=>:id)
66
+ ['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)',
67
+ '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.y = points.id) AND (lines.x = points.id)'
68
+ ].should(include(ds.sql))
69
+ end
70
+
71
+ it "#graph should not add columns if graph is called after set_graph_aliases" do
72
+ ds = @ds1.set_graph_aliases(:x=>[:points, :x], :y=>[:lines, :y])
73
+ ['SELECT points.x, lines.y FROM points',
74
+ 'SELECT lines.y, points.x FROM points'
75
+ ].should(include(ds.sql))
76
+ ds = ds.graph(:lines, :x=>:id)
77
+ ['SELECT points.x, lines.y FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)',
78
+ 'SELECT lines.y, points.x FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)'
79
+ ].should(include(ds.sql))
80
+ end
81
+
82
+ it "#graph should allow graphing of multiple datasets" do
83
+ ds = @ds1.graph(@ds2, :x=>:id).graph(@ds3, :id=>:graph_id)
84
+ 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)'
85
+ end
86
+
87
+ it "#graph should allow graphing of the same dataset multiple times" do
88
+ ds = @ds1.graph(@ds2, :x=>:id).graph(@ds2, {:y=>:points__id}, :table_alias=>:graph)
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, 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 graph ON (graph.y = points.id)'
90
+ end
91
+
92
+ it "#graph should raise an error if the table/table alias has already been used" do
93
+ proc{@ds1.graph(@ds1, :x=>:id)}.should raise_error(Sequel::Error)
94
+ proc{@ds1.graph(@ds2, :x=>:id)}.should_not raise_error
95
+ proc{@ds1.graph(@ds2, :x=>:id).graph(@ds2, :x=>:id)}.should raise_error(Sequel::Error)
96
+ proc{@ds1.graph(@ds2, :x=>:id).graph(@ds2, {:x=>:id}, :table_alias=>:blah)}.should_not raise_error
97
+ end
98
+
99
+ it "#set_graph_aliases should not modify the current dataset's opts" do
100
+ o1 = @ds1.opts
101
+ o2 = o1.dup
102
+ ds1 = @ds1.set_graph_aliases(:x=>[:graphs,:id])
103
+ @ds1.opts.should == o1
104
+ @ds1.opts.should == o2
105
+ ds1.opts.should_not == o1
106
+ end
107
+
108
+ it "#set_graph_aliases should specify the graph mapping" do
109
+ ds = @ds1.graph(:lines, :x=>:id)
110
+ 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)'
111
+ ds = ds.set_graph_aliases(:x=>[:points, :x], :y=>[:lines, :y])
112
+ ['SELECT points.x, lines.y FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)',
113
+ 'SELECT lines.y, points.x FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)'
114
+ ].should(include(ds.sql))
115
+ end
116
+
117
+ it "#set_graph_aliases should only alias columns if necessary" do
118
+ ds = @ds1.set_graph_aliases(:x=>[:points, :x], :y=>[:lines, :y])
119
+ ['SELECT points.x, lines.y FROM points',
120
+ 'SELECT lines.y, points.x FROM points'
121
+ ].should(include(ds.sql))
122
+
123
+ ds = @ds1.set_graph_aliases(:x1=>[:points, :x], :y=>[:lines, :y])
124
+ ['SELECT points.x AS x1, lines.y FROM points',
125
+ 'SELECT lines.y, points.x AS x1 FROM points'
126
+ ].should(include(ds.sql))
127
+ end
128
+
129
+ it "#graph_each should split the result set into component tables" do
130
+ ds = @ds1.graph(@ds2, :x=>:id)
131
+ def ds.fetch_rows(sql, &block)
132
+ yield({:id=>1,:x=>2,:y=>3,:lines_id=>4,:lines_x=>5,:lines_y=>6,:graph_id=>7})
133
+ end
134
+ results = ds.all
135
+ results.length.should == 1
136
+ results.first.should == {:points=>{:id=>1, :x=>2, :y=>3}, :lines=>{:id=>4, :x=>5, :y=>6, :graph_id=>7}}
137
+
138
+ ds = @ds1.graph(@ds2, :x=>:id).graph(@ds3, :id=>:graph_id)
139
+ def ds.fetch_rows(sql, &block)
140
+ yield({:id=>1,:x=>2,:y=>3,:lines_id=>4,:lines_x=>5,:lines_y=>6,:graph_id=>7, :graphs_id=>8, :name=>9, :graphs_x=>10, :graphs_y=>11, :graphs_lines_x=>12})
141
+ end
142
+ results = ds.all
143
+ results.length.should == 1
144
+ results.first.should == {:points=>{:id=>1, :x=>2, :y=>3}, :lines=>{:id=>4, :x=>5, :y=>6, :graph_id=>7}, :graphs=>{:id=>8, :name=>9, :x=>10, :y=>11, :lines_x=>12}}
145
+
146
+ ds = @ds1.graph(@ds2, :x=>:id).graph(@ds2, {:y=>:points__id}, :table_alias=>:graph)
147
+ def ds.fetch_rows(sql, &block)
148
+ yield({:id=>1,:x=>2,:y=>3,:lines_id=>4,:lines_x=>5,:lines_y=>6,:graph_id=>7, :graph_id_0=>8, :graph_x=>9, :graph_y=>10, :graph_graph_id=>11})
149
+ end
150
+ results = ds.all
151
+ results.length.should == 1
152
+ results.first.should == {:points=>{:id=>1, :x=>2, :y=>3}, :lines=>{:id=>4, :x=>5, :y=>6, :graph_id=>7}, :graph=>{:id=>8, :x=>9, :y=>10, :graph_id=>11}}
153
+ end
154
+
155
+ it "#graph_each should not included tables graphed with the :select option in the result set" do
156
+ ds = @ds1.graph(:lines, {:x=>:id}, :select=>false).graph(:graphs, :id=>:graph_id)
157
+ def ds.fetch_rows(sql, &block)
158
+ yield({:id=>1,:x=>2,:y=>3,:graphs_id=>8, :name=>9, :graphs_x=>10, :graphs_y=>11, :lines_x=>12})
159
+ end
160
+ results = ds.all
161
+ results.length.should == 1
162
+ results.first.should == {:points=>{:id=>1, :x=>2, :y=>3}, :graphs=>{:id=>8, :name=>9, :x=>10, :y=>11, :lines_x=>12}}
163
+ end
164
+
165
+ it "#graph_each should only include the columns selected with #set_graph_aliases, if called" do
166
+ ds = @ds1.graph(:lines, :x=>:id).set_graph_aliases(:x=>[:points, :x], :y=>[:lines, :y])
167
+ def ds.fetch_rows(sql, &block)
168
+ yield({:x=>2,:y=>3})
169
+ end
170
+ results = ds.all
171
+ results.length.should == 1
172
+ results.first.should == {:points=>{:x=>2}, :lines=>{:y=>3}}
173
+
174
+ ds = @ds1.graph(:lines, :x=>:id).set_graph_aliases(:x=>[:points, :x])
175
+ def ds.fetch_rows(sql, &block)
176
+ yield({:x=>2})
177
+ end
178
+ results = ds.all
179
+ results.length.should == 1
180
+ results.first.should == {:points=>{:x=>2}, :lines=>{}}
181
+ end
182
+
183
+ it "#graph_each should run the row_proc and transform for graphed datasets" do
184
+ @ds1.row_proc = proc{|h| h.keys.each{|k| h[k] *= 2}; h}
185
+ @ds2.row_proc = proc{|h| h.keys.each{|k| h[k] *= 3}; h}
186
+ @ds1.transform(:x=>[
187
+ proc{|v| 123},
188
+ proc{|v| 123}
189
+ ])
190
+ @ds2.transform(:x=>[
191
+ proc{|v| 321},
192
+ proc{|v| 321}
193
+ ])
194
+ ds = @ds1.graph(@ds2, :x=>:id)
195
+ def ds.fetch_rows(sql, &block)
196
+ yield({:id=>1,:x=>2,:y=>3,:lines_id=>4,:lines_x=>5,:lines_y=>6,:graph_id=>7})
197
+ end
198
+ results = ds.all
199
+ results.length.should == 1
200
+ results.first.should == {:points=>{:id=>2, :x=>246, :y=>6}, :lines=>{:id=>12, :x=>963, :y=>18, :graph_id=>21}}
201
+ end
202
+ end