sequel 5.2.0 → 5.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +32 -0
- data/bin/sequel +5 -6
- data/doc/release_notes/5.3.0.txt +121 -0
- data/doc/schema_modification.rdoc +15 -4
- data/doc/testing.rdoc +1 -0
- data/lib/sequel/adapters/jdbc.rb +4 -0
- data/lib/sequel/adapters/jdbc/postgresql.rb +15 -0
- data/lib/sequel/adapters/oracle.rb +2 -1
- data/lib/sequel/adapters/postgres.rb +4 -0
- data/lib/sequel/adapters/shared/mysql.rb +38 -3
- data/lib/sequel/adapters/shared/postgres.rb +15 -6
- data/lib/sequel/adapters/shared/sqlite.rb +10 -0
- data/lib/sequel/adapters/utils/mysql_mysql2.rb +2 -0
- data/lib/sequel/connection_pool.rb +12 -0
- data/lib/sequel/database/misc.rb +13 -0
- data/lib/sequel/dataset/dataset_module.rb +1 -1
- data/lib/sequel/dataset/features.rb +5 -0
- data/lib/sequel/dataset/query.rb +20 -6
- data/lib/sequel/dataset/sql.rb +3 -0
- data/lib/sequel/extensions/pg_extended_date_support.rb +15 -0
- data/lib/sequel/extensions/synchronize_sql.rb +45 -0
- data/lib/sequel/model/associations.rb +1 -0
- data/lib/sequel/model/base.rb +4 -11
- data/lib/sequel/plugins/validation_helpers.rb +2 -2
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/postgres_spec.rb +5 -34
- data/spec/core/database_spec.rb +32 -0
- data/spec/core/dataset_spec.rb +19 -0
- data/spec/core/mock_adapter_spec.rb +65 -0
- data/spec/extensions/association_pks_spec.rb +26 -33
- data/spec/extensions/class_table_inheritance_spec.rb +18 -32
- data/spec/extensions/composition_spec.rb +7 -23
- data/spec/extensions/list_spec.rb +4 -5
- data/spec/extensions/many_through_many_spec.rb +24 -32
- data/spec/extensions/optimistic_locking_spec.rb +1 -1
- data/spec/extensions/pg_array_associations_spec.rb +18 -25
- data/spec/extensions/pg_extended_date_support_spec.rb +13 -0
- data/spec/extensions/pg_hstore_spec.rb +2 -2
- data/spec/extensions/prepared_statements_safe_spec.rb +6 -6
- data/spec/extensions/pretty_table_spec.rb +39 -8
- data/spec/extensions/rcte_tree_spec.rb +22 -33
- data/spec/extensions/schema_dumper_spec.rb +42 -31
- data/spec/extensions/serialization_spec.rb +3 -3
- data/spec/extensions/synchronize_sql_spec.rb +124 -0
- data/spec/extensions/timestamps_spec.rb +2 -4
- data/spec/extensions/update_or_create_spec.rb +11 -15
- data/spec/extensions/uuid_spec.rb +2 -3
- data/spec/extensions/xml_serializer_spec.rb +5 -10
- data/spec/integration/database_test.rb +1 -1
- data/spec/integration/dataset_test.rb +7 -0
- data/spec/integration/plugin_test.rb +1 -1
- data/spec/integration/schema_test.rb +3 -3
- data/spec/integration/spec_helper.rb +4 -0
- data/spec/model/base_spec.rb +6 -0
- data/spec/model/eager_loading_spec.rb +31 -6
- data/spec/model/model_spec.rb +9 -19
- data/spec/model/record_spec.rb +4 -8
- metadata +6 -2
@@ -15,15 +15,15 @@ describe "Serialization plugin" do
|
|
15
15
|
it "should allow setting additional serializable attributes via plugin :serialization call" do
|
16
16
|
@c.plugin :serialization, :yaml, :abc
|
17
17
|
@c.create(:abc => 1, :def=> 2)
|
18
|
-
DB.sqls.
|
18
|
+
DB.sqls.map{|s| s.sub("1\n...", '1')}.must_equal ["INSERT INTO items (def, abc) VALUES (2, '--- 1\n')"]
|
19
19
|
|
20
20
|
@c.plugin :serialization, :marshal, :def
|
21
21
|
@c.create(:abc => 1, :def=> 1)
|
22
|
-
DB.sqls.
|
22
|
+
DB.sqls.map{|s| s.sub("1\n...", '1')}.must_equal ["INSERT INTO items (abc, def) VALUES ('--- 1\n', 'BAhpBg==\n')"]
|
23
23
|
|
24
24
|
@c.plugin :serialization, :json, :ghi
|
25
25
|
@c.create(:ghi => [123])
|
26
|
-
DB.sqls.
|
26
|
+
DB.sqls.must_equal ["INSERT INTO items (ghi) VALUES ('[123]')"]
|
27
27
|
end
|
28
28
|
|
29
29
|
it "should handle validations of underlying column" do
|
@@ -0,0 +1,124 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
|
3
|
+
describe "synchronize_sql extension" do
|
4
|
+
module Sync
|
5
|
+
def literal_string_append(sql, v)
|
6
|
+
db.synchronize{super}
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
before do
|
11
|
+
@db = Sequel.mock
|
12
|
+
@db.pool.extend(Module.new do
|
13
|
+
def assign_connection(*args)
|
14
|
+
r = super
|
15
|
+
@times_connection_acquired ||= 0
|
16
|
+
@times_connection_acquired += 1 if r
|
17
|
+
return r
|
18
|
+
end
|
19
|
+
|
20
|
+
def times_connection_acquired
|
21
|
+
v = @times_connection_acquired
|
22
|
+
@times_connection_acquired = 0
|
23
|
+
v || 0
|
24
|
+
end
|
25
|
+
end)
|
26
|
+
@db.extend_datasets(Sync)
|
27
|
+
@ds = @db[:tab1]
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'does not checkout a connection if SQL is given as a string' do
|
31
|
+
extds = @ds.extension(:synchronize_sql).with_sql('SELECT 1').sql
|
32
|
+
@db.pool.times_connection_acquired.must_equal 0
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'checks out an extra connection on insert_sql if there are no strings' do
|
36
|
+
@ds.insert_sql(:numeric_foo => 8)
|
37
|
+
@db.pool.times_connection_acquired.must_equal 0
|
38
|
+
|
39
|
+
extds = @ds.extension(:synchronize_sql)
|
40
|
+
extds.insert_sql(:numeric_foo => 8)
|
41
|
+
@db.pool.times_connection_acquired.must_equal 1
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'checks out just one connection on insert_sql if there are multiple strings' do
|
45
|
+
@ds.insert_sql(:string_foo1 => 'eight', :string_foo2 => 'nine', :string_foo3 => 'ten')
|
46
|
+
@db.pool.times_connection_acquired.must_equal 3
|
47
|
+
|
48
|
+
extds = @ds.extension(:synchronize_sql)
|
49
|
+
extds.insert_sql(:string_foo1 => 'eight', :string_foo2 => 'nine', :string_foo3 => 'ten')
|
50
|
+
@db.pool.times_connection_acquired.must_equal 1
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'cheks out an extra connectrion on update_sql if there are no strings' do
|
54
|
+
@ds.where(:numeric_foo => [1, 2, 3, 4, 5]).update_sql(:numeric_foo => 99)
|
55
|
+
@db.pool.times_connection_acquired.must_equal 0
|
56
|
+
|
57
|
+
extds = @ds.extension(:synchronize_sql)
|
58
|
+
extds.where(:numeric_foo => [1, 2, 3, 4, 5]).update_sql(:numeric_foo => 99)
|
59
|
+
@db.pool.times_connection_acquired.must_equal 1
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'checks out just one connection on update_sql if there are multiple strings' do
|
63
|
+
@ds.where(:numeric_foo => [1, 2, 3, 4, 5]).update_sql(:string_foo1 => 'eight', :string_foo2 => 'nine', :string_foo3 => 'ten')
|
64
|
+
@db.pool.times_connection_acquired.must_equal 3
|
65
|
+
|
66
|
+
extds = @ds.extension(:synchronize_sql)
|
67
|
+
extds.where(:numeric_foo => [1, 2, 3, 4, 5]).update_sql(:string_foo1 => 'eight', :string_foo2 => 'nine', :string_foo3 => 'ten')
|
68
|
+
@db.pool.times_connection_acquired.must_equal 1
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'checks out an extra connection on delete_sql if there are no strings' do
|
72
|
+
@ds.where(:numeric_foo => [1, 2, 3]).delete_sql
|
73
|
+
@db.pool.times_connection_acquired.must_equal 0
|
74
|
+
|
75
|
+
extds = @ds.extension(:synchronize_sql)
|
76
|
+
extds.where(:numeric_foo => [1, 2, 3]).delete_sql
|
77
|
+
@db.pool.times_connection_acquired.must_equal 1
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'checks out just one connection on delete_sql if there are multiple strings' do
|
81
|
+
@ds.where(:string_foo => ['one', 'two', 'three', 'four']).delete_sql
|
82
|
+
@db.pool.times_connection_acquired.must_equal 4
|
83
|
+
|
84
|
+
extds = @ds.extension(:synchronize_sql)
|
85
|
+
extds.where(:string_foo => ['one', 'two', 'three', 'four']).delete_sql
|
86
|
+
@db.pool.times_connection_acquired.must_equal 1
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'checks out an extra connection on select_sql if there are no strings' do
|
90
|
+
@ds.where(:numeric_foo => [1, 2, 3]).select_sql
|
91
|
+
@db.pool.times_connection_acquired.must_equal 0
|
92
|
+
|
93
|
+
extds = @ds.extension(:synchronize_sql)
|
94
|
+
extds.where(:numeric_foo => [1, 2, 3]).select_sql
|
95
|
+
@db.pool.times_connection_acquired.must_equal 1
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'checks out just one connection on select_sql if there are multiple strings' do
|
99
|
+
@ds.where(:string_foo => ['one', 'two', 'three', 'four']).select_sql
|
100
|
+
@db.pool.times_connection_acquired.must_equal 4
|
101
|
+
|
102
|
+
extds = @ds.extension(:synchronize_sql)
|
103
|
+
extds.where(:string_foo => ['one', 'two', 'three', 'four']).select_sql
|
104
|
+
@db.pool.times_connection_acquired.must_equal 1
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'checks out an extra connection on fetch if there are no strings' do
|
108
|
+
@db.fetch('SELECT * FROM tab1 WHERE numeric_foo IN (?, ?, ?, ?)', 1, 2, 3, 4).select_sql
|
109
|
+
@db.pool.times_connection_acquired.must_equal 0
|
110
|
+
|
111
|
+
@db.extension(:synchronize_sql)
|
112
|
+
@db.fetch('SELECT * FROM tab1 WHERE numeric_foo IN (?, ?, ?, ?)', 1, 2, 3, 4).select_sql
|
113
|
+
@db.pool.times_connection_acquired.must_equal 1
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'checks out just one connection on fetch if there are multiple strings' do
|
117
|
+
@db.fetch('SELECT * FROM tab1 WHERE string_foo IN (?, ?, ?, ?)', 'one', 'two', 'three', 'four').select_sql
|
118
|
+
@db.pool.times_connection_acquired.must_equal 4
|
119
|
+
|
120
|
+
@db.extension(:synchronize_sql)
|
121
|
+
@db.fetch('SELECT * FROM tab1 WHERE string_foo IN (?, ?, ?, ?)', 'one', 'two', 'three', 'four').select_sql
|
122
|
+
@db.pool.times_connection_acquired.must_equal 1
|
123
|
+
end
|
124
|
+
end
|
@@ -76,9 +76,7 @@ describe "Sequel::Plugins::Timestamps" do
|
|
76
76
|
it "should use the same value for the creation and update timestamps when creating if the :update_on_create option is given" do
|
77
77
|
@c.plugin :timestamps, :update_on_create=>true
|
78
78
|
o = @c.create
|
79
|
-
|
80
|
-
sqls.shift.must_match(/INSERT INTO t \((creat|updat)ed_at, (creat|updat)ed_at\) VALUES \('2009-08-01', '2009-08-01'\)/)
|
81
|
-
sqls.must_equal []
|
79
|
+
@c.db.sqls.must_equal ["INSERT INTO t (created_at, updated_at) VALUES ('2009-08-01', '2009-08-01')"]
|
82
80
|
o.created_at.must_be :===, o.updated_at
|
83
81
|
end
|
84
82
|
|
@@ -201,7 +199,7 @@ describe "Sequel::Plugins::Timestamps" do
|
|
201
199
|
o = c2.create
|
202
200
|
o.c.must_equal '2009-08-01'
|
203
201
|
o.u.must_be :===, o.c
|
204
|
-
c2.db.sqls.
|
202
|
+
c2.db.sqls.must_equal ["INSERT INTO t (c, u) VALUES ('2009-08-01', '2009-08-01')"]
|
205
203
|
c2.db.reset
|
206
204
|
o = c2.load(:id=>1).save
|
207
205
|
o.u.must_equal '2009-08-01'
|
@@ -20,32 +20,28 @@ describe "Sequel::Plugins::UpdateOrCreate" do
|
|
20
20
|
|
21
21
|
@db.fetch = [[{:id=>1, :a=>2, :b=>3}]]
|
22
22
|
@c.update_or_create({:a=>2}, :a=>3){|t| t.b = 4}.must_equal @c.load(:id=>1, :a=>3, :b=>4)
|
23
|
-
sqls =
|
24
|
-
|
25
|
-
sqls.shift.must_match(/UPDATE test SET [ab] = [34], [ab] = [34] WHERE \(id = 1\)/)
|
23
|
+
@db.sqls.must_equal ["SELECT * FROM test WHERE (a = 2) LIMIT 1",
|
24
|
+
'UPDATE test SET a = 3, b = 4 WHERE (id = 1)']
|
26
25
|
end
|
27
26
|
|
28
27
|
it ".update_or_create should create a record if an existing record does not exist" do
|
29
28
|
@db.fetch = [[], [{:id=>1, :a=>1, :b=>4}]]
|
30
29
|
@c.update_or_create(:a=>1){|t| t.b = 4}.must_equal @c.load(:id=>1, :a=>1, :b=>4)
|
31
|
-
sqls =
|
32
|
-
|
33
|
-
|
34
|
-
sqls.shift.must_equal "SELECT * FROM test WHERE (id = 1) LIMIT 1"
|
30
|
+
@db.sqls.must_equal ["SELECT * FROM test WHERE (a = 1) LIMIT 1",
|
31
|
+
"INSERT INTO test (a, b) VALUES (1, 4)",
|
32
|
+
"SELECT * FROM test WHERE (id = 1) LIMIT 1"]
|
35
33
|
|
36
34
|
@db.fetch = [[], [{:id=>1, :a=>1, :b=>4}]]
|
37
35
|
@c.update_or_create({:a=>1}, :b=>4).must_equal @c.load(:id=>1, :a=>1, :b=>4)
|
38
|
-
sqls =
|
39
|
-
|
40
|
-
|
41
|
-
sqls.shift.must_equal "SELECT * FROM test WHERE (id = 1) LIMIT 1"
|
36
|
+
@db.sqls.must_equal ["SELECT * FROM test WHERE (a = 1) LIMIT 1",
|
37
|
+
"INSERT INTO test (a, b) VALUES (1, 4)",
|
38
|
+
"SELECT * FROM test WHERE (id = 1) LIMIT 1"]
|
42
39
|
|
43
40
|
@db.fetch = [[], [{:id=>1, :a=>3, :b=>4}]]
|
44
41
|
@c.update_or_create({:a=>1}, :a=>3){|t| t.b = 4}.must_equal @c.load(:id=>1, :a=>3, :b=>4)
|
45
|
-
sqls =
|
46
|
-
|
47
|
-
|
48
|
-
sqls.shift.must_equal "SELECT * FROM test WHERE (id = 1) LIMIT 1"
|
42
|
+
@db.sqls.must_equal ["SELECT * FROM test WHERE (a = 1) LIMIT 1",
|
43
|
+
"INSERT INTO test (a, b) VALUES (3, 4)",
|
44
|
+
"SELECT * FROM test WHERE (id = 1) LIMIT 1"]
|
49
45
|
end
|
50
46
|
|
51
47
|
it ".update_or_create should return an existing record even if no changes necessary" do
|
@@ -45,8 +45,7 @@ describe "Sequel::Plugins::Uuid" do
|
|
45
45
|
def _save_refresh(*) end
|
46
46
|
end
|
47
47
|
o = c.create
|
48
|
-
c.db.sqls.
|
49
|
-
o.u.must_match(/[-0-9a-f]+/)
|
48
|
+
c.db.sqls.must_equal ["INSERT INTO t (u) VALUES ('#{o.u}')"]
|
50
49
|
end
|
51
50
|
|
52
51
|
it "should not raise an error if the model doesn't have the uuid column" do
|
@@ -97,6 +96,6 @@ describe "Sequel::Plugins::Uuid" do
|
|
97
96
|
c2.db.reset
|
98
97
|
o = c2.create
|
99
98
|
o.u.must_equal @uuid
|
100
|
-
c2.db.sqls.
|
99
|
+
c2.db.sqls.must_equal ["INSERT INTO t (u) VALUES ('#{@uuid}')"]
|
101
100
|
end
|
102
101
|
end
|
@@ -125,30 +125,25 @@ describe "Sequel::Plugins::XmlSerializer" do
|
|
125
125
|
end
|
126
126
|
|
127
127
|
it "should support an :encoding option when serializing" do
|
128
|
-
|
129
|
-
"<?xml version=\"1.0\" encoding=\"UTF-8\"?><artist><name>YJM</name><id>2</id></artist>"].must_include(@artist.to_xml(:encoding=>'UTF-8').gsub(/\n */m, ''))
|
128
|
+
@artist.to_xml(:encoding=>'UTF-8').gsub(/\n */m, '').must_equal "<?xml version=\"1.0\" encoding=\"UTF-8\"?><artist><id>2</id><name>YJM</name></artist>"
|
130
129
|
end
|
131
130
|
|
132
131
|
it "should support a :builder_opts option when serializing" do
|
133
|
-
|
134
|
-
"<?xml version=\"1.0\" encoding=\"UTF-8\"?><artist><name>YJM</name><id>2</id></artist>"].must_include(@artist.to_xml(:builder_opts=>{:encoding=>'UTF-8'}).gsub(/\n */m, ''))
|
132
|
+
@artist.to_xml(:builder_opts=>{:encoding=>'UTF-8'}).gsub(/\n */m, '').must_equal "<?xml version=\"1.0\" encoding=\"UTF-8\"?><artist><id>2</id><name>YJM</name></artist>"
|
135
133
|
end
|
136
134
|
|
137
135
|
it "should support an :types option when serializing" do
|
138
|
-
|
139
|
-
"<?xml version=\"1.0\"?><artist><name type=\"string\">YJM</name><id type=\"integer\">2</id></artist>"].must_include(@artist.to_xml(:types=>true).gsub(/\n */m, ''))
|
136
|
+
@artist.to_xml(:types=>true).gsub(/\n */m, '').must_equal "<?xml version=\"1.0\"?><artist><id type=\"integer\">2</id><name type=\"string\">YJM</name></artist>"
|
140
137
|
end
|
141
138
|
|
142
139
|
it "should support an :root_name option when serializing" do
|
143
|
-
|
144
|
-
"<?xml version=\"1.0\"?><ar><name>YJM</name><id>2</id></ar>"].must_include(@artist.to_xml(:root_name=>'ar').gsub(/\n */m, ''))
|
140
|
+
@artist.to_xml(:root_name=>'ar').gsub(/\n */m, '').must_equal "<?xml version=\"1.0\"?><ar><id>2</id><name>YJM</name></ar>"
|
145
141
|
end
|
146
142
|
|
147
143
|
it "should support an :array_root_name option when serializing arrays" do
|
148
144
|
artist = @artist
|
149
145
|
Artist.dataset = Artist.dataset.with_extend{define_method(:all){[artist]}}
|
150
|
-
|
151
|
-
"<?xml version=\"1.0\"?><ars><ar><name>YJM</name><id>2</id></ar></ars>"].must_include(Artist.to_xml(:array_root_name=>'ars', :root_name=>'ar').gsub(/\n */m, ''))
|
146
|
+
Artist.to_xml(:array_root_name=>'ars', :root_name=>'ar').gsub(/\n */m, '').must_equal "<?xml version=\"1.0\"?><ars><ar><id>2</id><name>YJM</name></ar></ars>"
|
152
147
|
end
|
153
148
|
|
154
149
|
it "should raise an exception for xml tags that aren't associations, columns, or setter methods" do
|
@@ -53,7 +53,7 @@ describe Sequel::Database do
|
|
53
53
|
proc{@db[:test].update(:a=>'1', :b=>'2')}.must_raise(Sequel::UniqueConstraintViolation)
|
54
54
|
end
|
55
55
|
|
56
|
-
cspecify "should raise Sequel::CheckConstraintViolation when a check constraint is violated", :mysql, [proc{|db| db.sqlite_version < 30802}, :sqlite] do
|
56
|
+
cspecify "should raise Sequel::CheckConstraintViolation when a check constraint is violated", [proc{|db| !db.mariadb? || db.server_version <= 100200}, :mysql], [proc{|db| db.sqlite_version < 30802}, :sqlite] do
|
57
57
|
@db.create_table!(:test){String :a; check Sequel.~(:a=>'1')}
|
58
58
|
proc{@db[:test].insert('1')}.must_raise(Sequel::CheckConstraintViolation)
|
59
59
|
@db[:test].insert('2')
|
@@ -771,6 +771,13 @@ if DB.dataset.supports_cte?(:update) # Assume INSERT and DELETE support as well
|
|
771
771
|
@ds2.filter(:id=>@db[:t].select{max(id)}).delete
|
772
772
|
@ds.select_order_map(:id).must_equal [1, 1]
|
773
773
|
end
|
774
|
+
|
775
|
+
it "should support a subselect in an subquery used for INSERT" do
|
776
|
+
@db.transaction(:rollback=>:always) do
|
777
|
+
@ds.insert([:id], @db[:foo].with(:foo, @ds.select{(id + 10).as(:id)}))
|
778
|
+
@ds.select_order_map(:id).must_equal [1,2,11,12]
|
779
|
+
end
|
780
|
+
end
|
774
781
|
end
|
775
782
|
end
|
776
783
|
|
@@ -2043,7 +2043,7 @@ describe "Sequel::Plugins::ConstraintValidations" do
|
|
2043
2043
|
end
|
2044
2044
|
|
2045
2045
|
ConstraintValidationsSpecs = shared_description do
|
2046
|
-
cspecify "should set up constraints that work even outside the model", :mysql do
|
2046
|
+
cspecify "should set up constraints that work even outside the model", [proc{|db| !db.mariadb? || db.server_version <= 100200}, :mysql] do
|
2047
2047
|
@ds.insert(@valid_row)
|
2048
2048
|
|
2049
2049
|
# Test for unique constraint
|
@@ -129,7 +129,7 @@ describe "Database schema parser" do
|
|
129
129
|
DB.schema(:items).first.last[:ruby_default].must_equal Sequel::CURRENT_TIMESTAMP
|
130
130
|
end
|
131
131
|
|
132
|
-
cspecify "should parse current date defaults from the schema properly", :mysql, :oracle do
|
132
|
+
cspecify "should parse current date defaults from the schema properly", [proc{|db| !db.mariadb? || db.server_version <= 100200}, :mysql], :oracle do
|
133
133
|
DB.create_table!(:items){Date :a, :default=>Sequel::CURRENT_DATE}
|
134
134
|
DB.schema(:items).first.last[:ruby_default].must_equal Sequel::CURRENT_DATE
|
135
135
|
end
|
@@ -765,14 +765,14 @@ describe "Database schema modifiers" do
|
|
765
765
|
primary_key :id
|
766
766
|
String :name2
|
767
767
|
String :number2
|
768
|
-
constraint :bar, Sequel.~(:
|
768
|
+
constraint :bar, Sequel.~(:number2=>nil, :name2=>nil)
|
769
769
|
end
|
770
770
|
@ds.insert(:name2=>'A12')
|
771
771
|
@db.alter_table(:items) do
|
772
772
|
add_column :number, Integer
|
773
|
+
drop_constraint :bar
|
773
774
|
drop_column :number2
|
774
775
|
rename_column :name2, :name
|
775
|
-
drop_constraint :bar
|
776
776
|
set_column_not_null :name
|
777
777
|
set_column_default :name, 'A13'
|
778
778
|
add_constraint :foo, Sequel.like(:name, 'A%')
|
@@ -42,6 +42,10 @@ if ENV['SEQUEL_ERROR_SQL']
|
|
42
42
|
DB.extension :error_sql
|
43
43
|
end
|
44
44
|
|
45
|
+
if ENV['SEQUEL_SYNCHRONIZE_SQL']
|
46
|
+
DB.extension :synchronize_sql
|
47
|
+
end
|
48
|
+
|
45
49
|
if ENV['SEQUEL_CONNECTION_VALIDATOR']
|
46
50
|
ENV['SEQUEL_NO_CHECK_SQLS'] = '1'
|
47
51
|
DB.extension(:connection_validator)
|
data/spec/model/base_spec.rb
CHANGED
@@ -316,6 +316,12 @@ describe Sequel::Model, ".dataset_module" do
|
|
316
316
|
@c.order(:bar).foo.sql.must_equal 'SELECT * FROM items ORDER BY baz, bar'
|
317
317
|
end
|
318
318
|
|
319
|
+
it "should have dataset_module support a reverse method" do
|
320
|
+
@c.dataset_module{reverse(:foo){:baz}}
|
321
|
+
@c.foo.sql.must_equal 'SELECT * FROM items ORDER BY baz DESC'
|
322
|
+
@c.where(:bar).foo.sql.must_equal 'SELECT * FROM items WHERE bar ORDER BY baz DESC'
|
323
|
+
end
|
324
|
+
|
319
325
|
it "should have dataset_module support a select method" do
|
320
326
|
@c.dataset_module{select :foo, :baz}
|
321
327
|
@c.foo.sql.must_equal 'SELECT baz FROM items'
|
@@ -222,6 +222,31 @@ describe Sequel::Model, "#eager" do
|
|
222
222
|
DB.sqls.must_equal []
|
223
223
|
end
|
224
224
|
|
225
|
+
it "should eagerly load a single one_to_one association using the :window_function strategy on MySQL" do
|
226
|
+
odb = DB
|
227
|
+
db = Class.new do
|
228
|
+
def database_type; :mysql; end
|
229
|
+
define_method(:method_missing) do |*args, &block|
|
230
|
+
odb.send(*args, &block)
|
231
|
+
end
|
232
|
+
end.new
|
233
|
+
|
234
|
+
begin
|
235
|
+
EagerTrack.dataset = EagerTrack.dataset.with_extend do
|
236
|
+
def supports_window_functions?; true end
|
237
|
+
define_method(:db){db}
|
238
|
+
end
|
239
|
+
EagerAlbum.one_to_one :track, :class=>'EagerTrack', :key=>:album_id, :order=>:name, :eager_limit_strategy=>:window_function
|
240
|
+
a = EagerAlbum.eager(:track).all
|
241
|
+
a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
|
242
|
+
DB.sqls.must_equal ['SELECT * FROM albums', 'SELECT * FROM (SELECT *, row_number() OVER (PARTITION BY tracks.album_id ORDER BY name) AS x_sequel_row_number_x FROM tracks WHERE (tracks.album_id IN (1))) AS t1 WHERE (x_sequel_row_number_x = 1) ORDER BY x_sequel_row_number_x']
|
243
|
+
a.first.track.must_equal EagerTrack.load(:id => 3, :album_id=>1)
|
244
|
+
DB.sqls.must_equal []
|
245
|
+
ensure
|
246
|
+
db = DB
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
225
250
|
it "should automatically use an eager limit stategy if the association has an offset" do
|
226
251
|
EagerAlbum.one_to_one :track, :class=>'EagerTrack', :key=>:album_id, :limit=>[1,1]
|
227
252
|
EagerTrack.dataset = EagerTrack.dataset.with_fetch([{:id => 4, :album_id=>1}])
|
@@ -675,9 +700,9 @@ describe Sequel::Model, "#eager" do
|
|
675
700
|
it "should cache the negative lookup when eagerly loading a *_to_many associations" do
|
676
701
|
a = EagerBand.eager(:albums).where{id > 100}.all
|
677
702
|
a.must_equal [EagerBand.load(:id => 101), EagerBand.load(:id =>102)]
|
678
|
-
sqls
|
679
|
-
|
680
|
-
|
703
|
+
DB.sqls.must_equal ['SELECT * FROM bands WHERE (id > 100)',
|
704
|
+
'SELECT * FROM albums WHERE (albums.band_id IN (101, 102))',
|
705
|
+
"SELECT * FROM tracks WHERE (tracks.album_id IN (101))"]
|
681
706
|
a.map{|b| b.associations[:albums]}.must_equal [[EagerAlbum.load({:band_id=>101, :id=>101})], []]
|
682
707
|
DB.sqls.must_equal []
|
683
708
|
end
|
@@ -1100,9 +1125,9 @@ describe Sequel::Model, "#eager" do
|
|
1100
1125
|
EagerTrack.dataset = EagerTrack.dataset.with_fetch([{:id=>3, :album_id=>1}])
|
1101
1126
|
a = EagerBand.eager(:top_10_albums=>{proc{|ds| ds.select(:id, :name)}=>:tracks}).all
|
1102
1127
|
a.must_equal [EagerBand.load(:id => 2)]
|
1103
|
-
sqls
|
1104
|
-
|
1105
|
-
|
1128
|
+
DB.sqls.must_equal ['SELECT * FROM bands',
|
1129
|
+
'SELECT id, name FROM albums WHERE (albums.band_id IN (2))',
|
1130
|
+
'SELECT * FROM tracks WHERE (tracks.album_id IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11))']
|
1106
1131
|
a = a.first
|
1107
1132
|
a.top_10_albums.must_equal((1..10).map{|i| EagerAlbum.load(:band_id=>2, :id=>i)})
|
1108
1133
|
a.top_10_albums.map{|x| x.tracks}.must_equal [[EagerTrack.load(:id => 3, :album_id=>1)]] + ([[]] * 9)
|
data/spec/model/model_spec.rb
CHANGED
@@ -231,10 +231,8 @@ end
|
|
231
231
|
|
232
232
|
describe Sequel::Model do
|
233
233
|
it "should have class method aliased as model" do
|
234
|
-
Sequel::Model.instance_methods.collect{|x| x.to_s}.must_include("model")
|
235
|
-
|
236
234
|
model_a = Class.new(Sequel::Model(:items))
|
237
|
-
model_a.new.model.
|
235
|
+
model_a.new.model.must_be_same_as model_a
|
238
236
|
end
|
239
237
|
|
240
238
|
it "should be associated with a dataset" do
|
@@ -626,10 +624,9 @@ describe Sequel::Model, ".find_or_create" do
|
|
626
624
|
@db.fetch = [[], {:x=>1, :id=>1}]
|
627
625
|
@db.autoid = 1
|
628
626
|
@c.find_or_create(:x => 1){|x| x[:y] = 2}.must_equal @c.load(:x=>1, :id=>1)
|
629
|
-
sqls =
|
630
|
-
|
631
|
-
|
632
|
-
sqls.last.must_equal "SELECT * FROM items WHERE id = 1"
|
627
|
+
@db.sqls.must_equal ["SELECT * FROM items WHERE (x = 1) LIMIT 1",
|
628
|
+
"INSERT INTO items (x, y) VALUES (1, 2)",
|
629
|
+
"SELECT * FROM items WHERE id = 1"]
|
633
630
|
end
|
634
631
|
end
|
635
632
|
|
@@ -687,17 +684,12 @@ describe Sequel::Model, "attribute accessors" do
|
|
687
684
|
end
|
688
685
|
|
689
686
|
it "should be created on set_dataset" do
|
690
|
-
|
691
|
-
|
692
|
-
end
|
687
|
+
a = [:x, :z, :x= ,:z=]
|
688
|
+
(a - @c.instance_methods).must_equal a
|
693
689
|
@c.set_dataset(@dataset)
|
694
|
-
|
695
|
-
@c.instance_methods.collect{|z| z.to_s}.must_include(x)
|
696
|
-
end
|
690
|
+
(a - @c.instance_methods).must_equal []
|
697
691
|
o = @c.new
|
698
|
-
|
699
|
-
o.methods.collect{|z| z.to_s}.must_include(x)
|
700
|
-
end
|
692
|
+
(a - o.methods).must_equal []
|
701
693
|
|
702
694
|
o.x.must_be_nil
|
703
695
|
o.x = 34
|
@@ -769,9 +761,7 @@ describe Sequel::Model, ".[]" do
|
|
769
761
|
it "should work correctly for composite primary key specified as array" do
|
770
762
|
@c.set_primary_key [:node_id, :kind]
|
771
763
|
@c[3921, 201].must_be_kind_of(@c)
|
772
|
-
sqls =
|
773
|
-
sqls.length.must_equal 1
|
774
|
-
sqls.first.must_match(/^SELECT \* FROM items WHERE \((\(node_id = 3921\) AND \(kind = 201\))|(\(kind = 201\) AND \(node_id = 3921\))\) LIMIT 1$/)
|
764
|
+
DB.sqls.must_equal ['SELECT * FROM items WHERE ((node_id = 3921) AND (kind = 201)) LIMIT 1']
|
775
765
|
end
|
776
766
|
end
|
777
767
|
|