sequel 5.2.0 → 5.3.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.
- 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
|
|