sequel 2.5.0 → 2.6.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.
- 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',
|