sequel 2.5.0 → 2.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +48 -0
- data/Rakefile +16 -6
- data/bin/sequel +0 -0
- data/doc/cheat_sheet.rdoc +4 -4
- data/doc/schema.rdoc +9 -0
- data/lib/sequel_core/adapters/jdbc.rb +7 -7
- data/lib/sequel_core/adapters/mysql.rb +6 -11
- data/lib/sequel_core/adapters/shared/mssql.rb +21 -1
- data/lib/sequel_core/adapters/shared/mysql.rb +19 -27
- data/lib/sequel_core/adapters/shared/postgres.rb +67 -11
- data/lib/sequel_core/adapters/shared/sqlite.rb +11 -22
- data/lib/sequel_core/adapters/sqlite.rb +8 -4
- data/lib/sequel_core/core_sql.rb +4 -4
- data/lib/sequel_core/database.rb +56 -31
- data/lib/sequel_core/database/schema.rb +13 -5
- data/lib/sequel_core/dataset/convenience.rb +1 -1
- data/lib/sequel_core/dataset/sql.rb +30 -15
- data/lib/sequel_core/migration.rb +7 -0
- data/lib/sequel_core/schema/generator.rb +13 -2
- data/lib/sequel_core/schema/sql.rb +27 -81
- data/lib/sequel_core/sql.rb +5 -2
- data/lib/sequel_model.rb +8 -2
- data/lib/sequel_model/associations.rb +7 -4
- data/lib/sequel_model/base.rb +10 -1
- data/lib/sequel_model/eager_loading.rb +29 -10
- data/lib/sequel_model/record.rb +19 -5
- data/spec/adapters/mysql_spec.rb +2 -2
- data/spec/adapters/postgres_spec.rb +26 -5
- data/spec/adapters/sqlite_spec.rb +42 -8
- data/spec/integration/eager_loader_test.rb +51 -58
- data/spec/integration/schema_test.rb +28 -4
- data/spec/sequel_core/core_sql_spec.rb +3 -0
- data/spec/sequel_core/database_spec.rb +24 -0
- data/spec/sequel_core/dataset_spec.rb +25 -17
- data/spec/sequel_core/schema_spec.rb +58 -26
- data/spec/sequel_model/eager_loading_spec.rb +65 -0
- data/spec/sequel_model/hooks_spec.rb +1 -1
- data/spec/sequel_model/model_spec.rb +1 -0
- data/spec/sequel_model/record_spec.rb +74 -1
- data/spec/sequel_model/spec_helper.rb +8 -0
- metadata +5 -3
@@ -1,21 +1,19 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), 'spec_helper.rb')
|
2
2
|
|
3
3
|
describe "Database schema parser" do
|
4
|
-
before do
|
5
|
-
INTEGRATION_DB.create_table!(:items){integer :number}
|
6
|
-
clear_sqls
|
7
|
-
end
|
8
4
|
after do
|
9
5
|
INTEGRATION_DB.drop_table(:items) if INTEGRATION_DB.table_exists?(:items)
|
10
6
|
end
|
11
7
|
|
12
8
|
specify "should be a hash with table_names as symbols" do
|
9
|
+
INTEGRATION_DB.create_table!(:items){integer :number}
|
13
10
|
schema = INTEGRATION_DB.schema(nil, :reload=>true)
|
14
11
|
schema.should be_a_kind_of(Hash)
|
15
12
|
schema.should include(:items)
|
16
13
|
end
|
17
14
|
|
18
15
|
specify "should not issue an sql query if the schema has been loaded unless :reload is true" do
|
16
|
+
INTEGRATION_DB.create_table!(:items){integer :number}
|
19
17
|
INTEGRATION_DB.schema(nil, :reload=>true)
|
20
18
|
clear_sqls
|
21
19
|
INTEGRATION_DB.schema
|
@@ -23,6 +21,7 @@ describe "Database schema parser" do
|
|
23
21
|
end
|
24
22
|
|
25
23
|
specify "should give the same result for a single table regardless of whether schema was called for a single table" do
|
24
|
+
INTEGRATION_DB.create_table!(:items){integer :number}
|
26
25
|
INTEGRATION_DB.schema(:items, :reload=>true).should == INTEGRATION_DB.schema(nil, :reload=>true)[:items]
|
27
26
|
end
|
28
27
|
|
@@ -42,6 +41,31 @@ describe "Database schema parser" do
|
|
42
41
|
INTEGRATION_DB.schema(:items)
|
43
42
|
sqls_should_be
|
44
43
|
end
|
44
|
+
|
45
|
+
specify "should parse primary keys from the schema properly" do
|
46
|
+
INTEGRATION_DB.create_table!(:items){integer :number}
|
47
|
+
INTEGRATION_DB.schema(:items).collect{|k,v| k if v[:primary_key]}.compact.should == []
|
48
|
+
INTEGRATION_DB.create_table!(:items){primary_key :number}
|
49
|
+
INTEGRATION_DB.schema(:items).collect{|k,v| k if v[:primary_key]}.compact.should == [:number]
|
50
|
+
INTEGRATION_DB.create_table!(:items){integer :number1; integer :number2; primary_key [:number1, :number2]}
|
51
|
+
INTEGRATION_DB.schema(:items).collect{|k,v| k if v[:primary_key]}.compact.should == [:number1, :number2]
|
52
|
+
end
|
53
|
+
|
54
|
+
specify "should parse NULL/NOT NULL from the schema properly" do
|
55
|
+
INTEGRATION_DB.create_table!(:items){integer :number, :null=>true}
|
56
|
+
INTEGRATION_DB.schema(:items).first.last[:allow_null].should == true
|
57
|
+
INTEGRATION_DB.create_table!(:items){integer :number, :null=>false}
|
58
|
+
INTEGRATION_DB.schema(:items).first.last[:allow_null].should == false
|
59
|
+
end
|
60
|
+
|
61
|
+
specify "should parse defaults from the schema properly" do
|
62
|
+
INTEGRATION_DB.create_table!(:items){integer :number}
|
63
|
+
INTEGRATION_DB.schema(:items).first.last[:default].should == nil
|
64
|
+
INTEGRATION_DB.create_table!(:items){integer :number, :default=>0}
|
65
|
+
INTEGRATION_DB.schema(:items).first.last[:default].to_s.should == "0"
|
66
|
+
INTEGRATION_DB.create_table!(:items){varchar :a, :default=>"blah", :size=>4}
|
67
|
+
INTEGRATION_DB.schema(:items).first.last[:default].gsub(/::character varying\z/, '').gsub("'", '').should == "blah"
|
68
|
+
end
|
45
69
|
end
|
46
70
|
|
47
71
|
describe "Database schema modifiers" do
|
@@ -30,10 +30,13 @@ context "Array#case and Hash#case" do
|
|
30
30
|
|
31
31
|
specify "should return SQL CASE expression" do
|
32
32
|
@d.literal({:x=>:y}.case(:z)).should == '(CASE WHEN x THEN y ELSE z END)'
|
33
|
+
@d.literal({:x=>:y}.case(:z, :exp)).should == '(CASE exp WHEN x THEN y ELSE z END)'
|
33
34
|
['(CASE WHEN x THEN y WHEN a THEN b ELSE z END)',
|
34
35
|
'(CASE WHEN a THEN b WHEN x THEN y ELSE z END)'].should(include(@d.literal({:x=>:y, :a=>:b}.case(:z))))
|
35
36
|
@d.literal([[:x, :y]].case(:z)).should == '(CASE WHEN x THEN y ELSE z END)'
|
36
37
|
@d.literal([[:x, :y], [:a, :b]].case(:z)).should == '(CASE WHEN x THEN y WHEN a THEN b ELSE z END)'
|
38
|
+
@d.literal([[:x, :y], [:a, :b]].case(:z, :exp)).should == '(CASE exp WHEN x THEN y WHEN a THEN b ELSE z END)'
|
39
|
+
@d.literal([[:x, :y], [:a, :b]].case(:z, :exp__w)).should == '(CASE exp.w WHEN x THEN y WHEN a THEN b ELSE z END)'
|
37
40
|
end
|
38
41
|
|
39
42
|
specify "should raise an error if an array that isn't all two pairs is used" do
|
@@ -1015,3 +1015,27 @@ context "Database#raise_error" do
|
|
1015
1015
|
proc{MockDatabase.new.send(:raise_error, Interrupt.new(''))}.should raise_error(Sequel::DatabaseError)
|
1016
1016
|
end
|
1017
1017
|
end
|
1018
|
+
|
1019
|
+
context "Database#typecast_value" do
|
1020
|
+
setup do
|
1021
|
+
@db = Sequel::Database.new(1 => 2, :logger => 3)
|
1022
|
+
end
|
1023
|
+
specify "should raise InvalidValue when setting invalid integer" do
|
1024
|
+
proc{@db.typecast_value(:integer, "13a")}.should raise_error(Sequel::Error::InvalidValue)
|
1025
|
+
end
|
1026
|
+
specify "should raise InvalidValue when setting invalid float" do
|
1027
|
+
proc{@db.typecast_value(:float, "4.e2")}.should raise_error(Sequel::Error::InvalidValue)
|
1028
|
+
end
|
1029
|
+
specify "should raise InvalidValue when setting invalid decimal" do
|
1030
|
+
proc{@db.typecast_value(:decimal, :invalid_value)}.should raise_error(Sequel::Error::InvalidValue)
|
1031
|
+
end
|
1032
|
+
specify "should raise InvalidValue when setting invalid date" do
|
1033
|
+
proc{@db.typecast_value(:date, Object.new)}.should raise_error(Sequel::Error::InvalidValue)
|
1034
|
+
end
|
1035
|
+
specify "should raise InvalidValue when setting invalid time" do
|
1036
|
+
proc{@db.typecast_value(:time, Date.new)}.should raise_error(Sequel::Error::InvalidValue)
|
1037
|
+
end
|
1038
|
+
specify "should raise InvalidValue when setting invalid datetime" do
|
1039
|
+
proc{@db.typecast_value(:datetime, 4)}.should raise_error(Sequel::Error::InvalidValue)
|
1040
|
+
end
|
1041
|
+
end
|
@@ -558,7 +558,7 @@ context "a grouped dataset" do
|
|
558
558
|
specify "should format the right statement for counting (as a subquery)" do
|
559
559
|
db = MockDatabase.new
|
560
560
|
db[:test].select(:name).group(:name).count
|
561
|
-
db.sqls.should == ["SELECT COUNT(*) FROM (SELECT name FROM test GROUP BY name) t1 LIMIT 1"]
|
561
|
+
db.sqls.should == ["SELECT COUNT(*) FROM (SELECT name FROM test GROUP BY name) AS t1 LIMIT 1"]
|
562
562
|
end
|
563
563
|
end
|
564
564
|
|
@@ -684,37 +684,34 @@ context "Dataset#from" do
|
|
684
684
|
|
685
685
|
specify "should format a Dataset as a subquery if it has had options set" do
|
686
686
|
@dataset.from(@dataset.from(:a).where(:a=>1)).select_sql.should ==
|
687
|
-
"SELECT * FROM (SELECT * FROM a WHERE (a = 1)) t1"
|
687
|
+
"SELECT * FROM (SELECT * FROM a WHERE (a = 1)) AS t1"
|
688
688
|
end
|
689
689
|
|
690
690
|
specify "should automatically alias sub-queries" do
|
691
691
|
@dataset.from(@dataset.from(:a).group(:b)).select_sql.should ==
|
692
|
-
"SELECT * FROM (SELECT * FROM a GROUP BY b) t1"
|
692
|
+
"SELECT * FROM (SELECT * FROM a GROUP BY b) AS t1"
|
693
693
|
|
694
694
|
d1 = @dataset.from(:a).group(:b)
|
695
695
|
d2 = @dataset.from(:c).group(:d)
|
696
696
|
|
697
697
|
@dataset.from(d1, d2).sql.should ==
|
698
|
-
"SELECT * FROM (SELECT * FROM a GROUP BY b) t1, (SELECT * FROM c GROUP BY d) t2"
|
698
|
+
"SELECT * FROM (SELECT * FROM a GROUP BY b) AS t1, (SELECT * FROM c GROUP BY d) AS t2"
|
699
699
|
end
|
700
700
|
|
701
701
|
specify "should accept a hash for aliasing" do
|
702
702
|
@dataset.from(:a => :b).sql.should ==
|
703
|
-
"SELECT * FROM a b"
|
703
|
+
"SELECT * FROM a AS b"
|
704
704
|
|
705
705
|
@dataset.from(:a => 'b').sql.should ==
|
706
|
-
"SELECT * FROM a b"
|
707
|
-
|
708
|
-
@dataset.from(:a => :c[:d]).sql.should ==
|
709
|
-
"SELECT * FROM a c(d)"
|
706
|
+
"SELECT * FROM a AS b"
|
710
707
|
|
711
708
|
@dataset.from(@dataset.from(:a).group(:b) => :c).sql.should ==
|
712
|
-
"SELECT * FROM (SELECT * FROM a GROUP BY b) c"
|
709
|
+
"SELECT * FROM (SELECT * FROM a GROUP BY b) AS c"
|
713
710
|
end
|
714
711
|
|
715
712
|
specify "should always use a subquery if given a dataset" do
|
716
713
|
@dataset.from(@dataset.from(:a)).select_sql.should ==
|
717
|
-
"SELECT * FROM (SELECT * FROM a) t1"
|
714
|
+
"SELECT * FROM (SELECT * FROM a) AS t1"
|
718
715
|
end
|
719
716
|
|
720
717
|
specify "should raise if no source is given" do
|
@@ -985,7 +982,7 @@ context "Dataset#limit" do
|
|
985
982
|
specify "should work with fixed sql datasets" do
|
986
983
|
@dataset.opts[:sql] = 'select * from cccc'
|
987
984
|
@dataset.limit(6, 10).sql.should ==
|
988
|
-
'SELECT * FROM (select * from cccc) t1 LIMIT 6 OFFSET 10'
|
985
|
+
'SELECT * FROM (select * from cccc) AS t1 LIMIT 6 OFFSET 10'
|
989
986
|
end
|
990
987
|
|
991
988
|
specify "should raise an error if an invalid limit or offset is used" do
|
@@ -1102,7 +1099,7 @@ context "Dataset#uniq" do
|
|
1102
1099
|
|
1103
1100
|
specify "should do a subselect for count" do
|
1104
1101
|
@dataset.uniq.count
|
1105
|
-
@db.sqls.should == ['SELECT COUNT(*) FROM (SELECT DISTINCT name FROM test) t1 LIMIT 1']
|
1102
|
+
@db.sqls.should == ['SELECT COUNT(*) FROM (SELECT DISTINCT name FROM test) AS t1 LIMIT 1']
|
1106
1103
|
end
|
1107
1104
|
end
|
1108
1105
|
|
@@ -1138,12 +1135,12 @@ context "Dataset#count" do
|
|
1138
1135
|
specify "should count properly for datasets with fixed sql" do
|
1139
1136
|
@dataset.opts[:sql] = "select abc from xyz"
|
1140
1137
|
@dataset.count.should == 1
|
1141
|
-
@c.sql.should == "SELECT COUNT(*) FROM (select abc from xyz) t1 LIMIT 1"
|
1138
|
+
@c.sql.should == "SELECT COUNT(*) FROM (select abc from xyz) AS t1 LIMIT 1"
|
1142
1139
|
end
|
1143
1140
|
|
1144
1141
|
specify "should return limit if count is greater than it" do
|
1145
1142
|
@dataset.limit(5).count.should == 1
|
1146
|
-
@c.sql.should == "SELECT COUNT(*) FROM (SELECT * FROM test LIMIT 5) t1 LIMIT 1"
|
1143
|
+
@c.sql.should == "SELECT COUNT(*) FROM (SELECT * FROM test LIMIT 5) AS t1 LIMIT 1"
|
1147
1144
|
end
|
1148
1145
|
|
1149
1146
|
it "should work on a graphed_dataset" do
|
@@ -1284,7 +1281,7 @@ context "Dataset#join_table" do
|
|
1284
1281
|
ds = MockDataset.new(nil).from(:foo => :f)
|
1285
1282
|
ds.quote_identifiers = true
|
1286
1283
|
ds.join_table(:inner, :bar, :id => :bar_id).sql.should ==
|
1287
|
-
'SELECT * FROM "foo" "f" INNER JOIN "bar" ON ("bar"."id" = "f"."bar_id")'
|
1284
|
+
'SELECT * FROM "foo" AS "f" INNER JOIN "bar" ON ("bar"."id" = "f"."bar_id")'
|
1288
1285
|
end
|
1289
1286
|
|
1290
1287
|
specify "should allow for arbitrary conditions in the JOIN clause" do
|
@@ -2162,7 +2159,7 @@ context "A paginated dataset" do
|
|
2162
2159
|
specify "should work with fixed sql" do
|
2163
2160
|
ds = @d.clone(:sql => 'select * from blah')
|
2164
2161
|
ds.meta_def(:count) {150}
|
2165
|
-
ds.paginate(2, 50).sql.should == 'SELECT * FROM (select * from blah) t1 LIMIT 50 OFFSET 50'
|
2162
|
+
ds.paginate(2, 50).sql.should == 'SELECT * FROM (select * from blah) AS t1 LIMIT 50 OFFSET 50'
|
2166
2163
|
end
|
2167
2164
|
end
|
2168
2165
|
|
@@ -2322,6 +2319,17 @@ context "Dataset#multi_insert" do
|
|
2322
2319
|
]
|
2323
2320
|
end
|
2324
2321
|
|
2322
|
+
specify "should accept string keys as column names" do
|
2323
|
+
@ds.multi_insert([{'x'=>1, 'y'=>2}, {'x'=>3, 'y'=>4}])
|
2324
|
+
@ds.multi_insert(['x', 'y'], [[1, 2], [3, 4]])
|
2325
|
+
@db.sqls.should == [
|
2326
|
+
'BEGIN',
|
2327
|
+
"INSERT INTO items (x, y) VALUES (1, 2)",
|
2328
|
+
"INSERT INTO items (x, y) VALUES (3, 4)",
|
2329
|
+
'COMMIT'
|
2330
|
+
] * 2
|
2331
|
+
end
|
2332
|
+
|
2325
2333
|
specify "should accept a columns array and a values array" do
|
2326
2334
|
@ds.multi_insert([:x, :y], [[1, 2], [3, 4]])
|
2327
2335
|
@db.sqls.should == [
|
@@ -244,7 +244,7 @@ context "DB#create_table" do
|
|
244
244
|
text :name
|
245
245
|
unique :name
|
246
246
|
end
|
247
|
-
@db.sqls.should == ["CREATE TABLE cats (name text, UNIQUE (name))"
|
247
|
+
@db.sqls.should == ["CREATE TABLE cats (name text, UNIQUE (name))"]
|
248
248
|
end
|
249
249
|
|
250
250
|
specify "should raise on full-text index definitions" do
|
@@ -331,6 +331,13 @@ context "DB#create_table" do
|
|
331
331
|
@db.sqls.should == ["CREATE TABLE cats (CHECK (price < 100))"]
|
332
332
|
end
|
333
333
|
|
334
|
+
specify "should accept hash constraints" do
|
335
|
+
@db.create_table(:cats) do
|
336
|
+
check :price=>100
|
337
|
+
end
|
338
|
+
@db.sqls.should == ["CREATE TABLE cats (CHECK (price = 100))"]
|
339
|
+
end
|
340
|
+
|
334
341
|
specify "should accept named constraint definitions" do
|
335
342
|
@db.create_table(:cats) do
|
336
343
|
integer :score
|
@@ -459,6 +466,20 @@ context "DB#alter_table" do
|
|
459
466
|
setup do
|
460
467
|
@db = SchemaDummyDatabase.new
|
461
468
|
end
|
469
|
+
|
470
|
+
specify "should allow adding not null constraint" do
|
471
|
+
@db.alter_table(:cats) do
|
472
|
+
set_column_allow_null :score, false
|
473
|
+
end
|
474
|
+
@db.sqls.should == ["ALTER TABLE cats ALTER COLUMN score SET NOT NULL"]
|
475
|
+
end
|
476
|
+
|
477
|
+
specify "should allow droping not null constraint" do
|
478
|
+
@db.alter_table(:cats) do
|
479
|
+
set_column_allow_null :score, true
|
480
|
+
end
|
481
|
+
@db.sqls.should == ["ALTER TABLE cats ALTER COLUMN score DROP NOT NULL"]
|
482
|
+
end
|
462
483
|
|
463
484
|
specify "should support add_column" do
|
464
485
|
@db.alter_table(:cats) do
|
@@ -598,44 +619,54 @@ end
|
|
598
619
|
|
599
620
|
context "Schema Parser" do
|
600
621
|
setup do
|
601
|
-
|
622
|
+
@sqls = []
|
602
623
|
@db = Sequel::Database.new
|
603
|
-
@db.meta_def(:dataset) do
|
604
|
-
ds = super()
|
605
|
-
ds.instance_variable_set(:@sqls, sqls)
|
606
|
-
def ds.fetch_rows(sql)
|
607
|
-
@sqls << sql
|
608
|
-
table = /'(.*)'/.match(sql)[1]
|
609
|
-
h = {:column=>"a", :db_type=>table, :max_chars=>nil, :numeric_precision=>nil, :default=>'', :allow_null=>'YES'}
|
610
|
-
(h[:column] = h[:table_name] = :x) if sql =~ /BASE TABLE/
|
611
|
-
yield h
|
612
|
-
end
|
613
|
-
ds
|
614
|
-
end
|
615
624
|
end
|
616
625
|
after do
|
617
626
|
Sequel.convert_tinyint_to_bool = true
|
618
627
|
end
|
619
628
|
|
620
629
|
specify "should parse the schema correctly for a single table" do
|
621
|
-
|
622
|
-
@
|
623
|
-
@db.
|
624
|
-
|
625
|
-
|
626
|
-
|
630
|
+
sqls = @sqls
|
631
|
+
proc{@db.schema(:x)}.should raise_error(Sequel::Error)
|
632
|
+
@db.meta_def(:schema_parse_table) do |t, opts|
|
633
|
+
sqls << t
|
634
|
+
[[:a, {:db_type=>t.to_s}]]
|
635
|
+
end
|
636
|
+
@db.schema(:x).should == [[:a, {:db_type=>"x"}]]
|
637
|
+
@sqls.should == [:x]
|
638
|
+
@db.schema(:x).should == [[:a, {:db_type=>"x"}]]
|
639
|
+
@sqls.should == [:x]
|
640
|
+
@db.schema(:x, :reload=>true).should == [[:a, {:db_type=>"x"}]]
|
641
|
+
@sqls.should == [:x, :x]
|
627
642
|
end
|
628
643
|
|
629
644
|
specify "should parse the schema correctly for all tables" do
|
630
|
-
|
631
|
-
@
|
632
|
-
@db.
|
633
|
-
@
|
634
|
-
|
635
|
-
|
645
|
+
sqls = @sqls
|
646
|
+
proc{@db.schema}.should raise_error(Sequel::Error)
|
647
|
+
@db.meta_def(:tables){[:x]}
|
648
|
+
@db.meta_def(:schema_parse_table) do |t, opts|
|
649
|
+
sqls << t
|
650
|
+
[[:x, {:db_type=>t.to_s}]]
|
651
|
+
end
|
652
|
+
@db.schema.should == {:x=>[[:x, {:db_type=>"x"}]]}
|
653
|
+
@sqls.should == [:x]
|
654
|
+
@db.schema.should == {:x=>[[:x, {:db_type=>"x"}]]}
|
655
|
+
@sqls.should == [:x]
|
656
|
+
@db.schema(nil, :reload=>true).should == {:x=>[[:x, {:db_type=>"x"}]]}
|
657
|
+
@sqls.should == [:x, :x]
|
658
|
+
@db.meta_def(:schema_parse_tables) do |opts|
|
659
|
+
sqls << 1
|
660
|
+
{:x=>[[:a, {:db_type=>"1"}]]}
|
661
|
+
end
|
662
|
+
@db.schema(nil, :reload=>true).should == {:x=>[[:a, {:db_type=>"1"}]]}
|
663
|
+
@sqls.should == [:x, :x, 1]
|
636
664
|
end
|
637
665
|
|
638
666
|
specify "should correctly parse all supported data types" do
|
667
|
+
@db.meta_def(:schema_parse_table) do |t, opts|
|
668
|
+
[[:x, {:type=>schema_column_type(t.to_s)}]]
|
669
|
+
end
|
639
670
|
@db.schema(:tinyint).first.last[:type].should == :boolean
|
640
671
|
Sequel.convert_tinyint_to_bool = false
|
641
672
|
@db.schema(:tinyint, :reload=>true).first.last[:type].should == :integer
|
@@ -646,6 +677,7 @@ context "Schema Parser" do
|
|
646
677
|
@db.schema(:character).first.last[:type].should == :string
|
647
678
|
@db.schema(:"character varying").first.last[:type].should == :string
|
648
679
|
@db.schema(:varchar).first.last[:type].should == :string
|
680
|
+
@db.schema(:"varchar(255)").first.last[:type].should == :string
|
649
681
|
@db.schema(:text).first.last[:type].should == :string
|
650
682
|
@db.schema(:date).first.last[:type].should == :date
|
651
683
|
@db.schema(:datetime).first.last[:type].should == :datetime
|
@@ -638,6 +638,37 @@ describe Sequel::Model, "#eager_graph" do
|
|
638
638
|
a.album.band.members.first.values.should == {:id => 5}
|
639
639
|
end
|
640
640
|
|
641
|
+
it "should allow cascading of eager loading for multiple *_to_many associations, eliminating duplicates caused by cartesian products" do
|
642
|
+
ds = GraphBand.eager_graph({:albums=>:tracks}, :members)
|
643
|
+
ds.sql.should == 'SELECT bands.id, bands.vocalist_id, albums.id AS albums_id, albums.band_id, tracks.id AS tracks_id, tracks.album_id, members.id AS members_id FROM bands LEFT OUTER JOIN albums ON (albums.band_id = bands.id) LEFT OUTER JOIN tracks ON (tracks.album_id = albums.id) LEFT OUTER JOIN bm ON (bm.band_id = bands.id) LEFT OUTER JOIN members ON (members.id = bm.member_id)'
|
644
|
+
def ds.fetch_rows(sql, &block)
|
645
|
+
yield({:id=>1, :vocalist_id=>2, :albums_id=>3, :band_id=>1, :tracks_id=>4, :album_id=>3, :members_id=>5})
|
646
|
+
yield({:id=>1, :vocalist_id=>2, :albums_id=>3, :band_id=>1, :tracks_id=>4, :album_id=>3, :members_id=>6})
|
647
|
+
yield({:id=>1, :vocalist_id=>2, :albums_id=>3, :band_id=>1, :tracks_id=>5, :album_id=>3, :members_id=>5})
|
648
|
+
yield({:id=>1, :vocalist_id=>2, :albums_id=>3, :band_id=>1, :tracks_id=>5, :album_id=>3, :members_id=>6})
|
649
|
+
yield({:id=>1, :vocalist_id=>2, :albums_id=>4, :band_id=>1, :tracks_id=>6, :album_id=>4, :members_id=>5})
|
650
|
+
yield({:id=>1, :vocalist_id=>2, :albums_id=>4, :band_id=>1, :tracks_id=>6, :album_id=>4, :members_id=>6})
|
651
|
+
yield({:id=>1, :vocalist_id=>2, :albums_id=>4, :band_id=>1, :tracks_id=>7, :album_id=>4, :members_id=>5})
|
652
|
+
yield({:id=>1, :vocalist_id=>2, :albums_id=>4, :band_id=>1, :tracks_id=>7, :album_id=>4, :members_id=>6})
|
653
|
+
yield({:id=>2, :vocalist_id=>2, :albums_id=>5, :band_id=>2, :tracks_id=>8, :album_id=>5, :members_id=>5})
|
654
|
+
yield({:id=>2, :vocalist_id=>2, :albums_id=>5, :band_id=>2, :tracks_id=>8, :album_id=>5, :members_id=>6})
|
655
|
+
yield({:id=>2, :vocalist_id=>2, :albums_id=>5, :band_id=>2, :tracks_id=>9, :album_id=>5, :members_id=>5})
|
656
|
+
yield({:id=>2, :vocalist_id=>2, :albums_id=>5, :band_id=>2, :tracks_id=>9, :album_id=>5, :members_id=>6})
|
657
|
+
yield({:id=>2, :vocalist_id=>2, :albums_id=>6, :band_id=>2, :tracks_id=>1, :album_id=>6, :members_id=>5})
|
658
|
+
yield({:id=>2, :vocalist_id=>2, :albums_id=>6, :band_id=>2, :tracks_id=>1, :album_id=>6, :members_id=>6})
|
659
|
+
yield({:id=>2, :vocalist_id=>2, :albums_id=>6, :band_id=>2, :tracks_id=>2, :album_id=>6, :members_id=>5})
|
660
|
+
yield({:id=>2, :vocalist_id=>2, :albums_id=>6, :band_id=>2, :tracks_id=>2, :album_id=>6, :members_id=>6})
|
661
|
+
end
|
662
|
+
a = ds.all
|
663
|
+
a.should == [GraphBand.load(:id=>1, :vocalist_id=>2), GraphBand.load(:id=>2, :vocalist_id=>2)]
|
664
|
+
members = a.map{|x| x.members}
|
665
|
+
members.should == [[GraphBandMember.load(:id=>5), GraphBandMember.load(:id=>6)], [GraphBandMember.load(:id=>5), GraphBandMember.load(:id=>6)]]
|
666
|
+
albums = a.map{|x| x.albums}
|
667
|
+
albums.should == [[GraphAlbum.load(:id=>3, :band_id=>1), GraphAlbum.load(:id=>4, :band_id=>1)], [GraphAlbum.load(:id=>5, :band_id=>2), GraphAlbum.load(:id=>6, :band_id=>2)]]
|
668
|
+
tracks = albums.map{|x| x.map{|y| y.tracks}}
|
669
|
+
tracks.should == [[[GraphTrack.load(:id=>4, :album_id=>3), GraphTrack.load(:id=>5, :album_id=>3)], [GraphTrack.load(:id=>6, :album_id=>4), GraphTrack.load(:id=>7, :album_id=>4)]], [[GraphTrack.load(:id=>8, :album_id=>5), GraphTrack.load(:id=>9, :album_id=>5)], [GraphTrack.load(:id=>1, :album_id=>6), GraphTrack.load(:id=>2, :album_id=>6)]]]
|
670
|
+
end
|
671
|
+
|
641
672
|
it "should populate the reciprocal many_to_one association when eagerly loading the one_to_many association" do
|
642
673
|
MODEL_DB.reset
|
643
674
|
ds = GraphAlbum.eager_graph(:tracks)
|
@@ -961,4 +992,38 @@ describe Sequel::Model, "#eager_graph" do
|
|
961
992
|
it "should create unique table aliases for all associations" do
|
962
993
|
GraphAlbum.eager_graph(:previous_album=>{:previous_album=>:previous_album}).sql.should == "SELECT albums.id, albums.band_id, previous_album.id AS previous_album_id, previous_album.band_id AS previous_album_band_id, previous_album_0.id AS previous_album_0_id, previous_album_0.band_id AS previous_album_0_band_id, previous_album_1.id AS previous_album_1_id, previous_album_1.band_id AS previous_album_1_band_id FROM albums LEFT OUTER JOIN albums AS previous_album ON (previous_album.id = albums.previous_album_id) LEFT OUTER JOIN albums AS previous_album_0 ON (previous_album_0.id = previous_album.previous_album_id) LEFT OUTER JOIN albums AS previous_album_1 ON (previous_album_1.id = previous_album_0.previous_album_id)"
|
963
994
|
end
|
995
|
+
|
996
|
+
it "should respect the association's :order" do
|
997
|
+
GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :order=>[:id, :album_id]
|
998
|
+
GraphAlbum.eager_graph(:right_tracks).sql.should == 'SELECT albums.id, albums.band_id, right_tracks.id AS right_tracks_id, right_tracks.album_id FROM albums LEFT OUTER JOIN tracks AS right_tracks ON (right_tracks.album_id = albums.id) ORDER BY right_tracks.id, right_tracks.album_id'
|
999
|
+
end
|
1000
|
+
|
1001
|
+
it "should only qualify unqualified symbols, identifiers, or ordered versions in association's :order" do
|
1002
|
+
GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :order=>[:blah__id.identifier, :blah__id.identifier.desc, :blah__id.desc, :blah__id, :album_id, :album_id.desc, 1, 'RANDOM()'.lit, :a.qualify(:b)]
|
1003
|
+
GraphAlbum.eager_graph(:right_tracks).sql.should == 'SELECT albums.id, albums.band_id, right_tracks.id AS right_tracks_id, right_tracks.album_id FROM albums LEFT OUTER JOIN tracks AS right_tracks ON (right_tracks.album_id = albums.id) ORDER BY right_tracks.blah__id, right_tracks.blah__id DESC, blah.id DESC, blah.id, right_tracks.album_id, right_tracks.album_id DESC, 1, RANDOM(), b.a'
|
1004
|
+
end
|
1005
|
+
|
1006
|
+
it "should not respect the association's :order if :order_eager_graph is false" do
|
1007
|
+
GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :order=>[:id, :album_id], :order_eager_graph=>false
|
1008
|
+
GraphAlbum.eager_graph(:right_tracks).sql.should == 'SELECT albums.id, albums.band_id, right_tracks.id AS right_tracks_id, right_tracks.album_id FROM albums LEFT OUTER JOIN tracks AS right_tracks ON (right_tracks.album_id = albums.id)'
|
1009
|
+
end
|
1010
|
+
|
1011
|
+
it "should add the association's :order to the existing order" do
|
1012
|
+
GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :order=>[:id, :album_id]
|
1013
|
+
GraphAlbum.order(:band_id).eager_graph(:right_tracks).sql.should == 'SELECT albums.id, albums.band_id, right_tracks.id AS right_tracks_id, right_tracks.album_id FROM albums LEFT OUTER JOIN tracks AS right_tracks ON (right_tracks.album_id = albums.id) ORDER BY band_id, right_tracks.id, right_tracks.album_id'
|
1014
|
+
end
|
1015
|
+
|
1016
|
+
it "should add the association's :order for cascading associations" do
|
1017
|
+
GraphBand.one_to_many :a_albums, :class=>'GraphAlbum', :key=>:band_id, :order=>:name
|
1018
|
+
GraphAlbum.one_to_many :b_tracks, :class=>'GraphTrack', :key=>:album_id, :order=>[:id, :album_id]
|
1019
|
+
GraphBand.eager_graph(:a_albums=>:b_tracks).sql.should == 'SELECT bands.id, bands.vocalist_id, a_albums.id AS a_albums_id, a_albums.band_id, b_tracks.id AS b_tracks_id, b_tracks.album_id FROM bands LEFT OUTER JOIN albums AS a_albums ON (a_albums.band_id = bands.id) LEFT OUTER JOIN tracks AS b_tracks ON (b_tracks.album_id = a_albums.id) ORDER BY a_albums.name, b_tracks.id, b_tracks.album_id'
|
1020
|
+
GraphAlbum.one_to_many :albums, :class=>'GraphAlbum', :key=>:band_id, :order=>[:band_id, :id]
|
1021
|
+
GraphAlbum.eager_graph(:albums=>{:albums=>:albums}).sql.should == 'SELECT albums.id, albums.band_id, albums_0.id AS albums_0_id, albums_0.band_id AS albums_0_band_id, albums_1.id AS albums_1_id, albums_1.band_id AS albums_1_band_id, albums_2.id AS albums_2_id, albums_2.band_id AS albums_2_band_id FROM albums LEFT OUTER JOIN albums AS albums_0 ON (albums_0.band_id = albums.id) LEFT OUTER JOIN albums AS albums_1 ON (albums_1.band_id = albums_0.id) LEFT OUTER JOIN albums AS albums_2 ON (albums_2.band_id = albums_1.id) ORDER BY albums_0.band_id, albums_0.id, albums_1.band_id, albums_1.id, albums_2.band_id, albums_2.id'
|
1022
|
+
end
|
1023
|
+
|
1024
|
+
it "should add the associations :order for multiple associations" do
|
1025
|
+
GraphAlbum.many_to_many :a_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :order=>:id
|
1026
|
+
GraphAlbum.one_to_many :b_tracks, :class=>'GraphTrack', :key=>:album_id, :order=>[:id, :album_id]
|
1027
|
+
GraphAlbum.eager_graph(:a_genres, :b_tracks).sql.should == 'SELECT albums.id, albums.band_id, a_genres.id AS a_genres_id, b_tracks.id AS b_tracks_id, b_tracks.album_id FROM albums LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres AS a_genres ON (a_genres.id = ag.genre_id) LEFT OUTER JOIN tracks AS b_tracks ON (b_tracks.album_id = albums.id) ORDER BY a_genres.id, b_tracks.id, b_tracks.album_id'
|
1028
|
+
end
|
964
1029
|
end
|
@@ -305,7 +305,7 @@ describe "Model#before_destroy && Model#after_destroy" do
|
|
305
305
|
|
306
306
|
specify "should be called around record destruction" do
|
307
307
|
@c.before_destroy {MODEL_DB << "BLAH before"}
|
308
|
-
m = @c.
|
308
|
+
m = @c.load(:id => 2233)
|
309
309
|
m.destroy
|
310
310
|
MODEL_DB.sqls.should == [
|
311
311
|
'BLAH before',
|